Skip to content

Commit

Permalink
Stabilize AbstractSynchronizationStoryTest
Browse files Browse the repository at this point in the history
These tests were unstable from the day one. The concurrent nature
of synchronization tasks led to a whole spectrum of various failures.
But we don't consider them important, because we want to concentrate
only on the basic functionality of multi-resource synchronization here.

So now we changed these tests so that concurrent execution is avoided.

Other changes:

1. Some test artifacts (tasks, sync object template) were moved from
`common` directory to test-specific `sync-story` one. This is to lessen
the potential for coupling between the tests. (They weren't used in
other tests, anyway.)

2. The test code was modernized a bit.

(cherry picked from commit 27a309f)
  • Loading branch information
mederly committed Jul 8, 2022
1 parent 4831591 commit 2ec73cb
Show file tree
Hide file tree
Showing 41 changed files with 834 additions and 1,176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,6 @@ public class AbstractConfiguredModelIntegrationTest extends AbstractEmptyModelIn
protected static final String USER_TEMPLATE_COMPLEX_INCLUDE_FILENAME = COMMON_DIR + "/user-template-complex-include.xml";
protected static final String USER_TEMPLATE_COMPLEX_INCLUDE_OID = "10000000-0000-0000-0000-000000000223";

protected static final String USER_TEMPLATE_SYNC_FILENAME = COMMON_DIR + "/user-template-sync.xml";
protected static final String USER_TEMPLATE_SYNC_OID = "10000000-0000-0000-0000-000000000333";

protected static final String USER_TEMPLATE_ORG_ASSIGNMENT_FILENAME = COMMON_DIR + "/user-template-org-assignment.xml";
protected static final String USER_TEMPLATE_ORG_ASSIGNMENT_OID = "10000000-0000-0000-0000-000000000444";

Expand Down Expand Up @@ -425,24 +422,8 @@ public class AbstractConfiguredModelIntegrationTest extends AbstractEmptyModelIn
protected static final File SERVICE_SHIP_SEA_MONKEY_FILE = new File(COMMON_DIR, "service-ship-sea-monkey.xml");
protected static final String SERVICE_SHIP_SEA_MONKEY_OID = "914b94be-1901-11e6-9269-972ee32cd8db";

protected static final String TASK_RECONCILE_DUMMY_FILENAME = COMMON_DIR + "/task-reconcile-dummy.xml";
protected static final String TASK_RECONCILE_DUMMY_OID = "10000000-0000-0000-5656-565600000004";

protected static final String TASK_RECONCILE_DUMMY_BLUE_FILENAME = COMMON_DIR + "/task-reconcile-dummy-blue.xml";
protected static final String TASK_RECONCILE_DUMMY_BLUE_OID = "10000000-0000-0000-5656-565600000204";

protected static final String TASK_RECONCILE_DUMMY_GREEN_FILENAME = COMMON_DIR + "/task-reconcile-dummy-green.xml";
protected static final String TASK_RECONCILE_DUMMY_GREEN_OID = "10000000-0000-0000-5656-565600000404";

protected static final String TASK_LIVE_SYNC_DUMMY_FILENAME = COMMON_DIR + "/task-dumy-livesync.xml";
protected static final String TASK_LIVE_SYNC_DUMMY_OID = "10000000-0000-0000-5555-555500000004";

protected static final String TASK_LIVE_SYNC_DUMMY_BLUE_FILENAME = COMMON_DIR + "/task-dumy-blue-livesync.xml";
protected static final String TASK_LIVE_SYNC_DUMMY_BLUE_OID = "10000000-0000-0000-5555-555500000204";

protected static final String TASK_LIVE_SYNC_DUMMY_GREEN_FILENAME = COMMON_DIR + "/task-dumy-green-livesync.xml";
protected static final String TASK_LIVE_SYNC_DUMMY_GREEN_OID = "10000000-0000-0000-5555-555500000404";

protected static final String TASK_VALIDITY_SCANNER_FILENAME = COMMON_DIR + "/task-validity-scanner.xml";
protected static final String TASK_VALIDITY_SCANNER_OID = "10000000-0000-0000-5555-555505060400";

