48a33593addd5fecdd10fcc4ab8f795f42fcd8d2
[netconf.git] / restconf / restconf-nb / src / test / java / org / opendaylight / restconf / nb / rfc8040 / streams / listeners / ListenerAdapterTest.java
1 /*
2  * Copyright (c) 2017 Red Hat, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.restconf.nb.rfc8040.streams.listeners;
9
10 import static org.junit.Assert.assertTrue;
11 import static org.junit.Assert.fail;
12 import static org.mockito.Mockito.mock;
13
14 import com.google.common.util.concurrent.Uninterruptibles;
15 import java.io.IOException;
16 import java.net.URISyntaxException;
17 import java.net.URL;
18 import java.nio.charset.StandardCharsets;
19 import java.nio.file.Files;
20 import java.nio.file.Paths;
21 import java.util.Map;
22 import java.util.concurrent.CountDownLatch;
23 import java.util.concurrent.TimeUnit;
24 import org.json.JSONException;
25 import org.json.JSONObject;
26 import org.junit.AfterClass;
27 import org.junit.Before;
28 import org.junit.BeforeClass;
29 import org.junit.Test;
30 import org.opendaylight.mdsal.binding.api.DataBroker;
31 import org.opendaylight.mdsal.binding.api.WriteTransaction;
32 import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractConcurrentDataBrokerTest;
33 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
34 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
35 import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService;
36 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
37 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
38 import org.opendaylight.restconf.nb.rfc8040.LeafNodesOnlyParam;
39 import org.opendaylight.restconf.nb.rfc8040.NotificationQueryParams;
40 import org.opendaylight.restconf.nb.rfc8040.SkipNotificationDataParam;
41 import org.opendaylight.restconf.nb.rfc8040.StartTimeParam;
42 import org.opendaylight.restconf.nb.rfc8040.handlers.SchemaContextHandler;
43 import org.opendaylight.yang.gen.v1.augment.instance.identifier.patch.module.rev220218.PatchCont1Builder;
44 import org.opendaylight.yang.gen.v1.augment.instance.identifier.patch.module.rev220218.patch.cont.patch.choice1.PatchCase1Builder;
45 import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.PatchCont;
46 import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.PatchContBuilder;
47 import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.patch.cont.MyList1;
48 import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.patch.cont.MyList1Builder;
49 import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.patch.cont.MyList1Key;
50 import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
51 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
53 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
54 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
55 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
56 import org.skyscreamer.jsonassert.JSONAssert;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59 import org.xmlunit.assertj.XmlAssert;
60
61 public class ListenerAdapterTest extends AbstractConcurrentDataBrokerTest {
62     private static final Logger LOG = LoggerFactory.getLogger(ListenerAdapterTest.class);
63
64     private static final String JSON_NOTIF_LEAVES_CREATE = "/listener-adapter-test/notif-leaves-create.json";
65     private static final String JSON_NOTIF_LEAVES_UPDATE =  "/listener-adapter-test/notif-leaves-update.json";
66     private static final String JSON_NOTIF_LEAVES_DEL =  "/listener-adapter-test/notif-leaves-del.json";
67     private static final String JSON_NOTIF_CREATE = "/listener-adapter-test/notif-create.json";
68     private static final String JSON_NOTIF_UPDATE = "/listener-adapter-test/notif-update.json";
69     private static final String JSON_NOTIF_DEL = "/listener-adapter-test/notif-del.json";
70     private static final String JSON_NOTIF_WITHOUT_DATA_CREATE =
71             "/listener-adapter-test/notif-without-data-create.json";
72     private static final String JSON_NOTIF_WITHOUT_DATA_UPDATE =
73             "/listener-adapter-test/notif-without-data-update.json";
74     private static final String JSON_NOTIF_WITHOUT_DATA_DELETE =
75             "/listener-adapter-test/notif-without-data-del.json";
76
77     private static final String XML_NOTIF_CREATE = "/listener-adapter-test/notif-create.xml";
78     private static final String XML_NOTIF_UPDATE =  "/listener-adapter-test/notif-update.xml";
79     private static final String XML_NOTIF_DEL =  "/listener-adapter-test/notif-delete.xml";
80
81     private static final String XML_NOTIF_LEAVES_CREATE = "/listener-adapter-test/notif-leaves-create.xml";
82     private static final String XML_NOTIF_LEAVES_UPDATE =  "/listener-adapter-test/notif-leaves-update.xml";
83     private static final String XML_NOTIF_LEAVES_DEL =  "/listener-adapter-test/notif-leaves-delete.xml";
84
85     private static final String XML_NOTIF_WITHOUT_DATA_CREATE =
86             "/listener-adapter-test/notif-without-data-create.xml";
87     private static final String XML_NOTIF_WITHOUT_DATA_UPDATE =
88             "/listener-adapter-test/notif-without-data-update.xml";
89     private static final String XML_NOTIF_WITHOUT_DATA_DELETE =
90             "/listener-adapter-test/notif-without-data-delete.xml";
91
92     private static final YangInstanceIdentifier PATCH_CONT_YIID =
93             YangInstanceIdentifier.create(new NodeIdentifier(PatchCont.QNAME));
94
95     private static EffectiveModelContext SCHEMA_CONTEXT;
96
97     private DataBroker dataBroker;
98     private DOMDataBroker domDataBroker;
99     private SchemaContextHandler schemaContextHandler;
100
101     @BeforeClass
102     public static void beforeClass() {
103         SCHEMA_CONTEXT = YangParserTestUtils.parseYangResourceDirectory(
104                 "/instanceidentifier/yang");
105     }
106
107     @AfterClass
108     public static void afterClass() {
109         SCHEMA_CONTEXT = null;
110     }
111
112     @Before
113     public void setUp() throws Exception {
114         dataBroker = getDataBroker();
115         domDataBroker = getDomBroker();
116
117         schemaContextHandler = new SchemaContextHandler(domDataBroker, mock(DOMSchemaService.class));
118         schemaContextHandler.onModelContextUpdated(SCHEMA_CONTEXT);
119     }
120
121     class ListenerAdapterTester extends ListenerAdapter {
122
123         private volatile String lastNotification;
124         private CountDownLatch notificationLatch = new CountDownLatch(1);
125
126         ListenerAdapterTester(final YangInstanceIdentifier path, final String streamName,
127                               final NotificationOutputType outputType,
128                               final boolean leafNodesOnly, final boolean skipNotificationData) {
129             super(path, streamName, outputType);
130             setQueryParams(NotificationQueryParams.of(StartTimeParam.forUriValue("1970-01-01T00:00:00Z"), null, null,
131                 LeafNodesOnlyParam.of(leafNodesOnly), SkipNotificationDataParam.of(skipNotificationData)));
132         }
133
134         @Override
135         protected void post(final String data) {
136             lastNotification = data;
137             notificationLatch.countDown();
138         }
139
140         public void assertGot(final String json) throws JSONException {
141             // FIXME: use awaitility
142             if (!Uninterruptibles.awaitUninterruptibly(notificationLatch, 500, TimeUnit.SECONDS)) {
143                 fail("Timed out waiting for notification for: " + json);
144             }
145
146             LOG.info("lastNotification: {}", lastNotification);
147             final String withFakeDate = withFakeDate(lastNotification);
148             LOG.info("Comparing: \n{}\n{}", json, withFakeDate);
149
150             JSONAssert.assertEquals(json, withFakeDate, false);
151             lastNotification = null;
152             notificationLatch = new CountDownLatch(1);
153         }
154
155         public void assertXmlSimilar(final String xml) {
156             awaitUntillNotification(xml);
157
158             LOG.info("lastNotification: {}", lastNotification);
159             final String withFakeDate = withFakeXmlDate(lastNotification);
160             LOG.info("Comparing: \n{}\n{}", xml, withFakeDate);
161
162             XmlAssert.assertThat(xml).and(withFakeDate).ignoreWhitespace().ignoreChildNodesOrder().areSimilar();
163             lastNotification = null;
164             notificationLatch = new CountDownLatch(1);
165         }
166
167         public String awaitUntillNotification(final String xml) {
168             // FIXME: use awaitility
169             if (!Uninterruptibles.awaitUninterruptibly(notificationLatch, 500, TimeUnit.SECONDS)) {
170                 fail("Timed out waiting for notification for: " + xml);
171             }
172             return lastNotification;
173         }
174
175         public void resetLatch() {
176             notificationLatch = new CountDownLatch(1);
177         }
178     }
179
180     static String withFakeDate(final String in) throws JSONException {
181         final JSONObject doc = new JSONObject(in);
182         final JSONObject notification =
183                 doc.getJSONObject("urn-ietf-params-xml-ns-netconf-notification-1.0:notification");
184         if (notification == null) {
185             return in;
186         }
187         notification.put("event-time", "someDate");
188         return doc.toString();
189     }
190
191     static String withFakeXmlDate(final String in) {
192         return in.replaceAll("<eventTime>.*</eventTime>", "<eventTime>someDate</eventTime>");
193     }
194
195     private String getNotifJson(final String path) throws IOException, URISyntaxException, JSONException {
196         final URL url = getClass().getResource(path);
197         final byte[] bytes = Files.readAllBytes(Paths.get(url.toURI()));
198         return withFakeDate(new String(bytes, StandardCharsets.UTF_8));
199     }
200
201     private String getResultXml(final String path) throws IOException, URISyntaxException, JSONException {
202         final URL url = getClass().getResource(path);
203         final byte[] bytes = Files.readAllBytes(Paths.get(url.toURI()));
204         return withFakeXmlDate(new String(bytes, StandardCharsets.UTF_8));
205     }
206
207     @Test
208     public void testJsonNotifsLeaves() throws Exception {
209         ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.JSON,
210             true, false);
211         adapter.setCloseVars(domDataBroker, schemaContextHandler);
212
213         final DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
214                 .getInstance(DOMDataTreeChangeService.class);
215         final DOMDataTreeIdentifier root =
216                 new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
217         changeService.registerDataTreeChangeListener(root, adapter);
218
219         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
220         final InstanceIdentifier<PatchCont> iid = InstanceIdentifier.create(PatchCont.class);
221         PatchContBuilder builder =
222                 new PatchContBuilder()
223                         .addAugmentation(
224                                 new PatchCont1Builder()
225                             .setPatchChoice1(new PatchCase1Builder().setCaseLeaf1("ChoiceLeaf").build())
226                                         .setLeaf1("AugmentLeaf").build())
227                         .setMyList1(
228                                 Map.of(new MyList1Key("Althea"),
229                                         new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build())
230                         );
231         writeTransaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
232         writeTransaction.commit();
233         adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_CREATE));
234
235         writeTransaction = dataBroker.newWriteOnlyTransaction();
236         builder = new PatchContBuilder()
237                 .addAugmentation(
238                         new PatchCont1Builder()
239                                 .setPatchChoice1(new PatchCase1Builder().setCaseLeaf1("ChoiceUpdate").build())
240                                 .setLeaf1("AugmentLeaf").build())
241                 .setMyList1(
242                         Map.of(new MyList1Key("Althea"),
243                                 new MyList1Builder().setMyLeaf12("Bertha").setName("Althea").build())
244                 );
245         writeTransaction.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
246         writeTransaction.commit();
247         adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_UPDATE));
248
249         writeTransaction = dataBroker.newWriteOnlyTransaction();
250         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
251         writeTransaction.commit();
252         adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_DEL));
253     }
254
255     @Test
256     public void testJsonNotifs() throws Exception {
257         ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.JSON,
258             false, false);
259         adapter.setCloseVars(domDataBroker, schemaContextHandler);
260
261         final DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
262                 .getInstance(DOMDataTreeChangeService.class);
263         final DOMDataTreeIdentifier root =
264                 new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
265         changeService.registerDataTreeChangeListener(root, adapter);
266
267         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
268         MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
269         final InstanceIdentifier<MyList1> iid = InstanceIdentifier.create(PatchCont.class)
270                 .child(MyList1.class, new MyList1Key("Althea"));
271         writeTransaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
272         writeTransaction.commit();
273         adapter.assertGot(getNotifJson(JSON_NOTIF_CREATE));
274
275         writeTransaction = dataBroker.newWriteOnlyTransaction();
276         builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
277         writeTransaction.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
278         writeTransaction.commit();
279         adapter.assertGot(getNotifJson(JSON_NOTIF_UPDATE));
280
281         writeTransaction = dataBroker.newWriteOnlyTransaction();
282         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
283         writeTransaction.commit();
284         adapter.assertGot(getNotifJson(JSON_NOTIF_DEL));
285     }
286
287     @Test
288     public void testJsonNotifsWithoutData() throws Exception {
289         ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.JSON,
290             false, true);
291         adapter.setCloseVars(domDataBroker, schemaContextHandler);
292
293         DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
294                 .getInstance(DOMDataTreeChangeService.class);
295         DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
296         changeService.registerDataTreeChangeListener(root, adapter);
297         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
298         MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
299         InstanceIdentifier<MyList1> iid = InstanceIdentifier.create(PatchCont.class)
300                 .child(MyList1.class, new MyList1Key("Althea"));
301         writeTransaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
302         writeTransaction.commit();
303         adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_CREATE));
304
305         writeTransaction = dataBroker.newWriteOnlyTransaction();
306         builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
307         writeTransaction.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
308         writeTransaction.commit();
309         adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_UPDATE));
310
311         writeTransaction = dataBroker.newWriteOnlyTransaction();
312         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
313         writeTransaction.commit();
314         adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_DELETE));
315     }
316
317     @Test
318     public void testXmlNotifications() throws Exception {
319         ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.XML,
320             false, false);
321         adapter.setCloseVars(domDataBroker, schemaContextHandler);
322
323         DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
324                 .getInstance(DOMDataTreeChangeService.class);
325         DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
326         changeService.registerDataTreeChangeListener(root, adapter);
327         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
328         MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
329         InstanceIdentifier<MyList1> iid = InstanceIdentifier.create(PatchCont.class)
330                 .child(MyList1.class, new MyList1Key("Althea"));
331         writeTransaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
332         writeTransaction.commit();
333         adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CREATE));
334
335         writeTransaction = dataBroker.newWriteOnlyTransaction();
336         builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
337         writeTransaction.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
338         writeTransaction.commit();
339         adapter.assertXmlSimilar(getResultXml(XML_NOTIF_UPDATE));
340
341         writeTransaction = dataBroker.newWriteOnlyTransaction();
342         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
343         writeTransaction.commit();
344         adapter.assertXmlSimilar(getResultXml(XML_NOTIF_DEL));
345     }
346
347     @Test
348     public void testXmlSkipData() throws Exception {
349         ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.XML,
350             false, true);
351         adapter.setCloseVars(domDataBroker, schemaContextHandler);
352
353         DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
354                 .getInstance(DOMDataTreeChangeService.class);
355         DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
356         changeService.registerDataTreeChangeListener(root, adapter);
357         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
358         MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
359         InstanceIdentifier<MyList1> iid = InstanceIdentifier.create(PatchCont.class)
360                 .child(MyList1.class, new MyList1Key("Althea"));
361         writeTransaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
362         writeTransaction.commit();
363         adapter.assertXmlSimilar(getResultXml(XML_NOTIF_WITHOUT_DATA_CREATE));
364
365         writeTransaction = dataBroker.newWriteOnlyTransaction();
366         builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
367         writeTransaction.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
368         writeTransaction.commit();
369         adapter.assertXmlSimilar(getResultXml(XML_NOTIF_WITHOUT_DATA_UPDATE));
370
371         writeTransaction = dataBroker.newWriteOnlyTransaction();
372         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
373         writeTransaction.commit();
374         adapter.assertXmlSimilar(getResultXml(XML_NOTIF_WITHOUT_DATA_DELETE));
375     }
376
377     @Test
378     public void testXmlLeavesOnly() throws Exception {
379         ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.XML,
380             true, false);
381         adapter.setCloseVars(domDataBroker, schemaContextHandler);
382
383         DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
384                 .getInstance(DOMDataTreeChangeService.class);
385         DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
386         changeService.registerDataTreeChangeListener(root, adapter);
387         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
388         final InstanceIdentifier<PatchCont> iid = InstanceIdentifier.create(PatchCont.class);
389         PatchContBuilder builder = new PatchContBuilder()
390                 .addAugmentation(
391                         new PatchCont1Builder()
392                                 .setPatchChoice1(new PatchCase1Builder().setCaseLeaf1("ChoiceLeaf").build())
393                                 .setLeaf1("AugmentLeaf").build())
394                                 .setMyList1(
395                                         Map.of(new MyList1Key("Althea"),
396                                                 new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build())
397                         );
398         writeTransaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
399         writeTransaction.commit();
400         adapter.assertXmlSimilar(getResultXml(XML_NOTIF_LEAVES_CREATE));
401
402         writeTransaction = dataBroker.newWriteOnlyTransaction();
403         builder = new PatchContBuilder()
404                 .addAugmentation(
405                         new PatchCont1Builder()
406                                 .setPatchChoice1(new PatchCase1Builder().setCaseLeaf1("ChoiceUpdate").build())
407                                 .setLeaf1("AugmentLeaf").build())
408                                 .setMyList1(
409                                     Map.of(new MyList1Key("Althea"),
410                                                 new MyList1Builder().setMyLeaf12("Bertha").setName("Althea").build())
411                 );
412         writeTransaction.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
413         writeTransaction.commit();
414         adapter.assertXmlSimilar(getResultXml(XML_NOTIF_LEAVES_UPDATE));
415
416         writeTransaction = dataBroker.newWriteOnlyTransaction();
417         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
418         writeTransaction.commit();
419
420         // xmlunit cannot compare deeper children it seems out of the box so just check the iid encoding
421         final String notification = adapter.awaitUntillNotification("");
422         assertTrue(notification.contains("instance-identifier-patch-module:my-leaf12"));
423         assertTrue(notification.contains("instance-identifier-patch-module:my-leaf11"));
424         assertTrue(notification.contains("instance-identifier-patch-module:name"));
425         assertTrue(notification.contains("augment-instance-identifier-patch-module:case-leaf1"));
426         assertTrue(notification.contains("augment-instance-identifier-patch-module:leaf1"));
427     }
428 }