[OLINGO-935] improved debug support including more unit tests
Signed-off-by: Christian Amend <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/9e67d0e3 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/9e67d0e3 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/9e67d0e3 Branch: refs/heads/master Commit: 9e67d0e3e8ae71ea15098ba24fd22bf74c2faaa4 Parents: 1600684 Author: Klaus Straubinger <[email protected]> Authored: Fri Oct 7 14:41:17 2016 +0200 Committer: Christian Amend <[email protected]> Committed: Fri Oct 7 14:52:41 2016 +0200 ---------------------------------------------------------------------- .../olingo/server/core/debug/DebugTabBody.java | 43 +- .../server/core/debug/DebugTabRuntime.java | 8 +- .../server/core/debug/DebugTabStacktrace.java | 2 +- .../olingo/server/core/debug/DebugTabUri.java | 49 ++- .../core/debug/ExpressionJsonVisitor.java | 78 +++- .../server/core/debug/AbstractDebugTabTest.java | 28 +- .../server/core/debug/DebugTabBodyTest.java | 67 +++ .../server/core/debug/DebugTabRuntimeTest.java | 73 ++++ .../core/debug/DebugTabStacktraceTest.java | 107 +++++ .../server/core/debug/DebugTabUriTest.java | 405 +++++++++++++++++++ .../core/debug/ServerCoreDebuggerTest.java | 37 +- 11 files changed, 832 insertions(+), 65 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9e67d0e3/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java index b0c5314..9bca8eb 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java @@ -23,7 +23,6 @@ import java.io.InputStream; import java.io.Writer; import org.apache.commons.codec.binary.Base64; -import org.apache.olingo.commons.api.ex.ODataRuntimeException; import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.deserializer.DeserializerException; @@ -70,33 +69,12 @@ public class DebugTabBody implements DebugTab { return "Body"; } - // @Override - public void appendJson(final JsonGenerator gen) throws IOException { + public void appendJson(final JsonGenerator json) throws IOException { if (response == null || response.getContent() == null) { - gen.writeNull(); + json.writeNull(); } else { - gen.writeString(getContentString()); - } - } - - private String getContentString() { - try { - String contentString; - switch (responseContent) { - case IMAGE: - contentString = Base64.encodeBase64String(streamToBytes(response.getContent())); - break; - case JSON: - case XML: - case TEXT: - default: - contentString = new String(streamToBytes(response.getContent()), "UTF-8"); - break; - } - return contentString; - } catch (IOException e) { - return "Could not parse Body for Debug Output"; + json.writeString(getContentString()); } } @@ -130,12 +108,23 @@ public class DebugTabBody implements DebugTab { } } - private byte[] streamToBytes(final InputStream input) { + private String getContentString() { + try { + final byte[] content = streamToBytes(response.getContent()); + return responseContent == ResponseContent.IMAGE ? + Base64.encodeBase64String(content) : + new String(content, "UTF-8"); + } catch (final IOException e) { + return "Could not parse Body for Debug Output"; + } + } + + private byte[] streamToBytes(final InputStream input) throws IOException { if (input != null) { try { return new FixedFormatDeserializerImpl().binary(input); } catch (final DeserializerException e) { - throw new ODataRuntimeException("Error on reading request content", e); + throw new IOException("Error on reading request content", e); } } return null; http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9e67d0e3/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRuntime.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRuntime.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRuntime.java index 4214050..7416594 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRuntime.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRuntime.java @@ -65,12 +65,12 @@ public class DebugTabRuntime implements DebugTab { private void appendJsonNode(final JsonGenerator gen, final RuntimeNode node) throws IOException { gen.writeStartObject(); gen.writeStringField("class", node.className); - gen.writeStringField("method ", node.methodName); + gen.writeStringField("method", node.methodName); if (node.timeStopped == 0) { gen.writeNullField("duration"); } else { - gen.writeStringField("duration", Long.toString((node.timeStopped - node.timeStarted) / TO_MILLIS_DIVISOR)); + gen.writeNumberField("duration", (node.timeStopped - node.timeStarted) / TO_MILLIS_DIVISOR); gen.writeStringField("unit", "µs"); } @@ -140,7 +140,9 @@ public class DebugTabRuntime implements DebugTab { protected boolean add(final RuntimeMeasurement runtimeMeasurement) { if (timeStarted <= runtimeMeasurement.getTimeStarted() - && timeStopped != 0 && timeStopped >= runtimeMeasurement.getTimeStopped()) { + && timeStopped != 0 + && timeStopped > runtimeMeasurement.getTimeStarted() // in case the stop time has not been set + && timeStopped >= runtimeMeasurement.getTimeStopped()) { for (RuntimeNode candidate : children) { if (candidate.add(runtimeMeasurement)) { return true; http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9e67d0e3/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabStacktrace.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabStacktrace.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabStacktrace.java index 3cc94b6..310ec3a 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabStacktrace.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabStacktrace.java @@ -90,7 +90,7 @@ public class DebugTabStacktrace implements DebugTab { gen.writeStartObject(); gen.writeStringField("class", element.getClassName()); gen.writeStringField("method", element.getMethodName()); - gen.writeStringField("line", Integer.toString(element.getLineNumber())); + gen.writeNumberField("line", element.getLineNumber()); gen.writeEndObject(); } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9e67d0e3/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabUri.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabUri.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabUri.java index 05ac2aa..007b7c6 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabUri.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabUri.java @@ -25,15 +25,18 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import org.apache.olingo.commons.api.edm.EdmType; import org.apache.olingo.commons.api.ex.ODataException; import org.apache.olingo.server.api.uri.UriInfo; import org.apache.olingo.server.api.uri.UriInfoKind; import org.apache.olingo.server.api.uri.UriParameter; import org.apache.olingo.server.api.uri.UriResource; +import org.apache.olingo.server.api.uri.UriResourceComplexProperty; import org.apache.olingo.server.api.uri.UriResourceEntitySet; import org.apache.olingo.server.api.uri.UriResourceFunction; import org.apache.olingo.server.api.uri.UriResourceNavigation; import org.apache.olingo.server.api.uri.UriResourcePartTyped; +import org.apache.olingo.server.api.uri.UriResourceSingleton; import org.apache.olingo.server.api.uri.queryoption.ApplyItem; import org.apache.olingo.server.api.uri.queryoption.ApplyOption; import org.apache.olingo.server.api.uri.queryoption.CountOption; @@ -92,6 +95,15 @@ public class DebugTabUri implements DebugTab { if (uriInfo.getKind() == UriInfoKind.resource) { gen.writeFieldName("uriResourceParts"); appendURIResourceParts(gen, uriInfo.getUriResourceParts()); + } else if (uriInfo.getKind() == UriInfoKind.crossjoin) { + gen.writeFieldName("entitySetNames"); + gen.writeStartArray(); + for (final String name : uriInfo.asUriInfoCrossjoin().getEntitySetNames()) { + gen.writeString(name); + } + gen.writeEndArray(); + } else if (uriInfo.getKind() == UriInfoKind.entityId) { + appendType(gen, "typeCast", uriInfo.asUriInfoEntityId().getEntityTypeCast()); } if (uriInfo.getFormatOption() != null) { @@ -183,23 +195,39 @@ public class DebugTabUri implements DebugTab { gen.writeStartObject(); gen.writeStringField("uriResourceKind", resource.getKind().toString()); gen.writeStringField("segment", resource.toString()); - if (resource instanceof UriResourcePartTyped && ((UriResourcePartTyped) resource).getType() != null) { - gen.writeStringField("type", - ((UriResourcePartTyped) resource).getType().getFullQualifiedName().getFullQualifiedNameAsString()); + if (resource instanceof UriResourcePartTyped) { + appendType(gen, "type", ((UriResourcePartTyped) resource).getType()); + gen.writeBooleanField("isCollection", ((UriResourcePartTyped) resource).isCollection()); } if (resource instanceof UriResourceEntitySet) { appendParameters(gen, "keys", ((UriResourceEntitySet) resource).getKeyPredicates()); + appendType(gen, "typeFilterOnCollection", ((UriResourceEntitySet) resource).getTypeFilterOnCollection()); + appendType(gen, "typeFilterOnEntry", ((UriResourceEntitySet) resource).getTypeFilterOnEntry()); } else if (resource instanceof UriResourceNavigation) { appendParameters(gen, "keys", ((UriResourceNavigation) resource).getKeyPredicates()); + appendType(gen, "typeFilterOnCollection", ((UriResourceNavigation) resource).getTypeFilterOnCollection()); + appendType(gen, "typeFilterOnEntry", ((UriResourceNavigation) resource).getTypeFilterOnEntry()); } else if (resource instanceof UriResourceFunction) { appendParameters(gen, "parameters", ((UriResourceFunction) resource).getParameters()); appendParameters(gen, "keys", ((UriResourceFunction) resource).getKeyPredicates()); + appendType(gen, "typeFilterOnCollection", ((UriResourceFunction) resource).getTypeFilterOnCollection()); + appendType(gen, "typeFilterOnEntry", ((UriResourceFunction) resource).getTypeFilterOnEntry()); + } else if (resource instanceof UriResourceSingleton) { + appendType(gen, "typeFilter", ((UriResourceSingleton) resource).getEntityTypeFilter()); + } else if (resource instanceof UriResourceComplexProperty) { + appendType(gen, "typeFilter", ((UriResourceComplexProperty) resource).getComplexTypeFilter()); } gen.writeEndObject(); } gen.writeEndArray(); } + private void appendType(JsonGenerator json, final String name, final EdmType type) throws IOException { + if (type != null) { + json.writeStringField(name, type.getFullQualifiedName().getFullQualifiedNameAsString()); + } + } + private void appendParameters(final JsonGenerator gen, final String name, final List<UriParameter> parameters) throws IOException { if (!parameters.isEmpty()) { @@ -260,7 +288,7 @@ public class DebugTabUri implements DebugTab { appendCommonJsonObjects(gen, item.getCountOption(), item.getSkipOption(), item.getTopOption(), item.getFilterOption(), item.getOrderByOption(), item.getSelectOption(), item.getExpandOption(), - item.getSearchOption(), null); // TODO: item.getApplyOption() + item.getSearchOption(), item.getApplyOption()); gen.writeEndObject(); } @@ -476,8 +504,21 @@ public class DebugTabUri implements DebugTab { appendURIResourceParts(json, uriInfo.getUriResourceParts()); json.close(); writer.append("\n</li>\n</ul>\n"); + } else if (uriInfo.getKind() == UriInfoKind.crossjoin) { + writer.append("<h2>Crossjoin EntitySet Names</h2>\n") + .append("<ul>\n"); + for (final String name : uriInfo.asUriInfoCrossjoin().getEntitySetNames()) { + writer.append("<li>").append(name).append("</li>\n"); + } + writer.append("</ul>\n"); } else { writer.append("<h2>Kind</h2>\n<p>").append(uriInfo.getKind().name()).append("</p>\n"); + if (uriInfo.getKind() == UriInfoKind.entityId && uriInfo.asUriInfoEntityId().getEntityTypeCast() != null) { + writer.append("<h2>Type Cast</h2>\n<p>") + .append(uriInfo.asUriInfoEntityId().getEntityTypeCast().getFullQualifiedName() + .getFullQualifiedNameAsString()) + .append("</p>\n"); + } } if (uriInfo.getSearchOption() != null) { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9e67d0e3/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ExpressionJsonVisitor.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ExpressionJsonVisitor.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ExpressionJsonVisitor.java index cff320f..4f12882 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ExpressionJsonVisitor.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ExpressionJsonVisitor.java @@ -18,17 +18,22 @@ */ package org.apache.olingo.server.core.debug; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.List; + import org.apache.olingo.commons.api.edm.EdmEnumType; import org.apache.olingo.commons.api.edm.EdmType; import org.apache.olingo.server.api.ODataApplicationException; +import org.apache.olingo.server.api.uri.UriParameter; import org.apache.olingo.server.api.uri.UriResource; +import org.apache.olingo.server.api.uri.UriResourceComplexProperty; +import org.apache.olingo.server.api.uri.UriResourceEntitySet; +import org.apache.olingo.server.api.uri.UriResourceFunction; +import org.apache.olingo.server.api.uri.UriResourceIt; import org.apache.olingo.server.api.uri.UriResourceLambdaAll; import org.apache.olingo.server.api.uri.UriResourceLambdaAny; +import org.apache.olingo.server.api.uri.UriResourceNavigation; import org.apache.olingo.server.api.uri.UriResourcePartTyped; +import org.apache.olingo.server.api.uri.UriResourceSingleton; import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind; import org.apache.olingo.server.api.uri.queryoption.expression.Expression; import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException; @@ -38,7 +43,10 @@ import org.apache.olingo.server.api.uri.queryoption.expression.Member; import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind; import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind; -import java.util.List; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; /** * A custom expression visitor which converts the tree into a {@link JsonNode} tree. @@ -76,6 +84,10 @@ public class ExpressionJsonVisitor implements ExpressionVisitor<JsonNode> { private static final String TYPE_NAME = "type"; private static final String OPERATOR_NAME = "operator"; private static final String NODE_TYPE_NAME = "nodeType"; + private static final String KEYS_NAME = "keys"; + private static final String TYPE_FILTER_NAME = "typeFilter"; + private static final String TYPE_FILTER_ON_COLLECTION_NAME = "typeFilterOnCollection"; + private static final String TYPE_FILTER_ON_ENTRY_NAME = "typeFilterOnEntry"; private final JsonNodeFactory nodeFactory = JsonNodeFactory.instance; @@ -140,6 +152,7 @@ public class ExpressionJsonVisitor implements ExpressionVisitor<JsonNode> { ObjectNode result = nodeFactory.objectNode() .put(NODE_TYPE_NAME, MEMBER_NAME) .put(TYPE_NAME, getType(lastSegment)); + putType(result, TYPE_FILTER_NAME, member.getStartTypeFilter()); ArrayNode segments = result.putArray(RESOURCE_SEGMENTS_NAME); for (final UriResource segment : uriResourceParts) { if (segment instanceof UriResourceLambdaAll) { @@ -149,10 +162,32 @@ public class ExpressionJsonVisitor implements ExpressionVisitor<JsonNode> { final UriResourceLambdaAny any = (UriResourceLambdaAny) segment; segments.add(visitLambdaExpression(ANY_NAME, any.getLambdaVariable(), any.getExpression())); } else if (segment instanceof UriResourcePartTyped) { - segments.add(nodeFactory.objectNode() + ObjectNode node = nodeFactory.objectNode() .put(NODE_TYPE_NAME, segment.getKind().toString()) .put(NAME_NAME, segment.toString()) - .put(TYPE_NAME, getType(segment))); + .put(TYPE_NAME, getType(segment)); + if (segment instanceof UriResourceEntitySet) { + putParameters(node, KEYS_NAME, ((UriResourceEntitySet) segment).getKeyPredicates()); + putType(node, TYPE_FILTER_ON_COLLECTION_NAME, ((UriResourceEntitySet) segment).getTypeFilterOnCollection()); + putType(node, TYPE_FILTER_ON_ENTRY_NAME, ((UriResourceEntitySet) segment).getTypeFilterOnEntry()); + } else if (segment instanceof UriResourceNavigation) { + putParameters(node, KEYS_NAME, ((UriResourceNavigation) segment).getKeyPredicates()); + putType(node, TYPE_FILTER_ON_COLLECTION_NAME, ((UriResourceNavigation) segment).getTypeFilterOnCollection()); + putType(node, TYPE_FILTER_ON_ENTRY_NAME, ((UriResourceNavigation) segment).getTypeFilterOnEntry()); + } else if (segment instanceof UriResourceFunction) { + putParameters(node, PARAMETERS_NAME, ((UriResourceFunction) segment).getParameters()); + putParameters(node, KEYS_NAME, ((UriResourceFunction) segment).getKeyPredicates()); + putType(node, TYPE_FILTER_ON_COLLECTION_NAME, ((UriResourceFunction) segment).getTypeFilterOnCollection()); + putType(node, TYPE_FILTER_ON_ENTRY_NAME, ((UriResourceFunction) segment).getTypeFilterOnEntry()); + } else if (segment instanceof UriResourceIt) { + putType(node, TYPE_FILTER_ON_COLLECTION_NAME, ((UriResourceIt) segment).getTypeFilterOnCollection()); + putType(node, TYPE_FILTER_ON_ENTRY_NAME, ((UriResourceIt) segment).getTypeFilterOnEntry()); + } else if (segment instanceof UriResourceSingleton) { + putType(node, TYPE_FILTER_NAME, ((UriResourceSingleton) segment).getEntityTypeFilter()); + } else if (segment instanceof UriResourceComplexProperty) { + putType(node, TYPE_FILTER_NAME, ((UriResourceComplexProperty) segment).getComplexTypeFilter()); + } + segments.add(node); } else { segments.add(nodeFactory.objectNode() .put(NODE_TYPE_NAME, segment.getKind().toString()) @@ -163,6 +198,22 @@ public class ExpressionJsonVisitor implements ExpressionVisitor<JsonNode> { return result; } + private void putType(ObjectNode node, final String name, final EdmType type) { + if (type != null) { + node.put(name, type.getFullQualifiedName().getFullQualifiedNameAsString()); + } + } + + private void putParameters(ObjectNode node, final String name, final List<UriParameter> parameters) { + if (!parameters.isEmpty()) { + ObjectNode parametersNode = node.putObject(name); + for (final UriParameter parameter : parameters) { + parametersNode.put(parameter.getName(), + parameter.getText() == null ? parameter.getAlias() : parameter.getText()); + } + } + } + @Override public JsonNode visitAlias(final String aliasName) throws ExpressionVisitException, ODataApplicationException { return nodeFactory.objectNode() @@ -186,8 +237,8 @@ public class ExpressionJsonVisitor implements ExpressionVisitor<JsonNode> { } @Override - public JsonNode visitEnum(final EdmEnumType type, final List<String> enumValues) throws ExpressionVisitException, - ODataApplicationException { + public JsonNode visitEnum(final EdmEnumType type, final List<String> enumValues) + throws ExpressionVisitException, ODataApplicationException { ObjectNode result = nodeFactory.objectNode() .put(NODE_TYPE_NAME, ENUM_NAME) .put(TYPE_NAME, getTypeString(type)); @@ -206,9 +257,8 @@ public class ExpressionJsonVisitor implements ExpressionVisitor<JsonNode> { return NUMBER_NAME; case NOT: return BOOLEAN_NAME; - default: - return UNKNOWN_NAME; } + return UNKNOWN_NAME; } private String getType(final MethodKind methodCall) { @@ -257,9 +307,9 @@ public class ExpressionJsonVisitor implements ExpressionVisitor<JsonNode> { return DATETIMEOFFSET_NAME; case CAST: - default: return UNKNOWN_NAME; } + return UNKNOWN_NAME; } private String getType(final BinaryOperatorKind operator) { @@ -281,10 +331,8 @@ public class ExpressionJsonVisitor implements ExpressionVisitor<JsonNode> { case AND: case OR: return BOOLEAN_NAME; - - default: - return UNKNOWN_NAME; } + return UNKNOWN_NAME; } private String getTypeString(final EdmType type) { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9e67d0e3/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/AbstractDebugTabTest.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/AbstractDebugTabTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/AbstractDebugTabTest.java index 95a3ba1..bbebe20 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/AbstractDebugTabTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/AbstractDebugTabTest.java @@ -21,24 +21,30 @@ package org.apache.olingo.server.core.debug; import java.io.IOException; import java.io.StringWriter; -import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.ObjectMapper; public abstract class AbstractDebugTabTest { - protected String createHtml(final DebugTab tab) throws IOException { - StringWriter writer = new StringWriter(); - tab.appendHtml(writer); - writer.flush(); - return writer.toString(); + protected String createHtml(DebugTab tab) throws IOException { + return create(tab, true); + } + + protected String createJson(DebugTab tab) throws IOException { + return create(tab, false); } - protected String createJson(final DebugTab tab) throws IOException { + private String create(DebugTab tab, final boolean html) throws IOException { StringWriter writer = new StringWriter(); - JsonGenerator gen = new JsonFactory().createGenerator(writer); - tab.appendJson(gen); - gen.flush(); - gen.close(); + if (html) { + tab.appendHtml(writer); + } else { + // Create JSON generator (the object mapper is necessary to write expression trees). + JsonGenerator json = new ObjectMapper().getFactory().createGenerator(writer); + tab.appendJson(json); + json.flush(); + json.close(); + } writer.flush(); return writer.toString(); } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9e67d0e3/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabBodyTest.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabBodyTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabBodyTest.java index 088e398..6365f16 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabBodyTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabBodyTest.java @@ -20,6 +20,14 @@ package org.apache.olingo.server.core.debug; import static org.junit.Assert.assertEquals; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +import org.apache.olingo.commons.api.format.ContentType; +import org.apache.olingo.commons.api.http.HttpHeader; +import org.apache.olingo.server.api.ODataResponse; import org.junit.Test; public class DebugTabBodyTest extends AbstractDebugTabTest { @@ -31,4 +39,63 @@ public class DebugTabBodyTest extends AbstractDebugTabTest { assertEquals("null", createJson(tab)); assertEquals("<pre class=\"code\">\nODataLibrary: No body.\n</pre>\n", createHtml(tab)); } + + @Test + public void json() throws Exception { + ODataResponse response = new ODataResponse(); + response.setHeader(HttpHeader.CONTENT_TYPE, ContentType.JSON_NO_METADATA.toContentTypeString()); + response.setContent(IOUtils.toInputStream("{\"property\": true}")); + assertEquals("\"{\\\"property\\\": true}\"", createJson(new DebugTabBody(response))); + + response.setContent(IOUtils.toInputStream("{\"property\": false}")); + assertEquals("<pre class=\"code json\">\n{\"property\": false}\n</pre>\n", createHtml(new DebugTabBody(response))); + } + + @Test + public void xml() throws Exception { + ODataResponse response = new ODataResponse(); + response.setHeader(HttpHeader.CONTENT_TYPE, ContentType.APPLICATION_XML.toContentTypeString()); + response.setContent(IOUtils.toInputStream("<?xml version='1.1'?>\n<a xmlns=\"b\" />\n")); + assertEquals("\"<?xml version='1.1'?>\\n<a xmlns=\\\"b\\\" />\\n\"", createJson(new DebugTabBody(response))); + + response.setContent(IOUtils.toInputStream("<?xml version='1.1'?>\n<c xmlns=\"d\" />\n")); + assertEquals("<pre class=\"code xml\">\n<?xml version='1.1'?>\n<c xmlns=\"d\" />\n\n</pre>\n", + createHtml(new DebugTabBody(response))); + } + + @Test + public void text() throws Exception { + ODataResponse response = new ODataResponse(); + response.setContent(IOUtils.toInputStream("testText\n12")); + assertEquals("\"testText\\n12\"", createJson(new DebugTabBody(response))); + + response.setContent(IOUtils.toInputStream("testText\n34")); + assertEquals("<pre class=\"code\">\ntestText\n34\n</pre>\n", createHtml(new DebugTabBody(response))); + } + + @Test + public void image() throws Exception { + ODataResponse response = new ODataResponse(); + response.setHeader(HttpHeader.CONTENT_TYPE, "image/png"); + response.setContent(new ByteArrayInputStream(new byte[] { -1, -2, -3, -4 })); + assertEquals("\"//79/A==\"", createJson(new DebugTabBody(response))); + + response.setContent(new ByteArrayInputStream(new byte[] { -5, -6, -7, -8 })); + assertEquals("<img src=\"data:image/png;base64,+/r5+A==\" />\n", createHtml(new DebugTabBody(response))); + } + + @Test + public void streamError() throws Exception { + ODataResponse response = new ODataResponse(); + InputStream input = new InputStream() { + @Override + public int read() throws IOException { + throw new IOException("test"); + } + }; + response.setContent(input); + assertEquals("\"Could not parse Body for Debug Output\"", createJson(new DebugTabBody(response))); + assertEquals("<pre class=\"code\">\nCould not parse Body for Debug Output\n</pre>\n", + createHtml(new DebugTabBody(response))); + } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9e67d0e3/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabRuntimeTest.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabRuntimeTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabRuntimeTest.java new file mode 100644 index 0000000..7f4f062 --- /dev/null +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabRuntimeTest.java @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.olingo.server.core.debug; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.apache.olingo.server.api.debug.RuntimeMeasurement; +import org.junit.Test; + +public class DebugTabRuntimeTest extends AbstractDebugTabTest { + + @Test + public void runtime() throws Exception { + final DebugTabRuntime tab = new DebugTabRuntime(Arrays.asList( + createMeasurement("class1", "method1", 0, 42), + createMeasurement("class2", "method2", 12, 23), + createMeasurement("class2", "method2", 24, 26), + createMeasurement("class3", "method3", 98, 0))); + assertEquals("[{\"class\":\"class1\",\"method\":\"method1\",\"duration\":42,\"unit\":\"µs\",\"children\":[" + + "{\"class\":\"class2\",\"method\":\"method2\",\"duration\":13,\"unit\":\"µs\"}]}," + + "{\"class\":\"class3\",\"method\":\"method3\",\"duration\":null}]", + createJson(tab)); + + assertEquals("<ol class=\"tree\">\n" + + "<li>\n" + + "<span class=\"code\"><span class=\"draw\">├─ </span>" + + "<span class=\"class\">class1</span>.<span class=\"method\">method1(…)</span>" + + "</span><span class=\"numeric\" title=\"Gross duration\">42 µs</span>\n" + + "<ol class=\"tree\">\n" + + "<li>\n" + + "<span class=\"code\"><span class=\"draw\">│ └─ </span>" + + "<span class=\"class\">class2</span>.<span class=\"method\">method2(…)</span>" + + "</span><span class=\"numeric\" title=\"Gross duration\">13 µs</span>\n" + + "</li>\n" + + "</ol>\n" + + "</li>\n" + + "<li>\n" + + "<span class=\"code\"><span class=\"draw\">└─ </span>" + + "<span class=\"class\">class3</span>.<span class=\"method\">method3(…)</span>" + + "</span><span class=\"null\" title=\"Stop time missing\">unfinished</span>\n" + + "</li>\n" + + "</ol>\n", + createHtml(tab)); + } + + private RuntimeMeasurement createMeasurement(final String className, final String methodName, + final int startMilliseconds, final int stopMilliseconds) { + RuntimeMeasurement measurement = new RuntimeMeasurement(); + measurement.setClassName(className); + measurement.setMethodName(methodName); + measurement.setTimeStarted(startMilliseconds * 1000); + measurement.setTimeStopped(stopMilliseconds * 1000); + return measurement; + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9e67d0e3/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabStacktraceTest.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabStacktraceTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabStacktraceTest.java new file mode 100644 index 0000000..35687da --- /dev/null +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabStacktraceTest.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * + "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.olingo.server.core.debug; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class DebugTabStacktraceTest extends AbstractDebugTabTest { + + @Test + public void stacktrace() throws Exception { + Exception cause = new Exception("innerError"); + cause.setStackTrace(new StackTraceElement[] { + new StackTraceElement("inner.class", "inner.method", "inner/filename", 99) }); + Exception exception = new Exception("error", cause); + exception.setStackTrace(new StackTraceElement[] { + new StackTraceElement("some.class", "some.method", "filename", 42), + cause.getStackTrace()[0] }); + final DebugTabStacktrace tab = new DebugTabStacktrace(exception); + assertEquals("{\"exceptions\":[" + + "{\"class\":\"java.lang.Exception\",\"message\":\"error\"," + + "\"invocation\":{\"class\":\"some.class\",\"method\":\"some.method\",\"line\":42}}," + + "{\"class\":\"java.lang.Exception\",\"message\":\"innerError\"," + + "\"invocation\":{\"class\":\"inner.class\",\"method\":\"inner.method\",\"line\":99}}]," + + "\"stacktrace\":[" + + "{\"class\":\"some.class\",\"method\":\"some.method\",\"line\":42}," + + "{\"class\":\"inner.class\",\"method\":\"inner.method\",\"line\":99}]}", + createJson(tab)); + + assertEquals("<h2>java.lang.Exception</h2>\n" + + "<p>innerError</p>\n" + + "<table>\n" + + "<thead>\n" + + "<tr>\n" + + "<th class=\"name\">Class</th>\n" + + "<th class=\"name\">Method</th>\n" + + "<th class=\"value\">Line number in class</th>\n" + + "</tr>\n" + + "</thead>\n" + + "<tbody>\n" + + "<tr>\n" + + "<td class=\"name\">inner.class</td>\n" + + "<td class=\"name\">inner.method</td>\n" + + "<td class=\"value\">99</td>\n" + + "</tr>\n" + + "</tbody>\n" + + "</table>\n" + + "<h2>java.lang.Exception</h2>\n" + + "<p>error</p>\n" + + "<table>\n" + + "<thead>\n" + + "<tr>\n" + + "<th class=\"name\">Class</th>\n" + + "<th class=\"name\">Method</th>\n" + + "<th class=\"value\">Line number in class</th>\n" + + "</tr>\n" + + "</thead>\n" + + "<tbody>\n" + + "<tr>\n" + + "<td class=\"name\">some.class</td>\n" + + "<td class=\"name\">some.method</td>\n" + + "<td class=\"value\">42</td>\n" + + "</tr>\n" + + "</tbody>\n" + + "</table>\n" + + "<h2>Stacktrace</h2>\n" + + "<table>\n" + + "<thead>\n" + + "<tr>\n" + + "<th class=\"name\">Class</th>\n" + + "<th class=\"name\">Method</th>\n" + + "<th class=\"value\">Line number in class</th>\n" + + "</tr>\n" + + "</thead>\n" + + "<tbody>\n" + + "<tr>\n" + + "<td class=\"name\">some.class</td>\n" + + "<td class=\"name\">some.method</td>\n" + + "<td class=\"value\">42</td>\n" + + "</tr>\n" + + "<tr>\n" + + "<td class=\"name\">inner.class</td>\n" + + "<td class=\"name\">inner.method</td>\n" + + "<td class=\"value\">99</td>\n" + + "</tr>\n" + + "</tbody>\n" + + "</table>\n", + createHtml(tab)); + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9e67d0e3/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabUriTest.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabUriTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabUriTest.java new file mode 100644 index 0000000..26b7db1 --- /dev/null +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabUriTest.java @@ -0,0 +1,405 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.olingo.server.core.debug; + +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.endsWith; +import static org.hamcrest.CoreMatchers.startsWith; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Arrays; + +import org.apache.olingo.commons.api.edm.EdmEntitySet; +import org.apache.olingo.commons.api.edm.EdmEntityType; +import org.apache.olingo.commons.api.edm.EdmFunction; +import org.apache.olingo.commons.api.edm.EdmFunctionImport; +import org.apache.olingo.commons.api.edm.EdmNavigationProperty; +import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; +import org.apache.olingo.commons.api.edm.EdmProperty; +import org.apache.olingo.commons.api.edm.EdmReturnType; +import org.apache.olingo.commons.api.edm.FullQualifiedName; +import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory; +import org.apache.olingo.server.api.uri.UriInfoKind; +import org.apache.olingo.server.api.uri.UriParameter; +import org.apache.olingo.server.api.uri.queryoption.SelectItem; +import org.apache.olingo.server.api.uri.queryoption.apply.AggregateExpression.StandardMethod; +import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind; +import org.apache.olingo.server.api.uri.queryoption.expression.Expression; +import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind; +import org.apache.olingo.server.core.uri.UriInfoImpl; +import org.apache.olingo.server.core.uri.UriParameterImpl; +import org.apache.olingo.server.core.uri.UriResourceEntitySetImpl; +import org.apache.olingo.server.core.uri.UriResourceFunctionImpl; +import org.apache.olingo.server.core.uri.UriResourceNavigationPropertyImpl; +import org.apache.olingo.server.core.uri.UriResourcePrimitivePropertyImpl; +import org.apache.olingo.server.core.uri.parser.search.SearchTermImpl; +import org.apache.olingo.server.core.uri.queryoption.AliasQueryOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.ApplyOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.CustomQueryOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.ExpandItemImpl; +import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.FilterOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.FormatOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.IdOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.LevelsOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.OrderByItemImpl; +import org.apache.olingo.server.core.uri.queryoption.OrderByOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.SearchOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.SelectItemImpl; +import org.apache.olingo.server.core.uri.queryoption.SelectOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.SkipOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.SkipTokenOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.TopOptionImpl; +import org.apache.olingo.server.core.uri.queryoption.apply.AggregateExpressionImpl; +import org.apache.olingo.server.core.uri.queryoption.apply.AggregateImpl; +import org.apache.olingo.server.core.uri.queryoption.apply.GroupByImpl; +import org.apache.olingo.server.core.uri.queryoption.apply.GroupByItemImpl; +import org.apache.olingo.server.core.uri.queryoption.expression.BinaryImpl; +import org.apache.olingo.server.core.uri.queryoption.expression.LiteralImpl; +import org.apache.olingo.server.core.uri.queryoption.expression.MemberImpl; +import org.apache.olingo.server.core.uri.queryoption.expression.MethodImpl; +import org.junit.Test; + +public class DebugTabUriTest extends AbstractDebugTabTest { + + @Test + public void resourceEntitySet() throws Exception { + EdmEntitySet edmEntitySet = mock(EdmEntitySet.class); + final DebugTabUri tab = new DebugTabUri(new UriInfoImpl().setKind(UriInfoKind.resource) + .addResourcePart(new UriResourceEntitySetImpl(edmEntitySet))); + + assertEquals("{\"kind\":\"resource\",\"uriResourceParts\":[" + + "{\"uriResourceKind\":\"entitySet\",\"segment\":null,\"isCollection\":true}]}", + createJson(tab)); + + final String html = createHtml(tab); + assertThat(html, allOf( + startsWith("<h2>Resource Path</h2>\n" + + "<ul>\n" + + "<li class=\"json\">"), + containsString("uriResourceKind"), containsString("entitySet"), + containsString("segment"), containsString("null"))); + assertThat(html, allOf( + containsString("isCollection"), containsString("true"), + endsWith("</li>\n</ul>\n"))); + } + + @Test + public void resourceFunction() throws Exception { + EdmReturnType returnType = mock(EdmReturnType.class); + EdmFunction edmFunction = mock(EdmFunction.class); + when(edmFunction.getReturnType()).thenReturn(returnType); + EdmFunctionImport edmFunctionImport = mock(EdmFunctionImport.class); + final DebugTabUri tab = new DebugTabUri(new UriInfoImpl().setKind(UriInfoKind.resource) + .addResourcePart(new UriResourceFunctionImpl(edmFunctionImport, edmFunction, + Arrays.asList((UriParameter) new UriParameterImpl().setName("parameter1"))))); + + assertEquals("{\"kind\":\"resource\",\"uriResourceParts\":[" + + "{\"uriResourceKind\":\"function\",\"segment\":null,\"isCollection\":false," + + "\"parameters\":{\"parameter1\":null}}]}", + createJson(tab)); + + final String html = createHtml(tab); + assertThat(html, allOf( + startsWith("<h2>Resource Path</h2>\n" + + "<ul>\n" + + "<li class=\"json\">"), + containsString("uriResourceKind"), containsString("function"), + containsString("segment"), containsString("null"))); + assertThat(html, allOf( + containsString("isCollection"), containsString("false"), + containsString("parameters"), containsString("parameter1"), + endsWith("</li>\n</ul>\n"))); + } + + @Test + public void crossjoin() throws Exception { + final DebugTabUri tab = new DebugTabUri(new UriInfoImpl().setKind(UriInfoKind.crossjoin) + .addEntitySetName("ES1").addEntitySetName("ES2")); + + assertEquals("{\"kind\":\"crossjoin\",\"entitySetNames\":[\"ES1\",\"ES2\"]}", createJson(tab)); + + assertEquals("<h2>Crossjoin EntitySet Names</h2>\n" + + "<ul>\n" + + "<li>ES1</li>\n" + + "<li>ES2</li>\n" + + "</ul>\n", + createHtml(tab)); + } + + @Test + public void entityId() throws Exception { + EdmEntityType edmEntityType = mock(EdmEntityType.class); + when(edmEntityType.getFullQualifiedName()).thenReturn(new FullQualifiedName("ns", "entityType")); + final DebugTabUri tab = new DebugTabUri(new UriInfoImpl().setKind(UriInfoKind.entityId) + .setEntityTypeCast(edmEntityType)); + + assertEquals("{\"kind\":\"entityId\",\"typeCast\":\"ns.entityType\"}", createJson(tab)); + + assertEquals("<h2>Kind</h2>\n" + + "<p>entityId</p>\n" + + "<h2>Type Cast</h2>\n" + + "<p>ns.entityType</p>\n", + createHtml(tab)); + } + + @Test + public void simpleQueryOptions() throws Exception { + final DebugTabUri tab = new DebugTabUri(new UriInfoImpl().setKind(UriInfoKind.all) + .setQueryOption(new FormatOptionImpl().setFormat("json")) + .setQueryOption(new IdOptionImpl().setValue("ES(42)").setText("ES(42)")) + .setQueryOption(new SkipOptionImpl().setValue(123).setText("123")) + .setQueryOption(new TopOptionImpl().setValue(456).setText("456")) + .setQueryOption(new SkipTokenOptionImpl().setValue("xyz123")) + .setQueryOption(new CountOptionImpl().setValue(false).setText("false")) + .setQueryOption(new SearchOptionImpl().setSearchExpression(new SearchTermImpl("searchTest"))) + .setQueryOption(new CustomQueryOptionImpl().setName("customQuery").setText("customValue")) + .setQueryOption(new AliasQueryOptionImpl().setAliasValue(null).setName("@alias"))); + + assertEquals("{\"kind\":\"all\"," + + "\"format\":\"json\"," + + "\"id\":\"ES(42)\"," + + "\"skiptoken\":\"xyz123\"," + + "\"isCount\":false," + + "\"skip\":123," + + "\"top\":456," + + "\"search\":{\"nodeType\":\"searchTerm\",\"searchTerm\":\"searchTest\"}," + + "\"aliases\":{\"@alias\":null}," + + "\"customQueryOptions\":{\"customQuery\":\"customValue\"}" + + "}", + createJson(tab)); + + final String html = createHtml(tab); + assertThat(html, allOf( + startsWith("<h2>Kind</h2>\n" + + "<p>all</p>\n"), + containsString("<h2>Search Option</h2>\n" + + "<ul>\n" + + "<li class=\"json\">"), + containsString("searchTerm"), containsString("searchTest"), + containsString("<h2>Unstructured System Query Options</h2>\n" + + "<table>\n" + + "<thead>\n" + + "<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n" + + "</thead>\n" + + "<tbody>\n" + + "<tr><td class=\"name\">$count</td><td class=\"value\">false</td></tr>\n" + + "<tr><td class=\"name\">$skip</td><td class=\"value\">123</td></tr>\n" + + "<tr><td class=\"name\">$skiptoken</td><td class=\"value\">xyz123</td></tr>\n" + + "<tr><td class=\"name\">$top</td><td class=\"value\">456</td></tr>\n" + + "<tr><td class=\"name\">$format</td><td class=\"value\">json</td></tr>\n" + + "<tr><td class=\"name\">$id</td><td class=\"value\">ES(42)</td></tr>\n" + + "</tbody>\n" + + "</table>\n"))); + assertThat(html, allOf( + containsString("<h2>Aliases</h2>\n" + + "<table>\n" + + "<thead>\n" + + "<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n" + + "</thead>\n" + + "<tbody>\n" + + "<tr><td class=\"name\">@alias</td><td class=\"value\">null</td></tr>\n" + + "</tbody>\n" + + "</table>\n"), + endsWith("<h2>Custom Query Options</h2>\n" + + "<table>\n" + + "<thead>\n" + + "<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n" + + "</thead>\n" + + "<tbody>\n" + + "<tr><td class=\"name\">customQuery</td><td class=\"value\">customValue</td></tr>\n" + + "</tbody>\n" + + "</table>\n"))); + } + + @Test + public void select() throws Exception { + EdmProperty edmProperty = mock(EdmProperty.class); + when(edmProperty.getName()).thenReturn("property"); + final DebugTabUri tab = new DebugTabUri(new UriInfoImpl().setKind(UriInfoKind.all) + .setSystemQueryOption(new SelectOptionImpl().setSelectItems(Arrays.asList( + (SelectItem) new SelectItemImpl().setStar(true), + new SelectItemImpl().setResourcePath( + new UriInfoImpl().setKind(UriInfoKind.resource) + .addResourcePart(new UriResourcePrimitivePropertyImpl(edmProperty))))))); + assertEquals("{\"kind\":\"all\",\"select\":[\"*\",\"property\"]}", createJson(tab)); + + assertEquals("<h2>Kind</h2>\n" + + "<p>all</p>\n" + + "<h2>Selected Properties</h2>\n" + + "<ul>\n" + + "<li>*</li>\n" + + "<li>property</li>\n" + + "</ul>\n", + createHtml(tab)); + } + + @Test + public void expand() throws Exception { + EdmNavigationProperty edmProperty = mock(EdmNavigationProperty.class); + when(edmProperty.getName()).thenReturn("property"); + final DebugTabUri tab = new DebugTabUri(new UriInfoImpl().setKind(UriInfoKind.all) + .setSystemQueryOption(new ExpandOptionImpl().addExpandItem( + new ExpandItemImpl().setResourcePath( + new UriInfoImpl().setKind(UriInfoKind.resource) + .addResourcePart(new UriResourceNavigationPropertyImpl(edmProperty))) + .setSystemQueryOption(new LevelsOptionImpl().setValue(1))))); + assertEquals("{\"kind\":\"all\",\"expand\":[{\"expandPath\":[" + + "{\"uriResourceKind\":\"navigationProperty\",\"segment\":\"property\",\"isCollection\":false}]," + + "\"levels\":1}]}", + createJson(tab)); + + final String html = createHtml(tab); + assertThat(html, allOf( + startsWith("<h2>Kind</h2>\n" + + "<p>all</p>\n" + + "<h2>Expand Option</h2>\n" + + "<ul>\n" + + "<li class=\"json\">"), + containsString("navigationProperty"), containsString("property"), + containsString("isCollection"), containsString("false"))); + assertThat(html, allOf(containsString("levels"), endsWith("</li>\n</ul>\n"))); + } + + @Test + public void filter() throws Exception { + final DebugTabUri tab = new DebugTabUri(new UriInfoImpl().setKind(UriInfoKind.all) + .setSystemQueryOption(new FilterOptionImpl().setExpression( + new BinaryImpl(new LiteralImpl("1", EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int64)), + BinaryOperatorKind.GT, + new LiteralImpl("2", EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.SByte)), + EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean))))); + assertEquals("{\"kind\":\"all\",\"filter\":{" + + "\"nodeType\":\"binary\",\"operator\":\"gt\",\"type\":\"Boolean\"," + + "\"left\":{\"nodeType\":\"literal\",\"type\":\"Edm.Int64\",\"value\":\"1\"}," + + "\"right\":{\"nodeType\":\"literal\",\"type\":\"Edm.SByte\",\"value\":\"2\"}}}", + createJson(tab)); + + assertThat(createHtml(tab), allOf( + startsWith("<h2>Kind</h2>\n" + + "<p>all</p>\n" + + "<h2>Filter Option</h2>\n" + + "<ul>\n" + + "<li class=\"json\">"), + containsString("nodeType"), containsString("binary"), + containsString("operator"), containsString("gt"))); + assertThat(createHtml(tab), allOf( + containsString("literal"), containsString("Int64"), + containsString("SByte"), containsString("2"), + endsWith("</li>\n</ul>\n"))); + + assertEquals("{\"kind\":\"all\",\"filter\":{" + + "\"nodeType\":\"method\",\"operator\":\"ceiling\",\"type\":\"Number\"," + + "\"parameters\":[{\"nodeType\":\"literal\",\"type\":\"Edm.Decimal\",\"value\":\"1.5\"}]}}", + createJson(new DebugTabUri(new UriInfoImpl().setKind(UriInfoKind.all) + .setSystemQueryOption(new FilterOptionImpl().setExpression( + new MethodImpl(MethodKind.CEILING, Arrays.asList( + (Expression) new LiteralImpl("1.5", + EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal))))))))); + + EdmEntityType edmEntityType = mock(EdmEntityType.class); + when(edmEntityType.getFullQualifiedName()).thenReturn(new FullQualifiedName("ns", "entityType")); + EdmProperty edmProperty = mock(EdmProperty.class); + when(edmProperty.getName()).thenReturn("property"); + assertEquals("{\"kind\":\"all\",\"filter\":{" + + "\"nodeType\":\"member\",\"type\":\"unknown\",\"typeFilter\":\"ns.entityType\"," + + "\"resourceSegments\":[{\"nodeType\":\"primitiveProperty\",\"name\":\"property\",\"type\":\"unknown\"}]}}", + createJson(new DebugTabUri(new UriInfoImpl().setKind(UriInfoKind.all) + .setSystemQueryOption(new FilterOptionImpl().setExpression( + new MemberImpl(new UriInfoImpl().setKind(UriInfoKind.resource) + .addResourcePart(new UriResourcePrimitivePropertyImpl(edmProperty)), + edmEntityType)))))); + } + + @Test + public void orderby() throws Exception { + final DebugTabUri tab = new DebugTabUri(new UriInfoImpl().setKind(UriInfoKind.all) + .setSystemQueryOption(new OrderByOptionImpl().addOrder( + new OrderByItemImpl().setExpression( + new LiteralImpl("false", EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean))) + .setDescending(true)))); + + assertEquals("{\"kind\":\"all\",\"orderby\":{\"nodeType\":\"orderCollection\",\"orders\":[" + + "{\"nodeType\":\"order\",\"sortorder\":\"desc\",\"expression\":" + + "{\"nodeType\":\"literal\",\"type\":\"Edm.Boolean\",\"value\":\"false\"}}]}}", + createJson(tab)); + + final String html = createHtml(tab); + assertThat(html, allOf( + startsWith("<h2>Kind</h2>\n" + + "<p>all</p>\n" + + "<h2>OrderBy Option</h2>\n" + + "<ul>\n" + + "<li class=\"json\">"), + containsString("nodeType"), containsString("order"), + containsString("sortorder"), containsString("desc"))); + assertThat(html, allOf( + containsString("expression"), containsString("literal"), + containsString("Edm.Boolean"), containsString("false"), + endsWith("</li>\n</ul>\n"))); + } + + @Test + public void apply() throws Exception { + EdmProperty edmProperty = mock(EdmProperty.class); + when(edmProperty.getName()).thenReturn("property"); + final DebugTabUri tab = new DebugTabUri(new UriInfoImpl().setKind(UriInfoKind.all) + .setSystemQueryOption(new ApplyOptionImpl().add(new AggregateImpl().addExpression( + new AggregateExpressionImpl() + .setPath(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart( + new UriResourcePrimitivePropertyImpl(edmProperty))) + .setStandardMethod(StandardMethod.AVERAGE) + .setAlias("average"))))); + + assertEquals("{\"kind\":\"all\",\"apply\":[{\"kind\":\"AGGREGATE\",\"aggregate\":[{" + + "\"path\":[{\"uriResourceKind\":\"primitiveProperty\",\"segment\":\"property\",\"isCollection\":false}]," + + "\"standardMethod\":\"AVERAGE\",\"as\":\"average\"}]}]}", + createJson(tab)); + + final String html = createHtml(tab); + assertThat(html, allOf( + startsWith("<h2>Kind</h2>\n" + + "<p>all</p>\n" + + "<h2>Apply Option</h2>\n" + + "<ul>\n" + + "<li class=\"json\">"), + containsString("kind"), containsString("AGGREGATE"), + containsString("aggregate"), containsString("path"))); + assertThat(html, allOf( + containsString("primitiveProperty"), containsString("property"), + containsString("standardMethod"), containsString("AVERAGE"))); + assertThat(html, allOf( + containsString("as"), containsString("average"), + endsWith("</li>\n</ul>\n"))); + + assertEquals("{\"kind\":\"all\",\"apply\":[{\"kind\":\"GROUP_BY\",\"groupBy\":[{" + + "\"path\":[{\"uriResourceKind\":\"primitiveProperty\",\"segment\":\"property\",\"isCollection\":false}]," + + "\"isRollupAll\":true}]}]}", + createJson(new DebugTabUri(new UriInfoImpl().setKind(UriInfoKind.all) + .setSystemQueryOption(new ApplyOptionImpl().add(new GroupByImpl().addGroupByItem( + new GroupByItemImpl().setIsRollupAll() + .setPath(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart( + new UriResourcePrimitivePropertyImpl(edmProperty))))))))); + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9e67d0e3/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/ServerCoreDebuggerTest.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/ServerCoreDebuggerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/ServerCoreDebuggerTest.java index 280ff38..9772061 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/ServerCoreDebuggerTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/ServerCoreDebuggerTest.java @@ -18,8 +18,11 @@ */ package org.apache.olingo.server.core.debug; +import static org.hamcrest.CoreMatchers.allOf; +import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; @@ -36,20 +39,22 @@ import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.debug.DebugInformation; import org.apache.olingo.server.api.debug.DebugSupport; +import org.apache.olingo.server.api.debug.DefaultDebugSupport; import org.junit.Before; import org.junit.Test; public class ServerCoreDebuggerTest { + private final OData odata = OData.newInstance(); private ServerCoreDebugger debugger; @Before public void setupDebugger() { - debugger = new ServerCoreDebugger(OData.newInstance()); + debugger = new ServerCoreDebugger(odata); DebugSupport processor = mock(DebugSupport.class); when(processor.isUserAuthorized()).thenReturn(true); when(processor.createDebugResponse(anyString(), any(DebugInformation.class))) - .thenThrow(new ODataRuntimeException("Test")); + .thenThrow(new ODataRuntimeException("Test")); debugger.setDebugSupportProcessor(processor); } @@ -63,7 +68,7 @@ public class ServerCoreDebuggerTest { HttpServletRequest request = mock(HttpServletRequest.class); when(request.getParameter(DebugSupport.ODATA_DEBUG_QUERY_PARAMETER)).thenReturn(DebugSupport.ODATA_DEBUG_JSON); - ServerCoreDebugger localDebugger = new ServerCoreDebugger(OData.newInstance()); + ServerCoreDebugger localDebugger = new ServerCoreDebugger(odata); localDebugger.resolveDebugMode(request); assertFalse(debugger.isDebugMode()); } @@ -84,7 +89,7 @@ public class ServerCoreDebuggerTest { DebugSupport debugSupportMock = mock(DebugSupport.class); when(debugSupportMock.isUserAuthorized()).thenReturn(false); - ServerCoreDebugger localDebugger = new ServerCoreDebugger(OData.newInstance()); + ServerCoreDebugger localDebugger = new ServerCoreDebugger(odata); localDebugger.setDebugSupportProcessor(debugSupportMock); localDebugger.resolveDebugMode(request); @@ -108,4 +113,28 @@ public class ServerCoreDebuggerTest { assertEquals(odResponse, debugResponse); } + + @Test + public void runtimeMeasurement() throws Exception { + ServerCoreDebugger defaultDebugger = new ServerCoreDebugger(odata); + defaultDebugger.setDebugSupportProcessor(new DefaultDebugSupport()); + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getParameter(DebugSupport.ODATA_DEBUG_QUERY_PARAMETER)).thenReturn(DebugSupport.ODATA_DEBUG_JSON); + defaultDebugger.resolveDebugMode(request); + + final int handle = defaultDebugger.startRuntimeMeasurement("someClass", "someMethod"); + defaultDebugger.stopRuntimeMeasurement(handle); + assertEquals(0, handle); + + assertThat(IOUtils.toString(defaultDebugger.createDebugResponse(null, null, null, null, null).getContent()), + allOf(containsString("\"runtime\""), containsString("\"someClass\""), containsString("\"someMethod\""), + containsString("]}}"))); + + request = mock(HttpServletRequest.class); + when(request.getParameter(DebugSupport.ODATA_DEBUG_QUERY_PARAMETER)).thenReturn(DebugSupport.ODATA_DEBUG_HTML); + defaultDebugger.resolveDebugMode(request); + assertThat(IOUtils.toString(defaultDebugger.createDebugResponse(null, null, null, null, null).getContent()), + allOf(containsString(">Runtime<"), containsString(">someClass<"), containsString(">someMethod("), + containsString("</html>"))); + } }
