All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.identityconnectors.contract.test.SyncApiOpTests Maven / Gradle / Ivy

The newest version!
/*
 * ====================
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of the Common Development
 * and Distribution License("CDDL") (the "License").  You may not use this file
 * except in compliance with the License.
 *
 * You can obtain a copy of the License at
 * http://opensource.org/licenses/cddl1.php
 * See the License for the specific language governing permissions and limitations
 * under the License.
 *
 * When distributing the Covered Code, include this CDDL Header Notice in each file
 * and include the License file at http://opensource.org/licenses/cddl1.php.
 * If applicable, add the following below this CDDL Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 * ====================
 * Portions Copyrighted 2010-2013 ForgeRock AS.
 * Portions Copyrighted 2018 ConnId
 */
package org.identityconnectors.contract.test;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.identityconnectors.common.logging.Log;
import org.identityconnectors.contract.exceptions.ObjectNotFoundException;
import org.identityconnectors.framework.api.operations.APIOperation;
import org.identityconnectors.framework.api.operations.CreateApiOp;
import org.identityconnectors.framework.api.operations.DeleteApiOp;
import org.identityconnectors.framework.api.operations.SyncApiOp;
import org.identityconnectors.framework.api.operations.UpdateApiOp;
import org.identityconnectors.framework.common.objects.Attribute;
import org.identityconnectors.framework.common.objects.AttributeUtil;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.SyncDelta;
import org.identityconnectors.framework.common.objects.SyncDeltaType;
import org.identityconnectors.framework.common.objects.SyncToken;
import org.identityconnectors.framework.common.objects.Uid;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

/**
 * Contract test of {@link SyncApiOp}.
 */
public class SyncApiOpTests extends ObjectClassRunner {

    private static final Log LOG = Log.getLog(SyncApiOpTests.class);

    public static final String TEST_NAME = "Sync";

    public static final String MODIFIED = "modified";

    /*
     * Properties' prefixes to disable particular sync change types.
     * (Some connectors are capable to sync only ie. CREATEs)
     */
    private static final String DISABLE = "disable";

    private static final String CREATE_PREFIX = "create";

    private static final String UPDATE_PREFIX = "update";

    private static final String DELETE_PREFIX = "delete";

