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.nb.rfc8040.utils.parser;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertTrue;
13 import static org.junit.Assert.fail;
15 import com.google.common.collect.Iterables;
16 import com.google.common.collect.Sets;
17 import java.io.FileNotFoundException;
18 import java.util.Iterator;
19 import java.util.LinkedHashMap;
21 import org.junit.Before;
22 import org.junit.Rule;
23 import org.junit.Test;
24 import org.junit.rules.ExpectedException;
25 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
26 import org.opendaylight.restconf.common.errors.RestconfError;
27 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
28 import org.opendaylight.yangtools.yang.common.QName;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
31 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
32 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
35 * Unit tests for {@link YangInstanceIdentifierDeserializer}.
37 public class YangInstanceIdentifierDeserializerTest {
40 public ExpectedException thrown = ExpectedException.none();
43 private SchemaContext schemaContext;
46 public void init() throws FileNotFoundException {
48 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/restconf/parser/deserializer"));
52 * Test of deserialization <code>String</code> URI with container to
53 * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
56 public void deserializeContainerTest() {
57 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
58 .create(this.schemaContext, "deserializer-test:contA");
60 assertEquals("Result does not contains expected number of path arguments", 1, Iterables.size(result));
61 assertEquals("Not expected path argument",
62 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
63 result.iterator().next());
67 * Test of deserialization <code>String</code> URI with container containing leaf to
68 * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
71 public void deserializeContainerWithLeafTest() {
72 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
73 .create(this.schemaContext, "deserializer-test:contA/leaf-A");
75 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
77 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
78 assertEquals("Not expected path argument",
79 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
81 assertEquals("Not expected path argument",
82 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "leaf-A")),
87 * Test of deserialization <code>String</code> URI with container containing list with leaf list to
88 * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
91 public void deserializeContainerWithListWithLeafListTest() {
92 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
93 .create(this.schemaContext, "deserializer-test:contA/list-A=100/leaf-list-AA=instance");
95 assertEquals("Result does not contains expected number of path arguments", 5, Iterables.size(result));
97 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
100 assertEquals("Not expected path argument",
101 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
105 final QName list = QName.create("deserializer:test", "2016-06-06", "list-A");
106 assertEquals("Not expected path argument",
107 YangInstanceIdentifier.NodeIdentifier.create(list),
109 assertEquals("Not expected path argument",
110 new YangInstanceIdentifier.NodeIdentifierWithPredicates(
111 list, QName.create(list, "list-key"), 100).toString(),
112 iterator.next().toString());
115 final QName leafList = QName.create("deserializer:test", "2016-06-06", "leaf-list-AA");
116 assertEquals("Not expected path argument",
117 YangInstanceIdentifier.NodeIdentifier.create(leafList),
119 assertEquals("Not expected path argument",
120 new YangInstanceIdentifier.NodeWithValue<>(leafList, "instance"),
125 * Test of deserialization <code>String</code> URI containing list with no keys to
126 * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
129 public void deserializeListWithNoKeysTest() {
130 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
131 .create(this.schemaContext, "deserializer-test:list-no-key");
133 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
135 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
136 final QName list = QName.create("deserializer:test", "2016-06-06", "list-no-key");
138 assertEquals("Not expected path argument",
139 YangInstanceIdentifier.NodeIdentifier.create(list),
141 assertEquals("Not expected path argument",
142 YangInstanceIdentifier.NodeIdentifier.create(list),
147 * Test of deserialization <code>String</code> URI containing list with one key to
148 * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
151 public void deserializeListWithOneKeyTest() {
152 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
153 .create(this.schemaContext, "deserializer-test:list-one-key=value");
155 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
157 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
158 final QName list = QName.create("deserializer:test", "2016-06-06", "list-one-key");
160 assertEquals("Not expected path argument",
161 YangInstanceIdentifier.NodeIdentifier.create(list),
163 assertEquals("Not expected path argument",
164 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, QName.create(list, "name"), "value"),
169 * Test of deserialization <code>String</code> URI containing list with multiple keys to
170 * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
173 public void deserializeListWithMultipleKeysTest() {
174 final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
175 final Map<QName, Object> values = new LinkedHashMap<>();
176 values.put(QName.create(list, "name"), "value");
177 values.put(QName.create(list, "number"), 100);
178 values.put(QName.create(list, "enabled"), false);
180 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
181 .create(this.schemaContext, "deserializer-test:list-multiple-keys=value,100,false");
183 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
185 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
187 assertEquals("Not expected path argument",
188 YangInstanceIdentifier.NodeIdentifier.create(list),
190 assertEquals("Not expected path argument",
191 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, values).toString(),
192 iterator.next().toString());
196 * Test of deserialization <code>String</code> URI containing leaf list to
197 * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
200 public void deserializeLeafListTest() {
201 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
202 .create(this.schemaContext, "deserializer-test:leaf-list-0=true");
204 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
206 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
207 final QName leafList = QName.create("deserializer:test", "2016-06-06", "leaf-list-0");
209 assertEquals("Not expected path argument",
210 new YangInstanceIdentifier.NodeIdentifier(leafList),
212 assertEquals("Not expected path argument",
213 new YangInstanceIdentifier.NodeWithValue<>(leafList, true).toString(),
214 iterator.next().toString());
218 * Test when empty <code>String</code> is supplied as an input. Test is expected to return empty result.
221 public void deserializeEmptyDataTest() {
222 final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(this.schemaContext, "");
223 assertTrue("Empty result expected", Iterables.isEmpty(result));
227 * Negative test when supplied <code>SchemaContext</code> is null. Test is expected to fail with
228 * <code>NullPointerException</code>.
231 public void deserializeNullSchemaContextNegativeTest() {
232 this.thrown.expect(NullPointerException.class);
233 YangInstanceIdentifierDeserializer.create(null, "deserializer-test:contA");
237 * Negative test when supplied <code>String</code> data to deserialize is null. Test is expected to fail with
238 * <code>NullPointerException</code>.
241 public void nullDataNegativeNegativeTest() {
242 this.thrown.expect(NullPointerException.class);
243 YangInstanceIdentifierDeserializer.create(this.schemaContext, null);
247 * Negative test when identifier is not followed by slash or equals. Test is expected to fail with
248 * <code>IllegalArgumentException</code>.
251 public void deserializeBadCharMissingSlashOrEqualNegativeTest() {
252 this.thrown.expect(IllegalArgumentException.class);
253 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:cont*leaf-A");
257 * Negative test of validating identifier when there is a slash after container without next identifier. Test
258 * is expected to fail with <code>IllegalArgumentException</code>.
261 public void validArgIdentifierContainerEndsWithSlashNegativeTest() {
262 this.thrown.expect(IllegalArgumentException.class);
263 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA/");
267 * Negative test of validating identifier when there is a slash after list key values without next identifier. Test
268 * is expected to fail with <code>IllegalArgumentException</code>.
271 public void validArgIdentifierListEndsWithSlashLNegativeTest() {
272 this.thrown.expect(IllegalArgumentException.class);
273 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:list-one-key=value/");
277 * Negative test of creating <code>QName</code> when identifier is empty (example: '/'). Test is expected to fail
278 * with <code>IllegalArgumentException</code>.
281 public void prepareQnameEmptyIdentifierNegativeTest() {
282 this.thrown.expect(IllegalArgumentException.class);
283 YangInstanceIdentifierDeserializer.create(this.schemaContext, "/");
287 * Negative test of creating <code>QName</code> when two identifiers are separated by two slashes. Test is
288 * expected to fail with <code>IllegalArgumentException</code>.
291 public void prepareQnameTwoSlashesNegativeTest() {
292 this.thrown.expect(IllegalArgumentException.class);
293 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA//leaf-A");
297 * Negative test of creating <code>QName</code> when in identifier there is another sign than colon or equals.
298 * Test is expected to fail with <code>IllegalArgumentException</code>.
301 public void prepareQnameBuildPathNegativeTest() {
302 this.thrown.expect(IllegalArgumentException.class);
303 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test*contA");
307 * Negative test of creating <code>QName</code> when it is not possible to find module for specified prefix. Test is
308 * expected to fail with <code>IllegalArgumentException</code>.
311 public void prepareQnameNotExistingPrefixNegativeTest() {
312 this.thrown.expect(IllegalArgumentException.class);
313 YangInstanceIdentifierDeserializer.create(this.schemaContext, "not-existing:contA");
317 * Negative test of creating <code>QName</code> when after prefix and colon there is not parsable identifier as
318 * local name. Test is expected to fail with <code>IllegalArgumentException</code>.
321 public void prepareQnameNotValidPrefixAndLocalNameNegativeTest() {
322 this.thrown.expect(IllegalArgumentException.class);
323 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:*not-parsable-identifier");
327 * Negative test of creating <code>QName</code> when data ends after prefix and colon. Test is expected to fail
328 * with <code>StringIndexOutOfBoundsException</code>.
331 public void prepareQnameErrorParsingNegativeTest() {
332 this.thrown.expect(StringIndexOutOfBoundsException.class);
333 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:");
337 * Negative test of creating <code>QName</code> when after identifier and colon there is node name of unknown
338 * node in current container. Test is expected to fail with <code>RestconfDocumentedException</code> and error
339 * type, error tag and error status code are compared to expected values.
342 public void prepareQnameNotValidContainerNameNegativeTest() {
344 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA/leafB");
345 fail("Test should fail due to unknown child node in container");
346 } catch (final RestconfDocumentedException e) {
347 assertEquals("Not expected error type",
348 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
349 assertEquals("Not expected error tag",
350 RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
351 assertEquals("Not expected error status code",
352 404, e.getErrors().get(0).getErrorTag().getStatusCode());
357 * Negative test of creating <code>QName</code> when after identifier and equals there is node name of unknown
358 * node in current list. Test is expected to fail with <code>RestconfDocumentedException</code> and error
359 * type, error tag and error status code are compared to expected values.
362 public void prepareQnameNotValidListNameNegativeTest() {
364 YangInstanceIdentifierDeserializer
365 .create(this.schemaContext, "deserializer-test:list-no-key/disabled=false");
366 fail("Test should fail due to unknown child node in list");
367 } catch (final RestconfDocumentedException e) {
368 assertEquals("Not expected error type",
369 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
370 assertEquals("Not expected error tag",
371 RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
372 assertEquals("Not expected error status code",
373 404, e.getErrors().get(0).getErrorTag().getStatusCode());
378 * Negative test of getting next identifier when current node is keyed entry. Test is expected to
379 * fail with <code>IllegalArgumentException</code>.
382 public void prepareIdentifierNotKeyedEntryNegativeTest() {
383 this.thrown.expect(IllegalArgumentException.class);
384 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:list-one-key");
388 * Negative test when there is a comma also after the last key. Test is expected to fail with
389 * <code>IllegalArgumentException</code>.
392 public void deserializeKeysEndsWithComaNegativeTest() {
393 this.thrown.expect(IllegalArgumentException.class);
394 YangInstanceIdentifierDeserializer.create(this.schemaContext,
395 "deserializer-test:list-multiple-keys=value,100,false,");
399 * Positive when not all keys of list are encoded. The missing keys should be considered to has empty
400 * <code>String</code> values. Also value of next leaf must not be considered to be missing key value.
403 public void notAllListKeysEncodedPositiveTest() {
404 final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
405 final Map<QName, Object> values = new LinkedHashMap<>();
406 values.put(QName.create(list, "name"), ":foo");
407 values.put(QName.create(list, "number"), "");
408 values.put(QName.create(list, "enabled"), "");
410 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer.create(
411 this.schemaContext, "deserializer-test:list-multiple-keys=%3Afoo,,/string-value");
413 assertEquals("Result does not contains expected number of path arguments", 3, Iterables.size(result));
415 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
418 assertEquals("Not expected path argument",
419 YangInstanceIdentifier.NodeIdentifier.create(list),
421 assertEquals("Not expected path argument",
422 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, values).toString(),
423 iterator.next().toString());
426 assertEquals("Not expected path argument",
427 new YangInstanceIdentifier.NodeIdentifier(
428 QName.create("deserializer:test", "2016-06-06", "string-value")),
433 * Negative test when not all keys of list are encoded and it is not possible to consider missing keys to be empty.
434 * Test is expected to fail with <code>RestconfDocumentedException</code> and error type, error tag and error
435 * status code are compared to expected values.
438 public void notAllListKeysEncodedNegativeTest() {
440 YangInstanceIdentifierDeserializer.create(
441 this.schemaContext, "deserializer-test:list-multiple-keys=%3Afoo/string-value");
442 fail("Test should fail due to missing list key values");
443 } catch (final RestconfDocumentedException e) {
444 assertEquals("Not expected error type",
445 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
446 assertEquals("Not expected error tag",
447 RestconfError.ErrorTag.MISSING_ATTRIBUTE, e.getErrors().get(0).getErrorTag());
448 assertEquals("Not expected error status code",
449 400, e.getErrors().get(0).getErrorTag().getStatusCode());
454 * Test URI with list where key value starts with, ends with or contains percent encoded characters.The encoded
455 * value should be complete also with not percent-encoded parts.
458 public void percentEncodedKeyEndsWithNoPercentEncodedChars() {
459 final String URI = "deserializer-test:list-multiple-keys=%3Afoo,1,true";
460 final YangInstanceIdentifier result = YangInstanceIdentifier.create(
461 YangInstanceIdentifierDeserializer.create(this.schemaContext, URI));
463 final Iterator<Map.Entry<QName, Object>> resultListKeys = ((YangInstanceIdentifier.NodeIdentifierWithPredicates)
464 result.getLastPathArgument()).getKeyValues().entrySet().iterator();
466 assertEquals(":foo", resultListKeys.next().getValue());
467 assertEquals(new Short("1"), resultListKeys.next().getValue());
468 assertEquals(true, resultListKeys.next().getValue());
472 * Positive test when all keys of list can be considered to be empty <code>String</code>.
475 public void deserializeAllKeysEmptyTest() {
476 final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
477 final Map<QName, Object> values = new LinkedHashMap<>();
478 values.put(QName.create(list, "name"), "");
479 values.put(QName.create(list, "number"), "");
480 values.put(QName.create(list, "enabled"), "");
482 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
483 .create(this.schemaContext, "deserializer-test:list-multiple-keys=,,");
485 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
487 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
489 assertEquals("Not expected path argument",
490 YangInstanceIdentifier.NodeIdentifier.create(list),
492 assertEquals("Not expected path argument",
493 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, values).toString(),
494 iterator.next().toString());
498 * Negative test of deserialization when for leaf list there is no specified instance value.
499 * <code>RestconfDocumentedException</code> is expected and error type, error tag and error status code are
500 * compared to expected values.
503 public void leafListMissingKeyNegativeTest() {
505 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:leaf-list-0=");
506 fail("Test should fail due to missing instance value");
507 } catch (final RestconfDocumentedException e) {
508 assertEquals("Not expected error type",
509 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
510 assertEquals("Not expected error tag",
511 RestconfError.ErrorTag.MISSING_ATTRIBUTE, e.getErrors().get(0).getErrorTag());
512 assertEquals("Not expected error status code",
513 400, e.getErrors().get(0).getErrorTag().getStatusCode());
518 * Positive test of deserialization when parts of input URI <code>String</code> are defined in another module.
521 public void deserializePartInOtherModuleTest() {
522 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer.create(
523 this.schemaContext, "deserializer-test-included:augmented-list=100/augmented-leaf");
525 assertEquals("Result does not contains expected number of path arguments", 4, Iterables.size(result));
527 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
528 final QName list = QName.create("deserializer:test:included", "2016-06-06", "augmented-list");
529 final QName child = QName.create("deserializer:test", "2016-06-06", "augmented-leaf");
532 assertEquals("Not expected path argument",
533 YangInstanceIdentifier.NodeIdentifier.create(list),
536 assertEquals("Not expected path argument",
537 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, QName.create(list, "list-key"), 100)
543 assertEquals("Not expected path argument",
544 new YangInstanceIdentifier.AugmentationIdentifier(Sets.newHashSet(child)),
547 assertEquals("Not expected path argument",
548 YangInstanceIdentifier.NodeIdentifier.create(child),