X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=restconf%2Fsal-rest-docgen%2Fsrc%2Ftest%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Frest%2Fdoc%2Fimpl%2FApiDocGeneratorTest.java;h=4595cb1b676eb56f19431f60c464acce10156b77;hb=4f8fe6ca68115fecdb9ce43573af5a2e26c50b50;hp=c72b5f019dff53a24c8ec22779c4ded342ceb5e7;hpb=42fca64cadd8bce723dc2b74bcf8cc73143189b0;p=netconf.git diff --git a/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGeneratorTest.java b/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGeneratorTest.java index c72b5f019d..4595cb1b67 100644 --- a/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGeneratorTest.java +++ b/restconf/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGeneratorTest.java @@ -13,60 +13,47 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.base.Preconditions; import java.sql.Date; import java.util.Arrays; import java.util.HashSet; -import java.util.List; +import java.util.Iterator; import java.util.Set; import java.util.TreeSet; -import javax.ws.rs.core.UriInfo; -import org.json.JSONException; -import org.json.JSONObject; -import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.opendaylight.controller.sal.core.api.model.SchemaService; -import org.opendaylight.netconf.sal.rest.doc.impl.ApiDocGenerator; -import org.opendaylight.netconf.sal.rest.doc.swagger.Api; -import org.opendaylight.netconf.sal.rest.doc.swagger.ApiDeclaration; -import org.opendaylight.netconf.sal.rest.doc.swagger.Operation; -import org.opendaylight.netconf.sal.rest.doc.swagger.Parameter; -import org.opendaylight.netconf.sal.rest.doc.swagger.Resource; -import org.opendaylight.netconf.sal.rest.doc.swagger.ResourceList; +import org.opendaylight.netconf.sal.rest.doc.impl.ApiDocGeneratorDraftO2; +import org.opendaylight.netconf.sal.rest.doc.impl.ApiDocServiceImpl; +import org.opendaylight.netconf.sal.rest.doc.impl.ApiDocServiceImpl.URIType; +import org.opendaylight.netconf.sal.rest.doc.swagger.SwaggerObject; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; import org.opendaylight.yangtools.yang.model.api.Module; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -/** - * - */ public class ApiDocGeneratorTest { - public static final String HTTP_HOST = "http://host"; private static final String NAMESPACE = "http://netconfcentral.org/ns/toaster2"; private static final String STRING_DATE = "2009-11-20"; private static final Date DATE = Date.valueOf(STRING_DATE); private static final String NAMESPACE_2 = "http://netconfcentral.org/ns/toaster"; private static final Date REVISION_2 = Date.valueOf(STRING_DATE); - private ApiDocGenerator generator; + private ApiDocGeneratorDraftO2 generator; private DocGenTestHelper helper; - private SchemaContext schemaContext; + private EffectiveModelContext schemaContext; @Before public void setUp() throws Exception { - this.generator = new ApiDocGenerator(); this.helper = new DocGenTestHelper(); this.helper.setUp(); this.schemaContext = this.helper.getSchemaContext(); - } - @After - public void after() throws Exception { + this.generator = new ApiDocGeneratorDraftO2(this.helper.createMockSchemaService(this.schemaContext)); } /** - * Method: getApiDeclaration(String module, String revision, UriInfo uriInfo) + * Method: getApiDeclaration(String module, String revision, UriInfo uriInfo). */ @Test public void testGetModuleDoc() throws Exception { @@ -75,139 +62,83 @@ public class ApiDocGeneratorTest { for (final Module m : this.helper.getSchemaContext().getModules()) { if (m.getQNameModule().getNamespace().toString().equals(NAMESPACE) && m.getQNameModule().getRevision().equals(DATE)) { - final ApiDeclaration doc = this.generator.getSwaggerDocSpec(m, "http://localhost:8080/restconf", "", - this.schemaContext); + final SwaggerObject doc = this.generator.getSwaggerDocSpec(m, "http","localhost:8181", "/", "", + this.schemaContext, URIType.DRAFT02, ApiDocServiceImpl.OAversion.V2_0); validateToaster(doc); - validateTosterDocContainsModulePrefixes(doc); validateSwaggerModules(doc); - validateSwaggerApisForPost(doc); } } } /** - * Validate whether ApiDelcaration contains Apis with concrete path and whether this Apis contain specified POST - * operations. + * Validates whether doc {@code doc} contains concrete specified models. */ - private void validateSwaggerApisForPost(final ApiDeclaration doc) { - // two POST URI with concrete schema name in summary - final Api lstApi = findApi("/config/toaster2:lst/", doc); - assertNotNull("Api /config/toaster2:lst/ wasn't found", lstApi); - assertTrue("POST for cont1 in lst is missing", - findOperation(lstApi.getOperations(), "POST", "(config)lstPOST", "(config)lst1", "(config)cont1")); - - final Api cont1Api = findApi("/config/toaster2:lst/cont1/", doc); - assertNotNull("Api /config/toaster2:lst/cont1/ wasn't found", cont1Api); - assertTrue("POST for cont11 in cont1 is missing", - findOperation(cont1Api.getOperations(), "POST", "(config)cont1POST", "(config)cont11", "(config)lst11")); - - // no POST URI - final Api cont11Api = findApi("/config/toaster2:lst/cont1/cont11/", doc); - assertNotNull("Api /config/toaster2:lst/cont1/cont11/ wasn't found", cont11Api); - assertTrue("POST operation shouldn't be present.", findOperations(cont11Api.getOperations(), "POST").isEmpty()); + private static void validateSwaggerModules(final SwaggerObject doc) { + final ObjectNode definitions = doc.getDefinitions(); + assertNotNull(definitions); - } + final JsonNode configLstTop = definitions.get("toaster2_config_lst_TOP"); + assertNotNull(configLstTop); - /** - * Tries to find operation with name {@code operationName} and with summary {@code summary} - */ - private boolean findOperation(final List operations, final String operationName, final String type, - final String... searchedParameters) { - final Set filteredOperations = findOperations(operations, operationName); - for (final Operation operation : filteredOperations) { - if (operation.getType().equals(type)) { - final List parameters = operation.getParameters(); - return containAllParameters(parameters, searchedParameters); - } - } - return false; - } + containsReferences(configLstTop, "lst", "toaster2_config_lst"); - private Set findOperations(final List operations, final String operationName) { - final Set filteredOperations = new HashSet<>(); - for (final Operation operation : operations) { - if (operation.getMethod().equals(operationName)) { - filteredOperations.add(operation); - } - } - return filteredOperations; - } + final JsonNode configLst = definitions.get("toaster2_config_lst"); + assertNotNull(configLst); - private boolean containAllParameters(final List searchedIns, final String[] searchedWhats) { - for (final String searchedWhat : searchedWhats) { - boolean parameterFound = false; - for (final Parameter searchedIn : searchedIns) { - if (searchedIn.getType().equals(searchedWhat)) { - parameterFound = true; - } - } - if (!parameterFound) { - return false; - } - } - return true; - } + containsReferences(configLst, "lst1", "toaster2_lst_config_lst1"); + containsReferences(configLst, "cont1", "toaster2_lst_config_cont1"); - /** - * Tries to find {@code Api} with path {@code path} - */ - private Api findApi(final String path, final ApiDeclaration doc) { - for (final Api api : doc.getApis()) { - if (api.getPath().equals(path)) { - return api; - } - } - return null; - } + final JsonNode configLst1Top = definitions.get("toaster2_lst_config_lst1_TOP"); + assertNotNull(configLst1Top); - /** - * Validates whether doc {@code doc} contains concrete specified models. - */ - private void validateSwaggerModules(final ApiDeclaration doc) { - final JSONObject models = doc.getModels(); - assertNotNull(models); - try { - final JSONObject configLst = models.getJSONObject("(config)lst"); - assertNotNull(configLst); + containsReferences(configLst1Top, "lst1", "toaster2_config_lst"); - containsReferences(configLst, "lst1"); - containsReferences(configLst, "cont1"); + final JsonNode configLst1 = definitions.get("toaster2_lst_config_lst1"); + assertNotNull(configLst1); - final JSONObject configLst1 = models.getJSONObject("(config)lst1"); - assertNotNull(configLst1); + final JsonNode configCont1Top = definitions.get("toaster2_lst_config_cont1_TOP"); + assertNotNull(configCont1Top); - final JSONObject configCont1 = models.getJSONObject("(config)cont1"); - assertNotNull(configCont1); + containsReferences(configCont1Top, "cont1", "toaster2_config_lst"); + final JsonNode configCont1 = definitions.get("toaster2_lst_config_cont1"); + assertNotNull(configCont1); - containsReferences(configCont1, "cont11"); - containsReferences(configCont1, "lst11"); + containsReferences(configCont1, "cont11", "toaster2_lst_config_cont1"); + containsReferences(configCont1, "lst11", "toaster2_lst_config_lst1"); - final JSONObject configCont11 = models.getJSONObject("(config)cont11"); - assertNotNull(configCont11); + final JsonNode configCont11Top = definitions.get("toaster2_lst_cont1_config_cont11_TOP"); + assertNotNull(configCont11Top); - final JSONObject configLst11 = models.getJSONObject("(config)lst11"); - assertNotNull(configLst11); - } catch (final JSONException e) { - fail("JSONException wasn't expected"); - } + containsReferences(configCont11Top, "cont11", "toaster2_lst_config_cont1"); + final JsonNode configCont11 = definitions.get("toaster2_lst_cont1_config_cont11"); + assertNotNull(configCont11); + final JsonNode configLst11Top = definitions.get("toaster2_lst_cont1_config_lst11_TOP"); + assertNotNull(configLst11Top); + + containsReferences(configLst11Top, "lst11", "toaster2_lst_config_cont1"); + final JsonNode configLst11 = definitions.get("toaster2_lst_cont1_config_lst11"); + assertNotNull(configLst11); } /** * Checks whether object {@code mainObject} contains in properties/items key $ref with concrete value. */ - private void containsReferences(final JSONObject mainObject, final String childObject) throws JSONException { - final JSONObject properties = mainObject.getJSONObject("properties"); + private static void containsReferences(final JsonNode mainObject, final String childObject, + final String expectedRef) { + final JsonNode properties = mainObject.get("properties"); assertNotNull(properties); - final JSONObject nodeInProperties = properties.getJSONObject(childObject); - assertNotNull(nodeInProperties); - - final JSONObject itemsInNodeInProperties = nodeInProperties.getJSONObject("items"); - assertNotNull(itemsInNodeInProperties); + final JsonNode childNode = properties.get(childObject); + assertNotNull(childNode); - final String itemRef = itemsInNodeInProperties.getString("$ref"); - assertEquals("(config)" + childObject, itemRef); + //list case + JsonNode refWrapper = childNode.get("items"); + if (refWrapper == null) { + //container case + refWrapper = childNode; + } + assertEquals(expectedRef, refWrapper.get("$ref").asText()); } @Test @@ -217,14 +148,38 @@ public class ApiDocGeneratorTest { for (final Module m : this.helper.getModules()) { if (m.getQNameModule().getNamespace().toString().equals(NAMESPACE_2) && m.getQNameModule().getRevision().equals(REVISION_2)) { - final ApiDeclaration doc = this.generator.getSwaggerDocSpec(m, "http://localhost:8080/restconf", "", - this.schemaContext); + final SwaggerObject doc = this.generator.getSwaggerDocSpec(m, "http", "localhost:8080", "/restconf", "", + this.schemaContext, URIType.DRAFT02, ApiDocServiceImpl.OAversion.V2_0); assertNotNull(doc); // testing bugs.opendaylight.org bug 1290. UnionType model type. - final String jsonString = doc.getModels().toString(); - assertTrue(jsonString.contains( - "testUnion\":{\"type\":\"integer or string\",\"required\":false}")); + final String jsonString = doc.getDefinitions().toString(); + assertTrue(jsonString.contains("testUnion\":{\"required\":false,\"type\":\"-2147483648\"," + + "\"enum\":[\"-2147483648\",\"Some testUnion\"]}")); + } + } + } + + @Test + public void testRPCsModel() throws Exception { + Preconditions.checkArgument(this.helper.getModules() != null, "No modules found"); + + for (final Module m : this.helper.getModules()) { + if (m.getQNameModule().getNamespace().toString().equals(NAMESPACE_2) + && m.getQNameModule().getRevision().equals(REVISION_2)) { + final SwaggerObject doc = this.generator.getSwaggerDocSpec(m, "http","localhost:8181", "/", "", + this.schemaContext, URIType.DRAFT02, ApiDocServiceImpl.OAversion.V2_0); + assertNotNull(doc); + + final ObjectNode definitions = doc.getDefinitions(); + final JsonNode inputTop = definitions.get("toaster_make-toast_input_TOP"); + assertNotNull(inputTop); + final String testString = "{\"input\":{\"$ref\":\"toaster_make-toast_input\"}}"; + assertEquals(testString, inputTop.get("properties").toString()); + final JsonNode input = definitions.get("toaster_make-toast_input"); + final JsonNode properties = input.get("properties"); + assertTrue(properties.has("toasterDoneness")); + assertTrue(properties.has("toasterToastType")); } } } @@ -232,104 +187,74 @@ public class ApiDocGeneratorTest { /** * Tests whether from yang files are generated all required paths for HTTP operations (GET, DELETE, PUT, POST) * - * If container | list is augmented then in path there should be specified module name followed with collon (e. g. + *

+ * If container | list is augmented then in path there should be specified module name followed with colon (e. g. * "/config/module1:element1/element2/module2:element3") * - * @param doc - * @throws Exception + * @param doc Api declaration + * @throws Exception if operation fails */ - private void validateToaster(final ApiDeclaration doc) throws Exception { - final Set expectedUrls = new TreeSet<>(Arrays.asList(new String[] { "/config/toaster2:toaster/", - "/operational/toaster2:toaster/", "/operations/toaster2:cancel-toast", - "/operations/toaster2:make-toast", "/operations/toaster2:restock-toaster", - "/config/toaster2:toaster/toasterSlot/{slotId}/toaster-augmented:slotInfo/" })); + private static void validateToaster(final SwaggerObject doc) throws Exception { + final Set expectedUrls = + new TreeSet<>(Arrays.asList("/restconf/config", "/restconf/config/toaster2:toaster", + "/restconf/config/toaster2:toaster/toasterSlot/{slotId}", + "/restconf/config/toaster2:toaster/toasterSlot/{slotId}/toaster-augmented:slotInfo", + "/restconf/operational/toaster2:toaster/toasterSlot/{slotId}", + "/restconf/operational/toaster2:toaster/toasterSlot/{slotId}/toaster-augmented:slotInfo", + "/restconf/config/toaster2:lst", + "/restconf/config/toaster2:lst/cont1", + "/restconf/config/toaster2:lst/cont1/cont11", + "/restconf/config/toaster2:lst/cont1/lst11", + "/restconf/config/toaster2:lst/lst1/{key1}/{key2}", + "/restconf/operational/toaster2:lst", + "/restconf/operational/toaster2:lst/cont1", + "/restconf/operational/toaster2:lst/cont1/cont11", + "/restconf/operational/toaster2:lst/cont1/lst11", + "/restconf/operational/toaster2:lst/lst1/{key1}/{key2}", + "/restconf/operational/toaster2:lst/lst1/{key1}/{key2}", + "/restconf/operations/toaster2:make-toast", + "/restconf/operations/toaster2:cancel-toast")); + final Set actualUrls = new TreeSet<>(); - Api configApi = null; - for (final Api api : doc.getApis()) { - actualUrls.add(api.getPath()); - if (api.getPath().contains("/config/toaster2:toaster/")) { - configApi = api; + final Set configActualPathItems = new HashSet<>(); + for (final JsonNode pathItem : doc.getPaths()) { + final String actualUrl = pathItem.fieldNames().next(); + actualUrls.add(actualUrl); + if (actualUrl.contains("/config/toaster2:toaster/")) { + configActualPathItems.add(pathItem); } } - boolean containsAll = actualUrls.containsAll(expectedUrls); - if (!containsAll) { + final boolean isAllDocumented = actualUrls.containsAll(expectedUrls); + + if (!isAllDocumented) { expectedUrls.removeAll(actualUrls); fail("Missing expected urls: " + expectedUrls); } - final Set expectedConfigMethods = new TreeSet<>(Arrays.asList(new String[] { "GET", "PUT", "DELETE" })); - final Set actualConfigMethods = new TreeSet<>(); - for (final Operation oper : configApi.getOperations()) { - actualConfigMethods.add(oper.getMethod()); - } + final Set expectedConfigMethods = new TreeSet<>(Arrays.asList("get", "put", "delete", "post")); - containsAll = actualConfigMethods.containsAll(expectedConfigMethods); - if (!containsAll) { - expectedConfigMethods.removeAll(actualConfigMethods); - fail("Missing expected method on config API: " + expectedConfigMethods); + for (final JsonNode configPathItem : configActualPathItems) { + final Set actualConfigMethods = new TreeSet<>(); + final JsonNode operations = configPathItem.get(0); + final Iterator it = operations.fieldNames(); + while (it.hasNext()) { + actualConfigMethods.add(it.next()); + } + final boolean isAllMethods = actualConfigMethods.containsAll(expectedConfigMethods); + if (!isAllMethods) { + expectedConfigMethods.removeAll(actualConfigMethods); + fail("Missing expected method on config API: " + expectedConfigMethods); + } } // TODO: we should really do some more validation of the // documentation... - /** + /* * Missing validation: Explicit validation of URLs, and their methods Input / output models. */ } - @Test - public void testGetResourceListing() throws Exception { - final UriInfo info = this.helper.createMockUriInfo(HTTP_HOST); - final SchemaService mockSchemaService = this.helper.createMockSchemaService(this.schemaContext); - - this.generator.setSchemaService(mockSchemaService); - - final ResourceList resourceListing = this.generator.getResourceListing(info); - - Resource toaster = null; - Resource toaster2 = null; - for (final Resource r : resourceListing.getApis()) { - final String path = r.getPath(); - if (path.contains("toaster2")) { - toaster2 = r; - } else if (path.contains("toaster")) { - toaster = r; - } - } - - assertNotNull(toaster2); - assertNotNull(toaster); - - assertEquals(HTTP_HOST + "/toaster(2009-11-20)", toaster.getPath()); - assertEquals(HTTP_HOST + "/toaster2(2009-11-20)", toaster2.getPath()); - } - - private void validateTosterDocContainsModulePrefixes(final ApiDeclaration doc) { - final JSONObject topLevelJson = doc.getModels(); - try { - final JSONObject configToaster = topLevelJson.getJSONObject("(config)toaster"); - assertNotNull("(config)toaster JSON object missing", configToaster); - // without module prefix - containsProperties(configToaster, "toasterSlot"); - - final JSONObject toasterSlot = topLevelJson.getJSONObject("(config)toasterSlot"); - assertNotNull("(config)toasterSlot JSON object missing", toasterSlot); - // with module prefix - containsProperties(toasterSlot, "toaster-augmented:slotInfo"); - - } catch (final JSONException e) { - fail("Json exception while reading JSON object. Original message " + e.getMessage()); - } - } - - private void containsProperties(final JSONObject jsonObject, final String... properties) throws JSONException { - for (final String property : properties) { - final JSONObject propertiesObject = jsonObject.getJSONObject("properties"); - assertNotNull("Properties object missing in ", propertiesObject); - final JSONObject concretePropertyObject = propertiesObject.getJSONObject(property); - assertNotNull(property + " is missing", concretePropertyObject); - } - } }