edu.internet2.middleware.psp.shibboleth.GrouperChangeLogDataConnectorTest.java Source code

Java tutorial

Introduction

Here is the source code for edu.internet2.middleware.psp.shibboleth.GrouperChangeLogDataConnectorTest.java

Source

/*
 * Licensed to the University Corporation for Advanced Internet Development, 
 * Inc. (UCAID) under one or more contributor license agreements.  See the 
 * NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The UCAID licenses this file to You under the Apache 
 * License, Version 2.0 (the "License"); you may not use this file except in 
 * compliance with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package edu.internet2.middleware.psp.shibboleth;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import junit.textui.TestRunner;

import org.hibernate.criterion.Restrictions;
import org.opensaml.util.resource.ResourceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.GenericApplicationContext;

import edu.internet2.middleware.grouper.attr.assign.AttributeAssign;
import edu.internet2.middleware.grouper.attr.assign.AttributeAssignType;
import edu.internet2.middleware.grouper.attr.finder.AttributeAssignFinder;
import edu.internet2.middleware.grouper.audit.AuditEntry;
import edu.internet2.middleware.grouper.audit.UserAuditQuery;
import edu.internet2.middleware.grouper.changeLog.ChangeLogEntry;
import edu.internet2.middleware.grouper.changeLog.ChangeLogLabel;
import edu.internet2.middleware.grouper.changeLog.ChangeLogLabels;
import edu.internet2.middleware.grouper.changeLog.ChangeLogTempToEntity;
import edu.internet2.middleware.grouper.changeLog.ChangeLogTypeBuiltin;
import edu.internet2.middleware.grouper.helper.SubjectTestHelper;
import edu.internet2.middleware.grouper.hibernate.HibernateSession;
import edu.internet2.middleware.grouper.misc.GrouperDAOFactory;
import edu.internet2.middleware.grouper.shibboleth.dataConnector.BaseDataConnectorTest;
import edu.internet2.middleware.grouper.util.GrouperUtil;
import edu.internet2.middleware.shibboleth.common.attribute.BaseAttribute;

/**
 * Test for {@link ChangeLogDataConnector}.
 */
public class GrouperChangeLogDataConnectorTest extends BaseDataConnectorTest {

    /** Logger. */
    private static final Logger LOG = LoggerFactory.getLogger(GrouperChangeLogDataConnectorTest.class);

    /** Path to attribute resolver configuration. */
    public static final String RESOLVER_CONFIG = "GrouperChangeLogDataConnectorTest-resolver.xml";

    /** The data connector. */
    private ChangeLogDataConnector changeLogDataConnector;

    /** The spring context. */
    private GenericApplicationContext gContext;

    /**
     * 
     * Constructor
     * 
     * @param name
     */
    public GrouperChangeLogDataConnectorTest(String name) {
        super(name);
    }

    /**
     * Run tests.
     * 
     * @param args
     */
    public static void main(String[] args) {
        // TestRunner.run(ChangeLogDataConnectorTest.class);
        TestRunner.run(new GrouperChangeLogDataConnectorTest("testFilterChangeLogAttributeAssignType"));
    }

