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.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;
16 import com.google.common.collect.Sets;
18 import java.util.List;
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;
40 * Unit test for {@link ParserFieldsParameter}.
42 @RunWith(MockitoJUnitRunner.class)
43 public class ParserFieldsParameterTest {
46 private InstanceIdentifierContext<ContainerSchemaNode> identifierJukebox;
49 private InstanceIdentifierContext<ContainerSchemaNode> identifierTestServices;
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"));
60 private ContainerSchemaNode containerJukebox;
61 private static final QName JUKEBOX_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "jukebox");
65 private ContainerSchemaNode containerPlayer;
66 private static final QName PLAYER_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "player");
70 private ContainerSchemaNode containerLibrary;
71 private static final QName LIBRARY_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "library");
73 // container augmented library
75 private ContainerSchemaNode augmentedContainerLibrary;
76 private static final QName AUGMENTED_LIBRARY_Q_NAME = QName.create(
78 URI.create("http://example.com/ns/augmented-jukebox"),
79 Revision.of("2016-05-05")),
84 private ListSchemaNode listAlbum;
85 private static final QName ALBUM_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "album");
89 private LeafSchemaNode leafName;
90 private static final QName NAME_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "name");
92 // container test data
94 private ContainerSchemaNode containerTestData;
95 private static final QName TEST_DATA_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "test-data");
99 private ListSchemaNode listServices;
100 private static final QName SERVICES_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "services");
102 // leaf type-of-service
104 private LeafSchemaNode leafTypeOfService;
105 private static final QName TYPE_OF_SERVICE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "type-of-service");
109 private ListSchemaNode listInstance;
110 private static final QName INSTANCE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "instance");
112 // leaf instance-name
114 private LeafSchemaNode leafInstanceName;
115 private static final QName INSTANCE_NAME_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "instance-name");
119 private LeafSchemaNode leafProvider;
120 private static final QName PROVIDER_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "provider");
122 // container next-data
124 private ContainerSchemaNode containerNextData;
125 private static final QName NEXT_DATA_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "next-data");
129 private LeafSchemaNode leafNextService;
130 private static final QName NEXT_SERVICE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "next-service");
133 public void setUp() throws Exception {
134 final EffectiveModelContext schemaContextJukebox =
135 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/jukebox"));
136 initJukeboxSchemaNodes(schemaContextJukebox);
138 final EffectiveModelContext schemaContextTestServices =
139 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/test-services"));
140 initTestServicesSchemaNodes(schemaContextTestServices);
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);
148 when(containerLibrary.getQName()).thenReturn(LIBRARY_Q_NAME);
149 when(containerJukebox.dataChildByName(LIBRARY_Q_NAME)).thenReturn(containerLibrary);
151 when(augmentedContainerLibrary.getQName()).thenReturn(AUGMENTED_LIBRARY_Q_NAME);
152 when(containerJukebox.dataChildByName(AUGMENTED_LIBRARY_Q_NAME))
153 .thenReturn(augmentedContainerLibrary);
155 when(containerPlayer.getQName()).thenReturn(PLAYER_Q_NAME);
156 when(containerJukebox.dataChildByName(PLAYER_Q_NAME)).thenReturn(containerPlayer);
158 when(listAlbum.getQName()).thenReturn(ALBUM_Q_NAME);
159 when(containerLibrary.dataChildByName(ALBUM_Q_NAME)).thenReturn(listAlbum);
161 when(leafName.getQName()).thenReturn(NAME_Q_NAME);
162 when(listAlbum.dataChildByName(NAME_Q_NAME)).thenReturn(leafName);
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);
170 when(listServices.getQName()).thenReturn(SERVICES_Q_NAME);
171 when(containerTestData.dataChildByName(SERVICES_Q_NAME)).thenReturn(listServices);
173 when(leafTypeOfService.getQName()).thenReturn(TYPE_OF_SERVICE_Q_NAME);
174 when(listServices.dataChildByName(TYPE_OF_SERVICE_Q_NAME)).thenReturn(leafTypeOfService);
176 when(listInstance.getQName()).thenReturn(INSTANCE_Q_NAME);
177 when(listServices.dataChildByName(INSTANCE_Q_NAME)).thenReturn(listInstance);
179 when(leafInstanceName.getQName()).thenReturn(INSTANCE_NAME_Q_NAME);
180 when(listInstance.dataChildByName(INSTANCE_NAME_Q_NAME)).thenReturn(leafInstanceName);
182 when(leafProvider.getQName()).thenReturn(PROVIDER_Q_NAME);
183 when(listInstance.dataChildByName(PROVIDER_Q_NAME)).thenReturn(leafProvider);
185 when(containerNextData.getQName()).thenReturn(NEXT_DATA_Q_NAME);
186 when(listServices.dataChildByName(NEXT_DATA_Q_NAME)).thenReturn(containerNextData);
188 when(leafNextService.getQName()).thenReturn(NEXT_SERVICE_Q_NAME);
189 when(containerNextData.dataChildByName(NEXT_SERVICE_Q_NAME)).thenReturn(leafNextService);
193 * Test parse fields parameter containing only one child selected.
196 public void parseFieldsParameterSimplePathTest() {
197 final String input = "library";
198 final List<Set<QName>> parsedFields = ParserFieldsParameter.parseFieldsParameter(identifierJukebox, input);
200 assertNotNull(parsedFields);
201 assertEquals(1, parsedFields.size());
202 assertEquals(1, parsedFields.get(0).size());
203 assertTrue(parsedFields.get(0).contains(LIBRARY_Q_NAME));
207 * Test parse fields parameter containing two child nodes selected.
210 public void parseFieldsParameterDoublePathTest() {
211 final String input = "library;player";
212 final List<Set<QName>> parsedFields = ParserFieldsParameter.parseFieldsParameter(identifierJukebox, input);
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));
222 * Test parse fields parameter containing sub-children selected delimited by slash.
225 public void parseFieldsParameterSubPathTest() {
226 final String input = "library/album/name";
227 final List<Set<QName>> parsedFields = ParserFieldsParameter.parseFieldsParameter(identifierJukebox, input);
229 assertNotNull(parsedFields);
230 assertEquals(3, parsedFields.size());
232 assertEquals(1, parsedFields.get(0).size());
233 assertTrue(parsedFields.get(0).contains(LIBRARY_Q_NAME));
235 assertEquals(1, parsedFields.get(1).size());
236 assertTrue(parsedFields.get(1).contains(ALBUM_Q_NAME));
238 assertEquals(1, parsedFields.get(2).size());
239 assertTrue(parsedFields.get(2).contains(NAME_Q_NAME));
243 * Test parse fields parameter containing sub-children selected delimited by parenthesis.
246 public void parseFieldsParameterChildrenPathTest() {
247 final String input = "library(album(name))";
248 final List<Set<QName>> parsedFields = ParserFieldsParameter.parseFieldsParameter(identifierJukebox, input);
250 assertNotNull(parsedFields);
251 assertEquals(3, parsedFields.size());
253 assertEquals(1, parsedFields.get(0).size());
254 assertTrue(parsedFields.get(0).contains(LIBRARY_Q_NAME));
256 assertEquals(1, parsedFields.get(1).size());
257 assertTrue(parsedFields.get(1).contains(ALBUM_Q_NAME));
259 assertEquals(1, parsedFields.get(2).size());
260 assertTrue(parsedFields.get(2).contains(NAME_Q_NAME));
264 * Test parse fields parameter when augmentation with different namespace is used.
267 public void parseFieldsParameterNamespaceTest() {
268 final String input = "augmented-jukebox:augmented-library";
269 final List<Set<QName>> parsedFields = ParserFieldsParameter.parseFieldsParameter(identifierJukebox, input);
271 assertNotNull(parsedFields);
272 assertEquals(1, parsedFields.size());
274 assertEquals(1, parsedFields.get(0).size());
275 assertTrue(parsedFields.get(0).contains(AUGMENTED_LIBRARY_Q_NAME));
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 '/'.
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);
287 assertNotNull(parsedFields);
288 assertEquals(parsedFields.size(), 3);
290 assertEquals(parsedFields.get(0).size(), 1);
291 assertTrue(parsedFields.get(0).contains(SERVICES_Q_NAME));
293 assertEquals(parsedFields.get(1).size(), 2);
294 assertTrue(parsedFields.get(1).containsAll(Sets.newHashSet(TYPE_OF_SERVICE_Q_NAME, INSTANCE_Q_NAME)));
296 assertEquals(parsedFields.get(2).size(), 2);
297 assertTrue(parsedFields.get(2).containsAll(Sets.newHashSet(INSTANCE_NAME_Q_NAME, PROVIDER_Q_NAME)));
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 '/'.
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);
309 assertNotNull(parsedFields);
310 assertEquals(parsedFields.size(), 3);
312 assertEquals(parsedFields.get(0).size(), 1);
313 assertTrue(parsedFields.get(0).contains(SERVICES_Q_NAME));
315 assertEquals(parsedFields.get(1).size(), 2);
316 assertTrue(parsedFields.get(1).containsAll(Sets.newHashSet(TYPE_OF_SERVICE_Q_NAME, INSTANCE_Q_NAME)));
318 assertEquals(parsedFields.get(2).size(), 2);
319 assertTrue(parsedFields.get(2).containsAll(Sets.newHashSet(INSTANCE_NAME_Q_NAME, PROVIDER_Q_NAME)));
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.
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);
331 assertNotNull(parsedFields);
332 assertEquals(parsedFields.size(), 3);
334 assertEquals(parsedFields.get(0).size(), 1);
335 assertTrue(parsedFields.get(0).contains(SERVICES_Q_NAME));
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)));
341 assertEquals(parsedFields.get(2).size(), 2);
342 assertTrue(parsedFields.get(2).containsAll(
343 Sets.newHashSet(INSTANCE_NAME_Q_NAME, NEXT_SERVICE_Q_NAME)));
347 * Test parse fields parameter containing not expected character.
350 public void parseFieldsParameterNotExpectedCharacterNegativeTest() {
351 final String input = "*";
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) {
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());
365 * Test parse fields parameter with missing closing parenthesis.
368 public void parseFieldsParameterMissingParenthesisNegativeTest() {
369 final String input = "library(";
372 ParserFieldsParameter.parseFieldsParameter(this.identifierJukebox, input);
373 fail("Test should fail due to missing closing parenthesis");
374 } catch (final RestconfDocumentedException e) {
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());
383 * Test parse fields parameter when not existing child node selected.
386 public void parseFieldsParameterMissingChildNodeNegativeTest() {
387 final String input = "library(not-existing)";
390 ParserFieldsParameter.parseFieldsParameter(this.identifierJukebox, input);
391 fail("Test should fail due to missing child node in parent node");
392 } catch (final RestconfDocumentedException e) {
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());
401 * Test parse fields parameter with unexpected character after parenthesis.
404 public void parseFieldsParameterAfterParenthesisNegativeTest() {
405 final String input = "library(album);";
408 ParserFieldsParameter.parseFieldsParameter(this.identifierJukebox, input);
409 fail("Test should fail due to unexpected character after parenthesis");
410 } catch (final RestconfDocumentedException e) {
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());
419 * Test parse fields parameter with missing semicolon after parenthesis.
422 public void parseFieldsParameterMissingSemicolonNegativeTest() {
423 final String input = "library(album)player";
426 ParserFieldsParameter.parseFieldsParameter(this.identifierJukebox, input);
427 fail("Test should fail due to missing semicolon after parenthesis");
428 } catch (final RestconfDocumentedException e) {
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());