Report HTTP status 409 on DATA_MISSING error
[netconf.git] / restconf / restconf-nb-rfc8040 / src / test / java / org / opendaylight / restconf / nb / rfc8040 / utils / parser / YangInstanceIdentifierDeserializerTest.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.restconf.nb.rfc8040.utils.parser;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertTrue;
12 import static org.junit.Assert.fail;
13
14 import com.google.common.collect.Iterables;
15 import com.google.common.collect.Sets;
16 import java.io.FileNotFoundException;
17 import java.util.Iterator;
18 import java.util.LinkedHashMap;
19 import java.util.Map;
20 import java.util.Map.Entry;
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.common.Uint8;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
32 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
33 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
35 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
36 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
37 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
38
39 /**
40  * Unit tests for {@link YangInstanceIdentifierDeserializer}.
41  */
42 public class YangInstanceIdentifierDeserializerTest {
43
44     @Rule
45     public ExpectedException thrown = ExpectedException.none();
46
47     // schema context
48     private SchemaContext schemaContext;
49
50     @Before
51     public void init() throws FileNotFoundException {
52         this.schemaContext =
53                 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/restconf/parser/deserializer"));
54     }
55
56     /**
57      * Test of deserialization <code>String</code> URI with container to
58      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
59      */
60     @Test
61     public void deserializeContainerTest() {
62         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer
63                 .create(this.schemaContext, "deserializer-test:contA");
64
65         assertEquals("Result does not contains expected number of path arguments", 1, Iterables.size(result));
66         assertEquals("Not expected path argument",
67                 NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
68                 result.iterator().next());
69     }
70
71     /**
72      * Test of deserialization <code>String</code> URI with container containing leaf to
73      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
74      */
75     @Test
76     public void deserializeContainerWithLeafTest() {
77         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer
78                 .create(this.schemaContext, "deserializer-test:contA/leaf-A");
79
80         assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
81
82         final Iterator<PathArgument> iterator = result.iterator();
83         assertEquals("Not expected path argument",
84                 NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
85                 iterator.next());
86         assertEquals("Not expected path argument",
87                 NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "leaf-A")),
88                 iterator.next());
89     }
90
91     /**
92      * Test of deserialization <code>String</code> URI with container containing list with leaf list to
93      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
94      */
95     @Test
96     public void deserializeContainerWithListWithLeafListTest() {
97         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer
98                 .create(this.schemaContext, "deserializer-test:contA/list-A=100/leaf-list-AA=instance");
99
100         assertEquals("Result does not contains expected number of path arguments", 5, Iterables.size(result));
101
102         final Iterator<PathArgument> iterator = result.iterator();
103
104         // container
105         assertEquals("Not expected path argument",
106                 NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
107                 iterator.next());
108
109         // list
110         final QName list = QName.create("deserializer:test", "2016-06-06", "list-A");
111         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
112         assertEquals("Not expected path argument", NodeIdentifierWithPredicates.of(
113             list, QName.create(list, "list-key"), 100).toString(), iterator.next().toString());
114
115         // leaf list
116         final QName leafList = QName.create("deserializer:test", "2016-06-06", "leaf-list-AA");
117         assertEquals("Not expected path argument", NodeIdentifier.create(leafList), iterator.next());
118         assertEquals("Not expected path argument", new NodeWithValue<>(leafList, "instance"), iterator.next());
119     }
120
121     /**
122      * Test of deserialization <code>String</code> URI with container containing list with Action to
123      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
124      */
125     @Test
126     public void deserializeContainerWithListWithActionTest() {
127         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(this.schemaContext,
128             "example-actions:interfaces/interface=eth0/reset");
129         assertEquals("Result does not contains expected number of path arguments", 4, Iterables.size(result));
130
131         final Iterator<PathArgument> iterator = result.iterator();
132
133         // container
134         assertEquals("Not expected path argument",
135             NodeIdentifier.create(QName.create("https://example.com/ns/example-actions", "2016-07-07", "interfaces")),
136             iterator.next());
137
138         // list
139         final QName list = QName.create("https://example.com/ns/example-actions", "2016-07-07", "interface");
140         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
141         assertEquals("Not expected path argument",
142             NodeIdentifierWithPredicates.of(list, QName.create(list, "name"), "eth0"), iterator.next());
143
144         // action QName
145         final QName action = QName.create("https://example.com/ns/example-actions", "2016-07-07", "reset");
146         assertEquals("Not expected path argument", NodeIdentifier.create(action),
147             iterator.next());
148     }
149
150     /**
151      * Test of deserialization <code>String</code> URI containing list with no keys to
152      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
153      */
154     @Test
155     public void deserializeListWithNoKeysTest() {
156         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(this.schemaContext,
157             "deserializer-test:list-no-key");
158
159         assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
160
161         final Iterator<PathArgument> iterator = result.iterator();
162         final QName list = QName.create("deserializer:test", "2016-06-06", "list-no-key");
163
164         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
165         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
166     }
167
168     /**
169      * Test of deserialization <code>String</code> URI containing list with one key to
170      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
171      */
172     @Test
173     public void deserializeListWithOneKeyTest() {
174         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(this.schemaContext,
175             "deserializer-test:list-one-key=value");
176
177         assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
178
179         final Iterator<PathArgument> iterator = result.iterator();
180         final QName list = QName.create("deserializer:test", "2016-06-06", "list-one-key");
181
182         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
183         assertEquals("Not expected path argument",
184             NodeIdentifierWithPredicates.of(list, QName.create(list, "name"), "value"), iterator.next());
185     }
186
187     /**
188      * Test of deserialization <code>String</code> URI containing list with multiple keys to
189      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
190      */
191     @Test
192     public void deserializeListWithMultipleKeysTest() {
193         final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
194         final Map<QName, Object> values = new LinkedHashMap<>();
195         values.put(QName.create(list, "name"), "value");
196         values.put(QName.create(list, "number"), 100);
197         values.put(QName.create(list, "enabled"), false);
198
199         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(this.schemaContext,
200             "deserializer-test:list-multiple-keys=value,100,false");
201
202         assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
203
204         final Iterator<PathArgument> iterator = result.iterator();
205
206         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
207         assertEquals("Not expected path argument", NodeIdentifierWithPredicates.of(list, values).toString(),
208                 iterator.next().toString());
209     }
210
211     /**
212      * Test of deserialization <code>String</code> URI containing leaf list to
213      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
214      */
215     @Test
216     public void deserializeLeafListTest() {
217         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(this.schemaContext,
218             "deserializer-test:leaf-list-0=true");
219
220         assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
221
222         final Iterator<PathArgument> iterator = result.iterator();
223         final QName leafList = QName.create("deserializer:test", "2016-06-06", "leaf-list-0");
224
225         assertEquals("Not expected path argument", new NodeIdentifier(leafList), iterator.next());
226         assertEquals("Not expected path argument",
227                 new NodeWithValue<>(leafList, true).toString(), iterator.next().toString());
228     }
229
230     /**
231      * Test when empty <code>String</code> is supplied as an input. Test is expected to return empty result.
232      */
233     @Test
234     public void deserializeEmptyDataTest() {
235         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(this.schemaContext, "");
236         assertTrue("Empty result expected", Iterables.isEmpty(result));
237     }
238
239     /**
240      * Test of deserialization <code>String</code> URI with identifiers separated by multiple slashes to
241      * {@code Iterable<YangInstanceIdentifier.PathArgument>}.
242      */
243     @Test
244     public void deserializeMultipleSlashesTest() {
245         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer
246                 .create(this.schemaContext, "deserializer-test:contA////list-A=40//list-key");
247
248         assertEquals("Result does not contains expected number of path arguments", 4, Iterables.size(result));
249
250         final Iterator<PathArgument> iterator = result.iterator();
251
252         // container
253         assertEquals("Not expected path argument",
254                 NodeIdentifier.create(QName.create("deserializer:test", "2016-06-06", "contA")),
255                 iterator.next());
256
257         // list
258         final QName list = QName.create("deserializer:test", "2016-06-06", "list-A");
259         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
260         assertEquals("Not expected path argument",
261                 NodeIdentifierWithPredicates.of(list, QName.create(list, "list-key"), 40).toString(),
262                 iterator.next().toString());
263
264         // leaf
265         assertEquals("Not expected path argument",
266                 new NodeIdentifier(QName.create("deserializer:test", "2016-06-06", "list-key")), iterator.next());
267     }
268
269     /**
270      * Negative test when supplied <code>SchemaContext</code> is null. Test is expected to fail with
271      * <code>NullPointerException</code>.
272      */
273     @Test
274     public void deserializeNullSchemaContextNegativeTest() {
275         this.thrown.expect(NullPointerException.class);
276         YangInstanceIdentifierDeserializer.create(null, "deserializer-test:contA");
277     }
278
279     /**
280      * Negative test when supplied <code>String</code> data to deserialize is null. Test is expected to fail with
281      * <code>NullPointerException</code>.
282      */
283     @Test
284     public void nullDataNegativeNegativeTest() {
285         this.thrown.expect(NullPointerException.class);
286         YangInstanceIdentifierDeserializer.create(this.schemaContext, null);
287     }
288
289     /**
290      * Negative test when identifier is not followed by slash or equals. Test is expected to fail with
291      * <code>RestconfDocumentedException</code>.
292      */
293     @Test
294     public void deserializeBadCharMissingSlashOrEqualNegativeTest() {
295         this.thrown.expect(RestconfDocumentedException.class);
296         YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:cont*leaf-A");
297     }
298
299     /**
300      * Negative test of validating identifier when there is a slash after container without next identifier. Test
301      * is expected to fail with <code>RestconfDocumentedException</code>.
302      */
303     @Test
304     public void validArgIdentifierContainerEndsWithSlashNegativeTest() {
305         this.thrown.expect(RestconfDocumentedException.class);
306         YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA/");
307     }
308
309     /**
310      * Negative test of validating identifier when there are multiple slashes after container without next identifier.
311      * Test is expected to fail with <code>RestconfDocumentedException</code>.
312      */
313     @Test
314     public void validArgIdentifierContainerEndsWithMultipleSlashesNegativeTest() {
315         this.thrown.expect(RestconfDocumentedException.class);
316         YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA///");
317     }
318
319     /**
320      * Negative test of validating identifier when there is a slash after list key values without next identifier. Test
321      * is expected to fail with <code>RestconfDocumentedException</code>.
322      */
323     @Test
324     public void validArgIdentifierListEndsWithSlashLNegativeTest() {
325         this.thrown.expect(RestconfDocumentedException.class);
326         YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:list-one-key=value/");
327     }
328
329     /**
330      * Negative test of validating identifier when there are multiple slashes after list key values without next
331      * identifier. Test is expected to fail with <code>RestconfDocumentedException</code>.
332      */
333     @Test
334     public void validArgIdentifierListEndsWithSlashesNegativeTest() {
335         this.thrown.expect(RestconfDocumentedException.class);
336         YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:list-one-key=value//");
337     }
338
339     /**
340      * Negative test of creating <code>QName</code> when identifier is empty (example: '/'). Test is expected to fail
341      * with <code>RestconfDocumentedException</code>.
342      */
343     @Test
344     public void prepareQnameEmptyIdentifierNegativeTest() {
345         this.thrown.expect(RestconfDocumentedException.class);
346         YangInstanceIdentifierDeserializer.create(this.schemaContext, "/");
347     }
348
349     /**
350      * Negative test of creating <code>QName</code> when in identifier there is another sign than colon or equals.
351      * Test is expected to fail with <code>RestconfDocumentedException</code>.
352      */
353     @Test
354     public void prepareQnameBuildPathNegativeTest() {
355         this.thrown.expect(RestconfDocumentedException.class);
356         YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test*contA");
357     }
358
359     /**
360      * Negative test of creating <code>QName</code> when it is not possible to find module for specified prefix. Test is
361      * expected to fail with <code>RestconfDocumentedException</code>.
362      */
363     @Test
364     public void prepareQnameNotExistingPrefixNegativeTest() {
365         this.thrown.expect(RestconfDocumentedException.class);
366         YangInstanceIdentifierDeserializer.create(this.schemaContext, "not-existing:contA");
367     }
368
369     /**
370      * Negative test of creating <code>QName</code> when after prefix and colon there is not parsable identifier as
371      * local name. Test is expected to fail with <code>RestconfDocumentedException</code>.
372      */
373     @Test
374     public void prepareQnameNotValidPrefixAndLocalNameNegativeTest() {
375         this.thrown.expect(RestconfDocumentedException.class);
376         YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:*not-parsable-identifier");
377     }
378
379     /**
380      * Negative test of creating <code>QName</code> when data ends after prefix and colon. Test is expected to fail
381      * with <code>StringIndexOutOfBoundsException</code>.
382      */
383     @Test
384     public void prepareQnameErrorParsingNegativeTest() {
385         this.thrown.expect(StringIndexOutOfBoundsException.class);
386         YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:");
387     }
388
389     /**
390      * Negative test of creating <code>QName</code> when after identifier and colon there is node name of unknown
391      * node in current container. Test is expected to fail with <code>RestconfDocumentedException</code> and error
392      * type, error tag and error status code are compared to expected values.
393      */
394     @Test
395     public void prepareQnameNotValidContainerNameNegativeTest() {
396         try {
397             YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:contA/leafB");
398             fail("Test should fail due to unknown child node in container");
399         } catch (final RestconfDocumentedException e) {
400             assertEquals("Not expected error type",
401                     RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
402             assertEquals("Not expected error tag",
403                     RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
404         }
405     }
406
407     /**
408      * Negative test of creating <code>QName</code> when after identifier and equals there is node name of unknown
409      * node in current list. Test is expected to fail with <code>RestconfDocumentedException</code> and error
410      * type, error tag and error status code are compared to expected values.
411      */
412     @Test
413     public void prepareQnameNotValidListNameNegativeTest() {
414         try {
415             YangInstanceIdentifierDeserializer
416                     .create(this.schemaContext, "deserializer-test:list-no-key/disabled=false");
417             fail("Test should fail due to unknown child node in list");
418         } catch (final RestconfDocumentedException e) {
419             assertEquals("Not expected error type",
420                     RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
421             assertEquals("Not expected error tag",
422                     RestconfError.ErrorTag.DATA_MISSING, e.getErrors().get(0).getErrorTag());
423         }
424     }
425
426     /**
427      * Negative test of getting next identifier when current node is keyed entry. Test is expected to
428      * fail with <code>RestconfDocumentedException</code>.
429      */
430     @Test
431     public void prepareIdentifierNotKeyedEntryNegativeTest() {
432         this.thrown.expect(RestconfDocumentedException.class);
433         YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:list-one-key");
434     }
435
436     /**
437      * Negative test when there is a comma also after the last key. Test is expected to fail with
438      * <code>RestconfDocumentedException</code>.
439      */
440     @Test
441     public void deserializeKeysEndsWithComaNegativeTest() {
442         this.thrown.expect(RestconfDocumentedException.class);
443         YangInstanceIdentifierDeserializer.create(this.schemaContext,
444                 "deserializer-test:list-multiple-keys=value,100,false,");
445     }
446
447     /**
448      * Positive when not all keys of list are encoded. The missing keys should be considered to has empty
449      * <code>String</code> values. Also value of next leaf must not be considered to be missing key value.
450      */
451     @Test
452     public void notAllListKeysEncodedPositiveTest() {
453         final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
454         final Map<QName, Object> values = new LinkedHashMap<>();
455         values.put(QName.create(list, "name"), ":foo");
456         values.put(QName.create(list, "number"), "");
457         values.put(QName.create(list, "enabled"), "");
458
459         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(
460                 this.schemaContext, "deserializer-test:list-multiple-keys=%3Afoo,,/string-value");
461
462         assertEquals("Result does not contains expected number of path arguments", 3, Iterables.size(result));
463
464         final Iterator<PathArgument> iterator = result.iterator();
465
466         // list
467         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
468         assertEquals("Not expected path argument", NodeIdentifierWithPredicates.of(list, values).toString(),
469                 iterator.next().toString());
470
471         // leaf
472         assertEquals("Not expected path argument",
473                 new NodeIdentifier(QName.create("deserializer:test", "2016-06-06", "string-value")), iterator.next());
474     }
475
476     /**
477      * Negative test when not all keys of list are encoded and it is not possible to consider missing keys to be empty.
478      * Test is expected to fail with <code>RestconfDocumentedException</code> and error type, error tag and error
479      * status code are compared to expected values.
480      */
481     @Test
482     public void notAllListKeysEncodedNegativeTest() {
483         try {
484             YangInstanceIdentifierDeserializer.create(
485                     this.schemaContext, "deserializer-test:list-multiple-keys=%3Afoo/string-value");
486             fail("Test should fail due to missing list key values");
487         } catch (final RestconfDocumentedException e) {
488             assertEquals("Not expected error type",
489                     RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
490             assertEquals("Not expected error tag",
491                     RestconfError.ErrorTag.MISSING_ATTRIBUTE, e.getErrors().get(0).getErrorTag());
492             assertEquals("Not expected error status code",
493                     400, e.getErrors().get(0).getErrorTag().getStatusCode());
494         }
495     }
496
497     /**
498      * Test URI with list where key value starts with, ends with or contains percent encoded characters.The encoded
499      * value should be complete also with not percent-encoded parts.
500      */
501     @Test
502     public void percentEncodedKeyEndsWithNoPercentEncodedChars() {
503         final String URI = "deserializer-test:list-multiple-keys=%3Afoo,1,true";
504         final YangInstanceIdentifier result = YangInstanceIdentifier.create(
505                 YangInstanceIdentifierDeserializer.create(this.schemaContext, URI));
506
507         final Iterator<Entry<QName, Object>> resultListKeys =
508                 ((NodeIdentifierWithPredicates)result.getLastPathArgument()).entrySet().iterator();
509
510         assertEquals(":foo", resultListKeys.next().getValue());
511         assertEquals(Uint8.ONE, resultListKeys.next().getValue());
512         assertEquals(true, resultListKeys.next().getValue());
513     }
514
515     /**
516      * Positive test when all keys of list can be considered to be empty <code>String</code>.
517      */
518     @Test
519     public void deserializeAllKeysEmptyTest() {
520         final QName list = QName.create("deserializer:test", "2016-06-06", "list-multiple-keys");
521         final Map<QName, Object> values = new LinkedHashMap<>();
522         values.put(QName.create(list, "name"), "");
523         values.put(QName.create(list, "number"), "");
524         values.put(QName.create(list, "enabled"), "");
525
526         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer
527                 .create(this.schemaContext, "deserializer-test:list-multiple-keys=,,");
528
529         assertEquals("Result does not contains expected number of path arguments", 2, Iterables.size(result));
530
531         final Iterator<PathArgument> iterator = result.iterator();
532
533         assertEquals("Not expected path argument", NodeIdentifier.create(list), iterator.next());
534         assertEquals("Not expected path argument", NodeIdentifierWithPredicates.of(list, values).toString(),
535                 iterator.next().toString());
536     }
537
538     /**
539      * Negative test of deserialization when for leaf list there is no specified instance value.
540      * <code>RestconfDocumentedException</code> is expected and error type, error tag and error status code are
541      * compared to expected values.
542      */
543     @Test
544     public void leafListMissingKeyNegativeTest() {
545         try {
546             YangInstanceIdentifierDeserializer.create(this.schemaContext, "deserializer-test:leaf-list-0=");
547             fail("Test should fail due to missing instance value");
548         } catch (final RestconfDocumentedException e) {
549             assertEquals("Not expected error type",
550                     RestconfError.ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
551             assertEquals("Not expected error tag",
552                     RestconfError.ErrorTag.MISSING_ATTRIBUTE, e.getErrors().get(0).getErrorTag());
553             assertEquals("Not expected error status code",
554                     400, e.getErrors().get(0).getErrorTag().getStatusCode());
555         }
556     }
557
558     /**
559      * Positive test of deserialization when parts of input URI <code>String</code> are defined in another module.
560      */
561     @Test
562     public void deserializePartInOtherModuleTest() {
563         final Iterable<PathArgument> result = YangInstanceIdentifierDeserializer.create(this.schemaContext,
564             "deserializer-test-included:augmented-list=100/augmented-leaf");
565
566         assertEquals("Result does not contains expected number of path arguments", 4, Iterables.size(result));
567
568         final Iterator<PathArgument> iterator = result.iterator();
569         final QName list = QName.create("deserializer:test:included", "2016-06-06", "augmented-list");
570         final QName child = QName.create("deserializer:test", "2016-06-06", "augmented-leaf");
571
572         // list
573         assertEquals("Not expected path argument",
574                 NodeIdentifier.create(list),
575                 iterator.next());
576
577         assertEquals("Not expected path argument",
578                 NodeIdentifierWithPredicates.of(list, QName.create(list, "list-key"), 100).toString(),
579                 iterator.next().toString());
580
581         // augmented leaf
582         assertEquals("Not expected path argument", new AugmentationIdentifier(Sets.newHashSet(child)), iterator.next());
583         assertEquals("Not expected path argument", NodeIdentifier.create(child), iterator.next());
584     }
585 }