Skip to content

Commit

Permalink
Fixing replace delta merge bug (MID-3028)
Browse files Browse the repository at this point in the history
  • Loading branch information
semancik committed May 16, 2016
1 parent 4c6416d commit 3a3671f
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 14 deletions.
Expand Up @@ -1029,9 +1029,8 @@ public void merge(ItemDelta<V,D> deltaToMerge) {
}

private void removeEmptySets() {
if (valuesToReplace != null && valuesToReplace.isEmpty()) {
valuesToReplace = null;
}
// Do not remove replace set, even if it is empty.
// Empty replace set is not the same as no replace set
if (valuesToAdd != null && valuesToAdd.isEmpty()) {
valuesToAdd = null;
}
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2015 Evolveum
* Copyright (c) 2010-2016 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -351,6 +351,32 @@ public void testPropertyDeltaMerge12() throws Exception {
PrismAsserts.assertNoAdd(delta1);
PrismAsserts.assertNoDelete(delta1);
}

@Test
public void testPropertyDeltaMerge13() throws Exception {
System.out.println("\n\n===[ testPropertyDeltaMerge13 ]===\n");

// GIVEN
PrismPropertyDefinition propertyDefinition = new PrismPropertyDefinition(UserType.F_DESCRIPTION,
DOMUtil.XSD_STRING, PrismTestUtil.getPrismContext());

PropertyDelta<String> delta1 = new PropertyDelta<String>(propertyDefinition, PrismTestUtil.getPrismContext());
delta1.setValuesToReplace(new PrismPropertyValue<String>("r1x"));

PropertyDelta<String> delta2 = new PropertyDelta<String>(propertyDefinition, PrismTestUtil.getPrismContext());
delta2.addValueToDelete(new PrismPropertyValue<String>("r1x"));

// WHEN
delta1.merge(delta2);

// THEN
System.out.println("Merged delta:");
System.out.println(delta1.debugDump());

PrismAsserts.assertReplace(delta1);
PrismAsserts.assertNoAdd(delta1);
PrismAsserts.assertNoDelete(delta1);
}

@Test
public void testPropertyDeltaMerge20() throws Exception {
Expand Down
Expand Up @@ -934,6 +934,7 @@ public static <V extends PrismValue, D extends ItemDefinition, F extends FocusTy
Mapping<V,D> mapping = mappingFactory.createMapping(mappingType, contextDesc);

if (!mapping.isApplicableToChannel(context.getChannel())) {
LOGGER.trace("Mapping {} not applicable to channel {}, skipping.", mapping, context.getChannel());
return null;
}

Expand Down Expand Up @@ -963,6 +964,7 @@ public static <V extends PrismValue, D extends ItemDefinition, F extends FocusTy
&& mapping.getStrength() == MappingStrengthType.WEAK) {
// This valueConstruction only applies if the property does not have a value yet.
// ... but it does
LOGGER.trace("Mapping {} is weak and focus already has a value {}, skipping.", mapping, existingUserItem);
return null;
}
}
Expand Down
Expand Up @@ -61,6 +61,7 @@
import com.evolveum.midpoint.repo.api.RepositoryService;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.DebugUtil;
import com.evolveum.midpoint.util.exception.ExpressionEvaluationException;
import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
Expand Down Expand Up @@ -146,6 +147,10 @@ public <F extends FocusType> void processTemplate(LensContext<F> context, Object

XMLGregorianCalendar nextRecomputeTime = collectTripleFromTemplate(context, objectTemplate, phase, focusOdo, outputTripleMap,
iteration, iterationToken, now, objectTemplate.toString(), task, result);

if (LOGGER.isTraceEnabled()) {
LOGGER.trace("outputTripleMap before item delta computation:\n{}", DebugUtil.debugDumpMapMultiLine(outputTripleMap));
}

Collection<ItemDelta<?,?>> itemDeltas = computeItemDeltas(outputTripleMap, itemDefinitionsMap, focusOdo, focusDefinition, "object template "+objectTemplate+ " for focus "+focusOdo.getAnyObject());

Expand Down Expand Up @@ -281,7 +286,7 @@ <F extends FocusType> Collection<ItemDelta<?,?>> computeItemDeltas(Map<ItemPath,
}

private <F extends FocusType> XMLGregorianCalendar collectTripleFromTemplate(LensContext<F> context,
ObjectTemplateType objectTemplateType, ObjectTemplateMappingEvaluationPhaseType phase, ObjectDeltaObject<F> userOdo,
ObjectTemplateType objectTemplateType, ObjectTemplateMappingEvaluationPhaseType phase, ObjectDeltaObject<F> focusOdo,
Map<ItemPath, DeltaSetTriple<? extends ItemValueWithOrigin<?,?>>> outputTripleMap,
int iteration, String iterationToken,
XMLGregorianCalendar now, String contextDesc, Task task, OperationResult result)
Expand All @@ -301,7 +306,7 @@ private <F extends FocusType> XMLGregorianCalendar collectTripleFromTemplate(Len
}
LOGGER.trace("Including template {}", includeObject);
ObjectTemplateType includeObjectType = includeObject.asObjectable();
XMLGregorianCalendar includeNextRecomputeTime = collectTripleFromTemplate(context, includeObjectType, phase, userOdo,
XMLGregorianCalendar includeNextRecomputeTime = collectTripleFromTemplate(context, includeObjectType, phase, focusOdo,
outputTripleMap, iteration, iterationToken,
now, "include "+includeObject+" in "+objectTemplateType + " in " + contextDesc, task, result);
if (includeNextRecomputeTime != null) {
Expand All @@ -313,7 +318,7 @@ private <F extends FocusType> XMLGregorianCalendar collectTripleFromTemplate(Len

// Process own mappings
Collection<ObjectTemplateMappingType> mappings = collectMapings(objectTemplateType);
XMLGregorianCalendar templateNextRecomputeTime = collectTripleFromMappings(mappings, phase, context, objectTemplateType, userOdo,
XMLGregorianCalendar templateNextRecomputeTime = collectTripleFromMappings(mappings, phase, context, objectTemplateType, focusOdo,
outputTripleMap, iteration, iterationToken, now, contextDesc, task, result);
if (templateNextRecomputeTime != null) {
if (nextRecomputeTime == null || nextRecomputeTime.compare(templateNextRecomputeTime) == DatatypeConstants.GREATER) {
Expand Down Expand Up @@ -344,7 +349,7 @@ private Collection<ObjectTemplateMappingType> collectMapings(ObjectTemplateType

private <V extends PrismValue, D extends ItemDefinition, F extends FocusType> XMLGregorianCalendar collectTripleFromMappings(
Collection<ObjectTemplateMappingType> mappings, ObjectTemplateMappingEvaluationPhaseType phase, LensContext<F> context,
ObjectTemplateType objectTemplateType, ObjectDeltaObject<F> userOdo,
ObjectTemplateType objectTemplateType, ObjectDeltaObject<F> focusOdo,
Map<ItemPath, DeltaSetTriple<? extends ItemValueWithOrigin<?,?>>> outputTripleMap,
int iteration, String iterationToken,
XMLGregorianCalendar now, String contextDesc, Task task, OperationResult result) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException {
Expand All @@ -359,7 +364,7 @@ private <V extends PrismValue, D extends ItemDefinition, F extends FocusType> XM
if (mappingPhase != phase) {
continue;
}
Mapping<V,D> mapping = LensUtil.createFocusMapping(mappingFactory, context, mappingType, objectTemplateType, userOdo,
Mapping<V,D> mapping = LensUtil.createFocusMapping(mappingFactory, context, mappingType, objectTemplateType, focusOdo,
null, iteration, iterationToken, context.getSystemConfiguration(), now, contextDesc, task, result);
if (mapping == null) {
continue;
Expand All @@ -386,6 +391,9 @@ private <V extends PrismValue, D extends ItemDefinition, F extends FocusType> XM
continue;
}
DeltaSetTriple<ItemValueWithOrigin<V,D>> outputTriple = ItemValueWithOrigin.createOutputTriple(mapping);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Output tripple for {}:\n{}", mapping, outputTriple==null?null:outputTriple.debugDump());
}
if (outputTriple == null) {
continue;
}
Expand Down
Expand Up @@ -1061,6 +1061,79 @@ public void test229UnassignRoleSailorFromUserRapp() throws Exception {
assertEquals("Wrong costCenter", "G001", userAfterType.getCostCenter());
}


/**
* Role Captains has focus mapping for the same costCenter as is given
* by the user template.
*/
@Test
public void test230AssignRoleCaptainToUserRapp() throws Exception {
final String TEST_NAME = "test230AssignRoleCaptainToUserRapp";
TestUtil.displayTestTile(this, TEST_NAME);

// GIVEN
Task task = taskManager.createTaskInstance(TestUserTemplate.class.getName() + "." + TEST_NAME);
OperationResult result = task.getResult();

// WHEN
assignRole(USER_RAPP_OID, ROLE_CAPTAIN_OID, task, result);

// THEN
PrismObject<UserType> userAfter = modelService.getObject(UserType.class, USER_RAPP_OID, null, task, result);
assertUser(userAfter, USER_RAPP_OID, "rapp", "Rapp Scallion", "Rapp", "Scallion");

assertAssignedAccount(userAfter, RESOURCE_DUMMY_BLUE_OID);
assertAssignedRole(userAfter, ROLE_CAPTAIN_OID);
assertAssignments(userAfter, 2);

UserType userAfterType = userAfter.asObjectable();
assertLinks(userAfter, 1);

result.computeStatus();
TestUtil.assertSuccess(result);

assertEquals("Unexpected value of employeeNumber",
"D3ADB33F", userAfterType.getEmployeeNumber());
assertEquals("Wrong costCenter", "G001", userAfterType.getCostCenter());
}

/**
* Role Captains has focus mapping for the same costCenter as is given
* by the user template.
* MID-3028
*/
@Test
public void test239UnassignRoleCaptainFromUserRapp() throws Exception {
final String TEST_NAME = "test239UnassignRoleCaptainFromUserRapp";
TestUtil.displayTestTile(this, TEST_NAME);

// GIVEN
Task task = taskManager.createTaskInstance(TestUserTemplate.class.getName() + "." + TEST_NAME);
OperationResult result = task.getResult();

// WHEN
unassignRole(USER_RAPP_OID, ROLE_CAPTAIN_OID, task, result);

// THEN
PrismObject<UserType> userAfter = modelService.getObject(UserType.class, USER_RAPP_OID, null, task, result);
display("User after", userAfter);
assertUser(userAfter, USER_RAPP_OID, "rapp", "Rapp Scallion", "Rapp", "Scallion");

assertAssignedAccount(userAfter, RESOURCE_DUMMY_BLUE_OID);
assertAssignedNoRole(userAfter);
assertAssignments(userAfter, 1);

UserType userAfterType = userAfter.asObjectable();
assertLinks(userAfter, 1);

result.computeStatus();
TestUtil.assertSuccess(result);

assertEquals("Unexpected value of employeeNumber",
"D3ADB33F", userAfterType.getEmployeeNumber());
assertEquals("Wrong costCenter", "G001", userAfterType.getCostCenter());
}

/**
* Move the time to the future. See if the time-based mapping in user template is properly recomputed.
*/
Expand Down
16 changes: 14 additions & 2 deletions model/model-intest/src/test/resources/common/role-captain.xml
@@ -1,5 +1,5 @@
<!--
~ Copyright (c) 2010-2013 Evolveum
~ Copyright (c) 2010-2016 Evolveum
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
Expand All @@ -18,7 +18,19 @@
xmlns:c="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
xmlns:t="http://prism.evolveum.com/xml/ns/public/types-3"
xmlns:ri="http://midpoint.evolveum.com/xml/ns/public/resource/instance/10000000-0000-0000-0000-000000000004">
<name>Captain</name>
<name>Captain</name>
<inducement>
<focusMappings>
<mapping>
<expression>
<value>G001</value> <!-- Same CC as defined in user-template-complex -->
</expression>
<target>
<path>costCenter</path>
</target>
</mapping>
</focusMappings>
</inducement>
<authorization>
<action>http://midpoint.evolveum.com/xml/ns/test/authorization#command</action>
</authorization>
Expand Down
4 changes: 2 additions & 2 deletions model/model-intest/src/test/resources/common/role-thief.xml
@@ -1,5 +1,5 @@
<!--
~ Copyright (c) 2015 Evolveum
~ Copyright (c) 2015-2016 Evolveum
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
Expand All @@ -21,7 +21,7 @@
<!-- No construction here. By purpose: to test exclusivity without any constructions. -->
<policyConstraints>
<exclusion>
<description>A judge cannot be a pirate at the same time. At least not openly.</description>
<description>A thief cannot be a pirate at the same time. At least not openly.</description>
<enforcement>enforce</enforcement>
<targetRef oid="12345111-1111-2222-1111-121212111111" type="RoleType"/> <!-- Judge -->
</exclusion>
Expand Down
4 changes: 3 additions & 1 deletion model/model-intest/src/test/resources/logback-test.xml
Expand Up @@ -49,13 +49,15 @@
<logger name="com.evolveum.midpoint.model.impl.lens.projector.InboundProcessor" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.projector.FocusConstraintsChecker" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.projector.FocusPolicyProcessor" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.projector.ObjectTemplateProcessor" level="TRACE" />
<logger name="com.evolveum.midpoint.model.impl.lens.projector.ProjectionValuesProcessor" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.projector.OutboundProcessor" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.projector.ConsolidationProcessor" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.projector.ReconciliationProcessor" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.ChangeExecutor" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.ShadowConstraintsChecker" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.LensUtil" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.lens.LensUtil" level="TRACE" />
<logger name="com.evolveum.midpoint.model.impl.lens.AssignmentEvaluator" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.expr" level="DEBUG" />
<logger name="com.evolveum.midpoint.model.impl.util" level="TRACE" />
Expand Down

0 comments on commit 3a3671f

Please sign in to comment.