InstanceIdentifierContext does not take generics
[netconf.git] / restconf / restconf-nb-rfc8040 / 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 import static org.mockito.Mockito.doReturn;
14 import static org.mockito.Mockito.when;
15
16 import java.text.ParseException;
17 import java.util.List;
18 import java.util.Optional;
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.junit.Before;
21 import org.junit.Test;
22 import org.mockito.Mock;
23 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
24 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
25 import org.opendaylight.restconf.nb.rfc8040.FieldsParam;
26 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
27 import org.opendaylight.yangtools.yang.common.ErrorTag;
28 import org.opendaylight.yangtools.yang.common.ErrorType;
29 import org.opendaylight.yangtools.yang.common.QName;
30 import org.opendaylight.yangtools.yang.common.QNameModule;
31 import org.opendaylight.yangtools.yang.common.Revision;
32 import org.opendaylight.yangtools.yang.common.XMLNamespace;
33 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
36 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
39 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
40
41 public abstract class AbstractFieldsTranslatorTest<T> {
42     @Mock
43     private InstanceIdentifierContext identifierJukebox;
44
45     @Mock
46     private InstanceIdentifierContext identifierTestServices;
47
48     private static final QNameModule Q_NAME_MODULE_JUKEBOX = QNameModule.create(
49         XMLNamespace.of("http://example.com/ns/example-jukebox"), Revision.of("2015-04-04"));
50     private static final QNameModule Q_NAME_MODULE_TEST_SERVICES = QNameModule.create(
51         XMLNamespace.of("tests:test-services"), Revision.of("2019-03-25"));
52     private static final QNameModule Q_NAME_MODULE_AUGMENTED_JUKEBOX = QNameModule.create(
53         XMLNamespace.of("http://example.com/ns/augmented-jukebox"), Revision.of("2016-05-05"));
54
55     // container jukebox
56     @Mock
57     private ContainerSchemaNode containerJukebox;
58     private static final QName JUKEBOX_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "jukebox");
59
60     // container player
61     @Mock
62     private ContainerSchemaNode containerPlayer;
63     protected static final QName PLAYER_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "player");
64
65     // container library
66     @Mock
67     private ContainerSchemaNode containerLibrary;
68     protected static final QName LIBRARY_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "library");
69
70     // container augmented library
71     @Mock
72     private ContainerSchemaNode augmentedContainerLibrary;
73     protected static final QName AUGMENTED_LIBRARY_Q_NAME = QName.create(Q_NAME_MODULE_AUGMENTED_JUKEBOX,
74             "augmented-library");
75
76     // augmentation that contains speed leaf
77     @Mock
78     private AugmentationSchemaNode speedAugmentation;
79
80     // leaf speed
81     @Mock
82     private LeafSchemaNode leafSpeed;
83     protected static final QName SPEED_Q_NAME = QName.create(Q_NAME_MODULE_AUGMENTED_JUKEBOX, "speed");
84
85     // list album
86     @Mock
87     private ListSchemaNode listAlbum;
88     public static final QName ALBUM_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "album");
89
90     // leaf name
91     @Mock
92     private LeafSchemaNode leafName;
93     protected static final QName NAME_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "name");
94
95     // container test data
96     @Mock
97     private ContainerSchemaNode containerTestData;
98     private static final QName TEST_DATA_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "test-data");
99
100     // list services
101     @Mock
102     private ListSchemaNode listServices;
103     protected static final QName SERVICES_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "services");
104
105     // leaf type-of-service
106     @Mock
107     private LeafSchemaNode leafTypeOfService;
108     protected static final QName TYPE_OF_SERVICE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "type-of-service");
109
110     // list instance
111     @Mock
112     private ListSchemaNode listInstance;
113     protected static final QName INSTANCE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "instance");
114
115     // leaf instance-name
116     @Mock
117     private LeafSchemaNode leafInstanceName;
118     protected static final QName INSTANCE_NAME_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "instance-name");
119
120     // leaf provider
121     @Mock
122     private LeafSchemaNode leafProvider;
123     protected static final QName PROVIDER_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "provider");
124
125     // container next-data
126     @Mock
127     private ContainerSchemaNode containerNextData;
128     protected static final QName NEXT_DATA_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "next-data");
129
130     // leaf next-service
131     @Mock
132     private LeafSchemaNode leafNextService;
133     protected static final QName NEXT_SERVICE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "next-service");
134
135     // leaf-list protocols
136     @Mock
137     private LeafListSchemaNode leafListProtocols;
138     protected static final QName PROTOCOLS_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "protocols");
139
140     @Before
141     public void setUp() throws Exception {
142         final EffectiveModelContext schemaContextJukebox =
143                 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/jukebox"));
144         initJukeboxSchemaNodes(schemaContextJukebox);
145
146         final EffectiveModelContext schemaContextTestServices =
147                 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/test-services"));
148         initTestServicesSchemaNodes(schemaContextTestServices);
149     }
150
151     private void initJukeboxSchemaNodes(final EffectiveModelContext schemaContext) {
152         when(identifierJukebox.getSchemaContext()).thenReturn(schemaContext);
153         when(containerJukebox.getQName()).thenReturn(JUKEBOX_Q_NAME);
154         when(identifierJukebox.getSchemaNode()).thenReturn(containerJukebox);
155
156         when(containerLibrary.getQName()).thenReturn(LIBRARY_Q_NAME);
157         when(containerJukebox.dataChildByName(LIBRARY_Q_NAME)).thenReturn(containerLibrary);
158
159         when(augmentedContainerLibrary.getQName()).thenReturn(AUGMENTED_LIBRARY_Q_NAME);
160         when(containerJukebox.dataChildByName(AUGMENTED_LIBRARY_Q_NAME))
161                 .thenReturn(augmentedContainerLibrary);
162
163         when(containerPlayer.getQName()).thenReturn(PLAYER_Q_NAME);
164         when(containerJukebox.dataChildByName(PLAYER_Q_NAME)).thenReturn(containerPlayer);
165
166         when(listAlbum.getQName()).thenReturn(ALBUM_Q_NAME);
167         when(containerLibrary.dataChildByName(ALBUM_Q_NAME)).thenReturn(listAlbum);
168
169         when(leafName.getQName()).thenReturn(NAME_Q_NAME);
170         when(listAlbum.dataChildByName(NAME_Q_NAME)).thenReturn(leafName);
171
172         when(leafSpeed.getQName()).thenReturn(SPEED_Q_NAME);
173         when(leafSpeed.isAugmenting()).thenReturn(true);
174         when(containerPlayer.dataChildByName(SPEED_Q_NAME)).thenReturn(leafSpeed);
175         when(containerPlayer.getDataChildByName(SPEED_Q_NAME)).thenReturn(leafSpeed);
176         doReturn(List.of(leafSpeed)).when(speedAugmentation).getChildNodes();
177         doReturn(List.of(speedAugmentation)).when(containerPlayer).getAvailableAugmentations();
178         when(speedAugmentation.findDataChildByName(SPEED_Q_NAME)).thenReturn(Optional.of(leafSpeed));
179     }
180
181     private void initTestServicesSchemaNodes(final EffectiveModelContext schemaContext) {
182         when(identifierTestServices.getSchemaContext()).thenReturn(schemaContext);
183         when(containerTestData.getQName()).thenReturn(TEST_DATA_Q_NAME);
184         when(identifierTestServices.getSchemaNode()).thenReturn(containerTestData);
185
186         when(listServices.getQName()).thenReturn(SERVICES_Q_NAME);
187         when(containerTestData.dataChildByName(SERVICES_Q_NAME)).thenReturn(listServices);
188
189         when(leafListProtocols.getQName()).thenReturn(PROTOCOLS_Q_NAME);
190         when(containerTestData.dataChildByName(PROTOCOLS_Q_NAME)).thenReturn(leafListProtocols);
191
192         when(leafTypeOfService.getQName()).thenReturn(TYPE_OF_SERVICE_Q_NAME);
193         when(listServices.dataChildByName(TYPE_OF_SERVICE_Q_NAME)).thenReturn(leafTypeOfService);
194
195         when(listInstance.getQName()).thenReturn(INSTANCE_Q_NAME);
196         when(listServices.dataChildByName(INSTANCE_Q_NAME)).thenReturn(listInstance);
197
198         when(leafInstanceName.getQName()).thenReturn(INSTANCE_NAME_Q_NAME);
199         when(listInstance.dataChildByName(INSTANCE_NAME_Q_NAME)).thenReturn(leafInstanceName);
200
201         when(leafProvider.getQName()).thenReturn(PROVIDER_Q_NAME);
202         when(listInstance.dataChildByName(PROVIDER_Q_NAME)).thenReturn(leafProvider);
203
204         when(containerNextData.getQName()).thenReturn(NEXT_DATA_Q_NAME);
205         when(listServices.dataChildByName(NEXT_DATA_Q_NAME)).thenReturn(containerNextData);
206
207         when(leafNextService.getQName()).thenReturn(NEXT_SERVICE_Q_NAME);
208         when(containerNextData.dataChildByName(NEXT_SERVICE_Q_NAME)).thenReturn(leafNextService);
209     }
210
211     protected abstract List<T> translateFields(InstanceIdentifierContext context, FieldsParam fields);
212
213     /**
214      * Test parse fields parameter containing only one child selected.
215      */
216     @Test
217     public void testSimplePath() {
218         final var result = translateFields(identifierJukebox, assertFields("library"));
219         assertNotNull(result);
220         assertSimplePath(result);
221     }
222
223     protected abstract void assertSimplePath(@NonNull List<T> result);
224
225     /**
226      * Test parse fields parameter containing two child nodes selected.
227      */
228     @Test
229     public void testDoublePath() {
230         final var result = translateFields(identifierJukebox, assertFields("library;player"));
231         assertNotNull(result);
232         assertDoublePath(result);
233     }
234
235     protected abstract void assertDoublePath(@NonNull List<T> result);
236
237     /**
238      * Test parse fields parameter containing sub-children selected delimited by slash.
239      */
240     @Test
241     public void testSubPath() {
242         final var result = translateFields(identifierJukebox, assertFields("library/album/name"));
243         assertNotNull(result);
244         assertSubPath(result);
245     }
246
247     protected abstract void assertSubPath(@NonNull List<T> result);
248
249     /**
250      * Test parse fields parameter containing sub-children selected delimited by parenthesis.
251      */
252     @Test
253     public void testChildrenPath() {
254         final var result = translateFields(identifierJukebox, assertFields("library(album(name))"));
255         assertNotNull(result);
256         assertChildrenPath(result);
257     }
258
259     protected abstract void assertChildrenPath(@NonNull List<T> result);
260
261     /**
262      * Test parse fields parameter when augmentation with different namespace is used.
263      */
264     @Test
265     public void testNamespace() {
266         final var result = translateFields(identifierJukebox, assertFields("augmented-jukebox:augmented-library"));
267         assertNotNull(result);
268         assertNamespace(result);
269     }
270
271     protected abstract void assertNamespace(@NonNull List<T> result);
272
273     /**
274      * Testing of fields parameter parsing when multiple nodes are wrapped in brackets and these nodes are not
275      * direct children of parent node - multiple children which are constructed using '/'.
276      */
277     @Test
278     public void testMultipleChildren1() {
279         final var result = translateFields(identifierTestServices,
280             assertFields("services(type-of-service;instance/instance-name;instance/provider)"));
281         assertNotNull(result);
282         assertMultipleChildren1(result);
283     }
284
285     protected abstract void assertMultipleChildren1(@NonNull List<T> result);
286
287     /**
288      * Testing of fields parameter parsing when multiple nodes are wrapped in brackets and these nodes are not
289      * direct children of parent node - one of children nodes is typed using brackets, other is constructed using '/'.
290      */
291     @Test
292     public void testMultipleChildren2() {
293         final var result = translateFields(identifierTestServices,
294             assertFields("services(type-of-service;instance(instance-name;provider))"));
295         assertNotNull(result);
296         assertMultipleChildren2(result);
297     }
298
299     protected abstract void assertMultipleChildren2(@NonNull List<T> result);
300
301     /**
302      * Testing of fields parameter parsing when multiple nodes are wrapped in brackets and these nodes are not
303      * direct children of parent node - multiple children with different parent nodes.
304      */
305     @Test
306     public void testMultipleChildren3() {
307         final var result = translateFields(identifierTestServices,
308             assertFields("services(instance/instance-name;type-of-service;next-data/next-service)"));
309         assertNotNull(result);
310         assertMultipleChildren3(result);
311     }
312
313     protected abstract void assertMultipleChildren3(@NonNull List<T> result);
314
315     @Test
316     public void testAugmentedChild() {
317         final var result = translateFields(identifierJukebox, assertFields("player/augmented-jukebox:speed"));
318         assertNotNull(result);
319         assertAugmentedChild(result);
320     }
321
322     protected abstract void assertAugmentedChild(@NonNull List<T> result);
323
324     @Test
325     public void testListFieldUnderList() {
326         final var result = translateFields(identifierTestServices, assertFields("services/instance"));
327         assertNotNull(result);
328         assertListFieldUnderList(result);
329     }
330
331     protected abstract void assertListFieldUnderList(@NonNull List<T> result);
332
333     @Test
334     public void testLeafList() {
335         final var result = translateFields(identifierTestServices, assertFields("protocols"));
336         assertNotNull(result);
337         assertLeafList(result);
338     }
339
340     protected abstract void assertLeafList(@NonNull List<T> result);
341
342     /**
343      * Test parse fields parameter when not existing child node selected.
344      */
345     @Test
346     public void testMissingChildSchema() throws ParseException {
347         final FieldsParam input = FieldsParam.parse("library(not-existing)");
348
349         final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
350             () -> translateFields(identifierJukebox, input));
351         // Bad request
352         assertEquals(ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
353         assertEquals(ErrorTag.INVALID_VALUE, ex.getErrors().get(0).getErrorTag());
354     }
355
356     private static FieldsParam assertFields(final String input) {
357         try {
358             return FieldsParam.parse(input);
359         } catch (ParseException e) {
360             throw new AssertionError(e);
361         }
362     }
363 }