    /**
     * {@inheritDoc}
     */
    public void setUp() {

        super.setUp();

        // setup Spring
        try {
            gContext = BaseDataConnectorTest.createSpringContext(RESOLVER_CONFIG);
        } catch (ResourceException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        // convert temp change log records
        ChangeLogTempToEntity.convertRecords();

        HibernateSession.byHqlStatic().createQuery("delete from ChangeLogEntryTemp").executeUpdate();
        HibernateSession.byHqlStatic().createQuery("delete from ChangeLogEntryEntity").executeUpdate();

        // delete a group and memberships
        groupA.delete();

        // convert temp change log records
        ChangeLogTempToEntity.convertRecords();
    }

    /**
     * Assert that the attributes returned from the data connector match the provided attributes.
     * 
     * @param dataConnector the data connector
     * @param sequenceNumber the change log entry identifier
     * @param correctMap the correct attributes
     */
    protected void runResolveTest(ChangeLogDataConnector dataConnector, String sequenceNumber,
            AttributeMap correctMap) {
        try {
            AttributeMap currentMap = new AttributeMap(dataConnector.resolve(getShibContext(sequenceNumber)));
            LOG.debug("current attributes\n{}", currentMap);
            LOG.debug("correct attributes\n{}", correctMap);

            // remove 'subject* attributes from comparison
            Map<String, BaseAttribute> map = currentMap.getMap();
            Set<String> keysToRemove = new HashSet<String>();
            for (String key : map.keySet()) {
                if (key.equals("subjectId")) {
                    continue;
                }
                if (key.startsWith("subject")) {
                    keysToRemove.add(key);
                }
            }
            for (String key : keysToRemove) {
                map.remove(key);
            }
            LOG.debug("current attributes\n{}", currentMap);

            assertEquals(correctMap, currentMap);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Add common change log entry attributes to the map.
     * 
     * @param correctMap the map to add attributes to
     * @param changeLogEntry the change log entry
     */
    protected void addChangeLogAttributesToMap(AttributeMap correctMap, ChangeLogEntry changeLogEntry) {
        correctMap.setAttribute("actionName", changeLogEntry.getChangeLogType().getActionName());
        correctMap.setAttribute("changeLogCategory", changeLogEntry.getChangeLogType().getChangeLogCategory());
        correctMap.setAttribute("sequenceNumber", changeLogEntry.getSequenceNumber().toString());
        correctMap.setAttribute("createdOn", changeLogEntry.getCreatedOn().toString());
    }

    /**
     * Test audit filter by both category and action.
     */
    public void testFilterChangeLogAudit() {

        changeLogDataConnector = (ChangeLogDataConnector) gContext.getBean("testFilterChangeLogAudit");

        // retrieve all change log entries
        List<ChangeLogEntry> changeLogEntryList = GrouperDAOFactory.getFactory().getChangeLogEntry()
                .retrieveBatch(-1, 1000);

        // for every change log entry
        for (ChangeLogEntry changeLogEntryFromList : changeLogEntryList) {

            // the empty map
            AttributeMap correctMap = new AttributeMap();

            // if change log entry matches, build correct map
            boolean match = false;

            List<AuditEntry> auditEntries = new UserAuditQuery()
                    .setExtraCriterion(
                            Restrictions.eq(AuditEntry.FIELD_CONTEXT_ID, changeLogEntryFromList.getContextId()))
                    .execute();

            for (AuditEntry auditEntry : auditEntries) {

                if (auditEntry.getAuditType().getActionName().equals("deleteGroup")
                        && auditEntry.getAuditType().getAuditCategory().equals("group")) {
                    match = true;
                    break;
                }
            }

            if (match) {
                // get change log entry via query
                ChangeLogEntry changeLogEntry = GrouperDAOFactory.getFactory().getChangeLogEntry()
                        .findBySequenceNumber(changeLogEntryFromList.getSequenceNumber(), false);

                if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.GROUP_DELETE)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.GROUP_DELETE.values()) {
                        correctMap.setAttribute(changeLogLabel, changeLogEntry);
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }
                if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.MEMBERSHIP_DELETE)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.MEMBERSHIP_DELETE.values()) {
                        correctMap.setAttribute(changeLogLabel, changeLogEntry);
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }
                if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.PRIVILEGE_DELETE)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.PRIVILEGE_DELETE.values()) {
                        correctMap.setAttribute(changeLogLabel, changeLogEntry);
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }

