c782be9bb0293c7f7aa6e86ac42d61e43d8c3ec6
[netconf.git] / restconf / restconf-nb-rfc8040 / src / test / java / org / opendaylight / restconf / nb / rfc8040 / utils / parser / ParserIdentifierTest.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 package org.opendaylight.restconf.nb.rfc8040.utils.parser;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.assertSame;
14 import static org.junit.Assert.assertThrows;
15 import static org.mockito.Mockito.when;
16
17 import java.util.Map.Entry;
18 import java.util.Optional;
19 import org.junit.AfterClass;
20 import org.junit.Before;
21 import org.junit.BeforeClass;
22 import org.junit.Test;
23 import org.junit.runner.RunWith;
24 import org.mockito.Mock;
25 import org.mockito.junit.MockitoJUnitRunner;
26 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
27 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
28 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
29 import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider;
30 import org.opendaylight.mdsal.dom.broker.DOMMountPointServiceImpl;
31 import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
32 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
33 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
34 import org.opendaylight.restconf.common.errors.RestconfError;
35 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
36 import org.opendaylight.restconf.common.schema.SchemaExportContext;
37 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
38 import org.opendaylight.restconf.nb.rfc8040.utils.RestconfConstants;
39 import org.opendaylight.yangtools.yang.common.ErrorType;
40 import org.opendaylight.yangtools.yang.common.QName;
41 import org.opendaylight.yangtools.yang.common.Revision;
42 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
43 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
44 import org.opendaylight.yangtools.yang.model.api.Module;
45 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
46
47 /**
48  * Unit tests for {@link ParserIdentifier}.
49  */
50 @RunWith(MockitoJUnitRunner.StrictStubs.class)
51 public class ParserIdentifierTest {
52     // mount point identifier
53     private static final String MOUNT_POINT_IDENT = "mount-point:mount-container/point-number/yang-ext:mount";
54
55     // invalid mount point identifier
56     private static final String INVALID_MOUNT_POINT_IDENT = "mount-point:point-number/yang-ext:mount";
57
58     // test identifier + expected result
59     private static final String TEST_IDENT =
60             "parser-identifier:cont1/cont2/listTest/list-in-grouping=name/leaf-A.B";
61
62     private static final String TEST_IDENT_RESULT =
63             "/(parser:identifier?revision=2016-06-02)cont1/cont2/listTest/listTest/list-in-grouping/"
64             + "list-in-grouping[{(parser:identifier?revision=2016-06-02)name=name}]/leaf-A.B";
65
66     // test identifier with nodes defined in other modules using augmentation + expected result
67     private static final String TEST_IDENT_OTHERS =
68             "parser-identifier-included:list-1=name,2016-06-02/parser-identifier:augment-leaf";
69
70     private static final String TEST_IDENT_OTHERS_RESULT =
71             "/(parser:identifier:included?revision=2016-06-02)list-1/list-1"
72             + "[{(parser:identifier:included?revision=2016-06-02)name=name, "
73             + "(parser:identifier:included?revision=2016-06-02)revision=2016-06-02}]"
74             + "/AugmentationIdentifier{childNames=[(parser:identifier?revision=2016-06-02)augment-leaf]}/"
75             + "(parser:identifier?revision=2016-06-02)augment-leaf";
76
77     // invalid test identifier
78     private static final String INVALID_TEST_IDENT =
79             "parser-identifier:cont2/listTest/list-in-grouping=name/leaf-A.B";
80
81     private static final String TEST_MODULE_NAME = "test-module";
82     private static final String TEST_MODULE_REVISION = "2016-06-02";
83     private static final String TEST_MODULE_NAMESPACE = "test:module";
84
85     private static final String INVOKE_RPC = "invoke-rpc-module:rpc-test";
86     private static final String INVOKE_ACTION = "example-actions:interfaces/interface=eth0/reset";
87
88     // schema context with test modules
89     private static EffectiveModelContext SCHEMA_CONTEXT;
90     // contains the same modules but it is different object (it can be compared with equals)
91     private static EffectiveModelContext SCHEMA_CONTEXT_ON_MOUNT_POINT;
92
93     // mount point and mount point service
94     private DOMMountPoint mountPoint;
95     private DOMMountPointService mountPointService;
96
97     // mock mount point and mount point service
98     @Mock
99     private DOMMountPoint mockMountPoint;
100     @Mock
101     private DOMMountPointService mockMountPointService;
102     @Mock
103     private DOMSchemaService domSchemaService;
104     @Mock
105     private DOMYangTextSourceProvider sourceProvider;
106
107     @BeforeClass
108     public static void beforeClass() throws Exception {
109         SCHEMA_CONTEXT = YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/parser-identifier"));
110         SCHEMA_CONTEXT_ON_MOUNT_POINT =
111                 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/parser-identifier"));
112     }
113
114     @AfterClass
115     public static void afterClass() {
116         SCHEMA_CONTEXT = null;
117         SCHEMA_CONTEXT_ON_MOUNT_POINT = null;
118     }
119
120     @Before
121     public void setup() throws Exception {
122         this.mountPointService = new DOMMountPointServiceImpl();
123
124         // create and register mount point
125         final YangInstanceIdentifier mountPointId = YangInstanceIdentifier.builder()
126                 .node(QName.create("mount:point", "2016-06-02", "mount-container"))
127                 .node(QName.create("mount:point", "2016-06-02", "point-number"))
128                 .build();
129
130         mountPoint = mountPointService.createMountPoint(mountPointId)
131                 .addService(DOMSchemaService.class, FixedDOMSchemaService.of(SCHEMA_CONTEXT_ON_MOUNT_POINT))
132                 .register()
133                 .getInstance();
134
135         // register mount point with null schema context
136         when(this.mockMountPointService.getMountPoint(YangInstanceIdentifier.empty()))
137                 .thenReturn(Optional.of(this.mockMountPoint));
138     }
139
140     /**
141      * {@link ParserIdentifier#toInstanceIdentifier(String, SchemaContext)} tests.
142      */
143
144     /**
145      * Positive test of creating <code>InstanceIdentifierContext</code> from identifier when all nodes are defined
146      * in one module.
147      */
148     @Test
149     public void toInstanceIdentifierTest() {
150         final InstanceIdentifierContext<?> context = ParserIdentifier.toInstanceIdentifier(
151                 TEST_IDENT, SCHEMA_CONTEXT, Optional.empty());
152
153         assertEquals("Returned not expected identifier",
154                 TEST_IDENT_RESULT, context .getInstanceIdentifier().toString());
155     }
156
157     /**
158      * Positive test of creating <code>InstanceIdentifierContext</code> from identifier when nodes are defined in
159      * multiple modules.
160      */
161     @Test
162     public void toInstanceIdentifierOtherModulesTest() {
163         final InstanceIdentifierContext<?> context = ParserIdentifier.toInstanceIdentifier(
164                 TEST_IDENT_OTHERS, SCHEMA_CONTEXT, Optional.empty());
165
166         assertEquals("Returned not expected identifier",
167                 TEST_IDENT_OTHERS_RESULT, context.getInstanceIdentifier().toString());
168     }
169
170     /**
171      * Positive test of creating <code>InstanceIdentifierContext</code> from identifier containing
172      * {@link RestconfConstants#MOUNT}.
173      */
174     @Test
175     public void toInstanceIdentifierMountPointTest() {
176         final InstanceIdentifierContext<?> context = ParserIdentifier.toInstanceIdentifier(
177                 MOUNT_POINT_IDENT + "/" + TEST_IDENT, SCHEMA_CONTEXT, Optional.of(this.mountPointService));
178
179         assertEquals("Returned not expected identifier",
180                 TEST_IDENT_RESULT.toString(), context.getInstanceIdentifier().toString());
181
182         assertEquals("Mount point not found",
183                 this.mountPoint, context.getMountPoint());
184
185         assertEquals("Schema context from mount point expected",
186                 SCHEMA_CONTEXT_ON_MOUNT_POINT, context.getSchemaContext());
187     }
188
189     /**
190      * Test of creating <code>InstanceIdentifierContext</code> when identifier is <code>null</code>.
191      * <code>{@link YangInstanceIdentifier#empty()}</code> should be returned.
192      */
193     @Test
194     public void toInstanceIdentifierNullIdentifierTest() {
195         final InstanceIdentifierContext<?> context = ParserIdentifier.toInstanceIdentifier(
196                 null, SCHEMA_CONTEXT, Optional.empty());
197         assertEquals("Returned not expected identifier",
198                 YangInstanceIdentifier.empty(), context.getInstanceIdentifier());
199     }
200
201     /**
202      * Negative test of creating <code>InstanceIdentifierContext</code> when <code>SchemaContext</code> is
203      * <code>null</code>. Test fails expecting <code>NullPointerException</code>.
204      */
205     @Test
206     public void toInstanceIdentifierNullSchemaContextNegativeTest() {
207         assertThrows(NullPointerException.class,
208             () -> ParserIdentifier.toInstanceIdentifier(TEST_IDENT, null, Optional.empty()));
209     }
210
211     /**
212      * Api path can be empty. <code>YangInstanceIdentifier.EMPTY</code> is expected to be returned.
213      */
214     @Test
215     public void toInstanceIdentifierEmptyIdentifierTest() {
216         final InstanceIdentifierContext<?> context = ParserIdentifier.toInstanceIdentifier(
217                 "", SCHEMA_CONTEXT, Optional.empty());
218         assertEquals("Returned not expected identifier",
219                 YangInstanceIdentifier.empty(), context.getInstanceIdentifier());
220     }
221
222     /**
223      * Negative test with invalid test identifier. Test should fail with <code>RestconfDocumentedException</code>.
224      */
225     @Test
226     public void toInstanceIdentifierInvalidIdentifierNegativeTest() {
227         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
228             () -> ParserIdentifier.toInstanceIdentifier(INVALID_TEST_IDENT, SCHEMA_CONTEXT, Optional.empty()));
229     }
230
231     /**
232      * Negative test when identifier contains {@link RestconfConstants#MOUNT} but identifier part is not valid. Test
233      * should fail with <code>RestconfDocumentedException</code>.
234      */
235     @Test
236     public void toInstanceIdentifierMountPointInvalidIdentifierNegativeTest() {
237         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
238             () -> ParserIdentifier.toInstanceIdentifier(INVALID_MOUNT_POINT_IDENT, SCHEMA_CONTEXT,
239                 Optional.of(this.mountPointService)));
240     }
241
242     /**
243      * Negative test when <code>DOMMountPoint</code> cannot be found. Test is expected to fail with
244      * <code>RestconfDocumentedException</code> error type, error tag and error status code are
245      * compared to expected values.
246      */
247     @Test
248     public void toInstanceIdentifierMissingMountPointNegativeTest() {
249         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
250             () -> ParserIdentifier.toInstanceIdentifier("/yang-ext:mount", SCHEMA_CONTEXT,
251                 Optional.of(this.mountPointService)));
252         assertEquals("Not expected error type", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
253         assertEquals("Not expected error tag", ErrorTag.RESOURCE_DENIED_TRANSPORT, ex.getErrors().get(0).getErrorTag());
254     }
255
256     /**
257      * Negative test when <code>{@link DOMMountPointService}</code> is absent. Test is expected to fail with
258      * <code>RestconfDocumentedException</code> error type, error tag and error status code are
259      * compared to expected values.
260      */
261     @Test
262     public void toInstanceIdentifierMissingMountPointServiceNegativeTest() {
263         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
264             () -> ParserIdentifier.toInstanceIdentifier("yang-ext:mount", SCHEMA_CONTEXT, Optional.empty()));
265         assertEquals("Not expected error type", ErrorType.APPLICATION, ex.getErrors().get(0).getErrorType());
266         assertEquals("Not expected error tag", ErrorTag.OPERATION_FAILED, ex.getErrors().get(0).getErrorTag());
267         assertEquals("Not expected error status code", 500, ex.getErrors().get(0).getErrorTag().getStatusCode());
268     }
269
270     /**
271      * {@link ParserIdentifier#makeQNameFromIdentifier(String)} tests.
272      */
273
274     /**
275      * Positive test of making <code>QName</code> from identifier and compare values from returned <code>QName</code>
276      * to expected values.
277      */
278     @Test
279     public void makeQNameFromIdentifierTest() {
280         final Entry<String, Revision> qName = ParserIdentifier.makeQNameFromIdentifier(
281             TEST_MODULE_NAME + "/" + TEST_MODULE_REVISION);
282
283         assertNotNull("QName should be created", qName);
284         assertEquals("Returned not expected module name", TEST_MODULE_NAME, qName.getKey());
285         assertEquals("Returned not expected module revision", Revision.of(TEST_MODULE_REVISION), qName.getValue());
286     }
287
288     /**
289      * Negative test when supplied identifier is in invalid format and then revision is not parsable.
290      * <code>RestconfDocumentedException</code> is expected and error type, error tag and error status code are
291      * compared to expected values.
292      */
293     @Test
294     public void makeQNameFromIdentifierInvalidIdentifierNegativeTest() {
295         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
296             () -> ParserIdentifier.makeQNameFromIdentifier(TEST_MODULE_REVISION + "/" + TEST_MODULE_NAME));
297         assertEquals("Not expected error type", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
298         assertEquals("Not expected error tag", RestconfError.ErrorTag.INVALID_VALUE,
299             ex.getErrors().get(0).getErrorTag());
300         assertEquals("Not expected error status code", 400, ex.getErrors().get(0).getErrorTag().getStatusCode());
301     }
302
303     /**
304      * Negative test when supplied identifier is too short (contains only module name).
305      * <code>RestconfDocumentedException</code> is expected and error type, error tag and error status code are
306      * compared to expected values.
307      */
308     @Test
309     public void makeQNameFromIdentifierTooShortIdentifierNegativeTest() {
310         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
311             () -> ParserIdentifier.makeQNameFromIdentifier(TEST_MODULE_NAME));
312         assertEquals("Not expected error type", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
313         assertEquals("Not expected error tag", RestconfError.ErrorTag.INVALID_VALUE,
314             ex.getErrors().get(0).getErrorTag());
315         assertEquals("Not expected error status code", 400, ex.getErrors().get(0).getErrorTag().getStatusCode());
316     }
317
318     /**
319      * Positive test of making <code>QName</code> from identifier for module behind mount point. Value from returned
320      * <code>QName</code> are compared to expected values.
321      */
322     @Test
323     public void makeQNameFromIdentifierMountTest() {
324         final Entry<String, Revision> qName = ParserIdentifier.makeQNameFromIdentifier(
325                 MOUNT_POINT_IDENT
326                 + "/"
327                 + TEST_MODULE_NAME
328                 + "/"
329                 + TEST_MODULE_REVISION);
330
331         assertNotNull("QName should be created", qName);
332         assertEquals("Returned not expected module name", TEST_MODULE_NAME, qName.getKey());
333         assertEquals("Returned not expected module revision", Revision.of(TEST_MODULE_REVISION), qName.getValue());
334     }
335
336     /**
337      * Negative test when supplied identifier for module behind mount point is in invalid format and then revision is
338      * not parsable. <code>RestconfDocumentedException</code> is expected and error type, error tag and error status
339      * code are compared to expected values.
340      */
341     @Test
342     public void makeQNameFromIdentifierMountPointInvalidIdentifierNegativeTest() {
343         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
344             () -> ParserIdentifier.makeQNameFromIdentifier(
345                     MOUNT_POINT_IDENT + "/" + TEST_MODULE_REVISION + "/" + TEST_MODULE_NAME));
346         assertEquals("Not expected error type", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
347         assertEquals("Not expected error tag", RestconfError.ErrorTag.INVALID_VALUE,
348             ex.getErrors().get(0).getErrorTag());
349         assertEquals("Not expected error status code", 400, ex.getErrors().get(0).getErrorTag().getStatusCode());
350     }
351
352     /**
353      * Negative test when supplied identifier for module behind mount point is too short (contains only module name).
354      * <code>RestconfDocumentedException</code> is expected and error type, error tag and error status code
355      * are compared to expected values.
356      */
357     @Test
358     public void makeQNameFromIdentifierMountPointTooShortIdentifierNegativeTest() {
359         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
360             () -> ParserIdentifier.makeQNameFromIdentifier(MOUNT_POINT_IDENT + "/" + TEST_MODULE_NAME));
361         assertEquals("Not expected error type", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
362         assertEquals("Not expected error tag", RestconfError.ErrorTag.INVALID_VALUE,
363             ex.getErrors().get(0).getErrorTag());
364         assertEquals("Not expected error status code", 400, ex.getErrors().get(0).getErrorTag().getStatusCode());
365     }
366
367     /**
368      * Negative test trying to make <code>QName</code> from <code>null</code> identifier. Test is expected to fail with
369      * <code>NullPointerException</code>.
370      */
371     @Test
372     public void makeQNameFromIdentifierNullIdentifierNegativeTest() {
373         assertThrows(NullPointerException.class, () -> ParserIdentifier.makeQNameFromIdentifier(null));
374     }
375
376     /**
377      * Negative test trying to make <code>QName</code> from empty identifier. Test is expected to fail with
378      * <code>RestconfDocumentedException</code>. Error type, error tag and error status code is compared to expected
379      * values.
380      */
381     @Test
382     public void makeQNameFromIdentifierEmptyIdentifierNegativeTest() {
383         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
384             () -> ParserIdentifier.makeQNameFromIdentifier(""));
385         assertEquals("Not expected error type", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
386         assertEquals("Not expected error tag", RestconfError.ErrorTag.INVALID_VALUE,
387             ex.getErrors().get(0).getErrorTag());
388         assertEquals("Not expected error status code", 400, ex.getErrors().get(0).getErrorTag().getStatusCode());
389     }
390
391     /**
392      * Negative test with identifier containing double slash. Between // there is one empty string which will be
393      * incorrectly considered to be module revision. Test is expected to fail with
394      * <code>RestconfDocumentedException</code> and error type, error tag and error status code are compared to
395      * expected values.
396      */
397     @Test
398     public void makeQNameFromIdentifierDoubleSlashNegativeTest() {
399         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
400             () -> ParserIdentifier.makeQNameFromIdentifier(TEST_MODULE_NAME + "//" + TEST_MODULE_REVISION));
401         assertEquals("Not expected error type", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
402         assertEquals("Not expected error tag", RestconfError.ErrorTag.INVALID_VALUE,
403             ex.getErrors().get(0).getErrorTag());
404         assertEquals("Not expected error status code", 400, ex.getErrors().get(0).getErrorTag().getStatusCode());
405     }
406
407     /**
408      * {@link ParserIdentifier#toSchemaExportContextFromIdentifier(SchemaContext, String, DOMMountPointService)} tests.
409      */
410
411     /**
412      * Positive test of getting <code>SchemaExportContext</code>. Expected module name, revision and namespace are
413      * verified.
414      */
415     @Test
416     public void toSchemaExportContextFromIdentifierTest() {
417         final SchemaExportContext exportContext = ParserIdentifier.toSchemaExportContextFromIdentifier(
418                 SCHEMA_CONTEXT, TEST_MODULE_NAME + "/" + TEST_MODULE_REVISION, null, sourceProvider);
419
420         assertNotNull("Export context should be parsed", exportContext);
421
422         final Module module = exportContext.getModule();
423         assertNotNull("Export context should contains test module", module);
424
425         assertEquals("Returned not expected module name",
426                 TEST_MODULE_NAME, module.getName());
427         assertEquals("Returned not expected module revision",
428                 Revision.ofNullable(TEST_MODULE_REVISION), module.getRevision());
429         assertEquals("Returned not expected module namespace",
430                 TEST_MODULE_NAMESPACE, module.getNamespace().toString());
431     }
432
433     /**
434      * Test of getting <code>SchemaExportContext</code> when desired module is not found.
435      * <code>SchemaExportContext</code> should be created but module should be set to <code>null</code>.
436      */
437     @Test
438     public void toSchemaExportContextFromIdentifierNotFoundTest() {
439         final SchemaExportContext exportContext = ParserIdentifier.toSchemaExportContextFromIdentifier(
440                 SCHEMA_CONTEXT,
441                 "not-existing-module" + "/" + "2016-01-01",
442                 null, sourceProvider);
443
444         assertNotNull("Export context should be parsed", exportContext);
445         assertNull("Not-existing module should be null", exportContext.getModule());
446     }
447
448     /**
449      * Negative test trying to get <code>SchemaExportContext</code> with invalid identifier. Test is expected to fail
450      * with <code>RestconfDocumentedException</code> error type, error tag and error status code are compared to
451      * expected values.
452      */
453     @Test
454     public void toSchemaExportContextFromIdentifierInvalidIdentifierNegativeTest() {
455         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
456             () -> ParserIdentifier.toSchemaExportContextFromIdentifier(
457                     SCHEMA_CONTEXT, TEST_MODULE_REVISION + "/" + TEST_MODULE_NAME, null, sourceProvider));
458         assertEquals("Not expected error type", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
459         assertEquals("Not expected error tag", RestconfError.ErrorTag.INVALID_VALUE,
460             ex.getErrors().get(0).getErrorTag());
461         assertEquals("Not expected error status code", 400, ex.getErrors().get(0).getErrorTag().getStatusCode());
462     }
463
464     /**
465      * Positive test of getting <code>SchemaExportContext</code> for module behind mount point.
466      * Expected module name, revision and namespace are verified.
467      */
468     @Test
469     public void toSchemaExportContextFromIdentifierMountPointTest() {
470         final SchemaExportContext exportContext = ParserIdentifier.toSchemaExportContextFromIdentifier(
471                 SCHEMA_CONTEXT,
472                 MOUNT_POINT_IDENT + "/" + TEST_MODULE_NAME + "/" + TEST_MODULE_REVISION,
473                 this.mountPointService, sourceProvider);
474
475         final Module module = exportContext.getModule();
476         assertNotNull("Export context should contains test module", module);
477
478         assertEquals("Returned not expected module name",
479                 TEST_MODULE_NAME, module.getName());
480         assertEquals("Returned not expected module revision",
481                 Revision.ofNullable(TEST_MODULE_REVISION), module.getRevision());
482         assertEquals("Returned not expected module namespace",
483                 TEST_MODULE_NAMESPACE, module.getNamespace().toString());
484     }
485
486     /**
487      * Negative test of getting <code>SchemaExportContext</code> when desired module is not found behind mount point.
488      * <code>SchemaExportContext</code> should be still created but module should be set to <code>null</code>.
489      */
490     @Test
491     public void toSchemaExportContextFromIdentifierMountPointNotFoundTest() {
492         final SchemaExportContext exportContext = ParserIdentifier.toSchemaExportContextFromIdentifier(
493                 SCHEMA_CONTEXT,
494                 MOUNT_POINT_IDENT + "/" + "not-existing-module" + "/" + "2016-01-01",
495                 this.mountPointService, sourceProvider);
496
497         assertNotNull("Export context should be parsed", exportContext);
498         assertNull("Not-existing module should be null", exportContext.getModule());
499     }
500
501     /**
502      * Negative test trying to get <code>SchemaExportContext</code> behind mount point with invalid identifier. Test is
503      * expected to fail with <code>RestconfDocumentedException</code> error type, error tag and error status code are
504      * compared to expected values.
505      */
506     @Test
507     public void toSchemaExportContextFromIdentifierMountPointInvalidIdentifierNegativeTest() {
508         RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
509             () -> ParserIdentifier.toSchemaExportContextFromIdentifier(SCHEMA_CONTEXT,
510                 MOUNT_POINT_IDENT + "/" + TEST_MODULE_REVISION + "/" + TEST_MODULE_NAME, this.mountPointService,
511                 sourceProvider));
512
513         assertEquals("Not expected error type", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
514         assertEquals("Not expected error tag", RestconfError.ErrorTag.INVALID_VALUE,
515             ex.getErrors().get(0).getErrorTag());
516         assertEquals("Not expected error status code", 400, ex.getErrors().get(0).getErrorTag().getStatusCode());
517     }
518
519     /**
520      * Negative test of getting <code>SchemaExportContext</code> when supplied identifier is null.
521      * <code>NullPointerException</code> is expected. <code>DOMMountPointService</code> is not used.
522      */
523     @Test
524     public void toSchemaExportContextFromIdentifierNullIdentifierNegativeTest() {
525         assertThrows(NullPointerException.class,
526             () -> ParserIdentifier.toSchemaExportContextFromIdentifier(SCHEMA_CONTEXT, null, null, sourceProvider));
527     }
528
529     /**
530      * Negative test of of getting <code>SchemaExportContext</code> when supplied <code>SchemaContext</code> is
531      * <code>null</code>. Test is expected to fail with <code>NullPointerException</code>.
532      */
533     @Test
534     public void toSchemaExportContextFromIdentifierNullSchemaContextNegativeTest() {
535         assertThrows(NullPointerException.class, () -> ParserIdentifier.toSchemaExportContextFromIdentifier(null,
536             TEST_MODULE_NAME + "/" + TEST_MODULE_REVISION, null, sourceProvider));
537     }
538
539     /**
540      * Negative test of of getting <code>SchemaExportContext</code> when supplied <code>SchemaContext</code> is
541      * <code>null</code> and identifier specifies module behind mount point. Test is expected to fail with
542      * <code>NullPointerException</code>.
543      */
544     @Test
545     public void toSchemaExportContextFromIdentifierMountPointNullSchemaContextNegativeTest() {
546         assertThrows(NullPointerException.class, () -> ParserIdentifier.toSchemaExportContextFromIdentifier(null,
547             MOUNT_POINT_IDENT + "/" + TEST_MODULE_NAME + "/" + TEST_MODULE_REVISION, this.mountPointService,
548             sourceProvider));
549     }
550
551     /**
552      * Negative test of of getting <code>SchemaExportContext</code> when supplied <code>DOMMountPointService</code>
553      * is <code>null</code> and identifier defines module behind mount point. Test is expected to fail with
554      * <code>NullPointerException</code>.
555      */
556     @Test
557     public void toSchemaExportContextFromIdentifierNullMountPointServiceNegativeTest() {
558         assertThrows(NullPointerException.class, () -> ParserIdentifier.toSchemaExportContextFromIdentifier(
559             SCHEMA_CONTEXT, MOUNT_POINT_IDENT + "/" + TEST_MODULE_NAME + "/" + TEST_MODULE_REVISION, null,
560             sourceProvider));
561     }
562
563     @Test
564     public void toSchemaExportContextFromIdentifierNullSchemaContextBehindMountPointNegativeTest() {
565         assertThrows(IllegalStateException.class, () -> ParserIdentifier.toSchemaExportContextFromIdentifier(
566                 SCHEMA_CONTEXT, "/yang-ext:mount/" + TEST_MODULE_NAME + "/" + TEST_MODULE_REVISION,
567                 this.mockMountPointService, sourceProvider));
568     }
569
570     /**
571      * Test invoke RPC.
572      *
573      * <p>
574      * Verify if RPC schema node was found.
575      */
576     @Test
577     public void invokeRpcTest() {
578         final InstanceIdentifierContext<?> result = ParserIdentifier.toInstanceIdentifier(
579                 INVOKE_RPC, SCHEMA_CONTEXT, Optional.empty());
580
581         // RPC schema node
582         final QName rpcQName = result.getSchemaNode().getQName();
583         assertEquals("invoke:rpc:module", rpcQName.getModule().getNamespace().toString());
584         assertEquals("rpc-test", rpcQName.getLocalName());
585
586         // other fields
587         assertEquals(IdentifierCodec.deserialize(INVOKE_RPC, SCHEMA_CONTEXT), result.getInstanceIdentifier());
588         assertEquals(null, result.getMountPoint());
589         assertEquals(SCHEMA_CONTEXT, result.getSchemaContext());
590     }
591
592     /**
593      * Test invoke RPC on mount point.
594      *
595      * <p>
596      * Verify if RPC schema node was found.
597      */
598     @Test
599     public void invokeRpcOnMountPointTest() {
600         final InstanceIdentifierContext<?> result = ParserIdentifier.toInstanceIdentifier(
601                 MOUNT_POINT_IDENT + "/" + INVOKE_RPC, SCHEMA_CONTEXT, Optional.of(this.mountPointService));
602
603         // RPC schema node
604         final QName rpcQName = result.getSchemaNode().getQName();
605         assertEquals("invoke:rpc:module", rpcQName.getModule().getNamespace().toString());
606         assertEquals("rpc-test", rpcQName.getLocalName());
607
608         // other fields
609         assertEquals(IdentifierCodec.deserialize(INVOKE_RPC, SCHEMA_CONTEXT), result.getInstanceIdentifier());
610         assertEquals(this.mountPoint, result.getMountPoint());
611         assertEquals(SCHEMA_CONTEXT_ON_MOUNT_POINT, result.getSchemaContext());
612     }
613
614     /**
615      * Test Action.
616      * Verify if Action schema node was found.
617      */
618     @Test
619     public void invokeActionTest() {
620         final InstanceIdentifierContext<?> result = ParserIdentifier
621             .toInstanceIdentifier(INVOKE_ACTION, SCHEMA_CONTEXT, Optional.empty());
622
623         // Action schema node
624         final QName actionQName = result.getSchemaNode().getQName();
625         assertEquals("https://example.com/ns/example-actions", actionQName.getModule().getNamespace().toString());
626         assertEquals("reset", actionQName.getLocalName());
627
628         // other fields
629         assertEquals(IdentifierCodec.deserialize(INVOKE_ACTION, SCHEMA_CONTEXT), result.getInstanceIdentifier());
630         assertNull(result.getMountPoint());
631         assertSame(SCHEMA_CONTEXT, result.getSchemaContext());
632     }
633
634     /**
635      * Test invoke Action on mount point.
636      * Verify if Action schema node was found.
637      */
638     @Test
639     public void invokeActionOnMountPointTest() {
640         final InstanceIdentifierContext<?> result = ParserIdentifier
641             .toInstanceIdentifier(MOUNT_POINT_IDENT + "/" + INVOKE_ACTION, SCHEMA_CONTEXT,
642                 Optional.of(this.mountPointService));
643
644         // Action schema node
645         final QName actionQName = result.getSchemaNode().getQName();
646         assertEquals("https://example.com/ns/example-actions", actionQName.getModule().getNamespace().toString());
647         assertEquals("reset", actionQName.getLocalName());
648
649         // other fields
650         assertEquals(IdentifierCodec.deserialize(INVOKE_ACTION, SCHEMA_CONTEXT), result.getInstanceIdentifier());
651         assertEquals(this.mountPoint, result.getMountPoint());
652         assertEquals(SCHEMA_CONTEXT_ON_MOUNT_POINT, result.getSchemaContext());
653     }
654 }