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.utils.parser;
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;
17 import com.google.common.base.Optional;
18 import com.google.common.collect.ImmutableClassToInstanceMap;
19 import com.google.common.collect.Maps;
20 import org.junit.Before;
21 import org.junit.Rule;
22 import org.junit.Test;
23 import org.junit.rules.ExpectedException;
24 import org.mockito.Mock;
25 import org.mockito.MockitoAnnotations;
26 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
27 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
28 import org.opendaylight.controller.md.sal.dom.broker.impl.mount.DOMMountPointServiceImpl;
29 import org.opendaylight.controller.md.sal.dom.broker.spi.mount.SimpleDOMMountPoint;
30 import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
31 import org.opendaylight.netconf.md.sal.rest.schema.SchemaExportContext;
32 import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
33 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
34 import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
35 import org.opendaylight.restconf.utils.RestconfConstants;
36 import org.opendaylight.yangtools.yang.common.QName;
37 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
38 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
39 import org.opendaylight.yangtools.yang.model.api.Module;
40 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
43 * Unit tests for {@link ParserIdentifier}
45 public class ParserIdentifierTest {
46 // mount point identifier + expected result
47 private static final String MOUNT_POINT_IDENT =
48 "mount-point:mount-container/point-number" + "/" + RestconfConstants.MOUNT;
50 private static final String MOUNT_POINT_IDENT_RESULT =
51 "/(mount:point?revision=2016-06-02)mount-container/point-number";
53 // invalid mount point identifier
54 private static final String INVALID_MOUNT_POINT_IDENT =
55 "mount-point:point-number" + "/" + RestconfConstants.MOUNT;
57 // test identifier + expected result
58 private static final String TEST_IDENT =
59 "parser-identifier:cont1/cont2/listTest/list-in-grouping=name/leaf-A.B";
61 private static final String TEST_IDENT_RESULT =
62 "/(parser:identifier?revision=2016-06-02)cont1/cont2/listTest/listTest/list-in-grouping/"
63 + "list-in-grouping[{(parser:identifier?revision=2016-06-02)name=name}]/leaf-A.B";
65 // test identifier with nodes defined in other modules using augmentation + expected result
66 private static final String TEST_IDENT_OTHERS =
67 "parser-identifier-included:list-1=name,2016-06-02/parser-identifier:augment-leaf";
69 private static final String TEST_IDENT_OTHERS_RESULT =
70 "/(parser:identifier:included?revision=2016-06-02)list-1/list-1"
71 + "[{(parser:identifier:included?revision=2016-06-02)name=name, "
72 + "(parser:identifier:included?revision=2016-06-02)revision=2016-06-02}]"
73 + "/AugmentationIdentifier{childNames=[(parser:identifier?revision=2016-06-02)augment-leaf]}/"
74 + "(parser:identifier?revision=2016-06-02)augment-leaf";
76 // invalid test identifier
77 private static final String INVALID_TEST_IDENT =
78 "parser-identifier:cont2/listTest/list-in-grouping=name/leaf-A.B";
80 // schema context with test modules
81 private SchemaContext schemaContext;
83 private static final String TEST_MODULE_NAME = "test-module";
84 private static final String TEST_MODULE_REVISION = "2016-06-02";
85 private static final String TEST_MODULE_NAMESPACE = "test:module";
87 // mount point and mount point service
88 private DOMMountPoint mountPoint;
89 private DOMMountPointService mountPointService;
91 // mock mount point and mount point service
92 @Mock DOMMountPoint mockMountPoint;
93 @Mock DOMMountPointService mockMountPointService;
96 public final ExpectedException thrown = ExpectedException.none();
99 public void setup() throws Exception {
100 MockitoAnnotations.initMocks(this);
101 schemaContext = TestRestconfUtils.loadSchemaContext("/parser-identifier");
103 // create and register mount point
104 mountPoint = SimpleDOMMountPoint.create(
105 YangInstanceIdentifier.builder()
106 .node(QName.create("mount:point", "2016-06-02", "mount-container"))
107 .node(QName.create("mount:point", "2016-06-02", "point-number"))
109 ImmutableClassToInstanceMap.copyOf(Maps.newHashMap()),
113 mountPointService = new DOMMountPointServiceImpl();
114 ((DOMMountPointServiceImpl) mountPointService).registerMountPoint(mountPoint);
116 // register mount point with null schema context
117 when(mockMountPoint.getSchemaContext()).thenReturn(null);
118 when(mockMountPointService.getMountPoint(YangInstanceIdentifier.EMPTY)).thenReturn(Optional.of(mockMountPoint));
122 * {@link ParserIdentifier#toInstanceIdentifier(String, SchemaContext)} tests
126 * Positive test of creating <code>InstanceIdentifierContext</code> from identifier when all nodes are defined
130 public void toInstanceIdentifierTest() {
131 final InstanceIdentifierContext<?> context = ParserIdentifier.toInstanceIdentifier(
132 TEST_IDENT, schemaContext);
134 assertEquals("Returned not expected identifier",
135 TEST_IDENT_RESULT, context .getInstanceIdentifier().toString());
139 * Positive test of creating <code>InstanceIdentifierContext</code> from identifier when nodes are defined in
143 public void toInstanceIdentifierOtherModulesTest() {
144 final InstanceIdentifierContext<?> context = ParserIdentifier.toInstanceIdentifier(
145 TEST_IDENT_OTHERS, schemaContext);
147 assertEquals("Returned not expected identifier",
148 TEST_IDENT_OTHERS_RESULT, context.getInstanceIdentifier().toString());
152 * Positive test of creating <code>InstanceIdentifierContext</code> from identifier containing
153 * {@link RestconfConstants#MOUNT}.
156 public void toInstanceIdentifierMountPointTest() {
157 final InstanceIdentifierContext<?> context = ParserIdentifier.toInstanceIdentifier(
158 MOUNT_POINT_IDENT, schemaContext);
160 assertEquals("Returned not expected identifier",
161 MOUNT_POINT_IDENT_RESULT, context.getInstanceIdentifier().toString());
165 * Test of creating <code>InstanceIdentifierContext</code> when identifier is <code>null</code>.
166 * <code>{@link YangInstanceIdentifier#EMPTY}</code> should be returned.
169 public void toInstanceIdentifierNullIdentifierTest() {
170 final InstanceIdentifierContext<?> context = ParserIdentifier.toInstanceIdentifier(null, schemaContext);
171 assertEquals("Returned not expected identifier",
172 YangInstanceIdentifier.EMPTY, context.getInstanceIdentifier());
176 * Negative test of creating <code>InstanceIdentifierContext</code> when <code>SchemaContext</code> is
177 * <code>null</code>. Test fails expecting <code>NullPointerException</code>.
180 public void toInstanceIdentifierNullSchemaContextNegativeTest() {
181 thrown.expect(NullPointerException.class);
182 ParserIdentifier.toInstanceIdentifier(TEST_IDENT, null);
186 * Api path can be empty. <code>YangInstanceIdentifier.EMPTY</code> is expected to be returned.
189 public void toInstanceIdentifierEmptyIdentifierTest() {
190 final InstanceIdentifierContext<?> context = ParserIdentifier.toInstanceIdentifier("", schemaContext);
191 assertEquals("Returned not expected identifier",
192 YangInstanceIdentifier.EMPTY, context.getInstanceIdentifier());
196 * Api path can be empty. <code>YangInstanceIdentifier.EMPTY</code> is expected to be returned.
197 * Test when identifier contains {@link RestconfConstants#MOUNT}.
200 public void toInstanceIdentifierEmptyIdentifierMountPointTest() {
201 final InstanceIdentifierContext<?> context = ParserIdentifier.toInstanceIdentifier(
202 "" + "/" + RestconfConstants.MOUNT, schemaContext);
203 assertEquals("Returned not expected identifier",
204 YangInstanceIdentifier.EMPTY, context.getInstanceIdentifier());
208 * Negative test with invalid test identifier. Test should fail with <code>IllegalArgumentException</code>.
211 public void toInstanceIdentifierInvalidIdentifierNegativeTest() {
212 thrown.expect(IllegalArgumentException.class);
213 ParserIdentifier.toInstanceIdentifier(INVALID_TEST_IDENT, schemaContext);
217 * Negative test when identifier contains {@link RestconfConstants#MOUNT} but identifier part is not valid. Test
218 * should fail with <code>IllegalArgumentException</code>.
221 public void toInstanceIdentifierMountPointInvalidIdentifierNegativeTest() {
222 thrown.expect(IllegalArgumentException.class);
223 ParserIdentifier.toInstanceIdentifier(INVALID_MOUNT_POINT_IDENT, schemaContext);
227 * {@link ParserIdentifier#makeQNameFromIdentifier(String)} tests
231 * Positive test of making <code>QName</code> from identifier and compare values from returned <code>QName</code>
232 * to expected values.
235 public void makeQNameFromIdentifierTest() {
236 final QName qName = ParserIdentifier.makeQNameFromIdentifier(TEST_MODULE_NAME + "/" + TEST_MODULE_REVISION);
238 assertNotNull("QName should be created", qName);
239 assertEquals("Returned not expected module name",
240 TEST_MODULE_NAME, qName.getLocalName());
241 assertEquals("Returned not expected module revision",
242 TEST_MODULE_REVISION, qName.getFormattedRevision());
246 * Negative test when supplied identifier is in invalid format and then revision is not parsable.
247 * <code>RestconfDocumentedException</code> is expected and error type, error tag and error status code are
248 * compared to expected values.
251 public void makeQNameFromIdentifierInvalidIdentifierNegativeTest() {
253 ParserIdentifier.makeQNameFromIdentifier(TEST_MODULE_REVISION + "/" + TEST_MODULE_NAME);
254 fail("Test should fail due to invalid identifier format");
255 } catch (final RestconfDocumentedException e) {
256 assertEquals("Not expected error type",
257 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
258 assertEquals("Not expected error tag",
259 RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
260 assertEquals("Not expected error status code",
261 400, e.getErrors().get(0).getErrorTag().getStatusCode());
266 * Negative test when supplied identifier is too short (contains only module name).
267 * <code>RestconfDocumentedException</code> is expected and error type, error tag and error status code are
268 * compared to expected values.
271 public void makeQNameFromIdentifierTooShortIdentifierNegativeTest() {
273 ParserIdentifier.makeQNameFromIdentifier(TEST_MODULE_NAME);
274 fail("Test should fail due to too short identifier format");
275 } catch (final RestconfDocumentedException e) {
276 assertEquals("Not expected error type",
277 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
278 assertEquals("Not expected error tag",
279 RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
280 assertEquals("Not expected error status code",
281 400, e.getErrors().get(0).getErrorTag().getStatusCode());
286 * Positive test of making <code>QName</code> from identifier for module behind mount point. Value from returned
287 * <code>QName</code> are compared to expected values.
290 public void makeQNameFromIdentifierMountTest() {
291 final QName qName = ParserIdentifier.makeQNameFromIdentifier(
296 + TEST_MODULE_REVISION);
298 assertNotNull("QName should be created", qName);
299 assertEquals("Returned not expected module name",
300 TEST_MODULE_NAME, qName.getLocalName());
301 assertEquals("Returned not expected module revision",
302 TEST_MODULE_REVISION, qName.getFormattedRevision());
306 * Negative test when supplied identifier for module behind mount point is in invalid format and then revision is
307 * not parsable. <code>RestconfDocumentedException</code> is expected and error type, error tag and error status
308 * code are compared to expected values.
311 public void makeQNameFromIdentifierMountPointInvalidIdentifierNegativeTest() {
313 ParserIdentifier.makeQNameFromIdentifier(
316 + TEST_MODULE_REVISION
320 fail("Test should fail due to invalid identifier format");
321 } catch (final RestconfDocumentedException e) {
322 assertEquals("Not expected error type",
323 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
324 assertEquals("Not expected error tag",
325 RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
326 assertEquals("Not expected error status code",
327 400, e.getErrors().get(0).getErrorTag().getStatusCode());
332 * Negative test when supplied identifier for module behind mount point is too short (contains only module name).
333 * <code>RestconfDocumentedException</code> is expected and error type, error tag and error status code
334 * are compared to expected values.
337 public void makeQNameFromIdentifierMountPointTooShortIdentifierNegativeTest() {
339 ParserIdentifier.makeQNameFromIdentifier(
344 fail("Test should fail due to too short identifier format");
345 } catch (final RestconfDocumentedException e) {
346 assertEquals("Not expected error type",
347 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
348 assertEquals("Not expected error tag",
349 RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
350 assertEquals("Not expected error status code",
351 400, e.getErrors().get(0).getErrorTag().getStatusCode());
356 * Negative test trying to make <code>QName</code> from <code>null</code> identifier. Test is expected to fail with
357 * <code>NullPointerException</code>.
360 public void makeQNameFromIdentifierNullIdentifierNegativeTest() {
361 thrown.expect(NullPointerException.class);
362 ParserIdentifier.makeQNameFromIdentifier(null);
366 * Negative test trying to make <code>QName</code> from empty identifier. Test is expected to fail with
367 * <code>RestconfDocumentedException</code>. Error type, error tag and error status code is compared to expected
371 public void makeQNameFromIdentifierEmptyIdentifierNegativeTest() {
373 ParserIdentifier.makeQNameFromIdentifier("");
374 fail("Test should fail due to empty identifier");
375 } catch (final RestconfDocumentedException e) {
376 assertEquals("Not expected error type",
377 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
378 assertEquals("Not expected error tag",
379 RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
380 assertEquals("Not expected error status code",
381 400, e.getErrors().get(0).getErrorTag().getStatusCode());
386 * Negative test with identifier containing double slash. Between // there is one empty string which will be
387 * incorrectly considered to be module revision. Test is expected to fail with
388 * <code>RestconfDocumentedException</code> and error type, error tag and error status code are compared to
392 public void makeQNameFromIdentifierDoubleSlashNegativeTest() {
394 ParserIdentifier.makeQNameFromIdentifier(TEST_MODULE_NAME + "//" + TEST_MODULE_REVISION);
395 fail("Test should fail due to identifier containing double slash");
396 } catch (final RestconfDocumentedException e) {
397 assertEquals("Not expected error type",
398 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
399 assertEquals("Not expected error tag",
400 RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
401 assertEquals("Not expected error status code",
402 400, e.getErrors().get(0).getErrorTag().getStatusCode());
407 * {@link ParserIdentifier#toSchemaExportContextFromIdentifier(SchemaContext, String, DOMMountPointService)} tests
411 * Positive test of getting <code>SchemaExportContext</code>. Expected module name, revision and namespace are
415 public void toSchemaExportContextFromIdentifierTest() {
416 final SchemaExportContext exportContext = ParserIdentifier.
417 toSchemaExportContextFromIdentifier(schemaContext, TEST_MODULE_NAME + "/" + TEST_MODULE_REVISION, null);
419 assertNotNull("Export context should be parsed", exportContext);
421 final Module module = exportContext.getModule();
422 assertNotNull("Export context should contains test module", module);
424 assertEquals("Returned not expected module name",
425 TEST_MODULE_NAME, module.getName());
426 assertEquals("Returned not expected module revision",
427 TEST_MODULE_REVISION, SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision()));
428 assertEquals("Returned not expected module namespace",
429 TEST_MODULE_NAMESPACE, module.getNamespace().toString());
433 * Test of getting <code>SchemaExportContext</code> when desired module is not found.
434 * <code>SchemaExportContext</code> should be created but module should be set to <code>null</code>.
437 public void toSchemaExportContextFromIdentifierNotFoundTest() {
438 final SchemaExportContext exportContext = ParserIdentifier.toSchemaExportContextFromIdentifier(
440 "not-existing-module" + "/" + "2016-01-01",
443 assertNotNull("Export context should be parsed", exportContext);
444 assertNull("Not-existing module should be null", exportContext.getModule());
448 * Negative test trying to get <code>SchemaExportContext</code> with invalid identifier. Test is expected to fail
449 * with <code>RestconfDocumentedException</code> error type, error tag and error status code are compared to
453 public void toSchemaExportContextFromIdentifierInvalidIdentifierNegativeTest() {
455 ParserIdentifier.toSchemaExportContextFromIdentifier(
456 schemaContext, TEST_MODULE_REVISION + "/" + TEST_MODULE_NAME, null);
457 fail("Test should fail due to invalid identifier supplied");
458 } catch (final RestconfDocumentedException e) {
459 assertEquals("Not expected error type",
460 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
461 assertEquals("Not expected error tag",
462 RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
463 assertEquals("Not expected error status code",
464 400, e.getErrors().get(0).getErrorTag().getStatusCode());
469 * Positive test of getting <code>SchemaExportContext</code> for module behind mount point.
470 * Expected module name, revision and namespace are verified.
473 public void toSchemaExportContextFromIdentifierMountPointTest() {
474 final SchemaExportContext exportContext = ParserIdentifier.toSchemaExportContextFromIdentifier(
476 MOUNT_POINT_IDENT + "/" + TEST_MODULE_NAME + "/" + TEST_MODULE_REVISION,
479 final Module module = exportContext.getModule();
480 assertNotNull("Export context should contains test module", module);
482 assertEquals("Returned not expected module name",
483 TEST_MODULE_NAME, module.getName());
484 assertEquals("Returned not expected module revision",
485 TEST_MODULE_REVISION, SimpleDateFormatUtil.getRevisionFormat().format(module.getRevision()));
486 assertEquals("Returned not expected module namespace",
487 TEST_MODULE_NAMESPACE, module.getNamespace().toString());
491 * Negative test of getting <code>SchemaExportContext</code> when desired module is not found behind mount point.
492 * <code>SchemaExportContext</code> should be still created but module should be set to <code>null</code>.
495 public void toSchemaExportContextFromIdentifierMountPointNotFoundTest() {
496 final SchemaExportContext exportContext = ParserIdentifier.toSchemaExportContextFromIdentifier(
498 MOUNT_POINT_IDENT + "/" + "not-existing-module" + "/" + "2016-01-01",
501 assertNotNull("Export context should be parsed", exportContext);
502 assertNull("Not-existing module should be null", exportContext.getModule());
506 * Negative test trying to get <code>SchemaExportContext</code> behind mount point with invalid identifier. Test is
507 * expected to fail with <code>RestconfDocumentedException</code> error type, error tag and error status code are
508 * compared to expected values.
511 public void toSchemaExportContextFromIdentifierMountPointInvalidIdentifierNegativeTest() {
513 ParserIdentifier.toSchemaExportContextFromIdentifier(
515 MOUNT_POINT_IDENT + "/" + TEST_MODULE_REVISION + "/" + TEST_MODULE_NAME,
518 fail("Test should fail due to invalid identifier supplied");
519 } catch (final RestconfDocumentedException e) {
520 assertEquals("Not expected error type",
521 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
522 assertEquals("Not expected error tag",
523 RestconfError.ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
524 assertEquals("Not expected error status code",
525 400, e.getErrors().get(0).getErrorTag().getStatusCode());
530 * Negative test of getting <code>SchemaExportContext</code> when supplied identifier is null.
531 * <code>NullPointerException</code> is expected. <code>DOMMountPointService</code> is not used.
534 public void toSchemaExportContextFromIdentifierNullIdentifierNegativeTest() {
535 thrown.expect(NullPointerException.class);
536 ParserIdentifier.toSchemaExportContextFromIdentifier(schemaContext, null, null);
540 * Negative test of of getting <code>SchemaExportContext</code> when supplied <code>SchemaContext</code> is
541 * <code>null</code>. Test is expected to fail with <code>NullPointerException</code>.
544 public void toSchemaExportContextFromIdentifierNullSchemaContextNegativeTest() {
545 thrown.expect(NullPointerException.class);
546 ParserIdentifier.toSchemaExportContextFromIdentifier(null, TEST_MODULE_NAME + "/" + TEST_MODULE_REVISION, null);
550 * Negative test of of getting <code>SchemaExportContext</code> when supplied <code>SchemaContext</code> is
551 * <code>null</code> and identifier specifies module behind mount point. Test is expected to fail with
552 * <code>NullPointerException</code>.
555 public void toSchemaExportContextFromIdentifierMountPointNullSchemaContextNegativeTest() {
556 thrown.expect(NullPointerException.class);
557 ParserIdentifier.toSchemaExportContextFromIdentifier(
563 + TEST_MODULE_REVISION,
568 * Negative test of of getting <code>SchemaExportContext</code> when supplied <code>DOMMountPointService</code>
569 * is <code>null</code> and identifier defines module behind mount point. Test is expected to fail with
570 * <code>NullPointerException</code>.
573 public void toSchemaExportContextFromIdentifierNullMountPointServiceNegativeTest() {
574 thrown.expect(NullPointerException.class);
575 ParserIdentifier.toSchemaExportContextFromIdentifier(
581 + TEST_MODULE_REVISION,
586 * Negative test of of getting <code>SchemaExportContext</code> when <code>SchemaContext</code> behind mount
587 * point is <code>null</code>. Test is expected to fail with <code>NullPointerException</code>.
590 public void toSchemaExportContextFromIdentifierNullSchemaContextBehindMountPointNegativeTest() {
591 thrown.expect(NullPointerException.class);
592 ParserIdentifier.toSchemaExportContextFromIdentifier(
595 + RestconfConstants.MOUNT
599 + TEST_MODULE_REVISION,
600 mockMountPointService);