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;
15 import com.google.common.collect.Iterables;
16 import com.google.common.collect.Sets;
17 import java.util.Iterator;
18 import java.util.LinkedHashMap;
20 import org.junit.Before;
21 import org.junit.Rule;
22 import org.junit.Test;
23 import org.junit.rules.ExpectedException;
24 import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
25 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
26 import org.opendaylight.restconf.common.errors.RestconfError;
27 import org.opendaylight.yangtools.yang.common.QName;
28 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
30 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
31 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
34 * Unit tests for {@link YangInstanceIdentifierDeserializer}.
36 public class YangInstanceIdentifierDeserializerTest {
39 public ExpectedException thrown = ExpectedException.none();
42 private SchemaContext schemaContext;
45 public void init() throws Exception {
47 YangParserTestUtils.parseYangSources(TestRestconfUtils.loadFiles("/restconf/parser/deserializer"));
51 * Test of deserialization <code>String</code> URI with container to
52 * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
55 public void deserializeContainerTest() {
56 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
57 .create(this.schemaContext, "deserializer-test:contA");
59 assertEquals("Result does not contains expected number of path arguments", 1, Iterables.size(result));
60 assertEquals("Not expected path argument",
61 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
62 result.iterator().next());
66 * Test of deserialization <code>String</code> URI with container containing leaf to
67 * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
70 public void deserializeContainerWithLeafTest() {
71 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
72 .create(this.schemaContext, "deserializer-test:contA/leaf-A");
74 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
76 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
77 assertEquals("Not expected path argument",
78 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
80 assertEquals("Not expected path argument",
81 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "leaf-A")),
86 * Test of deserialization <code>String</code> URI with container containing list with leaf list to
87 * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
90 public void deserializeContainerWithListWithLeafListTest() {
91 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
92 .create(this.schemaContext, "deserializer-test:contA/list-A=100/leaf-list-AA=instance");
94 assertEquals("Result does not contains expected number of path arguments", 5, Iterables.size(result));
96 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
99 assertEquals("Not expected path argument",
100 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
104 final QName list = QName.create("deserializer:test", "2016-06-06", "list-A");
105 assertEquals("Not expected path argument",
106 YangInstanceIdentifier.NodeIdentifier.create(list),
108 assertEquals("Not expected path argument",
109 new YangInstanceIdentifier.NodeIdentifierWithPredicates(
110 list, QName.create(list, "list-key"), 100).toString(),
111 iterator.next().toString());
114 final QName leafList = QName.create("deserializer:test", "2016-06-06", "leaf-list-AA");
115 assertEquals("Not expected path argument",
116 YangInstanceIdentifier.NodeIdentifier.create(leafList),
118 assertEquals("Not expected path argument",
119 new YangInstanceIdentifier.NodeWithValue<>(leafList, "instance"),
124 * Test of deserialization <code>String</code> URI containing list with no keys to
125 * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
128 public void deserializeListWithNoKeysTest() {
129 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
130 .create(this.schemaContext, "deserializer-test:list-no-key");
132 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
134 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
135 final QName list = QName.create("deserializer:test", "2016-06-06", "list-no-key");
137 assertEquals("Not expected path argument",
138 YangInstanceIdentifier.NodeIdentifier.create(list),
140 assertEquals("Not expected path argument",
141 YangInstanceIdentifier.NodeIdentifier.create(list),
146 * Test of deserialization <code>String</code> URI containing list with one key to
147 * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
150 public void deserializeListWithOneKeyTest() {
151 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
152 .create(this.schemaContext, "deserializer-test:list-one-key=value");
154 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
156 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
157 final QName list = QName.create("deserializer:test", "2016-06-06", "list-one-key");
159 assertEquals("Not expected path argument",
160 YangInstanceIdentifier.NodeIdentifier.create(list),
162 assertEquals("Not expected path argument",
163 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, QName.create(list, "name"), "value"),
168 * Test of deserialization <code>String</code> URI containing list with multiple keys to
169 * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
172 public void deserializeListWithMultipleKeysTest() {
173 final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
174 final Map<QName, Object> values = new LinkedHashMap<>();
175 values.put(QName.create(list, "name"), "value");
176 values.put(QName.create(list, "number"), 100);
177 values.put(QName.create(list, "enabled"), false);
179 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
180 .create(this.schemaContext, "deserializer-test:list-multiple-keys=value,100,false");
182 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
184 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
186 assertEquals("Not expected path argument",
187 YangInstanceIdentifier.NodeIdentifier.create(list),
189 assertEquals("Not expected path argument",
190 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, values).toString(),
191 iterator.next().toString());
195 * Test of deserialization <code>String</code> URI containing leaf list to
196 * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
199 public void deserializeLeafListTest() {
200 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
201 .create(this.schemaContext, "deserializer-test:leaf-list-0=true");
203 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
205 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
206 final QName leafList = QName.create("deserializer:test", "2016-06-06", "leaf-list-0");
208 assertEquals("Not expected path argument",
209 new YangInstanceIdentifier.NodeIdentifier(leafList),
211 assertEquals("Not expected path argument",
212 new YangInstanceIdentifier.NodeWithValue<>(leafList, true).toString(),
213 iterator.next().toString());
217 * Test when empty <code>String</code> is supplied as an input. Test is expected to return empty result.
220 public void deserializeEmptyDataTest() {
221 final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(this.schemaContext, "");
222 assertTrue("Empty result expected", Iterables.isEmpty(result));
226 * Negative test when supplied <code>SchemaContext</code> is null. Test is expected to fail with
227 * <code>NullPointerException</code>.
230 public void deserializeNullSchemaContextNegativeTest() {
231 this.thrown.expect(NullPointerException.class);
232 YangInstanceIdentifierDeserializer.create(null, "deserializer-test:contA");
236 * Negative test when supplied <code>String</code> data to deserialize is null. Test is expected to fail with
237 * <code>NullPointerException</code>.
240 public void nullDataNegativeNegativeTest() {
241 this.thrown.expect(NullPointerException.class);
242 YangInstanceIdentifierDeserializer.create(this.schemaContext, null);
246 * Negative test when identifier is not followed by slash or equals. Test is expected to fail with
247 * <code>IllegalArgumentException</code>.
250 public void deserializeBadCharMissingSlashOrEqualNegativeTest() {
251 this.thrown.expect(IllegalArgumentException.class);
252 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:cont*leaf-A");
256 * Negative test of validating identifier when there is a slash after container without next identifier. Test
257 * is expected to fail with <code>IllegalArgumentException</code>.
260 public void validArgIdentifierContainerEndsWithSlashNegativeTest() {
261 this.thrown.expect(IllegalArgumentException.class);
262 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA/");
266 * Negative test of validating identifier when there is a slash after list key values without next identifier. Test
267 * is expected to fail with <code>IllegalArgumentException</code>.
270 public void validArgIdentifierListEndsWithSlashLNegativeTest() {
271 this.thrown.expect(IllegalArgumentException.class);
272 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:list-one-key=value/");
276 * Negative test of creating <code>QName</code> when identifier is empty (example: '/'). Test is expected to fail
277 * with <code>IllegalArgumentException</code>.
280 public void prepareQnameEmptyIdentifierNegativeTest() {
281 this.thrown.expect(IllegalArgumentException.class);
282 YangInstanceIdentifierDeserializer.create(this.schemaContext, "/");
286 * Negative test of creating <code>QName</code> when two identifiers are separated by two slashes. Test is
287 * expected to fail with <code>IllegalArgumentException</code>.
290 public void prepareQnameTwoSlashesNegativeTest() {
291 this.thrown.expect(IllegalArgumentException.class);
292 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA//leaf-A");
296 * Negative test of creating <code>QName</code> when in identifier there is another sign than colon or equals.
297 * Test is expected to fail with <code>IllegalArgumentException</code>.
300 public void prepareQnameBuildPathNegativeTest() {
301 this.thrown.expect(IllegalArgumentException.class);
302 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test*contA");
306 * Negative test of creating <code>QName</code> when it is not possible to find module for specified prefix. Test is
307 * expected to fail with <code>IllegalArgumentException</code>.
310 public void prepareQnameNotExistingPrefixNegativeTest() {
311 this.thrown.expect(IllegalArgumentException.class);
312 YangInstanceIdentifierDeserializer.create(this.schemaContext, "not-existing:contA");
316 * Negative test of creating <code>QName</code> when after prefix and colon there is not parsable identifier as
317 * local name. Test is expected to fail with <code>IllegalArgumentException</code>.
320 public void prepareQnameNotValidPrefixAndLocalNameNegativeTest() {
321 this.thrown.expect(IllegalArgumentException.class);
322 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:*not-parsable-identifier");
326 * Negative test of creating <code>QName</code> when data ends after prefix and colon. Test is expected to fail
327 * with <code>StringIndexOutOfBoundsException</code>.
330 public void prepareQnameErrorParsingNegativeTest() {
331 this.thrown.expect(StringIndexOutOfBoundsException.class);
332 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:");
336 * Negative test of creating <code>QName</code> when after identifier and colon there is node name of unknown
337 * node in current container. Test is expected to fail with <code>RestconfDocumentedException</code> and error
338 * type, error tag and error status code are compared to expected values.
341 public void prepareQnameNotValidContainerNameNegativeTest() {
343 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA/leafB");
344 fail("Test should fail due to unknown child node in container");
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.DATA_MISSING, e.getErrors().get(0).getErrorTag());
350 assertEquals("Not expected error status code",
351 404, e.getErrors().get(0).getErrorTag().getStatusCode());
356 * Negative test of creating <code>QName</code> when after identifier and equals there is node name of unknown
357 * node in current list. Test is expected to fail with <code>RestconfDocumentedException</code> and error
358 * type, error tag and error status code are compared to expected values.
361 public void prepareQnameNotValidListNameNegativeTest() {
363 YangInstanceIdentifierDeserializer
364 .create(this.schemaContext, "deserializer-test:list-no-key/disabled=false");
365 fail("Test should fail due to unknown child node in list");
366 } catch (final RestconfDocumentedException e) {
367 assertEquals("Not expected error type",
368 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
369 assertEquals("Not expected error tag",
370 RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
371 assertEquals("Not expected error status code",
372 404, e.getErrors().get(0).getErrorTag().getStatusCode());
377 * Negative test of getting next identifier when current node is keyed entry. Test is expected to
378 * fail with <code>IllegalArgumentException</code>.
381 public void prepareIdentifierNotKeyedEntryNegativeTest() {
382 this.thrown.expect(IllegalArgumentException.class);
383 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:list-one-key");
387 * Negative test when there is a comma also after the last key. Test is expected to fail with
388 * <code>IllegalArgumentException</code>.
391 public void deserializeKeysEndsWithComaNegativeTest() {
392 this.thrown.expect(IllegalArgumentException.class);
393 YangInstanceIdentifierDeserializer.create(this.schemaContext,
394 "deserializer-test:list-multiple-keys=value,100,false,");
398 * Positive when not all keys of list are encoded. The missing keys should be considered to has empty
399 * <code>String</code> values. Also value of next leaf must not be considered to be missing key value.
402 public void notAllListKeysEncodedPositiveTest() {
403 final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
404 final Map<QName, Object> values = new LinkedHashMap<>();
405 values.put(QName.create(list, "name"), ":foo");
406 values.put(QName.create(list, "number"), "");
407 values.put(QName.create(list, "enabled"), "");
409 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer.create(
410 this.schemaContext, "deserializer-test:list-multiple-keys=%3Afoo,,/string-value");
412 assertEquals("Result does not contains expected number of path arguments", 3, Iterables.size(result));
414 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
417 assertEquals("Not expected path argument",
418 YangInstanceIdentifier.NodeIdentifier.create(list),
420 assertEquals("Not expected path argument",
421 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, values).toString(),
422 iterator.next().toString());
425 assertEquals("Not expected path argument",
426 new YangInstanceIdentifier.NodeIdentifier(
427 QName.create("deserializer:test", "2016-06-06", "string-value")),
432 * Negative test when not all keys of list are encoded and it is not possible to consider missing keys to be empty.
433 * Test is expected to fail with <code>RestconfDocumentedException</code> and error type, error tag and error
434 * status code are compared to expected values.
437 public void notAllListKeysEncodedNegativeTest() {
439 YangInstanceIdentifierDeserializer.create(
440 this.schemaContext, "deserializer-test:list-multiple-keys=%3Afoo/string-value");
441 fail("Test should fail due to missing list key values");
442 } catch (final RestconfDocumentedException e) {
443 assertEquals("Not expected error type",
444 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
445 assertEquals("Not expected error tag",
446 RestconfError.ErrorTag.MISSING_ATTRIBUTE, e.getErrors().get(0).getErrorTag());
447 assertEquals("Not expected error status code",
448 400, e.getErrors().get(0).getErrorTag().getStatusCode());
453 * Test URI with list where key value starts with, ends with or contains percent encoded characters.The encoded
454 * value should be complete also with not percent-encoded parts.
457 public void percentEncodedKeyEndsWithNoPercentEncodedChars() {
458 final String URI = "deserializer-test:list-multiple-keys=%3Afoo,1,true";
459 final YangInstanceIdentifier result = YangInstanceIdentifier.create(
460 YangInstanceIdentifierDeserializer.create(this.schemaContext, URI));
462 final Iterator<Map.Entry<QName, Object>> resultListKeys = ((YangInstanceIdentifier.NodeIdentifierWithPredicates)
463 result.getLastPathArgument()).getKeyValues().entrySet().iterator();
465 assertEquals(":foo", resultListKeys.next().getValue());
466 assertEquals(new Short("1"), resultListKeys.next().getValue());
467 assertEquals(true, resultListKeys.next().getValue());
471 * Positive test when all keys of list can be considered to be empty <code>String</code>.
474 public void deserializeAllKeysEmptyTest() {
475 final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
476 final Map<QName, Object> values = new LinkedHashMap<>();
477 values.put(QName.create(list, "name"), "");
478 values.put(QName.create(list, "number"), "");
479 values.put(QName.create(list, "enabled"), "");
481 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
482 .create(this.schemaContext, "deserializer-test:list-multiple-keys=,,");
484 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
486 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
488 assertEquals("Not expected path argument",
489 YangInstanceIdentifier.NodeIdentifier.create(list),
491 assertEquals("Not expected path argument",
492 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, values).toString(),
493 iterator.next().toString());
497 * Negative test of deserialization when for leaf list there is no specified instance value.
498 * <code>RestconfDocumentedException</code> is expected and error type, error tag and error status code are
499 * compared to expected values.
502 public void leafListMissingKeyNegativeTest() {
504 YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:leaf-list-0=");
505 fail("Test should fail due to missing instance value");
506 } catch (final RestconfDocumentedException e) {
507 assertEquals("Not expected error type",
508 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
509 assertEquals("Not expected error tag",
510 RestconfError.ErrorTag.MISSING_ATTRIBUTE, e.getErrors().get(0).getErrorTag());
511 assertEquals("Not expected error status code",
512 400, e.getErrors().get(0).getErrorTag().getStatusCode());
517 * Positive test of deserialization when parts of input URI <code>String</code> are defined in another module.
520 public void deserializePartInOtherModuleTest() {
521 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer.create(
522 this.schemaContext, "deserializer-test-included:augmented-list=100/augmented-leaf");
524 assertEquals("Result does not contains expected number of path arguments", 4, Iterables.size(result));
526 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
527 final QName list = QName.create("deserializer:test:included", "2016-06-06", "augmented-list");
528 final QName child = QName.create("deserializer:test", "2016-06-06", "augmented-leaf");
531 assertEquals("Not expected path argument",
532 YangInstanceIdentifier.NodeIdentifier.create(list),
535 assertEquals("Not expected path argument",
536 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, QName.create(list, "list-key"), 100)
542 assertEquals("Not expected path argument",
543 new YangInstanceIdentifier.AugmentationIdentifier(Sets.newHashSet(child)),
546 assertEquals("Not expected path argument",
547 YangInstanceIdentifier.NodeIdentifier.create(child),