[NO ISSUE][API][MTD] Query service servlet refactoring
- user model changes: no
- storage format changes: no
- interface changes: no
Details:
- Query service servlet refactoring.
- Add ".regexjson" to TestExecutor to allow comparing
JSON documents irrespective of the order of elements/fields
Change-Id: Ie477ba08405d2e58cb4b27d5d160e7773fe12488
Reviewed-on: https://asterix-gerrit.ics.uci.edu/3108
Sonar-Qube: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Murtadha Hubail <mhubail@apache.org>
diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
index fce9365..7c42e5c 100644
--- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
+++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/api/http/server/QueryServiceServlet.java
@@ -532,9 +532,7 @@
printSignature(sessionOutput.out(), param);
}
printType(sessionOutput.out(), sessionOutput.config());
- if (param.getStatement() == null || param.getStatement().isEmpty()) {
- throw new RuntimeDataException(ErrorCode.NO_STATEMENT_PROVIDED);
- }
+ validateStatement(param.getStatement());
String statementsText = param.getStatement() + ";";
if (param.isParseOnly()) {
ResultUtil.ParseOnlyResult parseOnlyResult = parseStatement(statementsText);
@@ -577,6 +575,12 @@
}
}
+ protected void validateStatement(String statement) throws RuntimeDataException {
+ if (statement == null || statement.isEmpty()) {
+ throw new RuntimeDataException(ErrorCode.NO_STATEMENT_PROVIDED);
+ }
+ }
+
protected ResultUtil.ParseOnlyResult parseStatement(String statementsText) throws CompilationException {
IParserFactory factory = compilationProvider.getParserFactory();
IParser parser = factory.createParser(statementsText);
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
index 3aa8807..4766639 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
@@ -234,6 +234,17 @@
} else if (actualFile.toString().endsWith(".regexadm")) {
runScriptAndCompareWithResultRegexAdm(scriptFile, expectedFile, actualFile);
return;
+ } else if (actualFile.toString().endsWith(".regexjson")) {
+ ObjectMapper OM = new ObjectMapper();
+ JsonNode expectedJson = OM.readTree(readerExpected);
+ JsonNode actualJson = OM.readTree(readerActual);
+ if (expectedJson == null || actualJson == null) {
+ throw new NullPointerException("Error parsing expected or actual result file for " + scriptFile);
+ }
+ if (!TestHelper.equalJson(expectedJson, actualJson)) {
+ throw new ComparisonException("Result for " + scriptFile + " didn't match the expected JSON");
+ }
+ return;
}
String lineExpected, lineActual;
int num = 1;
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestHelper.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestHelper.java
index a7a7fce..53ee9c2 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestHelper.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestHelper.java
@@ -23,9 +23,11 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.BitSet;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
@@ -44,6 +46,8 @@
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
public final class TestHelper {
@@ -137,6 +141,76 @@
return RequestParameters.deserializeParameterValues(RequestParameters.serializeParameterValues(stmtParams));
}
+ public static boolean equalJson(JsonNode expectedJson, JsonNode actualJson) {
+ if (expectedJson == actualJson) {
+ return true;
+ }
+ // exactly one is null
+ if (expectedJson == null || actualJson == null) {
+ return false;
+ }
+ // both are not null
+ if (!isRegexField(expectedJson) && expectedJson.getNodeType() != actualJson.getNodeType()) {
+ return false;
+ } else if (expectedJson.isArray() && actualJson.isArray()) {
+ ArrayNode expectedArray = (ArrayNode) expectedJson;
+ ArrayNode actualArray = (ArrayNode) actualJson;
+ if (expectedArray.size() != actualArray.size()) {
+ return false;
+ }
+ boolean found;
+ BitSet alreadyMatched = new BitSet(actualArray.size());
+ for (int i = 0; i < expectedArray.size(); i++) {
+ found = false;
+ for (int k = 0; k < actualArray.size(); k++) {
+ if (!alreadyMatched.get(k) && equalJson(expectedArray.get(i), actualArray.get(k))) {
+ alreadyMatched.set(k);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ return false;
+ }
+ }
+ return true;
+ } else if (expectedJson.isObject() && actualJson.isObject()) {
+ // assumes no duplicates in field names
+ ObjectNode expectedObject = (ObjectNode) expectedJson;
+ ObjectNode actualObject = (ObjectNode) actualJson;
+ if (expectedObject.size() != actualObject.size()) {
+ return false;
+ }
+ Iterator<Map.Entry<String, JsonNode>> expectedFields = expectedObject.fields();
+ Map.Entry<String, JsonNode> expectedField;
+ JsonNode actualFieldValue;
+ while (expectedFields.hasNext()) {
+ expectedField = expectedFields.next();
+ actualFieldValue = actualObject.get(expectedField.getKey());
+ if (actualFieldValue == null || !equalJson(expectedField.getValue(), actualFieldValue)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ // value node
+ String expectedAsString = expectedJson.asText();
+ String actualAsString = actualJson.asText();
+ if (expectedAsString.startsWith("R{")) {
+ expectedAsString = expectedAsString.substring(2, expectedAsString.length() - 1);
+ return actualAsString.matches(expectedAsString);
+ }
+ return expectedAsString.equals(actualAsString);
+ }
+
+ private static boolean isRegexField(JsonNode expectedJson) {
+ if (expectedJson.isTextual()) {
+ String regexValue = expectedJson.asText();
+ return regexValue.startsWith("R{");
+ }
+ return false;
+ }
+
private static ObjectMapper createObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);