Expand All @@ -452,9 +433,6 @@ public class AbstractConfiguredModelIntegrationTest extends AbstractEmptyModelIn
protected static final File TASK_MOCK_JACK_FILE = new File(COMMON_DIR, "task-mock-jack.xml");
protected static final String TASK_MOCK_JACK_OID = "10000000-0000-0000-5656-565674633311";

protected static final String TASK_DELETE_NOT_UPDATED_SHADOWS = COMMON_DIR + "/task-delete-not-updated-shadows.xml";
protected static final String TASK_DELETE_NOT_UPDATED_SHADOWS_OID = "5b2ba49f-6d4f-4618-afdf-4d138117e40a";

public static final File LOOKUP_LANGUAGES_FILE = new File(COMMON_DIR, "lookup-languages.xml");
public static final String LOOKUP_LANGUAGES_OID = "70000000-0000-0000-1111-000000000001";
public static final String LOOKUP_LANGUAGES_NAME = "Languages";
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
*/
package com.evolveum.midpoint.model.intest.sync;

import static com.evolveum.midpoint.model.intest.sync.AbstractSynchronizationStoryTest.Color.*;

import static org.testng.AssertJUnit.assertNotNull;
import static org.testng.AssertJUnit.assertNull;

import java.io.FileNotFoundException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.test.TestTask;

import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;
Expand All @@ -24,102 +28,100 @@
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.test.DummyResourceContoller;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;

