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.services.impl;
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 com.google.common.collect.Iterables;
19 import com.google.common.collect.Lists;
20 import java.util.AbstractMap;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.Iterator;
25 import java.util.List;
27 import org.junit.AfterClass;
28 import org.junit.Before;
29 import org.junit.BeforeClass;
30 import org.junit.Rule;
31 import org.junit.Test;
32 import org.junit.rules.ExpectedException;
33 import org.mockito.Mock;
34 import org.mockito.MockitoAnnotations;
35 import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
36 import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
37 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
38 import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
39 import org.opendaylight.netconf.sal.streams.listeners.Notificator;
40 import org.opendaylight.restconf.Draft18;
41 import org.opendaylight.restconf.handlers.SchemaContextHandler;
42 import org.opendaylight.restconf.rest.services.api.RestconfStreamsService;
43 import org.opendaylight.restconf.utils.mapping.RestconfMappingNodeConstants;
44 import org.opendaylight.restconf.utils.mapping.RestconfMappingStreamConstants;
45 import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
46 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
47 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
48 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
49 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
50 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
51 import org.opendaylight.yangtools.yang.data.impl.schema.nodes.AbstractImmutableDataContainerAttrNode;
52 import org.opendaylight.yangtools.yang.model.api.Module;
53 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
56 * Unit tests for {@link RestconfStreamsServiceImpl}
58 public class RestconfStreamsServiceTest {
59 private static final List<String> expectedStreams = Arrays.asList(new String[] {"stream-1", "stream-2", "stream-3"});
61 @Rule public ExpectedException thrown = ExpectedException.none();
63 @Mock private SchemaContextHandler contextHandler;
64 @Mock private SchemaContext mockSchemaContext;
67 private RestconfStreamsService streamsService;
69 // schema context with testing Restconf modules
70 private SchemaContext schemaContext;
73 public void setup() throws Exception {
74 MockitoAnnotations.initMocks(this);
76 this.schemaContext = TestRestconfUtils.loadSchemaContext("/modules/restconf-module-testing");
77 this.streamsService = new RestconfStreamsServiceImpl(this.contextHandler);
81 public static void setupTestStreams() {
83 Notificator.removeAllListeners();
86 Notificator.createListener(EMPTY, RestconfStreamsServiceTest.expectedStreams.get(0),
87 NotificationOutputType.XML);
88 Notificator.createListener(EMPTY, RestconfStreamsServiceTest.expectedStreams.get(1),
89 NotificationOutputType.XML);
90 Notificator.createListener(EMPTY, RestconfStreamsServiceTest.expectedStreams.get(2),
91 NotificationOutputType.XML);
95 public static void removeTestStreams() {
96 Notificator.removeAllListeners();
100 * Test of successful initialization of streams service.
103 public void restconfStreamsServiceImplInitTest() {
104 assertNotNull("Streams service should be initialized and not null", this.streamsService);
108 * Positive test to get all available streams supported by the server. Loaded streams are compared to expected
112 public void getAvailableStreamsTest() throws Exception {
113 // prepare conditions - get correct Restconf module
114 when(this.contextHandler.get()).thenReturn(this.mockSchemaContext);
115 when(this.mockSchemaContext.findModuleByNamespaceAndRevision(Draft18.RestconfModule.IETF_RESTCONF_QNAME
116 .getNamespace(), Draft18.RestconfModule.IETF_RESTCONF_QNAME.getRevision()))
117 .thenReturn(getTestingRestconfModule("ietf-restconf"));
120 final NormalizedNodeContext nodeContext = this.streamsService.getAvailableStreams(null);
122 // verify loaded streams
123 assertNotNull("Normalized node context should not be null", nodeContext);
124 verifyStreams(((ContainerNode) nodeContext.getData()).getValue());
128 * Try to get all available streams supported by the server when current <code>SchemaContext</code> is
129 * <code>null</code> expecting <code>NullPointerException</code>.
132 public void getAvailableStreamsNullSchemaContextNegativeTest() {
133 // prepare conditions - returned SchemaContext is null
134 when(this.contextHandler.get()).thenReturn(null);
137 this.thrown.expect(NullPointerException.class);
138 this.streamsService.getAvailableStreams(null);
142 * Try to get all available streams supported by the server when Restconf module is missing in
143 * <code>SchemaContext</code> expecting <code>NullPointerException</code>.
146 public void getAvailableStreamsMissingRestconfModuleNegativeTest() {
147 // prepare conditions - get null Restconf module
148 when(this.contextHandler.get()).thenReturn(this.mockSchemaContext);
149 when(this.mockSchemaContext.findModuleByNamespaceAndRevision(Draft18.RestconfModule.IETF_RESTCONF_QNAME
150 .getNamespace(), Draft18.RestconfModule.IETF_RESTCONF_QNAME.getRevision())).thenReturn(null);
153 this.thrown.expect(NullPointerException.class);
154 this.streamsService.getAvailableStreams(null);
158 * Try to get all available streams supported by the server when Restconf module does not contain list stream
159 * catching <code>RestconfDocumentedException</code>. Error type, error tag and error status code are validated
160 * against expected values.
163 public void getAvailableStreamsMissingListStreamNegativeTest() {
164 // prepare conditions - get Restconf module with missing list stream
165 when(this.contextHandler.get()).thenReturn(this.mockSchemaContext);
166 when(this.mockSchemaContext.findModuleByNamespaceAndRevision(Draft18.RestconfModule.IETF_RESTCONF_QNAME
167 .getNamespace(), Draft18.RestconfModule.IETF_RESTCONF_QNAME.getRevision()))
168 .thenReturn(getTestingRestconfModule("restconf-module-with-missing-list-stream"));
170 // make test and verify
172 this.streamsService.getAvailableStreams(null);
173 fail("Test is expected to fail due to missing list stream");
174 } catch (final RestconfDocumentedException e) {
175 assertEquals("Error type is not correct",
176 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
177 assertEquals("Error tag is not correct",
178 RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
179 assertEquals("Error status code is not correct",
180 404, e.getErrors().get(0).getErrorTag().getStatusCode());
185 * Try to get all available streams supported by the server when Restconf module does not contain container streams
186 * catching <code>RestconfDocumentedException</code>. Error type, error tag and error status code are validated
187 * against expected values.
190 public void getAvailableStreamsMissingContainerStreamsNegativeTest() {
191 // prepare conditions - get Restconf module with missing container streams
192 when(this.contextHandler.get()).thenReturn(this.mockSchemaContext);
193 when(this.mockSchemaContext.findModuleByNamespaceAndRevision(Draft18.RestconfModule.IETF_RESTCONF_QNAME
194 .getNamespace(), Draft18.RestconfModule.IETF_RESTCONF_QNAME.getRevision()))
195 .thenReturn(getTestingRestconfModule("restconf-module-with-missing-container-streams"));
197 // make test and verify
199 this.streamsService.getAvailableStreams(null);
200 fail("Test is expected to fail due to missing container streams");
201 } catch (final RestconfDocumentedException e) {
202 assertEquals("Error type is not correct",
203 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
204 assertEquals("Error tag is not correct",
205 RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
206 assertEquals("Error status code is not correct",
207 404, e.getErrors().get(0).getErrorTag().getStatusCode());
212 * Try to get all available streams supported by the server when Restconf module contains node with name 'stream'
213 * but it is not of type list. Test is expected to fail with <code>IllegalStateException</code>.
216 public void getAvailableStreamsIllegalListStreamNegativeTest() {
217 // prepare conditions - get Restconf module with illegal list stream
218 when(this.contextHandler.get()).thenReturn(this.mockSchemaContext);
219 when(this.mockSchemaContext.findModuleByNamespaceAndRevision(Draft18.RestconfModule.IETF_RESTCONF_QNAME
220 .getNamespace(), Draft18.RestconfModule.IETF_RESTCONF_QNAME.getRevision()))
221 .thenReturn(getTestingRestconfModule("restconf-module-with-illegal-list-stream"));
224 this.thrown.expect(IllegalStateException.class);
225 this.streamsService.getAvailableStreams(null);
229 * Try to get all available streams supported by the server when Restconf module contains node with name 'streams'
230 * but it is not of type container. Test is expected to fail with <code>IllegalStateException</code>.
233 public void getAvailableStreamsIllegalContainerStreamsNegativeTest() {
234 // prepare conditions - get Restconf module with illegal container streams
235 when(this.contextHandler.get()).thenReturn(this.mockSchemaContext);
236 when(this.mockSchemaContext.findModuleByNamespaceAndRevision(Draft18.RestconfModule.IETF_RESTCONF_QNAME
237 .getNamespace(), Draft18.RestconfModule.IETF_RESTCONF_QNAME.getRevision()))
238 .thenReturn(getTestingRestconfModule("restconf-module-with-illegal-container-streams"));
241 this.thrown.expect(IllegalStateException.class);
242 this.streamsService.getAvailableStreams(null);
246 * Try to get all available streams supported by the server when node 'description' in list stream in Restconf
247 * module is not of type leaf. Test is expected to fail with <code>IllegalStateException</code>.
250 public void getAvailableStreamsIllegalLeafDescriptionNegativeTest() {
251 // prepare conditions - get Restconf module with illegal leaf description in list stream
252 when(this.contextHandler.get()).thenReturn(this.mockSchemaContext);
253 when(this.mockSchemaContext.findModuleByNamespaceAndRevision(Draft18.RestconfModule.IETF_RESTCONF_QNAME
254 .getNamespace(), Draft18.RestconfModule.IETF_RESTCONF_QNAME.getRevision()))
255 .thenReturn(getTestingRestconfModule("restconf-module-with-illegal-leaf-description"));
258 this.thrown.expect(IllegalStateException.class);
259 this.streamsService.getAvailableStreams(null);
263 * There are multiple testing Restconf modules for different test cases. It is possible to distinguish them by
264 * name or by namespace. This method is looking for Restconf test module by its name.
265 * @param s Testing Restconf module name
266 * @return Restconf module
268 private Module getTestingRestconfModule(final String s) {
269 return this.schemaContext.findModuleByName(s, Draft18.RestconfModule.IETF_RESTCONF_QNAME.getRevision());
273 * Verify loaded streams
274 * @param streams Streams to be verified
276 private void verifyStreams(final Collection<DataContainerChild<? extends PathArgument, ?>> streams) {
277 assertNotNull("Collection of streams should not be empty", streams);
278 assertFalse("Collection of streams should not be empty", Iterables.isEmpty(streams));
279 final Iterator<DataContainerChild<? extends PathArgument, ?>> iterator = streams.iterator();
281 final List<String> loadedStreams = new ArrayList<>();
282 for (final Object stream : (Collection<?>) iterator.next().getValue()) {
283 final Iterator mapEntries = ((AbstractImmutableDataContainerAttrNode) stream)
284 .getChildren().entrySet().iterator();
286 final List<String> allowedKeys = Lists.newArrayList(
287 RestconfMappingNodeConstants.NAME,
288 RestconfMappingNodeConstants.DESCRIPTION,
289 RestconfMappingNodeConstants.REPLAY_SUPPORT,
290 RestconfMappingNodeConstants.REPLAY_LOG,
291 RestconfMappingNodeConstants.EVENTS);
293 while (mapEntries.hasNext()) {
294 final Map.Entry e = ((AbstractMap.SimpleImmutableEntry) mapEntries.next());
295 final String key = ((NodeIdentifier) e.getKey()).getNodeType().getLocalName();
297 assertTrue("Not allowed key", allowedKeys.contains(key));
300 case RestconfMappingNodeConstants.NAME :
301 loadedStreams.add((String) ((LeafNode) e.getValue()).getValue());
303 case RestconfMappingNodeConstants.DESCRIPTION :
304 assertEquals("Stream description value is not as expected",
305 RestconfMappingStreamConstants.DESCRIPTION, ((LeafNode) e.getValue()).getValue());
307 case RestconfMappingNodeConstants.REPLAY_SUPPORT :
308 assertEquals("Stream replay support value is not as expected",
309 RestconfMappingStreamConstants.REPLAY_SUPPORT, ((LeafNode) e.getValue()).getValue());
311 case RestconfMappingNodeConstants.REPLAY_LOG :
312 assertEquals("Stream replay log value is not as expected",
313 RestconfMappingStreamConstants.REPLAY_LOG, ((LeafNode) e.getValue()).getValue());
315 case RestconfMappingNodeConstants.EVENTS :
316 assertEquals("Stream events value is not as expected",
317 RestconfMappingStreamConstants.EVENTS, ((LeafNode) e.getValue()).getValue());
324 loadedStreams.sort((s1, s2) -> s1.compareTo(s2));
325 assertEquals("Returned streams are not as expected", expectedStreams, loadedStreams);