View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.fit.core;
20  
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertFalse;
23  import static org.junit.jupiter.api.Assertions.assertNotNull;
24  import static org.junit.jupiter.api.Assertions.assertNull;
25  import static org.junit.jupiter.api.Assertions.assertTrue;
26  import static org.junit.jupiter.api.Assertions.fail;
27  
28  import java.util.HashMap;
29  import java.util.Map;
30  import java.util.Set;
31  import javax.ws.rs.core.Response;
32  import org.apache.syncope.client.lib.SyncopeClient;
33  import org.apache.syncope.common.lib.SyncopeConstants;
34  import org.apache.syncope.common.lib.request.GroupCR;
35  import org.apache.syncope.common.lib.to.AnyTypeClassTO;
36  import org.apache.syncope.common.lib.to.ExecTO;
37  import org.apache.syncope.common.lib.to.GroupTO;
38  import org.apache.syncope.common.lib.to.Item;
39  import org.apache.syncope.common.lib.to.Mapping;
40  import org.apache.syncope.common.lib.to.NotificationTO;
41  import org.apache.syncope.common.lib.to.NotificationTaskTO;
42  import org.apache.syncope.common.lib.to.PagedResult;
43  import org.apache.syncope.common.lib.to.PlainSchemaTO;
44  import org.apache.syncope.common.lib.to.Provision;
45  import org.apache.syncope.common.lib.to.PushTaskTO;
46  import org.apache.syncope.common.lib.to.ReconStatus;
47  import org.apache.syncope.common.lib.to.ResourceTO;
48  import org.apache.syncope.common.lib.types.AnyTypeKind;
49  import org.apache.syncope.common.lib.types.AttrSchemaType;
50  import org.apache.syncope.common.lib.types.ExecStatus;
51  import org.apache.syncope.common.lib.types.IdMImplementationType;
52  import org.apache.syncope.common.lib.types.MappingPurpose;
53  import org.apache.syncope.common.lib.types.MatchingRule;
54  import org.apache.syncope.common.lib.types.SchemaType;
55  import org.apache.syncope.common.lib.types.TaskType;
56  import org.apache.syncope.common.lib.types.ThreadPoolSettings;
57  import org.apache.syncope.common.lib.types.TraceLevel;
58  import org.apache.syncope.common.lib.types.UnmatchingRule;
59  import org.apache.syncope.common.rest.api.RESTHeaders;
60  import org.apache.syncope.common.rest.api.beans.ReconQuery;
61  import org.apache.syncope.common.rest.api.beans.TaskQuery;
62  import org.apache.syncope.common.rest.api.service.NotificationService;
63  import org.apache.syncope.common.rest.api.service.ResourceService;
64  import org.apache.syncope.common.rest.api.service.TaskService;
65  import org.identityconnectors.framework.common.objects.ObjectClass;
66  import org.junit.jupiter.api.Test;
67  import org.springframework.jdbc.core.JdbcTemplate;
68  
69  public class PushTaskITCase extends AbstractTaskITCase {
70  
71      @Test
72      public void getPushActionsClasses() {
73          Set<String> actions = ANONYMOUS_CLIENT.platform().
74                  getJavaImplInfo(IdMImplementationType.PUSH_ACTIONS).get().getClasses();
75          assertNotNull(actions);
76      }
77  
78      @Test
79      public void read() {
80          PushTaskTO pushTaskTO = TASK_SERVICE.<PushTaskTO>read(
81                  TaskType.PUSH, "0bc11a19-6454-45c2-a4e3-ceef84e5d79b", true);
82          assertEquals(UnmatchingRule.ASSIGN, pushTaskTO.getUnmatchingRule());
83          assertEquals(MatchingRule.UPDATE, pushTaskTO.getMatchingRule());
84      }
85  
86      @Test
87      public void list() {
88          PagedResult<PushTaskTO> tasks = TASK_SERVICE.search(new TaskQuery.Builder(TaskType.PUSH).build());
89          assertFalse(tasks.getResult().isEmpty());
90          tasks.getResult().stream().
91                  filter((task) -> (!(task instanceof PushTaskTO))).
92                  forEach(item -> fail("This should not happen"));
93      }
94  
95      @Test
96      public void createPushTask() {
97          PushTaskTO task = new PushTaskTO();
98          task.setName(getUUIDString());
99          task.setResource(RESOURCE_NAME_WS2);
100         task.setSourceRealm(SyncopeConstants.ROOT_REALM);
101         task.getFilters().put(AnyTypeKind.USER.name(),
102                 SyncopeClient.getUserSearchConditionBuilder().hasNotResources(RESOURCE_NAME_TESTDB2).query());
103         task.getFilters().put(AnyTypeKind.GROUP.name(),
104                 SyncopeClient.getGroupSearchConditionBuilder().isNotNull("cool").query());
105         task.setMatchingRule(MatchingRule.LINK);
106 
107         Response response = TASK_SERVICE.create(TaskType.PUSH, task);
108         PushTaskTO actual = getObject(response.getLocation(), TaskService.class, PushTaskTO.class);
109         assertNotNull(actual);
110 
111         task = TASK_SERVICE.read(TaskType.PUSH, actual.getKey(), true);
112         assertNotNull(task);
113         assertEquals(task.getKey(), actual.getKey());
114         assertEquals(task.getJobDelegate(), actual.getJobDelegate());
115         assertEquals(task.getFilters().get(AnyTypeKind.USER.name()),
116                 actual.getFilters().get(AnyTypeKind.USER.name()));
117         assertEquals(task.getFilters().get(AnyTypeKind.GROUP.name()),
118                 actual.getFilters().get(AnyTypeKind.GROUP.name()));
119         assertEquals(UnmatchingRule.ASSIGN, actual.getUnmatchingRule());
120         assertEquals(MatchingRule.LINK, actual.getMatchingRule());
121     }
122 
123     @Test
124     public void pushMatchingUnmatchingGroups() {
125         assertFalse(GROUP_SERVICE.read("29f96485-729e-4d31-88a1-6fc60e4677f3").
126                 getResources().contains(RESOURCE_NAME_LDAP));
127 
128         execProvisioningTask(
129                 TASK_SERVICE, TaskType.PUSH, "fd905ba5-9d56-4f51-83e2-859096a67b75", MAX_WAIT_SECONDS, false);
130 
131         assertNotNull(RESOURCE_SERVICE.readConnObject(
132                 RESOURCE_NAME_LDAP, AnyTypeKind.GROUP.name(), "29f96485-729e-4d31-88a1-6fc60e4677f3"));
133         assertTrue(GROUP_SERVICE.read("29f96485-729e-4d31-88a1-6fc60e4677f3").
134                 getResources().contains(RESOURCE_NAME_LDAP));
135     }
136 
137     @Test
138     public void pushUnmatchingUsers() throws Exception {
139         assertFalse(USER_SERVICE.read("74cd8ece-715a-44a4-a736-e17b46c4e7e6").
140                 getResources().contains(RESOURCE_NAME_TESTDB2));
141         assertFalse(USER_SERVICE.read("b3cbc78d-32e6-4bd4-92e0-bbe07566a2ee").
142                 getResources().contains(RESOURCE_NAME_TESTDB2));
143         assertFalse(USER_SERVICE.read("c9b2dec2-00a7-4855-97c0-d854842b4b24").
144                 getResources().contains(RESOURCE_NAME_TESTDB2));
145         assertTrue(USER_SERVICE.read("823074dc-d280-436d-a7dd-07399fae48ec").
146                 getResources().contains(RESOURCE_NAME_TESTDB2));
147 
148         JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
149         assertEquals(0, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='puccini'").size());
150 
151         // ------------------------------------------
152         // Unmatching --> Assign --> dryRuyn
153         // ------------------------------------------
154         execProvisioningTask(
155                 TASK_SERVICE, TaskType.PUSH, "af558be4-9d2f-4359-bf85-a554e6e90be1", MAX_WAIT_SECONDS, true);
156         assertEquals(0, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='vivaldi'").size());
157         assertFalse(USER_SERVICE.read("b3cbc78d-32e6-4bd4-92e0-bbe07566a2ee").
158                 getResources().contains(RESOURCE_NAME_TESTDB2));
159         // ------------------------------------------
160 
161         Set<String> pushTaskKeys = Set.of(
162                 "af558be4-9d2f-4359-bf85-a554e6e90be1",
163                 "97f327b6-2eff-4d35-85e8-d581baaab855",
164                 "03aa2a04-4881-4573-9117-753f81b04865",
165                 "5e5f7c7e-9de7-4c6a-99f1-4df1af959807");
166         execProvisioningTasks(TASK_SERVICE, TaskType.PUSH, pushTaskKeys, MAX_WAIT_SECONDS, false);
167 
168         // ------------------------------------------
169         // Unatching --> Ignore
170         // ------------------------------------------
171         assertEquals(1, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='verdi'").size());
172         assertFalse(USER_SERVICE.read("74cd8ece-715a-44a4-a736-e17b46c4e7e6").
173                 getResources().contains(RESOURCE_NAME_TESTDB2));
174         // ------------------------------------------
175 
176         // ------------------------------------------
177         // Unmatching --> Assign
178         // ------------------------------------------
179         assertEquals(1, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='vivaldi'").size());
180         assertTrue(USER_SERVICE.read("b3cbc78d-32e6-4bd4-92e0-bbe07566a2ee").
181                 getResources().contains(RESOURCE_NAME_TESTDB2));
182         jdbcTemplate.execute("DELETE FROM test2 WHERE ID='vivaldi'");
183         // ------------------------------------------
184 
185         // ------------------------------------------
186         // Unmatching --> Provision
187         // ------------------------------------------
188         assertEquals(1, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='bellini'").size());
189         assertFalse(USER_SERVICE.read("c9b2dec2-00a7-4855-97c0-d854842b4b24").
190                 getResources().contains(RESOURCE_NAME_TESTDB2));
191         jdbcTemplate.execute("DELETE FROM test2 WHERE ID='bellini'");
192         // ------------------------------------------
193 
194         // ------------------------------------------
195         // Unmatching --> Unlink
196         // ------------------------------------------
197         assertEquals(0, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='puccini'").size());
198         assertFalse(USER_SERVICE.read("823074dc-d280-436d-a7dd-07399fae48ec").
199                 getResources().contains(RESOURCE_NAME_TESTDB2));
200         // ------------------------------------------
201     }
202 
203     @Test
204     public void pushMatchingUser() throws Exception {
205         assertTrue(USER_SERVICE.read("1417acbe-cbf6-4277-9372-e75e04f97000").
206                 getResources().contains(RESOURCE_NAME_TESTDB2));
207         assertFalse(USER_SERVICE.read("74cd8ece-715a-44a4-a736-e17b46c4e7e6").
208                 getResources().contains(RESOURCE_NAME_TESTDB2));
209 
210         JdbcTemplate jdbcTemplate = new JdbcTemplate(testDataSource);
211         assertEquals(1, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='verdi'").size());
212         assertEquals(1, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='rossini'").size());
213 
214         // ------------------------------------------
215         // Matching --> Deprovision --> dryRuyn
216         // ------------------------------------------
217         execProvisioningTask(
218                 TASK_SERVICE, TaskType.PUSH, "c46edc3a-a18b-4af2-b707-f4a415507496", MAX_WAIT_SECONDS, true);
219         assertTrue(USER_SERVICE.read("1417acbe-cbf6-4277-9372-e75e04f97000").
220                 getResources().contains(RESOURCE_NAME_TESTDB2));
221         assertEquals(1, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='rossini'").size());
222         // ------------------------------------------
223 
224         Set<String> pushTaskKeys = Set.of(
225                 "ec674143-480a-4816-98ad-b61fa090821e",
226                 "c46edc3a-a18b-4af2-b707-f4a415507496",
227                 "5e5f7c7e-9de7-4c6a-99f1-4df1af959807");
228         execProvisioningTasks(TASK_SERVICE, TaskType.PUSH, pushTaskKeys, MAX_WAIT_SECONDS, false);
229 
230         // ------------------------------------------
231         // Matching --> Deprovision && Ignore
232         // ------------------------------------------
233         assertFalse(USER_SERVICE.read("74cd8ece-715a-44a4-a736-e17b46c4e7e6").
234                 getResources().contains(RESOURCE_NAME_TESTDB2));
235         // DELETE Capability not available ....
236         assertEquals(1, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='verdi'").size());
237         // ------------------------------------------
238 
239         // ------------------------------------------
240         // Matching --> Unassign
241         // ------------------------------------------
242         assertFalse(USER_SERVICE.read("1417acbe-cbf6-4277-9372-e75e04f97000").
243                 getResources().contains(RESOURCE_NAME_TESTDB2));
244         // DELETE Capability not available ....
245         assertEquals(1, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='rossini'").size());
246         // ------------------------------------------
247 
248         // ------------------------------------------
249         // Matching --> Link
250         // ------------------------------------------
251         execProvisioningTask(
252                 TASK_SERVICE, TaskType.PUSH, "51318433-cce4-4f71-8f45-9534b6c9c819", MAX_WAIT_SECONDS, false);
253         assertTrue(USER_SERVICE.read("74cd8ece-715a-44a4-a736-e17b46c4e7e6").
254                 getResources().contains(RESOURCE_NAME_TESTDB2));
255         assertEquals(1, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='verdi'").size());
256         // ------------------------------------------
257 
258         pushTaskKeys = Set.of(
259                 "24b1be9c-7e3b-443a-86c9-798ebce5eaf2",
260                 "375c7b7f-9e3a-4833-88c9-b7787b0a69f2");
261         execProvisioningTasks(TASK_SERVICE, TaskType.PUSH, pushTaskKeys, MAX_WAIT_SECONDS, false);
262 
263         // ------------------------------------------
264         // Matching --> Unlink && Update
265         // ------------------------------------------
266         assertFalse(USER_SERVICE.read("74cd8ece-715a-44a4-a736-e17b46c4e7e6").
267                 getResources().contains(RESOURCE_NAME_TESTDB2));
268         assertEquals(1, jdbcTemplate.queryForList("SELECT ID FROM test2 WHERE ID='verdi'").size());
269         // ------------------------------------------
270     }
271 
272     @Test
273     public void pushPolicy() {
274         // 1. set push policy on ldap
275         ResourceTO ldap = RESOURCE_SERVICE.read(RESOURCE_NAME_LDAP);
276         assertNull(ldap.getPushPolicy());
277 
278         try {
279             ldap.setPushPolicy("fb6530e5-892d-4f47-a46b-180c5b6c5c83");
280             RESOURCE_SERVICE.update(ldap);
281 
282             // 2. create push task with sole scope as the user 'vivaldi'
283             PushTaskTO sendVivaldi = new PushTaskTO();
284             sendVivaldi.setName("Send Vivaldi");
285             sendVivaldi.setResource(RESOURCE_NAME_LDAP);
286             sendVivaldi.setUnmatchingRule(UnmatchingRule.PROVISION);
287             sendVivaldi.setMatchingRule(MatchingRule.UPDATE);
288             sendVivaldi.setSourceRealm(SyncopeConstants.ROOT_REALM);
289             sendVivaldi.getFilters().put(AnyTypeKind.GROUP.name(), "name==$null");
290             sendVivaldi.getFilters().put(AnyTypeKind.USER.name(), "username==vivaldi");
291             sendVivaldi.setPerformCreate(true);
292             sendVivaldi.setPerformUpdate(true);
293 
294             Response response = TASK_SERVICE.create(TaskType.PUSH, sendVivaldi);
295             sendVivaldi = getObject(response.getLocation(), TaskService.class, PushTaskTO.class);
296             assertNotNull(sendVivaldi);
297 
298             // 3. execute push: vivaldi is found on ldap
299             execProvisioningTask(TASK_SERVICE, TaskType.PUSH, sendVivaldi.getKey(), MAX_WAIT_SECONDS, false);
300 
301             ReconStatus status = RECONCILIATION_SERVICE.status(
302                     new ReconQuery.Builder(AnyTypeKind.USER.name(), RESOURCE_NAME_LDAP).anyKey("vivaldi").build());
303             assertNotNull(status.getOnResource());
304 
305             // 4. update vivaldi on ldap: reconciliation status does not find it anymore, as remote key was changed
306             Map<String, String> attrs = new HashMap<>();
307             attrs.put("sn", "VivaldiZ");
308             updateLdapRemoteObject(
309                     RESOURCE_LDAP_ADMIN_DN, RESOURCE_LDAP_ADMIN_PWD, "uid=vivaldi,ou=People,o=isp", attrs);
310 
311             status = RECONCILIATION_SERVICE.status(
312                     new ReconQuery.Builder(AnyTypeKind.USER.name(), RESOURCE_NAME_LDAP).anyKey("vivaldi").build());
313             assertNull(status.getOnResource());
314 
315             // 5. execute push again: propagation task for CREATE will be generated, but that will fail
316             // as task executor is not able any more to identify the entry to UPDATE
317             execProvisioningTask(TASK_SERVICE, TaskType.PUSH, sendVivaldi.getKey(), MAX_WAIT_SECONDS, false);
318 
319             status = RECONCILIATION_SERVICE.status(
320                     new ReconQuery.Builder(AnyTypeKind.USER.name(), RESOURCE_NAME_LDAP).anyKey("vivaldi").build());
321             assertNull(status.getOnResource());
322         } finally {
323             ldap.setPushPolicy(null);
324             RESOURCE_SERVICE.update(ldap);
325         }
326     }
327 
328     @Test
329     public void orgUnit() {
330         assertNull(getLdapRemoteObject(RESOURCE_LDAP_ADMIN_DN, RESOURCE_LDAP_ADMIN_PWD, "ou=odd,o=isp"));
331         assertNull(getLdapRemoteObject(RESOURCE_LDAP_ADMIN_DN, RESOURCE_LDAP_ADMIN_PWD, "ou=even,o=isp"));
332         assertNull(getLdapRemoteObject(RESOURCE_LDAP_ADMIN_DN, RESOURCE_LDAP_ADMIN_PWD, "ou=two,ou=even,o=isp"));
333 
334         // 1. create task for pulling org units
335         PushTaskTO task = new PushTaskTO();
336         task.setName("For orgUnit");
337         task.setActive(true);
338         task.setResource(RESOURCE_NAME_LDAP_ORGUNIT);
339         task.setSourceRealm(SyncopeConstants.ROOT_REALM);
340         task.setPerformCreate(true);
341         task.setPerformDelete(true);
342         task.setPerformUpdate(true);
343 
344         Response response = TASK_SERVICE.create(TaskType.PUSH, task);
345         PushTaskTO pushTask = getObject(response.getLocation(), TaskService.class, PushTaskTO.class);
346         assertNotNull(pushTask);
347 
348         ExecTO exec = execProvisioningTask(TASK_SERVICE, TaskType.PUSH, pushTask.getKey(), MAX_WAIT_SECONDS, false);
349         assertEquals(ExecStatus.SUCCESS, ExecStatus.valueOf(exec.getStatus()));
350 
351         // 2. check
352         assertNotNull(getLdapRemoteObject(RESOURCE_LDAP_ADMIN_DN, RESOURCE_LDAP_ADMIN_PWD, "ou=odd,o=isp"));
353         assertNotNull(getLdapRemoteObject(RESOURCE_LDAP_ADMIN_DN, RESOURCE_LDAP_ADMIN_PWD, "ou=even,o=isp"));
354         assertNotNull(getLdapRemoteObject(RESOURCE_LDAP_ADMIN_DN, RESOURCE_LDAP_ADMIN_PWD, "ou=two,ou=even,o=isp"));
355     }
356 
357     @Test
358     public void concurrentPush() {
359         // 1. create new concurrent pull task
360         PushTaskTO pushTask = TASK_SERVICE.read(TaskType.PUSH, "97f327b6-2eff-4d35-85e8-d581baaab855", false);
361         assertNull(pushTask.getConcurrentSettings());
362         pushTask.setKey(null);
363         pushTask.setName("Concurrent Export on resource-testdb2");
364         pushTask.setDescription("Concurrent Export on resource-testdb2");
365         pushTask.getFilters().put(AnyTypeKind.USER.name(), "username!=puccini;username!=vivaldi");
366 
367         ThreadPoolSettings tps = new ThreadPoolSettings();
368         tps.setCorePoolSize(3);
369         tps.setMaxPoolSize(3);
370         tps.setQueueCapacity(100);
371         pushTask.setConcurrentSettings(tps);
372 
373         Response response = TASK_SERVICE.create(TaskType.PUSH, pushTask);
374         String pushTaskKey = response.getHeaderString(RESTHeaders.RESOURCE_KEY);
375 
376         // 2. run concurrent pull task
377         ExecTO execution = execProvisioningTask(TASK_SERVICE, TaskType.PUSH, pushTaskKey, MAX_WAIT_SECONDS, false);
378 
379         // 3. verify execution status
380         assertEquals(ExecStatus.SUCCESS, ExecStatus.valueOf(execution.getStatus()));
381     }
382 
383     @Test
384     public void issueSYNCOPE598() {
385         // create a new group schema
386         PlainSchemaTO schemaTO = new PlainSchemaTO();
387         schemaTO.setKey("LDAPGroupName" + getUUIDString());
388         schemaTO.setType(AttrSchemaType.String);
389         schemaTO.setMandatoryCondition("true");
390 
391         schemaTO = createSchema(SchemaType.PLAIN, schemaTO);
392         assertNotNull(schemaTO);
393 
394         AnyTypeClassTO typeClass = new AnyTypeClassTO();
395         typeClass.setKey("SYNCOPE-598" + getUUIDString());
396         typeClass.getPlainSchemas().add(schemaTO.getKey());
397         ANY_TYPE_CLASS_SERVICE.create(typeClass);
398 
399         // create a new sample group
400         GroupCR groupCR = new GroupCR();
401         groupCR.setName("all" + getUUIDString());
402         groupCR.setRealm("/even");
403         groupCR.getAuxClasses().add(typeClass.getKey());
404 
405         groupCR.getPlainAttrs().add(attr(schemaTO.getKey(), "all"));
406 
407         GroupTO groupTO = createGroup(groupCR).getEntity();
408         assertNotNull(groupTO);
409 
410         String resourceName = "resource-ldap-grouponly";
411         ResourceTO newResourceTO = null;
412 
413         try {
414             // Create resource ad-hoc
415             ResourceTO resourceTO = new ResourceTO();
416             resourceTO.setKey(resourceName);
417             resourceTO.setConnector("74141a3b-0762-4720-a4aa-fc3e374ef3ef");
418 
419             Provision provisionTO = new Provision();
420             provisionTO.setAnyType(AnyTypeKind.GROUP.name());
421             provisionTO.setObjectClass(ObjectClass.GROUP_NAME);
422             provisionTO.getAuxClasses().add(typeClass.getKey());
423             resourceTO.getProvisions().add(provisionTO);
424 
425             Mapping mapping = new Mapping();
426             provisionTO.setMapping(mapping);
427 
428             Item item = new Item();
429             item.setExtAttrName("cn");
430             item.setIntAttrName(schemaTO.getKey());
431             item.setConnObjectKey(true);
432             item.setPurpose(MappingPurpose.BOTH);
433             mapping.setConnObjectKeyItem(item);
434 
435             mapping.setConnObjectLink("'cn=' + " + schemaTO.getKey() + " + ',ou=groups,o=isp'");
436 
437             Response response = RESOURCE_SERVICE.create(resourceTO);
438             newResourceTO = getObject(response.getLocation(), ResourceService.class, ResourceTO.class);
439             assertNotNull(newResourceTO);
440             assertFalse(newResourceTO.getProvision(AnyTypeKind.USER.name()).isPresent());
441             assertNotNull(newResourceTO.getProvision(AnyTypeKind.GROUP.name()).get().getMapping());
442 
443             // create push task ad-hoc
444             PushTaskTO task = new PushTaskTO();
445             task.setName("issueSYNCOPE598");
446             task.setActive(true);
447             task.setResource(resourceName);
448             task.setSourceRealm(SyncopeConstants.ROOT_REALM);
449             task.setPerformCreate(true);
450             task.setPerformDelete(true);
451             task.setPerformUpdate(true);
452             task.setUnmatchingRule(UnmatchingRule.ASSIGN);
453             task.setMatchingRule(MatchingRule.UPDATE);
454             task.getFilters().put(AnyTypeKind.GROUP.name(),
455                     SyncopeClient.getGroupSearchConditionBuilder().is("name").equalTo(groupTO.getName()).query());
456 
457             response = TASK_SERVICE.create(TaskType.PUSH, task);
458             PushTaskTO push = getObject(response.getLocation(), TaskService.class, PushTaskTO.class);
459             assertNotNull(push);
460 
461             // execute the new task
462             ExecTO exec = execProvisioningTask(TASK_SERVICE, TaskType.PUSH, push.getKey(), MAX_WAIT_SECONDS, false);
463             assertEquals(ExecStatus.SUCCESS, ExecStatus.valueOf(exec.getStatus()));
464         } finally {
465             GROUP_SERVICE.delete(groupTO.getKey());
466             if (newResourceTO != null) {
467                 RESOURCE_SERVICE.delete(resourceName);
468             }
469         }
470     }
471 
472     @Test
473     public void issueSYNCOPE648() {
474         // 1. Create Push Task
475         PushTaskTO task = new PushTaskTO();
476         task.setName("Test create Push");
477         task.setActive(true);
478         task.setResource(RESOURCE_NAME_LDAP);
479         task.setSourceRealm(SyncopeConstants.ROOT_REALM);
480         task.getFilters().put(AnyTypeKind.USER.name(),
481                 SyncopeClient.getUserSearchConditionBuilder().is("username").equalTo("_NO_ONE_").query());
482         task.getFilters().put(AnyTypeKind.GROUP.name(),
483                 SyncopeClient.getGroupSearchConditionBuilder().is("name").equalTo("citizen").query());
484         task.setMatchingRule(MatchingRule.IGNORE);
485         task.setUnmatchingRule(UnmatchingRule.IGNORE);
486 
487         Response response = TASK_SERVICE.create(TaskType.PUSH, task);
488         PushTaskTO actual = getObject(response.getLocation(), TaskService.class, PushTaskTO.class);
489         assertNotNull(actual);
490 
491         // 2. Create notification
492         NotificationTO notification = new NotificationTO();
493         notification.setTraceLevel(TraceLevel.FAILURES);
494         notification.getEvents().add("[PUSH]:[GROUP]:[resource-ldap]:[matchingrule_ignore]:[SUCCESS]");
495         notification.getEvents().add("[PUSH]:[GROUP]:[resource-ldap]:[unmatchingrule_ignore]:[SUCCESS]");
496 
497         notification.getStaticRecipients().add("issueyncope648@syncope.apache.org");
498         notification.setSelfAsRecipient(false);
499         notification.setRecipientAttrName("email");
500 
501         notification.setSender("syncope648@syncope.apache.org");
502         String subject = "Test notification";
503         notification.setSubject(subject);
504         notification.setTemplate("optin");
505         notification.setActive(true);
506 
507         Response responseNotification = NOTIFICATION_SERVICE.create(notification);
508         notification = getObject(responseNotification.getLocation(), NotificationService.class, NotificationTO.class);
509         assertNotNull(notification);
510 
511         execProvisioningTask(TASK_SERVICE, TaskType.PUSH, actual.getKey(), MAX_WAIT_SECONDS, false);
512 
513         NotificationTaskTO taskTO = findNotificationTask(notification.getKey(), 50);
514         assertNotNull(taskTO);
515     }
516 }