Skip to content

Commit

Permalink
Merge branch 'master' of github.com:Evolveum/midpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
1azyman committed Mar 16, 2023
2 parents 7c8c814 + e024772 commit cd707fb
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ public abstract class AbstractWfTest extends AbstractModelImplementationIntegrat

protected static final String USER_ADMINISTRATOR_OID = SystemObjectsType.USER_ADMINISTRATOR.value();

protected static final String DUMMY_SIMPLE_WORKFLOW_NOTIFIER_PROCESSES = "dummy:simpleWorkflowNotifier-Processes";
protected static final String DUMMY_SIMPLE_WORKFLOW_NOTIFIER_WORK_ITEMS = "dummy:simpleWorkflowNotifier-WorkItems";

@Autowired protected Clockwork clockwork;
@Autowired protected TaskManager taskManager;
@Autowired protected CaseManager caseManager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@
/**
* A special test dealing with assigning roles that have different metarole-induced approval policies.
*
* Role21 - uses default approval (org:approver)
* Role22 - uses metarole 1 'default' induced approval (org:special-approver)
* Role23 - uses both metarole 'default' and 'security' induced approval (org:special-approver and org:security-approver)
* RoleExtensionPropertyModApproval - requires an approval when extension property is to be modified
* . `Role21` - uses default approval (org:approver)
* . `Role22` - uses metarole 1 'default' induced approval (org:special-approver)
* . `Role23` - uses both metarole 'default' and 'security' induced approval (org:special-approver and org:security-approver)
* . `RoleExtensionPropertyModApproval` - requires an approval when extension property is to be modified
*
* TODO clean up this test, using "new" asserters
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -438,8 +438,8 @@ public void test220Reject() throws Exception {
assertEquals("Wrong causeDisplayName in " + r, Collections.singleton("Automatic rejection at deadline"), r.getPropertyValues(AuditingConstants.AUDIT_CAUSE_DISPLAY_NAME));
assertEquals("Wrong result in " + r, "Rejected", r.getResult());
}
displayCollection("notifications - process", dummyTransport.getMessages("dummy:simpleWorkflowNotifier-Processes"));
List<Message> notifications = dummyTransport.getMessages("dummy:simpleWorkflowNotifier-WorkItems");
displayCollection("notifications - cases", dummyTransport.getMessages(DUMMY_SIMPLE_WORKFLOW_NOTIFIER_PROCESSES));
List<Message> notifications = dummyTransport.getMessages(DUMMY_SIMPLE_WORKFLOW_NOTIFIER_WORK_ITEMS);
displayCollection("notifications - work items", notifications);
for (Message notification : notifications) {
assertContains(notification, "Reason: Automatic rejection at deadline (timed action)");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import java.util.*;
import java.util.stream.Collectors;

import com.evolveum.midpoint.notifications.api.transports.Message;

import org.jetbrains.annotations.NotNull;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
Expand Down Expand Up @@ -77,6 +79,9 @@ public class TestMiscellaneous extends AbstractWfTestPolicy {
private static final TestResource<RoleType> ROLE_TEST380 = new TestResource<>(TEST_RESOURCE_DIR, "role-test380.xml", "8f39e4ad-298a-4d9a-b793-56ad2f0fc7ce");
private static final TestResource<UserType> USER_TEST380 = new TestResource<>(TEST_RESOURCE_DIR, "user-test380.xml", "1994a4d0-4151-4260-82da-bcd1866c296a");

private static final TestResource<RoleType> ROLE_AUTOCOMPLETIONS = new TestResource<>(
TEST_RESOURCE_DIR, "role-autocompletions.xml", "a2570ee8-6c13-48b9-9a33-d8e88c4fe618");

@Override
protected PrismObject<UserType> getDefaultActor() {
return userAdministrator;
Expand Down Expand Up @@ -106,6 +111,8 @@ public void initSystem(Task initTask, OperationResult initResult) throws Excepti
addAndRecompute(USER_SCROOGE, initTask, initResult);
addAndRecompute(USER_GIZMODUCK, initTask, initResult);
addAndRecompute(USER_LAUNCHPAD, initTask, initResult);

addObject(ROLE_AUTOCOMPLETIONS, initTask, initResult);
}

@Test
Expand Down Expand Up @@ -665,11 +672,14 @@ public void test380DeleteUserWithApproval() throws Exception {
* Marks one root and one non-root case as indestructible, just to check if they survive the cleanup.
*
* Expected survivors:
*
* - indestructible root and all of its children,
* - indestructible child (selected in such a way that it has no children).
*
* Depends on previous test methods.
*/
@Test
public void test999CaseCleanup() throws Exception {
public void test399CaseCleanup() throws Exception {
given("mark indestructible cases");
OperationResult result = getTestOperationResult();

Expand Down Expand Up @@ -772,4 +782,57 @@ private boolean isChildLess(CaseType aCase, List<CaseType> closedCases) {
return closedCases.stream()
.noneMatch(c -> c.getParentRef() != null && c.getParentRef().getOid().equals(aCase.getOid()));
}

/**
* Checks that the notifications are sent out correctly even with auto-completed stages.
*
* MID-8587
*/
@Test
public void test400NotificationsWithAutoCompletion() throws Exception {
Task task = getTestTask();
OperationResult result = task.getResult();
login(userAdministrator);

dummyTransport.clearMessages();

when("a user with role assignment is created");
String name = "test390";
UserType user = new UserType()
.name(name)
.assignment(ROLE_AUTOCOMPLETIONS.assignmentTo());
addObject(user, task, result);

then("role is not assigned, and a case is created");
assertNoUserByUsername(name);
assertCase(result, "after")
.display();

and("case notifications are OK");
List<Message> casesNotifications = dummyTransport.getMessages(DUMMY_SIMPLE_WORKFLOW_NOTIFIER_PROCESSES);
displayCollection("notifications - cases", casesNotifications);
//noinspection AssertBetweenInconvertibleTypes
assertThat(casesNotifications).as("cases notifications")
.singleElement()
.extracting(m -> m.getSubject())
.isEqualTo("An approval case has been opened");

and("work items notifications are OK");
List<Message> workItemsNotifications =
new ArrayList<>(dummyTransport.getMessages(DUMMY_SIMPLE_WORKFLOW_NOTIFIER_WORK_ITEMS));
workItemsNotifications.sort(
Comparator.comparing(m -> m.getSubject()));
displayCollection("notifications - work items", workItemsNotifications);
assertThat(workItemsNotifications).as("work item notifications").hasSize(2);
Message first = workItemsNotifications.get(0);
assertThat(first.getSubject()).as("first work item notification subject")
.isEqualTo("A new work item has been created");
assertThat(first.getBody()).as("first work item notification body")
.contains("Stage: 3/3");
Message second = workItemsNotifications.get(1);
assertThat(second.getSubject()).as("second work item notification subject")
.isEqualTo("Work item has been allocated to you");
assertThat(second.getBody()).as("second work item notification body")
.contains("Stage: 3/3");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<!--
~ Copyright (C) 2010-2023 Evolveum and contributors
~
~ This work is dual-licensed under the Apache License 2.0
~ and European Union Public License. See LICENSE file for details.
-->

<role xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
oid="a2570ee8-6c13-48b9-9a33-d8e88c4fe618">
<name>autocompletions</name>
<assignment>
<policyRule>
<policyConstraints>
<assignment>
<operation>add</operation>
</assignment>
</policyConstraints>
<policyActions>
<approval>
<approvalSchema>
<stage>
<number>1</number>
<approverRef oid="00000000-0000-0000-0000-000000000002" type="UserType"/>
<automaticallyCompleted>
<script>
<code>'approve'</code>
</script>
</automaticallyCompleted>
</stage>
<stage>
<number>2</number>
<approverRef oid="00000000-0000-0000-0000-000000000002" type="UserType"/>
<automaticallyCompleted>
<script>
<code>'skip'</code>
</script>
</automaticallyCompleted>
</stage>
<stage>
<number>3</number>
<approverRef oid="00000000-0000-0000-0000-000000000002" type="UserType"/>
</stage>
</approvalSchema>
</approval>
</policyActions>
</policyRule>
</assignment>
</role>
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (C) 2010-2022 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/
package com.evolveum.midpoint.repo.sqale.filtering;

import java.util.function.Function;

import javax.xml.namespace.QName;

import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Ops;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.EnumPath;
import com.evolveum.midpoint.prism.query.PropertyValueFilter;
import com.evolveum.midpoint.repo.sqale.qmodel.object.MObjectType;
import com.evolveum.midpoint.repo.sqlbase.QueryException;
import com.evolveum.midpoint.repo.sqlbase.RepositoryException;
import com.evolveum.midpoint.repo.sqlbase.SqlQueryContext;
import com.evolveum.midpoint.repo.sqlbase.filtering.item.FilterOperation;
import com.evolveum.midpoint.repo.sqlbase.filtering.item.SimpleItemFilterProcessor;
import com.evolveum.midpoint.repo.sqlbase.filtering.item.SinglePathItemFilterProcessor;
import com.evolveum.midpoint.repo.sqlbase.querydsl.FlexibleRelationalPathBase;

/**
* Similar to {@link SimpleItemFilterProcessor} but String value can be just UUID prefixes
* and must be smartly converted based on the actual operation.
*
* [WARNING]
* Prefix support assumes OID column only and does not treat predicate for nullable columns.
*/
public class TypeQNameItemFilterProcessor extends SinglePathItemFilterProcessor<QName, EnumPath<MObjectType>> {

public <Q extends FlexibleRelationalPathBase<R>, R> TypeQNameItemFilterProcessor(
SqlQueryContext<?, Q, R> context, Function<Q, EnumPath<MObjectType>> rootToQueryItem) {
super(context, rootToQueryItem);
}

@Override
public Predicate process(PropertyValueFilter<QName> filter) throws RepositoryException {
FilterOperation operation = operation(filter);
if (!operation.isEqualOperation()) {
throw new QueryException("Only equal filter supported");
}
if (filter.hasNoValue()) {
if (operation.isAnyEqualOperation()) {
return ExpressionUtils.predicate(Ops.IS_NULL, path);
} else {
throw new QueryException("Null value for other than EQUAL filter: " + filter);
}
}

Predicate predicate = null;
for (var value : filter.getValues()) {
var local = path.eq(MObjectType.fromTypeQName(value.getValue()));
if (predicate == null) {
predicate = local;
} else {
predicate = ExpressionUtils.and(predicate, local);
}
}
return predicate;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@
import com.evolveum.midpoint.prism.path.PathSet;
import com.evolveum.midpoint.repo.sqale.SqaleRepoContext;
import com.evolveum.midpoint.repo.sqale.SqaleUtils;
import com.evolveum.midpoint.repo.sqale.delta.item.SinglePathItemDeltaProcessor;
import com.evolveum.midpoint.repo.sqale.filtering.TypeQNameItemFilterProcessor;
import com.evolveum.midpoint.repo.sqale.mapping.SqaleItemSqlMapper;
import com.evolveum.midpoint.repo.sqale.qmodel.common.QContainerMapping;
import com.evolveum.midpoint.repo.sqale.qmodel.object.MObjectType;
import com.evolveum.midpoint.repo.sqlbase.JdbcSession;
import com.evolveum.midpoint.repo.sqlbase.mapping.TableRelationResolver;
import com.evolveum.midpoint.repo.sqlbase.querydsl.UuidPath;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SimulationResultProcessedObjectType;
import com.querydsl.core.types.dsl.EnumPath;

import static com.evolveum.midpoint.xml.ns._public.common.common_3.SimulationResultProcessedObjectType.*;

import java.util.Objects;
import java.util.function.Function;

public class QProcessedObjectMapping extends QContainerMapping<SimulationResultProcessedObjectType, QProcessedObject, MProcessedObject, MSimulationResult> {

Expand Down Expand Up @@ -55,6 +61,12 @@ public QProcessedObjectMapping(@NotNull SqaleRepoContext repositoryContext) {
addItemMapping(F_NAME, polyStringMapper(
q -> q.nameOrig, q -> q.nameNorm));
//addItemMapping(F_TYPE, ));
Function<QProcessedObject, EnumPath<MObjectType>> objectTypePath = q -> q.objectType;
addItemMapping(F_TYPE, new SqaleItemSqlMapper<>(
ctx -> new TypeQNameItemFilterProcessor(ctx, objectTypePath),
ctx -> new SinglePathItemDeltaProcessor<>(ctx, objectTypePath),
objectTypePath
));
addItemMapping(F_TRANSACTION_ID, stringMapper(q -> q.transactionId));
addItemMapping(F_STATE, enumMapper(q -> q.state));
addRefMapping(F_EVENT_MARK_REF, QProcessedObjectEventMarkReferenceMapping.init(repositoryContext));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -405,18 +405,18 @@ public void test300SearchForProcessedObjects() throws SchemaException {
.as("state")
.isEqualTo(ObjectProcessingStateType.ADDED));

// when("checking search by type");
// ObjectQuery byType =
// PrismContext.get().queryFor(SimulationResultProcessedObjectType.class)
// .ownerId(secondResultOid)
// .and()
// .item(SimulationResultProcessedObjectType.F_TYPE)
// .eq(ShadowType.COMPLEX_TYPE)
// .build();
// checkCountAndSearch("by type", byType, 1, result,
// po -> assertThat(po.getType())
// .as("type")
// .isEqualTo(ShadowType.COMPLEX_TYPE));
when("checking search by type");
ObjectQuery byType =
PrismContext.get().queryFor(SimulationResultProcessedObjectType.class)
.ownerId(secondResultOid)
.and()
.item(SimulationResultProcessedObjectType.F_TYPE)
.eq(ShadowType.COMPLEX_TYPE)
.build();
checkCountAndSearch("by type", byType, 1, result,
po -> assertThat(po.getType())
.as("type")
.isEqualTo(ShadowType.COMPLEX_TYPE));
}

@SuppressWarnings("SameParameterValue")
Expand Down

0 comments on commit cd707fb

Please sign in to comment.