2 * Copyright (c) 2017 Red Hat, Inc. and others. All rights reserved.
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
8 package org.opendaylight.restconf.nb.rfc8040.streams;
10 import static org.hamcrest.CoreMatchers.allOf;
11 import static org.hamcrest.CoreMatchers.containsString;
12 import static org.hamcrest.MatcherAssert.assertThat;
13 import static org.junit.Assert.fail;
15 import com.google.common.util.concurrent.Uninterruptibles;
16 import java.io.IOException;
17 import java.net.URISyntaxException;
18 import java.nio.file.Files;
19 import java.nio.file.Paths;
20 import java.util.concurrent.CountDownLatch;
21 import java.util.concurrent.TimeUnit;
22 import org.json.JSONException;
23 import org.json.JSONObject;
24 import org.junit.AfterClass;
25 import org.junit.Before;
26 import org.junit.BeforeClass;
27 import org.junit.Test;
28 import org.opendaylight.mdsal.binding.api.DataBroker;
29 import org.opendaylight.mdsal.binding.api.WriteTransaction;
30 import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractConcurrentDataBrokerTest;
31 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
32 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
33 import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService;
34 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
35 import org.opendaylight.restconf.api.query.ChangedLeafNodesOnlyParam;
36 import org.opendaylight.restconf.api.query.ChildNodesOnlyParam;
37 import org.opendaylight.restconf.api.query.LeafNodesOnlyParam;
38 import org.opendaylight.restconf.api.query.SkipNotificationDataParam;
39 import org.opendaylight.restconf.api.query.StartTimeParam;
40 import org.opendaylight.restconf.nb.rfc8040.NotificationQueryParams;
41 import org.opendaylight.restconf.nb.rfc8040.databind.DatabindContext;
42 import org.opendaylight.restconf.nb.rfc8040.databind.DatabindProvider;
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.augment.instance.identifier.patch.module.rev220218.patch.cont.patch.choice2.PatchCase11Builder;
46 import org.opendaylight.yang.gen.v1.augment.instance.identifier.patch.module.rev220218.patch.cont.patch.choice2.patch.case11.patch.sub.choice11.PatchSubCase11Builder;
47 import org.opendaylight.yang.gen.v1.augment.instance.identifier.patch.module.rev220218.patch.cont.patch.choice2.patch.case11.patch.sub.choice11.patch.sub.case11.patch.sub.sub.choice11.PatchSubSubCase11Builder;
48 import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.PatchCont;
49 import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.PatchContBuilder;
50 import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.patch.cont.MyList1;
51 import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.patch.cont.MyList1Builder;
52 import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.patch.cont.MyList1Key;
53 import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55 import org.opendaylight.yangtools.yang.binding.util.BindingMap;
56 import org.opendaylight.yangtools.yang.common.QName;
57 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
58 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
59 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
60 import org.skyscreamer.jsonassert.JSONAssert;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63 import org.xmlunit.assertj.XmlAssert;
65 public class ListenerAdapterTest extends AbstractConcurrentDataBrokerTest {
66 private static final Logger LOG = LoggerFactory.getLogger(ListenerAdapterTest.class);
68 private static final String JSON_NOTIF_LEAVES_CREATE = "/listener-adapter-test/notif-leaves-create.json";
69 private static final String JSON_NOTIF_LEAVES_UPDATE = "/listener-adapter-test/notif-leaves-update.json";
70 private static final String JSON_NOTIF_LEAVES_DELETE = "/listener-adapter-test/notif-leaves-delete.json";
71 private static final String JSON_NOTIF_CHANGED_LEAVES_CREATE =
72 "/listener-adapter-test/notif-changed-leaves-create.json";
73 private static final String JSON_NOTIF_CHANGED_LEAVES_UPDATE =
74 "/listener-adapter-test/notif-changed-leaves-update.json";
75 private static final String JSON_NOTIF_CHANGED_LEAVES_DELETE =
76 "/listener-adapter-test/notif-changed-leaves-delete.json";
77 private static final String JSON_NOTIF_CHILD_NODES_ONLY_CREATE =
78 "/listener-adapter-test/notif-child-nodes-only-create.json";
79 private static final String JSON_NOTIF_CHILD_NODES_ONLY_UPDATE1 =
80 "/listener-adapter-test/notif-child-nodes-only-update1.json";
81 private static final String JSON_NOTIF_CHILD_NODES_ONLY_UPDATE2 =
82 "/listener-adapter-test/notif-child-nodes-only-update2.json";
83 private static final String JSON_NOTIF_CHILD_NODES_ONLY_DELETE =
84 "/listener-adapter-test/notif-child-nodes-only-delete.json";
86 private static final String XML_NOTIF_LEAVES_CREATE = "/listener-adapter-test/notif-leaves-create.xml";
87 private static final String XML_NOTIF_LEAVES_UPDATE = "/listener-adapter-test/notif-leaves-update.xml";
88 private static final String XML_NOTIF_LEAVES_DELETE = "/listener-adapter-test/notif-leaves-delete.xml";
89 private static final String XML_NOTIF_CHANGED_LEAVES_CREATE =
90 "/listener-adapter-test/notif-changed-leaves-create.xml";
91 private static final String XML_NOTIF_CHANGED_LEAVES_UPDATE =
92 "/listener-adapter-test/notif-changed-leaves-update.xml";
93 private static final String XML_NOTIF_CHANGED_LEAVES_DELETE =
94 "/listener-adapter-test/notif-changed-leaves-delete.xml";
95 private static final String XML_NOTIF_CHILD_NODES_ONLY_CREATE =
96 "/listener-adapter-test/notif-child-nodes-only-create.xml";
97 private static final String XML_NOTIF_CHILD_NODES_ONLY_UPDATE1 =
98 "/listener-adapter-test/notif-child-nodes-only-update1.xml";
99 private static final String XML_NOTIF_CHILD_NODES_ONLY_UPDATE2 =
100 "/listener-adapter-test/notif-child-nodes-only-update2.xml";
101 private static final String XML_NOTIF_CHILD_NODES_ONLY_DELETE =
102 "/listener-adapter-test/notif-child-nodes-only-delete.xml";
104 private static final String JSON_NOTIF_CONT_CREATE = "/listener-adapter-test/notif-cont-create.json";
105 private static final String JSON_NOTIF_CONT_UPDATE = "/listener-adapter-test/notif-cont-update.json";
106 private static final String JSON_NOTIF_CONT_DELETE = "/listener-adapter-test/notif-cont-delete.json";
107 private static final String JSON_NOTIF_LIST_CREATE = "/listener-adapter-test/notif-list-create.json";
108 private static final String JSON_NOTIF_LIST_UPDATE = "/listener-adapter-test/notif-list-update.json";
109 private static final String JSON_NOTIF_LIST_DELETE = "/listener-adapter-test/notif-list-delete.json";
110 private static final String JSON_NOTIF_WITHOUT_DATA_CONT_CREATE =
111 "/listener-adapter-test/notif-without-data-cont-create.json";
112 private static final String JSON_NOTIF_WITHOUT_DATA_CONT_UPDATE =
113 "/listener-adapter-test/notif-without-data-cont-update.json";
114 private static final String JSON_NOTIF_WITHOUT_DATA_CONT_DELETE =
115 "/listener-adapter-test/notif-without-data-cont-delete.json";
116 private static final String JSON_NOTIF_WITHOUT_DATA_LIST_CREATE =
117 "/listener-adapter-test/notif-without-data-list-create.json";
118 private static final String JSON_NOTIF_WITHOUT_DATA_LIST_UPDATE =
119 "/listener-adapter-test/notif-without-data-list-update.json";
120 private static final String JSON_NOTIF_WITHOUT_DATA_LIST_DELETE =
121 "/listener-adapter-test/notif-without-data-list-delete.json";
123 private static final String XML_NOTIF_CONT_CREATE = "/listener-adapter-test/notif-cont-create.xml";
124 private static final String XML_NOTIF_CONT_UPDATE = "/listener-adapter-test/notif-cont-update.xml";
125 private static final String XML_NOTIF_CONT_DELETE = "/listener-adapter-test/notif-cont-delete.xml";
126 private static final String XML_NOTIF_LIST_CREATE = "/listener-adapter-test/notif-list-create.xml";
127 private static final String XML_NOTIF_LIST_UPDATE = "/listener-adapter-test/notif-list-update.xml";
128 private static final String XML_NOTIF_LIST_DELETE = "/listener-adapter-test/notif-list-delete.xml";
129 private static final String XML_NOTIF_WITHOUT_DATA_CONT_CREATE =
130 "/listener-adapter-test/notif-without-data-cont-create.xml";
131 private static final String XML_NOTIF_WITHOUT_DATA_CONT_UPDATE =
132 "/listener-adapter-test/notif-without-data-cont-update.xml";
133 private static final String XML_NOTIF_WITHOUT_DATA_CONT_DELETE =
134 "/listener-adapter-test/notif-without-data-cont-delete.xml";
135 private static final String XML_NOTIF_WITHOUT_DATA_LIST_CREATE =
136 "/listener-adapter-test/notif-without-data-list-create.xml";
137 private static final String XML_NOTIF_WITHOUT_DATA_LIST_UPDATE =
138 "/listener-adapter-test/notif-without-data-list-update.xml";
139 private static final String XML_NOTIF_WITHOUT_DATA_LIST_DELETE =
140 "/listener-adapter-test/notif-without-data-list-delete.xml";
142 private static final YangInstanceIdentifier PATCH_CONT_YIID = YangInstanceIdentifier.of(PatchCont.QNAME);
144 private static final YangInstanceIdentifier MY_LIST1_YIID = YangInstanceIdentifier.builder()
145 .node(PatchCont.QNAME)
147 .nodeWithKey(MyList1.QNAME, QName.create(PatchCont.QNAME.getModule(), "name"), "Althea")
150 private static EffectiveModelContext SCHEMA_CONTEXT;
152 private final ListenersBroker listenersBroker = new ListenersBroker.ServerSentEvents();
153 private DataBroker dataBroker;
154 private DOMDataBroker domDataBroker;
155 private DatabindProvider databindProvider;
158 public static void beforeClass() {
159 SCHEMA_CONTEXT = YangParserTestUtils.parseYangResourceDirectory("/instanceidentifier/yang");
163 public static void afterClass() {
164 SCHEMA_CONTEXT = null;
168 public void setUp() throws Exception {
169 dataBroker = getDataBroker();
170 domDataBroker = getDomBroker();
171 databindProvider = () -> DatabindContext.ofModel(SCHEMA_CONTEXT);
174 class ListenerAdapterTester extends ListenerAdapter {
176 private volatile String lastNotification;
177 private CountDownLatch notificationLatch = new CountDownLatch(1);
179 ListenerAdapterTester(final YangInstanceIdentifier path, final String streamName,
180 final NotificationOutputType outputType, final boolean leafNodesOnly,
181 final boolean skipNotificationData, final boolean changedLeafNodesOnly, final boolean childNodesOnly,
182 final ListenersBroker listenersBroker) {
183 super(streamName, outputType, listenersBroker, LogicalDatastoreType.CONFIGURATION, path);
184 setQueryParams(NotificationQueryParams.of(StartTimeParam.forUriValue("1970-01-01T00:00:00Z"), null, null,
185 leafNodesOnly ? LeafNodesOnlyParam.of(true) : null,
186 skipNotificationData ? SkipNotificationDataParam.of(true) : null,
187 changedLeafNodesOnly ? ChangedLeafNodesOnlyParam.of(true) : null,
188 childNodesOnly ? ChildNodesOnlyParam.of(true) : null));
192 protected void post(final String data) {
193 lastNotification = data;
194 notificationLatch.countDown();
197 public void assertGot(final String json) throws JSONException {
198 // FIXME: use awaitility
199 if (!Uninterruptibles.awaitUninterruptibly(notificationLatch, 500, TimeUnit.SECONDS)) {
200 fail("Timed out waiting for notification for: " + json);
203 LOG.info("lastNotification: {}", lastNotification);
204 final String withFakeDate = withFakeDate(lastNotification);
205 LOG.info("Comparing: \n{}\n{}", json, withFakeDate);
207 JSONAssert.assertEquals(json, withFakeDate, false);
208 lastNotification = null;
209 notificationLatch = new CountDownLatch(1);
212 public void assertXmlSimilar(final String xml) {
213 awaitUntilNotification(xml);
215 LOG.info("lastNotification: {}", lastNotification);
216 final String withFakeDate = withFakeXmlDate(lastNotification);
217 LOG.info("Comparing: \n{}\n{}", xml, withFakeDate);
219 XmlAssert.assertThat(xml).and(withFakeDate).ignoreWhitespace().ignoreChildNodesOrder().areSimilar();
220 lastNotification = null;
221 notificationLatch = new CountDownLatch(1);
224 public String awaitUntilNotification(final String xml) {
225 // FIXME: use awaitility
226 if (!Uninterruptibles.awaitUninterruptibly(notificationLatch, 500, TimeUnit.SECONDS)) {
227 fail("Timed out waiting for notification for: " + xml);
229 return lastNotification;
232 public void resetLatch() {
233 notificationLatch = new CountDownLatch(1);
238 public void testJsonNotifsLeaves() throws Exception {
239 ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.JSON,
240 true, false, false, false, listenersBroker);
241 adapter.setCloseVars(domDataBroker, databindProvider);
243 final var changeService = domDataBroker.getExtensions().getInstance(DOMDataTreeChangeService.class);
244 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
245 changeService.registerDataTreeChangeListener(root, adapter);
247 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
248 final var iid = InstanceIdentifier.create(PatchCont.class);
249 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
250 .addAugmentation(new PatchCont1Builder()
251 .setPatchChoice1(new PatchCase1Builder().setCaseLeaf1("ChoiceLeaf").build())
252 .setLeaf1("AugmentLeaf")
254 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build()))
256 writeTransaction.commit();
257 adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_CREATE));
259 writeTransaction = dataBroker.newWriteOnlyTransaction();
260 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
261 .addAugmentation(new PatchCont1Builder()
262 .setPatchChoice1(new PatchCase1Builder().setCaseLeaf1("ChoiceUpdate").build())
263 .setLeaf1("AugmentLeaf")
265 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf12("Bertha").setName("Althea").build()))
267 writeTransaction.commit();
268 adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_UPDATE));
270 writeTransaction = dataBroker.newWriteOnlyTransaction();
271 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
272 writeTransaction.commit();
273 adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_DELETE));
277 public void testJsonNotifsChangedLeaves() throws Exception {
278 ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.JSON,
279 false, false, true, false, listenersBroker);
280 adapter.setCloseVars(domDataBroker, databindProvider);
282 final var changeService = domDataBroker.getExtensions().getInstance(DOMDataTreeChangeService.class);
283 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
284 changeService.registerDataTreeChangeListener(root, adapter);
286 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
287 final var iid = InstanceIdentifier.create(PatchCont.class);
288 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
289 .addAugmentation(new PatchCont1Builder()
290 .setPatchChoice2(new PatchCase11Builder()
291 .setPatchSubChoice11(new PatchSubCase11Builder()
292 .setPatchSubSubChoice11(new PatchSubSubCase11Builder().setCaseLeaf11("ChoiceLeaf").build())
295 .setLeaf1("AugmentLeaf")
297 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build()))
299 writeTransaction.commit();
300 adapter.assertGot(getNotifJson(JSON_NOTIF_CHANGED_LEAVES_CREATE));
302 writeTransaction = dataBroker.newWriteOnlyTransaction();
303 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
304 .addAugmentation(new PatchCont1Builder()
305 .setPatchChoice2(new PatchCase11Builder()
306 .setPatchSubChoice11(new PatchSubCase11Builder()
307 .setPatchSubSubChoice11(new PatchSubSubCase11Builder().setCaseLeaf11("ChoiceUpdate").build())
310 .setLeaf1("AugmentLeaf")
312 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf12("Bertha").setName("Althea").build()))
314 writeTransaction.commit();
315 adapter.assertGot(getNotifJson(JSON_NOTIF_CHANGED_LEAVES_UPDATE));
317 writeTransaction = dataBroker.newWriteOnlyTransaction();
318 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
319 writeTransaction.commit();
320 adapter.assertGot(getNotifJson(JSON_NOTIF_CHANGED_LEAVES_DELETE));
324 public void testJsonChildNodesOnly() throws Exception {
325 final var adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
326 NotificationOutputType.JSON, false, false, false, true, listenersBroker);
327 adapter.setCloseVars(domDataBroker, databindProvider);
329 final var changeService = domDataBroker.getExtensions().getInstance(DOMDataTreeChangeService.class);
330 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
331 changeService.registerDataTreeChangeListener(root, adapter);
333 final var iid = InstanceIdentifier.create(PatchCont.class).child(MyList1.class, new MyList1Key("Althea"));
334 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
335 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid,
336 new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build());
337 writeTransaction.commit();
338 adapter.assertGot(getNotifJson(JSON_NOTIF_CHILD_NODES_ONLY_CREATE));
340 writeTransaction = dataBroker.newWriteOnlyTransaction();
341 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid,
342 new MyList1Builder().setMyLeaf11("Bertha").setName("Althea").build());
343 writeTransaction.commit();
344 adapter.assertGot(getNotifJson(JSON_NOTIF_CHILD_NODES_ONLY_UPDATE1));
346 writeTransaction = dataBroker.newWriteOnlyTransaction();
347 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid,
348 new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build());
349 writeTransaction.commit();
350 adapter.assertGot(getNotifJson(JSON_NOTIF_CHILD_NODES_ONLY_UPDATE2));
352 writeTransaction = dataBroker.newWriteOnlyTransaction();
353 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
354 writeTransaction.commit();
355 adapter.assertGot(getNotifJson(JSON_NOTIF_CHILD_NODES_ONLY_DELETE));
359 public void testXmlLeavesOnly() throws Exception {
360 ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.XML,
361 true, false, false, false, listenersBroker);
362 adapter.setCloseVars(domDataBroker, databindProvider);
364 final var changeService = domDataBroker.getExtensions().getInstance(DOMDataTreeChangeService.class);
365 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
366 changeService.registerDataTreeChangeListener(root, adapter);
367 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
368 final var iid = InstanceIdentifier.create(PatchCont.class);
369 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
370 .addAugmentation(new PatchCont1Builder()
371 .setPatchChoice1(new PatchCase1Builder().setCaseLeaf1("ChoiceLeaf").build())
372 .setLeaf1("AugmentLeaf")
374 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build()))
376 writeTransaction.commit();
377 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_LEAVES_CREATE));
379 writeTransaction = dataBroker.newWriteOnlyTransaction();
380 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
381 .addAugmentation(new PatchCont1Builder()
382 .setPatchChoice1(new PatchCase1Builder().setCaseLeaf1("ChoiceUpdate").build())
383 .setLeaf1("AugmentLeaf")
385 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf12("Bertha").setName("Althea").build()))
387 writeTransaction.commit();
388 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_LEAVES_UPDATE));
390 writeTransaction = dataBroker.newWriteOnlyTransaction();
391 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
392 writeTransaction.commit();
394 // xmlunit cannot compare deeper children it seems out of the box so just check the iid encoding
395 final String notification = adapter.awaitUntilNotification("");
396 assertThat(notification, allOf(
397 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
398 + "/a:my-list1[a:name='Althea']/a:my-leaf11</path>"),
399 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
400 + "/a:my-list1[a:name='Althea']/a:my-leaf12</path>"),
401 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
402 + "/a:my-list1[a:name='Althea']/a:name</path>"),
403 containsString("<path xmlns:a=\"instance:identifier:patch:module\" "
404 + "xmlns:b=\"augment:instance:identifier:patch:module\">/a:patch-cont/b:leaf1</path>"),
405 containsString("<path xmlns:a=\"instance:identifier:patch:module\" "
406 + "xmlns:b=\"augment:instance:identifier:patch:module\">/a:patch-cont/b:case-leaf1</path>")));
410 public void testXmlChangedLeavesOnly() throws Exception {
411 ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.XML,
412 false, false, true, false, listenersBroker);
413 adapter.setCloseVars(domDataBroker, databindProvider);
415 final var changeService = domDataBroker.getExtensions().getInstance(DOMDataTreeChangeService.class);
416 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
417 changeService.registerDataTreeChangeListener(root, adapter);
418 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
419 final var iid = InstanceIdentifier.create(PatchCont.class);
420 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
421 .addAugmentation(new PatchCont1Builder()
422 .setPatchChoice2(new PatchCase11Builder()
423 .setPatchSubChoice11(new PatchSubCase11Builder()
424 .setPatchSubSubChoice11(new PatchSubSubCase11Builder().setCaseLeaf11("ChoiceLeaf").build())
427 .setLeaf1("AugmentLeaf")
429 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build()))
431 writeTransaction.commit();
432 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHANGED_LEAVES_CREATE));
434 writeTransaction = dataBroker.newWriteOnlyTransaction();
435 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
436 .addAugmentation(new PatchCont1Builder()
437 .setPatchChoice2(new PatchCase11Builder()
438 .setPatchSubChoice11(new PatchSubCase11Builder()
439 .setPatchSubSubChoice11(new PatchSubSubCase11Builder().setCaseLeaf11("ChoiceUpdate").build())
442 .setLeaf1("AugmentLeaf")
444 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf12("Bertha").setName("Althea").build()))
446 writeTransaction.commit();
447 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHANGED_LEAVES_UPDATE));
449 writeTransaction = dataBroker.newWriteOnlyTransaction();
450 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
451 writeTransaction.commit();
453 // xmlunit cannot compare deeper children it seems out of the box so just check the iid encoding
454 final String notification = adapter.awaitUntilNotification("");
455 assertThat(notification, allOf(
456 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
457 + "/a:my-list1[a:name='Althea']/a:my-leaf11</path>"),
458 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
459 + "/a:my-list1[a:name='Althea']/a:my-leaf12</path>"),
460 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
461 + "/a:my-list1[a:name='Althea']/a:name</path>"),
462 containsString("<path xmlns:a=\"instance:identifier:patch:module\" "
463 + "xmlns:b=\"augment:instance:identifier:patch:module\">/a:patch-cont/b:leaf1</path>"),
464 containsString("<path xmlns:a=\"instance:identifier:patch:module\" "
465 + "xmlns:b=\"augment:instance:identifier:patch:module\">/a:patch-cont/b:case-leaf11</path>")));
469 public void testXmlChildNodesOnly() throws Exception {
470 final var adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
471 NotificationOutputType.XML, false, false, false, true, listenersBroker);
472 adapter.setCloseVars(domDataBroker, databindProvider);
474 final var changeService = domDataBroker.getExtensions().getInstance(DOMDataTreeChangeService.class);
475 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
476 changeService.registerDataTreeChangeListener(root, adapter);
478 final var iid = InstanceIdentifier.create(PatchCont.class).child(MyList1.class, new MyList1Key("Althea"));
479 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
480 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid,
481 new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build());
482 writeTransaction.commit();
483 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHILD_NODES_ONLY_CREATE));
485 writeTransaction = dataBroker.newWriteOnlyTransaction();
486 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid,
487 new MyList1Builder().setMyLeaf11("Bertha").setName("Althea").build());
488 writeTransaction.commit();
489 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHILD_NODES_ONLY_UPDATE1));
491 writeTransaction = dataBroker.newWriteOnlyTransaction();
492 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid,
493 new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build());
494 writeTransaction.commit();
495 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHILD_NODES_ONLY_UPDATE2));
497 writeTransaction = dataBroker.newWriteOnlyTransaction();
498 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
499 writeTransaction.commit();
500 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHILD_NODES_ONLY_DELETE));
504 public void testJsonContNotifications() throws Exception {
505 jsonNotifications(PATCH_CONT_YIID, false, JSON_NOTIF_CONT_CREATE,
506 JSON_NOTIF_CONT_UPDATE, JSON_NOTIF_CONT_DELETE);
510 public void testJsonListNotifications() throws Exception {
511 jsonNotifications(MY_LIST1_YIID, false, JSON_NOTIF_LIST_CREATE,
512 JSON_NOTIF_LIST_UPDATE, JSON_NOTIF_LIST_DELETE);
516 public void testJsonContNotificationsWithoutData() throws Exception {
517 jsonNotifications(PATCH_CONT_YIID, true, JSON_NOTIF_WITHOUT_DATA_CONT_CREATE,
518 JSON_NOTIF_WITHOUT_DATA_CONT_UPDATE, JSON_NOTIF_WITHOUT_DATA_CONT_DELETE);
522 public void testJsonListNotificationsWithoutData() throws Exception {
523 jsonNotifications(MY_LIST1_YIID, true, JSON_NOTIF_WITHOUT_DATA_LIST_CREATE,
524 JSON_NOTIF_WITHOUT_DATA_LIST_UPDATE, JSON_NOTIF_WITHOUT_DATA_LIST_DELETE);
528 public void testXmlContNotifications() throws Exception {
529 xmlNotifications(PATCH_CONT_YIID, false, XML_NOTIF_CONT_CREATE,
530 XML_NOTIF_CONT_UPDATE, XML_NOTIF_CONT_DELETE);
534 public void testXmlListNotifications() throws Exception {
535 xmlNotifications(MY_LIST1_YIID, false, XML_NOTIF_LIST_CREATE,
536 XML_NOTIF_LIST_UPDATE, XML_NOTIF_LIST_DELETE);
540 public void testXmlContNotificationsWithoutData() throws Exception {
541 xmlNotifications(PATCH_CONT_YIID, true, XML_NOTIF_WITHOUT_DATA_CONT_CREATE,
542 XML_NOTIF_WITHOUT_DATA_CONT_UPDATE, XML_NOTIF_WITHOUT_DATA_CONT_DELETE);
546 public void testXmlListNotificationsWithoutData() throws Exception {
547 xmlNotifications(MY_LIST1_YIID, true, XML_NOTIF_WITHOUT_DATA_LIST_CREATE,
548 XML_NOTIF_WITHOUT_DATA_LIST_UPDATE, XML_NOTIF_WITHOUT_DATA_LIST_DELETE);
551 static String withFakeDate(final String in) throws JSONException {
552 final JSONObject doc = new JSONObject(in);
553 final JSONObject notification = doc.getJSONObject("ietf-restconf:notification");
554 if (notification == null) {
557 notification.put("event-time", "someDate");
558 return doc.toString();
561 static String withFakeXmlDate(final String in) {
562 return in.replaceAll("<eventTime>.*</eventTime>", "<eventTime>someDate</eventTime>");
565 private String getNotifJson(final String path) throws IOException, URISyntaxException, JSONException {
566 return withFakeDate(Files.readString(Paths.get(getClass().getResource(path).toURI())));
569 private String getResultXml(final String path) throws IOException, URISyntaxException, JSONException {
570 return withFakeXmlDate(Files.readString(Paths.get(getClass().getResource(path).toURI())));
573 private void jsonNotifications(final YangInstanceIdentifier pathYiid, final boolean skipData,
574 final String jsonNotifCreate, final String jsonNotifUpdate, final String jsonNotifDelete) throws Exception {
575 final var adapter = new ListenerAdapterTester(pathYiid, "Casey",
576 NotificationOutputType.JSON, false, skipData, false, false, listenersBroker);
577 adapter.setCloseVars(domDataBroker, databindProvider);
579 final var changeService = domDataBroker.getExtensions().getInstance(DOMDataTreeChangeService.class);
580 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, pathYiid);
581 changeService.registerDataTreeChangeListener(root, adapter);
583 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
584 MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
585 final var iid = InstanceIdentifier.create(PatchCont.class)
586 .child(MyList1.class, new MyList1Key("Althea"));
587 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
588 writeTransaction.commit();
589 adapter.assertGot(getNotifJson(jsonNotifCreate));
591 writeTransaction = dataBroker.newWriteOnlyTransaction();
592 builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
593 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
594 writeTransaction.commit();
595 adapter.assertGot(getNotifJson(jsonNotifUpdate));
597 writeTransaction = dataBroker.newWriteOnlyTransaction();
598 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
599 writeTransaction.commit();
600 adapter.assertGot(getNotifJson(jsonNotifDelete));
603 private void xmlNotifications(final YangInstanceIdentifier pathYiid, final boolean skipData,
604 final String xmlNotifCreate, final String xmlNotifUpdate, final String xmlNotifDelete) throws Exception {
605 final var adapter = new ListenerAdapterTester(pathYiid, "Casey", NotificationOutputType.XML,
606 false, skipData, false, false, listenersBroker);
607 adapter.setCloseVars(domDataBroker, databindProvider);
609 final var changeService = domDataBroker.getExtensions().getInstance(DOMDataTreeChangeService.class);
610 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, pathYiid);
611 changeService.registerDataTreeChangeListener(root, adapter);
613 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
614 MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
615 final var iid = InstanceIdentifier.create(PatchCont.class)
616 .child(MyList1.class, new MyList1Key("Althea"));
617 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
618 writeTransaction.commit();
619 adapter.assertXmlSimilar(getResultXml(xmlNotifCreate));
621 writeTransaction = dataBroker.newWriteOnlyTransaction();
622 builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
623 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
624 writeTransaction.commit();
625 adapter.assertXmlSimilar(getResultXml(xmlNotifUpdate));
627 writeTransaction = dataBroker.newWriteOnlyTransaction();
628 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
629 writeTransaction.commit();
630 adapter.assertXmlSimilar(getResultXml(xmlNotifDelete));