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.Ignore;
22 import org.junit.Rule;
23 import org.junit.Test;
24 import org.junit.rules.ExpectedException;
25 import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
26 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
27 import org.opendaylight.netconf.sal.restconf.impl.RestconfError;
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;
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 {
46 schemaContext = TestRestconfUtils.loadSchemaContext("/restconf/parser/deserializer");
50 * Test of deserialization <code>String</code> URI with container to
51 * <code>Iterable<YangInstanceIdentifier.PathArgument></code>.
54 public void deserializeContainerTest() {
55 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
56 .create(schemaContext, "deserializer-test:contA");
58 assertEquals("Result does not contains expected number of path arguments", 1, Iterables.size(result));
59 assertEquals("Not expected path argument",
60 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
61 result.iterator().next());
65 * Test of deserialization <code>String</code> URI with container containing leaf to
66 * <code>Iterable<YangInstanceIdentifier.PathArgument></code>.
69 public void deserializeContainerWithLeafTest() {
70 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
71 .create(schemaContext, "deserializer-test:contA/leaf-A");
73 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
75 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
76 assertEquals("Not expected path argument",
77 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
79 assertEquals("Not expected path argument",
80 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "leaf-A")),
85 * Test of deserialization <code>String</code> URI with container containing list with leaf list to
86 * <code>Iterable<YangInstanceIdentifier.PathArgument></code>.
89 public void deserializeContainerWithListWithLeafListTest() {
90 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
91 .create(schemaContext, "deserializer-test:contA/list-A=100/leaf-list-AA=instance");
93 assertEquals("Result does not contains expected number of path arguments", 5, Iterables.size(result));
95 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
98 assertEquals("Not expected path argument",
99 YangInstanceIdentifier.NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
103 final QName list = QName.create("deserializer:test", "2016-06-06", "list-A");
104 assertEquals("Not expected path argument",
105 YangInstanceIdentifier.NodeIdentifier.create(list),
107 assertEquals("Not expected path argument",
108 new YangInstanceIdentifier.NodeIdentifierWithPredicates(
109 list, QName.create(list, "list-key"), 100).toString(),
110 iterator.next().toString());
113 final QName leafList = QName.create("deserializer:test", "2016-06-06", "leaf-list-AA");
114 assertEquals("Not expected path argument",
115 YangInstanceIdentifier.NodeIdentifier.create(leafList),
117 assertEquals("Not expected path argument",
118 new YangInstanceIdentifier.NodeWithValue(leafList, "instance"),
123 * Test of deserialization <code>String</code> URI containing list with no keys to
124 * <code>Iterable<YangInstanceIdentifier.PathArgument></code>.
127 public void deserializeListWithNoKeysTest() {
128 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
129 .create(schemaContext, "deserializer-test:list-no-key");
131 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
133 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
134 final QName list = QName.create("deserializer:test", "2016-06-06", "list-no-key");
136 assertEquals("Not expected path argument",
137 YangInstanceIdentifier.NodeIdentifier.create(list),
139 assertEquals("Not expected path argument",
140 YangInstanceIdentifier.NodeIdentifier.create(list),
145 * Test of deserialization <code>String</code> URI containing list with one key to
146 * <code>Iterable<YangInstanceIdentifier.PathArgument></code>.
149 public void deserializeListWithOneKeyTest() {
150 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
151 .create(schemaContext, "deserializer-test:list-one-key=value");
153 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
155 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
156 final QName list = QName.create("deserializer:test", "2016-06-06", "list-one-key");
158 assertEquals("Not expected path argument",
159 YangInstanceIdentifier.NodeIdentifier.create(list),
161 assertEquals("Not expected path argument",
162 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, QName.create(list, "name"), "value"),
167 * Test of deserialization <code>String</code> URI containing list with multiple keys to
168 * <code>Iterable<YangInstanceIdentifier.PathArgument></code>.
171 public void deserializeListWithMultipleKeysTest() {
172 final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
173 final Map<QName, Object> values = new LinkedHashMap<>();
174 values.put(QName.create(list, "name"), "value");
175 values.put(QName.create(list, "number"), 100);
176 values.put(QName.create(list, "enabled"), false);
178 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
179 .create(schemaContext, "deserializer-test:list-multiple-keys=value,100,false");
181 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
183 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
185 assertEquals("Not expected path argument",
186 YangInstanceIdentifier.NodeIdentifier.create(list),
188 assertEquals("Not expected path argument",
189 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, values).toString(),
190 iterator.next().toString());
194 * Test of deserialization <code>String</code> URI containing leaf list to
195 * <code>Iterable<YangInstanceIdentifier.PathArgument></code>.
198 public void deserializeLeafListTest() {
199 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
200 .create(schemaContext, "deserializer-test:leaf-list-0=true");
202 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
204 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
205 final QName leafList = QName.create("deserializer:test", "2016-06-06", "leaf-list-0");
207 assertEquals("Not expected path argument",
208 new YangInstanceIdentifier.NodeIdentifier(leafList),
210 assertEquals("Not expected path argument",
211 new YangInstanceIdentifier.NodeWithValue(leafList, true).toString(),
212 iterator.next().toString());
216 * Test when empty <code>String</code> is supplied as an input. Test is expected to return empty result.
219 public void deserializeEmptyDataTest() {
220 final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(schemaContext, "");
221 assertTrue("Empty result expected", Iterables.isEmpty(result));
225 * Negative test when supplied <code>SchemaContext</code> is null. Test is expected to fail with
226 * <code>NullPointerException</code>.
229 public void deserializeNullSchemaContextNegativeTest() {
230 thrown.expect(NullPointerException.class);
231 YangInstanceIdentifierDeserializer.create(null, "deserializer-test:contA");
235 * Negative test when supplied <code>String</code> data to deserialize is null. Test is expected to fail with
236 * <code>NullPointerException</code>.
239 public void nullDataNegativeNegativeTest() {
240 thrown.expect(NullPointerException.class);
241 YangInstanceIdentifierDeserializer.create(schemaContext, null);
245 * Negative test when identifier is not followed by slash or equals. Test is expected to fail with
246 * <code>IllegalArgumentException</code>.
249 public void deserializeBadCharMissingSlashOrEqualNegativeTest() {
250 thrown.expect(IllegalArgumentException.class);
251 YangInstanceIdentifierDeserializer.create(schemaContext, "deserializer-test:cont*leaf-A");
255 * Negative test of validating identifier when there is a slash after container without next identifier. Test
256 * is expected to fail with <code>IllegalArgumentException</code>.
259 public void validArgIdentifierContainerEndsWithSlashNegativeTest() {
260 thrown.expect(IllegalArgumentException.class);
261 YangInstanceIdentifierDeserializer.create(schemaContext, "deserializer-test:contA/");
265 * Negative test of validating identifier when there is a slash after list key values without next identifier. Test
266 * is expected to fail with <code>IllegalArgumentException</code>.
269 public void validArgIdentifierListEndsWithSlashLNegativeTest() {
270 thrown.expect(IllegalArgumentException.class);
271 YangInstanceIdentifierDeserializer.create(schemaContext, "deserializer-test:list-one-key=value/");
275 * Negative test of creating <code>QName</code> when identifier is empty (example: '/'). Test is expected to fail
276 * with <code>IllegalArgumentException</code>.
279 public void prepareQnameEmptyIdentifierNegativeTest() {
280 thrown.expect(IllegalArgumentException.class);
281 YangInstanceIdentifierDeserializer.create(schemaContext, "/");
285 * Negative test of creating <code>QName</code> when two identifiers are separated by two slashes. Test is
286 * expected to fail with <code>IllegalArgumentException</code>.
289 public void prepareQnameTwoSlashesNegativeTest() {
290 thrown.expect(IllegalArgumentException.class);
291 YangInstanceIdentifierDeserializer.create(schemaContext, "deserializer-test:contA//leaf-A");
295 * Negative test of creating <code>QName</code> when in identifier there is another sign than colon or equals.
296 * Test is expected to fail with <code>IllegalArgumentException</code>.
299 public void prepareQnameBuildPathNegativeTest() {
300 thrown.expect(IllegalArgumentException.class);
301 YangInstanceIdentifierDeserializer.create(schemaContext, "deserializer-test*contA");
305 * Negative test of creating <code>QName</code> when it is not possible to find module for specified prefix. Test is
306 * expected to fail with <code>IllegalArgumentException</code>.
309 public void prepareQnameNotExistingPrefixNegativeTest() {
310 thrown.expect(IllegalArgumentException.class);
311 YangInstanceIdentifierDeserializer.create(schemaContext, "not-existing:contA");
315 * Negative test of creating <code>QName</code> when after prefix and colon there is not parsable identifier as
316 * local name. Test is expected to fail with <code>IllegalArgumentException</code>.
319 public void prepareQnameNotValidPrefixAndLocalNameNegativeTest() {
320 thrown.expect(IllegalArgumentException.class);
321 YangInstanceIdentifierDeserializer.create(schemaContext, "deserializer-test:*not-parsable-identifier");
325 * Negative test of creating <code>QName</code> when data ends after prefix and colon. Test is expected to fail
326 * with <code>StringIndexOutOfBoundsException</code>.
329 public void prepareQnameErrorParsingNegativeTest() {
330 thrown.expect(StringIndexOutOfBoundsException.class);
331 YangInstanceIdentifierDeserializer.create(schemaContext, "deserializer-test:");
335 * Negative test of creating <code>QName</code> when after identifier and colon there is node name of unknown
336 * node in current container. Test is expected to fail with <code>RestconfDocumentedException</code> and error
337 * type, error tag and error status code are compared to expected values.
340 public void prepareQnameNotValidContainerNameNegativeTest() {
342 YangInstanceIdentifierDeserializer.create(schemaContext, "deserializer-test:contA/leafB");
343 fail("Test should fail due to unknown child node in container");
344 } catch (final RestconfDocumentedException e) {
345 assertEquals("Not expected error type",
346 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
347 assertEquals("Not expected error tag",
348 RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
349 assertEquals("Not expected error status code",
350 404, e.getErrors().get(0).getErrorTag().getStatusCode());
355 * Negative test of creating <code>QName</code> when after identifier and equals there is node name of unknown
356 * node in current list. Test is expected to fail with <code>RestconfDocumentedException</code> and error
357 * type, error tag and error status code are compared to expected values.
360 public void prepareQnameNotValidListNameNegativeTest() {
362 YangInstanceIdentifierDeserializer.create(schemaContext, "deserializer-test:list-no-key/disabled=false");
363 fail("Test should fail due to unknown child node in list");
364 } catch (final RestconfDocumentedException e) {
365 assertEquals("Not expected error type",
366 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
367 assertEquals("Not expected error tag",
368 RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
369 assertEquals("Not expected error status code",
370 404, e.getErrors().get(0).getErrorTag().getStatusCode());
375 * Negative test of getting next identifier when current node is keyed entry. Test is expected to
376 * fail with <code>IllegalArgumentException</code>.
379 public void prepareIdentifierNotKeyedEntryNegativeTest() {
380 thrown.expect(IllegalArgumentException.class);
381 YangInstanceIdentifierDeserializer.create(schemaContext, "deserializer-test:list-one-key");
385 * Negative test when there is a comma also after the last key. Test is expected to fail with
386 * <code>IllegalArgumentException</code>.
389 public void deserializeKeysEndsWithComaNegativeTest() {
390 thrown.expect(IllegalArgumentException.class);
391 YangInstanceIdentifierDeserializer.create( schemaContext,
392 "deserializer-test:list-multiple-keys=value,100,false,");
396 * Positive when not all keys of list are encoded. The missing keys should be considered to has empty
397 * <code>String</code> values. Also value of next leaf must not be considered to be missing key value.
400 public void notAllListKeysEncodedPositiveTest() {
401 final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
402 final Map<QName, Object> values = new LinkedHashMap<>();
403 values.put(QName.create(list, "name"), ":foo");
404 values.put(QName.create(list, "number"), "");
405 values.put(QName.create(list, "enabled"), "");
407 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer.create(
408 schemaContext, "deserializer-test:list-multiple-keys=%3Afoo,,/string-value");
410 assertEquals("Result does not contains expected number of path arguments", 3, Iterables.size(result));
412 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
415 assertEquals("Not expected path argument",
416 YangInstanceIdentifier.NodeIdentifier.create(list),
418 assertEquals("Not expected path argument",
419 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, values).toString(),
420 iterator.next().toString());
423 assertEquals("Not expected path argument",
424 new YangInstanceIdentifier.NodeIdentifier(
425 QName.create("deserializer:test", "2016-06-06", "string-value")),
430 * Negative test when not all keys of list are encoded and it is not possible to consider missing keys to be empty.
431 * Test is expected to fail with <code>RestconfDocumentedException</code> and error type, error tag and error
432 * status code are compared to expected values.
435 public void notAllListKeysEncodedNegativeTest() {
437 YangInstanceIdentifierDeserializer.create(
438 schemaContext, "deserializer-test:list-multiple-keys=%3Afoo/string-value");
439 fail("Test should fail due to missing list key values");
440 } catch (final RestconfDocumentedException e) {
441 assertEquals("Not expected error type",
442 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
443 assertEquals("Not expected error tag",
444 RestconfError.ErrorTag.MISSING_ATTRIBUTE, e.getErrors().get(0).getErrorTag());
445 assertEquals("Not expected error status code",
446 400, e.getErrors().get(0).getErrorTag().getStatusCode());
451 * Test URI with list where key value starts with, ends with or contains percent encoded characters.The encoded
452 * value should be complete also with not percent-encoded parts.
455 public void percentEncodedKeyEndsWithNoPercentEncodedChars() {
456 final String URI = "deserializer-test:list-multiple-keys=%3Afoo,bar%3A,foo%3Abar";
457 final YangInstanceIdentifier result = YangInstanceIdentifier.create(
458 YangInstanceIdentifierDeserializer.create(schemaContext, URI));
460 final Iterator<Map.Entry<QName, Object>> resultListKeys = ((YangInstanceIdentifier.NodeIdentifierWithPredicates)
461 result.getLastPathArgument()).getKeyValues().entrySet().iterator();
463 assertEquals(":foo", resultListKeys.next().getValue());
464 assertEquals("bar:", resultListKeys.next().getValue());
465 assertEquals("foo:bar", resultListKeys.next().getValue());
469 * Positive test when all keys of list can be considered to be empty <code>String</code>.
472 public void deserializeAllKeysEmptyTest() {
473 final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
474 final Map<QName, Object> values = new LinkedHashMap<>();
475 values.put(QName.create(list, "name"), "");
476 values.put(QName.create(list, "number"), "");
477 values.put(QName.create(list, "enabled"), "");
479 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer
480 .create(schemaContext, "deserializer-test:list-multiple-keys=,,");
482 assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
484 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
486 assertEquals("Not expected path argument",
487 YangInstanceIdentifier.NodeIdentifier.create(list),
489 assertEquals("Not expected path argument",
490 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, values).toString(),
491 iterator.next().toString());
495 * Negative test of deserialization when for leaf list there is no specified instance value.
496 * <code>RestconfDocumentedException</code> is expected and error type, error tag and error status code are
497 * compared to expected values.
500 public void leafListMissingKeyNegativeTest() {
502 YangInstanceIdentifierDeserializer.create(schemaContext, "deserializer-test:leaf-list-0=");
503 fail("Test should fail due to missing instance value");
504 } catch (final RestconfDocumentedException e) {
505 assertEquals("Not expected error type",
506 RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
507 assertEquals("Not expected error tag",
508 RestconfError.ErrorTag.MISSING_ATTRIBUTE, e.getErrors().get(0).getErrorTag());
509 assertEquals("Not expected error status code",
510 400, e.getErrors().get(0).getErrorTag().getStatusCode());
515 * Positive test of deserialization when parts of input URI <code>String</code> are defined in another module.
518 public void deserializePartInOtherModuleTest() {
519 final Iterable<YangInstanceIdentifier.PathArgument> result = YangInstanceIdentifierDeserializer.create(
520 schemaContext, "deserializer-test-included:augmented-list=100/augmented-leaf");
522 assertEquals("Result does not contains expected number of path arguments", 4, Iterables.size(result));
524 final Iterator<YangInstanceIdentifier.PathArgument> iterator = result.iterator();
525 final QName list = QName.create("deserializer:test:included", "2016-06-06", "augmented-list");
526 final QName child = QName.create("deserializer:test", "2016-06-06", "augmented-leaf");
529 assertEquals("Not expected path argument",
530 YangInstanceIdentifier.NodeIdentifier.create(list),
533 assertEquals("Not expected path argument",
534 new YangInstanceIdentifier.NodeIdentifierWithPredicates(list, QName.create(list, "list-key"), 100)
540 assertEquals("Not expected path argument",
541 new YangInstanceIdentifier.AugmentationIdentifier(Sets.newHashSet(child)),
544 assertEquals("Not expected path argument",
545 YangInstanceIdentifier.NodeIdentifier.create(child),