2 * Copyright (c) 2014 Brocade Communications 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.netconf.sal.rest.doc.impl;
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.mockito.Mockito.mock;
14 import static org.mockito.Mockito.when;
16 import com.fasterxml.jackson.databind.JsonNode;
17 import com.fasterxml.jackson.databind.node.ObjectNode;
18 import java.util.HashSet;
19 import java.util.Iterator;
20 import java.util.List;
22 import java.util.Optional;
24 import java.util.TreeSet;
25 import javax.ws.rs.core.UriInfo;
26 import org.glassfish.jersey.internal.util.collection.ImmutableMultivaluedMap;
27 import org.junit.Before;
28 import org.junit.Test;
29 import org.opendaylight.mdsal.dom.api.DOMMountPoint;
30 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
31 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
32 import org.opendaylight.netconf.sal.rest.doc.impl.ApiDocServiceImpl.OAversion;
33 import org.opendaylight.netconf.sal.rest.doc.mountpoints.MountPointSwagger;
34 import org.opendaylight.netconf.sal.rest.doc.swagger.OpenApiObject;
35 import org.opendaylight.netconf.sal.rest.doc.swagger.SwaggerObject;
36 import org.opendaylight.yangtools.yang.common.QName;
37 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
39 public final class MountPointSwaggerTest extends AbstractApiDocTest {
40 private static final String TOASTER = "toaster";
41 private static final String TOASTER_REVISION = "2009-11-20";
42 private static final Long DEVICE_ID = 1L;
43 private static final String DEVICE_NAME = "123";
44 private static final String TOASTER_NODE_PATH = "/rests/data/nodes/node=123/yang-ext:mount/toaster:toaster";
45 private static final String TOASTER_NODE_GET_SUMMARY = "GET - " + DEVICE_NAME + " - toaster - toaster";
46 private static final String GET_ALL = "http://localhost:8181/openapi/api/v3/mounts/" + DEVICE_ID;
47 private static final String GET_TOASTER = "http://localhost:8181/openapi/api/v3/mounts/%s/%s(%s)".formatted(
48 DEVICE_ID, TOASTER, TOASTER_REVISION);
49 private static final YangInstanceIdentifier INSTANCE_ID = YangInstanceIdentifier.builder()
50 .node(QName.create("", "nodes"))
51 .node(QName.create("", "node"))
52 .nodeWithKey(QName.create("", "node"), QName.create("", "id"), DEVICE_NAME).build();
53 private static final String INSTANCE_URL = "/nodes/node=123/";
55 private MountPointSwagger swagger;
56 private UriInfo uriDeviceAll;
57 private UriInfo uriDeviceToaster;
60 public void before() throws Exception {
61 // We are sharing the global schema service and the mount schema service
63 // OK for testing - real thing would have separate instances.
64 final DOMMountPoint mountPoint = mock(DOMMountPoint.class);
65 when(mountPoint.getService(DOMSchemaService.class)).thenReturn(Optional.of(SCHEMA_SERVICE));
67 final DOMMountPointService service = mock(DOMMountPointService.class);
68 when(service.getMountPoint(INSTANCE_ID)).thenReturn(Optional.of(mountPoint));
70 swagger = new MountPointSwaggerGeneratorRFC8040(SCHEMA_SERVICE, service).getMountPointSwagger();
72 uriDeviceAll = DocGenTestHelper.createMockUriInfo(GET_ALL);
73 when(uriDeviceAll.getQueryParameters()).thenReturn(ImmutableMultivaluedMap.empty());
74 uriDeviceToaster = DocGenTestHelper.createMockUriInfo(GET_TOASTER);
75 when(uriDeviceToaster.getQueryParameters()).thenReturn(ImmutableMultivaluedMap.empty());
79 public void getInstanceIdentifiers() {
80 assertEquals(0, swagger.getInstanceIdentifiers().size());
81 swagger.onMountPointCreated(INSTANCE_ID); // add this ID into the list of mount points
82 assertEquals(1, swagger.getInstanceIdentifiers().size());
83 assertEquals((Long) 1L, swagger.getInstanceIdentifiers().entrySet().iterator().next()
85 assertEquals(INSTANCE_URL, swagger.getInstanceIdentifiers().entrySet().iterator().next()
87 swagger.onMountPointRemoved(INSTANCE_ID); // remove ID from list of mount points
88 assertEquals(0, swagger.getInstanceIdentifiers().size());
92 public void testGetDataStoreApi() {
93 swagger.onMountPointCreated(INSTANCE_ID); // add this ID into the list of mount points
95 final SwaggerObject mountPointApi = (SwaggerObject) swagger.getMountPointApi(URI_INFO, 1L, "Datastores", "-",
97 assertNotNull("failed to find Datastore API", mountPointApi);
99 final ObjectNode pathsObject = mountPointApi.getPaths();
100 assertNotNull(pathsObject);
102 assertEquals("Unexpected api list size", 2, pathsObject.size());
104 final Set<String> actualUrls = new TreeSet<>();
106 final Iterator<Map.Entry<String, JsonNode>> fields = pathsObject.fields();
107 while (fields.hasNext()) {
108 final Map.Entry<String, JsonNode> field = fields.next();
109 final String path = field.getKey();
110 final JsonNode operations = field.getValue();
111 actualUrls.add(field.getKey());
112 assertEquals("unexpected operations size on " + path, 1, operations.size());
114 final JsonNode getOperation = operations.get("get");
116 assertNotNull("unexpected operation method on " + path, getOperation);
118 assertNotNull("expected non-null desc on " + path, getOperation.get("description"));
121 assertEquals(Set.of("/rests/data" + INSTANCE_URL + "yang-ext:mount",
122 "/rests/operations" + INSTANCE_URL + "yang-ext:mount"), actualUrls);
126 * Test that request parameters are correctly numbered.
129 * It means we should have name and name1, etc. when we have the same parameter in path multiple times.
132 public void testParametersNumberingForMountPointApi() {
133 swagger.onMountPointCreated(INSTANCE_ID);
135 final OpenApiObject mountPointApi = (OpenApiObject) swagger.getMountPointApi(URI_INFO, 1L, Optional.empty(),
137 assertNotNull("Failed to find Datastore API", mountPointApi);
139 var pathToList1 = "/rests/data/nodes/node=123/yang-ext:mount/path-params-test:cont/list1={name}";
140 assertTrue(mountPointApi.getPaths().has(pathToList1));
141 assertEquals(List.of("name"), getPathParameters(mountPointApi.getPaths(), pathToList1));
143 var pathToList2 = "/rests/data/nodes/node=123/yang-ext:mount/path-params-test:cont/list1={name}/list2={name1}";
144 assertTrue(mountPointApi.getPaths().has(pathToList2));
145 assertEquals(List.of("name", "name1"), getPathParameters(mountPointApi.getPaths(), pathToList2));
147 var pathToList3 = "/rests/data/nodes/node=123/yang-ext:mount/path-params-test:cont/list3={name}";
148 assertTrue(mountPointApi.getPaths().has(pathToList3));
149 assertEquals(List.of("name"), getPathParameters(mountPointApi.getPaths(), pathToList3));
151 var pathToList4 = "/rests/data/nodes/node=123/yang-ext:mount/path-params-test:cont/list1={name}/list4={name1}";
152 assertTrue(mountPointApi.getPaths().has(pathToList4));
153 assertEquals(List.of("name", "name1"), getPathParameters(mountPointApi.getPaths(), pathToList4));
155 var pathToList5 = "/rests/data/nodes/node=123/yang-ext:mount/path-params-test:cont/list1={name}/cont2";
156 assertTrue(mountPointApi.getPaths().has(pathToList5));
157 assertEquals(List.of("name"), getPathParameters(mountPointApi.getPaths(), pathToList5));
161 * Test that request for actions is correct and has parameters.
164 public void testActionPathsParamsForMountPointApi() {
165 swagger.onMountPointCreated(INSTANCE_ID);
167 final var mountPointApi = (OpenApiObject) swagger.getMountPointApi(URI_INFO, 1L, Optional.empty(),
169 assertNotNull("Failed to find Datastore API", mountPointApi);
171 final var pathWithParameters =
172 "/rests/operations/nodes/node=123/yang-ext:mount/action-types:list={name}/list-action";
173 assertTrue(mountPointApi.getPaths().has(pathWithParameters));
174 assertEquals(List.of("name"), getPathParameters(mountPointApi.getPaths(), pathWithParameters));
176 final var pathWithoutParameters =
177 "/rests/operations/nodes/node=123/yang-ext:mount/action-types:multi-container/inner-container/action";
178 assertTrue(mountPointApi.getPaths().has(pathWithoutParameters));
179 assertEquals(List.of(), getPathParameters(mountPointApi.getPaths(), pathWithoutParameters));
183 public void testSummaryForAllModules() {
184 swagger.onMountPointCreated(INSTANCE_ID);
185 // get OpenApiObject for the device (all modules)
186 final OpenApiObject openApiAll = (OpenApiObject) swagger.getMountPointApi(uriDeviceAll, DEVICE_ID,
187 Optional.empty(), OAversion.V3_0);
188 final var paths = openApiAll.getPaths();
189 final String getToasterSummary = openApiAll.getPaths()
190 .get(TOASTER_NODE_PATH)
194 assertEquals(TOASTER_NODE_GET_SUMMARY, getToasterSummary);
198 public void testSummaryForSingleModule() {
199 swagger.onMountPointCreated(INSTANCE_ID);
200 // get OpenApiObject for a specific module (toaster) associated with the mounted device
201 final OpenApiObject openApiToaster = (OpenApiObject) swagger.getMountPointApi(uriDeviceToaster, DEVICE_ID,
202 TOASTER, TOASTER_REVISION, OAversion.V3_0);
203 final String getToasterSummary = openApiToaster.getPaths()
204 .get(TOASTER_NODE_PATH)
208 assertEquals(TOASTER_NODE_GET_SUMMARY, getToasterSummary);
212 public void testPathsForSpecificModuleOfMounted() {
213 swagger.onMountPointCreated(INSTANCE_ID);
214 // get OpenApiObject for the device (all modules)
215 final OpenApiObject openApiAll = (OpenApiObject) swagger.getMountPointApi(uriDeviceAll, DEVICE_ID,
216 Optional.empty(), OAversion.V3_0);
217 // get OpenApiObject for a specific module (toaster(2009-11-20))
218 final OpenApiObject openApiToaster = (OpenApiObject) swagger.getMountPointApi(uriDeviceToaster, DEVICE_ID,
219 TOASTER, TOASTER_REVISION, OAversion.V3_0);
221 filter paths from openapi for all modules down to only those that are present in openapi for toaster.
222 The object for the path, that in this case ends with "yang-ext:mount" is constructed in a different way
223 when requesting OpenApiObject for a single module compared to requesting it for all modules.
224 We do not want to include it in this particular comparison, so filter it out
226 final Set<JsonNode> toasterPathsFromAll = new HashSet<>();
227 openApiAll.getPaths().fieldNames().forEachRemaining(path -> {
228 if (openApiToaster.getPaths().has(path) && !path.endsWith("yang-ext:mount")) {
229 toasterPathsFromAll.add(openApiAll.getPaths().get(path));
232 final Set<JsonNode> toasterPathsFromToaster = new HashSet<>();
233 openApiToaster.getPaths().fieldNames().forEachRemaining(path -> {
234 if (!path.endsWith("yang-ext:mount")) {
235 toasterPathsFromToaster.add(openApiToaster.getPaths().get(path));
238 // verify that the filtered set (from openapi for all modules) is the same as the set from openapi for toaster
239 assertEquals(toasterPathsFromToaster, toasterPathsFromAll);
243 * Test that checks if namespace for rpc is present.
246 public void testRpcNamespace() {
247 swagger.onMountPointCreated(INSTANCE_ID);
248 final OpenApiObject openApiToaster = (OpenApiObject) swagger.getMountPointApi(uriDeviceToaster, DEVICE_ID,
249 TOASTER, TOASTER_REVISION, OAversion.V3_0);
250 final var path = openApiToaster
251 .getPaths().get("/rests/operations/nodes/node=123/yang-ext:mount/toaster:cancel-toast");
253 final var post = path.get("post");
255 final var requestBody = post.get("requestBody");
256 assertNotNull(requestBody);
257 final var content = requestBody.get("content");
258 assertNotNull(content);
259 final var application = content.get("application/xml");
260 assertNotNull(application);
261 final var schema = application.get("schema");
262 assertNotNull(schema);
263 final var xml = schema.get("xml");
265 final var namespace = xml.get("namespace");
266 assertNotNull(namespace);
267 assertEquals("http://netconfcentral.org/ns/toaster", namespace.asText());
271 * Test that checks if namespace for actions is present.
274 public void testActionsNamespace() {
275 swagger.onMountPointCreated(INSTANCE_ID);
276 final var openApiAll = (OpenApiObject) swagger.getMountPointApi(uriDeviceAll, DEVICE_ID,
277 Optional.empty(), OAversion.V3_0);
278 final var path = openApiAll.getPaths().get(
279 "/rests/operations/nodes/node=123/yang-ext:mount/action-types:multi-container/inner-container/action");
281 final var post = path.get("post");
283 final var requestBody = post.get("requestBody");
284 assertNotNull(requestBody);
285 final var content = requestBody.get("content");
286 assertNotNull(content);
287 final var application = content.get("application/xml");
288 assertNotNull(application);
289 final var schema = application.get("schema");
290 assertNotNull(schema);
291 final var xml = schema.get("xml");
293 final var namespace = xml.get("namespace");
294 assertNotNull(namespace);
295 assertEquals("urn:ietf:params:xml:ns:yang:test:action:types", namespace.asText());