    /**
     * {@inheritDoc}
     */
    @Override
    public Set> getAPIOperations() {
        Set> s = new HashSet<>();
        // list of required operations by this test:
        s.add(SyncApiOp.class);
        s.add(CreateApiOp.class);
        return s;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void testRun(ObjectClass objectClass) {
        Uid uid = null;

        try {
            // start synchronizing from now
            SyncToken token = getConnectorFacade().getLatestSyncToken(objectClass);

            /* CREATE: */
            // create record
            Set attrs = ConnectorHelper.getCreateableAttributes(getDataProvider(),
                    getObjectClassInfo(objectClass), getTestName(), 0, true, false);
            uid = getConnectorFacade().create(objectClass, attrs,
                    getOperationOptionsByOp(objectClass, CreateApiOp.class));
            assertNotNull(uid, "Create returned null uid.");

            if (canSyncAfterOp(CreateApiOp.class)) {
                // sync after create
                List deltas = ConnectorHelper.sync(getConnectorFacade(), objectClass, token,
                        getOperationOptionsByOp(objectClass, SyncApiOp.class));

                // check that returned one delta
                String msg = "Sync should have returned one sync delta after creation of one object, but returned: %d";
                assertTrue(deltas.size() == 1, String.format(msg, deltas.size()));

                // check delta
                ConnectorHelper.checkSyncDelta(
                        getObjectClassInfo(objectClass), deltas.get(0), uid, attrs, SyncDeltaType.CREATE_OR_UPDATE, true);

                token = deltas.get(0).getToken();
            }

            /* UPDATE: */
            if (ConnectorHelper.operationSupported(getConnectorFacade(), UpdateApiOp.class)
                    && canSyncAfterOp(UpdateApiOp.class)) {

                Set replaceAttributes = ConnectorHelper.getUpdateableAttributes(
                        getDataProvider(), getObjectClassInfo(objectClass), getTestName(), MODIFIED, 0, false,
                        false);

                // update only in case there is something to update
                if (!replaceAttributes.isEmpty()) {
                    replaceAttributes.add(uid);

                    assertTrue((!replaceAttributes.isEmpty()), "no update attributes were found");
                    Uid newUid = getConnectorFacade().update(
                            objectClass, uid, AttributeUtil.filterUid(replaceAttributes),
                            getOperationOptionsByOp(objectClass, UpdateApiOp.class));

                    // Update change of Uid must be propagated to
                    // replaceAttributes
                    if (!newUid.equals(uid)) {
                        replaceAttributes.remove(uid);
                        replaceAttributes.add(newUid);
                        uid = newUid;
                    }

                    // sync after update
                    List deltas = ConnectorHelper.sync(getConnectorFacade(), objectClass, token,
                            getOperationOptionsByOp(objectClass, SyncApiOp.class));

                    // check that returned one delta
                    String msg =
                            "Sync should have returned one sync delta after update of one object, but returned: %d";
                    assertTrue(deltas.size() == 1, String.format(msg, deltas.size()));

                    // check delta
                    ConnectorHelper.checkSyncDelta(getObjectClassInfo(objectClass), deltas.get(0), uid,
                            replaceAttributes, SyncDeltaType.CREATE_OR_UPDATE, true);

                    token = deltas.get(0).getToken();
                }
            }

            /* DELETE: */
            if (canSyncAfterOp(DeleteApiOp.class)) {
                // delete object
                getConnectorFacade().delete(objectClass, uid,
                        getOperationOptionsByOp(objectClass, DeleteApiOp.class));

                // sync after delete
                List deltas = ConnectorHelper.sync(getConnectorFacade(), objectClass, token,
                        getOperationOptionsByOp(objectClass, SyncApiOp.class));

                // check that returned one delta
                String msg = "Sync should have returned one sync delta after delete of one object, but returned: %d";
                assertTrue(deltas.size() == 1, String.format(msg, deltas.size()));

                // check delta
                ConnectorHelper.checkSyncDelta(
                        getObjectClassInfo(objectClass), deltas.get(0), uid, null, SyncDeltaType.DELETE, true);
            }
        } finally {
            // cleanup test data
            ConnectorHelper.deleteObject(getConnectorFacade(), objectClass, uid,
                    false, getOperationOptionsByOp(objectClass, DeleteApiOp.class));
        }
    }

    /**
     * Test Sync without attrsToGet.
     */
    @ParameterizedTest
    @MethodSource("objectClasses")
    public void testSyncWithoutAttrsToGet(ObjectClass objectClass) {
        // run the test only if sync is supported and also object class is
        // supported and connector can sync CREATEs
        if (ConnectorHelper.operationsSupported(getConnectorFacade(), objectClass, getAPIOperations())
                && canSyncAfterOp(CreateApiOp.class)) {
            Uid uid = null;
            try {
                // start synchronizing from now
                SyncToken token = getConnectorFacade().getLatestSyncToken(objectClass);

                // create record
                Set attrs = ConnectorHelper.getCreateableAttributes(getDataProvider(),
                        getObjectClassInfo(objectClass), getTestName(), 1, true, false);
                uid = getConnectorFacade().create(objectClass, attrs, null);
                assertNotNull(uid, "Create returned null uid.");

                List deltas = ConnectorHelper.sync(getConnectorFacade(), objectClass, token, null);

                // check that returned one delta
                final String MSG =
                        "Sync should have returned one sync delta after creation of one object, but returned: %d";
                assertTrue(deltas.size() == 1, String.format(MSG, deltas.size()));

                // check delta, but don't check attributes which are not returned by default
                ConnectorHelper.checkSyncDelta(getObjectClassInfo(objectClass), deltas.get(0), uid, attrs,
                        SyncDeltaType.CREATE_OR_UPDATE, false);
            } finally {
                // cleanup
                getConnectorFacade().delete(objectClass, uid, null);
            }
        } else {
            LOG.info("----------------------------------------------------------------------------------------");
            LOG.info("Skipping test ''testSyncWithoutAttrsToGet'' for object class ''" + objectClass + "''.");
            LOG.info("----------------------------------------------------------------------------------------");
        }
    }

    /**
     * Tests that {@link SyncApiOp#getLatestSyncToken(ObjectClass)} returns really the latest sync token which is
     * available.
     */
    @ParameterizedTest
    @MethodSource("objectClasses")
    public void testLatestSyncToken(ObjectClass objectClass) {
        // run the test only if sync is supported by the tested object class
        if (ConnectorHelper.operationsSupported(getConnectorFacade(), objectClass, getAPIOperations())
                && canSyncAfterOp(CreateApiOp.class)) {
            Uid uid1 = null;
            Uid uid2 = null;
            try {
                // create one new object
                Set attrs1 = ConnectorHelper.getCreateableAttributes(getDataProvider(),
                        getObjectClassInfo(objectClass), getTestName(), 2, true, false);
                uid1 = getConnectorFacade().create(objectClass, attrs1, null);
                assertNotNull(uid1, "Create returned null uid.");

                // get latest sync token
                SyncToken latestToken = getConnectorFacade().getLatestSyncToken(objectClass);

                // sync with latest sync token, should return nothing
                final LinkedList deltas = new LinkedList<>();
                getConnectorFacade().sync(objectClass, latestToken, (SyncDelta delta) -> {
                    deltas.add(delta);
                    return true;
                }, null);

                String msg1 = "Sync with previously retrieved latest sync token should not return any deltas, "
                        + "but returned: %d.";
                assertTrue(deltas.isEmpty(), String.format(msg1, deltas.size()));

                // create another object
                Set attrs2 = ConnectorHelper.getCreateableAttributes(getDataProvider(),
                        getObjectClassInfo(objectClass), getTestName(), 3, true, false);
                uid2 = getConnectorFacade().create(objectClass, attrs2, null);
                assertNotNull(uid2, "Create returned null uid.");

                // sync with the same latest sync token as previous sync
                // should return one change this time
                getConnectorFacade().sync(objectClass, latestToken, (SyncDelta delta) -> {
                    deltas.add(delta);
                    return true;
                }, null);

                String msg2 = "Sync with latest sync token retrieved before one create should return one sync delta, "
                        + "but returned: %d";
                assertTrue(deltas.size() == 1, String.format(msg2, deltas.size()));

                ConnectorHelper.checkSyncDelta(getObjectClassInfo(objectClass), deltas.get(0), uid2, attrs2,
                        SyncDeltaType.CREATE_OR_UPDATE, false);
            } finally {
                // cleanup
                getConnectorFacade().delete(objectClass, uid1, null);
                getConnectorFacade().delete(objectClass, uid2, null);
            }
        } else {
            LOG.info("----------------------------------------------------------------------------------------");
            LOG.info("Skipping test ''testLatestSyncToken'' for object class ''" + objectClass + "''.");
            LOG.info("----------------------------------------------------------------------------------------");
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String getTestName() {
        return TEST_NAME;
    }

    /**
     * Returns true if tests are configured to test connector's sync after specified operation.
     * Some connectors implement sync but are not capable to sync all changes' types.
     */
    protected static boolean canSyncAfterOp(Class operation) {
        // by default it's supposed that sync works for all change types
        Boolean canSync = true;
        try {
            if (operation.equals(CreateApiOp.class)) {
                canSync = !(Boolean) getDataProvider().getTestSuiteAttribute(
                        DISABLE + "." + CREATE_PREFIX, TEST_NAME);
            } else if (operation.equals(UpdateApiOp.class)) {
                canSync = !(Boolean) getDataProvider().getTestSuiteAttribute(
                        DISABLE + "." + UPDATE_PREFIX, TEST_NAME);
            } else if (operation.equals(DeleteApiOp.class)) {
                canSync = !(Boolean) getDataProvider().getTestSuiteAttribute(
                        DISABLE + "." + DELETE_PREFIX, TEST_NAME);
            }
        } catch (ObjectNotFoundException ex) {
            // exceptions is throw in case property definition is not found
            // ok
        }

        return canSync;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy