Skip to content

Commit

Permalink
Add support for sync reaction lifecycle state
Browse files Browse the repository at this point in the history
This resolves MID-8671, at least on the backend.
(The GUI support is to be added yet.)
  • Loading branch information
mederly committed Mar 24, 2023
1 parent 1303c89 commit 29488ed
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@

package com.evolveum.midpoint.schema.processor;

import com.evolveum.midpoint.schema.TaskExecutionMode;
import com.evolveum.midpoint.schema.util.SimulationUtil;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.exception.ConfigurationException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;
import java.util.stream.Collectors;
Expand All @@ -28,6 +31,7 @@ public class SynchronizationReactionDefinition implements Comparable<Synchroniza

private final Integer order;
private final String name;
@Nullable private final String lifecycleState;
@NotNull private final Set<SynchronizationSituationType> situations;
@NotNull private final Collection<String> channels;
private final ExpressionType condition;
Expand All @@ -43,6 +47,7 @@ private SynchronizationReactionDefinition(
throws ConfigurationException {
this.order = null;
this.name = legacyBean.getName();
this.lifecycleState = null;
this.situations = Set.of(
MiscUtil.requireNonNull(
legacyBean.getSituation(),
Expand Down Expand Up @@ -84,6 +89,7 @@ private SynchronizationReactionDefinition(
@NotNull SynchronizationReactionType bean, @NotNull ClockworkSettings syncLevelSettings) {
this.order = bean.getOrder();
this.name = bean.getName();
this.lifecycleState = bean.getLifecycleState();
this.situations = new HashSet<>(bean.getSituation());
this.channels = bean.getChannel();
this.condition = bean.getCondition();
Expand Down Expand Up @@ -179,4 +185,8 @@ public String toString() {
", # of actions: " + actions.size() +
'}';
}

public boolean isVisible(TaskExecutionMode mode) {
return SimulationUtil.isVisible(lifecycleState, mode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5157,6 +5157,7 @@
</xsd:element>
<xsd:element ref="tns:description" minOccurs="0"/>
<xsd:element ref="tns:documentation" minOccurs="0"/>
<xsd:element ref="tns:lifecycleState" minOccurs="0"/>
<xsd:element name="order" type="xsd:int" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.evolveum.midpoint.repo.common.expression.ExpressionEnvironmentThreadLocalHolder;

import com.evolveum.midpoint.schema.GetOperationOptionsBuilder;
import com.evolveum.midpoint.schema.TaskExecutionMode;
import com.evolveum.midpoint.schema.processor.ResourceObjectTypeIdentification;
import com.evolveum.midpoint.schema.util.ShadowUtil;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
Expand Down Expand Up @@ -104,6 +105,12 @@ private SynchronizationReactionDefinition getReaction(OperationResult result)

SynchronizationReactionDefinition defaultReaction = null;
for (SynchronizationReactionDefinition reactionToConsider : policy.getReactions()) {
TaskExecutionMode executionMode = syncCtx.getTask().getExecutionMode();
if (!reactionToConsider.isVisible(executionMode)) {
LOGGER.trace("Skipping {} because it is not visible for current task execution mode: {}",
reactionToConsider, executionMode);
continue;
}
if (!reactionToConsider.matchesSituation(currentSituation)) {
LOGGER.trace("Skipping {} because the situation does not match: {}", reactionToConsider, currentSituation);
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,60 @@ public void test230ImportWithError() throws Exception {
displayValueAsXml("processed object", processedObject.toBean());
}

/**
* There is a synchronization reaction in `proposed` state.
* It should be ignored in production mode.
*
* MID-8671
*/
@Test
public void test240ExecutingDevelopmentModeSyncReaction() throws Exception {
Task task = getTestTask();
OperationResult result = task.getResult();

String name = "test240";
ResourceObjectTypeIdentification employeeTypeId =
ResourceObjectTypeIdentification.of(ShadowKindType.ACCOUNT, "employee");

given("an account on production source with an imported user");
var account = RESOURCE_SIMPLE_PRODUCTION_SOURCE.addAccount(name);
account.addAttributeValue(ATTR_TYPE, "employee");
account.addAttributeValue(ATTR_EMPLOYEE_NUMBER, "11111");

and("its imported owner");
importAccountsRequest()
.withResourceOid(RESOURCE_SIMPLE_PRODUCTION_SOURCE.oid)
.withTypeIdentification(employeeTypeId)
.withNameValue(name)
.executeOnForeground(result);
assertUserBeforeByUsername(name);

when("the account is deleted and the simulated reconciliation is run");
RESOURCE_SIMPLE_PRODUCTION_SOURCE.controller.deleteAccount(name);
var taskOid = reconcileAccountsRequest()
.withResourceOid(RESOURCE_SIMPLE_PRODUCTION_SOURCE.oid)
.withTaskExecutionMode(getExecutionMode())
.withTypeIdentification(employeeTypeId)
.withNameValue(name)
.withNotAssertingSuccess()
.execute(result);

then("the user still exists");
assertUserAfterByUsername(name);

boolean actionVisible = isDevelopmentConfigurationSeen();
and(actionVisible ? "simulation result contains user deletion" : "simulation result does NOT contain user deletion");
var a = assertProcessedObjects(taskOid, "after")
.display();
if (actionVisible) {
a.by().objectType(ShadowType.class).state(ObjectProcessingStateType.UNMODIFIED).find().end()
.by().objectType(UserType.class).state(ObjectProcessingStateType.DELETED).find().end()
.assertSize(2);
} else {
a.assertSize(0); // Even the shadow is not visible, because the clockwork was not executed
}
}

/**
* Creates a user of archetype `person`, with a rich (conditional) configuration:
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1729,6 +1729,8 @@ public void test320ReconcileDummyAzureDeleteOtis() throws Exception {
then();

Task taskAfter = waitForTaskFinish(TASK_RECONCILE_DUMMY_AZURE.oid, false);
assertTask(taskAfter, "after")
.assertSuccess();

dumpStatistics(taskAfter);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@
</actions>
</reaction>
<reaction>
<lifecycleState>proposed</lifecycleState> <!-- MID-8671 -->
<situation>deleted</situation>
<actions>
<deleteFocus/>
Expand Down

0 comments on commit 29488ed

Please sign in to comment.