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 final ListenersBroker listenersBroker = new ListenersBroker();
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(path, streamName, outputType, listenersBroker);
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 DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
244 .getInstance(DOMDataTreeChangeService.class);
245 final DOMDataTreeIdentifier root =
246 new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
247 changeService.registerDataTreeChangeListener(root, adapter);
249 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
250 final InstanceIdentifier<PatchCont> iid = InstanceIdentifier.create(PatchCont.class);
251 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
252 .addAugmentation(new PatchCont1Builder()
253 .setPatchChoice1(new PatchCase1Builder().setCaseLeaf1("ChoiceLeaf").build())
254 .setLeaf1("AugmentLeaf")
256 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build()))
258 writeTransaction.commit();
259 adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_CREATE));
261 writeTransaction = dataBroker.newWriteOnlyTransaction();
262 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
263 .addAugmentation(new PatchCont1Builder()
264 .setPatchChoice1(new PatchCase1Builder().setCaseLeaf1("ChoiceUpdate").build())
265 .setLeaf1("AugmentLeaf")
267 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf12("Bertha").setName("Althea").build()))
269 writeTransaction.commit();
270 adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_UPDATE));
272 writeTransaction = dataBroker.newWriteOnlyTransaction();
273 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
274 writeTransaction.commit();
275 adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_DELETE));
279 public void testJsonNotifsChangedLeaves() throws Exception {
280 ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.JSON,
281 false, false, true, false, listenersBroker);
282 adapter.setCloseVars(domDataBroker, databindProvider);
284 final DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
285 .getInstance(DOMDataTreeChangeService.class);
286 final DOMDataTreeIdentifier root =
287 new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
288 changeService.registerDataTreeChangeListener(root, adapter);
290 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
291 final InstanceIdentifier<PatchCont> iid = InstanceIdentifier.create(PatchCont.class);
292 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
293 .addAugmentation(new PatchCont1Builder()
294 .setPatchChoice2(new PatchCase11Builder()
295 .setPatchSubChoice11(new PatchSubCase11Builder()
296 .setPatchSubSubChoice11(new PatchSubSubCase11Builder().setCaseLeaf11("ChoiceLeaf").build())
299 .setLeaf1("AugmentLeaf")
301 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build()))
303 writeTransaction.commit();
304 adapter.assertGot(getNotifJson(JSON_NOTIF_CHANGED_LEAVES_CREATE));
306 writeTransaction = dataBroker.newWriteOnlyTransaction();
307 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
308 .addAugmentation(new PatchCont1Builder()
309 .setPatchChoice2(new PatchCase11Builder()
310 .setPatchSubChoice11(new PatchSubCase11Builder()
311 .setPatchSubSubChoice11(new PatchSubSubCase11Builder().setCaseLeaf11("ChoiceUpdate").build())
314 .setLeaf1("AugmentLeaf")
316 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf12("Bertha").setName("Althea").build()))
318 writeTransaction.commit();
319 adapter.assertGot(getNotifJson(JSON_NOTIF_CHANGED_LEAVES_UPDATE));
321 writeTransaction = dataBroker.newWriteOnlyTransaction();
322 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
323 writeTransaction.commit();
324 adapter.assertGot(getNotifJson(JSON_NOTIF_CHANGED_LEAVES_DELETE));
328 public void testJsonChildNodesOnly() throws Exception {
329 final var adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
330 NotificationOutputType.JSON, false, false, false, true, listenersBroker);
331 adapter.setCloseVars(domDataBroker, databindProvider);
333 final var changeService = domDataBroker.getExtensions()
334 .getInstance(DOMDataTreeChangeService.class);
335 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
336 changeService.registerDataTreeChangeListener(root, adapter);
338 final var iid = InstanceIdentifier.create(PatchCont.class).child(MyList1.class, new MyList1Key("Althea"));
339 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
340 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid,
341 new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build());
342 writeTransaction.commit();
343 adapter.assertGot(getNotifJson(JSON_NOTIF_CHILD_NODES_ONLY_CREATE));
345 writeTransaction = dataBroker.newWriteOnlyTransaction();
346 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid,
347 new MyList1Builder().setMyLeaf11("Bertha").setName("Althea").build());
348 writeTransaction.commit();
349 adapter.assertGot(getNotifJson(JSON_NOTIF_CHILD_NODES_ONLY_UPDATE1));
351 writeTransaction = dataBroker.newWriteOnlyTransaction();
352 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid,
353 new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build());
354 writeTransaction.commit();
355 adapter.assertGot(getNotifJson(JSON_NOTIF_CHILD_NODES_ONLY_UPDATE2));
357 writeTransaction = dataBroker.newWriteOnlyTransaction();
358 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
359 writeTransaction.commit();
360 adapter.assertGot(getNotifJson(JSON_NOTIF_CHILD_NODES_ONLY_DELETE));
364 public void testXmlLeavesOnly() throws Exception {
365 ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.XML,
366 true, false, false, false, listenersBroker);
367 adapter.setCloseVars(domDataBroker, databindProvider);
369 DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
370 .getInstance(DOMDataTreeChangeService.class);
371 DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
372 changeService.registerDataTreeChangeListener(root, adapter);
373 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
374 final InstanceIdentifier<PatchCont> iid = InstanceIdentifier.create(PatchCont.class);
375 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
376 .addAugmentation(new PatchCont1Builder()
377 .setPatchChoice1(new PatchCase1Builder().setCaseLeaf1("ChoiceLeaf").build())
378 .setLeaf1("AugmentLeaf")
380 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build()))
382 writeTransaction.commit();
383 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_LEAVES_CREATE));
385 writeTransaction = dataBroker.newWriteOnlyTransaction();
386 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
387 .addAugmentation(new PatchCont1Builder()
388 .setPatchChoice1(new PatchCase1Builder().setCaseLeaf1("ChoiceUpdate").build())
389 .setLeaf1("AugmentLeaf")
391 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf12("Bertha").setName("Althea").build()))
393 writeTransaction.commit();
394 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_LEAVES_UPDATE));
396 writeTransaction = dataBroker.newWriteOnlyTransaction();
397 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
398 writeTransaction.commit();
400 // xmlunit cannot compare deeper children it seems out of the box so just check the iid encoding
401 final String notification = adapter.awaitUntilNotification("");
402 assertThat(notification, allOf(
403 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
404 + "/a:my-list1[a:name='Althea']/a:my-leaf11</path>"),
405 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
406 + "/a:my-list1[a:name='Althea']/a:my-leaf12</path>"),
407 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
408 + "/a:my-list1[a:name='Althea']/a:name</path>"),
409 containsString("<path xmlns:a=\"instance:identifier:patch:module\" "
410 + "xmlns:b=\"augment:instance:identifier:patch:module\">/a:patch-cont/b:leaf1</path>"),
411 containsString("<path xmlns:a=\"instance:identifier:patch:module\" "
412 + "xmlns:b=\"augment:instance:identifier:patch:module\">/a:patch-cont/b:case-leaf1</path>")));
416 public void testXmlChangedLeavesOnly() throws Exception {
417 ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey", NotificationOutputType.XML,
418 false, false, true, false, listenersBroker);
419 adapter.setCloseVars(domDataBroker, databindProvider);
421 DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
422 .getInstance(DOMDataTreeChangeService.class);
423 DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
424 changeService.registerDataTreeChangeListener(root, adapter);
425 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
426 final InstanceIdentifier<PatchCont> iid = InstanceIdentifier.create(PatchCont.class);
427 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
428 .addAugmentation(new PatchCont1Builder()
429 .setPatchChoice2(new PatchCase11Builder()
430 .setPatchSubChoice11(new PatchSubCase11Builder()
431 .setPatchSubSubChoice11(new PatchSubSubCase11Builder().setCaseLeaf11("ChoiceLeaf").build())
434 .setLeaf1("AugmentLeaf")
436 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build()))
438 writeTransaction.commit();
439 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHANGED_LEAVES_CREATE));
441 writeTransaction = dataBroker.newWriteOnlyTransaction();
442 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, new PatchContBuilder()
443 .addAugmentation(new PatchCont1Builder()
444 .setPatchChoice2(new PatchCase11Builder()
445 .setPatchSubChoice11(new PatchSubCase11Builder()
446 .setPatchSubSubChoice11(new PatchSubSubCase11Builder().setCaseLeaf11("ChoiceUpdate").build())
449 .setLeaf1("AugmentLeaf")
451 .setMyList1(BindingMap.of(new MyList1Builder().setMyLeaf12("Bertha").setName("Althea").build()))
453 writeTransaction.commit();
454 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHANGED_LEAVES_UPDATE));
456 writeTransaction = dataBroker.newWriteOnlyTransaction();
457 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
458 writeTransaction.commit();
460 // xmlunit cannot compare deeper children it seems out of the box so just check the iid encoding
461 final String notification = adapter.awaitUntilNotification("");
462 assertThat(notification, allOf(
463 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
464 + "/a:my-list1[a:name='Althea']/a:my-leaf11</path>"),
465 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
466 + "/a:my-list1[a:name='Althea']/a:my-leaf12</path>"),
467 containsString("<path xmlns:a=\"instance:identifier:patch:module\">/a:patch-cont"
468 + "/a:my-list1[a:name='Althea']/a:name</path>"),
469 containsString("<path xmlns:a=\"instance:identifier:patch:module\" "
470 + "xmlns:b=\"augment:instance:identifier:patch:module\">/a:patch-cont/b:leaf1</path>"),
471 containsString("<path xmlns:a=\"instance:identifier:patch:module\" "
472 + "xmlns:b=\"augment:instance:identifier:patch:module\">/a:patch-cont/b:case-leaf11</path>")));
476 public void testXmlChildNodesOnly() throws Exception {
477 final var adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
478 NotificationOutputType.XML, false, false, false, true, listenersBroker);
479 adapter.setCloseVars(domDataBroker, databindProvider);
481 final var changeService = domDataBroker.getExtensions()
482 .getInstance(DOMDataTreeChangeService.class);
483 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
484 changeService.registerDataTreeChangeListener(root, adapter);
486 final var iid = InstanceIdentifier.create(PatchCont.class).child(MyList1.class, new MyList1Key("Althea"));
487 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
488 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid,
489 new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build());
490 writeTransaction.commit();
491 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHILD_NODES_ONLY_CREATE));
493 writeTransaction = dataBroker.newWriteOnlyTransaction();
494 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid,
495 new MyList1Builder().setMyLeaf11("Bertha").setName("Althea").build());
496 writeTransaction.commit();
497 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHILD_NODES_ONLY_UPDATE1));
499 writeTransaction = dataBroker.newWriteOnlyTransaction();
500 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid,
501 new MyList1Builder().setMyLeaf11("Jed").setName("Althea").build());
502 writeTransaction.commit();
503 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHILD_NODES_ONLY_UPDATE2));
505 writeTransaction = dataBroker.newWriteOnlyTransaction();
506 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
507 writeTransaction.commit();
508 adapter.assertXmlSimilar(getResultXml(XML_NOTIF_CHILD_NODES_ONLY_DELETE));
512 public void testJsonContNotifications() throws Exception {
513 jsonNotifications(PATCH_CONT_YIID, false, JSON_NOTIF_CONT_CREATE,
514 JSON_NOTIF_CONT_UPDATE, JSON_NOTIF_CONT_DELETE);
518 public void testJsonListNotifications() throws Exception {
519 jsonNotifications(MY_LIST1_YIID, false, JSON_NOTIF_LIST_CREATE,
520 JSON_NOTIF_LIST_UPDATE, JSON_NOTIF_LIST_DELETE);
524 public void testJsonContNotificationsWithoutData() throws Exception {
525 jsonNotifications(PATCH_CONT_YIID, true, JSON_NOTIF_WITHOUT_DATA_CONT_CREATE,
526 JSON_NOTIF_WITHOUT_DATA_CONT_UPDATE, JSON_NOTIF_WITHOUT_DATA_CONT_DELETE);
530 public void testJsonListNotificationsWithoutData() throws Exception {
531 jsonNotifications(MY_LIST1_YIID, true, JSON_NOTIF_WITHOUT_DATA_LIST_CREATE,
532 JSON_NOTIF_WITHOUT_DATA_LIST_UPDATE, JSON_NOTIF_WITHOUT_DATA_LIST_DELETE);
536 public void testXmlContNotifications() throws Exception {
537 xmlNotifications(PATCH_CONT_YIID, false, XML_NOTIF_CONT_CREATE,
538 XML_NOTIF_CONT_UPDATE, XML_NOTIF_CONT_DELETE);
542 public void testXmlListNotifications() throws Exception {
543 xmlNotifications(MY_LIST1_YIID, false, XML_NOTIF_LIST_CREATE,
544 XML_NOTIF_LIST_UPDATE, XML_NOTIF_LIST_DELETE);
548 public void testXmlContNotificationsWithoutData() throws Exception {
549 xmlNotifications(PATCH_CONT_YIID, true, XML_NOTIF_WITHOUT_DATA_CONT_CREATE,
550 XML_NOTIF_WITHOUT_DATA_CONT_UPDATE, XML_NOTIF_WITHOUT_DATA_CONT_DELETE);
554 public void testXmlListNotificationsWithoutData() throws Exception {
555 xmlNotifications(MY_LIST1_YIID, true, XML_NOTIF_WITHOUT_DATA_LIST_CREATE,
556 XML_NOTIF_WITHOUT_DATA_LIST_UPDATE, XML_NOTIF_WITHOUT_DATA_LIST_DELETE);
559 static String withFakeDate(final String in) throws JSONException {
560 final JSONObject doc = new JSONObject(in);
561 final JSONObject notification = doc.getJSONObject("ietf-restconf:notification");
562 if (notification == null) {
565 notification.put("event-time", "someDate");
566 return doc.toString();
569 static String withFakeXmlDate(final String in) {
570 return in.replaceAll("<eventTime>.*</eventTime>", "<eventTime>someDate</eventTime>");
573 private String getNotifJson(final String path) throws IOException, URISyntaxException, JSONException {
574 return withFakeDate(Files.readString(Paths.get(getClass().getResource(path).toURI())));
577 private String getResultXml(final String path) throws IOException, URISyntaxException, JSONException {
578 return withFakeXmlDate(Files.readString(Paths.get(getClass().getResource(path).toURI())));
581 private void jsonNotifications(final YangInstanceIdentifier pathYiid, final boolean skipData,
582 final String jsonNotifCreate, final String jsonNotifUpdate, final String jsonNotifDelete) throws Exception {
583 final var adapter = new ListenerAdapterTester(pathYiid, "Casey",
584 NotificationOutputType.JSON, false, skipData, false, false, listenersBroker);
585 adapter.setCloseVars(domDataBroker, databindProvider);
587 final var changeService = domDataBroker.getExtensions()
588 .getInstance(DOMDataTreeChangeService.class);
589 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, pathYiid);
590 changeService.registerDataTreeChangeListener(root, adapter);
592 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
593 MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
594 final var iid = InstanceIdentifier.create(PatchCont.class)
595 .child(MyList1.class, new MyList1Key("Althea"));
596 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
597 writeTransaction.commit();
598 adapter.assertGot(getNotifJson(jsonNotifCreate));
600 writeTransaction = dataBroker.newWriteOnlyTransaction();
601 builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
602 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
603 writeTransaction.commit();
604 adapter.assertGot(getNotifJson(jsonNotifUpdate));
606 writeTransaction = dataBroker.newWriteOnlyTransaction();
607 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
608 writeTransaction.commit();
609 adapter.assertGot(getNotifJson(jsonNotifDelete));
612 private void xmlNotifications(final YangInstanceIdentifier pathYiid, final boolean skipData,
613 final String xmlNotifCreate, final String xmlNotifUpdate, final String xmlNotifDelete) throws Exception {
614 final var adapter = new ListenerAdapterTester(pathYiid, "Casey", NotificationOutputType.XML,
615 false, skipData, false, false, listenersBroker);
616 adapter.setCloseVars(domDataBroker, databindProvider);
618 final var changeService = domDataBroker.getExtensions()
619 .getInstance(DOMDataTreeChangeService.class);
620 final var root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, pathYiid);
621 changeService.registerDataTreeChangeListener(root, adapter);
623 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
624 MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
625 final var iid = InstanceIdentifier.create(PatchCont.class)
626 .child(MyList1.class, new MyList1Key("Althea"));
627 writeTransaction.put(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
628 writeTransaction.commit();
629 adapter.assertXmlSimilar(getResultXml(xmlNotifCreate));
631 writeTransaction = dataBroker.newWriteOnlyTransaction();
632 builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
633 writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
634 writeTransaction.commit();
635 adapter.assertXmlSimilar(getResultXml(xmlNotifUpdate));
637 writeTransaction = dataBroker.newWriteOnlyTransaction();
638 writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
639 writeTransaction.commit();
640 adapter.assertXmlSimilar(getResultXml(xmlNotifDelete));