33fc50f7aec24d1e471cba14c5c22fb4ea83bec6
[netconf.git] / restconf / restconf-nb / src / test / java / org / opendaylight / restconf / nb / rfc8040 / utils / parser / AbstractFieldsTranslatorTest.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.assertNotNull;
12 import static org.junit.Assert.assertThrows;
13
14 import java.text.ParseException;
15 import java.util.List;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.junit.Before;
18 import org.junit.Test;
19 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
20 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
21 import org.opendaylight.restconf.nb.rfc8040.FieldsParam;
22 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
23 import org.opendaylight.yangtools.yang.common.ErrorTag;
24 import org.opendaylight.yangtools.yang.common.ErrorType;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.common.QNameModule;
27 import org.opendaylight.yangtools.yang.common.Revision;
28 import org.opendaylight.yangtools.yang.common.XMLNamespace;
29 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
30 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
31 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
32
33 public abstract class AbstractFieldsTranslatorTest<T> {
34     private static final QNameModule Q_NAME_MODULE_JUKEBOX = QNameModule.create(
35         XMLNamespace.of("http://example.com/ns/example-jukebox"), Revision.of("2015-04-04"));
36     private static final QNameModule Q_NAME_MODULE_TEST_SERVICES = QNameModule.create(
37         XMLNamespace.of("tests:test-services"), Revision.of("2019-03-25"));
38     private static final QNameModule Q_NAME_MODULE_AUGMENTED_JUKEBOX = QNameModule.create(
39         XMLNamespace.of("http://example.com/ns/augmented-jukebox"), Revision.of("2016-05-05"));
40
41     private InstanceIdentifierContext identifierJukebox;
42     private InstanceIdentifierContext identifierTestServices;
43
44     // FIXME: remove all this mocking -- just parse the underlying model and be done with it
45
46     // container jukebox
47     private static final QName JUKEBOX_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "jukebox");
48
49     // container player
50     protected static final QName PLAYER_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "player");
51
52     // container library
53     protected static final QName LIBRARY_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "library");
54
55     // list artist
56     protected static final QName ARTIST_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "artist");
57
58     // container augmented library
59     protected static final QName AUGMENTED_LIBRARY_Q_NAME = QName.create(Q_NAME_MODULE_AUGMENTED_JUKEBOX,
60             "augmented-library");
61
62     // leaf speed
63     protected static final QName SPEED_Q_NAME = QName.create(Q_NAME_MODULE_AUGMENTED_JUKEBOX, "speed");
64
65     // list album
66     public static final QName ALBUM_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "album");
67
68     // leaf name
69     protected static final QName NAME_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "name");
70
71     // container test data
72     private static final QName TEST_DATA_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "test-data");
73
74     // list services
75     protected static final QName SERVICES_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "services");
76
77     // leaf type-of-service
78     protected static final QName TYPE_OF_SERVICE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "type-of-service");
79
80     // list instance
81     protected static final QName INSTANCE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "instance");
82
83     // leaf instance-name
84     protected static final QName INSTANCE_NAME_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "instance-name");
85
86     // leaf provider
87     protected static final QName PROVIDER_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "provider");
88
89     // container next-data
90     protected static final QName NEXT_DATA_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "next-data");
91
92     // leaf next-service
93     protected static final QName NEXT_SERVICE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "next-service");
94
95     // leaf-list protocols
96     protected static final QName PROTOCOLS_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "protocols");
97
98     @Before
99     public void setUp() throws Exception {
100         final EffectiveModelContext schemaContextJukebox =
101                 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/jukebox"));
102         identifierJukebox = InstanceIdentifierContext.ofStack(
103             SchemaInferenceStack.ofDataTreePath(schemaContextJukebox, JUKEBOX_Q_NAME));
104
105         final EffectiveModelContext schemaContextTestServices =
106                 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/test-services"));
107         identifierTestServices = InstanceIdentifierContext.ofStack(
108             SchemaInferenceStack.ofDataTreePath(schemaContextTestServices, TEST_DATA_Q_NAME));
109     }
110
111     protected abstract List<T> translateFields(InstanceIdentifierContext context, FieldsParam fields);
112
113     /**
114      * Test parse fields parameter containing only one child selected.
115      */
116     @Test
117     public void testSimplePath() {
118         final var result = translateFields(identifierJukebox, assertFields("library"));
119         assertNotNull(result);
120         assertSimplePath(result);
121     }
122
123     protected abstract void assertSimplePath(@NonNull List<T> result);
124
125     /**
126      * Test parse fields parameter containing two child nodes selected.
127      */
128     @Test
129     public void testDoublePath() {
130         final var result = translateFields(identifierJukebox, assertFields("library;player"));
131         assertNotNull(result);
132         assertDoublePath(result);
133     }
134
135     protected abstract void assertDoublePath(@NonNull List<T> result);
136
137     /**
138      * Test parse fields parameter containing sub-children selected delimited by slash.
139      */
140     @Test
141     public void testSubPath() {
142         final var result = translateFields(identifierJukebox, assertFields("library/artist/album/name"));
143         assertNotNull(result);
144         assertSubPath(result);
145     }
146
147     protected abstract void assertSubPath(@NonNull List<T> result);
148
149     /**
150      * Test parse fields parameter containing sub-children selected delimited by parenthesis.
151      */
152     @Test
153     public void testChildrenPath() {
154         final var result = translateFields(identifierJukebox, assertFields("library(artist(album(name)))"));
155         assertNotNull(result);
156         assertChildrenPath(result);
157     }
158
159     protected abstract void assertChildrenPath(@NonNull List<T> result);
160
161     /**
162      * Test parse fields parameter when augmentation with different namespace is used.
163      */
164     @Test
165     public void testNamespace() {
166         final var result = translateFields(identifierJukebox, assertFields("augmented-jukebox:augmented-library"));
167         assertNotNull(result);
168         assertNamespace(result);
169     }
170
171     protected abstract void assertNamespace(@NonNull List<T> result);
172
173     /**
174      * Testing of fields parameter parsing when multiple nodes are wrapped in brackets and these nodes are not
175      * direct children of parent node - multiple children which are constructed using '/'.
176      */
177     @Test
178     public void testMultipleChildren1() {
179         final var result = translateFields(identifierTestServices,
180             assertFields("services(type-of-service;instance/instance-name;instance/provider)"));
181         assertNotNull(result);
182         assertMultipleChildren1(result);
183     }
184
185     protected abstract void assertMultipleChildren1(@NonNull List<T> result);
186
187     /**
188      * Testing of fields parameter parsing when multiple nodes are wrapped in brackets and these nodes are not
189      * direct children of parent node - one of children nodes is typed using brackets, other is constructed using '/'.
190      */
191     @Test
192     public void testMultipleChildren2() {
193         final var result = translateFields(identifierTestServices,
194             assertFields("services(type-of-service;instance(instance-name;provider))"));
195         assertNotNull(result);
196         assertMultipleChildren2(result);
197     }
198
199     protected abstract void assertMultipleChildren2(@NonNull List<T> result);
200
201     /**
202      * Testing of fields parameter parsing when multiple nodes are wrapped in brackets and these nodes are not
203      * direct children of parent node - multiple children with different parent nodes.
204      */
205     @Test
206     public void testMultipleChildren3() {
207         final var result = translateFields(identifierTestServices,
208             assertFields("services(instance/instance-name;type-of-service;next-data/next-service)"));
209         assertNotNull(result);
210         assertMultipleChildren3(result);
211     }
212
213     protected abstract void assertMultipleChildren3(@NonNull List<T> result);
214
215     @Test
216     public void testAugmentedChild() {
217         final var result = translateFields(identifierJukebox, assertFields("player/augmented-jukebox:speed"));
218         assertNotNull(result);
219         assertAugmentedChild(result);
220     }
221
222     protected abstract void assertAugmentedChild(@NonNull List<T> result);
223
224     @Test
225     public void testListFieldUnderList() {
226         final var result = translateFields(identifierTestServices, assertFields("services/instance"));
227         assertNotNull(result);
228         assertListFieldUnderList(result);
229     }
230
231     protected abstract void assertListFieldUnderList(@NonNull List<T> result);
232
233     @Test
234     public void testLeafList() {
235         final var result = translateFields(identifierTestServices, assertFields("protocols"));
236         assertNotNull(result);
237         assertLeafList(result);
238     }
239
240     protected abstract void assertLeafList(@NonNull List<T> result);
241
242     /**
243      * Test parse fields parameter when not existing child node selected.
244      */
245     @Test
246     public void testMissingChildSchema() throws ParseException {
247         final FieldsParam input = FieldsParam.parse("library(not-existing)");
248
249         final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
250             () -> translateFields(identifierJukebox, input));
251         // Bad request
252         assertEquals(ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
253         assertEquals(ErrorTag.INVALID_VALUE, ex.getErrors().get(0).getErrorTag());
254     }
255
256     private static FieldsParam assertFields(final String input) {
257         try {
258             return FieldsParam.parse(input);
259         } catch (ParseException e) {
260             throw new AssertionError(e);
261         }
262     }
263 }