Merge "Fix bug 5810, 5812: 1. only when node's config statement is true, such apis...
[netconf.git] / restconf / sal-rest-connector / src / test / java / org / opendaylight / restconf / rest / impl / services / RestconfStreamsServiceTest.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.restconf.rest.impl.services;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertFalse;
13 import static org.junit.Assert.assertNotNull;
14 import static org.junit.Assert.assertTrue;
15 import static org.junit.Assert.fail;
16 import static org.mockito.Mockito.when;
17 import static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.EMPTY;
18 import static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
19 import static org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
20
21 import com.google.common.collect.Iterables;
22 import com.google.common.collect.Lists;
23 import java.util.AbstractMap;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import org.junit.Before;
31 import org.junit.Rule;
32 import org.junit.Test;
33 import org.junit.rules.ExpectedException;
34 import org.mockito.Mock;
35 import org.mockito.MockitoAnnotations;
36 import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
37 import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
38 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
39 import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
40 import org.opendaylight.netconf.sal.streams.listeners.Notificator;
41 import org.opendaylight.restconf.Draft11;
42 import org.opendaylight.restconf.rest.api.schema.context.SchemaContextHandler;
43 import org.opendaylight.restconf.rest.api.services.RestconfStreamsService;
44 import org.opendaylight.restconf.utils.mapping.RestconfMappingNodeConstants;
45 import org.opendaylight.restconf.utils.mapping.RestconfMappingStreamConstants;
46 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
47 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
48 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
49 import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableDataContainerAttrNode;
50 import org.opendaylight.yangtools.yang.model.api.Module;
51 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
52
53 /**
54  * Unit tests for {@link RestconfStreamsServiceImpl}
55  */
56 public class RestconfStreamsServiceTest {
57     private final List<String> expectedStreams = Arrays.asList(new String[] {"stream-1", "stream-2", "stream-3"});
58
59     @Rule public ExpectedException thrown = ExpectedException.none();
60
61     @Mock private SchemaContextHandler contextHandler;
62     @Mock private SchemaContext mockSchemaContext;
63
64     // service under test
65     private RestconfStreamsService streamsService;
66
67     // schema context with testing Restconf modules
68     private SchemaContext schemaContext;
69
70     @Before
71     public void setup() throws Exception {
72         MockitoAnnotations.initMocks(this);
73
74         schemaContext = TestRestconfUtils.loadSchemaContext("/modules/restconf-module-testing");
75         streamsService = new RestconfStreamsServiceImpl(contextHandler);
76
77         // create streams
78         Notificator.createListener(EMPTY, expectedStreams.get(0));
79         Notificator.createListener(EMPTY, expectedStreams.get(1));
80         Notificator.createListener(EMPTY, expectedStreams.get(2));
81     }
82
83     /**
84      * Test of successful initialization of streams service.
85      */
86     @Test
87     public void restconfStreamsServiceImplInitTest() {
88         assertNotNull("Streams service should be initialized and not null", streamsService);
89     }
90
91     /**
92      * Positive test to get all available streams supported by the server. Loaded streams are compared to expected
93      * streams.
94      */
95     @Test
96     public void getAvailableStreamsTest() throws Exception {
97         // prepare conditions - get correct Restconf module
98         when(contextHandler.getSchemaContext()).thenReturn(mockSchemaContext);
99         when(mockSchemaContext.findModuleByNamespaceAndRevision(Draft11.RestconfModule.IETF_RESTCONF_QNAME
100                 .getNamespace(), Draft11.RestconfModule.IETF_RESTCONF_QNAME.getRevision()))
101                 .thenReturn(getTestingRestconfModule("ietf-restconf"));
102
103         // make test
104         final NormalizedNodeContext nodeContext = streamsService.getAvailableStreams(null);
105
106         // verify loaded streams
107         assertNotNull("Normalized node context should not be null", nodeContext);
108         verifyStreams(((ContainerNode) nodeContext.getData()).getValue());
109     }
110
111     /**
112      * Try to get all available streams supported by the server when current <code>SchemaContext</code> is
113      * <code>null</code> expecting <code>NullPointerException</code>.
114      */
115     @Test
116     public void getAvailableStreamsNullSchemaContextNegativeTest() {
117         // prepare conditions - returned SchemaContext is null
118         when(contextHandler.getSchemaContext()).thenReturn(null);
119
120         // make test
121         thrown.expect(NullPointerException.class);
122         streamsService.getAvailableStreams(null);
123     }
124
125     /**
126      * Try to get all available streams supported by the server when Restconf module is missing in
127      * <code>SchemaContext</code> expecting <code>NullPointerException</code>.
128      */
129     @Test
130     public void getAvailableStreamsMissingRestconfModuleNegativeTest() {
131         // prepare conditions - get null Restconf module
132         when(contextHandler.getSchemaContext()).thenReturn(mockSchemaContext);
133         when(mockSchemaContext.findModuleByNamespaceAndRevision(Draft11.RestconfModule.IETF_RESTCONF_QNAME
134                 .getNamespace(), Draft11.RestconfModule.IETF_RESTCONF_QNAME.getRevision())).thenReturn(null);
135
136         // make test
137         thrown.expect(NullPointerException.class);
138         streamsService.getAvailableStreams(null);
139     }
140
141     /**
142      * Try to get all available streams supported by the server when Restconf module does not contain list stream
143      * catching <code>RestconfDocumentedException</code>. Error type, error tag and error status code are validated
144      * against expected values.
145      */
146     @Test
147     public void getAvailableStreamsMissingListStreamNegativeTest() {
148         // prepare conditions - get Restconf module with missing list stream
149         when(contextHandler.getSchemaContext()).thenReturn(mockSchemaContext);
150         when(mockSchemaContext.findModuleByNamespaceAndRevision(Draft11.RestconfModule.IETF_RESTCONF_QNAME
151                 .getNamespace(), Draft11.RestconfModule.IETF_RESTCONF_QNAME.getRevision()))
152                 .thenReturn(getTestingRestconfModule("restconf-module-with-missing-list-stream"));
153
154         // make test and verify
155         try {
156             streamsService.getAvailableStreams(null);
157             fail("Test is expected to fail due to missing list stream");
158         } catch (final RestconfDocumentedException e) {
159             assertEquals("Error type is not correct",
160                     RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
161             assertEquals("Error tag is not correct",
162                     RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
163             assertEquals("Error status code is not correct",
164                     404, e.getErrors().get(0).getErrorTag().getStatusCode());
165         }
166     }
167
168     /**
169      * Try to get all available streams supported by the server when Restconf module does not contain container streams
170      * catching <code>RestconfDocumentedException</code>. Error type, error tag and error status code are validated
171      * against expected values.
172      */
173     @Test
174     public void getAvailableStreamsMissingContainerStreamsNegativeTest() {
175         // prepare conditions - get Restconf module with missing container streams
176         when(contextHandler.getSchemaContext()).thenReturn(mockSchemaContext);
177         when(mockSchemaContext.findModuleByNamespaceAndRevision(Draft11.RestconfModule.IETF_RESTCONF_QNAME
178                 .getNamespace(), Draft11.RestconfModule.IETF_RESTCONF_QNAME.getRevision()))
179                 .thenReturn(getTestingRestconfModule("restconf-module-with-missing-container-streams"));
180
181         // make test and verify
182         try {
183             streamsService.getAvailableStreams(null);
184             fail("Test is expected to fail due to missing container streams");
185         } catch (final RestconfDocumentedException e) {
186             assertEquals("Error type is not correct",
187                     RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
188             assertEquals("Error tag is not correct",
189                     RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
190             assertEquals("Error status code is not correct",
191                     404, e.getErrors().get(0).getErrorTag().getStatusCode());
192         }
193     }
194
195     /**
196      * Try to get all available streams supported by the server when Restconf module contains node with name 'stream'
197      * but it is not of type list. Test is expected to fail with <code>IllegalStateException</code>.
198      */
199     @Test
200     public void getAvailableStreamsIllegalListStreamNegativeTest() {
201         // prepare conditions - get Restconf module with illegal list stream
202         when(contextHandler.getSchemaContext()).thenReturn(mockSchemaContext);
203         when(mockSchemaContext.findModuleByNamespaceAndRevision(Draft11.RestconfModule.IETF_RESTCONF_QNAME
204                 .getNamespace(), Draft11.RestconfModule.IETF_RESTCONF_QNAME.getRevision()))
205                 .thenReturn(getTestingRestconfModule("restconf-module-with-illegal-list-stream"));
206
207         // make test
208         thrown.expect(IllegalStateException.class);
209         streamsService.getAvailableStreams(null);
210     }
211
212     /**
213      * Try to get all available streams supported by the server when Restconf module contains node with name 'streams'
214      * but it is not of type container. Test is expected to fail with <code>IllegalStateException</code>.
215      */
216     @Test
217     public void getAvailableStreamsIllegalContainerStreamsNegativeTest() {
218         // prepare conditions - get Restconf module with illegal container streams
219         when(contextHandler.getSchemaContext()).thenReturn(mockSchemaContext);
220         when(mockSchemaContext.findModuleByNamespaceAndRevision(Draft11.RestconfModule.IETF_RESTCONF_QNAME
221                 .getNamespace(), Draft11.RestconfModule.IETF_RESTCONF_QNAME.getRevision()))
222                 .thenReturn(getTestingRestconfModule("restconf-module-with-illegal-container-streams"));
223
224         // make test
225         thrown.expect(IllegalStateException.class);
226         streamsService.getAvailableStreams(null);
227     }
228
229     /**
230      * Try to get all available streams supported by the server when node 'description' in list stream in Restconf
231      * module is not of type leaf. Test is expected to fail with <code>IllegalStateException</code>.
232      */
233     @Test
234     public void getAvailableStreamsIllegalLeafDescriptionNegativeTest() {
235         // prepare conditions - get Restconf module with illegal leaf description in list stream
236         when(contextHandler.getSchemaContext()).thenReturn(mockSchemaContext);
237         when(mockSchemaContext.findModuleByNamespaceAndRevision(Draft11.RestconfModule.IETF_RESTCONF_QNAME
238                 .getNamespace(), Draft11.RestconfModule.IETF_RESTCONF_QNAME.getRevision()))
239                 .thenReturn(getTestingRestconfModule("restconf-module-with-illegal-leaf-description"));
240
241         // make test
242         thrown.expect(IllegalStateException.class);
243         streamsService.getAvailableStreams(null);
244     }
245
246     /**
247      * There are multiple testing Restconf modules for different test cases. It is possible to distinguish them by
248      * name or by namespace. This method is looking for Restconf test module by its name.
249      * @param s Testing Restconf module name
250      * @return Restconf module
251      */
252     private Module getTestingRestconfModule(final String s) {
253         return schemaContext.findModuleByName(s, Draft11.RestconfModule.IETF_RESTCONF_QNAME.getRevision());
254     }
255
256     /**
257      * Verify loaded streams
258      * @param streams Streams to be verified
259      */
260     private void verifyStreams(final Collection<DataContainerChild<? extends PathArgument, ?>> streams) {
261         assertNotNull("Collection of streams should not be empty", streams);
262         assertFalse("Collection of streams should not be empty", Iterables.isEmpty(streams));
263         final Iterator<DataContainerChild<? extends PathArgument, ?>> iterator = streams.iterator();
264
265         final List<String> loadedStreams = new ArrayList<>();
266         for (final Object stream : (Collection<?>) iterator.next().getValue()) {
267             final Iterator mapEntries = ((AbstractImmutableDataContainerAttrNode) stream)
268                     .getChildren().entrySet().iterator();
269
270             final List<String> allowedKeys = Lists.newArrayList(
271                     RestconfMappingNodeConstants.NAME,
272                     RestconfMappingNodeConstants.DESCRIPTION,
273                     RestconfMappingNodeConstants.REPLAY_SUPPORT,
274                     RestconfMappingNodeConstants.REPLAY_LOG,
275                     RestconfMappingNodeConstants.EVENTS);
276
277             while (mapEntries.hasNext()) {
278                 final Map.Entry e = ((AbstractMap.SimpleImmutableEntry) mapEntries.next());
279                 final String key = ((NodeIdentifier) e.getKey()).getNodeType().getLocalName();
280
281                 assertTrue("Not allowed key", allowedKeys.contains(key));
282
283                 switch (key) {
284                     case RestconfMappingNodeConstants.NAME :
285                         loadedStreams.add((String) ((LeafNode) e.getValue()).getValue());
286                         break;
287                     case RestconfMappingNodeConstants.DESCRIPTION :
288                         assertEquals("Stream description value is not as expected",
289                                 RestconfMappingStreamConstants.DESCRIPTION, ((LeafNode) e.getValue()).getValue());
290                         break;
291                     case RestconfMappingNodeConstants.REPLAY_SUPPORT :
292                         assertEquals("Stream replay support value is not as expected",
293                                 RestconfMappingStreamConstants.REPLAY_SUPPORT, ((LeafNode) e.getValue()).getValue());
294                         break;
295                     case RestconfMappingNodeConstants.REPLAY_LOG :
296                         assertEquals("Stream replay log value is not as expected",
297                                 RestconfMappingStreamConstants.REPLAY_LOG, ((LeafNode) e.getValue()).getValue());
298                         break;
299                     case RestconfMappingNodeConstants.EVENTS :
300                         assertEquals("Stream events value is not as expected",
301                                 RestconfMappingStreamConstants.EVENTS, ((LeafNode) e.getValue()).getValue());
302                         break;
303                 }
304             }
305         }
306
307         // sort and compare
308         loadedStreams.sort((s1, s2) -> s1.compareTo(s2));
309         assertEquals("Returned streams are not as expected", expectedStreams, loadedStreams);
310     }
311 }