Skip to content

Commit

Permalink
Add sim. tests for linking/assigning accounts
Browse files Browse the repository at this point in the history
  • Loading branch information
mederly committed Dec 8, 2022
1 parent 91b46b0 commit 24484e7
Show file tree
Hide file tree
Showing 10 changed files with 385 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ public abstract class SchemaConstants {
public static final ItemPath PATH_AUTOASSIGN_ENABLED = ItemPath
.create(AbstractRoleType.F_AUTOASSIGN, AutoassignSpecificationType.F_ENABLED);
public static final ItemPath PATH_PARENT_ORG_REF = ItemPath.create(ObjectType.F_PARENT_ORG_REF);
public static final ItemPath PATH_METADATA_LAST_PROVISIONING_TIMESTAMP = ItemPath.create(ObjectType.F_METADATA, MetadataType.F_LAST_PROVISIONING_TIMESTAMP);
public static final ItemPath PATH_METADATA_MODIFY_TIMESTAMP = ItemPath.create(ObjectType.F_METADATA, MetadataType.F_MODIFY_TIMESTAMP);
public static final ItemPath PATH_METADATA_MODIFY_CHANNEL = ItemPath.create(ObjectType.F_METADATA, MetadataType.F_MODIFY_CHANNEL);
public static final ItemPath PATH_METADATA_MODIFIER_REF = ItemPath.create(ObjectType.F_METADATA, MetadataType.F_MODIFIER_REF);
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,20 @@
package com.evolveum.midpoint.model.intest.simulation;

import com.evolveum.midpoint.model.intest.AbstractEmptyModelIntegrationTest;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.schema.ObjectDeltaOperation;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.test.DummyTestResource;
import com.evolveum.midpoint.util.exception.CommonException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import java.io.File;

import static com.evolveum.midpoint.schema.constants.SchemaConstants.RI_ACCOUNT_OBJECT_CLASS;

public class AbstractSimulationsTest extends AbstractEmptyModelIntegrationTest {

private static final File SIM_TEST_DIR = new File("src/test/resources/simulation");
Expand Down Expand Up @@ -48,4 +56,44 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti
RESOURCE_SIMPLE_PRODUCTION_SOURCE.initAndTest(this, initTask, initResult);
RESOURCE_SIMPLE_DEVELOPMENT_SOURCE.initAndTest(this, initTask, initResult);
}

private ShadowType createAccount(DummyTestResource target) {
return new ShadowType()
.resourceRef(target.oid, ResourceType.COMPLEX_TYPE)
.objectClass(RI_ACCOUNT_OBJECT_CLASS)
.kind(ShadowKindType.ACCOUNT)
.intent("default");
// Name should be computed by mappings
}

ObjectReferenceType createLinkRefWithFullObject(DummyTestResource target) {
return ObjectTypeUtil.createObjectRefWithFullObject(
createAccount(target));
}

String addUser(String name, Task task, OperationResult result) throws CommonException {
UserType user = new UserType()
.name(name);

var executed =
executeChanges(user.asPrismObject().createAddDelta(), null, task, result);
return ObjectDeltaOperation.findFocusDeltaOidInCollection(executed);
}

ObjectDelta<UserType> createLinkRefDelta(String userOid, DummyTestResource target) throws SchemaException {
return deltaFor(UserType.class)
.item(UserType.F_LINK_REF)
.add(createLinkRefWithFullObject(target))
.asObjectDelta(userOid);
}

ObjectDelta<UserType> createAssignmentDelta(String userOid, DummyTestResource target) throws SchemaException {
return deltaFor(UserType.class)
.item(UserType.F_ASSIGNMENT)
.add(new AssignmentType()
.construction(
new ConstructionType()
.resourceRef(target.oid, ResourceType.COMPLEX_TYPE)))
.asObjectDelta(userOid);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public void test110SimpleCreateOnDemandSimulation() throws Exception {
assertCollectedCounts(counts, task, result);

and("there are simulation deltas");
simResult.assertNoExecutedDeltas();
simResult.assertNoExecutedNorAuditedDeltas();
List<ObjectDelta<?>> simulatedDeltas = simResult.getSimulatedDeltas();
displayCollection("simulated deltas", simulatedDeltas);
// TODO some asserts here
Expand Down Expand Up @@ -232,7 +232,7 @@ public void test160CreateOnDemandForOrgAndRoleSimulated() throws Exception {
assertCollectedCounts(counts, task, result);

and("there are simulation deltas");
simResult.assertNoExecutedDeltas();
simResult.assertNoExecutedNorAuditedDeltas();
List<ObjectDelta<?>> simulatedDeltas = simResult.getSimulatedDeltas();
displayCollection("simulated deltas", simulatedDeltas);
// TODO some asserts here
Expand Down Expand Up @@ -267,7 +267,7 @@ public void test200CreateOnDemandWithProvisioning() throws Exception {
assertCollectedCounts(counts, task, result);

and("there are simulation deltas");
simResult.assertNoExecutedDeltas();
simResult.assertNoExecutedNorAuditedDeltas();
List<ObjectDelta<?>> simulatedDeltas = simResult.getSimulatedDeltas();
displayCollection("simulated deltas", simulatedDeltas);
// TODO some asserts here
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,19 @@
*/
package com.evolveum.midpoint.model.intest.simulation;

import static com.evolveum.midpoint.schema.constants.SchemaConstants.RI_ACCOUNT_OBJECT_CLASS;

import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;
import org.testng.annotations.Test;

import com.evolveum.midpoint.model.test.ObjectsCounter;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.exception.CommonException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

/**
* Real execution of operations against development-mode components.
*
* Currently fails.
*/
@ContextConfiguration(locations = { "classpath:ctx-model-intest-test-main.xml" })
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
Expand All @@ -45,9 +40,7 @@ public void test100CreateUserWithLinkedDevelopmentAccount() throws Exception {
given("a user");
UserType user = new UserType()
.name("test100")
.linkRef(
ObjectTypeUtil.createObjectRefWithFullObject(
createAccount()));
.linkRef(createLinkRefWithFullObject(RESOURCE_SIMPLE_DEVELOPMENT_TARGET));

when("user is created");
executeChanges(user.asPrismObject().createAddDelta(), null, task, result);
Expand All @@ -59,15 +52,6 @@ public void test100CreateUserWithLinkedDevelopmentAccount() throws Exception {
// TODO add audit asserts
}

private ShadowType createAccount() {
return new ShadowType()
.resourceRef(RESOURCE_SIMPLE_DEVELOPMENT_TARGET.oid, ResourceType.COMPLEX_TYPE)
.objectClass(RI_ACCOUNT_OBJECT_CLASS)
.kind(ShadowKindType.ACCOUNT)
.intent("default");
// Name should be computed by mappings
}

private void assertSuccessAndNoShadow(String username, OperationResult result) throws CommonException {
then("everything is OK");
assertSuccess(result);
Expand Down Expand Up @@ -111,4 +95,72 @@ public void test110CreateUserWithAssignedDevelopmentAccount() throws Exception {
displayDumpable("audit", dummyAuditService);
// TODO add audit asserts
}

/**
* Link an account "by value" on development-mode resource.
*
* As {@link #test100CreateUserWithLinkedDevelopmentAccount()} but the user is pre-existing.
*/
@Test
public void test120LinkDevelopmentAccount() throws Exception {
Task task = getTestTask();
OperationResult result = task.getResult();

given("a user is in repository");
String userOid = addUser("test120", task, result);

objectsCounter.remember(result);
dummyAuditService.clear();

when("account is linked");
executeChanges(
createLinkRefDelta(userOid, RESOURCE_SIMPLE_DEVELOPMENT_TARGET),
null, task, result);

// TODO Maybe we should report at least warning or partial error, because the (requested) linkRef was not created.
assertSuccessAndNoNewObjects("test120", result);

displayDumpable("audit", dummyAuditService);
// TODO add audit asserts
// There is a SYNCHRONIZATION/EXECUTION event ... why?
}

/**
* Assign an account on development-mode resource.
*
* As {@link #test110CreateUserWithAssignedDevelopmentAccount()} but the user is pre-existing.
*/
@Test
public void test130AssignDevelopmentAccount() throws Exception {
Task task = getTestTask();
OperationResult result = task.getResult();

given("a user is in repository");
String userOid = addUser("test130", task, result);

objectsCounter.remember(result);
dummyAuditService.clear();

when("account is assigned");
executeChanges(
createAssignmentDelta(userOid, RESOURCE_SIMPLE_DEVELOPMENT_TARGET),
null, task, result);

assertSuccessAndNoNewObjects("test130", result);

displayDumpable("audit", dummyAuditService);
// TODO add audit asserts
}

private void assertSuccessAndNoNewObjects(String name, OperationResult result) throws CommonException {
then("everything is OK");
assertSuccess(result);

and("no new objects should be there");
objectsCounter.assertNoNewObjects(result);

and("the user is OK, no linkRef");
assertUserAfterByUsername(name)
.assertLinks(0, 0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6987,8 +6987,10 @@ protected SimulationResult executeInSimulationMode(

SimulationResult simulationResult = new SimulationResult(simulationResultContext);
AggregatedObjectProcessingListener testObjectProcessingListener = simulationResult.aggregatedObjectProcessingListener();
DummyAuditEventListener auditEventListener = simulationResult.auditEventListener();
TaskExecutionMode oldMode = task.setExecutionMode(mode);
try {
dummyAuditService.addEventListener(auditEventListener);
task.addObjectProcessingListener(testObjectProcessingListener);
if (simulationObjectProcessingListener != null) {
task.addObjectProcessingListener(simulationObjectProcessingListener);
Expand All @@ -6999,6 +7001,7 @@ protected SimulationResult executeInSimulationMode(
if (simulationObjectProcessingListener != null) {
task.removeObjectProcessingListener(simulationObjectProcessingListener);
}
dummyAuditService.removeEventListener(auditEventListener);
task.setExecutionMode(oldMode);
}
return simulationResult;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
import com.evolveum.midpoint.model.api.context.ModelContext;
import com.evolveum.midpoint.model.api.simulation.SimulationResultContext;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.schema.ObjectDeltaOperation;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.AggregatedObjectProcessingListener;
import com.evolveum.midpoint.test.DummyAuditEventListener;
import com.evolveum.midpoint.util.annotation.Experimental;

import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;

Expand All @@ -37,6 +38,7 @@ public class SimulationResult {

@Nullable private final SimulationResultContext simulationResultContext;
private final List<ObjectDelta<?>> executedDeltas = new ArrayList<>();
private final List<ObjectDeltaOperation<?>> auditedDeltas = new ArrayList<>();
private final List<ObjectDelta<?>> simulatedDeltas = new ArrayList<>();
private ModelContext<?> lastModelContext;

Expand Down Expand Up @@ -74,6 +76,10 @@ AggregatedObjectProcessingListener aggregatedObjectProcessingListener() {
return this::onItemProcessed;
}

DummyAuditEventListener auditEventListener() {
return record -> auditedDeltas.addAll(record.getDeltas());
}

private <O extends ObjectType> void onItemProcessed(
@Nullable O stateBefore,
@Nullable ObjectDelta<O> executedDelta,
Expand All @@ -87,12 +93,13 @@ private <O extends ObjectType> void onItemProcessed(
}
}

public void assertNoExecutedDeltas() {
public void assertNoExecutedNorAuditedDeltas() {
// This is a bit fake. We currently do not report executed deltas using onItemProcessed method.
assertThat(executedDeltas).as("executed deltas").isEmpty();
}

public @Nullable SimulationResultContext getSimulationResultContext() {
return simulationResultContext;
// In a similar way, auditing is currently explicitly turned off in non-persistent mode. Nevertheless, this
// could catch situations when (e.g. embedded) clockwork is executed in persistent mode.
assertThat(auditedDeltas).as("audited deltas").isEmpty();
}

public Collection<ObjectDelta<?>> getStoredDeltas(OperationResult result) throws SchemaException {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright (C) 2010-2022 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/

package com.evolveum.midpoint.test;

import com.evolveum.midpoint.audit.api.AuditEventRecord;

/**
* Used for non-invasive observing audit records being emitted.
*/
public interface DummyAuditEventListener {

void onAudit(AuditEventRecord record);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.*;
import javax.xml.datatype.Duration;

import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -54,6 +55,8 @@ public class DummyAuditService implements AuditService, DebugDumpable {
*/
private final List<AuditEventRecord> records = new ArrayList<>();

private final Set<DummyAuditEventListener> listeners = Sets.newConcurrentHashSet();

// This is to be able to be able to disable this service for some tests e.g. to prevent memory leaks
// TODO consider introducing auto-cleanup mechanism for this
private boolean enabled = true;
Expand All @@ -75,6 +78,9 @@ public synchronized void audit(AuditEventRecord record, Task task, OperationResu
}
}
records.add(record.clone());
for (DummyAuditEventListener listener : listeners) {
listener.onAudit(record);
}
}
}

Expand Down Expand Up @@ -575,4 +581,12 @@ public SearchResultMetadata searchObjectsIterative(
@NotNull OperationResult parentResult) throws SchemaException {
throw new UnsupportedOperationException("searchObjectsIterative not supported");
}

public void addEventListener(DummyAuditEventListener listener) {
listeners.add(listener);
}

public void removeEventListener(DummyAuditEventListener listener) {
listeners.remove(listener);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,17 @@ public ObjectDeltaAsserter<O,RA> assertModifications(int expected) {
return this;
}

/** Asserts that the specified paths are modified (among other ones - optionally). */
public ObjectDeltaAsserter<O,RA> assertModifiedPaths(ItemPath... expectedPaths) {
return assertModifiedPaths(false, expectedPaths);
}

/** Asserts that the set of modified paths is exactly the same as expected. */
public ObjectDeltaAsserter<O,RA> assertModifiedPathsStrict(ItemPath... expectedPaths) {
return assertModifiedPaths(true, expectedPaths);
}

private ObjectDeltaAsserter<O,RA> assertModifiedPaths(boolean strict, ItemPath... expectedPaths) {
assertModify();
PathSet actualPathSet = delta.getModifications().stream()
.map(modification -> modification.getPath())
Expand All @@ -104,9 +114,11 @@ public ObjectDeltaAsserter<O,RA> assertModifiedPaths(ItemPath... expectedPaths)
fail("Expected path '" + expected + "' is not among actually modified paths: " + actualPathSet);
}
}
for (ItemPath actualPath : actualPathSet) {
if (!expectedPathSet.contains(actualPath)) {
fail("Actual path '" + actualPath + "' is not among expected modified paths: " + expectedPathSet);
if (strict) {
for (ItemPath actualPath : actualPathSet) {
if (!expectedPathSet.contains(actualPath)) {
fail("Actual path '" + actualPath + "' is not among expected modified paths: " + expectedPathSet);
}
}
}
return this;
Expand Down

0 comments on commit 24484e7

Please sign in to comment.