Skip to content

Commit

Permalink
Add test and workaround for MID-6122
Browse files Browse the repository at this point in the history
When modifying primary delta we sometimes need to clean up lens
and focus context appropriately. (Normally this should be ensured
by rot() method but it is not.)

So here we provide a test for MID-6122, showing appropriate workaround.

See MID-6132 as well.

Here we also include a small fix for tracing script variables/results.
  • Loading branch information
mederly committed Mar 23, 2020
1 parent 4486a4e commit 90644c4
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 47 deletions.
Expand Up @@ -8,6 +8,7 @@
package com.evolveum.midpoint.schema.util;

import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismPropertyValue;
import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.util.DebugDumpable;
import com.evolveum.midpoint.util.PrettyPrinter;
Expand Down Expand Up @@ -58,10 +59,15 @@ public static NamedValueType toNamedValueType(Object object, QName name, PrismCo
private static void setAnyValueTypeContent(Object object, AnyValueType anyValue, PrismContext prismContext) {
if (object instanceof PrismValue) {
PrismValue prismValue = (PrismValue) object;
if (prismValue.hasRealClass()) {
setAnyValueReal(prismValue.getRealValue(), anyValue, prismContext);
boolean emptyEmbeddedValue = prismValue instanceof PrismPropertyValue && ((PrismPropertyValue) prismValue).getValue() == null;
if (emptyEmbeddedValue) {
// very strange case - let's simply skip it; there's nothing to store to AnyValueType here
} else {
setAnyValueDynamic(prismValue, anyValue, prismContext);
if (prismValue.hasRealClass()) {
setAnyValueReal(prismValue.getRealValue(), anyValue, prismContext);
} else {
setAnyValueDynamic(prismValue, anyValue, prismContext);
}
}
} else {
setAnyValueReal(object, anyValue, prismContext);
Expand Down Expand Up @@ -94,7 +100,7 @@ public static boolean isAtLeastNormal(TracingLevelType level) {
return isAtLeast(level, TracingLevelType.NORMAL);
}

public static boolean isAtLeast(TracingLevelType level, @NotNull TracingLevelType threshold) {
private static boolean isAtLeast(TracingLevelType level, @NotNull TracingLevelType threshold) {
return level != null && level.ordinal() >= threshold.ordinal();
}
}
Expand Up @@ -36,7 +36,6 @@
import com.evolveum.midpoint.prism.util.PrismTestUtil;
import com.evolveum.midpoint.prism.xml.XmlTypeConverter;
import com.evolveum.midpoint.schema.ObjectDeltaOperation;
import com.evolveum.midpoint.schema.constants.MidPointConstants;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.MiscSchemaUtil;
Expand All @@ -53,6 +52,7 @@
* @author semancik
* @see TestValidityRecomputeTask
*/
@SuppressWarnings({ "FieldCanBeLocal", "unused", "SameParameterValue", "SimplifiedTestNGAssertion" })
@ContextConfiguration(locations = { "classpath:ctx-model-intest-test-main.xml" })
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
public class TestActivation extends AbstractInitializedModelIntegrationTest {
Expand All @@ -61,21 +61,20 @@ public class TestActivation extends AbstractInitializedModelIntegrationTest {

// This resource does not support native activation. It has simulated activation instead.
// + unusual validTo and validFrom mappings
protected static final File RESOURCE_DUMMY_KHAKI_FILE = new File(TEST_DIR, "resource-dummy-khaki.xml");
protected static final String RESOURCE_DUMMY_KHAKI_OID = "10000000-0000-0000-0000-0000000a1004";
protected static final String RESOURCE_DUMMY_KHAKI_NAME = "khaki";
protected static final String RESOURCE_DUMMY_KHAKI_NAMESPACE = MidPointConstants.NS_RI;
private static final File RESOURCE_DUMMY_KHAKI_FILE = new File(TEST_DIR, "resource-dummy-khaki.xml");
private static final String RESOURCE_DUMMY_KHAKI_OID = "10000000-0000-0000-0000-0000000a1004";
private static final String RESOURCE_DUMMY_KHAKI_NAME = "khaki";

// This resource does not support native activation. It has simulated activation instead.
// + unusual validTo and validFrom mappings
protected static final File RESOURCE_DUMMY_CORAL_FILE = new File(TEST_DIR, "resource-dummy-coral.xml");
protected static final String RESOURCE_DUMMY_CORAL_OID = "10000000-0000-0000-0000-0000000b1004";
protected static final String RESOURCE_DUMMY_CORAL_NAME = "coral";
private static final File RESOURCE_DUMMY_CORAL_FILE = new File(TEST_DIR, "resource-dummy-coral.xml");
private static final String RESOURCE_DUMMY_CORAL_OID = "10000000-0000-0000-0000-0000000b1004";
private static final String RESOURCE_DUMMY_CORAL_NAME = "coral";

private static final TestResource RESOURCE_DUMMY_PRECREATE = new TestResource(TEST_DIR, "resource-dummy-precreate.xml", "f18711a2-5db5-4562-b50d-3ef4c74f2e1d");
private static final String RESOURCE_DUMMY_PRECREATE_NAME = "precreate";

protected static final String ACCOUNT_MANCOMB_DUMMY_USERNAME = "mancomb";
private static final String ACCOUNT_MANCOMB_DUMMY_USERNAME = "mancomb";
private static final Date ACCOUNT_MANCOMB_VALID_FROM_DATE = MiscUtil.asDate(2011, 2, 3, 4, 5, 6);
private static final Date ACCOUNT_MANCOMB_VALID_TO_DATE = MiscUtil.asDate(2066, 5, 4, 3, 2, 1);
private static final String SUSPENDED_ATTRIBUTE_NAME = "suspended";
Expand All @@ -84,24 +83,23 @@ public class TestActivation extends AbstractInitializedModelIntegrationTest {
private String accountRedOid;
private String accountYellowOid;
private XMLGregorianCalendar lastValidityChangeTimestamp;
private String accountMancombOid;
private String userMancombOid;
private XMLGregorianCalendar manana;

protected DummyResource dummyResourceKhaki;
protected DummyResourceContoller dummyResourceCtlKhaki;
protected ResourceType resourceDummyKhakiType;
protected PrismObject<ResourceType> resourceDummyKhaki;
private DummyResource dummyResourceKhaki;
private DummyResourceContoller dummyResourceCtlKhaki;
private ResourceType resourceDummyKhakiType;
private PrismObject<ResourceType> resourceDummyKhaki;

protected DummyResource dummyResourceCoral;
protected DummyResourceContoller dummyResourceCtlCoral;
protected ResourceType resourceDummyCoralType;
protected PrismObject<ResourceType> resourceDummyCoral;
private DummyResource dummyResourceCoral;
private DummyResourceContoller dummyResourceCtlCoral;
private ResourceType resourceDummyCoralType;
private PrismObject<ResourceType> resourceDummyCoral;

protected DummyResource dummyResourcePrecreate;
protected DummyResourceContoller dummyResourceCtlPrecreate;
protected ResourceType resourceDummyPrecreateType;
protected PrismObject<ResourceType> resourceDummyPrecreate;
private DummyResource dummyResourcePrecreate;
private DummyResourceContoller dummyResourceCtlPrecreate;
private ResourceType resourceDummyPrecreateType;
private PrismObject<ResourceType> resourceDummyPrecreate;

@Override
public void initSystem(Task initTask, OperationResult initResult)
Expand Down Expand Up @@ -1617,8 +1615,8 @@ public void test212SeeLargoTomorrow() throws Exception {
OperationResult result = task.getResult();

// Let's play with the clock, move the time to tomorrow
long crrentNow = System.currentTimeMillis() + 24 * 60 * 60 * 1000;
clock.override(crrentNow);
long currentNow = System.currentTimeMillis() + 24 * 60 * 60 * 1000;
clock.override(currentNow);

// WHEN
recomputeUser(USER_LARGO_OID, task, result);
Expand Down Expand Up @@ -1656,8 +1654,8 @@ public void test213HastaLaMananaLargo() throws Exception {
OperationResult result = task.getResult();

// Let's play with the clock, move the time forward 20 days
long crrentNow = System.currentTimeMillis() + 20 * 24 * 60 * 60 * 1000;
clock.override(crrentNow);
long currentNow = System.currentTimeMillis() + 20 * 24 * 60 * 60 * 1000;
clock.override(currentNow);

// WHEN
modelService.recompute(UserType.class, USER_LARGO_OID, null, task, result);
Expand All @@ -1667,7 +1665,7 @@ public void test213HastaLaMananaLargo() throws Exception {
display("User after change execution", userLargo);

assertValidity(userLargo, TimeIntervalStatusType.AFTER);
assertValidityTimestamp(userLargo, crrentNow);
assertValidityTimestamp(userLargo, currentNow);
assertEffectiveStatus(userLargo, ActivationStatusType.DISABLED);

assertUser(userLargo, USER_LARGO_OID, USER_LARGO_USERNAME, "Largo LaGrande", "Largo", "LaGrande");
Expand Down Expand Up @@ -2060,7 +2058,6 @@ public void test300AddDummyGreenAccountMancomb() throws Exception {
display("Account after", dummyAccountAfter);

assertNotNull("No mancomb account shadow", accountMancomb);
accountMancombOid = accountMancomb.getOid();
assertEquals("Wrong resourceRef in mancomb account", RESOURCE_DUMMY_GREEN_OID,
accountMancomb.asObjectable().getResourceRef().getOid());
assertValidFrom(accountMancomb, ACCOUNT_MANCOMB_VALID_FROM_DATE);
Expand Down Expand Up @@ -2282,27 +2279,27 @@ public void test515OrgScummBarRecompute() throws Exception {
}

@Test
public void test520CheckSerivceSeaMonkeyInitial() throws Exception {
public void test520CheckServiceSeaMonkeyInitial() throws Exception {
test5X0CheckInitial(ServiceType.class, SERVICE_SHIP_SEA_MONKEY_OID);
}

@Test
public void test521SerivceSeaMonkeyRecompute() throws Exception {
public void test521ServiceSeaMonkeyRecompute() throws Exception {
test5X1Recompute(ServiceType.class, SERVICE_SHIP_SEA_MONKEY_OID);
}

@Test
public void test522ModifySerivceSeaMonkeyDisable() throws Exception {
public void test522ModifyServiceSeaMonkeyDisable() throws Exception {
test5X2ModifyDisable(ServiceType.class, SERVICE_SHIP_SEA_MONKEY_OID);
}

@Test
public void test524ModifySerivceSeaMonkeyEnable() throws Exception {
public void test524ModifyServiceSeaMonkeyEnable() throws Exception {
test5X4ModifyEnable(ServiceType.class, SERVICE_SHIP_SEA_MONKEY_OID);
}

@Test
public void test525SerivceSeaMonkeyRecompute() throws Exception {
public void test525ServiceSeaMonkeyRecompute() throws Exception {
test5X5Recompute(ServiceType.class, SERVICE_SHIP_SEA_MONKEY_OID);
}

Expand Down Expand Up @@ -2408,7 +2405,7 @@ private <F extends FocusType> void test5X4ModifyEnable(Class<F> type, String oid
/**
* Make sure that recompute does not destroy anything.
*/
public <F extends FocusType> void test5X5Recompute(Class<F> type, String oid) throws Exception {
private <F extends FocusType> void test5X5Recompute(Class<F> type, String oid) throws Exception {
given();
Task task = getTestTask();
OperationResult result = task.getResult();
Expand Down Expand Up @@ -2446,8 +2443,8 @@ public void test600AddUser1() throws Exception {
.item(UserType.F_NAME).replace(new PolyString("user1"))
.item(UserType.F_ASSIGNMENT).add(ObjectTypeUtil.createAssignmentTo(resourceDummyCoral, prismContext).asPrismContainerValue())
.item(ACTIVATION_ADMINISTRATIVE_STATUS_PATH).replace(ActivationStatusType.DISABLED)
.asObjectDelta(null)
.applyTo((PrismObject) user1);
.<UserType>asObjectDelta(null)
.applyTo(user1);

ObjectDelta<UserType> addDelta = user1.createAddDelta();

Expand Down Expand Up @@ -2681,6 +2678,52 @@ public void test750AddAndDeleteUserWithPrecreate() throws Exception {
assertSuccess(result, 2);
}


/**
* If an invalid assignment is being deleted, we don't want to update its effectiveStatus (because the resulting replace
* delta would collide with assignment delete delta). Normally midPoint ensures this behavior. So this test is not
* strictly necessary.
*
* This test was introduced as part of MID-6122 diagnosis and is kept only as "to be sure". In MID-6122 the deltas collision
* was caused by adding assignment delete delta in the model scripting hook.
*/
@Test
public void test800DeleteInvalidAssignment() throws Exception {
given();
Task task = getTestTask();
OperationResult result = task.getResult();

setDefaultObjectTemplate(UserType.COMPLEX_TYPE, null, result);

XMLGregorianCalendar dayBeforeYesterday = XmlTypeConverter.fromNow("-P2D");
XMLGregorianCalendar yesterday = XmlTypeConverter.fromNow("-P1D");

UserType user = new UserType(prismContext)
.name("test800")
.beginAssignment()
.targetRef(ROLE_SUPERUSER_OID, RoleType.COMPLEX_TYPE)
.beginActivation()
.effectiveStatus(ActivationStatusType.ENABLED)
.validFrom(dayBeforeYesterday)
.validTo(yesterday)
.<AssignmentType>end()
.end();
repoAddObject(user.asPrismObject(), result);

when();
ObjectDelta<UserType> delta = deltaFor(UserType.class)
.item(UserType.F_ASSIGNMENT).delete(user.getAssignment().get(0).clone())
.asObjectDelta(user.getOid());
executeChanges(delta, null, task, result);

then();
result.computeStatus();
assertSuccess(result);
assertUser(user.getOid(), "after")
.display()
.assertAssignments(0);
}

private void assertDummyActivationEnabledState(String userId, Boolean expectedEnabled) throws SchemaViolationException, ConflictException, InterruptedException {
assertDummyActivationEnabledState(null, userId, expectedEnabled);
}
Expand Down
Expand Up @@ -10,6 +10,12 @@

import java.io.File;

import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.prism.xml.XmlTypeConverter;

import com.evolveum.midpoint.repo.api.RepoAddOptions;

import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;
Expand All @@ -24,29 +30,33 @@
import com.evolveum.midpoint.test.DummyResourceContoller;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import javax.xml.datatype.XMLGregorianCalendar;

/**
* @author Radovan Semancik
*/
@SuppressWarnings({ "FieldCanBeLocal", "unused" })
@ContextConfiguration(locations = { "classpath:ctx-model-intest-test-main.xml" })
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
public class TestScriptHooks extends AbstractInitializedModelIntegrationTest {

private static final File TEST_DIR = new File("src/test/resources/scripthooks");

protected static final File RESOURCE_DUMMY_HOOK_FILE = new File(TEST_DIR, "resource-dummy-hook.xml");
protected static final String RESOURCE_DUMMY_HOOK_OID = "10000000-0000-0000-0000-000004444001";
protected static final String RESOURCE_DUMMY_HOOK_NAME = "hook";
private static final File RESOURCE_DUMMY_HOOK_FILE = new File(TEST_DIR, "resource-dummy-hook.xml");
private static final String RESOURCE_DUMMY_HOOK_OID = "10000000-0000-0000-0000-000004444001";
private static final String RESOURCE_DUMMY_HOOK_NAME = "hook";

private static final File ORG_TOP_FILE = new File(TEST_DIR, "org-top.xml");

private static final File GENERIC_BLACK_PEARL_FILE = new File(TEST_DIR, "generic-blackpearl.xml");

private static final File SYSTEM_CONFIGURATION_HOOKS_FILE = new File(TEST_DIR, "system-configuration-hooks.xml");
private static final File SYSTEM_CONFIGURATION_PRIMARY_DELTA_HOOK_FILE = new File(TEST_DIR, "system-configuration-primary-delta-hook.xml");

protected DummyResource dummyResourceHook;
protected DummyResourceContoller dummyResourceCtlHook;
protected ResourceType resourceDummyHookType;
protected PrismObject<ResourceType> resourceDummyHook;
private DummyResource dummyResourceHook;
private DummyResourceContoller dummyResourceCtlHook;
private ResourceType resourceDummyHookType;
private PrismObject<ResourceType> resourceDummyHook;

@Override
public void initSystem(Task initTask, OperationResult initResult) throws Exception {
Expand Down Expand Up @@ -166,4 +176,47 @@ public void test110JackAddOrganization() throws Exception {
StaticHookRecorder.assertInvocationCount("bar", 10);
StaticHookRecorder.assertInvocationCount("bar-user", 1);
}

/**
* MID-6122
*/
@Test
public void test200DeleteAssignment() throws Exception {
given();
Task task = getTestTask();
OperationResult result = task.getResult();

XMLGregorianCalendar dayBeforeYesterday = XmlTypeConverter.fromNow("-P2D");
XMLGregorianCalendar yesterday = XmlTypeConverter.fromNow("-P1D");

PrismObject<ObjectType> newConfiguration = prismContext.parseObject(SYSTEM_CONFIGURATION_PRIMARY_DELTA_HOOK_FILE);
repositoryService.addObject(newConfiguration, RepoAddOptions.createOverwrite(), result);

UserType user = new UserType(prismContext)
.name("test200")
.beginAssignment()
.targetRef(ROLE_SUPERUSER_OID, RoleType.COMPLEX_TYPE)
.subtype("fragile")
.beginActivation()
.effectiveStatus(ActivationStatusType.ENABLED)
.validFrom(dayBeforeYesterday)
.validTo(yesterday)
.<AssignmentType>end()
.end();
repoAddObject(user.asPrismObject(), result);

when();
ObjectDelta<UserType> delta = deltaFor(UserType.class)
.item(UserType.F_FULL_NAME).replace(PolyString.fromOrig("new-name"))
.asObjectDelta(user.getOid());
executeChanges(delta, null, task, result);

then();
result.computeStatus();
assertSuccess(result);
assertUser(user.getOid(), "after")
.display()
.assertAssignments(0)
.assertFullName("new-name");
}
}

0 comments on commit 90644c4

Please sign in to comment.