Fix NPE when trying to download restconf provided yang files
[netconf.git] / restconf / restconf-nb-rfc8040 / src / test / java / org / opendaylight / restconf / nb / rfc8040 / services / simple / impl / RestconfSchemaServiceTest.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.nb.rfc8040.services.simple.impl;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.fail;
15 import static org.mockito.Mockito.when;
16
17 import com.google.common.collect.ImmutableClassToInstanceMap;
18 import java.util.HashMap;
19 import org.junit.Before;
20 import org.junit.Rule;
21 import org.junit.Test;
22 import org.junit.rules.ExpectedException;
23 import org.mockito.Mock;
24 import org.mockito.MockitoAnnotations;
25 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
26 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
27 import org.opendaylight.controller.md.sal.dom.broker.impl.mount.DOMMountPointServiceImpl;
28 import org.opendaylight.controller.md.sal.dom.broker.spi.mount.SimpleDOMMountPoint;
29 import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider;
30 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
31 import org.opendaylight.restconf.common.errors.RestconfError;
32 import org.opendaylight.restconf.common.schema.SchemaExportContext;
33 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
34 import org.opendaylight.restconf.nb.rfc8040.handlers.DOMMountPointServiceHandler;
35 import org.opendaylight.restconf.nb.rfc8040.handlers.SchemaContextHandler;
36 import org.opendaylight.restconf.nb.rfc8040.services.simple.api.RestconfSchemaService;
37 import org.opendaylight.restconf.nb.rfc8040.utils.RestconfConstants;
38 import org.opendaylight.yangtools.yang.common.QName;
39 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
40 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
41 import org.opendaylight.yangtools.yang.model.api.Module;
42 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
43 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
44
45 /**
46  * Unit tests for {@code RestconfSchemaService}.
47  */
48 public class RestconfSchemaServiceTest {
49     private static final String MOUNT_POINT = "mount-point-1:cont" + "/" + RestconfConstants.MOUNT + "/";
50     private static final String NULL_MOUNT_POINT = "mount-point-2:cont" + "/" + RestconfConstants.MOUNT + "/";
51     private static final String NOT_EXISTING_MOUNT_POINT = "mount-point-3:cont" + "/" + RestconfConstants.MOUNT + "/";
52
53     private static final String TEST_MODULE = "module1/2014-01-01";
54     private static final String TEST_MODULE_BEHIND_MOUNT_POINT = "module1-behind-mount-point/2014-02-03";
55     private static final String NOT_EXISTING_MODULE = "not-existing/2016-01-01";
56
57     @Rule public ExpectedException thrown = ExpectedException.none();
58
59     // service under test
60     private RestconfSchemaService schemaService;
61
62     // handlers
63     @Mock
64     private SchemaContextHandler mockContextHandler;
65     @Mock
66     private DOMMountPointServiceHandler mockMountPointHandler;
67     @Mock
68     private DOMYangTextSourceProvider sourceProvider;
69
70     // schema context with modules
71     private SchemaContext schemaContext;
72     // schema context with modules behind mount point
73     private SchemaContext schemaContextBehindMountPoint;
74     // schema context with mount points
75     private SchemaContext schemaContextWithMountPoints;
76
77     // mount point with schema context with modules behind mount point
78     private DOMMountPoint mountPoint;
79     // mount point with null schema context
80     private DOMMountPoint mountPointWithNullSchemaContext;
81     // mount point service
82     private DOMMountPointService mountPointService;
83
84     @Before
85     public void setup() throws Exception {
86         MockitoAnnotations.initMocks(this);
87
88         this.schemaContext = YangParserTestUtils.parseYangSources(TestRestconfUtils.loadFiles("/modules"));
89         this.schemaContextBehindMountPoint = YangParserTestUtils
90                 .parseYangSources(TestRestconfUtils.loadFiles("/modules/modules-behind-mount-point"));
91         this.schemaContextWithMountPoints =
92                 YangParserTestUtils.parseYangSources(TestRestconfUtils.loadFiles("/modules/mount-points"));
93
94         // create and register mount points
95         this.mountPoint = SimpleDOMMountPoint.create(
96                 YangInstanceIdentifier.of(QName.create("mount:point:1", "2016-01-01", "cont")),
97                 ImmutableClassToInstanceMap.copyOf(new HashMap<>()),
98                 this.schemaContextBehindMountPoint
99         );
100
101         this.mountPointWithNullSchemaContext = SimpleDOMMountPoint.create(
102                 YangInstanceIdentifier.of(QName.create("mount:point:2", "2016-01-01", "cont")),
103                 ImmutableClassToInstanceMap.copyOf(new HashMap<>()),
104                 null
105         );
106
107         this.mountPointService = new DOMMountPointServiceImpl();
108         ((DOMMountPointServiceImpl) this.mountPointService).registerMountPoint(this.mountPoint);
109         ((DOMMountPointServiceImpl) this.mountPointService).registerMountPoint(this.mountPointWithNullSchemaContext);
110         when(this.mockMountPointHandler.get()).thenReturn(this.mountPointService);
111
112         this.schemaService = new RestconfSchemaServiceImpl(this.mockContextHandler, this.mockMountPointHandler,
113                 sourceProvider);
114     }
115
116     /**
117      * Test if service was successfully created.
118      */
119     @Test
120     public void schemaServiceImplInitTest() {
121         assertNotNull("Schema service should be initialized and not null", this.schemaService);
122     }
123
124     /**
125      * Get schema with identifier of existing module and check if correct module was found.
126      */
127     @Test
128     public void getSchemaTest() {
129         // prepare conditions - return not-mount point schema context
130         when(this.mockContextHandler.get()).thenReturn(this.schemaContext);
131
132         // make test
133         final SchemaExportContext exportContext = this.schemaService.getSchema(TEST_MODULE);
134
135         // verify
136         assertNotNull("Export context should not be null", exportContext);
137
138         final Module module = exportContext.getModule();
139         assertNotNull("Existing module should be found", module);
140
141         assertEquals("Not expected module name", "module1", module.getName());
142         assertEquals("Not expected module revision", "2014-01-01",
143                 SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision()));
144         assertEquals("Not expected module namespace", "module:1", module.getNamespace().toString());
145     }
146
147     /**
148      * Get schema with identifier of not-existing module. <code>SchemaExportContext</code> is still created, but module
149      * should be set to <code>null</code>.
150      */
151     @Test
152     public void getSchemaForNotExistingModuleTest() {
153         // prepare conditions - return not-mount point schema context
154         when(this.mockContextHandler.get()).thenReturn(this.schemaContext);
155
156         // make test
157         final SchemaExportContext exportContext = this.schemaService.getSchema(NOT_EXISTING_MODULE);
158
159         // verify
160         assertNotNull("Export context should not be null", exportContext);
161         assertNull("Not-existing module should not be found", exportContext.getModule());
162     }
163
164     /**
165      * Get schema with identifier of existing module behind mount point and check if correct module was found.
166      */
167     @Test
168     public void getSchemaMountPointTest() {
169         // prepare conditions - return schema context with mount points
170         when(this.mockContextHandler.get()).thenReturn(this.schemaContextWithMountPoints);
171
172         // make test
173         final SchemaExportContext exportContext =
174                 this.schemaService.getSchema(MOUNT_POINT + TEST_MODULE_BEHIND_MOUNT_POINT);
175
176         // verify
177         assertNotNull("Export context should not be null", exportContext);
178
179         final Module module = exportContext.getModule();
180         assertNotNull("Existing module should be found", module);
181
182         assertEquals("Not expected module name", "module1-behind-mount-point", module.getName());
183         assertEquals("Not expected module revision", "2014-02-03",
184                 SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision()));
185         assertEquals("Not expected module namespace", "module:1:behind:mount:point", module.getNamespace().toString());
186     }
187
188     /**
189      * Get schema with identifier of not-existing module behind mount point. <code>SchemaExportContext</code> is still
190      * created, but module should be set to <code>null</code>.
191      */
192     @Test
193     public void getSchemaForNotExistingModuleMountPointTest() {
194         // prepare conditions - return schema context with mount points
195         when(this.mockContextHandler.get()).thenReturn(this.schemaContextWithMountPoints);
196
197         // make test
198         final SchemaExportContext exportContext = this.schemaService.getSchema(MOUNT_POINT + NOT_EXISTING_MODULE);
199
200         // verify
201         assertNotNull("Export context should not be null", exportContext);
202         assertNull("Not-existing module should not be found", exportContext.getModule());
203     }
204
205     /**
206      * Try to get schema with <code>null</code> <code>SchemaContext</code> expecting <code>NullPointerException</code>.
207      */
208     @Test
209     public void getSchemaWithNullSchemaContextTest() {
210         // prepare conditions - returned schema context is null
211         when(this.mockContextHandler.get()).thenReturn(null);
212
213         // make test
214         this.thrown.expect(NullPointerException.class);
215         this.schemaService.getSchema(TEST_MODULE);
216     }
217
218     /**
219      * Try to get schema with <code>null</code> <code>SchemaContext</code> for mount points.
220      * <code>NullPointerException</code> is expected.
221      */
222     @Test
223     public void getSchemaWithNullSchemaContextMountPointTest() {
224         // prepare conditions - returned schema context for mount points is null
225         when(this.mockContextHandler.get()).thenReturn(null);
226
227         // make test
228         this.thrown.expect(NullPointerException.class);
229         this.schemaService.getSchema(MOUNT_POINT + TEST_MODULE_BEHIND_MOUNT_POINT);
230     }
231
232     /**
233      * Try to get schema with <code>null</code> <code>SchemaContext</code> behind mount point when using
234      * <code>NULL_MOUNT_POINT</code>. Test is expected to fail with <code>NullPointerException</code>.
235      */
236     @Test
237     public void getSchemaNullSchemaContextBehindMountPointTest() {
238         // prepare conditions - return correct schema context for mount points (this is not null)
239         when(this.mockContextHandler.get()).thenReturn(this.schemaContextWithMountPoints);
240
241         // make test - call service on mount point with null schema context
242         this.thrown.expect(NullPointerException.class);
243         // NULL_MOUNT_POINT contains null schema context
244         this.schemaService.getSchema(NULL_MOUNT_POINT + TEST_MODULE_BEHIND_MOUNT_POINT);
245     }
246
247     /**
248      * Try to get schema with null identifier expecting <code>NullPointerException</code>. The same processing is for
249      * server and also for mount point.
250      */
251     @Test
252     public void getSchemaWithNullIdentifierTest() {
253         // prepare conditions - return correct schema context
254         when(this.mockContextHandler.get()).thenReturn(this.schemaContext);
255
256         // make test
257         this.thrown.expect(NullPointerException.class);
258         this.schemaService.getSchema(null);
259     }
260
261     /**
262      * Try to get schema with empty (not valid) identifier catching <code>RestconfDocumentedException</code>. Error
263      * type, error tag and error status code are compared to expected values.
264      */
265     @Test
266     public void getSchemaWithEmptyIdentifierTest() {
267         // prepare conditions - return correct schema context
268         when(this.mockContextHandler.get()).thenReturn(this.schemaContext);
269
270         // make test and verify
271         try {
272             this.schemaService.getSchema("");
273             fail("Test should fail due to invalid identifier");
274         } catch (final RestconfDocumentedException e) {
275             assertEquals(RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
276             assertEquals(RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
277             assertEquals(400, e.getErrors().get(0).getErrorTag().getStatusCode());
278         }
279     }
280
281     /**
282      * Try to get schema with empty (not valid) identifier behind mount point catching
283      * <code>RestconfDocumentedException</code>. Error type, error tag and error status code are compared to expected
284      * values.
285      */
286     @Test
287     public void getSchemaWithEmptyIdentifierMountPointTest() {
288         // prepare conditions - return correct schema context with mount points
289         when(this.mockContextHandler.get()).thenReturn(this.schemaContextWithMountPoints);
290
291         // make test and verify
292         try {
293             this.schemaService.getSchema(MOUNT_POINT + "");
294             fail("Test should fail due to invalid identifier");
295         } catch (final RestconfDocumentedException e) {
296             assertEquals(RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
297             assertEquals(RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
298             assertEquals(400, e.getErrors().get(0).getErrorTag().getStatusCode());
299         }
300     }
301
302     /**
303      * Try to get schema with not-parsable identifier catching <code>RestconfDocumentedException</code>. Error type,
304      * error tag and error status code are compared to expected values.
305      */
306     @Test
307     public void getSchemaWithNotParsableIdentifierTest() {
308         // prepare conditions - return correct schema context without mount points
309         when(this.mockContextHandler.get()).thenReturn(this.schemaContext);
310
311         // make test and verify
312         try {
313             this.schemaService.getSchema("01_module/2016-01-01");
314             fail("Test should fail due to invalid identifier");
315         } catch (final RestconfDocumentedException e) {
316             assertEquals(RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
317             assertEquals(RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
318             assertEquals(400, e.getErrors().get(0).getErrorTag().getStatusCode());
319         }
320     }
321
322     /**
323      * Try to get schema behind mount point with not-parsable identifier catching
324      * <code>RestconfDocumentedException</code>. Error type, error tag and error status code are compared to expected
325      * values.
326      */
327     @Test
328     public void getSchemaWithNotParsableIdentifierMountPointTest() {
329         // prepare conditions - return correct schema context with mount points
330         when(this.mockContextHandler.get()).thenReturn(this.schemaContextWithMountPoints);
331
332         // make test and verify
333         try {
334             this.schemaService.getSchema(MOUNT_POINT + "01_module/2016-01-01");
335             fail("Test should fail due to invalid identifier");
336         } catch (final RestconfDocumentedException e) {
337             assertEquals(RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
338             assertEquals(RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
339             assertEquals(400, e.getErrors().get(0).getErrorTag().getStatusCode());
340         }
341     }
342
343     /**
344      * Try to get schema with wrong (not valid) identifier catching <code>RestconfDocumentedException</code>. Error
345      * type, error tag and error status code are compared to expected values.
346      *
347      * <p>
348      * Not valid identifier contains only revision without module name.
349      */
350     @Test
351     public void getSchemaWrongIdentifierTest() {
352         // prepare conditions - return correct schema context without mount points
353         when(this.mockContextHandler.get()).thenReturn(this.schemaContext);
354
355         // make test and verify
356         try {
357             this.schemaService.getSchema("2014-01-01");
358             fail("Test should fail due to invalid identifier");
359         } catch (final RestconfDocumentedException e) {
360             assertEquals(RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
361             assertEquals(RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
362             assertEquals(400, e.getErrors().get(0).getErrorTag().getStatusCode());
363         }
364     }
365
366     /**
367      * Try to get schema with wrong (not valid) identifier behind mount point catching
368      * <code>RestconfDocumentedException</code>. Error type, error tag and error status code are compared to expected
369      * values.
370      *
371      * <p>
372      * Not valid identifier contains only revision without module name.
373      */
374     @Test
375     public void getSchemaWrongIdentifierMountPointTest() {
376         // prepare conditions - return correct schema context with mount points
377         when(this.mockContextHandler.get()).thenReturn(this.schemaContextWithMountPoints);
378
379         // make test and verify
380         try {
381             this.schemaService.getSchema(MOUNT_POINT + "2014-01-01");
382             fail("Test should fail due to invalid identifier");
383         } catch (final RestconfDocumentedException e) {
384             assertEquals(RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
385             assertEquals(RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
386             assertEquals(400, e.getErrors().get(0).getErrorTag().getStatusCode());
387         }
388     }
389
390     /**
391      * Try to get schema with identifier which does not contain revision catching
392      * <code>RestconfDocumentedException</code>. Error type, error tag and error status code are compared to expected
393      * values.
394      */
395     @Test
396     public void getSchemaWithoutRevisionTest() {
397         // prepare conditions - return correct schema context without mount points
398         when(this.mockContextHandler.get()).thenReturn(this.schemaContext);
399
400         // make test and verify
401         try {
402             this.schemaService.getSchema("module");
403             fail("Test should fail due to invalid identifier");
404         } catch (final RestconfDocumentedException e) {
405             assertEquals(RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
406             assertEquals(RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
407             assertEquals(400, e.getErrors().get(0).getErrorTag().getStatusCode());
408         }
409     }
410
411     /**
412      * Try to get schema behind mount point with identifier when does not contain revision catching
413      * <code>RestconfDocumentedException</code>. Error type, error tag and error status code are compared to expected
414      * values.
415      */
416     @Test
417     public void getSchemaWithoutRevisionMountPointTest() {
418         // prepare conditions - return correct schema context with mount points
419         when(this.mockContextHandler.get()).thenReturn(this.schemaContextWithMountPoints);
420
421         // make test and verify
422         try {
423             this.schemaService.getSchema(MOUNT_POINT + "module");
424             fail("Test should fail due to invalid identifier");
425         } catch (final RestconfDocumentedException e) {
426             assertEquals(RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
427             assertEquals(RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
428             assertEquals(400, e.getErrors().get(0).getErrorTag().getStatusCode());
429         }
430     }
431
432     /**
433      * Negative test when mount point module is not found in current <code>SchemaContext</code> for mount points.
434      * <code>IllegalArgumentException</code> exception is expected.
435      */
436     @Test
437     public void getSchemaContextWithNotExistingMountPointTest() {
438         // prepare conditions - return schema context with mount points
439         when(this.mockContextHandler.get()).thenReturn(this.schemaContextWithMountPoints);
440
441         // make test
442         this.thrown.expect(IllegalArgumentException.class);
443         this.schemaService.getSchema(NOT_EXISTING_MOUNT_POINT + TEST_MODULE_BEHIND_MOUNT_POINT);
444     }
445 }