                // verify that the correct attributes are returned from the data connector for every change log entry
                runResolveTest(changeLogDataConnector,
                        ChangeLogDataConnector.principalName(changeLogEntry.getSequenceNumber()), correctMap);
            }
        }
    }

    /**
     * Test audit filter by action only.
     */
    public void testFilterChangeLogAuditAction() {

        changeLogDataConnector = (ChangeLogDataConnector) gContext.getBean("testFilterChangeLogAuditAction");

        // retrieve all change log entries
        List<ChangeLogEntry> changeLogEntryList = GrouperDAOFactory.getFactory().getChangeLogEntry()
                .retrieveBatch(-1, 1000);

        // for every change log entry
        for (ChangeLogEntry changeLogEntryFromList : changeLogEntryList) {

            // the empty map
            AttributeMap correctMap = new AttributeMap();

            // if change log entry matches, build correct map
            boolean match = false;

            List<AuditEntry> auditEntries = new UserAuditQuery()
                    .setExtraCriterion(
                            Restrictions.eq(AuditEntry.FIELD_CONTEXT_ID, changeLogEntryFromList.getContextId()))
                    .execute();

            for (AuditEntry auditEntry : auditEntries) {
                if (auditEntry.getAuditType().getActionName().equals("deleteGroup")) {
                    match = true;
                    break;
                }
            }

            if (match) {
                ChangeLogEntry changeLogEntry = GrouperDAOFactory.getFactory().getChangeLogEntry()
                        .findBySequenceNumber(changeLogEntryFromList.getSequenceNumber(), false);

                if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.GROUP_DELETE)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.GROUP_DELETE.values()) {
                        correctMap.setAttribute(changeLogLabel, changeLogEntry);
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }
                if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.MEMBERSHIP_DELETE)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.MEMBERSHIP_DELETE.values()) {
                        correctMap.setAttribute(changeLogLabel, changeLogEntry);
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }
                if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.PRIVILEGE_DELETE)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.PRIVILEGE_DELETE.values()) {
                        correctMap.setAttribute(changeLogLabel, changeLogEntry);
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }

                // verify that the correct attributes are returned from the data connector for every change log entry
                runResolveTest(changeLogDataConnector,
                        ChangeLogDataConnector.principalName(changeLogEntry.getSequenceNumber()), correctMap);
            }
        }
    }

    /**
     * Test audit filter by category only.
     */
    public void testFilterChangeLogAuditCategory() {

        changeLogDataConnector = (ChangeLogDataConnector) gContext.getBean("testFilterChangeLogAuditCategory");

        // retrieve all change log entries
        List<ChangeLogEntry> changeLogEntryList = GrouperDAOFactory.getFactory().getChangeLogEntry()
                .retrieveBatch(-1, 1000);

        // for every change log entry
        for (ChangeLogEntry changeLogEntryFromList : changeLogEntryList) {

            // the empty map
            AttributeMap correctMap = new AttributeMap();

            // if change log entry matches, build correct map
            boolean match = false;

            List<AuditEntry> auditEntries = new UserAuditQuery()
                    .setExtraCriterion(
                            Restrictions.eq(AuditEntry.FIELD_CONTEXT_ID, changeLogEntryFromList.getContextId()))
                    .execute();

            for (AuditEntry auditEntry : auditEntries) {
                if (auditEntry.getAuditType().getAuditCategory().equals("stem")) {
                    match = true;
                    break;
                }
            }

            if (match) {
                ChangeLogEntry changeLogEntry = GrouperDAOFactory.getFactory().getChangeLogEntry()
                        .findBySequenceNumber(changeLogEntryFromList.getSequenceNumber(), false);

                if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.STEM_ADD)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.STEM_ADD.values()) {
                        correctMap.setAttribute(changeLogLabel, changeLogEntry);
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }
                if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.STEM_DELETE)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.STEM_DELETE.values()) {
                        correctMap.setAttribute(changeLogLabel, changeLogEntry);
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }
                if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.STEM_UPDATE)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.STEM_UPDATE.values()) {
                        // a runtime exception is thrown here, see ChangeLogLabels.STEM_UPDATE.displayExtension
                        if (changeLogLabel.name().equals(ChangeLogLabels.STEM_UPDATE.displayExtension.name())) {
                            continue;
                        }
                        correctMap.setAttribute(changeLogLabel, changeLogEntry);
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }
                if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.PRIVILEGE_DELETE)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.PRIVILEGE_DELETE.values()) {
                        correctMap.setAttribute(changeLogLabel, changeLogEntry);
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }

                // verify that the correct attributes are returned from the data connector for every change log entry
                runResolveTest(changeLogDataConnector,
                        ChangeLogDataConnector.principalName(changeLogEntry.getSequenceNumber()), correctMap);
            }
        }
    }

    /**
     * Test filter by change log entry category and action.
     */
    public void testFilterChangeLogEntry() {

        // initialize the data connector
        changeLogDataConnector = (ChangeLogDataConnector) gContext.getBean("testFilterChangeLogEntry");

        // retrieve all change log entries
        List<ChangeLogEntry> changeLogEntryList = GrouperDAOFactory.getFactory().getChangeLogEntry()
                .retrieveBatch(-1, 1000);

        // for every change log entry
        for (ChangeLogEntry changeLogEntryFromList : changeLogEntryList) {

            ChangeLogEntry changeLogEntry = GrouperDAOFactory.getFactory().getChangeLogEntry()
                    .findBySequenceNumber(changeLogEntryFromList.getSequenceNumber(), false);

            // the empty map
            AttributeMap correctMap = new AttributeMap();

            // if change log entry matches, build correct map
            if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.MEMBERSHIP_DELETE)) {
                // for every field in the change log entry, add the corresponding attribute to the map
                for (ChangeLogLabel changeLogLabel : ChangeLogLabels.MEMBERSHIP_DELETE.values()) {
                    correctMap.setAttribute(changeLogLabel.name(),
                            changeLogEntry.retrieveValueForLabel(changeLogLabel));
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }
            }

            // verify that the correct attributes are returned from the data connector for every change log entry
            runResolveTest(changeLogDataConnector,
                    ChangeLogDataConnector.principalName(changeLogEntry.getSequenceNumber()), correctMap);
        }
    }

    /**
     * Test filter by change log action only.
     */
    public void testFilterChangeLogEntryAction() {

        // initialize the data connector
        changeLogDataConnector = (ChangeLogDataConnector) gContext.getBean("testFilterChangeLogEntryAction");

        // retrieve all change log entries
        List<ChangeLogEntry> changeLogEntryList = GrouperDAOFactory.getFactory().getChangeLogEntry()
                .retrieveBatch(-1, 1000);

        // for every change log entry
        for (ChangeLogEntry changeLogEntryFromList : changeLogEntryList) {

            ChangeLogEntry changeLogEntry = GrouperDAOFactory.getFactory().getChangeLogEntry()
                    .findBySequenceNumber(changeLogEntryFromList.getSequenceNumber(), false);

            // the empty map
            AttributeMap correctMap = new AttributeMap();

            // if change log entry matches, build correct map
            if (changeLogEntry.getChangeLogType().getActionName().equals("deleteMembership")) {
                // for every field in the change log entry, add the corresponding attribute to the map
                for (ChangeLogLabel changeLogLabel : ChangeLogLabels.MEMBERSHIP_DELETE.values()) {
                    correctMap.setAttribute(changeLogLabel.name(),
                            changeLogEntry.retrieveValueForLabel(changeLogLabel));
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }
            }

            // verify that the correct attributes are returned from the data connector for every change log entry
            runResolveTest(changeLogDataConnector,
                    ChangeLogDataConnector.principalName(changeLogEntry.getSequenceNumber()), correctMap);
        }
    }

    /**
     * Test filter by change log category only.
     */
    public void testFilterChangeLogEntryCategory() {

        changeLogDataConnector = (ChangeLogDataConnector) gContext.getBean("testFilterChangeLogEntryCategory");

        // retrieve all change log entries
        List<ChangeLogEntry> changeLogEntryList = GrouperDAOFactory.getFactory().getChangeLogEntry()
                .retrieveBatch(-1, 1000);

        // for every change log entry
        for (ChangeLogEntry changeLogEntryFromList : changeLogEntryList) {

            ChangeLogEntry changeLogEntry = GrouperDAOFactory.getFactory().getChangeLogEntry()
                    .findBySequenceNumber(changeLogEntryFromList.getSequenceNumber(), false);

            // the empty map
            AttributeMap correctMap = new AttributeMap();

            // if change log entry matches, build correct map
            if (changeLogEntry.getChangeLogType().getChangeLogCategory().equals("membership")) {
                // for every field in the change log entry, add the corresponding attribute to the map
                if (changeLogEntry.getChangeLogType()
                        .equalsCategoryAndAction(ChangeLogTypeBuiltin.MEMBERSHIP_DELETE)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.MEMBERSHIP_DELETE.values()) {
                        correctMap.setAttribute(changeLogLabel.name(),
                                changeLogEntry.retrieveValueForLabel(changeLogLabel));
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }
                if (changeLogEntry.getChangeLogType()
                        .equalsCategoryAndAction(ChangeLogTypeBuiltin.MEMBERSHIP_ADD)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.MEMBERSHIP_ADD.values()) {
                        correctMap.setAttribute(changeLogLabel.name(),
                                changeLogEntry.retrieveValueForLabel(changeLogLabel));
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }
            }

            // verify that the correct attributes are returned from the data connector for every change log entry
            runResolveTest(changeLogDataConnector,
                    ChangeLogDataConnector.principalName(changeLogEntry.getSequenceNumber()), correctMap);
        }
    }

    /**
     * Test filter by change log category and action and audit category and action.
     */
    public void testFilterDeleteMembership() {

        groupB.deleteMember(SubjectTestHelper.SUBJ1);

        ChangeLogTempToEntity.convertRecords();

        changeLogDataConnector = (ChangeLogDataConnector) gContext.getBean("testFilterDeleteMembership");

        // retrieve all change log entries
        List<ChangeLogEntry> changeLogEntryList = GrouperDAOFactory.getFactory().getChangeLogEntry()
                .retrieveBatch(-1, 1000);

        // for every change log entry
        for (ChangeLogEntry changeLogEntryFromList : changeLogEntryList) {

            ChangeLogEntry changeLogEntry = GrouperDAOFactory.getFactory().getChangeLogEntry()
                    .findBySequenceNumber(changeLogEntryFromList.getSequenceNumber(), false);

            // the empty map
            AttributeMap correctMap = new AttributeMap();

            // if change log entry matches, build correct map
            boolean match = false;

            List<AuditEntry> auditEntries = new UserAuditQuery()
                    .setExtraCriterion(Restrictions.eq(AuditEntry.FIELD_CONTEXT_ID, changeLogEntry.getContextId()))
                    .execute();

            if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.MEMBERSHIP_DELETE)) {
                for (AuditEntry auditEntry : auditEntries) {
                    if (!(auditEntry.getAuditType().getActionName().equals("deleteGroup")
                            && auditEntry.getAuditType().getAuditCategory().equals("group"))) {
                        match = true;
                        break;
                    }
                }
            }

            if (match) {
                if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.MEMBERSHIP_DELETE)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.MEMBERSHIP_DELETE.values()) {
                        correctMap.setAttribute(changeLogLabel.name(),
                                changeLogEntry.retrieveValueForLabel(changeLogLabel));
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }
            }

            // verify that the correct attributes are returned from the data connector for every change log entry
            runResolveTest(changeLogDataConnector,
                    ChangeLogDataConnector.principalName(changeLogEntry.getSequenceNumber()), correctMap);
        }
    }

    /**
     * Test filter by change log category and action and audit category and action. Should not match any entries.
     */
    public void testFilterDeleteMembershipNoMatch() {

        changeLogDataConnector = (ChangeLogDataConnector) gContext.getBean("testFilterDeleteMembership");

        // retrieve all change log entries
        List<ChangeLogEntry> changeLogEntryList = GrouperDAOFactory.getFactory().getChangeLogEntry()
                .retrieveBatch(-1, 1000);

        // for every change log entry
        for (ChangeLogEntry changeLogEntryFromList : changeLogEntryList) {

            ChangeLogEntry changeLogEntry = GrouperDAOFactory.getFactory().getChangeLogEntry()
                    .findBySequenceNumber(changeLogEntryFromList.getSequenceNumber(), false);

            // the empty map
            AttributeMap correctMap = new AttributeMap();

            // if change log entry matches, build correct map
            boolean match = false;

            List<AuditEntry> auditEntries = new UserAuditQuery()
                    .setExtraCriterion(Restrictions.eq(AuditEntry.FIELD_CONTEXT_ID, changeLogEntry.getContextId()))
                    .execute();

            if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.MEMBERSHIP_DELETE)) {
                for (AuditEntry auditEntry : auditEntries) {
                    if (!(auditEntry.getAuditType().getActionName().equals("deleteGroup")
                            && auditEntry.getAuditType().getAuditCategory().equals("group"))) {
                        match = true;
                        break;
                    }
                }
            }

            if (match) {
                if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.GROUP_DELETE)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.GROUP_DELETE.values()) {
                        correctMap.setAttribute(changeLogLabel.name(),
                                changeLogEntry.retrieveValueForLabel(changeLogLabel));
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }
                if (changeLogEntry.equalsCategoryAndAction(ChangeLogTypeBuiltin.MEMBERSHIP_DELETE)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.MEMBERSHIP_DELETE.values()) {
                        correctMap.setAttribute(changeLogLabel.name(),
                                changeLogEntry.retrieveValueForLabel(changeLogLabel));
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                }
            }

            // verify that the correct attributes are returned from the data connector for every change log entry
            runResolveTest(changeLogDataConnector,
                    ChangeLogDataConnector.principalName(changeLogEntry.getSequenceNumber()), correctMap);
        }
    }

    /**
     * Test filter by change log exact attribute.
     */
    public void testFilterChangeLogExactAttribute() {

        // initialize the data connector
        changeLogDataConnector = (ChangeLogDataConnector) gContext.getBean("testFilterChangeLogExactAttribute");

        // retrieve all change log entries
        List<ChangeLogEntry> changeLogEntryList = GrouperDAOFactory.getFactory().getChangeLogEntry()
                .retrieveBatch(-1, 1000);

        // for every change log entry
        for (ChangeLogEntry changeLogEntryFromList : changeLogEntryList) {

            ChangeLogEntry changeLogEntry = GrouperDAOFactory.getFactory().getChangeLogEntry()
                    .findBySequenceNumber(changeLogEntryFromList.getSequenceNumber(), false);

            // the empty map
            AttributeMap correctMap = new AttributeMap();

            // if change log entry matches, build correct map
            if (changeLogEntry.getChangeLogType().getActionName().equals("updateStem")) {
                // for every field in the change log entry, add the corresponding attribute to the map

                for (ChangeLogLabel changeLogLabel : ChangeLogLabels.STEM_UPDATE.values()) {
                    try {
                        correctMap.setAttribute(changeLogLabel.name(),
                                changeLogEntry.retrieveValueForLabel(changeLogLabel));
                    } catch (RuntimeException e) {
                        // do not blame me
                    }
                }
            }

            // verify that the correct attributes are returned from the data connector for every change log entry
            runResolveTest(changeLogDataConnector,
                    ChangeLogDataConnector.principalName(changeLogEntry.getSequenceNumber()), correctMap);
        }
    }

    /**
     * Test filter by change log attribute assign type.
     */
    public void testFilterChangeLogAttributeAssignType() {

        groupB.getAttributeValueDelegate().assignValuesString("parentStem:mailAlternateAddress",
                GrouperUtil.toSet("foo@example.edu"), true);

        childStem.getAttributeValueDelegate().assignValuesString("parentStem:mailAlternateAddress",
                GrouperUtil.toSet("bar@example.edu"), true);

        ChangeLogTempToEntity.convertRecords();

        // initialize the data connector
        changeLogDataConnector = (ChangeLogDataConnector) gContext
                .getBean("testFilterChangeLogAttributeAssignType");

        // retrieve all change log entries
        List<ChangeLogEntry> changeLogEntryList = GrouperDAOFactory.getFactory().getChangeLogEntry()
                .retrieveBatch(-1, 1000);

        // for every change log entry
        for (ChangeLogEntry changeLogEntryFromList : changeLogEntryList) {

            ChangeLogEntry changeLogEntry = GrouperDAOFactory.getFactory().getChangeLogEntry()
                    .findBySequenceNumber(changeLogEntryFromList.getSequenceNumber(), false);

            // the empty map
            AttributeMap correctMap = new AttributeMap();

            // if change log entry matches, build correct map
            if (changeLogEntry.getChangeLogType().getActionName().equals("addAttributeAssignValue")) {
                String attributeAssignId = changeLogEntry.retrieveValueForLabel("attributeAssignId");
                AttributeAssign attributeAssign = AttributeAssignFinder.findById(attributeAssignId, false);

                if (attributeAssign.getAttributeAssignType().equals(AttributeAssignType.group)) {
                    for (ChangeLogLabel changeLogLabel : ChangeLogLabels.ATTRIBUTE_ASSIGN_VALUE_ADD.values()) {
                        correctMap.setAttribute(changeLogLabel, changeLogEntry);
                    }
                    addChangeLogAttributesToMap(correctMap, changeLogEntry);
                    correctMap.setAttribute("parentStem:mailAlternateAddress", "foo@example.edu");
                    correctMap.setAttribute("name", "parentStem:groupB");
                    correctMap.setAttribute("attributeAssignType", "group");
                }
            }

            // verify that the correct attributes are returned from the data connector for every change log entry
            runResolveTest(changeLogDataConnector,
                    ChangeLogDataConnector.principalName(changeLogEntry.getSequenceNumber()), correctMap);
        }
    }

}