@Test
  public void testUnmetARsForEvaluation() throws Exception {
    RestrictableObjectDescriptor rod =
        AccessRequirementUtilsTest.createRestrictableObjectDescriptor(
            evaluation.getId(), RestrictableObjectType.EVALUATION);
    // Logic for unmet requirements doesn't reflect ownership at the DAO level.  It's factored in at
    // the manager level.
    // Therefore, the owner see unmet ARs for herself..
    List<Long> unmetARIds =
        accessRequirementDAO.unmetAccessRequirements(
            rod,
            Arrays.asList(new Long[] {Long.parseLong(individualGroup.getId())}),
            participateAndDownload);
    assertEquals(1, unmetARIds.size());
    assertEquals(accessRequirement2.getId(), unmetARIds.iterator().next());
    // ... just as someone else does, if they haven't signed the ToU
    unmetARIds =
        accessRequirementDAO.unmetAccessRequirements(
            rod,
            Arrays.asList(new Long[] {Long.parseLong(individualGroup2.getId())}),
            participateAndDownload);
    assertEquals(1, unmetARIds.size());
    assertEquals(accessRequirement2.getId(), unmetARIds.iterator().next());

    // Create a new object
    accessApproval2 = newAccessApproval(individualGroup2, accessRequirement2);

    // Create it
    accessApproval2 = accessApprovalDAO.create(accessApproval2);
    String id = accessApproval2.getId().toString();
    assertNotNull(id);

    // no unmet requirement anymore ...
    assertTrue(
        accessRequirementDAO
            .unmetAccessRequirements(
                rod,
                Arrays.asList(new Long[] {Long.parseLong(individualGroup2.getId())}),
                participateAndDownload)
            .isEmpty());

    // Get by evaluation Id
    Collection<AccessApproval> ars =
        accessApprovalDAO.getForAccessRequirementsAndPrincipals(
            Arrays.asList(new String[] {accessRequirement2.getId().toString()}),
            Arrays.asList(new String[] {individualGroup2.getId().toString()}));
    assertEquals(1, ars.size());
    assertEquals(accessApproval2, ars.iterator().next());
  }
  @Override
  public <T extends AccessApproval> T createAccessApproval(UserInfo userInfo, T accessApproval)
      throws DatastoreException, InvalidModelException, UnauthorizedException, NotFoundException,
          ForbiddenException {
    validateAccessApproval(userInfo, accessApproval);

    if ((accessApproval instanceof ACTAccessApproval)) {
      verifyAccess(userInfo, accessApproval, ADMINISTER_ACCESS_APPROVAL_ACCESS_TYPE);
    }

    if ((accessApproval instanceof TermsOfUseAccessApproval)) {
      verifyAccess(userInfo, accessApproval, ACCESS_TYPE.READ);
    }

    populateCreationFields(userInfo, accessApproval);
    return accessApprovalDAO.create(accessApproval);
  }
  @Test
  public void testCRUD() throws Exception {
    // first of all, we should see the unmet requirement
    RestrictableObjectDescriptor rod =
        AccessRequirementUtilsTest.createRestrictableObjectDescriptor(node.getId());
    List<Long> unmetARIds =
        accessRequirementDAO.unmetAccessRequirements(
            rod,
            Arrays.asList(new Long[] {Long.parseLong(individualGroup.getId())}),
            downloadAccessType);
    assertEquals(1, unmetARIds.size());
    assertEquals(accessRequirement.getId(), unmetARIds.iterator().next());
    // while we're at it, check the edge cases:
    // same result for ficticious principal ID
    unmetARIds =
        accessRequirementDAO.unmetAccessRequirements(
            rod, Arrays.asList(new Long[] {8888L}), downloadAccessType);
    assertEquals(1, unmetARIds.size());
    assertEquals(accessRequirement.getId(), unmetARIds.iterator().next());
    // no unmet requirements for ficticious node ID
    assertTrue(
        accessRequirementDAO
            .unmetAccessRequirements(
                AccessRequirementUtilsTest.createRestrictableObjectDescriptor("syn7890"),
                Arrays.asList(new Long[] {Long.parseLong(individualGroup.getId())}),
                downloadAccessType)
            .isEmpty());
    // no unmet requirement for other type of access
    assertTrue(
        accessRequirementDAO
            .unmetAccessRequirements(
                rod,
                Arrays.asList(new Long[] {Long.parseLong(individualGroup.getId())}),
                updateAccessType)
            .isEmpty());

    // Create a new object
    accessApproval = newAccessApproval(individualGroup, accessRequirement);

    // Create it
    accessApproval = accessApprovalDAO.create(accessApproval);
    String id = accessApproval.getId().toString();
    assertNotNull(id);

    // no unmet requirement anymore ...
    assertTrue(
        accessRequirementDAO
            .unmetAccessRequirements(
                rod,
                Arrays.asList(new Long[] {Long.parseLong(individualGroup.getId())}),
                downloadAccessType)
            .isEmpty());
    // ... but for a different (ficticious) user, the requirement isn't met...
    unmetARIds =
        accessRequirementDAO.unmetAccessRequirements(
            rod, Arrays.asList(new Long[] {8888L}), downloadAccessType);
    assertEquals(1, unmetARIds.size());
    assertEquals(accessRequirement.getId(), unmetARIds.iterator().next());
    // ... and it's still unmet for the second node
    RestrictableObjectDescriptor rod2 =
        AccessRequirementUtilsTest.createRestrictableObjectDescriptor(node2.getId());
    unmetARIds =
        accessRequirementDAO.unmetAccessRequirements(
            rod2,
            Arrays.asList(new Long[] {Long.parseLong(individualGroup.getId())}),
            participateAndDownload);
    assertEquals(1, unmetARIds.size());
    assertEquals(accessRequirement2.getId(), unmetARIds.iterator().next());

    // Fetch it
    AccessApproval clone = accessApprovalDAO.get(id);
    assertNotNull(clone);
    assertEquals(accessApproval, clone);

    // Get by Node Id
    Collection<AccessApproval> ars =
        accessApprovalDAO.getForAccessRequirementsAndPrincipals(
            Arrays.asList(new String[] {accessRequirement.getId().toString()}),
            Arrays.asList(new String[] {individualGroup.getId().toString()}));
    assertEquals(1, ars.size());
    assertEquals(accessApproval, ars.iterator().next());

    // update it
    clone = ars.iterator().next();
    AccessApproval updatedAA = accessApprovalDAO.update(clone);
    assertEquals(
        ((TermsOfUseAccessApproval) clone).getEntityType(),
        ((TermsOfUseAccessApproval) updatedAA).getEntityType());
    assertTrue(
        "etags should be different after an update", !clone.getEtag().equals(updatedAA.getEtag()));

    try {
      accessApprovalDAO.update(clone);
      fail("conflicting update exception not thrown");
    } catch (ConflictingUpdateException e) {
      // We expected this exception
    }

    try {
      // Update from a backup.
      updatedAA = accessApprovalDAO.updateFromBackup(clone);
      assertEquals(clone.getEtag(), updatedAA.getEtag());
    } catch (ConflictingUpdateException e) {
      fail("Update from backup should not generate exception even if the e-tag is different.");
    }

    // Delete it
    accessApprovalDAO.delete(id);
  }