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
8 package org.opendaylight.restconf.nb.rfc8040.utils.parser;
10 import static org.junit.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
12 import static org.junit.jupiter.api.Assertions.assertThrows;
14 import com.google.common.collect.ImmutableMap;
15 import java.text.ParseException;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.junit.jupiter.api.Test;
19 import org.opendaylight.restconf.api.ApiPath;
20 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
21 import org.opendaylight.restconf.common.errors.RestconfError;
22 import org.opendaylight.restconf.server.api.DatabindContext;
23 import org.opendaylight.restconf.server.spi.ApiPathNormalizer;
24 import org.opendaylight.restconf.server.spi.ApiPathNormalizer.Path.Data;
25 import org.opendaylight.yangtools.yang.common.ErrorTag;
26 import org.opendaylight.yangtools.yang.common.ErrorType;
27 import org.opendaylight.yangtools.yang.common.QName;
28 import org.opendaylight.yangtools.yang.common.Uint32;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
32 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
35 * Unit tests for {@link YangInstanceIdentifierSerializer}.
37 class YangInstanceIdentifierSerializerTest {
38 private static final @NonNull DatabindContext DATABIND = DatabindContext.ofModel(
39 YangParserTestUtils.parseYangResourceDirectory("/restconf/parser/serializer"));
40 private static final YangInstanceIdentifierSerializer SERIALIZER = new YangInstanceIdentifierSerializer(DATABIND);
43 * Positive test of serialization of <code>YangInstanceIdentifier</code> containing container node to
44 * <code>String</code>. Returned <code>String</code> is compared to have expected value.
47 void serializeContainerTest() {
48 assertEquals("serializer-test:contA", SERIALIZER.serializePath(
49 YangInstanceIdentifier.of(QName.create("serializer:test", "2016-06-06", "contA"))));
53 * Positive test of serialization of <code>YangInstanceIdentifier</code> containing container with leaf node to
54 * <code>String</code>. Returned <code>String</code> is compared to have expected value.
57 void serializeContainerWithLeafTest() {
58 assertEquals("serializer-test:contA/leaf-A", SERIALIZER.serializePath(
59 YangInstanceIdentifier.of(
60 QName.create("serializer:test", "2016-06-06", "contA"),
61 QName.create("serializer:test", "2016-06-06", "leaf-A"))));
65 * Positive test of serialization of <code>YangInstanceIdentifier</code> containing container with list with leaf
66 * list node to <code>String</code>. Returned <code>String</code> is compared to have expected value.
69 void serializeContainerWithListWithLeafListTest() {
70 final var list = QName.create("serializer:test", "2016-06-06", "list-A");
71 final var leafList = QName.create("serializer:test", "2016-06-06", "leaf-list-AA");
73 assertEquals("serializer-test:contA/list-A=100/leaf-list-AA=instance", SERIALIZER.serializePath(
74 YangInstanceIdentifier.builder()
75 .node(QName.create("serializer:test", "2016-06-06", "contA"))
77 .node(NodeIdentifierWithPredicates.of(list, QName.create(list, "list-key"), 100))
79 .node(new NodeWithValue<>(leafList, "instance"))
84 * Positive test of serialization of <code>YangInstanceIdentifier</code> to <code>String</code> when serialized
85 * <code>YangInstanceIdentifier</code> contains list with no keys. Returned <code>String</code> is compared to have
89 void serializeListWithNoKeysTest() {
90 assertEquals("serializer-test:list-no-key", SERIALIZER.serializePath(
91 YangInstanceIdentifier.of(
92 QName.create("serializer:test", "2016-06-06", "list-no-key"),
93 QName.create("serializer:test", "2016-06-06", "list-no-key"))));
97 * Positive test of serialization of <code>YangInstanceIdentifier</code> to <code>String</code> when serialized
98 * <code>YangInstanceIdentifier</code> contains a keyed list, but the path argument does not specify them. Returned
99 * <code>String</code> is compared to have expected value.
102 void serializeMapWithNoKeysTest() {
103 assertEquals("serializer-test:list-one-key", SERIALIZER.serializePath(
104 YangInstanceIdentifier.builder()
105 .node(QName.create("serializer:test", "2016-06-06", "list-one-key"))
106 .nodeWithKey(QName.create("serializer:test", "2016-06-06", "list-one-key"), Map.of())
111 * Positive test of serialization of <code>YangInstanceIdentifier</code> to <code>String</code> when serialized
112 * <code>YangInstanceIdentifier</code> contains list with one key. Returned <code>String</code> is compared to have
116 void serializeMapWithOneKeyTest() {
117 assertEquals("serializer-test:list-one-key=value", SERIALIZER.serializePath(
118 YangInstanceIdentifier.builder()
119 .node(QName.create("serializer:test", "2016-06-06", "list-one-key"))
120 .nodeWithKey(QName.create("serializer:test", "2016-06-06", "list-one-key"),
121 QName.create("serializer:test", "2016-06-06", "list-one-key"), "value")
126 * Positive test of serialization of <code>YangInstanceIdentifier</code> to <code>String</code> when serialized
127 * <code>YangInstanceIdentifier</code> contains list with multiple keys. Returned <code>String</code> is compared
128 * to have expected value.
131 void serializeMapWithMultipleKeysTest() {
132 final var list = QName.create("serializer:test", "2016-06-06", "list-multiple-keys");
134 assertEquals("serializer-test:list-multiple-keys=value-1,2,true", SERIALIZER.serializePath(
135 YangInstanceIdentifier.builder()
137 .nodeWithKey(list, ImmutableMap.of(
138 QName.create(list, "name"), "value-1",
139 QName.create(list, "number"), "2",
140 QName.create(list, "enabled"), "true"))
145 * Positive test of serialization of <code>YangInstanceIdentifier</code> to <code>String</code> when serialized
146 * <code>YangInstanceIdentifier</code> contains leaf node. Returned <code>String</code> is compared to have
150 void serializeLeafTest() {
151 assertEquals("serializer-test:leaf-0", SERIALIZER.serializePath(
152 YangInstanceIdentifier.of(QName.create("serializer:test", "2016-06-06", "leaf-0"))));
156 * Positive test of serialization of <code>YangInstanceIdentifier</code> to <code>String</code> when serialized
157 * <code>YangInstanceIdentifier</code> contains leaf list node. Returned <code>String</code> is compared to have
161 void serializeLeafListTest() {
162 assertEquals("serializer-test:leaf-list-0=true", SERIALIZER.serializePath(
163 YangInstanceIdentifier.builder()
164 .node(QName.create("serializer:test", "2016-06-06", "leaf-list-0"))
165 .node(new NodeWithValue<>(QName.create("serializer:test", "2016-06-06", "leaf-list-0"), Boolean.TRUE))
170 * Negative test of serialization <code>YangInstanceIdentifier</code> to <code>String</code> when
171 * <code>SchemaContext</code> is <code>null</code>. Test is expected to fail with
172 * <code>NullPointerException</code>.
175 void serializeNullSchemaContextNegativeTest() {
176 assertThrows(NullPointerException.class, () -> new YangInstanceIdentifierSerializer(null));
180 * Negative test of serialization <code>YangInstanceIdentifier</code> to <code>String</code> when supplied
181 * <code>YangInstanceIdentifier</code> is <code>null</code>. Test is expected to fail with
182 * <code>NullPointerException</code>.
185 void serializeNullDataNegativeTest() {
186 assertThrows(NullPointerException.class, () -> SERIALIZER.serializePath(null));
190 * Test of serialization <code>YangInstanceIdentifier</code> to <code>String</code> when supplied
191 * <code>YangInstanceIdentifier</code> is <code>YangInstanceIdentifier.EMPTY</code>.
192 * Empty <code>String</code> is expected as a return value.
195 void serializeEmptyDataTest() {
196 assertEquals("", SERIALIZER.serializePath(YangInstanceIdentifier.of()));
200 * Negative test when it is not possible to find child node of current node. Test is expected to fail with
201 * {@link RestconfDocumentedException} and error message is compared to expected error message.
204 void serializeChildNodeNotFoundNegativeTest() {
205 final var error = assertError(YangInstanceIdentifier.of(
206 QName.create("serializer:test", "2016-06-06", "contA"),
207 QName.create("serializer:test", "2016-06-06", "not-existing-leaf")));
209 Invalid input '/(serializer:test?revision=2016-06-06)contA/not-existing-leaf': schema for argument \
210 '(serializer:test?revision=2016-06-06)not-existing-leaf' (after 'serializer-test:contA') not found""",
211 error.getErrorMessage());
212 assertEquals(ErrorType.APPLICATION, error.getErrorType());
213 assertEquals(ErrorTag.UNKNOWN_ELEMENT, error.getErrorTag());
217 * Test if URIs with percent encoded characters are all correctly serialized.
220 void serializePercentEncodingTest() {
221 assertEquals("serializer-test:list-one-key=foo%3Afoo bar%2Ffoo%2Cbar%2F%27bar%27", SERIALIZER.serializePath(
222 YangInstanceIdentifier.builder()
223 .node(QName.create("serializer:test", "2016-06-06", "list-one-key"))
224 .nodeWithKey(QName.create("serializer:test", "2016-06-06", "list-one-key"),
225 QName.create("serializer:test", "2016-06-06", "list-one-key"), "foo:foo bar/foo,bar/'bar'")
230 * Test if URIs with no percent encoded characters are correctly serialized. Input should be untouched.
233 void serializeNoPercentEncodingTest() {
234 assertEquals("serializer-test:list-one-key=foo\"b\"bar", SERIALIZER.serializePath(
235 YangInstanceIdentifier.builder()
236 .node(QName.create("serializer:test", "2016-06-06", "list-one-key"))
237 .nodeWithKey(QName.create("serializer:test", "2016-06-06", "list-one-key"),
238 QName.create("serializer:test", "2016-06-06", "list-one-key"), "foo\"b\"bar")
243 * Test of serialization when nodes in input <code>YangInstanceIdentifier</code> are defined in two different
244 * modules by using augmentation.
247 void serializeIncludedNodesTest() {
248 final var list = QName.create("serializer:test:included", "2016-06-06", "augmented-list");
249 final var child = QName.create("serializer:test", "2016-06-06", "augmented-leaf");
251 assertEquals("serializer-test-included:augmented-list=100/serializer-test:augmented-leaf",
252 SERIALIZER.serializePath(YangInstanceIdentifier.builder()
254 .node(NodeIdentifierWithPredicates.of(list, QName.create(list, "list-key"), 100))
260 * Test of serialization when nodes in input <code>YangInstanceIdentifier</code> are defined in two different
261 * modules by using augmentation. Augmented node in data supplied for serialization has wrong namespace.
262 * <code>RestconfDocumentedException</code> is expected because augmented node is defined in other module than its
263 * parent and will not be found.
266 void serializeIncludedNodesSerializationTest() {
267 final var list = QName.create("serializer:test:included", "2016-06-06", "augmented-list");
269 final var error = assertError(YangInstanceIdentifier.builder()
271 .node(NodeIdentifierWithPredicates.of(list, QName.create(list, "list-key"), 100))
272 // child should has different namespace
273 .node(QName.create("serializer:test:included", "2016-06-06", "augmented-leaf"))
276 Invalid input '/(serializer:test:included?revision=2016-06-06)augmented-list/augmented-list[{(\
277 serializer:test:included?revision=2016-06-06)list-key=100}]/augmented-leaf': schema for argument \
278 '(serializer:test:included?revision=2016-06-06)augmented-leaf' (after \
279 'serializer-test-included:augmented-list=100') not found""", error.getErrorMessage());
280 assertEquals(ErrorType.APPLICATION, error.getErrorType());
281 assertEquals(ErrorTag.UNKNOWN_ELEMENT, error.getErrorTag());
285 * Positive test of deserialization URI <code>String</code> to <code>YangInstanceIdentifier</code> and
286 * serialization of <code>YangInstanceIdentifier</code> to <code>String</code> when original <code>String</code>
287 * URI contains list identifier and leaf identifier.
290 void codecListAndLeafTest() {
291 final var dataYangII = assertNormalized("list-test:top/list1=%2C%27\"%3A\"%20%2F,,foo/list2=a,b/result");
292 final var list1 = QName.create("list:test", "2016-04-29", "list1");
293 final var list2 = QName.create("list:test", "2016-04-29", "list2");
294 assertEquals(YangInstanceIdentifier.builder()
295 .node(QName.create("list:test", "2016-04-29", "top"))
297 .nodeWithKey(list1, Map.<QName, Object>of(
298 QName.create(list1, "key1"), ",'\":\" /",
299 QName.create(list1, "key2"), "",
300 QName.create(list1, "key3"), "foo"))
302 .nodeWithKey(list2, Map.<QName, Object>of(
303 QName.create(list2, "key4"), "a",
304 QName.create(list2, "key5"), "b"))
305 .node(QName.create("list:test", "2016-04-29", "result"))
306 .build(), dataYangII);
307 assertEquals("list-test:top/list1=%2C%27\"%3A\" %2F,,foo/list2=a,b/result",
308 SERIALIZER.serializePath(dataYangII));
312 * Positive test of deserialization URI <code>String</code> to <code>YangInstanceIdentifier</code> and
313 * serialization of <code>YangInstanceIdentifier</code> to <code>String</code> when original <code>String</code>
314 * URI contains leaf list identifier.
317 void codecLeafListTest() {
318 final var str = "list-test:top/Y=4";
319 final var dataYangII = assertNormalized(str);
320 final var y = QName.create("list:test", "2016-04-29", "Y");
321 assertEquals(YangInstanceIdentifier.builder()
322 .node(QName.create("list:test", "2016-04-29", "top"))
324 .node(new NodeWithValue<>(y, Uint32.valueOf(4)))
325 .build(), dataYangII);
326 assertEquals(str, SERIALIZER.serializePath(dataYangII));
330 * Positive test of serialization of an empty {@link YangInstanceIdentifier}.
333 void codecDeserializeAndSerializeEmptyTest() {
334 assertEquals("", SERIALIZER.serializePath(YangInstanceIdentifier.of()));
337 private static YangInstanceIdentifier assertNormalized(final String str) {
339 return assertInstanceOf(Data.class, new ApiPathNormalizer(DATABIND).normalizePath(ApiPath.parse(str)))
341 } catch (ParseException e) {
342 throw new AssertionError(e);
346 private static RestconfError assertError(final YangInstanceIdentifier path) {
347 final var ex = assertThrows(RestconfDocumentedException.class, () -> SERIALIZER.serializePath(path));
348 final var errors = ex.getErrors();
349 assertEquals(1, errors.size());
350 return errors.get(0);