Test paths with single module vs all modules
[netconf.git] / restconf / sal-rest-docgen / src / test / java / org / opendaylight / netconf / sal / rest / doc / impl / MountPointSwaggerTest.java
1 /*
2  * Copyright (c) 2014 Brocade Communications 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.netconf.sal.rest.doc.impl;
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.mockito.Mockito.mock;
14 import static org.mockito.Mockito.when;
15
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;
21 import java.util.Map;
22 import java.util.Optional;
23 import java.util.Set;
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;
38
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/";
54
55     private MountPointSwagger swagger;
56     private UriInfo uriDeviceAll;
57     private UriInfo uriDeviceToaster;
58
59     @Before
60     public void before() throws Exception {
61         // We are sharing the global schema service and the mount schema service
62         // in our test.
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));
66
67         final DOMMountPointService service = mock(DOMMountPointService.class);
68         when(service.getMountPoint(INSTANCE_ID)).thenReturn(Optional.of(mountPoint));
69
70         swagger = new MountPointSwaggerGeneratorRFC8040(SCHEMA_SERVICE, service).getMountPointSwagger();
71
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());
76     }
77
78     @Test()
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()
84                 .getValue());
85         assertEquals(INSTANCE_URL, swagger.getInstanceIdentifiers().entrySet().iterator().next()
86                 .getKey());
87         swagger.onMountPointRemoved(INSTANCE_ID); // remove ID from list of mount points
88         assertEquals(0, swagger.getInstanceIdentifiers().size());
89     }
90
91     @Test
92     public void testGetDataStoreApi() {
93         swagger.onMountPointCreated(INSTANCE_ID); // add this ID into the list of mount points
94
95         final SwaggerObject mountPointApi = (SwaggerObject) swagger.getMountPointApi(URI_INFO, 1L, "Datastores", "-",
96             OAversion.V2_0);
97         assertNotNull("failed to find Datastore API", mountPointApi);
98
99         final ObjectNode pathsObject = mountPointApi.getPaths();
100         assertNotNull(pathsObject);
101
102         assertEquals("Unexpected api list size", 2, pathsObject.size());
103
104         final Set<String> actualUrls = new TreeSet<>();
105
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());
113
114             final JsonNode getOperation = operations.get("get");
115
116             assertNotNull("unexpected operation method on " + path, getOperation);
117
118             assertNotNull("expected non-null desc on " + path, getOperation.get("description"));
119         }
120
121         assertEquals(Set.of("/rests/data" + INSTANCE_URL + "yang-ext:mount",
122             "/rests/operations" + INSTANCE_URL + "yang-ext:mount"), actualUrls);
123     }
124
125     /**
126      * Test that request parameters are correctly numbered.
127      *
128      * <p>
129      * It means we should have name and name1, etc. when we have the same parameter in path multiple times.
130      */
131     @Test
132     public void testParametersNumberingForMountPointApi() {
133         swagger.onMountPointCreated(INSTANCE_ID);
134
135         final OpenApiObject mountPointApi = (OpenApiObject) swagger.getMountPointApi(URI_INFO, 1L, Optional.empty(),
136                 OAversion.V3_0);
137         assertNotNull("Failed to find Datastore API", mountPointApi);
138
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));
142
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));
146
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));
150
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));
154
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));
158     }
159
160     /**
161      * Test that request for actions is correct and has parameters.
162      */
163     @Test
164     public void testActionPathsParamsForMountPointApi() {
165         swagger.onMountPointCreated(INSTANCE_ID);
166
167         final var mountPointApi = (OpenApiObject) swagger.getMountPointApi(URI_INFO, 1L, Optional.empty(),
168             OAversion.V3_0);
169         assertNotNull("Failed to find Datastore API", mountPointApi);
170
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));
175
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));
180     }
181
182     @Test
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)
191             .get("get")
192             .get("summary")
193             .asText();
194         assertEquals(TOASTER_NODE_GET_SUMMARY, getToasterSummary);
195     }
196
197     @Test
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)
205             .get("get")
206             .get("summary")
207             .asText();
208         assertEquals(TOASTER_NODE_GET_SUMMARY, getToasterSummary);
209     }
210
211     @Test
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);
220         /*
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
225          */
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));
230             }
231         });
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));
236             }
237         });
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);
240     }
241 }