/**
* @author semancik
* Besides synchronization itself here we test the shadow cleanup activity.
*
* @author semancik
*/
@ContextConfiguration(locations = {"classpath:ctx-model-intest-test-main.xml"})
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
public class TestSyncStoryUsingLiveSync extends AbstractSynchronizationStoryTest {

private static final TestTask TASK_LIVE_SYNC_DUMMY = new TestTask(
TEST_DIR, "task-live-sync-dummy.xml", "f5517850-5cd8-46dc-b40e-4816881dc171");
private static final TestTask TASK_LIVE_SYNC_DUMMY_GREEN = new TestTask(
TEST_DIR, "task-live-sync-dummy-green.xml", "bf124268-d75a-419d-95e7-00ff95c21924");
private static final TestTask TASK_LIVE_SYNC_DUMMY_BLUE = new TestTask(
TEST_DIR, "task-live-sync-dummy-blue.xml", "200c8126-b176-42c4-910d-9f469e96b27b");

private static final TestTask TASK_SHADOW_CLEANUP_GREEN = new TestTask(
TEST_DIR, "task-shadow-cleanup-green.xml", "5b2ba49f-6d4f-4618-afdf-4d138117e40a");

@Override
public void initSystem(Task initTask, OperationResult initResult) throws Exception {
super.initSystem(initTask, initResult);

getDummyResource(RESOURCE_DUMMY_GREEN_NAME).setSyncStyle(DummySyncStyle.SMART);
getDummyResource().setSyncStyle(DummySyncStyle.DUMB);
getDummyResource(RESOURCE_DUMMY_BLUE_NAME).setSyncStyle(DummySyncStyle.SMART);
}

@Override
protected String getExpectedChannel() {
return SchemaConstants.CHANNEL_LIVE_SYNC_URI;
for (TestTask task : getTaskMap().values()) {
task.initialize(this, initTask, initResult);
task.rerun(initResult); // To obtain live sync token
}

TASK_SHADOW_CLEANUP_GREEN.initialize(this, initTask, initResult);
}

@Override
protected void importSyncTask(PrismObject<ResourceType> resource) throws FileNotFoundException {
if (resource == getDummyResourceObject(RESOURCE_DUMMY_GREEN_NAME)) {
importObjectFromFile(TASK_LIVE_SYNC_DUMMY_GREEN_FILENAME);
} else if (resource == getDummyResourceObject(RESOURCE_DUMMY_BLUE_NAME)) {
importObjectFromFile(TASK_LIVE_SYNC_DUMMY_BLUE_FILENAME);
} else if (resource == getDummyResourceObject()) {
importObjectFromFile(TASK_LIVE_SYNC_DUMMY_FILENAME);
} else {
throw new IllegalArgumentException("Unknown resource "+resource);
}
protected Map<Color, TestTask> getTaskMap() {
return Map.of(
DEFAULT, TASK_LIVE_SYNC_DUMMY,
GREEN, TASK_LIVE_SYNC_DUMMY_GREEN,
BLUE, TASK_LIVE_SYNC_DUMMY_BLUE);
}

@Override
protected String getSyncTaskOid(PrismObject<ResourceType> resource) {
if (resource == getDummyResourceObject(RESOURCE_DUMMY_GREEN_NAME)) {
return TASK_LIVE_SYNC_DUMMY_GREEN_OID;
} else if (resource == getDummyResourceObject(RESOURCE_DUMMY_BLUE_NAME)) {
return TASK_LIVE_SYNC_DUMMY_BLUE_OID;
} else if (resource == getDummyResourceObject()) {
return TASK_LIVE_SYNC_DUMMY_OID;
} else {
throw new IllegalArgumentException("Unknown resource "+resource);
}
protected String getExpectedChannel() {
return SchemaConstants.CHANNEL_LIVE_SYNC_URI;
}

@Test
public void test999DeletingNotUpdatedShadowDummyGreen() throws Exception {
public void test999GreenShadowsCleanup() throws Exception {
OperationResult result = getTestOperationResult();

String ACCOUNT_JACK_DUMMY_USERNAME = "jack";
String ACCOUNT_CAROL_DUMMY_USERNAME = "carol";

// GIVEN
rememberTimeBeforeSync();
prepareNotifications();

DummyAccount accountCarol = new DummyAccount(ACCOUNT_CAROL_DUMMY_USERNAME);
accountCarol.setEnabled(true);
accountCarol.addAttributeValues(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_FULLNAME_NAME, "Carol Seepgood");
accountCarol.addAttributeValues(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_LOCATION_NAME, "Melee Island");

when("jack account is added and sync is run");
DummyAccount accountJack = new DummyAccount(ACCOUNT_JACK_DUMMY_USERNAME);
accountJack.setEnabled(true);
accountJack.addAttributeValues(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_FULLNAME_NAME, "Jack Sevenseas");
accountJack.addAttributeValues(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_LOCATION_NAME, "The Seven Seas");
getGreenResource().addAccount(accountJack);
runSyncTasks(GREEN, GREEN, GREEN); // To stabilize the situation, and eat all secondary changes related to jack's account

/// WHEN
when();
when("sleeping 10 seconds to make jack's account rot");
TimeUnit.SECONDS.sleep(10);

getDummyResource(RESOURCE_DUMMY_GREEN_NAME).addAccount(accountJack);
waitForSyncTaskNextRunAssertSuccess(getDummyResourceObject(RESOURCE_DUMMY_GREEN_NAME));
importObjectFromFile(TASK_DELETE_NOT_UPDATED_SHADOWS);
TimeUnit.SECONDS.sleep(6);
getDummyResource(RESOURCE_DUMMY_GREEN_NAME).addAccount(accountCarol);
waitForSyncTaskNextRunAssertSuccess(getDummyResourceObject(RESOURCE_DUMMY_GREEN_NAME));
suspendTask(getSyncTaskOid(getDummyResourceObject(RESOURCE_DUMMY_GREEN_NAME)));
rerunTask(TASK_DELETE_NOT_UPDATED_SHADOWS_OID);
when("carol account is added and sync is run");
DummyAccount accountCarol = new DummyAccount(ACCOUNT_CAROL_DUMMY_USERNAME);
accountCarol.setEnabled(true);
accountCarol.addAttributeValues(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_FULLNAME_NAME, "Carol Seepgood");
accountCarol.addAttributeValues(DummyResourceContoller.DUMMY_ACCOUNT_ATTRIBUTE_LOCATION_NAME, "Melee Island");
getGreenResource().addAccount(accountCarol);
runSyncTasks(GREEN);

// THEN
then();
when("cleanup task is run");
TASK_SHADOW_CLEANUP_GREEN.rerun(result);
TASK_SHADOW_CLEANUP_GREEN.assertAfter();

then("carol's account should be still there");
PrismObject<UserType> userCarol = findUserByUsername(ACCOUNT_CAROL_DUMMY_USERNAME);
display("User carol", userCarol);
assertNotNull("No carol user", userCarol);

and("jack should be gone, as the shadow is too old");
PrismObject<UserType> userJack = findUserByUsername(ACCOUNT_JACK_DUMMY_USERNAME);
display("User jack", userJack);
assertNull("User jack is not null", userJack);

// notifications
displayAllNotifications();
notificationManager.setDisabled(true);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,26 @@
*/
package com.evolveum.midpoint.model.intest.sync;

import java.io.FileNotFoundException;

import com.evolveum.midpoint.repo.common.activity.run.buckets.BucketingConfigurationOverrides;
import com.evolveum.midpoint.schema.constants.SchemaConstants;

import com.evolveum.midpoint.test.TestTask;

import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;

import com.evolveum.icf.dummy.resource.DummySyncStyle;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;

/**
* @author semancik
*
*/
@ContextConfiguration(locations = {"classpath:ctx-model-intest-test-main.xml"})
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
public class TestSyncStoryUsingReconciliation extends AbstractSynchronizationStoryTest {
public abstract class TestSyncStoryUsingReconciliation extends AbstractSynchronizationStoryTest {

@Override
protected boolean isReconciliation() {
Expand All @@ -42,41 +42,16 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti
getDummyResource(RESOURCE_DUMMY_BLUE_NAME).setSyncStyle(DummySyncStyle.NONE);

alwaysCheckTimestamp = true;
}

@Override
protected String getExpectedChannel() {
return SchemaConstants.CHANNEL_RECON_URI;
}

@Override
protected void importSyncTask(PrismObject<ResourceType> resource) throws FileNotFoundException {
if (resource == getDummyResourceObject(RESOURCE_DUMMY_GREEN_NAME)) {
importObjectFromFile(TASK_RECONCILE_DUMMY_GREEN_FILENAME);
} else if (resource == getDummyResourceObject(RESOURCE_DUMMY_BLUE_NAME)) {
importObjectFromFile(TASK_RECONCILE_DUMMY_BLUE_FILENAME);
} else if (resource == getDummyResourceObject()) {
importObjectFromFile(TASK_RECONCILE_DUMMY_FILENAME);
} else {
throw new IllegalArgumentException("Unknown resource "+resource);
BucketingConfigurationOverrides.setFreeBucketWaitIntervalOverride(100L);
for (TestTask task : getTaskMap().values()) {
task.initialize(this, initTask, initResult);
}
}

@Override
protected String getSyncTaskOid(PrismObject<ResourceType> resource) {
if (resource == getDummyResourceObject(RESOURCE_DUMMY_GREEN_NAME)) {
return TASK_RECONCILE_DUMMY_GREEN_OID;
} else if (resource == getDummyResourceObject(RESOURCE_DUMMY_BLUE_NAME)) {
return TASK_RECONCILE_DUMMY_BLUE_OID;
} else if (resource == getDummyResourceObject()) {
return TASK_RECONCILE_DUMMY_OID;
} else {
throw new IllegalArgumentException("Unknown resource "+resource);
}
}

protected int getWaitTimeout() {
return 70000;
protected String getExpectedChannel() {
return SchemaConstants.CHANNEL_RECON_URI;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,63 +6,41 @@
*/
package com.evolveum.midpoint.model.intest.sync;

import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;
import com.evolveum.midpoint.test.TestTask;

import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;

import java.io.FileNotFoundException;
import java.util.Map;

import static com.evolveum.midpoint.model.intest.sync.AbstractSynchronizationStoryTest.Color.*;

/**
* The same as TestReconTaskPartitioned but the second partition (resource reconciliation) is executed in a set of worker tasks.
* (Currently there is only a single bucket, but multiple bucket processing will be implemented shortly.)
* Uses multiple worker tasks.
*
* Shouldn't be run under H2 because of too much contention.
* Also, it takes a little longer than standard TestReconTask because of the overhead.
* Also, it takes a little longer than standard reconciliation test because of the overhead.
*
* NOTE: The utility of this test is questionable, as the synchronization story test is about the correctness
* of the synchronization algorithms themselves, not about the distribution features of the reconciliation activity.
*/
@ContextConfiguration(locations = {"classpath:ctx-model-intest-test-main.xml"})
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
public class TestSyncStoryUsingReconciliationMultiNode extends TestSyncStoryUsingReconciliationPartitioned {

protected static final String TASK_RECONCILE_DUMMY_MULTINODE_FILENAME = COMMON_DIR + "/task-reconcile-dummy-multinode.xml";
protected static final String TASK_RECONCILE_DUMMY_MULTINODE_OID = "10000000-0000-0000-565f-565600000004";

protected static final String TASK_RECONCILE_DUMMY_BLUE_MULTINODE_FILENAME = COMMON_DIR + "/task-reconcile-dummy-blue-multinode.xml";
protected static final String TASK_RECONCILE_DUMMY_BLUE_MULTINODE_OID = "10000000-0000-0000-565f-565600000204";
public class TestSyncStoryUsingReconciliationMultiNode extends TestSyncStoryUsingReconciliation {

protected static final String TASK_RECONCILE_DUMMY_GREEN_MULTINODE_FILENAME = COMMON_DIR + "/task-reconcile-dummy-green-multinode.xml";
protected static final String TASK_RECONCILE_DUMMY_GREEN_MULTINODE_OID = "10000000-0000-0000-565f-565600000404";
private static final TestTask TASK_RECONCILE_DUMMY = new TestTask(
TEST_DIR, "task-reconcile-dummy-multinode.xml", "c36de89d-5ee2-469c-935b-ff34560d4e77");
private static final TestTask TASK_RECONCILE_DUMMY_GREEN = new TestTask(
TEST_DIR, "task-reconcile-dummy-green-multinode.xml", "87100587-1f5c-468f-8e89-8731650833fd");
private static final TestTask TASK_RECONCILE_DUMMY_BLUE = new TestTask(
TEST_DIR, "task-reconcile-dummy-blue-multinode.xml", "fa8abd8d-c379-46c1-aec8-38afb1a2d469");

@SuppressWarnings("Duplicates")
@Override
protected void importSyncTask(PrismObject<ResourceType> resource) throws FileNotFoundException {
if (resource == getDummyResourceObject(RESOURCE_DUMMY_GREEN_NAME)) {
importObjectFromFile(TASK_RECONCILE_DUMMY_GREEN_MULTINODE_FILENAME);
} else if (resource == getDummyResourceObject(RESOURCE_DUMMY_BLUE_NAME)) {
importObjectFromFile(TASK_RECONCILE_DUMMY_BLUE_MULTINODE_FILENAME);
} else if (resource == getDummyResourceObject()) {
importObjectFromFile(TASK_RECONCILE_DUMMY_MULTINODE_FILENAME);
} else {
throw new IllegalArgumentException("Unknown resource "+resource);
}
}

@SuppressWarnings("Duplicates")
@Override
protected String getSyncTaskOid(PrismObject<ResourceType> resource) {
if (resource == getDummyResourceObject(RESOURCE_DUMMY_GREEN_NAME)) {
return TASK_RECONCILE_DUMMY_GREEN_MULTINODE_OID;
} else if (resource == getDummyResourceObject(RESOURCE_DUMMY_BLUE_NAME)) {
return TASK_RECONCILE_DUMMY_BLUE_MULTINODE_OID;
} else if (resource == getDummyResourceObject()) {
return TASK_RECONCILE_DUMMY_MULTINODE_OID;
} else {
throw new IllegalArgumentException("Unknown resource "+resource);
}
}

protected int getWaitTimeout() {
return 300000;
protected Map<Color, TestTask> getTaskMap() {
return Map.of(
DEFAULT, TASK_RECONCILE_DUMMY,
GREEN, TASK_RECONCILE_DUMMY_GREEN,
BLUE, TASK_RECONCILE_DUMMY_BLUE);
}
}

0 comments on commit 2ec73cb

Please sign in to comment.