Skip to content

Commit

Permalink
Add a test for simulated import on foreground
Browse files Browse the repository at this point in the history
Important change (not tested yet): BaseClockworkAction no longer invokes
"previewChanges" in simulated modes. It now always calls executeChanges.
  • Loading branch information
mederly committed Dec 7, 2022
1 parent 555dbcb commit 9b296bb
Show file tree
Hide file tree
Showing 11 changed files with 250 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@
import com.evolveum.midpoint.prism.ItemDefinitionResolver;
import com.evolveum.midpoint.prism.query.builder.S_FilterExit;
import com.evolveum.midpoint.prism.query.builder.S_MatchingRuleEntry;
import com.evolveum.midpoint.schema.processor.ResourceObjectDefinition;
import com.evolveum.midpoint.schema.processor.ResourceObjectTypeDefinition;
import com.evolveum.midpoint.schema.processor.ResourceSchema;
import com.evolveum.midpoint.schema.processor.ResourceSchemaFactory;
import com.evolveum.midpoint.schema.processor.*;
import com.evolveum.midpoint.util.annotation.Experimental;
import com.evolveum.midpoint.util.exception.ConfigurationException;
import com.evolveum.midpoint.util.exception.SchemaException;
Expand Down Expand Up @@ -92,6 +89,11 @@ public static Resource of(@NotNull PrismObject<ResourceType> resourceObject) {
return schema != null ? schema.getObjectTypeDefinitions() : List.of();
}

public @NotNull S_MatchingRuleEntry queryFor(@NotNull ResourceObjectTypeIdentification typeIdentification)
throws SchemaException, ConfigurationException {
return queryFor(typeIdentification.getKind(), typeIdentification.getIntent());
}

