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.assertThrows;
13 import static org.mockito.Mockito.doReturn;
14 import static org.mockito.Mockito.when;
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;
41 public abstract class AbstractFieldsTranslatorTest<T> {
43 private InstanceIdentifierContext identifierJukebox;
46 private InstanceIdentifierContext identifierTestServices;
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"));
57 private ContainerSchemaNode containerJukebox;
58 private static final QName JUKEBOX_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "jukebox");
62 private ContainerSchemaNode containerPlayer;
63 protected static final QName PLAYER_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "player");
67 private ContainerSchemaNode containerLibrary;
68 protected static final QName LIBRARY_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "library");
70 // container augmented library
72 private ContainerSchemaNode augmentedContainerLibrary;
73 protected static final QName AUGMENTED_LIBRARY_Q_NAME = QName.create(Q_NAME_MODULE_AUGMENTED_JUKEBOX,
76 // augmentation that contains speed leaf
78 private AugmentationSchemaNode speedAugmentation;
82 private LeafSchemaNode leafSpeed;
83 protected static final QName SPEED_Q_NAME = QName.create(Q_NAME_MODULE_AUGMENTED_JUKEBOX, "speed");
87 private ListSchemaNode listAlbum;
88 public static final QName ALBUM_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "album");
92 private LeafSchemaNode leafName;
93 protected static final QName NAME_Q_NAME = QName.create(Q_NAME_MODULE_JUKEBOX, "name");
95 // container test data
97 private ContainerSchemaNode containerTestData;
98 private static final QName TEST_DATA_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "test-data");
102 private ListSchemaNode listServices;
103 protected static final QName SERVICES_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "services");
105 // leaf type-of-service
107 private LeafSchemaNode leafTypeOfService;
108 protected static final QName TYPE_OF_SERVICE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "type-of-service");
112 private ListSchemaNode listInstance;
113 protected static final QName INSTANCE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "instance");
115 // leaf instance-name
117 private LeafSchemaNode leafInstanceName;
118 protected static final QName INSTANCE_NAME_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "instance-name");
122 private LeafSchemaNode leafProvider;
123 protected static final QName PROVIDER_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "provider");
125 // container next-data
127 private ContainerSchemaNode containerNextData;
128 protected static final QName NEXT_DATA_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "next-data");
132 private LeafSchemaNode leafNextService;
133 protected static final QName NEXT_SERVICE_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "next-service");
135 // leaf-list protocols
137 private LeafListSchemaNode leafListProtocols;
138 protected static final QName PROTOCOLS_Q_NAME = QName.create(Q_NAME_MODULE_TEST_SERVICES, "protocols");
141 public void setUp() throws Exception {
142 final EffectiveModelContext schemaContextJukebox =
143 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/jukebox"));
144 initJukeboxSchemaNodes(schemaContextJukebox);
146 final EffectiveModelContext schemaContextTestServices =
147 YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/test-services"));
148 initTestServicesSchemaNodes(schemaContextTestServices);
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);
156 when(containerLibrary.getQName()).thenReturn(LIBRARY_Q_NAME);
157 when(containerJukebox.dataChildByName(LIBRARY_Q_NAME)).thenReturn(containerLibrary);
159 when(augmentedContainerLibrary.getQName()).thenReturn(AUGMENTED_LIBRARY_Q_NAME);
160 when(containerJukebox.dataChildByName(AUGMENTED_LIBRARY_Q_NAME))
161 .thenReturn(augmentedContainerLibrary);
163 when(containerPlayer.getQName()).thenReturn(PLAYER_Q_NAME);
164 when(containerJukebox.dataChildByName(PLAYER_Q_NAME)).thenReturn(containerPlayer);
166 when(listAlbum.getQName()).thenReturn(ALBUM_Q_NAME);
167 when(containerLibrary.dataChildByName(ALBUM_Q_NAME)).thenReturn(listAlbum);
169 when(leafName.getQName()).thenReturn(NAME_Q_NAME);
170 when(listAlbum.dataChildByName(NAME_Q_NAME)).thenReturn(leafName);
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));
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);
186 when(listServices.getQName()).thenReturn(SERVICES_Q_NAME);
187 when(containerTestData.dataChildByName(SERVICES_Q_NAME)).thenReturn(listServices);
189 when(leafListProtocols.getQName()).thenReturn(PROTOCOLS_Q_NAME);
190 when(containerTestData.dataChildByName(PROTOCOLS_Q_NAME)).thenReturn(leafListProtocols);
192 when(leafTypeOfService.getQName()).thenReturn(TYPE_OF_SERVICE_Q_NAME);
193 when(listServices.dataChildByName(TYPE_OF_SERVICE_Q_NAME)).thenReturn(leafTypeOfService);
195 when(listInstance.getQName()).thenReturn(INSTANCE_Q_NAME);
196 when(listServices.dataChildByName(INSTANCE_Q_NAME)).thenReturn(listInstance);
198 when(leafInstanceName.getQName()).thenReturn(INSTANCE_NAME_Q_NAME);
199 when(listInstance.dataChildByName(INSTANCE_NAME_Q_NAME)).thenReturn(leafInstanceName);
201 when(leafProvider.getQName()).thenReturn(PROVIDER_Q_NAME);
202 when(listInstance.dataChildByName(PROVIDER_Q_NAME)).thenReturn(leafProvider);
204 when(containerNextData.getQName()).thenReturn(NEXT_DATA_Q_NAME);
205 when(listServices.dataChildByName(NEXT_DATA_Q_NAME)).thenReturn(containerNextData);
207 when(leafNextService.getQName()).thenReturn(NEXT_SERVICE_Q_NAME);
208 when(containerNextData.dataChildByName(NEXT_SERVICE_Q_NAME)).thenReturn(leafNextService);
211 protected abstract List<T> translateFields(InstanceIdentifierContext context, FieldsParam fields);
214 * Test parse fields parameter containing only one child selected.
217 public void testSimplePath() {
218 final var result = translateFields(identifierJukebox, assertFields("library"));
219 assertNotNull(result);
220 assertSimplePath(result);
223 protected abstract void assertSimplePath(@NonNull List<T> result);
226 * Test parse fields parameter containing two child nodes selected.
229 public void testDoublePath() {
230 final var result = translateFields(identifierJukebox, assertFields("library;player"));
231 assertNotNull(result);
232 assertDoublePath(result);
235 protected abstract void assertDoublePath(@NonNull List<T> result);
238 * Test parse fields parameter containing sub-children selected delimited by slash.
241 public void testSubPath() {
242 final var result = translateFields(identifierJukebox, assertFields("library/album/name"));
243 assertNotNull(result);
244 assertSubPath(result);
247 protected abstract void assertSubPath(@NonNull List<T> result);
250 * Test parse fields parameter containing sub-children selected delimited by parenthesis.
253 public void testChildrenPath() {
254 final var result = translateFields(identifierJukebox, assertFields("library(album(name))"));
255 assertNotNull(result);
256 assertChildrenPath(result);
259 protected abstract void assertChildrenPath(@NonNull List<T> result);
262 * Test parse fields parameter when augmentation with different namespace is used.
265 public void testNamespace() {
266 final var result = translateFields(identifierJukebox, assertFields("augmented-jukebox:augmented-library"));
267 assertNotNull(result);
268 assertNamespace(result);
271 protected abstract void assertNamespace(@NonNull List<T> result);
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 '/'.
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);
285 protected abstract void assertMultipleChildren1(@NonNull List<T> result);
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 '/'.
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);
299 protected abstract void assertMultipleChildren2(@NonNull List<T> result);
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.
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);
313 protected abstract void assertMultipleChildren3(@NonNull List<T> result);
316 public void testAugmentedChild() {
317 final var result = translateFields(identifierJukebox, assertFields("player/augmented-jukebox:speed"));
318 assertNotNull(result);
319 assertAugmentedChild(result);
322 protected abstract void assertAugmentedChild(@NonNull List<T> result);
325 public void testListFieldUnderList() {
326 final var result = translateFields(identifierTestServices, assertFields("services/instance"));
327 assertNotNull(result);
328 assertListFieldUnderList(result);
331 protected abstract void assertListFieldUnderList(@NonNull List<T> result);
334 public void testLeafList() {
335 final var result = translateFields(identifierTestServices, assertFields("protocols"));
336 assertNotNull(result);
337 assertLeafList(result);
340 protected abstract void assertLeafList(@NonNull List<T> result);
343 * Test parse fields parameter when not existing child node selected.
346 public void testMissingChildSchema() throws ParseException {
347 final FieldsParam input = FieldsParam.parse("library(not-existing)");
349 final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
350 () -> translateFields(identifierJukebox, input));
352 assertEquals(ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType());
353 assertEquals(ErrorTag.INVALID_VALUE, ex.getErrors().get(0).getErrorTag());
356 private static FieldsParam assertFields(final String input) {
358 return FieldsParam.parse(input);
359 } catch (ParseException e) {
360 throw new AssertionError(e);