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.listeners;
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 DataBroker dataBroker;
153 private DOMDataBroker domDataBroker;
154 private DatabindProvider databindProvider;
157 public static void beforeClass() {
158 SCHEMA_CONTEXT = YangParserTestUtils.parseYangResourceDirectory("/instanceidentifier/yang");
162 public static void afterClass() {
163 SCHEMA_CONTEXT = null;
167 public void setUp() throws Exception {
168 dataBroker = getDataBroker();
169 domDataBroker = getDomBroker();
170 databindProvider = () -> DatabindContext.ofModel(SCHEMA_CONTEXT);
173 class ListenerAdapterTester extends ListenerAdapter {
175 private volatile String lastNotification;
176 private CountDownLatch notificationLatch = new CountDownLatch(1);
178 ListenerAdapterTester(final YangInstanceIdentifier path, final String streamName,
179 final NotificationOutputType outputType, final boolean leafNodesOnly,
180 final boolean skipNotificationData, final boolean changedLeafNodesOnly, final boolean childNodesOnly) {
181 super(path, streamName, outputType);
182 setQueryParams(NotificationQueryParams.of(StartTimeParam.forUriValue("1970-01-01T00:00:00Z"), null, null,
183 leafNodesOnly ? LeafNodesOnlyParam.of(true) : null,
184 skipNotificationData ? SkipNotificationDataParam.of(true) : null,
185 changedLeafNodesOnly ? ChangedLeafNodesOnlyParam.of(true) : null,
186 childNodesOnly ? ChildNodesOnlyParam.of(true) : null));
190 protected void post(final String data) {
191 lastNotification = data;
192 notificationLatch.countDown();
195 public void assertGot(final String json) throws JSONException {
196 // FIXME: use awaitility
197 if (!Uninterruptibles.awaitUninterruptibly(notificationLatch, 500, TimeUnit.SECONDS)) {
198 fail("Timed out waiting for notification for: " + json);
201 LOG.info("lastNotification: {}", lastNotification);
202 final String withFakeDate = withFakeDate(lastNotification);
203 LOG.info("Comparing: \n{}\n{}", json, withFakeDate);
205 JSONAssert.assertEquals(json, withFakeDate, false);
206 lastNotification = null;
207 notificationLatch = new CountDownLatch(1);
210 public void assertXmlSimilar(final String xml) {
211 awaitUntilNotification(xml);
213 LOG.info("lastNotification: {}", lastNotification);
214 final String withFakeDate = withFakeXmlDate(lastNotification);
215 LOG.info("Comparing: \n{}\n{}", xml, withFakeDate);
217 XmlAssert.assertThat(xml).and(withFakeDate).ignoreWhitespace().ignoreChildNodesOrder().areSimilar();
218 lastNotification = null;
219 notificationLatch = new CountDownLatch(1);
222 public String awaitUntilNotification(final String xml) {
223 // FIXME: use awaitility
224 if (!Uninterruptibles.awaitUninterruptibly(notificationLatch, 500, TimeUnit.SECONDS)) {
225 fail("Timed out waiting for notification for: " + xml);
227 return lastNotification;
230 public void resetLatch() {
231 notificationLatch = new CountDownLatch(1);
236 public void testJsonNotifsLeaves() throws Exception {
237 ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.JSON,
238 true, false, false, false);
239 adapter.setCloseVars(domDataBroker, databindProvider);
241 final DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
242 .getInstance(DOMDataTreeChangeService.class);
243 final DOMDataTreeIdentifier root =
244 new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
245 changeService.registerDataTreeChangeListener(root, adapter);
247 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
248 final InstanceIdentifier<PatchCont> 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);
280 adapter.setCloseVars(domDataBroker, databindProvider);
282 final DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
283 .getInstance(DOMDataTreeChangeService.class);
284 final DOMDataTreeIdentifier root =
285 new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
286 changeService.registerDataTreeChangeListener(root, adapter);
288 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
289 final InstanceIdentifier<PatchCont> iid = InstanceIdentifier.create(PatchCont.class);
290 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
291 .addAugmentation(new PatchCont1Builder()
292 .setPatchChoice2(new PatchCase11Builder()
293 .setPatchSubChoice11(new PatchSubCase11Builder()
294 .setPatchSubSubChoice11(new PatchSubSubCase11Builder().setCaseLeaf11("ChoiceLeaf").build())
297 .setLeaf1("AugmentLeaf")
299 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build()))
301 writeTransaction.commit();
302 adapter.assertGot(getNotifJson(JSON_NOTIF_CHANGED_LEAVES_CREATE));
304 writeTransaction = dataBroker.newWriteOnlyTransaction();
305 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
306 .addAugmentation(new PatchCont1Builder()
307 .setPatchChoice2(new PatchCase11Builder()
308 .setPatchSubChoice11(new PatchSubCase11Builder()
309 .setPatchSubSubChoice11(new PatchSubSubCase11Builder().setCaseLeaf11("ChoiceUpdate").build())
312 .setLeaf1("AugmentLeaf")
314 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf12("Bertha").setName("Althea").build()))
316 writeTransaction.commit();
317 adapter.assertGot(getNotifJson(JSON_NOTIF_CHANGED_LEAVES_UPDATE));
319 writeTransaction = dataBroker.newWriteOnlyTransaction();
320 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
321 writeTransaction.commit();
322 adapter.assertGot(getNotifJson(JSON_NOTIF_CHANGED_LEAVES_DELETE));
326 public void testJsonChildNodesOnly() throws Exception {
327 final var adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
328 NotificationOutputType.JSON, false, false, false, true);
329 adapter.setCloseVars(domDataBroker, databindProvider);
331 final var changeService = domDataBroker.getExtensions()
332 .getInstance(DOMDataTreeChangeService.class);
333 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
334 changeService.registerDataTreeChangeListener(root, adapter);
336 final var iid = InstanceIdentifier.create(PatchCont.class).child(MyList1.class, new MyList1Key("Althea"));
337 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
338 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid,
339 new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build());
340 writeTransaction.commit();
341 adapter.assertGot(getNotifJson(JSON_NOTIF_CHILD_NODES_ONLY_CREATE));
343 writeTransaction = dataBroker.newWriteOnlyTransaction();
344 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid,
345 new MyList1Builder().setMyLeaf11("Bertha").setName("Althea").build());
346 writeTransaction.commit();
347 adapter.assertGot(getNotifJson(JSON_NOTIF_CHILD_NODES_ONLY_UPDATE1));
349 writeTransaction = dataBroker.newWriteOnlyTransaction();
350 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid,
351 new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build());
352 writeTransaction.commit();
353 adapter.assertGot(getNotifJson(JSON_NOTIF_CHILD_NODES_ONLY_UPDATE2));
355 writeTransaction = dataBroker.newWriteOnlyTransaction();
356 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
357 writeTransaction.commit();
358 adapter.assertGot(getNotifJson(JSON_NOTIF_CHILD_NODES_ONLY_DELETE));
362 public void testXmlLeavesOnly() throws Exception {
363 ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.XML,
364 true, false, false, false);
365 adapter.setCloseVars(domDataBroker, databindProvider);
367 DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
368 .getInstance(DOMDataTreeChangeService.class);
369 DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
370 changeService.registerDataTreeChangeListener(root, adapter);
371 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
372 final InstanceIdentifier<PatchCont> iid = InstanceIdentifier.create(PatchCont.class);
373 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
374 .addAugmentation(new PatchCont1Builder()
375 .setPatchChoice1(new PatchCase1Builder().setCaseLeaf1("ChoiceLeaf").build())
376 .setLeaf1("AugmentLeaf")
378 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build()))
380 writeTransaction.commit();
381 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_LEAVES_CREATE));
383 writeTransaction = dataBroker.newWriteOnlyTransaction();
384 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
385 .addAugmentation(new PatchCont1Builder()
386 .setPatchChoice1(new PatchCase1Builder().setCaseLeaf1("ChoiceUpdate").build())
387 .setLeaf1("AugmentLeaf")
389 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf12("Bertha").setName("Althea").build()))
391 writeTransaction.commit();
392 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_LEAVES_UPDATE));
394 writeTransaction = dataBroker.newWriteOnlyTransaction();
395 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
396 writeTransaction.commit();
398 // xmlunit cannot compare deeper children it seems out of the box so just check the iid encoding
399 final String notification = adapter.awaitUntilNotification("");
400 assertThat(notification, allOf(
401 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
402 + "/a:my-list1[a:name='Althea']/a:my-leaf11</path>"),
403 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
404 + "/a:my-list1[a:name='Althea']/a:my-leaf12</path>"),
405 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
406 + "/a:my-list1[a:name='Althea']/a:name</path>"),
407 containsString("<path xmlns:a=\"instance:identifier:patch:module\" "
408 + "xmlns:b=\"augment:instance:identifier:patch:module\">/a:patch-cont/b:leaf1</path>"),
409 containsString("<path xmlns:a=\"instance:identifier:patch:module\" "
410 + "xmlns:b=\"augment:instance:identifier:patch:module\">/a:patch-cont/b:case-leaf1</path>")));
414 public void testXmlChangedLeavesOnly() throws Exception {
415 ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.XML,
416 false, false, true, false);
417 adapter.setCloseVars(domDataBroker, databindProvider);
419 DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
420 .getInstance(DOMDataTreeChangeService.class);
421 DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
422 changeService.registerDataTreeChangeListener(root, adapter);
423 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
424 final InstanceIdentifier<PatchCont> iid = InstanceIdentifier.create(PatchCont.class);
425 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
426 .addAugmentation(new PatchCont1Builder()
427 .setPatchChoice2(new PatchCase11Builder()
428 .setPatchSubChoice11(new PatchSubCase11Builder()
429 .setPatchSubSubChoice11(new PatchSubSubCase11Builder().setCaseLeaf11("ChoiceLeaf").build())
432 .setLeaf1("AugmentLeaf")
434 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build()))
436 writeTransaction.commit();
437 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHANGED_LEAVES_CREATE));
439 writeTransaction = dataBroker.newWriteOnlyTransaction();
440 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
441 .addAugmentation(new PatchCont1Builder()
442 .setPatchChoice2(new PatchCase11Builder()
443 .setPatchSubChoice11(new PatchSubCase11Builder()
444 .setPatchSubSubChoice11(new PatchSubSubCase11Builder().setCaseLeaf11("ChoiceUpdate").build())
447 .setLeaf1("AugmentLeaf")
449 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf12("Bertha").setName("Althea").build()))
451 writeTransaction.commit();
452 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHANGED_LEAVES_UPDATE));
454 writeTransaction = dataBroker.newWriteOnlyTransaction();
455 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
456 writeTransaction.commit();
458 // xmlunit cannot compare deeper children it seems out of the box so just check the iid encoding
459 final String notification = adapter.awaitUntilNotification("");
460 assertThat(notification, allOf(
461 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
462 + "/a:my-list1[a:name='Althea']/a:my-leaf11</path>"),
463 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
464 + "/a:my-list1[a:name='Althea']/a:my-leaf12</path>"),
465 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
466 + "/a:my-list1[a:name='Althea']/a:name</path>"),
467 containsString("<path xmlns:a=\"instance:identifier:patch:module\" "
468 + "xmlns:b=\"augment:instance:identifier:patch:module\">/a:patch-cont/b:leaf1</path>"),
469 containsString("<path xmlns:a=\"instance:identifier:patch:module\" "
470 + "xmlns:b=\"augment:instance:identifier:patch:module\">/a:patch-cont/b:case-leaf11</path>")));
474 public void testXmlChildNodesOnly() throws Exception {
475 final var adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
476 NotificationOutputType.XML, false, false, false, true);
477 adapter.setCloseVars(domDataBroker, databindProvider);
479 final var changeService = domDataBroker.getExtensions()
480 .getInstance(DOMDataTreeChangeService.class);
481 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
482 changeService.registerDataTreeChangeListener(root, adapter);
484 final var iid = InstanceIdentifier.create(PatchCont.class).child(MyList1.class, new MyList1Key("Althea"));
485 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
486 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid,
487 new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build());
488 writeTransaction.commit();
489 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHILD_NODES_ONLY_CREATE));
491 writeTransaction = dataBroker.newWriteOnlyTransaction();
492 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid,
493 new MyList1Builder().setMyLeaf11("Bertha").setName("Althea").build());
494 writeTransaction.commit();
495 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHILD_NODES_ONLY_UPDATE1));
497 writeTransaction = dataBroker.newWriteOnlyTransaction();
498 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid,
499 new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build());
500 writeTransaction.commit();
501 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHILD_NODES_ONLY_UPDATE2));
503 writeTransaction = dataBroker.newWriteOnlyTransaction();
504 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
505 writeTransaction.commit();
506 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHILD_NODES_ONLY_DELETE));
510 public void testJsonContNotifications() throws Exception {
511 jsonNotifications(PATCH_CONT_YIID, false, JSON_NOTIF_CONT_CREATE,
512 JSON_NOTIF_CONT_UPDATE, JSON_NOTIF_CONT_DELETE);
516 public void testJsonListNotifications() throws Exception {
517 jsonNotifications(MY_LIST1_YIID, false, JSON_NOTIF_LIST_CREATE,
518 JSON_NOTIF_LIST_UPDATE, JSON_NOTIF_LIST_DELETE);
522 public void testJsonContNotificationsWithoutData() throws Exception {
523 jsonNotifications(PATCH_CONT_YIID, true, JSON_NOTIF_WITHOUT_DATA_CONT_CREATE,
524 JSON_NOTIF_WITHOUT_DATA_CONT_UPDATE, JSON_NOTIF_WITHOUT_DATA_CONT_DELETE);
528 public void testJsonListNotificationsWithoutData() throws Exception {
529 jsonNotifications(MY_LIST1_YIID, true, JSON_NOTIF_WITHOUT_DATA_LIST_CREATE,
530 JSON_NOTIF_WITHOUT_DATA_LIST_UPDATE, JSON_NOTIF_WITHOUT_DATA_LIST_DELETE);
534 public void testXmlContNotifications() throws Exception {
535 xmlNotifications(PATCH_CONT_YIID, false, XML_NOTIF_CONT_CREATE,
536 XML_NOTIF_CONT_UPDATE, XML_NOTIF_CONT_DELETE);
540 public void testXmlListNotifications() throws Exception {
541 xmlNotifications(MY_LIST1_YIID, false, XML_NOTIF_LIST_CREATE,
542 XML_NOTIF_LIST_UPDATE, XML_NOTIF_LIST_DELETE);
546 public void testXmlContNotificationsWithoutData() throws Exception {
547 xmlNotifications(PATCH_CONT_YIID, true, XML_NOTIF_WITHOUT_DATA_CONT_CREATE,
548 XML_NOTIF_WITHOUT_DATA_CONT_UPDATE, XML_NOTIF_WITHOUT_DATA_CONT_DELETE);
552 public void testXmlListNotificationsWithoutData() throws Exception {
553 xmlNotifications(MY_LIST1_YIID, true, XML_NOTIF_WITHOUT_DATA_LIST_CREATE,
554 XML_NOTIF_WITHOUT_DATA_LIST_UPDATE, XML_NOTIF_WITHOUT_DATA_LIST_DELETE);
557 static String withFakeDate(final String in) throws JSONException {
558 final JSONObject doc = new JSONObject(in);
559 final JSONObject notification = doc.getJSONObject("ietf-restconf:notification");
560 if (notification == null) {
563 notification.put("event-time", "someDate");
564 return doc.toString();
567 static String withFakeXmlDate(final String in) {
568 return in.replaceAll("<eventTime>.*</eventTime>", "<eventTime>someDate</eventTime>");
571 private String getNotifJson(final String path) throws IOException, URISyntaxException, JSONException {
572 return withFakeDate(Files.readString(Paths.get(getClass().getResource(path).toURI())));
575 private String getResultXml(final String path) throws IOException, URISyntaxException, JSONException {
576 return withFakeXmlDate(Files.readString(Paths.get(getClass().getResource(path).toURI())));
579 private void jsonNotifications(final YangInstanceIdentifier pathYiid, final boolean skipData,
580 final String jsonNotifCreate, final String jsonNotifUpdate, final String jsonNotifDelete) throws Exception {
581 final var adapter = new ListenerAdapterTester(pathYiid, "Casey",
582 NotificationOutputType.JSON, false, skipData, false, false);
583 adapter.setCloseVars(domDataBroker, databindProvider);
585 final var changeService = domDataBroker.getExtensions()
586 .getInstance(DOMDataTreeChangeService.class);
587 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, pathYiid);
588 changeService.registerDataTreeChangeListener(root, adapter);
590 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
591 MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
592 final var iid = InstanceIdentifier.create(PatchCont.class)
593 .child(MyList1.class, new MyList1Key("Althea"));
594 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
595 writeTransaction.commit();
596 adapter.assertGot(getNotifJson(jsonNotifCreate));
598 writeTransaction = dataBroker.newWriteOnlyTransaction();
599 builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
600 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
601 writeTransaction.commit();
602 adapter.assertGot(getNotifJson(jsonNotifUpdate));
604 writeTransaction = dataBroker.newWriteOnlyTransaction();
605 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
606 writeTransaction.commit();
607 adapter.assertGot(getNotifJson(jsonNotifDelete));
610 private void xmlNotifications(final YangInstanceIdentifier pathYiid, final boolean skipData,
611 final String xmlNotifCreate, final String xmlNotifUpdate, final String xmlNotifDelete) throws Exception {
612 final var adapter = new ListenerAdapterTester(pathYiid, "Casey", NotificationOutputType.XML,
613 false, skipData, false, false);
614 adapter.setCloseVars(domDataBroker, databindProvider);
616 final var changeService = domDataBroker.getExtensions()
617 .getInstance(DOMDataTreeChangeService.class);
618 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, pathYiid);
619 changeService.registerDataTreeChangeListener(root, adapter);
621 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
622 MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
623 final var iid = InstanceIdentifier.create(PatchCont.class)
624 .child(MyList1.class, new MyList1Key("Althea"));
625 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
626 writeTransaction.commit();
627 adapter.assertXmlSimilar(getResultXml(xmlNotifCreate));
629 writeTransaction = dataBroker.newWriteOnlyTransaction();
630 builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
631 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
632 writeTransaction.commit();
633 adapter.assertXmlSimilar(getResultXml(xmlNotifUpdate));
635 writeTransaction = dataBroker.newWriteOnlyTransaction();
636 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
637 writeTransaction.commit();
638 adapter.assertXmlSimilar(getResultXml(xmlNotifDelete));