a2e5063e10611160a6c9438ae901f7d9c62ae064
[netconf.git] / restconf / restconf-nb-rfc8040 / src / test / java / org / opendaylight / restconf / nb / rfc8040 / utils / parser / ParserFieldsParameterTest.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.assertTrue;
13 import static org.junit.Assert.fail;
14 import static org.mockito.Mockito.when;
15
16 import com.google.common.collect.Sets;
17 import java.net.URI;
18 import java.util.List;
19 import java.util.Set;
20 import org.junit.Before;
21 import org.junit.Test;
22 import org.junit.runner.RunWith;
23 import org.mockito.Mock;
24 import org.mockito.junit.MockitoJUnitRunner;
25 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
26 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
27 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
28 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
29 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
30 import org.opendaylight.yangtools.yang.common.QName;
31 import org.opendaylight.yangtools.yang.common.QNameModule;
32 import org.opendaylight.yangtools.yang.common.Revision;
33 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
35 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
37 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
38
39 /**
40  * Unit test for {@link ParserFieldsParameter}.
41  */
42 @RunWith(MockitoJUnitRunner.class)
43 public class ParserFieldsParameterTest {
44
45     @Mock
46     private InstanceIdentifierContext<ContainerSchemaNode> identifierJukebox;
47
48     @Mock
49     private InstanceIdentifierContext<ContainerSchemaNode> identifierTestServices;
50
51     private static final QNameModule Q_NAME_MODULE_JUKEBOX = QNameModule.create(
52             URI.create("http://example.com/ns/example-jukebox"),
53             Revision.of("2015-04-04"));
54     private static final QNameModule Q_NAME_MODULE_TEST_SERVICES = QNameModule.create(
55             URI.create("tests:test-services"),
56             Revision.of("2019-03-25"));
57
58     // container jukebox
59     @Mock
60     private ContainerSchemaNode containerJukebox;
61     private static final QName JUKEBOX_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "jukebox");
62
63     // container player
64     @Mock
65     private ContainerSchemaNode containerPlayer;
66     private static final QName PLAYER_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "player");
67
68     // container library
69     @Mock
70     private ContainerSchemaNode containerLibrary;
71     private static final QName LIBRARY_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "library");
72
73     // container augmented library
74     @Mock
75     private ContainerSchemaNode augmentedContainerLibrary;
76     private static final QName AUGMENTED_LIBRARY_Q_NAME = QName.create(
77             QNameModule.create(
78                     URI.create("http://example.com/ns/augmented-jukebox"),
79                     Revision.of("2016-05-05")),
80             "augmented-library");
81
82     // list album
83     @Mock
84     private ListSchemaNode listAlbum;
85     private static final QName ALBUM_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "album");
86
87     // leaf name
88     @Mock
89     private LeafSchemaNode leafName;
90     private static final QName NAME_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "name");
91
92     // container test data
93     @Mock
94     private ContainerSchemaNode containerTestData;
95     private static final QName TEST_DATA_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "test-data");
96
97     // list services
98     @Mock
99     private ListSchemaNode listServices;
100     private static final QName SERVICES_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "services");
101
102     // leaf type-of-service
103     @Mock
104     private LeafSchemaNode leafTypeOfService;
105     private static final QName TYPE_OF_SERVICE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "type-of-service");
106
107     // list instance
108     @Mock
109     private ListSchemaNode listInstance;
110     private static final QName INSTANCE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "instance");
111
112     // leaf instance-name
113     @Mock
114     private LeafSchemaNode leafInstanceName;
115     private static final QName INSTANCE_NAME_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "instance-name");
116
117     // leaf provider
118     @Mock
119     private LeafSchemaNode leafProvider;
120     private static final QName PROVIDER_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "provider");
121
122     // container next-data
123     @Mock
124     private ContainerSchemaNode containerNextData;
125     private static final QName NEXT_DATA_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "next-data");
126
127     // leaf next-service
128     @Mock
129     private LeafSchemaNode leafNextService;
130     private static final QName NEXT_SERVICE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "next-service");
131
132     @Before
133     public void setUp() throws Exception {
134         final EffectiveModelContext schemaContextJukebox =
135                 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/jukebox"));
136         initJukeboxSchemaNodes(schemaContextJukebox);
137
138         final EffectiveModelContext schemaContextTestServices =
139                 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/test-services"));
140         initTestServicesSchemaNodes(schemaContextTestServices);
141     }
142
143     private void initJukeboxSchemaNodes(final EffectiveModelContext schemaContext) {
144         when(identifierJukebox.getSchemaContext()).thenReturn(schemaContext);
145         when(containerJukebox.getQName()).thenReturn(JUKEBOX_Q_NAME);
146         when(identifierJukebox.getSchemaNode()).thenReturn(containerJukebox);
147
148         when(containerLibrary.getQName()).thenReturn(LIBRARY_Q_NAME);
149         when(containerJukebox.dataChildByName(LIBRARY_Q_NAME)).thenReturn(containerLibrary);
150
151         when(augmentedContainerLibrary.getQName()).thenReturn(AUGMENTED_LIBRARY_Q_NAME);
152         when(containerJukebox.dataChildByName(AUGMENTED_LIBRARY_Q_NAME))
153                 .thenReturn(augmentedContainerLibrary);
154
155         when(containerPlayer.getQName()).thenReturn(PLAYER_Q_NAME);
156         when(containerJukebox.dataChildByName(PLAYER_Q_NAME)).thenReturn(containerPlayer);
157
158         when(listAlbum.getQName()).thenReturn(ALBUM_Q_NAME);
159         when(containerLibrary.dataChildByName(ALBUM_Q_NAME)).thenReturn(listAlbum);
160
161         when(leafName.getQName()).thenReturn(NAME_Q_NAME);
162         when(listAlbum.dataChildByName(NAME_Q_NAME)).thenReturn(leafName);
163     }
164
165     private void initTestServicesSchemaNodes(final EffectiveModelContext schemaContext) {
166         when(identifierTestServices.getSchemaContext()).thenReturn(schemaContext);
167         when(containerTestData.getQName()).thenReturn(TEST_DATA_Q_NAME);
168         when(identifierTestServices.getSchemaNode()).thenReturn(containerTestData);
169
170         when(listServices.getQName()).thenReturn(SERVICES_Q_NAME);
171         when(containerTestData.dataChildByName(SERVICES_Q_NAME)).thenReturn(listServices);
172
173         when(leafTypeOfService.getQName()).thenReturn(TYPE_OF_SERVICE_Q_NAME);
174         when(listServices.dataChildByName(TYPE_OF_SERVICE_Q_NAME)).thenReturn(leafTypeOfService);
175
176         when(listInstance.getQName()).thenReturn(INSTANCE_Q_NAME);
177         when(listServices.dataChildByName(INSTANCE_Q_NAME)).thenReturn(listInstance);
178
179         when(leafInstanceName.getQName()).thenReturn(INSTANCE_NAME_Q_NAME);
180         when(listInstance.dataChildByName(INSTANCE_NAME_Q_NAME)).thenReturn(leafInstanceName);
181
182         when(leafProvider.getQName()).thenReturn(PROVIDER_Q_NAME);
183         when(listInstance.dataChildByName(PROVIDER_Q_NAME)).thenReturn(leafProvider);
184
185         when(containerNextData.getQName()).thenReturn(NEXT_DATA_Q_NAME);
186         when(listServices.dataChildByName(NEXT_DATA_Q_NAME)).thenReturn(containerNextData);
187
188         when(leafNextService.getQName()).thenReturn(NEXT_SERVICE_Q_NAME);
189         when(containerNextData.dataChildByName(NEXT_SERVICE_Q_NAME)).thenReturn(leafNextService);
190     }
191
192     /**
193      * Test parse fields parameter containing only one child selected.
194      */
195     @Test
196     public void parseFieldsParameterSimplePathTest() {
197         final String input = "library";
198         final List<Set<QName>> parsedFields = ParserFieldsParameter.parseFieldsParameter(identifierJukebox, input);
199
200         assertNotNull(parsedFields);
201         assertEquals(1, parsedFields.size());
202         assertEquals(1, parsedFields.get(0).size());
203         assertTrue(parsedFields.get(0).contains(LIBRARY_Q_NAME));
204     }
205
206     /**
207      * Test parse fields parameter containing two child nodes selected.
208      */
209     @Test
210     public void parseFieldsParameterDoublePathTest() {
211         final String input = "library;player";
212         final List<Set<QName>> parsedFields = ParserFieldsParameter.parseFieldsParameter(identifierJukebox, input);
213
214         assertNotNull(parsedFields);
215         assertEquals(1, parsedFields.size());
216         assertEquals(2, parsedFields.get(0).size());
217         assertTrue(parsedFields.get(0).contains(LIBRARY_Q_NAME));
218         assertTrue(parsedFields.get(0).contains(PLAYER_Q_NAME));
219     }
220
221     /**
222      * Test parse fields parameter containing sub-children selected delimited by slash.
223      */
224     @Test
225     public void parseFieldsParameterSubPathTest() {
226         final String input = "library/album/name";
227         final List<Set<QName>> parsedFields = ParserFieldsParameter.parseFieldsParameter(identifierJukebox, input);
228
229         assertNotNull(parsedFields);
230         assertEquals(3, parsedFields.size());
231
232         assertEquals(1, parsedFields.get(0).size());
233         assertTrue(parsedFields.get(0).contains(LIBRARY_Q_NAME));
234
235         assertEquals(1, parsedFields.get(1).size());
236         assertTrue(parsedFields.get(1).contains(ALBUM_Q_NAME));
237
238         assertEquals(1, parsedFields.get(2).size());
239         assertTrue(parsedFields.get(2).contains(NAME_Q_NAME));
240     }
241
242     /**
243      * Test parse fields parameter containing sub-children selected delimited by parenthesis.
244      */
245     @Test
246     public void parseFieldsParameterChildrenPathTest() {
247         final String input = "library(album(name))";
248         final List<Set<QName>> parsedFields = ParserFieldsParameter.parseFieldsParameter(identifierJukebox, input);
249
250         assertNotNull(parsedFields);
251         assertEquals(3, parsedFields.size());
252
253         assertEquals(1, parsedFields.get(0).size());
254         assertTrue(parsedFields.get(0).contains(LIBRARY_Q_NAME));
255
256         assertEquals(1, parsedFields.get(1).size());
257         assertTrue(parsedFields.get(1).contains(ALBUM_Q_NAME));
258
259         assertEquals(1, parsedFields.get(2).size());
260         assertTrue(parsedFields.get(2).contains(NAME_Q_NAME));
261     }
262
263     /**
264      * Test parse fields parameter when augmentation with different namespace is used.
265      */
266     @Test
267     public void parseFieldsParameterNamespaceTest() {
268         final String input = "augmented-jukebox:augmented-library";
269         final List<Set<QName>> parsedFields = ParserFieldsParameter.parseFieldsParameter(identifierJukebox, input);
270
271         assertNotNull(parsedFields);
272         assertEquals(1, parsedFields.size());
273
274         assertEquals(1, parsedFields.get(0).size());
275         assertTrue(parsedFields.get(0).contains(AUGMENTED_LIBRARY_Q_NAME));
276     }
277
278     /**
279      * Testing of fields parameter parsing when multiple nodes are wrapped in brackets and these nodes are not
280      * direct children of parent node - multiple children which are constructed using '/'.
281      */
282     @Test
283     public void parseFieldsParameterWithMultipleChildrenTest1() {
284         final String input = "services(type-of-service;instance/instance-name;instance/provider)";
285         final List<Set<QName>> parsedFields = ParserFieldsParameter.parseFieldsParameter(identifierTestServices, input);
286
287         assertNotNull(parsedFields);
288         assertEquals(parsedFields.size(), 3);
289
290         assertEquals(parsedFields.get(0).size(), 1);
291         assertTrue(parsedFields.get(0).contains(SERVICES_Q_NAME));
292
293         assertEquals(parsedFields.get(1).size(), 2);
294         assertTrue(parsedFields.get(1).containsAll(Sets.newHashSet(TYPE_OF_SERVICE_Q_NAME, INSTANCE_Q_NAME)));
295
296         assertEquals(parsedFields.get(2).size(), 2);
297         assertTrue(parsedFields.get(2).containsAll(Sets.newHashSet(INSTANCE_NAME_Q_NAME, PROVIDER_Q_NAME)));
298     }
299
300     /**
301      * Testing of fields parameter parsing when multiple nodes are wrapped in brackets and these nodes are not
302      * direct children of parent node - one of children nodes is typed using brackets, other is constructed using '/'.
303      */
304     @Test
305     public void parseFieldsParameterWithMultipleChildrenTest2() {
306         final String input = "services(type-of-service;instance(instance-name;provider))";
307         final List<Set<QName>> parsedFields = ParserFieldsParameter.parseFieldsParameter(identifierTestServices, input);
308
309         assertNotNull(parsedFields);
310         assertEquals(parsedFields.size(), 3);
311
312         assertEquals(parsedFields.get(0).size(), 1);
313         assertTrue(parsedFields.get(0).contains(SERVICES_Q_NAME));
314
315         assertEquals(parsedFields.get(1).size(), 2);
316         assertTrue(parsedFields.get(1).containsAll(Sets.newHashSet(TYPE_OF_SERVICE_Q_NAME, INSTANCE_Q_NAME)));
317
318         assertEquals(parsedFields.get(2).size(), 2);
319         assertTrue(parsedFields.get(2).containsAll(Sets.newHashSet(INSTANCE_NAME_Q_NAME, PROVIDER_Q_NAME)));
320     }
321
322     /**
323      * Testing of fields parameter parsing when multiple nodes are wrapped in brackets and these nodes are not
324      * direct children of parent node - multiple children with different parent nodes.
325      */
326     @Test
327     public void parseFieldsParameterWithMultipleChildrenTest3() {
328         final String input = "services(instance/instance-name;type-of-service;next-data/next-service)";
329         final List<Set<QName>> parsedFields = ParserFieldsParameter.parseFieldsParameter(identifierTestServices, input);
330
331         assertNotNull(parsedFields);
332         assertEquals(parsedFields.size(), 3);
333
334         assertEquals(parsedFields.get(0).size(), 1);
335         assertTrue(parsedFields.get(0).contains(SERVICES_Q_NAME));
336
337         assertEquals(parsedFields.get(1).size(), 3);
338         assertTrue(parsedFields.get(1).containsAll(
339                 Sets.newHashSet(TYPE_OF_SERVICE_Q_NAME, INSTANCE_Q_NAME, NEXT_DATA_Q_NAME)));
340
341         assertEquals(parsedFields.get(2).size(), 2);
342         assertTrue(parsedFields.get(2).containsAll(
343                 Sets.newHashSet(INSTANCE_NAME_Q_NAME, NEXT_SERVICE_Q_NAME)));
344     }
345
346     /**
347      * Test parse fields parameter containing not expected character.
348      */
349     @Test
350     public void parseFieldsParameterNotExpectedCharacterNegativeTest() {
351         final String input = "*";
352
353         try {
354             ParserFieldsParameter.parseFieldsParameter(this.identifierJukebox, input);
355             fail("Test should fail due to not expected character used in parameter input value");
356         } catch (final RestconfDocumentedException e) {
357             // Bad request
358             assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
359             assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
360             assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
361         }
362     }
363
364     /**
365      * Test parse fields parameter with missing closing parenthesis.
366      */
367     @Test
368     public void parseFieldsParameterMissingParenthesisNegativeTest() {
369         final String input = "library(";
370
371         try {
372             ParserFieldsParameter.parseFieldsParameter(this.identifierJukebox, input);
373             fail("Test should fail due to missing closing parenthesis");
374         } catch (final RestconfDocumentedException e) {
375             // Bad request
376             assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
377             assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
378             assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
379         }
380     }
381
382     /**
383      * Test parse fields parameter when not existing child node selected.
384      */
385     @Test
386     public void parseFieldsParameterMissingChildNodeNegativeTest() {
387         final String input = "library(not-existing)";
388
389         try {
390             ParserFieldsParameter.parseFieldsParameter(this.identifierJukebox, input);
391             fail("Test should fail due to missing child node in parent node");
392         } catch (final RestconfDocumentedException e) {
393             // Bad request
394             assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
395             assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
396             assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
397         }
398     }
399
400     /**
401      * Test parse fields parameter with unexpected character after parenthesis.
402      */
403     @Test
404     public void parseFieldsParameterAfterParenthesisNegativeTest() {
405         final String input = "library(album);";
406
407         try {
408             ParserFieldsParameter.parseFieldsParameter(this.identifierJukebox, input);
409             fail("Test should fail due to unexpected character after parenthesis");
410         } catch (final RestconfDocumentedException e) {
411             // Bad request
412             assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
413             assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
414             assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
415         }
416     }
417
418     /**
419      * Test parse fields parameter with missing semicolon after parenthesis.
420      */
421     @Test
422     public void parseFieldsParameterMissingSemicolonNegativeTest() {
423         final String input = "library(album)player";
424
425         try {
426             ParserFieldsParameter.parseFieldsParameter(this.identifierJukebox, input);
427             fail("Test should fail due to missing semicolon after parenthesis");
428         } catch (final RestconfDocumentedException e) {
429             // Bad request
430             assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
431             assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
432             assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
433         }
434     }
435
436
437 }