public @NotNull S_MatchingRuleEntry queryFor(@NotNull ShadowKindType kind, @NotNull String intent)
throws SchemaException, ConfigurationException {
ResourceObjectDefinition objectDefinition =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import com.evolveum.midpoint.schema.processor.ResourceObjectTypeIdentification;
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.QNameUtil;
import com.evolveum.midpoint.util.exception.CommonException;
import com.evolveum.midpoint.util.exception.SchemaException;
Expand Down Expand Up @@ -67,13 +66,7 @@ public void handle(@NotNull OperationResult parentResult) throws CommonException

beans.medic.enterModelMethod(false);
try {
Task task = syncCtx.getTask();
// Temporary code - we'll have a single entry point in the future
if (task.isPersistentExecution()) {
beans.clockwork.run(lensContext, task, result);
} else {
beans.clockwork.previewChanges(lensContext, null, task, result);
}
beans.clockwork.run(lensContext, syncCtx.getTask(), result);
} finally {
beans.medic.exitModelMethod(false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ public class ImportFromResourceLauncher {
@Autowired private PrismContext prismContext;
@Autowired private TaskManager taskManager;

public boolean importSingleShadow(String shadowOid, Task task, OperationResult parentResult) throws ObjectNotFoundException,
CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException {
public boolean importSingleShadow(String shadowOid, Task task, OperationResult parentResult)
throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException,
SecurityViolationException, ExpressionEvaluationException {
OperationResult result = parentResult.createSubresult(OP_IMPORT_SINGLE_SHADOW);
try {
ShadowType shadow = provisioningService
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class AbstractSimulationsTest extends AbstractEmptyModelIntegrationTest {
"resource-simple-production-target.xml",
"3f8d6dee-9663-496f-a718-b3c27234aca7",
"simple-production-target");
private static final DummyTestResource RESOURCE_SIMPLE_PRODUCTION_SOURCE = new DummyTestResource(
static final DummyTestResource RESOURCE_SIMPLE_PRODUCTION_SOURCE = new DummyTestResource(
SIM_TEST_DIR,
"resource-simple-production-source.xml",
"c6caaa46-96c4-4244-883f-2771e18b82c9",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

import com.evolveum.midpoint.prism.delta.ObjectDelta;

import com.evolveum.midpoint.schema.TaskExecutionMode;

import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;
Expand Down Expand Up @@ -371,7 +373,69 @@ private void assertTest120UserAndAccountDeltas(Collection<ObjectDelta<?>> simula
* Simulated import from production source.
*/
@Test
public void test200SimulatedProductionImport() {
// TODO
public void test200SimulatedProductionImport() throws Exception {
Task task = getTestTask();
OperationResult result = task.getResult();

objectsCounter.remember(result);

given("an account on production source");
RESOURCE_SIMPLE_PRODUCTION_SOURCE.controller.addAccount("test200");

when("the account is imported");
SimulationResult simResult =
executeInProductionSimulationMode(
null,
task,
() ->
importSingleAccountRequest()
.withResourceOid(RESOURCE_SIMPLE_PRODUCTION_SOURCE.oid)
.withNameValue("test200")
.withTaskExecutionMode(TaskExecutionMode.SIMULATED_PRODUCTION)
.build()
.executeOnForeground(result));

then("no new objects should be created (except for one shadow), no model deltas really executed");
objectsCounter.assertShadowOnlyIncrement(1, result);
simResult.assertNoExecutedDeltas();

and("deltas are correct (in testing storage)");
assertTest200Deltas(simResult.getSimulatedDeltas(), "simulated deltas in testing storage");
}

private void assertTest200Deltas(Collection<ObjectDelta<?>> simulatedDeltas, String message) {
// @formatter:off
assertDeltaCollection(simulatedDeltas, message)
.display()
.by().changeType(ChangeType.ADD).objectType(UserType.class).find()
.objectToAdd()
.assertName("test200")
.objectMetadata()
.assertRequestTimestampPresent()
.assertCreateTimestampPresent()
.assertLastProvisioningTimestampPresent()
.assertCreateChannel(CHANNEL_IMPORT_URI)
.end()
.asFocus()
.activation()
.assertEffectiveStatus(ActivationStatusType.ENABLED)
.assertEnableTimestampPresent()
.end()
.end()
.end()
.by().changeType(ChangeType.MODIFY).objectType(UserType.class).find()
.assertModifiedPaths(UserType.F_LINK_REF)
.end()
.by().changeType(ChangeType.MODIFY).objectType(ShadowType.class).find()
.assertModifiedPaths( // fragile, may change when projector changes
ShadowType.F_ITERATION,
ShadowType.F_ITERATION_TOKEN,
PATH_METADATA_MODIFY_CHANNEL,
PATH_METADATA_MODIFY_TIMESTAMP,
PATH_METADATA_MODIFIER_REF,
PATH_METADATA_MODIFY_TASK_REF,
PATH_METADATA_MODIFY_APPROVER_REF,
PATH_METADATA_MODIFY_APPROVAL_COMMENT);
// @formatter:on
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6792,26 +6792,24 @@ protected String determineSingleInducedRuleId(String roleOid, OperationResult re
return roleOid + ":" + id;
}

public interface TracedFunctionCall<X> {
X execute() throws CommonException, PreconditionViolationException, IOException;
public interface FunctionCall<X> {
X execute() throws CommonException, IOException;
}

public interface TracedProcedureCall {
void execute() throws CommonException, PreconditionViolationException;
public interface ProcedureCall {
void execute() throws CommonException;
}

protected <X> X traced(TracedFunctionCall<X> tracedCall)
protected <X> X traced(FunctionCall<X> tracedCall)
throws CommonException, PreconditionViolationException, IOException {
return traced(createModelLoggingTracingProfile(), tracedCall);
}

protected void traced(TracedProcedureCall tracedCall)
throws CommonException, PreconditionViolationException {
protected void traced(ProcedureCall tracedCall) throws CommonException {
traced(createModelLoggingTracingProfile(), tracedCall);
}

public void traced(TracingProfileType profile, TracedProcedureCall tracedCall)
throws CommonException, PreconditionViolationException {
public void traced(TracingProfileType profile, ProcedureCall tracedCall) throws CommonException {
setGlobalTracingOverride(profile);
try {
tracedCall.execute();
Expand All @@ -6820,7 +6818,7 @@ public void traced(TracingProfileType profile, TracedProcedureCall tracedCall)
}
}

public <X> X traced(TracingProfileType profile, TracedFunctionCall<X> tracedCall)
public <X> X traced(TracingProfileType profile, FunctionCall<X> tracedCall)
throws CommonException, PreconditionViolationException, IOException {
setGlobalTracingOverride(profile);
try {
Expand Down Expand Up @@ -6910,37 +6908,65 @@ protected SimulationResult executeInProductionSimulationMode(
@NotNull Task task,
@NotNull OperationResult result)
throws CommonException {
return executeInSimulationMode(
TaskExecutionMode.SIMULATED_PRODUCTION,
simulationConfiguration,
task,
(simResult) ->
modelService.executeChanges(
deltas, null, task, List.of(simResult.contextRecordingListener()), result));
}

/** Convenience method */
protected SimulationResult executeInProductionSimulationMode(
@NotNull Collection<ObjectDelta<? extends ObjectType>> deltas,
@NotNull Task task,
@NotNull OperationResult result)
throws CommonException {
return executeInProductionSimulationMode(deltas, null, task, result);
}

/**
* Executes a {@link ProcedureCall} in {@link TaskExecutionMode#SIMULATED_PRODUCTION} mode.
*/
public SimulationResult executeInProductionSimulationMode(
Object simulationConfiguration, Task task, ProcedureCall simulatedCall) throws CommonException {
return executeInSimulationMode(
TaskExecutionMode.SIMULATED_PRODUCTION,
simulationConfiguration,
task,
(simResult) -> simulatedCall.execute());
}

/** As {@link ProcedureCall} but has {@link SimulationResult} as a parameter. Currently for internal purposes. */
public interface SimulatedProcedureCall {
void execute(SimulationResult simResult) throws CommonException;
}

private SimulationResult executeInSimulationMode(
TaskExecutionMode mode, Object simulationConfiguration, Task task, SimulatedProcedureCall simulatedCall)
throws CommonException {

ObjectProcessingListener simulationObjectProcessingListener =
simulationConfiguration != null ?
null : null; //simulationResultManager.createNewSimulationResult(simulationConfiguration); // TODO

SimulationResult simulationResult = new SimulationResult();
ObjectProcessingListener testObjectProcessingListener = simulationResult.objectProcessingListener();
TaskExecutionMode oldExecutionMode = task.getExecutionMode();
TaskExecutionMode oldMode = task.setExecutionMode(mode);
try {
task.setExecutionMode(TaskExecutionMode.SIMULATED_PRODUCTION);
task.addObjectProcessingListener(testObjectProcessingListener);
if (simulationObjectProcessingListener != null) {
task.addObjectProcessingListener(simulationObjectProcessingListener);
}
modelService.executeChanges(deltas, null, task, List.of(simulationResult.contextRecordingListener()), result);
simulatedCall.execute(simulationResult);
} finally {
task.removeObjectProcessingListener(testObjectProcessingListener);
if (simulationObjectProcessingListener != null) {
task.removeObjectProcessingListener(simulationObjectProcessingListener);
}
task.setExecutionMode(oldExecutionMode);
task.setExecutionMode(oldMode);
}
return simulationResult;
}

/** Convenience method */
protected SimulationResult executeInProductionSimulationMode(
@NotNull Collection<ObjectDelta<? extends ObjectType>> deltas,
@NotNull Task task,
@NotNull OperationResult result)
throws CommonException {
return executeInProductionSimulationMode(deltas, null, task, result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SystemException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;

import java.lang.reflect.Modifier;
import java.util.*;

import static com.evolveum.midpoint.util.MiscUtil.or0;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

/**
Expand Down Expand Up @@ -45,6 +48,21 @@ public void assertNoNewObjects(OperationResult result) {
assertThat(currentState).as("current objects counts").isEqualTo(lastState);
}

// FIXME provide nicer implementation
public void assertShadowOnlyIncrement(int expected, OperationResult result) {
Map<Class<? extends ObjectType>, Integer> currentState = new HashMap<>();
countObjects(currentState, result);
add(lastState, ShadowType.class, expected);
assertThat(currentState).as("current objects counts").isEqualTo(lastState);
}

@SuppressWarnings("SameParameterValue")
private void add(Map<Class<? extends ObjectType>, Integer> counts, Class<ShadowType> clazz, int increment) {
counts.compute(
clazz,
(aClass, oldValue) -> or0(oldValue) + increment);
}

private void countObjects(Map<Class<? extends ObjectType>, Integer> state, OperationResult result) {
RepositoryService repositoryService = ModelCommonBeans.get().cacheRepositoryService;
for (ObjectTypes type : ObjectTypes.values()) {
Expand Down

0 comments on commit 9b296bb

Please sign in to comment.