2 * Copyright (c) 2016 Cisco Systems, 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
9 package org.opendaylight.restconf.rest.impl.services;
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;
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;
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;
54 * Unit tests for {@link RestconfStreamsServiceImpl}
56 public class RestconfStreamsServiceTest {
57 private final List<String> expectedStreams = Arrays.asList(new String[] {"stream-1", "stream-2", "stream-3"});
59 @Rule public ExpectedException thrown = ExpectedException.none();
61 @Mock private SchemaContextHandler contextHandler;
62 @Mock private SchemaContext mockSchemaContext;
65 private RestconfStreamsService streamsService;
67 // schema context with testing Restconf modules
68 private SchemaContext schemaContext;
71 public void setup() throws Exception {
72 MockitoAnnotations.initMocks(this);
74 schemaContext = TestRestconfUtils.loadSchemaContext("/modules/restconf-module-testing");
75 streamsService = new RestconfStreamsServiceImpl(contextHandler);
78 Notificator.createListener(EMPTY, expectedStreams.get(0));
79 Notificator.createListener(EMPTY, expectedStreams.get(1));
80 Notificator.createListener(EMPTY, expectedStreams.get(2));
84 * Test of successful initialization of streams service.
87 public void restconfStreamsServiceImplInitTest() {
88 assertNotNull("Streams service should be initialized and not null", streamsService);
92 * Positive test to get all available streams supported by the server. Loaded streams are compared to expected
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"));
104 final NormalizedNodeContext nodeContext = streamsService.getAvailableStreams(null);
106 // verify loaded streams
107 assertNotNull("Normalized node context should not be null", nodeContext);
108 verifyStreams(((ContainerNode) nodeContext.getData()).getValue());
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>.
116 public void getAvailableStreamsNullSchemaContextNegativeTest() {
117 // prepare conditions - returned SchemaContext is null
118 when(contextHandler.getSchemaContext()).thenReturn(null);
121 thrown.expect(NullPointerException.class);
122 streamsService.getAvailableStreams(null);
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>.
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);
137 thrown.expect(NullPointerException.class);
138 streamsService.getAvailableStreams(null);
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.
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"));
154 // make test and verify
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());
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.
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"));
181 // make test and verify
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());
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>.
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"));
208 thrown.expect(IllegalStateException.class);
209 streamsService.getAvailableStreams(null);
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>.
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"));
225 thrown.expect(IllegalStateException.class);
226 streamsService.getAvailableStreams(null);
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>.
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"));
242 thrown.expect(IllegalStateException.class);
243 streamsService.getAvailableStreams(null);
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
252 private Module getTestingRestconfModule(final String s) {
253 return schemaContext.findModuleByName(s, Draft11.RestconfModule.IETF_RESTCONF_QNAME.getRevision());
257 * Verify loaded streams
258 * @param streams Streams to be verified
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();
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();
270 final List<String> allowedKeys = Lists.newArrayList(
271 RestconfMappingNodeConstants.NAME,
272 RestconfMappingNodeConstants.DESCRIPTION,
273 RestconfMappingNodeConstants.REPLAY_SUPPORT,
274 RestconfMappingNodeConstants.REPLAY_LOG,
275 RestconfMappingNodeConstants.EVENTS);
277 while (mapEntries.hasNext()) {
278 final Map.Entry e = ((AbstractMap.SimpleImmutableEntry) mapEntries.next());
279 final String key = ((NodeIdentifier) e.getKey()).getNodeType().getLocalName();
281 assertTrue("Not allowed key", allowedKeys.contains(key));
284 case RestconfMappingNodeConstants.NAME :
285 loadedStreams.add((String) ((LeafNode) e.getValue()).getValue());
287 case RestconfMappingNodeConstants.DESCRIPTION :
288 assertEquals("Stream description value is not as expected",
289 RestconfMappingStreamConstants.DESCRIPTION, ((LeafNode) e.getValue()).getValue());
291 case RestconfMappingNodeConstants.REPLAY_SUPPORT :
292 assertEquals("Stream replay support value is not as expected",
293 RestconfMappingStreamConstants.REPLAY_SUPPORT, ((LeafNode) e.getValue()).getValue());
295 case RestconfMappingNodeConstants.REPLAY_LOG :
296 assertEquals("Stream replay log value is not as expected",
297 RestconfMappingStreamConstants.REPLAY_LOG, ((LeafNode) e.getValue()).getValue());
299 case RestconfMappingNodeConstants.EVENTS :
300 assertEquals("Stream events value is not as expected",
301 RestconfMappingStreamConstants.EVENTS, ((LeafNode) e.getValue()).getValue());
308 loadedStreams.sort((s1, s2) -> s1.compareTo(s2));
309 assertEquals("Returned streams are not as expected", expectedStreams, loadedStreams);