From 0b032d20dd66b886d9be6f0d10c84b31841435de Mon Sep 17 00:00:00 2001 From: Jozef Gloncak Date: Wed, 25 Jun 2014 11:16:05 +0200 Subject: [PATCH] BUG 1016 - JSON|XML output with|without white chars Pretty print formating can be turned on for XML | JSON output via URI parameter prettyPrint=true. In other cases (prettyPrint=false, other value, missing URI parameter...) XML | JSON output are returned as stream of characters without white characters. Example of URI: http://localhost:8080/restconf/config/opendaylight-inventory:nodes?prettyPrint=true Change-Id: I459c9663cdf8bfc78b8df67d7338a44d77c18a5c Signed-off-by: Jozef Gloncak --- .../sal/rest/api/RestconfService.java | 128 +++++++++--------- .../impl/StructuredDataToJsonProvider.java | 13 +- .../impl/StructuredDataToXmlProvider.java | 9 +- .../sal/restconf/impl/RestconfImpl.java | 81 ++++++----- .../sal/restconf/impl/StructuredData.java | 11 ++ .../CnSnToJsonNotExistingLeafTypeTest.java | 5 +- .../json/test/CnSnToJsonWithAugmentTest.java | 17 ++- ...nSnToXmlAndJsonInstanceIdentifierTest.java | 81 ++++++----- .../impl/test/InvokeRpcMethodTest.java | 37 ++--- .../restconf/impl/test/MediaTypesTest.java | 80 ++++++----- .../impl/test/RestGetOperationTest.java | 41 +++++- .../sal/restconf/impl/test/TestUtils.java | 23 +++- 12 files changed, 302 insertions(+), 224 deletions(-) diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java index 056be72d4e..2f11d8ed7d 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/api/RestconfService.java @@ -10,42 +10,41 @@ package org.opendaylight.controller.sal.rest.api; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; +import javax.ws.rs.Encoded; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; -import javax.ws.rs.Encoded; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; - import org.opendaylight.controller.sal.restconf.impl.StructuredData; import org.opendaylight.yangtools.yang.data.api.CompositeNode; /** - * The URI hierarchy for the RESTCONF resources consists of an entry - * point container, 4 top-level resources, and 1 field. - * + * The URI hierarchy for the RESTCONF resources consists of an entry point + * container, 4 top-level resources, and 1 field. + * */ @Path("/") public interface RestconfService { @@ -58,81 +57,81 @@ public interface RestconfService { @GET @Path("/modules") - @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public StructuredData getModules(); + @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) + public StructuredData getModules(@Context UriInfo uriInfo); @GET @Path("/modules/{identifier:.+}") - @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public StructuredData getModules(@PathParam("identifier") String identifier); + @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) + public StructuredData getModules(@PathParam("identifier") String identifier, @Context UriInfo uriInfo); @GET @Path("/modules/module/{identifier:.+}") - @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public StructuredData getModule(@PathParam("identifier") String identifier); + @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) + public StructuredData getModule(@PathParam("identifier") String identifier, @Context UriInfo uriInfo); @GET @Path("/operations") - @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public StructuredData getOperations(); + @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) + public StructuredData getOperations(@Context UriInfo uriInfo); @GET @Path("/operations/{identifier:.+}") - @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public StructuredData getOperations(@PathParam("identifier") String identifier); + @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) + public StructuredData getOperations(@PathParam("identifier") String identifier, @Context UriInfo uriInfo); @POST @Path("/operations/{identifier:.+}") - @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML, - Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - @Consumes({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML, - Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, CompositeNode payload); + @Produces({ Draft02.MediaTypes.OPERATION + JSON, Draft02.MediaTypes.OPERATION + XML, + Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) + @Consumes({ Draft02.MediaTypes.OPERATION + JSON, Draft02.MediaTypes.OPERATION + XML, + Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) + public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, CompositeNode payload, @Context UriInfo uriInfo); @POST @Path("/operations/{identifier:.+}") - @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML, - Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, @DefaultValue("") String noPayload); + @Produces({ Draft02.MediaTypes.OPERATION + JSON, Draft02.MediaTypes.OPERATION + XML, + Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) + public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, + @DefaultValue("") String noPayload, @Context UriInfo uriInfo); @GET @Path("/config/{identifier:.+}") - @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) + @Produces({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public StructuredData readConfigurationData(@Encoded @PathParam("identifier") String identifier, - @Context UriInfo depth); + @Context UriInfo uriInfo); @GET @Path("/operational/{identifier:.+}") - @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public StructuredData readOperationalData(@Encoded @PathParam("identifier") String identifier, - @Context UriInfo depth); + @Produces({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) + public StructuredData readOperationalData(@Encoded @PathParam("identifier") String identifier, @Context UriInfo uriInfo); @PUT @Path("/config/{identifier:.+}") - @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) + @Consumes({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public Response updateConfigurationData(@Encoded @PathParam("identifier") String identifier, CompositeNode payload); @POST @Path("/config/{identifier:.+}") - @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) + @Consumes({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public Response createConfigurationData(@Encoded @PathParam("identifier") String identifier, CompositeNode payload); @POST @Path("/config") - @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) + @Consumes({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) public Response createConfigurationData(CompositeNode payload); @DELETE @@ -145,9 +144,8 @@ public interface RestconfService { @GET @Path("/streams") - @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML}) - public StructuredData getAvailableStreams(); - + @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON, + MediaType.APPLICATION_XML, MediaType.TEXT_XML }) + public StructuredData getAvailableStreams(@Context UriInfo uriInfo); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java index 1c2e9c5009..063d2f51af 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java @@ -9,13 +9,11 @@ package org.opendaylight.controller.sal.rest.impl; import com.google.common.base.Charsets; import com.google.gson.stream.JsonWriter; - import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.lang.annotation.Annotation; import java.lang.reflect.Type; - import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; @@ -23,7 +21,6 @@ import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Provider; - import org.opendaylight.controller.sal.rest.api.Draft02; import org.opendaylight.controller.sal.rest.api.RestconfService; import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; @@ -39,7 +36,7 @@ public enum StructuredDataToJsonProvider implements MessageBodyWriter type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) { - return type.equals( StructuredData.class ); + return type.equals(StructuredData.class); } @Override @@ -57,10 +54,14 @@ public enum StructuredDataToJsonProvider implements MessageBodyWriter type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) { - return type.equals( StructuredData.class ); + return type.equals(StructuredData.class); } @Override @@ -90,6 +88,11 @@ public enum StructuredDataToXmlProvider implements MessageBodyWriter> modulesAsData = new ArrayList>(); @@ -127,11 +139,11 @@ public class RestconfImpl implements RestconfService { restconfModule, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE); QName qName = modulesSchemaNode.getQName(); final CompositeNode modulesNode = NodeFactory.createImmutableCompositeNode(qName, null, modulesAsData); - return new StructuredData(modulesNode, modulesSchemaNode, null); + return new StructuredData(modulesNode, modulesSchemaNode, null,parsePrettyPrintParameter( uriInfo )); } @Override - public StructuredData getAvailableStreams() { + public StructuredData getAvailableStreams(final UriInfo uriInfo) { Set availableStreams = Notificator.getStreamNames(); final List> streamsAsData = new ArrayList>(); @@ -146,11 +158,11 @@ public class RestconfImpl implements RestconfService { restconfModule, Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE); QName qName = streamsSchemaNode.getQName(); final CompositeNode streamsNode = NodeFactory.createImmutableCompositeNode(qName, null, streamsAsData); - return new StructuredData(streamsNode, streamsSchemaNode, null); + return new StructuredData(streamsNode, streamsSchemaNode, null,parsePrettyPrintParameter( uriInfo )); } @Override - public StructuredData getModules(final String identifier) { + public StructuredData getModules(final String identifier,final UriInfo uriInfo) { Set modules = null; MountInstance mountPoint = null; if (identifier.contains(ControllerContext.MOUNT)) { @@ -178,11 +190,11 @@ public class RestconfImpl implements RestconfService { restconfModule, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE); QName qName = modulesSchemaNode.getQName(); final CompositeNode modulesNode = NodeFactory.createImmutableCompositeNode(qName, null, modulesAsData); - return new StructuredData(modulesNode, modulesSchemaNode, mountPoint); + return new StructuredData(modulesNode, modulesSchemaNode, mountPoint,parsePrettyPrintParameter( uriInfo )); } @Override - public StructuredData getModule(final String identifier) { + public StructuredData getModule(final String identifier,final UriInfo uriInfo) { final QName moduleNameAndRevision = this.getModuleNameAndRevision(identifier); Module module = null; MountInstance mountPoint = null; @@ -207,17 +219,17 @@ public class RestconfImpl implements RestconfService { final DataSchemaNode moduleSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode( restconfModule, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE); final CompositeNode moduleNode = this.toModuleCompositeNode(module, moduleSchemaNode); - return new StructuredData(moduleNode, moduleSchemaNode, mountPoint); + return new StructuredData(moduleNode, moduleSchemaNode, mountPoint,parsePrettyPrintParameter( uriInfo )); } @Override - public StructuredData getOperations() { + public StructuredData getOperations(final UriInfo uriInfo) { Set allModules = this.controllerContext.getAllModules(); - return this.operationsFromModulesToStructuredData(allModules, null); + return this.operationsFromModulesToStructuredData(allModules, null,parsePrettyPrintParameter(uriInfo)); } @Override - public StructuredData getOperations(final String identifier) { + public StructuredData getOperations(final String identifier,final UriInfo uriInfo) { Set modules = null; MountInstance mountPoint = null; if (identifier.contains(ControllerContext.MOUNT)) { @@ -232,11 +244,11 @@ public class RestconfImpl implements RestconfService { ControllerContext.MOUNT, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE ); } - return this.operationsFromModulesToStructuredData(modules, mountPoint); + return this.operationsFromModulesToStructuredData(modules, mountPoint,parsePrettyPrintParameter(uriInfo)); } private StructuredData operationsFromModulesToStructuredData(final Set modules, - final MountInstance mountPoint) { + final MountInstance mountPoint,boolean prettyPrint) { final List> operationsAsData = new ArrayList>(); Module restconfModule = this.getRestconfModule(); final DataSchemaNode operationsSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode( @@ -269,7 +281,7 @@ public class RestconfImpl implements RestconfService { final CompositeNode operationsNode = NodeFactory.createImmutableCompositeNode(qName, null, operationsAsData); ContainerSchemaNode schemaNode = fakeOperationsSchemaNode.build(); - return new StructuredData(operationsNode, schemaNode, mountPoint); + return new StructuredData(operationsNode, schemaNode, mountPoint,prettyPrint); } private Module getRestconfModule() { @@ -389,18 +401,18 @@ public class RestconfImpl implements RestconfService { } @Override - public StructuredData invokeRpc(final String identifier, final CompositeNode payload) { + public StructuredData invokeRpc(final String identifier, final CompositeNode payload,final UriInfo uriInfo) { final RpcExecutor rpc = this.resolveIdentifierInInvokeRpc(identifier); QName rpcName = rpc.getRpcDefinition().getQName(); URI rpcNamespace = rpcName.getNamespace(); if (Objects.equal(rpcNamespace.toString(), SAL_REMOTE_NAMESPACE) && Objects.equal(rpcName.getLocalName(), SAL_REMOTE_RPC_SUBSRCIBE)) { - return invokeSalRemoteRpcSubscribeRPC(payload, rpc.getRpcDefinition()); + return invokeSalRemoteRpcSubscribeRPC(payload, rpc.getRpcDefinition(),parsePrettyPrintParameter(uriInfo)); } validateInput( rpc.getRpcDefinition().getInput(), payload ); - return callRpc(rpc, payload); + return callRpc(rpc, payload,parsePrettyPrintParameter(uriInfo)); } private void validateInput(final DataSchemaNode inputSchema, final CompositeNode payload) { @@ -426,7 +438,7 @@ public class RestconfImpl implements RestconfService { } private StructuredData invokeSalRemoteRpcSubscribeRPC(final CompositeNode payload, - final RpcDefinition rpc) { + final RpcDefinition rpc,final boolean prettyPrint) { final CompositeNode value = this.normalizeNode(payload, rpc.getInput(), null); final SimpleNode pathNode = value == null ? null : value.getFirstSimpleByName( QName.create(rpc.getQName(), "path") ); @@ -463,16 +475,16 @@ public class RestconfImpl implements RestconfService { Notificator.createListener(pathIdentifier, streamName); } - return new StructuredData(responseData, rpc.getOutput(), null); + return new StructuredData(responseData, rpc.getOutput(), null,prettyPrint); } @Override - public StructuredData invokeRpc(final String identifier, final String noPayload) { + public StructuredData invokeRpc(final String identifier, final String noPayload, final UriInfo uriInfo) { if (StringUtils.isNotBlank(noPayload)) { throw new RestconfDocumentedException( "Content must be empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE ); } - return invokeRpc( identifier, (CompositeNode)null ); + return invokeRpc( identifier, (CompositeNode)null,uriInfo); } private RpcExecutor resolveIdentifierInInvokeRpc(final String identifier) { @@ -516,7 +528,7 @@ public class RestconfImpl implements RestconfService { } - private StructuredData callRpc(final RpcExecutor rpcExecutor, final CompositeNode payload) { + private StructuredData callRpc(final RpcExecutor rpcExecutor, final CompositeNode payload,boolean prettyPrint) { if (rpcExecutor == null) { throw new RestconfDocumentedException( "RPC does not exist.", ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT ); @@ -547,7 +559,7 @@ public class RestconfImpl implements RestconfService { return null; //no output, nothing to send back. } - return new StructuredData(rpcResult.getResult(), rpc.getOutput(), null); + return new StructuredData(rpcResult.getResult(), rpc.getOutput(), null,prettyPrint); } private void checkRpcSuccessAndThrowException(final RpcResult rpcResult) { @@ -570,7 +582,7 @@ public class RestconfImpl implements RestconfService { } @Override - public StructuredData readConfigurationData(final String identifier, final UriInfo info) { + public StructuredData readConfigurationData(final String identifier, final UriInfo uriInfo) { final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier); CompositeNode data = null; MountInstance mountPoint = iiWithData.getMountPoint(); @@ -581,8 +593,9 @@ public class RestconfImpl implements RestconfService { data = broker.readConfigurationData(iiWithData.getInstanceIdentifier()); } - data = pruneDataAtDepth( data, parseDepthParameter( info ) ); - return new StructuredData(data, iiWithData.getSchemaNode(), iiWithData.getMountPoint()); + data = pruneDataAtDepth( data, parseDepthParameter( uriInfo ) ); + boolean prettyPrintMode = parsePrettyPrintParameter( uriInfo ); + return new StructuredData(data, iiWithData.getSchemaNode(), iiWithData.getMountPoint(),prettyPrintMode); } @SuppressWarnings("unchecked") @@ -607,7 +620,7 @@ public class RestconfImpl implements RestconfService { } private Integer parseDepthParameter( final UriInfo info ) { - String param = info.getQueryParameters( false ).getFirst( "depth" ); + String param = info.getQueryParameters( false ).getFirst( UriParameters.DEPTH.toString() ); if( Strings.isNullOrEmpty( param ) || "unbounded".equals( param ) ) { return null; } @@ -643,7 +656,13 @@ public class RestconfImpl implements RestconfService { } data = pruneDataAtDepth( data, parseDepthParameter( info ) ); - return new StructuredData(data, iiWithData.getSchemaNode(), mountPoint); + boolean prettyPrintMode = parsePrettyPrintParameter( info ); + return new StructuredData(data, iiWithData.getSchemaNode(), mountPoint,prettyPrintMode); + } + + private boolean parsePrettyPrintParameter(UriInfo info) { + String param = info.getQueryParameters(false).getFirst(UriParameters.PRETTY_PRINT.toString()); + return Boolean.parseBoolean(param); } @Override diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java index 231fe7e02e..c745a8009d 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/StructuredData.java @@ -16,11 +16,18 @@ public class StructuredData { private final CompositeNode data; private final DataSchemaNode schema; private final MountInstance mountPoint; + private final boolean prettyPrintMode; public StructuredData(final CompositeNode data, final DataSchemaNode schema, final MountInstance mountPoint) { + this(data, schema, mountPoint, false); + } + + public StructuredData(final CompositeNode data, final DataSchemaNode schema, final MountInstance mountPoint, + final boolean preattyPrintMode) { this.data = data; this.schema = schema; this.mountPoint = mountPoint; + this.prettyPrintMode = preattyPrintMode; } public CompositeNode getData() { @@ -34,4 +41,8 @@ public class StructuredData { public MountInstance getMountPoint() { return mountPoint; } + + public boolean isPrettyPrintMode() { + return prettyPrintMode; + } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonNotExistingLeafTypeTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonNotExistingLeafTypeTest.java index 24dba17c90..3f89c97367 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonNotExistingLeafTypeTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonNotExistingLeafTypeTest.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.opendaylight.controller.sal.restconf.impl.test.TestUtils.containsStringData; import java.io.IOException; import java.util.Collections; @@ -50,7 +51,9 @@ public class CnSnToJsonNotExistingLeafTypeTest extends YangAndXmlAndDataSchemaLo Collections.emptySet(), prepareDataSchemaNode(), StructuredDataToJsonProvider.INSTANCE); assertNotNull(jsonOutput); - assertTrue(jsonOutput.contains("\"lf1\": \"\"")); + +// pattern for e.g. > "lf1" : "" < or >"lf1":""< + assertTrue(containsStringData(jsonOutput, "\"lf1\"",":","\"\"")); } private CompositeNode prepareCompositeNode() { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithAugmentTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithAugmentTest.java index e116129bf7..3d25955b3c 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithAugmentTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithAugmentTest.java @@ -9,11 +9,10 @@ package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.opendaylight.controller.sal.restconf.impl.test.TestUtils.containsStringData; import java.io.IOException; - import javax.ws.rs.WebApplicationException; - import org.junit.BeforeClass; import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; @@ -47,12 +46,12 @@ public class CnSnToJsonWithAugmentTest extends YangAndXmlAndDataSchemaLoader { } assertNotNull(jsonOutput); - assertTrue(jsonOutput.contains("\"augment-leaf:lf2\": \"lf2\"")); - assertTrue(jsonOutput.contains("\"augment-container:cont1\": {")); - assertTrue(jsonOutput.contains("\"augment-container:lf11\": \"lf11\"")); - assertTrue(jsonOutput.contains("\"augment-list:lst1\": [")); - assertTrue(jsonOutput.contains("\"augment-list:lf11\": \"lf1_1\"")); - assertTrue(jsonOutput.contains("\"augment-list:lf11\": \"lf1_2\"")); - assertTrue(jsonOutput.contains("\"augment-leaflist:lflst1\": [")); + assertTrue(containsStringData(jsonOutput,"\"augment-leaf:lf2\"",":", "\"lf2\"")); + assertTrue(containsStringData(jsonOutput,"\"augment-container:cont1\"",":", "\\{")); + assertTrue(containsStringData(jsonOutput,"\"augment-container:lf11\"",":", "\"lf11\"")); + assertTrue(containsStringData(jsonOutput,"\"augment-list:lst1\"",":", "\\[")); + assertTrue(containsStringData(jsonOutput,"\"augment-list:lf11\"",":", "\"lf1_1\"")); + assertTrue(containsStringData(jsonOutput,"\"augment-list:lf11\"",":", "\"lf1_2\"")); + assertTrue(containsStringData(jsonOutput,"\"augment-leaflist:lflst1\"",":", "\\[")); } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java index 3f2c212bd8..47171bf247 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.sal.restconf.impl.test; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.opendaylight.controller.sal.restconf.impl.test.TestUtils.containsStringData; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -19,16 +20,13 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; - import javax.ws.rs.WebApplicationException; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; - import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider; import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider; @@ -39,9 +37,10 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifie import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; -import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode; -import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode; +import org.opendaylight.yangtools.yang.data.api.SimpleNode; +import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; import org.opendaylight.yangtools.yang.data.impl.NodeFactory; +import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder; public class CnSnToXmlAndJsonInstanceIdentifierTest extends YangAndXmlAndDataSchemaLoader { @@ -55,21 +54,16 @@ public class CnSnToXmlAndJsonInstanceIdentifierTest extends YangAndXmlAndDataSch CompositeNode cnSn = prepareCnSn(createInstanceIdentifier()); String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode, StructuredDataToXmlProvider.INSTANCE); - //uncomment for debug - // System.out.println(output); validateXmlOutput(output); } - @Ignore @Test public void saveCnSnWithLeafListInstIdentifierToXmlTest() throws WebApplicationException, IOException, - URISyntaxException, XMLStreamException { + URISyntaxException, XMLStreamException { CompositeNode cnSn = prepareCnSn(createInstanceIdentifierWithLeafList()); String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode, StructuredDataToXmlProvider.INSTANCE); - //uncomment for debug - // System.out.println(output); validateXmlOutputWithLeafList(output); } @@ -79,33 +73,40 @@ public class CnSnToXmlAndJsonInstanceIdentifierTest extends YangAndXmlAndDataSch String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode, StructuredDataToJsonProvider.INSTANCE); boolean strInOutput = false; - strInOutput = output - .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11[augment-module:keyvalue111=\\\"value1\\\"][augment-module:keyvalue112=\\\"value2\\\"]/augment-augment-module:lf112\""); + strInOutput = containsStringData( + output, + "\"augment-augment-module:lf111\"", + ":", + "\"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11\\[augment-module:keyvalue111=\\\\\"value1\\\\\"\\]\\[augment-module:keyvalue112=\\\\\"value2\\\\\"\\]/augment-augment-module:lf112\""); if (!strInOutput) { - strInOutput = output - .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11[augment-module:keyvalue111='value1'][augment-module:keyvalue112='value2']/augment-augment-module:lf112\""); + strInOutput = containsStringData( + output, + "\"augment-augment-module:lf111\"", + ":", + "\"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11\\[augment-module:keyvalue111='value1'\\]\\[augment-module:keyvalue112='value2'\\]/augment-augment-module:lf112\""); } - //uncomment for debug - // System.out.println(output); assertTrue(strInOutput); } - @Test public void saveCnSnWithLeafListInstIdentifierToJsonTest() throws WebApplicationException, IOException, - URISyntaxException { + URISyntaxException { CompositeNode cnSn = prepareCnSn(createInstanceIdentifierWithLeafList()); String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode, StructuredDataToJsonProvider.INSTANCE); - //uncomment for debug - // System.out.println(output); boolean strInOutput = false; - strInOutput = output - .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module-leaf-list:lflst11[.='lflst11_1']\""); + strInOutput = containsStringData( + output, + "\"augment-augment-module:lf111\"", + ":", + "\"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module-leaf-list:lflst11\\[.='lflst11_1'\\]\""); if (!strInOutput) { - strInOutput = output - .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module-leaf-list:lflst11[.=\\\"lflst11_1\\\"]\""); + strInOutput = containsStringData( + output, + "\"augment-augment-module:lf111\"", + ":", + "\"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module-leaf-list:lflst11\\[.=\\\\\"lflst11_1\\\\\"\\]\""); } assertTrue(strInOutput); @@ -189,27 +190,21 @@ public class CnSnToXmlAndJsonInstanceIdentifierTest extends YangAndXmlAndDataSch } private CompositeNode prepareCnSn(final InstanceIdentifier instanceIdentifier) throws URISyntaxException { - MutableCompositeNode cont = NodeFactory.createMutableCompositeNode( - TestUtils.buildQName("cont", "instance:identifier:module", "2014-01-17"), null, null,null,null); - MutableCompositeNode cont1 = NodeFactory.createMutableCompositeNode( - TestUtils.buildQName("cont1", "instance:identifier:module", "2014-01-17"), cont, null,null,null); - MutableCompositeNode lst11 = NodeFactory.createMutableCompositeNode( - TestUtils.buildQName("lst11", "augment:module", "2014-01-17"), cont1, null,null,null); - - MutableSimpleNode lf111 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111", "augment:augment:module", "2014-01-17"), - lst11, instanceIdentifier,null,null); - - - lst11.getValue().add(lf111); - lst11.init(); + CompositeNodeBuilder cont = ImmutableCompositeNode.builder(); + cont.setQName(QName.create("instance:identifier:module", "2014-01-17", "cont")); - cont1.getValue().add(lst11); - cont1.init(); + CompositeNodeBuilder cont1 = ImmutableCompositeNode.builder(); + cont1.setQName(QName.create("instance:identifier:module", "2014-01-17", "cont1")); - cont.getValue().add(cont1); - cont.init(); + CompositeNodeBuilder lst11 = ImmutableCompositeNode.builder(); + lst11.setQName(QName.create("augment:module", "2014-01-17", "lst11")); - return cont; + SimpleNode lf111 = NodeFactory.createImmutableSimpleNode( + QName.create("augment:augment:module", "2014-01-17", "lf111"), null, instanceIdentifier); + lst11.add(lf111); + cont1.add(lst11.toInstance()); + cont.add(cont1.toInstance()); + return cont.toInstance(); } private InstanceIdentifier createInstanceIdentifier() throws URISyntaxException { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java index 910ca8e20a..b90097bc94 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java @@ -19,6 +19,9 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import java.io.FileNotFoundException; import java.net.URI; import java.net.URISyntaxException; @@ -27,7 +30,9 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; - +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriInfo; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -56,14 +61,11 @@ import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import com.google.common.base.Optional; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; - public class InvokeRpcMethodTest { private RestconfImpl restconfImpl = null; private static ControllerContext controllerContext = null; + private static UriInfo uriInfo; @BeforeClass @@ -77,7 +79,10 @@ public class InvokeRpcMethodTest { SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules); controllerContext = spy( ControllerContext.getInstance() ); controllerContext.setSchemas(schemaContext); - + uriInfo = mock(UriInfo.class); + MultivaluedMap map = new MultivaluedHashMap<>(); + map.put("prettyPrint", Collections.singletonList("true")); + when(uriInfo.getQueryParameters(any(Boolean.class))).thenReturn(map); } @Before @@ -114,7 +119,7 @@ public class InvokeRpcMethodTest { .thenReturn( Futures.>immediateFuture( Rpcs.getRpcResult( true ) ) ); - StructuredData structData = restconf.invokeRpc("invoke-rpc-module:rpc-test", payload); + StructuredData structData = restconf.invokeRpc("invoke-rpc-module:rpc-test", payload,uriInfo); assertTrue(structData == null); } @@ -143,7 +148,7 @@ public class InvokeRpcMethodTest { restconfImpl.setBroker(brokerFacade); try { - restconfImpl.invokeRpc("toaster:cancel-toast", ""); + restconfImpl.invokeRpc("toaster:cancel-toast", "",uriInfo); fail("Expected an exception to be thrown."); } catch (RestconfDocumentedException e) { @@ -196,7 +201,7 @@ public class InvokeRpcMethodTest { restconfImpl.setBroker(brokerFacade); try { - restconfImpl.invokeRpc("toaster:cancel-toast", ""); + restconfImpl.invokeRpc("toaster:cancel-toast", "",uriInfo); fail("Expected an exception to be thrown."); } catch (RestconfDocumentedException e) { @@ -220,7 +225,7 @@ public class InvokeRpcMethodTest { restconfImpl.setBroker(brokerFacade); StructuredData output = restconfImpl.invokeRpc("toaster:cancel-toast", - ""); + "",uriInfo); assertEquals(null, output); //additional validation in the fact that the restconfImpl does not throw an exception. } @@ -228,7 +233,7 @@ public class InvokeRpcMethodTest { @Test public void testInvokeRpcMethodExpectingNoPayloadButProvidePayload() { try { - restconfImpl.invokeRpc("toaster:cancel-toast", " a payload "); + restconfImpl.invokeRpc("toaster:cancel-toast", " a payload ",uriInfo); fail("Expected an exception"); } catch (RestconfDocumentedException e) { verifyRestconfDocumentedException( e, 0, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE, @@ -239,7 +244,7 @@ public class InvokeRpcMethodTest { @Test public void testInvokeRpcMethodWithBadMethodName() { try { - restconfImpl.invokeRpc("toaster:bad-method", ""); + restconfImpl.invokeRpc("toaster:bad-method", "",uriInfo); fail("Expected an exception"); } catch (RestconfDocumentedException e) { @@ -263,7 +268,7 @@ public class InvokeRpcMethodTest { restconfImpl.setBroker(brokerFacade); StructuredData output = restconfImpl.invokeRpc("toaster:make-toast", - payload); + payload,uriInfo); assertEquals(null, output); //additional validation in the fact that the restconfImpl does not throw an exception. } @@ -271,7 +276,7 @@ public class InvokeRpcMethodTest { @Test public void testThrowExceptionWhenSlashInModuleName() { try { - restconfImpl.invokeRpc("toaster/slash", ""); + restconfImpl.invokeRpc("toaster/slash", "",uriInfo); fail("Expected an exception."); } catch (RestconfDocumentedException e) { @@ -294,7 +299,7 @@ public class InvokeRpcMethodTest { restconfImpl.setBroker(brokerFacade); - StructuredData output = restconfImpl.invokeRpc("toaster:testOutput", ""); + StructuredData output = restconfImpl.invokeRpc("toaster:testOutput", "",uriInfo); assertNotNull( output ); assertSame( compositeNode, output.getData() ); assertNotNull( output.getSchema() ); @@ -330,7 +335,7 @@ public class InvokeRpcMethodTest { restconfImpl.setControllerContext( mockedContext ); StructuredData output = restconfImpl.invokeRpc( "opendaylight-inventory:nodes/node/REMOTE_HOST/yang-ext:mount/toaster:cancel-toast", - ""); + "",uriInfo); assertEquals(null, output); //additional validation in the fact that the restconfImpl does not throw an exception. diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MediaTypesTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MediaTypesTest.java index 319603dfc1..3dd3101a2e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MediaTypesTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MediaTypesTest.java @@ -19,12 +19,10 @@ import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUt import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; - import javax.ws.rs.client.Entity; import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriInfo; - import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; import org.junit.BeforeClass; @@ -55,10 +53,10 @@ public class MediaTypesTest extends JerseyTest { @Override protected Application configure() { /* enable/disable Jersey logs to console */ -// enable(TestProperties.LOG_TRAFFIC); -// enable(TestProperties.DUMP_ENTITY); -// enable(TestProperties.RECORD_LOG_LEVEL); -// set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue()); + // enable(TestProperties.LOG_TRAFFIC); + // enable(TestProperties.DUMP_ENTITY); + // enable(TestProperties.RECORD_LOG_LEVEL); + // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue()); ResourceConfig resourceConfig = new ResourceConfig(); resourceConfig = resourceConfig.registerInstances(restconfService, StructuredDataToXmlProvider.INSTANCE, StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE, @@ -66,31 +64,31 @@ public class MediaTypesTest extends JerseyTest { return resourceConfig; } - @Test - public void testPostOperationsWithInputDataMediaTypes() throws UnsupportedEncodingException { - String uriPrefix = "/operations/"; - String uriPath = "ietf-interfaces:interfaces"; - String uri = uriPrefix + uriPath; - when(restconfService.invokeRpc(eq(uriPath), any(CompositeNode.class))).thenReturn(null); - post(uri, Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+JSON, jsonData); - verify(restconfService, times(1)).invokeRpc(eq(uriPath), any(CompositeNode.class)); - post(uri, Draft02.MediaTypes.OPERATION+XML, Draft02.MediaTypes.OPERATION+XML, xmlData); - verify(restconfService, times(2)).invokeRpc(eq(uriPath), any(CompositeNode.class)); - post(uri, MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON, jsonData); - verify(restconfService, times(3)).invokeRpc(eq(uriPath), any(CompositeNode.class)); - post(uri, MediaType.APPLICATION_XML, MediaType.APPLICATION_XML, xmlData); - verify(restconfService, times(4)).invokeRpc(eq(uriPath), any(CompositeNode.class)); - post(uri, MediaType.TEXT_XML, MediaType.TEXT_XML, xmlData); - verify(restconfService, times(5)).invokeRpc(eq(uriPath), any(CompositeNode.class)); - post(uri, null, MediaType.TEXT_XML, xmlData); - verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(CompositeNode.class)); - - // negative tests - post(uri, MediaType.TEXT_PLAIN, MediaType.TEXT_XML, xmlData); - verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(CompositeNode.class)); - post(uri, MediaType.TEXT_XML, MediaType.TEXT_PLAIN, xmlData); - verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(CompositeNode.class)); - } + @Test + public void testPostOperationsWithInputDataMediaTypes() throws UnsupportedEncodingException { + String uriPrefix = "/operations/"; + String uriPath = "ietf-interfaces:interfaces"; + String uri = uriPrefix + uriPath; + when(restconfService.invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class))).thenReturn(null); + post(uri, Draft02.MediaTypes.OPERATION + JSON, Draft02.MediaTypes.OPERATION + JSON, jsonData); + verify(restconfService, times(1)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class)); + post(uri, Draft02.MediaTypes.OPERATION + XML, Draft02.MediaTypes.OPERATION + XML, xmlData); + verify(restconfService, times(2)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class)); + post(uri, MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON, jsonData); + verify(restconfService, times(3)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class)); + post(uri, MediaType.APPLICATION_XML, MediaType.APPLICATION_XML, xmlData); + verify(restconfService, times(4)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class)); + post(uri, MediaType.TEXT_XML, MediaType.TEXT_XML, xmlData); + verify(restconfService, times(5)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class)); + post(uri, null, MediaType.TEXT_XML, xmlData); + verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class)); + + // negative tests + post(uri, MediaType.TEXT_PLAIN, MediaType.TEXT_XML, xmlData); + verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class)); + post(uri, MediaType.TEXT_XML, MediaType.TEXT_PLAIN, xmlData); + verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class)); + } @Test public void testGetConfigMediaTypes() throws UnsupportedEncodingException { @@ -98,9 +96,9 @@ public class MediaTypesTest extends JerseyTest { String uriPath = "ietf-interfaces:interfaces"; String uri = uriPrefix + uriPath; when(restconfService.readConfigurationData(eq(uriPath), any(UriInfo.class))).thenReturn(null); - get(uri, Draft02.MediaTypes.DATA+JSON); + get(uri, Draft02.MediaTypes.DATA + JSON); verify(restconfService, times(1)).readConfigurationData(eq(uriPath), any(UriInfo.class)); - get(uri, Draft02.MediaTypes.DATA+XML); + get(uri, Draft02.MediaTypes.DATA + XML); verify(restconfService, times(2)).readConfigurationData(eq(uriPath), any(UriInfo.class)); get(uri, MediaType.APPLICATION_JSON); verify(restconfService, times(3)).readConfigurationData(eq(uriPath), any(UriInfo.class)); @@ -120,9 +118,9 @@ public class MediaTypesTest extends JerseyTest { String uriPath = "ietf-interfaces:interfaces"; String uri = uriPrefix + uriPath; when(restconfService.readOperationalData(eq(uriPath), any(UriInfo.class))).thenReturn(null); - get(uri, Draft02.MediaTypes.DATA+JSON); + get(uri, Draft02.MediaTypes.DATA + JSON); verify(restconfService, times(1)).readOperationalData(eq(uriPath), any(UriInfo.class)); - get(uri, Draft02.MediaTypes.DATA+XML); + get(uri, Draft02.MediaTypes.DATA + XML); verify(restconfService, times(2)).readOperationalData(eq(uriPath), any(UriInfo.class)); get(uri, MediaType.APPLICATION_JSON); verify(restconfService, times(3)).readOperationalData(eq(uriPath), any(UriInfo.class)); @@ -142,9 +140,9 @@ public class MediaTypesTest extends JerseyTest { String uriPath = "ietf-interfaces:interfaces"; String uri = uriPrefix + uriPath; when(restconfService.updateConfigurationData(eq(uriPath), any(CompositeNode.class))).thenReturn(null); - put(uri, null, Draft02.MediaTypes.DATA+JSON, jsonData); + put(uri, null, Draft02.MediaTypes.DATA + JSON, jsonData); verify(restconfService, times(1)).updateConfigurationData(eq(uriPath), any(CompositeNode.class)); - put(uri, null, Draft02.MediaTypes.DATA+XML, xmlData); + put(uri, null, Draft02.MediaTypes.DATA + XML, xmlData); verify(restconfService, times(2)).updateConfigurationData(eq(uriPath), any(CompositeNode.class)); put(uri, null, MediaType.APPLICATION_JSON, jsonData); verify(restconfService, times(3)).updateConfigurationData(eq(uriPath), any(CompositeNode.class)); @@ -162,9 +160,9 @@ public class MediaTypesTest extends JerseyTest { String uriPath = "ietf-interfaces:interfaces"; String uri = uriPrefix + uriPath; when(restconfService.createConfigurationData(eq(uriPath), any(CompositeNode.class))).thenReturn(null); - post(uri, null, Draft02.MediaTypes.DATA+JSON, jsonData); + post(uri, null, Draft02.MediaTypes.DATA + JSON, jsonData); verify(restconfService, times(1)).createConfigurationData(eq(uriPath), any(CompositeNode.class)); - post(uri, null, Draft02.MediaTypes.DATA+XML, xmlData); + post(uri, null, Draft02.MediaTypes.DATA + XML, xmlData); verify(restconfService, times(2)).createConfigurationData(eq(uriPath), any(CompositeNode.class)); post(uri, null, MediaType.APPLICATION_JSON, jsonData); verify(restconfService, times(3)).createConfigurationData(eq(uriPath), any(CompositeNode.class)); @@ -181,9 +179,9 @@ public class MediaTypesTest extends JerseyTest { String uriPrefix = "/config/"; String uri = uriPrefix; when(restconfService.createConfigurationData(any(CompositeNode.class))).thenReturn(null); - post(uri, null, Draft02.MediaTypes.DATA+JSON, jsonData); + post(uri, null, Draft02.MediaTypes.DATA + JSON, jsonData); verify(restconfService, times(1)).createConfigurationData(any(CompositeNode.class)); - post(uri, null, Draft02.MediaTypes.DATA+XML, xmlData); + post(uri, null, Draft02.MediaTypes.DATA + XML, xmlData); verify(restconfService, times(2)).createConfigurationData(any(CompositeNode.class)); post(uri, null, MediaType.APPLICATION_JSON, jsonData); verify(restconfService, times(3)).createConfigurationData(any(CompositeNode.class)); diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java index 41a1c3827d..9fd5128d19 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java @@ -8,6 +8,7 @@ package org.opendaylight.controller.sal.restconf.impl.test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -16,6 +17,8 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import java.io.FileNotFoundException; import java.io.InputStream; import java.io.UnsupportedEncodingException; @@ -29,14 +32,12 @@ import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; - import javax.ws.rs.core.Application; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; - import org.glassfish.jersey.server.ResourceConfig; import org.glassfish.jersey.test.JerseyTest; import org.junit.BeforeClass; @@ -68,9 +69,6 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; - public class RestGetOperationTest extends JerseyTest { static class NodeData { @@ -615,6 +613,39 @@ public class RestGetOperationTest extends JerseyTest { return null; } + /** + * If includeWhiteChars URI parameter is set to false then no white + * characters can be included in returned output + * @throws UnsupportedEncodingException + */ + @Test + public void getDataWithUriIncludeWhiteCharsParameterTest() throws UnsupportedEncodingException { + getDataWithUriIncludeWhiteCharsParameter("config"); + getDataWithUriIncludeWhiteCharsParameter("operational"); + } + + + private void getDataWithUriIncludeWhiteCharsParameter(String target) throws UnsupportedEncodingException { + mockReadConfigurationDataMethod(); + String uri = "/"+target+"/ietf-interfaces:interfaces/interface/eth0"; + Response response = target(uri).queryParam("prettyPrint", "false").request("application/xml").get(); + String xmlData = response.readEntity(String.class); + + Pattern pattern = Pattern.compile(".*(>\\s+|\\s+<).*", Pattern.DOTALL); + Matcher matcher = pattern.matcher(xmlData); + // XML element can't surrounded with white character (e.g "> " or + // " <") + assertFalse(matcher.matches()); + + response = target(uri).queryParam("prettyPrint", "false").request("application/json").get(); + String jsonData = response.readEntity(String.class); + pattern = Pattern.compile(".*(\\}\\s+|\\s+\\{|\\]\\s+|\\s+\\[|\\s+:|:\\s+).*", Pattern.DOTALL); + matcher = pattern.matcher(jsonData); + // JSON element can't surrounded with white character (e.g "} ", " {", + // "] ", " [", " :" or ": ") + assertFalse(matcher.matches()); + } + @Test public void getDataWithUriDepthParameterTest() throws UnsupportedEncodingException { diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java index 853c19f935..449b79923e 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java @@ -13,6 +13,7 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import com.google.common.base.Preconditions; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; @@ -27,7 +28,8 @@ import java.sql.Date; import java.util.ArrayList; import java.util.List; import java.util.Set; - +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.ws.rs.WebApplicationException; import javax.ws.rs.ext.MessageBodyReader; import javax.ws.rs.ext.MessageBodyWriter; @@ -40,7 +42,6 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; - import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper; @@ -61,8 +62,6 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.xml.sax.SAXException; -import com.google.common.base.Preconditions; - public final class TestUtils { private static final Logger LOG = LoggerFactory.getLogger(TestUtils.class); @@ -297,6 +296,22 @@ public final class TestUtils { } bufReader.close(); return result.toString(); + } + + private static Pattern patternForStringsSeparatedByWhiteChars(String ... substrings ) { + StringBuilder pattern = new StringBuilder(); + pattern.append(".*"); + for (String substring : substrings) { + pattern.append(substring); + pattern.append("\\s*"); + } + pattern.append(".*"); + return Pattern.compile(pattern.toString(), Pattern.DOTALL); + } + public static boolean containsStringData(String jsonOutput,String ...substrings ) { + Pattern pattern = patternForStringsSeparatedByWhiteChars(substrings); + Matcher matcher = pattern.matcher(jsonOutput); + return matcher.matches(); } } -- 2.36.6