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.parser.builder;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertTrue;
13 import static org.junit.Assert.fail;
14 import com.google.common.collect.Iterables;
15 import com.google.common.collect.Sets;
16 import java.util.Iterator;
17 import java.util.LinkedHashMap;
19 import org.junit.Before;
20 import org.junit.Rule;
21 import org.junit.Test;
22 import org.junit.rules.ExpectedException;
23 import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
24 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
25 import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
26 import org.opendaylight.yangtools.yang.common.QName;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
29 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
32 * Unit tests for {@link YangInstanceIdentifierDeserializer}
34 public class YangInstanceIdentifierDeserializerTest {
37 public ExpectedException thrown = ExpectedException.none();
40 private SchemaContext schemaContext;
43 public void init() throws Exception {
44 this.schemaContext = TestRestconfUtils.loadSchemaContext("/restconf/parser/deserializer");
48 * Test of deserialization <code>String</code> URI with container to
49 * <code>Iterable<YangInstanceIdentifier.PathArgument></code>.
52 public void deserializeContainerTest() {
53 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
54 .create(this.schemaContext, "deserializer-test:contA");
56 assertEquals("Result does not contains expected number of path arguments", 1, Iterables.size(result));
57 assertEquals("Not expected path argument",
58 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
59 result.iterator().next());
63 * Test of deserialization <code>String</code> URI with container containing leaf to
64 * <code>Iterable<YangInstanceIdentifier.PathArgument></code>.
67 public void deserializeContainerWithLeafTest() {
68 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
69 .create(this.schemaContext, "deserializer-test:contA/leaf-A");
71 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
73 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
74 assertEquals("Not expected path argument",
75 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
77 assertEquals("Not expected path argument",
78 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "leaf-A")),
83 * Test of deserialization <code>String</code> URI with container containing list with leaf list to
84 * <code>Iterable<YangInstanceIdentifier.PathArgument></code>.
87 public void deserializeContainerWithListWithLeafListTest() {
88 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
89 .create(this.schemaContext, "deserializer-test:contA/list-A=100/leaf-list-AA=instance");
91 assertEquals("Result does not contains expected number of path arguments", 5, Iterables.size(result));
93 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
96 assertEquals("Not expected path argument",
97 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
101 final QName list = QName.create("deserializer:test", "2016-06-06", "list-A");
102 assertEquals("Not expected path argument",
103 YangInstanceIdentifier.NodeIdentifier.create(list),
105 assertEquals("Not expected path argument",
106 new YangInstanceIdentifier.NodeIdentifierWithPredicates(
107 list, QName.create(list, "list-key"), 100).toString(),
108 iterator.next().toString());
111 final QName leafList = QName.create("deserializer:test", "2016-06-06", "leaf-list-AA");
112 assertEquals("Not expected path argument",
113 YangInstanceIdentifier.NodeIdentifier.create(leafList),
115 assertEquals("Not expected path argument",
116 new YangInstanceIdentifier.NodeWithValue(leafList, "instance"),
121 * Test of deserialization <code>String</code> URI containing list with no keys to
122 * <code>Iterable<YangInstanceIdentifier.PathArgument></code>.
125 public void deserializeListWithNoKeysTest() {
126 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
127 .create(this.schemaContext, "deserializer-test:list-no-key");
129 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
131 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
132 final QName list = QName.create("deserializer:test", "2016-06-06", "list-no-key");
134 assertEquals("Not expected path argument",
135 YangInstanceIdentifier.NodeIdentifier.create(list),
137 assertEquals("Not expected path argument",
138 YangInstanceIdentifier.NodeIdentifier.create(list),
143 * Test of deserialization <code>String</code> URI containing list with one key to
144 * <code>Iterable<YangInstanceIdentifier.PathArgument></code>.
147 public void deserializeListWithOneKeyTest() {
148 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
149 .create(this.schemaContext, "deserializer-test:list-one-key=value");
151 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
153 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
154 final QName list = QName.create("deserializer:test", "2016-06-06", "list-one-key");
156 assertEquals("Not expected path argument",
157 YangInstanceIdentifier.NodeIdentifier.create(list),
159 assertEquals("Not expected path argument",
160 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, QName.create(list, "name"), "value"),
165 * Test of deserialization <code>String</code> URI containing list with multiple keys to
166 * <code>Iterable<YangInstanceIdentifier.PathArgument></code>.
169 public void deserializeListWithMultipleKeysTest() {
170 final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
171 final Map<QName, Object> values = new LinkedHashMap<>();
172 values.put(QName.create(list, "name"), "value");
173 values.put(QName.create(list, "number"), 100);
174 values.put(QName.create(list, "enabled"), false);
176 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
177 .create(this.schemaContext, "deserializer-test:list-multiple-keys=value,100,false");
179 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
181 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
183 assertEquals("Not expected path argument",
184 YangInstanceIdentifier.NodeIdentifier.create(list),
186 assertEquals("Not expected path argument",
187 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, values).toString(),
188 iterator.next().toString());
192 * Test of deserialization <code>String</code> URI containing leaf list to
193 * <code>Iterable<YangInstanceIdentifier.PathArgument></code>.
196 public void deserializeLeafListTest() {
197 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
198 .create(this.schemaContext, "deserializer-test:leaf-list-0=true");
200 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
202 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
203 final QName leafList = QName.create("deserializer:test", "2016-06-06", "leaf-list-0");
205 assertEquals("Not expected path argument",
206 new YangInstanceIdentifier.NodeIdentifier(leafList),
208 assertEquals("Not expected path argument",
209 new YangInstanceIdentifier.NodeWithValue(leafList, true).toString(),
210 iterator.next().toString());
214 * Test when empty <code>String</code> is supplied as an input. Test is expected to return empty result.
217 public void deserializeEmptyDataTest() {
218 final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(this.schemaContext, "");
219 assertTrue("Empty result expected", Iterables.isEmpty(result));
223 * Negative test when supplied <code>SchemaContext</code> is null. Test is expected to fail with
224 * <code>NullPointerException</code>.
227 public void deserializeNullSchemaContextNegativeTest() {
228 this.thrown.expect(NullPointerException.class);
229 YangInstanceIdentifierDeserializer.create(null, "deserializer-test:contA");
233 * Negative test when supplied <code>String</code> data to deserialize is null. Test is expected to fail with
234 * <code>NullPointerException</code>.
237 public void nullDataNegativeNegativeTest() {
238 this.thrown.expect(NullPointerException.class);
239 YangInstanceIdentifierDeserializer.create(this.schemaContext, null);
243 * Negative test when identifier is not followed by slash or equals. Test is expected to fail with
244 * <code>IllegalArgumentException</code>.
247 public void deserializeBadCharMissingSlashOrEqualNegativeTest() {
248 this.thrown.expect(IllegalArgumentException.class);
249 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:cont*leaf-A");
253 * Negative test of validating identifier when there is a slash after container without next identifier. Test
254 * is expected to fail with <code>IllegalArgumentException</code>.
257 public void validArgIdentifierContainerEndsWithSlashNegativeTest() {
258 this.thrown.expect(IllegalArgumentException.class);
259 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA/");
263 * Negative test of validating identifier when there is a slash after list key values without next identifier. Test
264 * is expected to fail with <code>IllegalArgumentException</code>.
267 public void validArgIdentifierListEndsWithSlashLNegativeTest() {
268 this.thrown.expect(IllegalArgumentException.class);
269 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:list-one-key=value/");
273 * Negative test of creating <code>QName</code> when identifier is empty (example: '/'). Test is expected to fail
274 * with <code>IllegalArgumentException</code>.
277 public void prepareQnameEmptyIdentifierNegativeTest() {
278 this.thrown.expect(IllegalArgumentException.class);
279 YangInstanceIdentifierDeserializer.create(this.schemaContext, "/");
283 * Negative test of creating <code>QName</code> when two identifiers are separated by two slashes. Test is
284 * expected to fail with <code>IllegalArgumentException</code>.
287 public void prepareQnameTwoSlashesNegativeTest() {
288 this.thrown.expect(IllegalArgumentException.class);
289 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA//leaf-A");
293 * Negative test of creating <code>QName</code> when in identifier there is another sign than colon or equals.
294 * Test is expected to fail with <code>IllegalArgumentException</code>.
297 public void prepareQnameBuildPathNegativeTest() {
298 this.thrown.expect(IllegalArgumentException.class);
299 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test*contA");
303 * Negative test of creating <code>QName</code> when it is not possible to find module for specified prefix. Test is
304 * expected to fail with <code>IllegalArgumentException</code>.
307 public void prepareQnameNotExistingPrefixNegativeTest() {
308 this.thrown.expect(IllegalArgumentException.class);
309 YangInstanceIdentifierDeserializer.create(this.schemaContext, "not-existing:contA");
313 * Negative test of creating <code>QName</code> when after prefix and colon there is not parsable identifier as
314 * local name. Test is expected to fail with <code>IllegalArgumentException</code>.
317 public void prepareQnameNotValidPrefixAndLocalNameNegativeTest() {
318 this.thrown.expect(IllegalArgumentException.class);
319 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:*not-parsable-identifier");
323 * Negative test of creating <code>QName</code> when data ends after prefix and colon. Test is expected to fail
324 * with <code>StringIndexOutOfBoundsException</code>.
327 public void prepareQnameErrorParsingNegativeTest() {
328 this.thrown.expect(StringIndexOutOfBoundsException.class);
329 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:");
333 * Negative test of creating <code>QName</code> when after identifier and colon there is node name of unknown
334 * node in current container. Test is expected to fail with <code>RestconfDocumentedException</code> and error
335 * type, error tag and error status code are compared to expected values.
338 public void prepareQnameNotValidContainerNameNegativeTest() {
340 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA/leafB");
341 fail("Test should fail due to unknown child node in container");
342 } catch (final RestconfDocumentedException e) {
343 assertEquals("Not expected error type",
344 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
345 assertEquals("Not expected error tag",
346 RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
347 assertEquals("Not expected error status code",
348 404, e.getErrors().get(0).getErrorTag().getStatusCode());
353 * Negative test of creating <code>QName</code> when after identifier and equals there is node name of unknown
354 * node in current list. Test is expected to fail with <code>RestconfDocumentedException</code> and error
355 * type, error tag and error status code are compared to expected values.
358 public void prepareQnameNotValidListNameNegativeTest() {
360 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:list-no-key/disabled=false");
361 fail("Test should fail due to unknown child node in list");
362 } catch (final RestconfDocumentedException e) {
363 assertEquals("Not expected error type",
364 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
365 assertEquals("Not expected error tag",
366 RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
367 assertEquals("Not expected error status code",
368 404, e.getErrors().get(0).getErrorTag().getStatusCode());
373 * Negative test of getting next identifier when current node is keyed entry. Test is expected to
374 * fail with <code>IllegalArgumentException</code>.
377 public void prepareIdentifierNotKeyedEntryNegativeTest() {
378 this.thrown.expect(IllegalArgumentException.class);
379 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:list-one-key");
383 * Negative test when there is a comma also after the last key. Test is expected to fail with
384 * <code>IllegalArgumentException</code>.
387 public void deserializeKeysEndsWithComaNegativeTest() {
388 this.thrown.expect(IllegalArgumentException.class);
389 YangInstanceIdentifierDeserializer.create( this.schemaContext,
390 "deserializer-test:list-multiple-keys=value,100,false,");
394 * Positive when not all keys of list are encoded. The missing keys should be considered to has empty
395 * <code>String</code> values. Also value of next leaf must not be considered to be missing key value.
398 public void notAllListKeysEncodedPositiveTest() {
399 final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
400 final Map<QName, Object> values = new LinkedHashMap<>();
401 values.put(QName.create(list, "name"), ":foo");
402 values.put(QName.create(list, "number"), "");
403 values.put(QName.create(list, "enabled"), "");
405 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer.create(
406 this.schemaContext, "deserializer-test:list-multiple-keys=%3Afoo,,/string-value");
408 assertEquals("Result does not contains expected number of path arguments", 3, Iterables.size(result));
410 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
413 assertEquals("Not expected path argument",
414 YangInstanceIdentifier.NodeIdentifier.create(list),
416 assertEquals("Not expected path argument",
417 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, values).toString(),
418 iterator.next().toString());
421 assertEquals("Not expected path argument",
422 new YangInstanceIdentifier.NodeIdentifier(
423 QName.create("deserializer:test", "2016-06-06", "string-value")),
428 * Negative test when not all keys of list are encoded and it is not possible to consider missing keys to be empty.
429 * Test is expected to fail with <code>RestconfDocumentedException</code> and error type, error tag and error
430 * status code are compared to expected values.
433 public void notAllListKeysEncodedNegativeTest() {
435 YangInstanceIdentifierDeserializer.create(
436 this.schemaContext, "deserializer-test:list-multiple-keys=%3Afoo/string-value");
437 fail("Test should fail due to missing list key values");
438 } catch (final RestconfDocumentedException e) {
439 assertEquals("Not expected error type",
440 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
441 assertEquals("Not expected error tag",
442 RestconfError.ErrorTag.MISSING_ATTRIBUTE, e.getErrors().get(0).getErrorTag());
443 assertEquals("Not expected error status code",
444 400, e.getErrors().get(0).getErrorTag().getStatusCode());
449 * Test URI with list where key value starts with, ends with or contains percent encoded characters.The encoded
450 * value should be complete also with not percent-encoded parts.
453 public void percentEncodedKeyEndsWithNoPercentEncodedChars() {
454 final String URI = "deserializer-test:list-multiple-keys=%3Afoo,1,true";
455 final YangInstanceIdentifier result = YangInstanceIdentifier.create(
456 YangInstanceIdentifierDeserializer.create(this.schemaContext, URI));
458 final Iterator<Map.Entry<QName, Object>> resultListKeys = ((YangInstanceIdentifier.NodeIdentifierWithPredicates)
459 result.getLastPathArgument()).getKeyValues().entrySet().iterator();
461 assertEquals(":foo", resultListKeys.next().getValue());
462 assertEquals(new Short("1"), resultListKeys.next().getValue());
463 assertEquals(true, resultListKeys.next().getValue());
467 * Positive test when all keys of list can be considered to be empty <code>String</code>.
470 public void deserializeAllKeysEmptyTest() {
471 final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
472 final Map<QName, Object> values = new LinkedHashMap<>();
473 values.put(QName.create(list, "name"), "");
474 values.put(QName.create(list, "number"), "");
475 values.put(QName.create(list, "enabled"), "");
477 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
478 .create(this.schemaContext, "deserializer-test:list-multiple-keys=,,");
480 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
482 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
484 assertEquals("Not expected path argument",
485 YangInstanceIdentifier.NodeIdentifier.create(list),
487 assertEquals("Not expected path argument",
488 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, values).toString(),
489 iterator.next().toString());
493 * Negative test of deserialization when for leaf list there is no specified instance value.
494 * <code>RestconfDocumentedException</code> is expected and error type, error tag and error status code are
495 * compared to expected values.
498 public void leafListMissingKeyNegativeTest() {
500 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:leaf-list-0=");
501 fail("Test should fail due to missing instance value");
502 } catch (final RestconfDocumentedException e) {
503 assertEquals("Not expected error type",
504 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
505 assertEquals("Not expected error tag",
506 RestconfError.ErrorTag.MISSING_ATTRIBUTE, e.getErrors().get(0).getErrorTag());
507 assertEquals("Not expected error status code",
508 400, e.getErrors().get(0).getErrorTag().getStatusCode());
513 * Positive test of deserialization when parts of input URI <code>String</code> are defined in another module.
516 public void deserializePartInOtherModuleTest() {
517 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer.create(
518 this.schemaContext, "deserializer-test-included:augmented-list=100/augmented-leaf");
520 assertEquals("Result does not contains expected number of path arguments", 4, Iterables.size(result));
522 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
523 final QName list = QName.create("deserializer:test:included", "2016-06-06", "augmented-list");
524 final QName child = QName.create("deserializer:test", "2016-06-06", "augmented-leaf");
527 assertEquals("Not expected path argument",
528 YangInstanceIdentifier.NodeIdentifier.create(list),
531 assertEquals("Not expected path argument",
532 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, QName.create(list, "list-key"), 100)
538 assertEquals("Not expected path argument",
539 new YangInstanceIdentifier.AugmentationIdentifier(Sets.newHashSet(child)),
542 assertEquals("Not expected path argument",
543 YangInstanceIdentifier.NodeIdentifier.create(child),