diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-model-context-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-model-context-3.xsd index 666f4ff99b3..7624538f9ab 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-model-context-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-model-context-3.xsd @@ -813,6 +813,26 @@ + + + + Lens (model) context at input (text dump). + + + 4.0.1 + + + + + + + Lens (model) context at output (text dump). + + + 4.0.1 + + + diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-policy-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-policy-3.xsd index ee34b586a2e..ae0a1fd345d 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-policy-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-policy-3.xsd @@ -2235,7 +2235,7 @@ for activation in these hardcoded states ("undefined" for active and deprecated states, "archived" for archived state, "disabled" for all other states). To turn off this default behaviour those hardcoded lifecycle states need to be explicitly defined in the state model - and the forcedActivationStatus property shoule be left undefined. + and the forcedActivationStatus property should be left undefined.

@@ -2249,10 +2249,10 @@

There are cases when you need to force midpoint thinks that user has assigned some - role. The assignemnt actually doesn't exist but there is a need to preted as it does. + role. The assignment actually doesn't exist but there is a need to pretend as it does. This can be used e.g. for post-authentication flow. The user has assigned all business, application, etc. roles but we don't want to consider these roles during his - post-authentication proces. Instead, we want to pretend he has "temporary" role assigned + post-authentication process. Instead, we want to pretend he has "temporary" role assigned which allows him to perform post-authentication.

@@ -2340,10 +2340,10 @@

There are cases when you need to force midpoint thinks that user has assigned some - role. The assignemnt actually doesn't exist but there is a need to preted as it does. + role. The assignment actually doesn't exist but there is a need to pretend as it does. This can be used e.g. for post-authentication flow. The user has assigned all business, application, etc. roles but we don't want to consider these roles during his - post-authentication proces. Instead, we want to pretend he has "temporary" role assigned + post-authentication process. Instead, we want to pretend he has "temporary" role assigned which allows him to perform post-authentication.

diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Clockwork.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Clockwork.java index ee25e58770b..a789e112235 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Clockwork.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Clockwork.java @@ -266,10 +266,7 @@ private boolean startTracingIfRequested(LensContext co private ClockworkRunTraceType recordTraceAtStart(LensContext context, Task task, OperationResult result) throws SchemaException { ClockworkRunTraceType trace = new ClockworkRunTraceType(prismContext); - TracingLevelType level = result.getTracingLevel(trace.getClass()); - if (level.ordinal() >= TracingLevelType.MINIMAL.ordinal()) { - trace.getText().add(context.debugDump()); // todo - } + trace.setInputLensContextText(context.debugDump()); trace.setInputLensContext(context.toLensContextType(getExportTypeTraceOrReduced(trace, result))); result.addTrace(trace); return trace; @@ -278,6 +275,7 @@ private ClockworkRunTraceType recordTraceAtStart(LensCont private void recordTraceAtEnd(LensContext context, ClockworkRunTraceType trace, OperationResult result) throws SchemaException { if (trace != null) { + trace.setOutputLensContextText(context.debugDump()); trace.setOutputLensContext(context.toLensContextType(getExportTypeTraceOrReduced(trace, result))); if (context.getFocusContext() != null) { // todo reconsider this PrismObject objectAny = context.getFocusContext().getObjectAny(); @@ -537,6 +535,9 @@ public HookOperationMode click(LensContext context, Ta ClockworkClickTraceType trace; if (result.isTraced()) { trace = new ClockworkClickTraceType(prismContext); + if (result.isTracingNormal(ClockworkClickTraceType.class)) { + trace.setInputLensContextText(context.debugDump()); + } trace.setInputLensContext(context.toLensContextType(getExportType(trace, result))); result.getTraces().add(trace); } else { @@ -627,6 +628,9 @@ public HookOperationMode click(LensContext context, Ta throw e; } finally { if (trace != null) { + if (result.isTracingNormal(ClockworkClickTraceType.class)) { + trace.setOutputLensContextText(context.debugDump()); + } trace.setOutputLensContext(context.toLensContextType(getExportType(trace, result))); } result.computeStatusIfUnknown(); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ClockworkMedic.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ClockworkMedic.java index 408509e07c4..712fac566af 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ClockworkMedic.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ClockworkMedic.java @@ -195,6 +195,9 @@ public void partialExecute(String baseComponentName, ProjectorComponentRunnable ProjectorComponentTraceType trace; if (result.isTraced()) { trace = new ProjectorComponentTraceType(); + if (result.isTracingNormal(ProjectorComponentTraceType.class)) { + trace.setInputLensContextText(context.debugDump()); + } trace.setInputLensContext(context.toLensContextType(getExportType(trace, result))); result.addTrace(trace); } else { @@ -215,6 +218,9 @@ public void partialExecute(String baseComponentName, ProjectorComponentRunnable } finally { result.computeStatusIfUnknown(); if (trace != null) { + if (result.isTracingNormal(ProjectorComponentTraceType.class)) { + trace.setOutputLensContextText(context.debugDump()); + } trace.setOutputLensContext(context.toLensContextType(getExportType(trace, result))); } if (clockworkInspector != null) { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java index 2315ef50d49..aa0a3fa85d5 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ContextLoader.java @@ -107,6 +107,9 @@ public void load(LensContext context, String activityD ProjectorComponentTraceType trace; if (result.isTraced()) { trace = new ProjectorComponentTraceType(prismContext); + if (result.isTracingNormal(ProjectorComponentTraceType.class)) { + trace.setInputLensContextText(context.debugDump()); + } trace.setInputLensContext(context.toLensContextType(getExportType(trace, result))); result.addTrace(trace); } else { @@ -194,6 +197,9 @@ public void load(LensContext context, String activityD throw e; } finally { if (trace != null) { + if (result.isTracingNormal(ProjectorComponentTraceType.class)) { + trace.setOutputLensContextText(context.debugDump()); + } trace.setOutputLensContext(context.toLensContextType(getExportType(trace, result))); } } @@ -327,6 +333,9 @@ public void determineFocusContext(LensContext context, FocusLoadedTraceType trace; if (result.isTraced()) { trace = new FocusLoadedTraceType(); + if (result.isTracingNormal(FocusLoadedTraceType.class)) { + trace.setInputLensContextText(context.debugDump()); + } trace.setInputLensContext(context.toLensContextType(getExportType(trace, result))); result.addTrace(trace); } else { @@ -392,6 +401,9 @@ public void determineFocusContext(LensContext context, throw t; } finally { if (trace != null) { + if (result.isTracingNormal(FocusLoadedTraceType.class)) { + trace.setOutputLensContextText(context.debugDump()); + } trace.setOutputLensContext(context.toLensContextType(getExportType(trace, result))); } result.computeStatusIfUnknown(); @@ -1444,6 +1456,9 @@ public void loadFullShadow(LensContext context, LensPr FullShadowLoadedTraceType trace; if (result.isTraced()) { trace = new FullShadowLoadedTraceType(prismContext); + if (result.isTracingNormal(FullShadowLoadedTraceType.class)) { + trace.setInputLensContextText(context.debugDump()); + } trace.setInputLensContext(context.toLensContextType(getExportType(trace, result))); result.addTrace(trace); } else { @@ -1512,6 +1527,9 @@ public void loadFullShadow(LensContext context, LensPr throw t; } finally { if (trace != null) { + if (result.isTracingNormal(FullShadowLoadedTraceType.class)) { + trace.setOutputLensContextText(context.debugDump()); + } trace.setOutputLensContext(context.toLensContextType(getExportType(trace, result))); } result.computeStatusIfUnknown(); diff --git a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java index 52624b2714a..6b6a3513e0e 100644 --- a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java +++ b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java @@ -3588,25 +3588,33 @@ protected void restartTask(String taskOid) throws CommonException { LOGGER.warn("Sleep interrupted: {}", e.getMessage(), e); } - final OperationResult result = new OperationResult(AbstractIntegrationTest.class+".restartTask"); - Task task = taskManager.getTaskWithResult(taskOid, result); - LOGGER.info("Restarting task {}", taskOid); - if (task.getExecutionStatus() == TaskExecutionStatus.SUSPENDED) { - LOGGER.debug("Task {} is suspended, resuming it", task); - taskManager.resumeTask(task, result); - } else if (task.getExecutionStatus() == TaskExecutionStatus.CLOSED) { - LOGGER.debug("Task {} is closed, scheduling it to run now", task); - taskManager.scheduleTasksNow(singleton(taskOid), result); - } else if (task.getExecutionStatus() == TaskExecutionStatus.RUNNABLE) { - if (taskManager.getLocallyRunningTaskByIdentifier(task.getTaskIdentifier()) != null) { - // Task is really executing. Let's wait until it finishes; hopefully it won't start again (TODO) - LOGGER.debug("Task {} is running, waiting while it finishes before restarting", task); - waitForTaskFinish(taskOid, false); + OperationResult result = createSubresult("restartTask"); + try { + Task task = taskManager.getTaskWithResult(taskOid, result); + LOGGER.info("Restarting task {}", taskOid); + if (task.getExecutionStatus() == TaskExecutionStatus.SUSPENDED) { + LOGGER.debug("Task {} is suspended, resuming it", task); + taskManager.resumeTask(task, result); + } else if (task.getExecutionStatus() == TaskExecutionStatus.CLOSED) { + LOGGER.debug("Task {} is closed, scheduling it to run now", task); + taskManager.scheduleTasksNow(singleton(taskOid), result); + } else if (task.getExecutionStatus() == TaskExecutionStatus.RUNNABLE) { + if (taskManager.getLocallyRunningTaskByIdentifier(task.getTaskIdentifier()) != null) { + // Task is really executing. Let's wait until it finishes; hopefully it won't start again (TODO) + LOGGER.debug("Task {} is running, waiting while it finishes before restarting", task); + waitForTaskFinish(taskOid, false); + } + LOGGER.debug("Task {} is finished, scheduling it to run now", task); + taskManager.scheduleTasksNow(singleton(taskOid), result); + } else { + throw new IllegalStateException( + "Task " + task + " cannot be restarted, because its state is: " + task.getExecutionStatus()); } - LOGGER.debug("Task {} is finished, scheduling it to run now", task); - taskManager.scheduleTasksNow(singleton(taskOid), result); - } else { - throw new IllegalStateException("Task " + task + " cannot be restarted, because its state is: " + task.getExecutionStatus()); + } catch (Throwable t) { + result.recordFatalError(t); + throw t; + } finally { + result.computeStatusIfUnknown(); } } diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java index 80b1075beec..19c31731d02 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/AbstractIntegrationTest.java @@ -331,6 +331,18 @@ protected Task getOrCreateTask(String methodName) { } } + protected OperationResult createSubresult(String methodName) { + String className = this.getClass().getName(); + MidpointTestMethodContext ctx = MidpointTestMethodContext.get(); + OperationResult parent; + if (ctx != null) { + parent = ctx.getResult(); + } else { + parent = new OperationResult(className + ".parent"); + } + return parent.createSubresult(className + "." + methodName); + } + protected OperationResult getResult() { MidpointTestMethodContext ctx = MidpointTestMethodContext.get(); if (ctx != null) { diff --git a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/grouper/TestGrouperAsyncUpdate.java b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/grouper/TestGrouperAsyncUpdate.java index fce6bc6f146..467d4d87691 100644 --- a/testing/story/src/test/java/com/evolveum/midpoint/testing/story/grouper/TestGrouperAsyncUpdate.java +++ b/testing/story/src/test/java/com/evolveum/midpoint/testing/story/grouper/TestGrouperAsyncUpdate.java @@ -68,6 +68,8 @@ public class TestGrouperAsyncUpdate extends AbstractStoryTest { private static final TestResource USER_BANDERSON = new TestResource(TEST_DIR, "user-banderson.xml", "4f439db5-181e-4297-9f7d-b3115524dbe8"); private static final TestResource USER_JLEWIS685 = new TestResource(TEST_DIR, "user-jlewis685.xml", "8b7bd936-b863-45d0-aabe-734fa3e22081"); + private static final TestResource TASK_GROUP_SCAVENGER = new TestResource(TEST_DIR, "task-group-scavenger.xml", "1d7bef40-953e-443e-8e9a-ec6e313668c4"); + private static final String NS_EXT = "http://grouper-demo.tier.internet2.edu"; public static final QName EXT_GROUPER_NAME = new QName(NS_EXT, "grouperName"); public static final QName EXT_LDAP_DN = new QName(NS_EXT, "ldapDn"); @@ -84,8 +86,10 @@ public class TestGrouperAsyncUpdate extends AbstractStoryTest { private static final File CHANGE_200 = new File(TEST_DIR, "change-200-banderson-add-alumni.json"); private static final File CHANGE_210 = new File(TEST_DIR, "change-210-banderson-add-staff.json"); private static final File CHANGE_220 = new File(TEST_DIR, "change-220-jlewis685-add-alumni.json"); + private static final File CHANGE_221 = new File(TEST_DIR, "change-221-jlewis685-add-staff.json"); private static final File CHANGE_230 = new File(TEST_DIR, "change-230-nobody-add-alumni.json"); private static final File CHANGE_250 = new File(TEST_DIR, "change-250-banderson-delete-alumni.json"); + private static final File CHANGE_310 = new File(TEST_DIR, "change-310-staff-delete.json"); private static final ItemName ATTR_MEMBER = new ItemName(MidPointConstants.NS_RI, "member"); @@ -127,6 +131,8 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti addObject(ROLE_LDAP_BASIC, initTask, initResult); addObject(TEMPLATE_USER, initTask, initResult); + addObject(TASK_GROUP_SCAVENGER, initTask, initResult); + setGlobalTracingOverride(createModelAndProvisioningLoggingTracingProfile()); } @@ -204,6 +210,8 @@ public void test110AddAlumni() throws Exception { assertMembers(ALUMNI_NAME, task, result); orgAlumniOid = assertOrgByName("affiliation_alumni", "alumni after") + .display() + .assertLifecycleState("active") .extension() .property(EXT_GROUPER_NAME).singleValue().assertValue(ALUMNI_NAME).end().end() .property(EXT_LDAP_DN).singleValue().assertValue(DN_ALUMNI).end().end() @@ -212,6 +220,18 @@ public void test110AddAlumni() throws Exception { .assertDisplayName("Affiliation: alumni") .assertIdentifier("alumni") .assertLinks(2) // todo assert details + .links() + .projectionOnResource(RESOURCE_GROUPER.oid) + .target() + .assertNotDead() + .end() + .end() + .projectionOnResource(RESOURCE_LDAP.oid) + .target() + .assertNotDead() + .end() + .end() + .end() .getOid(); } @@ -241,6 +261,8 @@ public void test115AddStaff() throws Exception { assertMembers(STAFF_NAME, task, result); orgStaffOid = assertOrgByName("affiliation_staff", "staff after") + .display() + .assertLifecycleState("active") .extension() .property(EXT_GROUPER_NAME).singleValue().assertValue(STAFF_NAME).end().end() .property(EXT_LDAP_DN).singleValue().assertValue(DN_STAFF).end().end() @@ -249,6 +271,18 @@ public void test115AddStaff() throws Exception { .assertDisplayName("Affiliation: staff") .assertIdentifier("staff") .assertLinks(2) // todo assert details + .links() + .projectionOnResource(RESOURCE_GROUPER.oid) + .target() + .assertNotDead() + .end() + .end() + .projectionOnResource(RESOURCE_LDAP.oid) + .target() + .assertNotDead() + .end() + .end() + .end() .getOid(); } @@ -404,8 +438,39 @@ public void test220AddAlumniForLewis() throws Exception { .assertTriggers(1); } + /** + * Adding ref:affiliation:staff membership for jlewis685. + */ + @Test + public void test221AddStaffForLewis() throws Exception { + Task task = getTask(); + OperationResult result = getResult(); + + // GIVEN + + MockAsyncUpdateSource.INSTANCE.reset(); + MockAsyncUpdateSource.INSTANCE.prepareMessage(getAmqp091Message(CHANGE_221)); + + // WHEN + + ResourceShadowDiscriminator coords = new ResourceShadowDiscriminator(RESOURCE_GROUPER.oid); + String handle = provisioningService.startListeningForAsyncUpdates(coords, task, result); + provisioningService.stopListeningForAsyncUpdates(handle, task, result); + + // THEN + + assertSuccess(result); + + assertMembers(ALUMNI_NAME, task, result, BANDERSON_USERNAME, JLEWIS685_USERNAME); + assertMembers(STAFF_NAME, task, result, BANDERSON_USERNAME, JLEWIS685_USERNAME); + + assertUserAfterByUsername(JLEWIS685_USERNAME) + .triggers() + .assertTriggers(1); + } + /** - * Lewis should obtain an assignment. + * Lewis should obtain two assignments. */ @Test public void test222RecomputeLewis() throws Exception { @@ -422,15 +487,17 @@ public void test222RecomputeLewis() throws Exception { assertUserAfterByUsername(JLEWIS685_USERNAME) .assignments() - .assertAssignments(2) + .assertAssignments(3) .assertRole(ROLE_LDAP_BASIC.oid) .assertOrg(orgAlumniOid) + .assertOrg(orgStaffOid) .end() .links() .assertLinks(1) .projectionOnResource(resourceLdap.getOid()); openDJController.assertUniqueMember(DN_ALUMNI, DN_JLEWIS685); + openDJController.assertUniqueMember(DN_STAFF, DN_JLEWIS685); } /** @@ -518,6 +585,101 @@ public void test252RecomputeAnderson() throws Exception { openDJController.assertUniqueMember(DN_STAFF, DN_BANDERSON); } + /** + * Deleting ref:affiliation:staff group. + */ + @Test + public void test310DeleteStaff() throws Exception { + Task task = getTask(); + OperationResult result = getResult(); + + // GIVEN + + MockAsyncUpdateSource.INSTANCE.reset(); + MockAsyncUpdateSource.INSTANCE.prepareMessage(getAmqp091Message(CHANGE_310)); + + executeChanges(deltaFor(UserType.class).item(UserType.F_TRIGGER).replace().asObjectDelta(USER_BANDERSON.oid), null, task, result); + executeChanges(deltaFor(UserType.class).item(UserType.F_TRIGGER).replace().asObjectDelta(USER_JLEWIS685.oid), null, task, result); + + // WHEN + + ResourceShadowDiscriminator coords = new ResourceShadowDiscriminator(RESOURCE_GROUPER.oid); + String handle = provisioningService.startListeningForAsyncUpdates(coords, task, result); + provisioningService.stopListeningForAsyncUpdates(handle, task, result); + + // THEN + + assertSuccess(result); + + assertOrgByName("affiliation_staff", "staff after deletion") + .display() + .assertLifecycleState("archiving") + .extension() + .property(EXT_GROUPER_NAME).singleValue().assertValue(STAFF_NAME).end().end() + .property(EXT_LDAP_DN).singleValue().assertValue(DN_STAFF).end().end() + .end() + .assertAssignments(1) // archetype, todo assert target + .assertDisplayName("Affiliation: staff") + .assertIdentifier("staff") + .links() + .projectionOnResource(RESOURCE_GROUPER.oid) + .target() + .assertDead() + .end() + .end() + .projectionOnResource(RESOURCE_LDAP.oid) + .target() + .assertNotDead() + .end() + .end() + .end(); + } + + /** + * Completes the deletion of staff group. + */ + @Test + public void test312ScavengeGroups() throws Exception { + Task task = getTask(); + OperationResult result = getResult(); + + // GIVEN + + + // WHEN + + rerunTask(TASK_GROUP_SCAVENGER.oid); + + // THEN + + assertSuccess(result); + + assertNoObject(OrgType.class, orgStaffOid, task, result); + assertUserAfterByUsername(BANDERSON_USERNAME) + .assignments() + .assertAssignments(1) + .assertRole(ROLE_LDAP_BASIC.oid) + .end() + .links() + .assertLinks(1) + .projectionOnResource(resourceLdap.getOid()); + + assertUserAfterByUsername(JLEWIS685_USERNAME) + .assignments() + .assertAssignments(2) + .assertRole(ROLE_LDAP_BASIC.oid) + .assertOrg(orgAlumniOid) + .end() + .links() + .assertLinks(1) + .projectionOnResource(resourceLdap.getOid()); + + openDJController.assertNoEntry(DN_STAFF); + + openDJController.assertNoUniqueMember(DN_ALUMNI, DN_BANDERSON); + openDJController.assertUniqueMember(DN_ALUMNI, DN_JLEWIS685); + } + private AsyncUpdateMessageType getAmqp091Message(File file) throws IOException { Amqp091MessageType rv = new Amqp091MessageType(); String json = String.join("\n", IOUtils.readLines(new FileReader(file))); diff --git a/testing/story/src/test/resources/grouper/change-221-jlewis685-add-staff.json b/testing/story/src/test/resources/grouper/change-221-jlewis685-add-staff.json new file mode 100644 index 00000000000..02fbb2e2400 --- /dev/null +++ b/testing/story/src/test/resources/grouper/change-221-jlewis685-add-staff.json @@ -0,0 +1,18 @@ +{ + "encrypted": false, + "esbEvent": [ + { + "sourceId": "ldap", + "membershipType": "flattened", + "fieldName": "members", + "groupId": "00000000000000000000000000000003", + "changeOccurred": false, + "createdOnMicros": 1551884899000200, + "subjectId": "jlewis685", + "id": "32193201930193029105543238888888", + "sequenceNumber": "221", + "eventType": "MEMBERSHIP_ADD", + "groupName": "ref:affiliation:staff" + } + ] +} \ No newline at end of file diff --git a/testing/story/src/test/resources/grouper/change-310-staff-delete.json b/testing/story/src/test/resources/grouper/change-310-staff-delete.json index becaadeacee..e106565b456 100644 --- a/testing/story/src/test/resources/grouper/change-310-staff-delete.json +++ b/testing/story/src/test/resources/grouper/change-310-staff-delete.json @@ -9,7 +9,7 @@ "id": "00000000000000000000000000000003", "sequenceNumber": "310", "eventType": "GROUP_DELETE", - "name": "ref:staff" + "name": "ref:affiliation:staff" } ] } \ No newline at end of file diff --git a/testing/story/src/test/resources/grouper/metarole-grouper-provided-group.xml b/testing/story/src/test/resources/grouper/metarole-grouper-provided-group.xml index 8d7322e558b..765255287fc 100644 --- a/testing/story/src/test/resources/grouper/metarole-grouper-provided-group.xml +++ b/testing/story/src/test/resources/grouper/metarole-grouper-provided-group.xml @@ -148,6 +148,38 @@ displayName + + + lifecycle state + This mapping sets org lifecycle state to be either "active" or "archiving", depending on + whether Grouper group for this org still exists. Orgs in the latter state are on the way to deletion: + their members are unassigned and after no members are there, the org is automatically deleted. + strong + + + + + lifecycleState + + - http://midpoint.evolveum.com/xml/ns/public/model/action-3#unlink - + + + + + + true unlinked diff --git a/testing/story/src/test/resources/grouper/system-configuration.xml b/testing/story/src/test/resources/grouper/system-configuration.xml index f6775969246..0e877ba7be2 100644 --- a/testing/story/src/test/resources/grouper/system-configuration.xml +++ b/testing/story/src/test/resources/grouper/system-configuration.xml @@ -31,6 +31,15 @@ UserType + + OrgType + + + archiving + + + + diff --git a/testing/story/src/test/resources/grouper/task-group-scavenger.xml b/testing/story/src/test/resources/grouper/task-group-scavenger.xml new file mode 100644 index 00000000000..1941184bb6a --- /dev/null +++ b/testing/story/src/test/resources/grouper/task-group-scavenger.xml @@ -0,0 +1,83 @@ + + + + + + + Group Scavenger + + + + execute-script + + script + + import com.evolveum.midpoint.xml.ns._public.common.common_3.* + + result = midpoint.currentResult + log.info('Processing dead group: {}', input) + query = prismContext.queryFor(UserType.class) + .item(UserType.F_ROLE_MEMBERSHIP_REF).ref(input.oid) + .build() + members = midpoint.repositoryService.searchObjects(UserType.class, query, null, result) + log.info('Found {} members: {}', members.size(), members) + + for (member in members) { + log.info('Going to recompute {}', member) + try { + midpoint.recompute(UserType.class, member.oid) + } catch (Throwable t) { + log.error('Couldn\'t recompute {}: {}', member, t.message, t) + } + } + log.info('Members recomputed; checking if the org is still in "archiving" state') + orgAfter = midpoint.repositoryService.getObject(OrgType.class, input.oid, null, result) + currentState = orgAfter.asObjectable().lifecycleState + log.info('Current state = {}', currentState) + if (currentState == 'archiving') { + log.info('Deleting the org: {}', orgAfter) + midpoint.deleteObject(OrgType.class, orgAfter.oid, null) + } else { + log.info('State has changed, not deleting the org: {}', orgAfter) + } + log.info('Dead group processing done: {}', input) + + + + + + OrgType + + + + lifecycleState + archiving + + + + + + runnable + BulkActions + http://midpoint.evolveum.com/xml/ns/public/model/iterative-scripting/handler-3 + recurring + + diff --git a/testing/story/src/test/resources/grouper/template-user.xml b/testing/story/src/test/resources/grouper/template-user.xml index 73476790beb..9442803c7f3 100644 --- a/testing/story/src/test/resources/grouper/template-user.xml +++ b/testing/story/src/test/resources/grouper/template-user.xml @@ -28,13 +28,13 @@ memberDef = prismContext.definitionFactory().createPropertyDefinition(MEMBER_NAME, DOMUtil.XSD_STRING) memberDef.setMaxOccurs(-1) - - // TODO check for exists/dead + shadowQuery = prismContext.queryFor(ShadowType.class) .item(ShadowType.F_RESOURCE_REF).ref(GROUPER_RESOURCE_OID) .and().item(ShadowType.F_SYNCHRONIZATION_SITUATION).eq(SynchronizationSituationType.LINKED) .and().item(ShadowType.F_KIND).eq(ShadowKindType.ENTITLEMENT) .and().item(ShadowType.F_INTENT).eq('group') + .and().block().item(ShadowType.F_DEAD).isNull().or().item(ShadowType.F_DEAD).eq(false).endBlock() .and().item(ItemPath.create(ShadowType.F_ATTRIBUTES, MEMBER_NAME), memberDef).eq(basic.stringify(name)) .build()