1f2cf6597091096a024f32429ca12ff5ca5f56f4
[netconf.git] / restconf / restconf-nb-rfc8040 / src / test / java / org / opendaylight / restconf / nb / rfc8040 / streams / listeners / XmlNotificationListenerTest.java
1 /*
2  * Copyright (c) 2020 Pantheon.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.restconf.nb.rfc8040.streams.listeners;
10
11 import static org.mockito.ArgumentMatchers.any;
12 import static org.mockito.Mockito.mock;
13 import static org.mockito.Mockito.when;
14 import static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
15 import static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
16 import static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
17 import static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
18
19 import com.google.common.collect.Lists;
20 import java.net.URI;
21 import java.time.Instant;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Optional;
25 import org.junit.AfterClass;
26 import org.junit.BeforeClass;
27 import org.junit.Test;
28 import org.junit.runner.RunWith;
29 import org.mockito.junit.MockitoJUnitRunner;
30 import org.opendaylight.mdsal.dom.api.DOMNotification;
31 import org.opendaylight.restconf.nb.rfc8040.TestUtils;
32 import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping;
33 import org.opendaylight.yangtools.util.SingletonSet;
34 import org.opendaylight.yangtools.yang.common.QName;
35 import org.opendaylight.yangtools.yang.common.QNameModule;
36 import org.opendaylight.yangtools.yang.common.Revision;
37 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
38 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
39 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
40 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
43 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
44 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
45 import org.xmlunit.assertj.XmlAssert;
46
47 @RunWith(MockitoJUnitRunner.StrictStubs.class)
48 public class XmlNotificationListenerTest {
49     private static final QNameModule MODULE = QNameModule.create(URI.create("notifi:mod"), Revision.of("2016-11-23"));
50
51     private static EffectiveModelContext SCHEMA_CONTEXT;
52
53     @BeforeClass
54     public static void beforeClass() throws Exception {
55         SCHEMA_CONTEXT = TestUtils.loadSchemaContext("/notifications");
56     }
57
58     @AfterClass
59     public static void afterClass() {
60         SCHEMA_CONTEXT = null;
61     }
62
63     @Test
64     public void notifi_leafTest() throws Exception {
65         final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-leaf"));
66
67         final DOMNotification notificationData = mock(DOMNotification.class);
68
69         final LeafNode<String> leaf = mockLeaf(QName.create(MODULE, "lf"));
70         final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), leaf);
71
72         when(notificationData.getType()).thenReturn(schemaPathNotifi);
73         when(notificationData.getBody()).thenReturn(notifiBody);
74
75         final String result = prepareXmlResult(notificationData, schemaPathNotifi);
76
77         final String control = "<notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\">"
78                 + "<eventTime>2020-06-29T14:23:46.086855+02:00</eventTime><notifi-leaf xmlns=\"notifi:mod\">"
79                 + "<lf>value</lf></notifi-leaf></notification>";
80
81         assertXmlMatches(result, control);
82     }
83
84     @Test
85     public void notifi_cont_leafTest() throws Exception {
86         final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-cont"));
87
88         final DOMNotification notificationData = mock(DOMNotification.class);
89
90         final LeafNode<String> leaf = mockLeaf(QName.create(MODULE, "lf"));
91         final ContainerNode cont = mockCont(QName.create(MODULE, "cont"), leaf);
92         final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), cont);
93
94         when(notificationData.getType()).thenReturn(schemaPathNotifi);
95         when(notificationData.getBody()).thenReturn(notifiBody);
96
97         final String result = prepareXmlResult(notificationData, schemaPathNotifi);
98
99         final String control = "<notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\">"
100                 + "<eventTime>2020-06-29T14:23:46.086855+02:00</eventTime><notifi-cont xmlns=\"notifi:mod\">"
101                 + "<cont><lf>value</lf></cont></notifi-cont></notification>";
102
103         assertXmlMatches(result, control);
104     }
105
106     @Test
107     public void notifi_list_Test() throws Exception {
108         final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-list"));
109
110         final DOMNotification notificationData = mock(DOMNotification.class);
111
112         final LeafNode<String> leaf = mockLeaf(QName.create(MODULE, "lf"));
113         final MapEntryNode entry = mockMapEntry(QName.create(MODULE, "lst"), leaf);
114         final MapNode list = mockList(QName.create(MODULE, "lst"), entry);
115         final ContainerNode cont = mockCont(QName.create(MODULE, "cont"), list);
116         final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), cont);
117
118         when(notificationData.getType()).thenReturn(schemaPathNotifi);
119         when(notificationData.getBody()).thenReturn(notifiBody);
120
121         final String result = prepareXmlResult(notificationData, schemaPathNotifi);
122
123         final String control = "<notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\">"
124                 + "<eventTime>2020-06-29T14:23:46.086855+02:00</eventTime><notifi-list xmlns=\"notifi:mod\">"
125                 + "<notifi-list><lf><lf>value</lf></lf></notifi-list></notifi-list></notification>";
126
127         assertXmlMatches(result, control);
128     }
129
130     @Test
131     public void notifi_grpTest() throws Exception {
132         final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-grp"));
133
134         final DOMNotification notificationData = mock(DOMNotification.class);
135
136         final LeafNode<String> leaf = mockLeaf(QName.create(MODULE, "lf"));
137         final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), leaf);
138
139         when(notificationData.getType()).thenReturn(schemaPathNotifi);
140         when(notificationData.getBody()).thenReturn(notifiBody);
141
142         final String result = prepareXmlResult(notificationData, schemaPathNotifi);
143
144         final String control = "<notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\">"
145                 + "<eventTime>2020-06-29T14:23:46.086855+02:00</eventTime><notifi-grp xmlns=\"notifi:mod\">"
146                 + "<lf>value</lf></notifi-grp></notification>";
147
148         assertXmlMatches(result, control);
149     }
150
151     @Test
152     public void notifi_augmTest() throws Exception {
153         final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-augm"));
154
155         final DOMNotification notificationData = mock(DOMNotification.class);
156
157         final LeafNode<String> leaf = mockLeaf(QName.create(MODULE, "lf-augm"));
158         final AugmentationNode augm = mockAugm(leaf);
159         final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), augm);
160
161         when(notificationData.getType()).thenReturn(schemaPathNotifi);
162         when(notificationData.getBody()).thenReturn(notifiBody);
163
164         final String result = prepareXmlResult(notificationData, schemaPathNotifi);
165
166         final String control = "<notification xmlns=\"urn:ietf:params:xml:ns:netconf:notification:1.0\">"
167                 + "<eventTime>2020-06-29T14:23:46.086855+02:00</eventTime><notifi-augm xmlns=\"notifi:mod\">"
168                 + "<lf-augm>value</lf-augm></notifi-augm></notification>";
169
170         assertXmlMatches(result, control);
171     }
172
173     private static void assertXmlMatches(String result, String control) {
174         XmlAssert.assertThat(result).and(control)
175                 // text values have localName null but we want to compare those, ignore only nodes that have localName
176                 // with eventTime value
177                 .withNodeFilter(node -> node.getLocalName() == null || !node.getLocalName().equals("eventTime"))
178                 .areSimilar();
179     }
180
181     private static AugmentationNode mockAugm(final LeafNode<String> leaf) {
182         final AugmentationNode augm = mock(AugmentationNode.class);
183         final AugmentationIdentifier augmId = new AugmentationIdentifier(SingletonSet.of(leaf.getNodeType()));
184         when(augm.getIdentifier()).thenReturn(augmId);
185
186         final Collection<DataContainerChild<? extends PathArgument, ?>> childs = new ArrayList<>();
187         childs.add(leaf);
188
189         when(augm.getValue()).thenReturn(childs);
190         return augm;
191     }
192
193     private static MapEntryNode mockMapEntry(final QName entryQName, final LeafNode<String> leaf) {
194         final MapEntryNode entry = mock(MapEntryNode.class);
195         final NodeIdentifierWithPredicates nodeId = NodeIdentifierWithPredicates.of(leaf.getNodeType(),
196                 leaf.getNodeType(), "value");
197         when(entry.getIdentifier()).thenReturn(nodeId);
198         when(entry.getChild(any())).thenReturn(Optional.of(leaf));
199
200         final Collection<DataContainerChild<? extends PathArgument, ?>> childs = new ArrayList<>();
201         childs.add(leaf);
202
203         when(entry.getValue()).thenReturn(childs);
204         return entry;
205     }
206
207     private static MapNode mockList(final QName listQName, final MapEntryNode... entries) {
208         final MapNode list = mock(MapNode.class);
209         when(list.getIdentifier()).thenReturn(NodeIdentifier.create(listQName));
210         when(list.getValue()).thenReturn(Lists.newArrayList(entries));
211         return list;
212     }
213
214     private static ContainerNode mockCont(final QName contQName,
215                                           final DataContainerChild<? extends PathArgument, ?> child) {
216         final ContainerNode cont = mock(ContainerNode.class);
217         when(cont.getIdentifier()).thenReturn(NodeIdentifier.create(contQName));
218
219         final Collection<DataContainerChild<? extends PathArgument, ?>> childs = new ArrayList<>();
220         childs.add(child);
221         when(cont.getValue()).thenReturn(childs);
222         return cont;
223     }
224
225     private static LeafNode<String> mockLeaf(final QName leafQName) {
226         final LeafNode<String> child = mock(LeafNode.class);
227         when(child.getNodeType()).thenReturn(leafQName);
228         when(child.getIdentifier()).thenReturn(NodeIdentifier.create(leafQName));
229         when(child.getValue()).thenReturn("value");
230         return child;
231     }
232
233     private static String prepareXmlResult(final DOMNotification notificationData, final Absolute schemaPathNotifi)
234             throws Exception {
235         final NotificationListenerAdapter notifiAdapter = ListenersBroker.getInstance().registerNotificationListener(
236                 schemaPathNotifi, "xml-stream", NotificationOutputTypeGrouping.NotificationOutputType.XML);
237         return notifiAdapter.formatter.eventData(SCHEMA_CONTEXT, notificationData, Instant.now(), false, false).get();
238     }
239 }