From ec6e767c8282e70dfebe8c073ceb1fed4010951f Mon Sep 17 00:00:00 2001 From: Radovan Semancik Date: Mon, 6 Aug 2018 15:37:06 +0200 Subject: [PATCH] Consistency update: the devil is in the details (MID-3891) --- .../midpoint/common/SynchronizationUtils.java | 10 +- .../model/impl/lens/ChangeExecutor.java | 36 ++--- .../model/intest/TestMultiResource.java | 32 +++-- .../AbstractDirectManualResourceTest.java | 22 +-- .../test/AbstractModelIntegrationTest.java | 31 +++++ .../impl/ProvisioningServiceImpl.java | 2 +- .../provisioning/impl/ShadowCache.java | 4 +- .../errorhandling/ObjectNotFoundHandler.java | 9 ++ .../AbstractProvisioningIntegrationTest.java | 16 ++- .../impl/dummy/TestDummyConsistency.java | 85 +++++++----- .../test/asserter/AbstractAsserter.java | 8 +- .../midpoint/test/asserter/FocusAsserter.java | 51 +++---- .../midpoint/test/asserter/LinkFinder.java | 106 ++++++++++++++ .../midpoint/test/asserter/LinksAsserter.java | 130 ++++++++++++++++++ .../asserter/ObjectDeltaTypeAsserter.java | 18 +-- .../asserter/ObjectReferenceAsserter.java | 15 +- .../asserter/ShadowReferenceAsserter.java | 10 +- .../midpoint/test/asserter/UserAsserter.java | 43 +++--- 18 files changed, 482 insertions(+), 146 deletions(-) create mode 100644 repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/LinkFinder.java create mode 100644 repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/LinksAsserter.java diff --git a/infra/common/src/main/java/com/evolveum/midpoint/common/SynchronizationUtils.java b/infra/common/src/main/java/com/evolveum/midpoint/common/SynchronizationUtils.java index e7ea5dbaa0f..f6f6aaff3b5 100644 --- a/infra/common/src/main/java/com/evolveum/midpoint/common/SynchronizationUtils.java +++ b/infra/common/src/main/java/com/evolveum/midpoint/common/SynchronizationUtils.java @@ -197,25 +197,25 @@ public static PropertyDelta createSynchronizationTimestamp return syncSituationDelta; } - public static List> createSynchronizationSituationAndDescriptionDelta(PrismObject object, + public static List> createSynchronizationSituationAndDescriptionDelta(PrismObject currentObject, SynchronizationSituationType situation, String sourceChannel, boolean full) { XMLGregorianCalendar timestamp = XmlTypeConverter .createXMLGregorianCalendar(System.currentTimeMillis()); - List> delta = createSynchronizationSituationDescriptionDelta(object, situation, + List> delta = createSynchronizationSituationDescriptionDelta(currentObject, situation, timestamp, sourceChannel, full); - PropertyDelta timestampDelta = createSynchronizationTimestampDelta(object, + PropertyDelta timestampDelta = createSynchronizationTimestampDelta(currentObject, ShadowType.F_SYNCHRONIZATION_TIMESTAMP, timestamp); delta.add(timestampDelta); if (full) { - timestampDelta = createSynchronizationTimestampDelta(object, + timestampDelta = createSynchronizationTimestampDelta(currentObject, ShadowType.F_FULL_SYNCHRONIZATION_TIMESTAMP, timestamp); delta.add(timestampDelta); } - PropertyDelta syncSituationDelta = createSynchronizationSituationDelta(object, situation); + PropertyDelta syncSituationDelta = createSynchronizationSituationDelta(currentObject, situation); if (syncSituationDelta != null) { delta.add(syncSituationDelta); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ChangeExecutor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ChangeExecutor.java index ae33673d9c5..1232e3c6070 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ChangeExecutor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/ChangeExecutor.java @@ -632,7 +632,7 @@ private void updateLinks( // Already linked, nothing to do, only be sure, the // situation is set with the good value LOGGER.trace("Updating situation in already linked shadow."); - updateSituationInShadow(task, SynchronizationSituationType.LINKED, null, focusObjectContext, + updateSituationInShadow(task, SynchronizationSituationType.LINKED, focusObjectContext, projCtx, result); return; } @@ -642,7 +642,7 @@ private void updateLinks( linkShadow(focusContext.getOid(), projOid, focusObjectContext, projCtx, task, result); // be sure, that the situation is set correctly LOGGER.trace("Updating situation after shadow was linked."); - updateSituationInShadow(task, SynchronizationSituationType.LINKED, null, focusObjectContext, projCtx, + updateSituationInShadow(task, SynchronizationSituationType.LINKED, focusObjectContext, projCtx, result); } else { // Link should NOT exist @@ -665,26 +665,11 @@ private void updateLinks( } } - if (projCtx.isDelete() || projCtx.isThombstone()) { - LOGGER.trace("Resource object {} deleted, updating also situation in shadow.", projOid); - // HACK HACK? - try { - updateSituationInShadow(task, SynchronizationSituationType.DELETED, true, focusObjectContext, - projCtx, result); - } catch (ObjectNotFoundException e) { - // HACK HACK? - LOGGER.trace( - "Resource object {} is gone, cannot update situation in shadow (this is probably harmless).", - projOid); - result.getLastSubresult().setStatus(OperationResultStatus.HANDLED_ERROR); - } - } else { - // This should NOT be UNLINKED. We just do not know the - // situation here. Reflect that in the shadow. - LOGGER.trace("Resource object {} unlinked from the user, updating also situation in shadow.", - projOid); - updateSituationInShadow(task, null, null, focusObjectContext, projCtx, result); - } + // This should NOT be UNLINKED. We just do not know the + // situation here. Reflect that in the shadow. + LOGGER.trace("Resource object {} unlinked from the user, updating also situation in shadow.", + projOid); + updateSituationInShadow(task, null, focusObjectContext, projCtx, result); // Not linked, that's OK } } @@ -803,7 +788,7 @@ private void unlinkShadow(String focusOid, PrismReference } private void updateSituationInShadow(Task task, - SynchronizationSituationType situation, Boolean dead, LensFocusContext focusContext, + SynchronizationSituationType situation, LensFocusContext focusContext, LensProjectionContext projectionCtx, OperationResult parentResult) throws ObjectNotFoundException, SchemaException { @@ -826,11 +811,6 @@ private void updateSituationInShadow(Task task, List> syncSituationDeltas = SynchronizationUtils .createSynchronizationSituationAndDescriptionDelta(account, situation, task.getChannel(), projectionCtx.hasFullShadow()); - - if (dead != null) { - PropertyDelta deadDelta = PropertyDelta.createModificationReplaceProperty(ShadowType.F_DEAD, account.getDefinition(), dead); - syncSituationDeltas.add(deadDelta); - } try { Utils.setRequestee(task, focusContext); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMultiResource.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMultiResource.java index e6d2c3240f7..351c5209e9e 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMultiResource.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/TestMultiResource.java @@ -534,9 +534,8 @@ public void test223JackKillDefaultDummyAccounAndRecompute() throws Exception { displayThen(TEST_NAME); assertSuccess(result); - PrismObject userJack = getUser(USER_JACK_OID); - display("user after", userJack); - assertLinks(userJack, 2); + assertUserAfter(USER_JACK_OID) + .assertLinks(2); display("dummy resource after", getDummyResource()); @@ -572,12 +571,29 @@ public void test224JackKillBeigeAccounAndRecompute() throws Exception { // THEN displayThen(TEST_NAME); - result.computeStatus(); - display("Result", result); - TestUtil.assertSuccess(result); + assertSuccess(result); - PrismObject userJack = getUser(USER_JACK_OID); - assertLinks(userJack, 2); + assertUserAfter(USER_JACK_OID) + .displayWithProjections() + .links() + .assertLinks(3) + .by() + .resourceOid(RESOURCE_DUMMY_BEIGE_OID) + .dead(true) + .find() + .end() + .by() + .resourceOid(RESOURCE_DUMMY_BEIGE_OID) + .dead(false) + .find() + .end() + .by() + .resourceOid(RESOURCE_DUMMY_OID) + .find() + .target() + .assertLife() + .end() + .end(); display("beige dummy resource after", getDummyResource(RESOURCE_DUMMY_BEIGE_NAME)); diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractDirectManualResourceTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractDirectManualResourceTest.java index 6a6875d891d..2a56aa684f9 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractDirectManualResourceTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/manual/AbstractDirectManualResourceTest.java @@ -1180,7 +1180,7 @@ public void test302RecomputeWill() throws Exception { } /** - * Case is closed. The operation is complete. + * Case is closed. The unassign operation is complete. * However, in the semi-manual case this gets really interesting. * We have Schroedinger's shadow here. deleted account, ticket closed, account is deleted * by administrator in the target system. But the account is still in the backing store (CSV) @@ -1346,7 +1346,7 @@ public void test330UpdateBackingStoreAndRecomputeWill() throws Exception { .end(); assertUnassignedShadow(shadowRepoAsserter, true, null); - ShadowAsserter shadowModelAsserter = assertModelShadow(accountWillOid) + ShadowAsserter shadowModelAsserter = assertModelShadowNoFetch(accountWillOid) .assertName(USER_WILL_NAME) .assertKind(ShadowKindType.ACCOUNT) .pendingOperations() @@ -1360,12 +1360,14 @@ public void test330UpdateBackingStoreAndRecomputeWill() throws Exception { assertUnassignedShadow(shadowModelAsserter, true, ActivationStatusType.DISABLED); // Do NOT assert password here. There is no password even for semi-manual case as the shadow is dead and account gone. - PrismObject shadowModelFuture = modelService.getObject(ShadowType.class, - accountWillOid, - SelectorOptions.createCollection(GetOperationOptions.createPointInTimeType(PointInTimeType.FUTURE)), - task, result); - display("Model shadow (future)", shadowModelFuture); - assertWillUnassignedFuture(shadowModelFuture, false); + assertModelShadow(accountWillOid) + .assertTombstone(); + + assertModelShadowFuture(accountWillOid) + .assertTombstone(); + + assertModelShadowFutureNoFetch(accountWillOid) + .assertTombstone(); assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); @@ -1738,7 +1740,7 @@ public void test515CloseCasesAndReconcileWill() throws Exception { SelectorOptions.createCollection(GetOperationOptions.createPointInTimeType(PointInTimeType.FUTURE)), task, result); display("Model shadow (future)", shadowModelFuture); - assertWillUnassignedFuture(shadowModelFuture, true); + assertWillUnassignedFuture(shadowModelFuture, false); assertCase(willLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); assertCase(willSecondLastCaseOid, SchemaConstants.CASE_STATE_CLOSED); @@ -1988,7 +1990,7 @@ public void test524TwoHoursForRoleTwo() throws Exception { */ @Test public void test525CloseCasesAndRecomputeWill() throws Exception { - final String TEST_NAME = "test515CloseCasesAndRecomputeWill"; + final String TEST_NAME = "test525CloseCasesAndRecomputeWill"; displayTestTitle(TEST_NAME); // GIVEN Task task = createTask(TEST_NAME); 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 a496aa2f7da..62cacd32923 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 @@ -5291,6 +5291,14 @@ protected ShadowAsserter assertModelShadow(String oid) throws ObjectNotFou return asserter; } + protected ShadowAsserter assertModelShadowNoFetch(String oid) throws ObjectNotFoundException, SchemaException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + PrismObject repoShadow = getShadowModelNoFetch(oid); + ShadowAsserter asserter = ShadowAsserter.forShadow(repoShadow, "model(noFetch)"); + asserter + .display(); + return asserter; + } + protected ShadowAsserter assertModelShadowFuture(String oid) throws ObjectNotFoundException, SchemaException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { PrismObject repoShadow = getShadowModelFuture(oid); ShadowAsserter asserter = ShadowAsserter.forShadow(repoShadow, "model(future)"); @@ -5299,6 +5307,16 @@ protected ShadowAsserter assertModelShadowFuture(String oid) throws Object return asserter; } + protected ShadowAsserter assertModelShadowFutureNoFetch(String oid) throws ObjectNotFoundException, SchemaException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + GetOperationOptions options = GetOperationOptions.createPointInTimeType(PointInTimeType.FUTURE); + options.setNoFetch(true); + PrismObject repoShadow = getShadowModel(oid, options, true); + ShadowAsserter asserter = ShadowAsserter.forShadow(repoShadow, "model(future,noFetch)"); + asserter + .display(); + return asserter; + } + protected void assertNoModelShadow(String oid) throws SchemaException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { Task task = createTask("assertNoModelShadow"); OperationResult result = task.getResult(); @@ -5310,5 +5328,18 @@ protected void assertNoModelShadow(String oid) throws SchemaException, SecurityV assertFailure(result); } } + + protected void assertNoModelShadowFuture(String oid) throws SchemaException, SecurityViolationException, CommunicationException, ConfigurationException, ExpressionEvaluationException { + Task task = createTask("assertNoModelShadowFuture"); + OperationResult result = task.getResult(); + Collection> options = SelectorOptions.createCollection(GetOperationOptions.createPointInTimeType(PointInTimeType.FUTURE)); + try { + PrismObject shadow = modelService.getObject(ShadowType.class, oid, options, task, result); + fail("Expected that future shadow "+oid+" will not be in the model. But it was: "+shadow); + } catch (ObjectNotFoundException e) { + // Expected + assertFailure(result); + } + } } diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ProvisioningServiceImpl.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ProvisioningServiceImpl.java index d6aae2e10d5..b5b51ede329 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ProvisioningServiceImpl.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ProvisioningServiceImpl.java @@ -257,7 +257,7 @@ public PrismObject getObject(Class type, String oid } } - result.computeStatus(); + result.computeStatusIfUnknown(); if (!GetOperationOptions.isRaw(rootOptions)) { resultingObject = resultingObject.cloneIfImmutable(); resultingObject.asObjectable().setFetchResult(result.createOperationResultType()); diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java index 575975857eb..264751068da 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java @@ -2605,7 +2605,9 @@ private PrismObject completeShadow(ProvisioningContext ctx, ProvisioningUtil.setProtectedFlag(ctx, resultShadow, matchingRuleRegistry); // exists, dead - resultShadowType.setExists(resourceShadowType.isExists()); + // This may seem strange, but always take exists and dead flags from the repository. + // Repository is wiser in this case. It may seem that the shadow exists if it is returned + // by the resource. But that may be just a quantum illusion (gestation and corpse shadow states). // Activation ActivationType resultActivationType = resultShadowType.getActivation(); diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/errorhandling/ObjectNotFoundHandler.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/errorhandling/ObjectNotFoundHandler.java index 4c23e7c962e..c51570cbf43 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/errorhandling/ObjectNotFoundHandler.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/errorhandling/ObjectNotFoundHandler.java @@ -92,6 +92,15 @@ public PrismObject handleGetError(ProvisioningContext ctx, discoverDeletedShadow(ctx, repositoryShadow, cause, task, parentResult); } + if (repositoryShadow != null) { + // We always want to return repository shadow it such shadow is available. + // The shadow may be dead, or it may be marked as "not exists", but we want + // to return something if shadow exists in the repo. Otherwise model may + // unlink the shadow or otherwise "forget" about it. + LOGGER.debug("Shadow {} not found on the resource. However still have it in the repository. Therefore returning repository version.", repositoryShadow); + parentResult.setStatus(OperationResultStatus.HANDLED_ERROR); + return repositoryShadow; + } return super.handleGetError(ctx, repositoryShadow, rootOptions, cause, task, parentResult); } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/AbstractProvisioningIntegrationTest.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/AbstractProvisioningIntegrationTest.java index 8066f4e5643..47e89a0ac74 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/AbstractProvisioningIntegrationTest.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/AbstractProvisioningIntegrationTest.java @@ -291,7 +291,7 @@ protected ShadowAsserter assertShadowNoFetch(String oid) throws ObjectNotF } protected ShadowAsserter assertShadowFuture(String oid) throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { - Task task = createTask("assertShadowProvisioning"); + Task task = createTask("assertShadowFuture"); OperationResult result = task.getResult(); Collection> options = SelectorOptions.createCollection(GetOperationOptions.createPointInTimeType(PointInTimeType.FUTURE)); PrismObject shadow = provisioningService.getObject(ShadowType.class, oid, options, task, result); @@ -301,4 +301,18 @@ protected ShadowAsserter assertShadowFuture(String oid) throws ObjectNotFo .display(); return asserter; } + + protected ShadowAsserter assertShadowFutureNoFetch(String oid) throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { + Task task = createTask("assertShadowFutureNoFetch"); + OperationResult result = task.getResult(); + GetOperationOptions rootOptions = GetOperationOptions.createPointInTimeType(PointInTimeType.FUTURE); + rootOptions.setNoFetch(true); + Collection> options = SelectorOptions.createCollection(rootOptions); + PrismObject shadow = provisioningService.getObject(ShadowType.class, oid, options, task, result); + assertSuccess(result); + ShadowAsserter asserter = ShadowAsserter.forShadow(shadow, "future,noFetch"); + asserter + .display(); + return asserter; + } } diff --git a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java index f5b4efbfb4b..59cb50ed6a2 100644 --- a/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java +++ b/provisioning/provisioning-impl/src/test/java/com/evolveum/midpoint/provisioning/impl/dummy/TestDummyConsistency.java @@ -412,9 +412,7 @@ private void assertMorganDead() throws Exception { PrismObject repoShadow = getShadowRepo(ACCOUNT_MORGAN_OID); assertNotNull("Shadow was not created in the repository", repoShadow); - ShadowAsserter shadowAsserter = ShadowAsserter.forShadow(repoShadow, "repository"); - shadowAsserter - .display() + assertRepoShadow(ACCOUNT_MORGAN_OID) .pendingOperations() .singleOperation() .display() @@ -427,8 +425,10 @@ private void assertMorganDead() throws Exception { .assertCompletionTimestamp(lastAttemptStartTs, lastAttemptEndTs) .delta() .display() - .assertAdd(); - shadowAsserter + .assertAdd() + .end() + .end() + .end() .assertBasicRepoProperties() .assertKind(ShadowKindType.ACCOUNT) .assertDead() @@ -437,10 +437,7 @@ private void assertMorganDead() throws Exception { .attributes() .assertAttributes(SchemaConstants.ICFS_NAME); - PrismObject shadowNoFetch = getShadowNoFetch(ACCOUNT_MORGAN_OID); - shadowAsserter = ShadowAsserter.forShadow(shadowNoFetch, "noFetch"); - shadowAsserter - .display() + assertShadowNoFetch(ACCOUNT_MORGAN_OID) .pendingOperations() .singleOperation() .assertRequestTimestamp(lastRequestStartTs, lastRequestEndTs) @@ -451,8 +448,10 @@ private void assertMorganDead() throws Exception { .assertLastAttemptTimestamp(lastAttemptStartTs, lastAttemptEndTs) .assertCompletionTimestamp(lastAttemptStartTs, lastAttemptEndTs) .delta() - .assertAdd(); - shadowAsserter + .assertAdd() + .end() + .end() + .end() .assertDead() .assertIsNotExists() .assertNoLegacyConsistency() @@ -462,17 +461,26 @@ private void assertMorganDead() throws Exception { .assertHasSecondaryIdentifier() .assertSize(1); - PrismObject accountProvisioningFuture = getShadowFuture(ACCOUNT_MORGAN_OID); - shadowAsserter = ShadowAsserter.forShadow(accountProvisioningFuture,"future"); - shadowAsserter - .display() + ShadowAsserter shadowProvisioningFutureAsserter = + assertShadowFuture(ACCOUNT_MORGAN_OID) .assertDead() .assertIsNotExists() .assertNoLegacyConsistency() .attributes() .assertResourceAttributeContainer() .assertNoPrimaryIdentifier() - .assertHasSecondaryIdentifier(); + .assertHasSecondaryIdentifier() + .end(); + + assertShadowFutureNoFetch(ACCOUNT_MORGAN_OID) + .assertDead() + .assertIsNotExists() + .assertNoLegacyConsistency() + .attributes() + .assertResourceAttributeContainer() + .assertNoPrimaryIdentifier() + .assertHasSecondaryIdentifier() + .end(); dummyResource.resetBreakMode(); @@ -485,7 +493,7 @@ private void assertMorganDead() throws Exception { // Check if the shadow is still in the repo (e.g. that the consistency or sync haven't removed it) - checkUniqueness(accountProvisioningFuture); + checkUniqueness(shadowProvisioningFutureAsserter.getObject()); assertSteadyResources(); } @@ -1305,16 +1313,25 @@ public void test190AccountMorganDeadExpireOperation() throws Exception { .pendingOperations() .assertNone(); - ShadowAsserter asserterShadowFuture = assertShadowFuture(ACCOUNT_MORGAN_OID) - .assertDead() - .assertIsNotExists() + ShadowAsserter asserterShadowFuture = assertShadowFuture(ACCOUNT_MORGAN_OID) + .assertTombstone() .assertNoLegacyConsistency() .attributes() .assertResourceAttributeContainer() .assertNoPrimaryIdentifier() .assertHasSecondaryIdentifier() .end(); + + assertShadowFutureNoFetch(ACCOUNT_MORGAN_OID) + .assertTombstone() + .assertNoLegacyConsistency() + .attributes() + .assertResourceAttributeContainer() + .assertNoPrimaryIdentifier() + .assertHasSecondaryIdentifier() + .end(); + dummyResource.resetBreakMode(); // Check if the shadow is still in the repo (e.g. that the consistency or sync haven't removed it) @@ -1381,10 +1398,13 @@ public void test192AccountMorganSecondDeadExpireOperation() throws Exception { assertShadowProvisioning(shadowMorganOid) .assertTombstone(); - + assertShadowFuture(shadowMorganOid) .assertTombstone(); + assertShadowFutureNoFetch(shadowMorganOid) + .assertTombstone(); + dummyResource.resetBreakMode(); assertSteadyResources(); @@ -1851,17 +1871,11 @@ public void test810GetAccountMorganNotFound() throws Exception { // WHEN displayWhen(TEST_NAME); - try { - provisioningService.getObject(ShadowType.class, shadowMorganOid, null, task, result); - assertNotReached(); - } catch (ObjectNotFoundException e) { - displayThen(TEST_NAME); - display("expected exception", e); - } + PrismObject provisioningShadow = provisioningService.getObject(ShadowType.class, shadowMorganOid, null, task, result); // THEN - display("Result", result); - assertFailure(result); + displayThen(TEST_NAME); + assertSuccess(result); syncServiceMock .assertNotifyChange() @@ -1888,11 +1902,13 @@ public void test810GetAccountMorganNotFound() throws Exception { .assertNone(); assertRepoShadow(shadowMorganOid) - .assertDead() - .assertIsNotExists() + .assertTombstone() .pendingOperations() .assertNone(); + ShadowAsserter.forShadow(provisioningShadow, "provisioning") + .assertTombstone(); + assertNoRepoShadow(ACCOUNT_MORGAN_OID); assertSteadyResources(); } @@ -2810,6 +2826,9 @@ private void assertDeletedMorgan(int expectedAttemptNumber, int expectenNumberOf assertShadowFuture(shadowMorganOid) .assertTombstone(); + + assertShadowFutureNoFetch(shadowMorganOid) + .assertTombstone(); dummyResource.resetBreakMode(); dummyResourceCtl.assertNoAccountByUsername(ACCOUNT_MORGAN_NAME); @@ -2853,7 +2872,7 @@ private PrismObject getShadowFuture(String oid) throws ObjectNotFoun assertSuccess(result); return shadow; } - + private PrismObject getShadowFuturePartialError(String oid) throws ObjectNotFoundException, CommunicationException, SchemaException, ConfigurationException, SecurityViolationException, ExpressionEvaluationException { Task task = createTask("getShadowFuture"); OperationResult result = task.getResult(); diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/AbstractAsserter.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/AbstractAsserter.java index 525ccfe8e41..0df0c0416ea 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/AbstractAsserter.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/AbstractAsserter.java @@ -30,10 +30,10 @@ * @author semancik * */ -public abstract class AbstractAsserter { +public abstract class AbstractAsserter { private String details; - private R returnAsserter; + private RA returnAsserter; private PrismContext prismContext; private ObjectResolver objectResolver; @@ -46,7 +46,7 @@ public AbstractAsserter(String details) { this.details = details; } - public AbstractAsserter(R returnAsserter, String details) { + public AbstractAsserter(RA returnAsserter, String details) { super(); this.returnAsserter = returnAsserter; this.details = details; @@ -84,7 +84,7 @@ protected String descWithDetails(Object o) { } } - public R end() { + public RA end() { return returnAsserter; } diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/FocusAsserter.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/FocusAsserter.java index 5c176a2787a..33e817cc1f0 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/FocusAsserter.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/FocusAsserter.java @@ -49,7 +49,7 @@ * @author semancik * */ -public class FocusAsserter extends PrismObjectAsserter { +public class FocusAsserter extends PrismObjectAsserter { private Map> projectionCache = new HashMap<>(); @@ -61,7 +61,7 @@ public FocusAsserter(PrismObject focus, String details) { super(focus, details); } - public FocusAsserter(PrismObject focus, R returnAsserter, String details) { + public FocusAsserter(PrismObject focus, RA returnAsserter, String details) { super(focus, returnAsserter, details); } @@ -74,48 +74,48 @@ public static FocusAsserter forFocus(PrismObject assertOid() { + public FocusAsserter assertOid() { super.assertOid(); return this; } @Override - public FocusAsserter assertOid(String expected) { + public FocusAsserter assertOid(String expected) { super.assertOid(expected); return this; } @Override - public FocusAsserter assertOidDifferentThan(String oid) { + public FocusAsserter assertOidDifferentThan(String oid) { super.assertOidDifferentThan(oid); return this; } @Override - public FocusAsserter assertName() { + public FocusAsserter assertName() { super.assertName(); return this; } @Override - public FocusAsserter assertName(String expectedOrig) { + public FocusAsserter assertName(String expectedOrig) { super.assertName(expectedOrig); return this; } @Override - public FocusAsserter assertLifecycleState(String expected) { + public FocusAsserter assertLifecycleState(String expected) { super.assertLifecycleState(expected); return this; } @Override - public FocusAsserter assertActiveLifecycleState() { + public FocusAsserter assertActiveLifecycleState() { super.assertActiveLifecycleState(); return this; } - public FocusAsserter assertAdministrativeStatus(ActivationStatusType expected) { + public FocusAsserter assertAdministrativeStatus(ActivationStatusType expected) { ActivationType activation = getActivation(); if (activation == null) { if (expected == null) { @@ -132,45 +132,46 @@ private ActivationType getActivation() { return getObject().asObjectable().getActivation(); } - public FocusAsserter display() { + public FocusAsserter display() { super.display(); return this; } - public FocusAsserter display(String message) { + public FocusAsserter display(String message) { super.display(message); return this; } - public FocusAsserter assertLinks(int expected) { - PrismReference linkRef = getObject().findReference(FocusType.F_LINK_REF); - if (linkRef == null) { - assertTrue("Expected "+expected+" links, but there is no linkRef in "+desc(), expected == 0); - return this; - } - assertEquals("Wrong number of links in " + desc(), expected, linkRef.size()); + public LinksAsserter, RA> links() { + LinksAsserter,RA> asserter = new LinksAsserter<>(this, getDetails()); + copySetupTo(asserter); + return asserter; + } + + public FocusAsserter assertLinks(int expected) { + links().assertLinks(expected); return this; } - public ShadowReferenceAsserter> singleLink() { + public ShadowReferenceAsserter> singleLink() { PrismReference linkRef = getObject().findReference(FocusType.F_LINK_REF); if (linkRef == null) { fail("Expected single link, but is no linkRef in "+desc()); return null; // not reached } assertEquals("Wrong number of links in " + desc(), 1, linkRef.size()); - ShadowReferenceAsserter> asserter = new ShadowReferenceAsserter<>(linkRef.getValue(0), this, "link in "+desc()); + ShadowReferenceAsserter> asserter = new ShadowReferenceAsserter<>(linkRef.getValue(0), null, this, "link in "+desc()); copySetupTo(asserter); return asserter; } - public FocusAsserter assertHasProjectionOnResource(String resourceOid) throws ObjectNotFoundException, SchemaException { + public FocusAsserter assertHasProjectionOnResource(String resourceOid) throws ObjectNotFoundException, SchemaException { PrismObject shadow = findProjectionOnResource(resourceOid); assertNotNull("Projection for resource "+resourceOid+" not found in "+desc(), shadow); return this; } - public > ShadowAsserter projectionOnResource(String resourceOid) throws ObjectNotFoundException, SchemaException { + public > ShadowAsserter projectionOnResource(String resourceOid) throws ObjectNotFoundException, SchemaException { PrismObject shadow = findProjectionOnResource(resourceOid); assertNotNull("Projection for resource "+resourceOid+" not found in "+desc(), shadow); ShadowAsserter asserter = new ShadowAsserter(shadow, (A)this, "projection of "+desc()); @@ -199,7 +200,7 @@ private List> getLinkTargets() throws ObjectNotFoundExce return shadows; } - private PrismObject getLinkTarget(String oid) throws ObjectNotFoundException, SchemaException { + PrismObject getLinkTarget(String oid) throws ObjectNotFoundException, SchemaException { PrismObject shadow = projectionCache.get(oid); if (shadow == null) { shadow = resolveObject(ShadowType.class, oid); @@ -208,7 +209,7 @@ private PrismObject getLinkTarget(String oid) throws ObjectNotFoundE return shadow; } - public FocusAsserter displayWithProjections() throws ObjectNotFoundException, SchemaException { + public FocusAsserter displayWithProjections() throws ObjectNotFoundException, SchemaException { display(); for (PrismObject linkTarget: getLinkTargets()) { IntegrationTestTools.display("projetion of "+desc(), linkTarget); diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/LinkFinder.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/LinkFinder.java new file mode 100644 index 00000000000..77e3424da65 --- /dev/null +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/LinkFinder.java @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2018 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.evolveum.midpoint.test.asserter; + +import java.util.List; + +import org.testng.AssertJUnit; + +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.PrismReferenceValue; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.schema.util.ShadowUtil; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultStatusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.PendingOperationExecutionStatusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.PendingOperationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; +import com.evolveum.prism.xml.ns._public.types_3.ChangeTypeType; +import com.evolveum.prism.xml.ns._public.types_3.ItemDeltaType; +import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; + +/** + * @author semancik + * + */ +public class LinkFinder,RA> { + + private final LinksAsserter linksAsserter; + private String resourceOid; + private Boolean dead; + + public LinkFinder(LinksAsserter linksAsserter) { + this.linksAsserter = linksAsserter; + } + + public LinkFinder resourceOid(String resourceOid) { + this.resourceOid = resourceOid; + return this; + } + + public LinkFinder dead(boolean dead) { + this.dead = dead; + return this; + } + + public ShadowReferenceAsserter> find() throws ObjectNotFoundException, SchemaException { + PrismReferenceValue found = null; + PrismObject foundTarget = null; + for (PrismReferenceValue link: linksAsserter.getLinks()) { + PrismObject linkTarget = linksAsserter.getLinkTarget(link.getOid()); + if (matches(link, linkTarget)) { + if (found == null) { + found = link; + foundTarget = linkTarget; + } else { + fail("Found more than one link that matches search criteria"); + } + } + } + if (found == null) { + fail("Found no link that matches search criteria"); + } + return linksAsserter.forLink(found, foundTarget); + } + + private boolean matches(PrismReferenceValue refVal, PrismObject linkTarget) throws ObjectNotFoundException, SchemaException { + ShadowType linkTargetType = linkTarget.asObjectable(); + + if (resourceOid != null) { + if (!resourceOid.equals(linkTargetType.getResourceRef().getOid())) { + return false; + } + } + + if (dead != null) { + if (dead && !ShadowUtil.isDead(linkTargetType)) { + return false; + } else if (!dead && ShadowUtil.isDead(linkTargetType)) { + return false; + } + } + + // TODO: more criteria + return true; + } + + protected void fail(String message) { + AssertJUnit.fail(message); + } + +} diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/LinksAsserter.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/LinksAsserter.java new file mode 100644 index 00000000000..859a42466d9 --- /dev/null +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/LinksAsserter.java @@ -0,0 +1,130 @@ +/** + * Copyright (c) 2018 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.evolveum.midpoint.test.asserter; + +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.PrismReference; +import com.evolveum.midpoint.prism.PrismReferenceValue; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.PendingOperationExecutionStatusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.PendingOperationType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; +import com.evolveum.prism.xml.ns._public.types_3.ChangeTypeType; + +/** + * @author semancik + * + */ +public class LinksAsserter,RA> extends AbstractAsserter { + + private FA focusAsserter; + private List links; + + public LinksAsserter(FA focusAsserter) { + super(); + this.focusAsserter = focusAsserter; + } + + public LinksAsserter(FA focusAsserter, String details) { + super(details); + this.focusAsserter = focusAsserter; + } + + public static LinksAsserter,Void> forFocus(PrismObject focus) { + return new LinksAsserter<>(FocusAsserter.forFocus(focus)); + } + + PrismObject getLinkTarget(String oid) throws ObjectNotFoundException, SchemaException { + return focusAsserter.getLinkTarget(oid); + } + + List getLinks() { + if (links == null) { + PrismReference linkRef = getFocus().findReference(FocusType.F_LINK_REF); + if (linkRef == null) { + links = new ArrayList<>(); + } else { + links = linkRef.getValues(); + } + } + return links; + } + + public LinksAsserter assertLinks(int expected) { + assertEquals("Wrong number of links in " + desc(), expected, getLinks().size()); + return this; + } + + public LinksAsserter assertNone() { + assertLinks(0); + return this; + } + + ShadowReferenceAsserter> forLink(PrismReferenceValue refVal, PrismObject shadow) { + ShadowReferenceAsserter> asserter = new ShadowReferenceAsserter<>(refVal, shadow, this, "link in "+desc()); + copySetupTo(asserter); + return asserter; + } + + public ShadowReferenceAsserter> single() { + assertLinks(1); + return forLink(getLinks().get(0), null); + } + + PrismObject getFocus() { + return focusAsserter.getObject(); + } + + @Override + public FA end() { + return focusAsserter; + } + + @Override + protected String desc() { + return descWithDetails("links of "+getFocus()); + } + + public LinkFinder by() { + return new LinkFinder<>(this); + } + + public ShadowReferenceAsserter> projectionOnResource(String resourceOid) throws ObjectNotFoundException, SchemaException { + return by() + .resourceOid(resourceOid) + .find(); + } + + public ShadowReferenceAsserter> deadShadow(String resourceOid) throws ObjectNotFoundException, SchemaException { + return by() + .dead(true) + .find(); + } + + +} diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/ObjectDeltaTypeAsserter.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/ObjectDeltaTypeAsserter.java index 92e036c7ef4..d285f8fa33d 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/ObjectDeltaTypeAsserter.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/ObjectDeltaTypeAsserter.java @@ -31,7 +31,7 @@ * @author semancik * */ -public class ObjectDeltaTypeAsserter extends AbstractAsserter { +public class ObjectDeltaTypeAsserter extends AbstractAsserter { private ObjectDeltaType delta; @@ -45,8 +45,8 @@ public ObjectDeltaTypeAsserter(ObjectDeltaType delta, String details) { this.delta = delta; } - public ObjectDeltaTypeAsserter(ObjectDeltaType delta, R returnAsserter, String details) { - super(details); + public ObjectDeltaTypeAsserter(ObjectDeltaType delta, RA returnAsserter, String details) { + super(returnAsserter, details); this.delta = delta; } @@ -58,22 +58,22 @@ public static ObjectDeltaTypeAsserter forDelta(ObjectDeltaType delta, Stri return new ObjectDeltaTypeAsserter<>(delta, details); } - public ObjectDeltaTypeAsserter assertAdd() { + public ObjectDeltaTypeAsserter assertAdd() { assertChangeType(ChangeTypeType.ADD); return this; } - public ObjectDeltaTypeAsserter assertModify() { + public ObjectDeltaTypeAsserter assertModify() { assertChangeType(ChangeTypeType.MODIFY); return this; } - public ObjectDeltaTypeAsserter assertDelete() { + public ObjectDeltaTypeAsserter assertDelete() { assertChangeType(ChangeTypeType.DELETE); return this; } - public ObjectDeltaTypeAsserter assertChangeType(ChangeTypeType expected) { + public ObjectDeltaTypeAsserter assertChangeType(ChangeTypeType expected) { assertEquals("Wrong change type in "+desc(), expected, delta.getChangeType()); return this; } @@ -82,7 +82,7 @@ protected String desc() { return descWithDetails(delta); } - public ObjectDeltaTypeAsserter display() { + public ObjectDeltaTypeAsserter display() { if (getDetails() != null) { display(getDetails()); } else { @@ -91,7 +91,7 @@ public ObjectDeltaTypeAsserter display() { return this; } - public ObjectDeltaTypeAsserter display(String message) { + public ObjectDeltaTypeAsserter display(String message) { IntegrationTestTools.display(message, PrettyPrinter.debugDump(delta, 1)); return this; } diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/ObjectReferenceAsserter.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/ObjectReferenceAsserter.java index 135b10aaba9..dbb975a4d4b 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/ObjectReferenceAsserter.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/ObjectReferenceAsserter.java @@ -47,6 +47,7 @@ public class ObjectReferenceAsserter extends AbstractAsserter { final private PrismReferenceValue refVal; + private PrismObject resolvedTarget = null; final private Class defaultTargetTypeClass; public ObjectReferenceAsserter(PrismReferenceValue refVal, Class defaultTargetTypeClass) { @@ -61,10 +62,11 @@ public ObjectReferenceAsserter(PrismReferenceValue refVal, Class defaultTarge this.defaultTargetTypeClass = defaultTargetTypeClass; } - public ObjectReferenceAsserter(PrismReferenceValue refVal, Class defaultTargetTypeClass, R returnAsserter, String detail) { + public ObjectReferenceAsserter(PrismReferenceValue refVal, Class defaultTargetTypeClass, PrismObject resolvedTarget, R returnAsserter, String detail) { super(returnAsserter, detail); this.refVal = refVal; this.defaultTargetTypeClass = defaultTargetTypeClass; + this.resolvedTarget = resolvedTarget; } protected PrismReferenceValue getRefVal() { @@ -85,6 +87,17 @@ public PrismObjectAsserter> object() { return new PrismObjectAsserter<>((PrismObject)refVal.getObject(), this, "object in "+desc()); } + protected PrismObject getResolvedTarget() throws ObjectNotFoundException, SchemaException { + if (resolvedTarget == null) { + resolvedTarget = resolveTargetObject(); + } + return resolvedTarget; + } + + public PrismObjectAsserter> target() throws ObjectNotFoundException, SchemaException { + return new PrismObjectAsserter<>(getResolvedTarget(), this, "object resolved from "+desc()); + } + public PrismObjectAsserter> resolveTarget() throws ObjectNotFoundException, SchemaException { PrismObject object = resolveTargetObject(); return new PrismObjectAsserter<>(object, this, "object resolved from "+desc()); diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/ShadowReferenceAsserter.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/ShadowReferenceAsserter.java index 6304f03629b..98009115575 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/ShadowReferenceAsserter.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/ShadowReferenceAsserter.java @@ -54,8 +54,8 @@ public ShadowReferenceAsserter(PrismReferenceValue refVal, String detail) { super(refVal, ShadowType.class, detail); } - public ShadowReferenceAsserter(PrismReferenceValue refVal, R returnAsserter, String detail) { - super(refVal, ShadowType.class, returnAsserter, detail); + public ShadowReferenceAsserter(PrismReferenceValue refVal, PrismObject resolvedTarget, R returnAsserter, String detail) { + super(refVal, ShadowType.class, resolvedTarget, returnAsserter, detail); } @Override @@ -75,6 +75,12 @@ public ShadowAsserter> shadow() { return asserter; } + @Override + public ShadowAsserter> target() + throws ObjectNotFoundException, SchemaException { + return new ShadowAsserter<>(getResolvedTarget(), this, "object resolved from "+desc()); + } + @Override public ShadowAsserter> resolveTarget() throws ObjectNotFoundException, SchemaException { diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/UserAsserter.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/UserAsserter.java index c8625e59283..c996874c086 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/UserAsserter.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/asserter/UserAsserter.java @@ -42,7 +42,7 @@ * @author semancik * */ -public class UserAsserter extends FocusAsserter { +public class UserAsserter extends FocusAsserter { public UserAsserter(PrismObject focus) { super(focus); @@ -52,7 +52,7 @@ public UserAsserter(PrismObject focus, String details) { super(focus, details); } - public UserAsserter(PrismObject focus, R returnAsserter, String details) { + public UserAsserter(PrismObject focus, RA returnAsserter, String details) { super(focus, returnAsserter, details); } @@ -65,48 +65,48 @@ public static UserAsserter forUser(PrismObject focus, String det } @Override - public UserAsserter assertOid() { + public UserAsserter assertOid() { super.assertOid(); return this; } @Override - public UserAsserter assertOid(String expected) { + public UserAsserter assertOid(String expected) { super.assertOid(expected); return this; } @Override - public UserAsserter assertOidDifferentThan(String oid) { + public UserAsserter assertOidDifferentThan(String oid) { super.assertOidDifferentThan(oid); return this; } @Override - public UserAsserter assertName() { + public UserAsserter assertName() { super.assertName(); return this; } @Override - public UserAsserter assertName(String expectedOrig) { + public UserAsserter assertName(String expectedOrig) { super.assertName(expectedOrig); return this; } @Override - public UserAsserter assertLifecycleState(String expected) { + public UserAsserter assertLifecycleState(String expected) { super.assertLifecycleState(expected); return this; } @Override - public UserAsserter assertActiveLifecycleState() { + public UserAsserter assertActiveLifecycleState() { super.assertActiveLifecycleState(); return this; } - public UserAsserter assertAdministrativeStatus(ActivationStatusType expected) { + public UserAsserter assertAdministrativeStatus(ActivationStatusType expected) { ActivationType activation = getActivation(); if (activation == null) { if (expected == null) { @@ -123,45 +123,52 @@ private ActivationType getActivation() { return getObject().asObjectable().getActivation(); } - public UserAsserter display() { + public UserAsserter display() { super.display(); return this; } - public UserAsserter display(String message) { + public UserAsserter display(String message) { super.display(message); return this; } @Override - public UserAsserter assertLinks(int expected) { + public LinksAsserter, RA> links() { + LinksAsserter, RA> asserter = new LinksAsserter<>(this, getDetails()); + copySetupTo(asserter); + return asserter; + } + + @Override + public UserAsserter assertLinks(int expected) { super.assertLinks(expected); return this; } - public UserAsserter assertFullName(String expectedOrig) { + public UserAsserter assertFullName(String expectedOrig) { assertPolyStringProperty(UserType.F_FULL_NAME, expectedOrig); return this; } - public UserAsserter assertLocality(String expectedOrig) { + public UserAsserter assertLocality(String expectedOrig) { assertPolyStringProperty(UserType.F_LOCALITY, expectedOrig); return this; } @Override - public UserAsserter assertHasProjectionOnResource(String resourceOid) throws ObjectNotFoundException, SchemaException { + public UserAsserter assertHasProjectionOnResource(String resourceOid) throws ObjectNotFoundException, SchemaException { super.assertHasProjectionOnResource(resourceOid); return this; } @Override - public ShadowAsserter> projectionOnResource(String resourceOid) throws ObjectNotFoundException, SchemaException { + public ShadowAsserter> projectionOnResource(String resourceOid) throws ObjectNotFoundException, SchemaException { return super.projectionOnResource(resourceOid); } @Override - public UserAsserter displayWithProjections() throws ObjectNotFoundException, SchemaException { + public UserAsserter displayWithProjections() throws ObjectNotFoundException, SchemaException { super.displayWithProjections(); return this; }