You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@vxquery.apache.org by pr...@apache.org on 2017/08/25 16:59:10 UTC
[2/4] vxquery git commit: [VXQUERY-180] REST Server implementation
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-rest/src/site/markdown/index.md
----------------------------------------------------------------------
diff --git a/vxquery-rest/src/site/markdown/index.md b/vxquery-rest/src/site/markdown/index.md
new file mode 100644
index 0000000..703df65
--- /dev/null
+++ b/vxquery-rest/src/site/markdown/index.md
@@ -0,0 +1,249 @@
+<!--
+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.
+-->
+# VXQuery REST Server
+
+VXQuery REST Server allows users to submit queries and receive results either synchronously or
+asynchronously through the exposed REST API. Along with the statement to be executed, few other parameters can be given as
+well. Complete REST API specification can be found at [REST API Specification](specification.html).
+
+## Installation
+
+No additional steps needed to be taken to get the REST Server up and running. That is, setting up a VXQuery cluster will
+automatically start the REST Server on port `8080`. Please see [VXQuery Cluster Setup](../user_cluster_installation.html)
+to understand how a VXQuery cluster is setup.
+
+## Getting Started
+
+Suppose we want to execute a very simple XQuery like:
+
+```
+for $x in (1, 2.0, 3) return $x
+```
+
+### Async (Default Mode) Example
+
+If we want to send this, following will be the plain HTTP request.
+
+```
+GET http://127.0.1.1:39003/vxquery/query?statement=for+%24x+in+%281%2C+2.0%2C+3%29+return+%24x HTTP/1.1
+```
+
+Note the query parameter `statement=for+%24x+in+%281%2C+2.0%2C+3%29+return+%24x` in which the above mentioned statement
+has been encoded. If we send this request using **cURL**, it will look like follows.
+
+#### Accept: application/json
+
+```
+curl -i -H "Accept: application/json" -X GET "http://localhost:39003/vxquery/query?statement=for+%24x+in+%281%2C+2.0%2C+3%29+return+%24x"
+```
+
+and the response is,
+
+```
+HTTP/1.1 200 OK
+transfer-encoding: chunked
+connection: keep-alive
+Access-Control-Allow-Origin: *
+Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
+content-type: application/json
+content-length: 320
+
+{
+ "status": "success",
+ "requestId": "b0cbe06f-3454-4422-ba23-59150e1c1400",
+ "statement": "for $x in (1, 2.0, 3) return $x",
+ "abstractSyntaxTree": null,
+ "translatedExpressionTree": null,
+ "optimizedExpressionTree": null,
+ "runtimePlan": null,
+ "metrics": {
+ "compileTime": 0,
+ "elapsedTime": 0
+ },
+ "resultId": 6,
+ "resultUrl": "/vxquery/query/result/6"
+}
+```
+
+#### Accept: application/xml
+
+```
+curl -i -H "Accept: application/xml" -X GET "http://localhost:39003/vxquery/query?statement=for+%24x+in+%281%2C+2.0%2C+3%29+return+%24x"
+```
+
+and the response is,
+
+```
+HTTP/1.1 200 OK
+transfer-encoding: chunked
+connection: keep-alive
+Access-Control-Allow-Origin: *
+Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
+content-type: application/xml
+content-length: 403
+
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<asyncQueryResponse>
+ <requestId>d0c2c0ef-2e46-4153-9d4b-1ef4593184e7</requestId>
+ <metrics>
+ <compileTime>0</compileTime>
+ <elapsedTime>0</elapsedTime>
+ </metrics>
+ <statement>for $x in (1, 2.0, 3) return $x</statement>
+ <resultId>8</resultId>
+ <resultUrl>/vxquery/query/result/8</resultUrl>
+</asyncQueryResponse>
+```
+
+#### Result Fetching
+
+Since we have used the default mode (**async**), we only got the **resultId**. Now we have to send another request asking
+for the actual results. Send a cURL request to `/vxquery/query/result/8` to fetch results for result ID 8.
+
+##### Accept: application/json
+
+```
+curl -i -H "Accept: application/json" -X GET "http://localhost:39003/vxquery/query/result/8"
+```
+
+and the response is,
+
+```
+HTTP/1.1 200 OK
+transfer-encoding: chunked
+connection: keep-alive
+Access-Control-Allow-Origin: *
+Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
+content-type: application/json
+content-length: 137
+
+{
+ "status": "success",
+ "requestId": "d0c2c0ef-2e46-4153-9d4b-1ef4593184e7",
+ "results": "1\n2\n3\n",
+ "metrics": {
+ "compileTime": 0,
+ "elapsedTime": 0
+ }
+}
+```
+
+Note the *results* in the JSON content in the response.
+
+##### Accept: application/xml
+
+```
+curl -i -H "Accept: application/xml" -X GET "http://localhost:39003/vxquery/query/result/8"
+```
+
+and the response is,
+
+```
+HTTP/1.1 200 OK
+transfer-encoding: chunked
+connection: keep-alive
+Access-Control-Allow-Origin: *
+Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
+content-type: application/xml
+content-length: 298
+
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<queryResultResponse>
+ <requestId>d0c2c0ef-2e46-4153-9d4b-1ef4593184e7</requestId>
+ <metrics>
+ <compileTime>0</compileTime>
+ <elapsedTime>0</elapsedTime>
+ </metrics>
+ <results>1
+2
+3
+</results>
+</queryResultResponse>
+```
+
+Note the *<results></results>* in the XML content in the response.
+
+### Sync (Synchronous Mode) Example
+
+Similarly to what we did under async requests, we can send the query requests here as well, but with the added query parameter
+`mode=sync` which is to indicate that the response should be a synchronous one. That is, we wait for the query to be
+executed and the response to arrive.
+
+```
+curl -i -H "Accept: application/xml" -X GET \
+"http://localhost:39003/vxquery/query?statement=for+%24x+in+%281%2C+2.0%2C+3%29+return+%24x&mode=sync"
+```
+
+and the response now contains **results** instead of the **resultId** we received previously.
+
+```
+HTTP/1.1 200 OK
+transfer-encoding: chunked
+connection: keep-alive
+Access-Control-Allow-Origin: *
+Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
+content-type: application/xml
+content-length: 353
+
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<syncQueryResponse>
+ <requestId>93b67f50-4f14-4304-a9b2-f75b4a736df3</requestId>
+ <metrics>
+ <compileTime>0</compileTime>
+ <elapsedTime>0</elapsedTime>
+ </metrics>
+ <statement>for $x in (1, 2.0, 3) return $x</statement>
+ <results>1
+2
+3
+</results>
+</syncQueryResponse>
+```
+
+Similarly with `accept:application/json`,
+
+```
+curl -i -H "Accept: application/json" -X GET \
+"http://localhost:39003/vxquery/query?statement=for+%24x+in+%281%2C+2.0%2C+3%29+return+%24x&mode=sync"
+```
+
+and the response is,
+
+```
+HTTP/1.1 200 OK
+transfer-encoding: chunked
+connection: keep-alive
+Access-Control-Allow-Origin: *
+Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
+content-type: application/json
+content-length: 291
+
+{
+ "status": "success",
+ "requestId": "8010a699-a6f2-423c-91e1-8ac17cd5c5cd",
+ "statement": "for $x in (1, 2.0, 3) return $x",
+ "abstractSyntaxTree": null,
+ "translatedExpressionTree": null,
+ "optimizedExpressionTree": null,
+ "runtimePlan": null,
+ "metrics": {
+ "compileTime": 0,
+ "elapsedTime": 0
+ },
+ "results": "1\n2\n3\n"
+}
+```
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-rest/src/site/markdown/specification.md
----------------------------------------------------------------------
diff --git a/vxquery-rest/src/site/markdown/specification.md b/vxquery-rest/src/site/markdown/specification.md
new file mode 100644
index 0000000..3977439
--- /dev/null
+++ b/vxquery-rest/src/site/markdown/specification.md
@@ -0,0 +1,102 @@
+<!--
+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.
+-->
+# REST API Specification
+
+Swagger configuration of the REST API can be found
+[here](https://cwiki.apache.org/confluence/display/VXQUERY/SwaggerIO+Configuration).
+
+**NOTE:** This REST API supports both **content types**, `application/json` and `application/xml`. Based on the `accept` header
+of your query request, REST API will return the results wither in *json* form or *XML* form. Returned content type
+defaults to `application/json` if no `accept` header is present.
+
+Base Path **${host}/vxquery**
+
+## Query Request
+
+Request of this type should be submitted for a given *query* to be executed. Depending on the value of the parameter
+`mode`, a **synchronous** response or an **asynchronous** response will be returned
+
+`*` required
+
+| Path | Method |Parameters | Type | Description |
+| ------ | ------ | ------ | ----- |----- |
+| /query | GET |statement* | string | Statement to be executed |
+| | |mode | string | `sync` or `async`. **async** will return an asynchronous response **(default: async)** |
+| | |compileOnly | boolean | If `true`, statement will be compiled, but won't be executed (default: false) |
+| | |optimization | integer | Optimization level (0 - 2,147,483,647). (Default: Full optimization) |
+| | |frameSize | integer | Frame size in bytes (default: 65536) |
+| | |repeatExecutions|integer | Number of times to repeat execution (default: 1) |
+| | |metrics | boolean | If `true`, returns metrics (compile and execution time) with the response (default: false) |
+| | |showAbstractSyntaxTree | boolean | Shows abstract syntax tree if `true` (default: false) |
+| | |showTranslatedExpressionTree | boolean | Shows translated expression tree if `true` (default: false) |
+| | |showOptimizedExpressionTree | boolean | Shows optimized expression tree if `true` (default: false) |
+| | |showRuntimePlan| boolean | Shows runtime plan if set to `true` (default: false) |
+
+### Synchronous Query Response
+
+Received only when `mode` is set to `sync` in the query request above.
+
+| Attribute | Type | Description |
+| ------ | ------ | ------ |
+|statement* |string | Statement submitted to be executed |
+|status* |string | `success` to indicate that the query execution was successful |
+|requestId* |string | A unique ID assigned to the request sent earlier |
+|abstractSyntaxTree |string | Abstract Syntax Tree if requested in the query request. Else `null` |
+|translatedExpressionTree |string | Translated Expression Tree if requested in the query request. Else `null` |
+|optimizedExpressionTree |string | Optimized Expression Tree if requested in the query request. Else `null` |
+|runtimePlan |string | Runtime plan if requested in the query request. Else `null` |
+|metrics |metrics | Metrics (`compileTime` and `elapsedTime`) if requested in the query request |
+|results* |string | Results of the query/statement submitted for execution |
+
+### Asynchronous Query Response
+
+Received only when `mode` is set to `async` (which is the default value) in the query request above.
+
+| Attribute | Type | Description |
+| ------ | ------ | ------ |
+|statement* |string | Statement submitted to be executed |
+|status* |string | `success` to indicate that the query execution was successful |
+|requestId* |string | A unique ID assigned to the request sent earlier |
+|abstractSyntaxTree |string | Abstract Syntax Tree if requested in the query request. Else `null` |
+|translatedExpressionTree |string | Translated Expression Tree if requested in the query request. Else `null` |
+|optimizedExpressionTree |string | Optimized Expression Tree if requested in the query request. Else `null` |
+|runtimePlan |string | Runtime plan if requested in the query request. Else `null` |
+|metrics |metrics | Metrics (`compileTime` and `elapsedTime`) if requested in the query request |
+|resultId* |string | Result ID of the query submitted for execution. This ID is required later for result fetching |
+|resultUrl* |string | URL from which the results of the submitted query can be retrieved |
+
+### Result fetching (After an Asynchronous Query Response)
+
+The **resultId** received in the asynchronous query response needs to be submitted as a
+**path parameter** (`/query/result/${resultId}`) to the REST API in order to retrieve the corresponding results.
+
+| Path | Method |Parameters | Type | Description |
+| ------ | ------ | ------ | ----- |----- |
+| /query/result/${resultId} | GET | metrics | boolean | If `true`, returns metrics (compile and execution time) with the response (default: false) |
+
+***
+
+## Error Response
+
+In any of the above scenarios, if an error occurred while processing, REST API will return an *Error Response* as
+specified below.
+
+| Attribute | Type | Description |
+| ------ | ------ | ------ |
+|status* |string | `fatal` to indicate that the query execution was failed at some point |
+|requestId* |string | A unique ID assigned to the request sent |
+|error* |Error | An error object which include an error code with an error message. {code: xxx, message: "error message"} |
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-rest/src/site/site.xml
----------------------------------------------------------------------
diff --git a/vxquery-rest/src/site/site.xml b/vxquery-rest/src/site/site.xml
new file mode 100644
index 0000000..bd9b9ab
--- /dev/null
+++ b/vxquery-rest/src/site/site.xml
@@ -0,0 +1,53 @@
+<!--
+ ~ 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.
+ -->
+<project name="VXQuery">
+ <bannerLeft>
+ <name>VXQuery</name>
+ <src>../images/VXQuery.png</src>
+ <href>../index.html</href>
+ </bannerLeft>
+
+ <bannerRight>
+ <name>Apache Software Foundation</name>
+ <src>../images/asf_logo_wide.png</src>
+ <href>http://www.apache.org/</href>
+ </bannerRight>
+
+ <skin>
+ <groupId>org.apache.maven.skins</groupId>
+ <artifactId>maven-fluido-skin</artifactId>
+ <version>1.5</version>
+ </skin>
+
+ <body>
+ <menu name="VXQuery REST API">
+ <item name="Overview" href="index.html"/>
+ <item name="Specification" href="specification.html"/>
+ </menu>
+
+ <menu ref="reports"/>
+ <footer><![CDATA[
+ <div class="row-fluid">Apache VXQuery, VXQuery, Apache, the Apache
+ feather logo, and the Apache VXQuery project logo are either
+ registered trademarks or trademarks of The Apache Software
+ Foundation in the United States and other countries.
+ All other marks mentioned may be trademarks or registered
+ trademarks of their respective owners.
+ </div>]]>
+ </footer>
+ </body>
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-rest/src/test/java/org/apache/vxquery/rest/AbstractRestServerTest.java
----------------------------------------------------------------------
diff --git a/vxquery-rest/src/test/java/org/apache/vxquery/rest/AbstractRestServerTest.java b/vxquery-rest/src/test/java/org/apache/vxquery/rest/AbstractRestServerTest.java
new file mode 100644
index 0000000..3d4b124
--- /dev/null
+++ b/vxquery-rest/src/test/java/org/apache/vxquery/rest/AbstractRestServerTest.java
@@ -0,0 +1,225 @@
+/*
+ * 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.vxquery.rest;
+
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+
+import javax.ws.rs.HttpMethod;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHeaders;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.utils.HttpClientUtils;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.vxquery.app.VXQueryApplication;
+import org.apache.vxquery.app.util.LocalClusterUtil;
+import org.apache.vxquery.app.util.RestUtils;
+import org.apache.vxquery.rest.request.QueryRequest;
+import org.apache.vxquery.rest.request.QueryResultRequest;
+import org.apache.vxquery.rest.response.AsyncQueryResponse;
+import org.apache.vxquery.rest.response.QueryResponse;
+import org.apache.vxquery.rest.response.QueryResultResponse;
+import org.apache.vxquery.rest.response.SyncQueryResponse;
+import org.apache.vxquery.rest.service.VXQueryConfig;
+import org.apache.vxquery.rest.service.VXQueryService;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+
+import io.netty.handler.codec.http.HttpResponseStatus;
+
+/**
+ * Abstract test class to be used for {@link VXQueryApplication} related tests.
+ * These tests are expected to use the REST API for querying and fetching
+ * results
+ *
+ * @author Erandi Ganepola
+ */
+public class AbstractRestServerTest {
+
+ protected static LocalClusterUtil vxqueryLocalCluster = new LocalClusterUtil();
+ protected static String restIpAddress;
+ protected static int restPort;
+ protected static VXQueryService vxQueryService;
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ vxqueryLocalCluster.init(new VXQueryConfig());
+ vxQueryService = vxqueryLocalCluster.getVxQueryService();
+ restIpAddress = vxqueryLocalCluster.getIpAddress();
+ restPort = vxqueryLocalCluster.getRestPort();
+ }
+
+ @AfterClass
+ public static void tearDown() throws Exception {
+ vxqueryLocalCluster.deinit();
+ }
+
+ protected static String normalize(String string) {
+ if (string == null) {
+ return null;
+ }
+
+ return string.replace("\r\n", "").replace("\n", "").replace("\r", "");
+ }
+
+ protected static void checkMetrics(QueryResponse response, boolean showMetrics) {
+ if (showMetrics) {
+ Assert.assertTrue(response.getMetrics().getCompileTime() > 0);
+ Assert.assertTrue(response.getMetrics().getElapsedTime() > 0);
+ } else {
+ Assert.assertTrue(response.getMetrics().getCompileTime() == 0);
+ Assert.assertTrue(response.getMetrics().getElapsedTime() == 0);
+ }
+ }
+
+ protected static void checkResults(AsyncQueryResponse response, boolean compileOnly) {
+ if (compileOnly) {
+ Assert.assertNull(response.getResultUrl());
+ Assert.assertEquals(0, response.getResultId());
+ } else {
+ Assert.assertTrue(response.getResultUrl().startsWith(Constants.RESULT_URL_PREFIX));
+ Assert.assertNotEquals(0, response.getResultId());
+ }
+ }
+
+ protected static void checkResults(SyncQueryResponse response, boolean compileOnly) {
+ if (compileOnly) {
+ Assert.assertNull(response.getResults());
+ } else {
+ Assert.assertNotNull(response.getResults());
+ Assert.assertFalse(response.getResults().isEmpty());
+ }
+ }
+
+ /**
+ * Submit a {@link QueryRequest} and fetth the resulting
+ * {@link AsyncQueryResponse}
+ *
+ * @param uri
+ * uri of the GET request
+ * @param accepts
+ * application/json | application/xml
+ * @param method
+ * Http Method to be used to send the request
+ * @return Response received for the query request
+ * @throws Exception
+ */
+ protected static <T> T getQuerySuccessResponse(URI uri, String accepts, Class<T> type, String method)
+ throws Exception {
+ CloseableHttpClient httpClient = HttpClients.custom().setConnectionTimeToLive(20, TimeUnit.SECONDS).build();
+
+ try {
+ HttpUriRequest request = getRequest(uri, method);
+
+ if (accepts != null) {
+ request.setHeader(HttpHeaders.ACCEPT, accepts);
+ }
+
+ try (CloseableHttpResponse httpResponse = httpClient.execute(request)) {
+ Assert.assertEquals(HttpResponseStatus.OK.code(), httpResponse.getStatusLine().getStatusCode());
+ if (accepts != null) {
+ Assert.assertEquals(accepts, httpResponse.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue());
+ }
+
+ HttpEntity entity = httpResponse.getEntity();
+ Assert.assertNotNull(entity);
+
+ String response = RestUtils.readEntity(entity);
+ return RestUtils.mapEntity(response, type, accepts);
+ }
+ } finally {
+ HttpClientUtils.closeQuietly(httpClient);
+ }
+ }
+
+ /**
+ * Fetch the {@link QueryResultResponse} from query result endpoint once the
+ * corresponding {@link QueryResultRequest} is given.
+ *
+ * @param resultRequest
+ * {@link QueryResultRequest}
+ * @param accepts
+ * expected
+ *
+ * <pre>
+ * Accepts
+ * </pre>
+ *
+ * header in responses
+ * @param method
+ * Http Method to be used to send the request
+ * @return query result response received
+ * @throws Exception
+ */
+ protected static QueryResultResponse getQueryResultResponse(QueryResultRequest resultRequest, String accepts,
+ String method) throws Exception {
+ URI uri = RestUtils.buildQueryResultURI(resultRequest, restIpAddress, restPort);
+ CloseableHttpClient httpClient = HttpClients.custom().setConnectionTimeToLive(20, TimeUnit.SECONDS).build();
+ try {
+ HttpUriRequest request = getRequest(uri, method);
+
+ if (accepts != null) {
+ request.setHeader(HttpHeaders.ACCEPT, accepts);
+ }
+
+ try (CloseableHttpResponse httpResponse = httpClient.execute(request)) {
+ if (accepts != null) {
+ Assert.assertEquals(accepts, httpResponse.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue());
+ }
+ Assert.assertEquals(httpResponse.getStatusLine().getStatusCode(), HttpResponseStatus.OK.code());
+
+ HttpEntity entity = httpResponse.getEntity();
+ Assert.assertNotNull(entity);
+
+ String response = RestUtils.readEntity(entity);
+ return RestUtils.mapEntity(response, QueryResultResponse.class, accepts);
+ }
+ } finally {
+ HttpClientUtils.closeQuietly(httpClient);
+ }
+ }
+
+ /**
+ * Creates a POST or GET request accordingly from the given {@link URI}
+ *
+ * @param uri
+ * URI to which the request us to be sent
+ * @param method
+ * Http method- GET or POST
+ * @return request
+ */
+ protected static HttpUriRequest getRequest(URI uri, String method) {
+ HttpUriRequest request;
+ switch (method) {
+ case HttpMethod.POST:
+ request = new HttpPost(uri);
+ break;
+ case HttpMethod.GET:
+ default:
+ request = new HttpGet(uri);
+ }
+
+ return request;
+ }
+}
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-rest/src/test/java/org/apache/vxquery/rest/ErrorResponseTest.java
----------------------------------------------------------------------
diff --git a/vxquery-rest/src/test/java/org/apache/vxquery/rest/ErrorResponseTest.java b/vxquery-rest/src/test/java/org/apache/vxquery/rest/ErrorResponseTest.java
new file mode 100644
index 0000000..12b61f3
--- /dev/null
+++ b/vxquery-rest/src/test/java/org/apache/vxquery/rest/ErrorResponseTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.vxquery.rest;
+
+import static org.apache.vxquery.app.util.RestUtils.buildQueryResultURI;
+import static org.apache.vxquery.app.util.RestUtils.buildQueryURI;
+import static org.apache.vxquery.rest.Constants.ErrorCodes.INVALID_INPUT;
+import static org.apache.vxquery.rest.Constants.ErrorCodes.NOT_FOUND;
+import static org.apache.vxquery.rest.Constants.ErrorCodes.PROBLEM_WITH_QUERY;
+import static org.apache.vxquery.rest.Constants.HttpHeaderValues.CONTENT_TYPE_JSON;
+import static org.apache.vxquery.rest.Constants.HttpHeaderValues.CONTENT_TYPE_XML;
+
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+
+import javax.ws.rs.HttpMethod;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHeaders;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.utils.HttpClientUtils;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.vxquery.app.util.RestUtils;
+import org.apache.vxquery.rest.request.QueryRequest;
+import org.apache.vxquery.rest.request.QueryResultRequest;
+import org.apache.vxquery.rest.response.ErrorResponse;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests error codes of the possible error responses that can be received for
+ * erroneous queries.
+ *
+ * @author Erandi Ganepola
+ */
+public class ErrorResponseTest extends AbstractRestServerTest {
+
+ @Test
+ public void testInvalidInput01() throws Exception {
+ QueryRequest request = new QueryRequest(" ");
+ runTest(buildQueryURI(request, restIpAddress, restPort), null, INVALID_INPUT);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_JSON, INVALID_INPUT);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_XML, INVALID_INPUT);
+ }
+
+ @Test
+ public void testInvalidInput02() throws Exception {
+ QueryRequest request = new QueryRequest("");
+ runTest(buildQueryURI(request, restIpAddress, restPort), null, 405);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_JSON, 405);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_XML, 405);
+ }
+
+ @Test
+ public void testInvalidQuery01() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1,2,3) return $y");
+ runTest(buildQueryURI(request, restIpAddress, restPort), null, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_JSON, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_XML, PROBLEM_WITH_QUERY);
+ }
+
+ @Test
+ public void testInvalidQuery02() throws Exception {
+ QueryRequest request = new QueryRequest("for x in (1,2,3) return $x");
+ runTest(buildQueryURI(request, restIpAddress, restPort), null, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_JSON, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_XML, PROBLEM_WITH_QUERY);
+ }
+
+ @Test
+ public void testInvalidQuery03() throws Exception {
+ QueryRequest request = new QueryRequest("insert nodes <book></book> into doc(\"abcd.xml\")/books");
+ runTest(buildQueryURI(request, restIpAddress, restPort), null, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_JSON, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_XML, PROBLEM_WITH_QUERY);
+ }
+
+ @Test
+ public void testInvalidQuery04() throws Exception {
+ QueryRequest request = new QueryRequest("delete nodes /a/b//node()");
+ runTest(buildQueryURI(request, restIpAddress, restPort), null, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_JSON, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_XML, PROBLEM_WITH_QUERY);
+ }
+
+ @Test
+ public void testInvalidResultId() throws Exception {
+ QueryResultRequest request = new QueryResultRequest(1000);
+ runTest(buildQueryResultURI(request, restIpAddress, restPort), null, NOT_FOUND);
+ runTest(buildQueryResultURI(request, restIpAddress, restPort), CONTENT_TYPE_JSON, NOT_FOUND);
+ runTest(buildQueryResultURI(request, restIpAddress, restPort), CONTENT_TYPE_XML, NOT_FOUND);
+ }
+
+ @Test
+ public void testSyncInvalidInput01() throws Exception {
+ QueryRequest request = new QueryRequest(" ");
+ request.setAsync(false);
+ runTest(buildQueryURI(request, restIpAddress, restPort), null, INVALID_INPUT);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_JSON, INVALID_INPUT);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_XML, INVALID_INPUT);
+ }
+
+ @Test
+ public void testSyncInvalidInput02() throws Exception {
+ QueryRequest request = new QueryRequest("");
+ request.setAsync(false);
+ runTest(buildQueryURI(request, restIpAddress, restPort), null, 405);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_JSON, 405);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_XML, 405);
+ }
+
+ @Test
+ public void testSyncInvalidQuery01() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1,2,3) return $y");
+ request.setAsync(false);
+ runTest(buildQueryURI(request, restIpAddress, restPort), null, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_JSON, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_XML, PROBLEM_WITH_QUERY);
+ }
+
+ @Test
+ public void testSyncInvalidQuery02() throws Exception {
+ QueryRequest request = new QueryRequest("for x in (1,2,3) return $x");
+ request.setAsync(false);
+ runTest(buildQueryURI(request, restIpAddress, restPort), null, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_JSON, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_XML, PROBLEM_WITH_QUERY);
+ }
+
+ @Test
+ public void testSyncInvalidQuery03() throws Exception {
+ QueryRequest request = new QueryRequest("insert nodes <book></book> into doc(\"abcd.xml\")/books");
+ request.setAsync(false);
+ runTest(buildQueryURI(request, restIpAddress, restPort), null, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_JSON, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_XML, PROBLEM_WITH_QUERY);
+ }
+
+ @Test
+ public void testSyncInvalidQuery04() throws Exception {
+ QueryRequest request = new QueryRequest("delete nodes /a/b//node()");
+ request.setAsync(false);
+ runTest(buildQueryURI(request, restIpAddress, restPort), null, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_JSON, PROBLEM_WITH_QUERY);
+ runTest(buildQueryURI(request, restIpAddress, restPort), CONTENT_TYPE_XML, PROBLEM_WITH_QUERY);
+ }
+
+ private void runTest(URI uri, String accepts, int expectedStatusCode) throws Exception {
+ runTest(uri, accepts, expectedStatusCode, HttpMethod.GET);
+ runTest(uri, accepts, expectedStatusCode, HttpMethod.POST);
+ }
+
+ private void runTest(URI uri, String accepts, int expectedStatusCode, String httpMethod) throws Exception {
+ CloseableHttpClient httpClient = HttpClients.custom().setConnectionTimeToLive(20, TimeUnit.SECONDS).build();
+
+ ErrorResponse errorResponse;
+ try {
+ HttpUriRequest request = getRequest(uri, httpMethod);
+ if (accepts != null) {
+ request.setHeader(HttpHeaders.ACCEPT, accepts);
+ }
+
+ try (CloseableHttpResponse httpResponse = httpClient.execute(request)) {
+ Assert.assertEquals(expectedStatusCode, httpResponse.getStatusLine().getStatusCode());
+ if (accepts != null) {
+ Assert.assertEquals(accepts, httpResponse.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue());
+ }
+
+ HttpEntity entity = httpResponse.getEntity();
+ Assert.assertNotNull(entity);
+
+ String response = RestUtils.readEntity(entity);
+ errorResponse = RestUtils.mapEntity(response, ErrorResponse.class, accepts);
+ }
+ } finally {
+ HttpClientUtils.closeQuietly(httpClient);
+ }
+
+ Assert.assertNotNull(errorResponse);
+ Assert.assertNotNull(errorResponse.getError().getMessage());
+ Assert.assertEquals(errorResponse.getError().getCode(), expectedStatusCode);
+ }
+}
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-rest/src/test/java/org/apache/vxquery/rest/SuccessAsyncResponseTest.java
----------------------------------------------------------------------
diff --git a/vxquery-rest/src/test/java/org/apache/vxquery/rest/SuccessAsyncResponseTest.java b/vxquery-rest/src/test/java/org/apache/vxquery/rest/SuccessAsyncResponseTest.java
new file mode 100644
index 0000000..d1385c8
--- /dev/null
+++ b/vxquery-rest/src/test/java/org/apache/vxquery/rest/SuccessAsyncResponseTest.java
@@ -0,0 +1,289 @@
+/*
+ * 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.vxquery.rest;
+
+import static org.apache.vxquery.rest.Constants.HttpHeaderValues.CONTENT_TYPE_JSON;
+import static org.apache.vxquery.rest.Constants.HttpHeaderValues.CONTENT_TYPE_XML;
+
+import java.net.URI;
+
+import javax.ws.rs.HttpMethod;
+
+import org.apache.vxquery.app.util.RestUtils;
+import org.apache.vxquery.rest.request.QueryRequest;
+import org.apache.vxquery.rest.request.QueryResultRequest;
+import org.apache.vxquery.rest.response.APIResponse;
+import org.apache.vxquery.rest.response.AsyncQueryResponse;
+import org.apache.vxquery.rest.response.ErrorResponse;
+import org.apache.vxquery.rest.response.QueryResultResponse;
+import org.apache.vxquery.rest.service.Status;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * This class tests the success responses received for XQueries submitted. i.e
+ * we are submitting correct queries which are expected to return a predictable
+ * result. All the parameters that are expected to be sent with query requests
+ * are subjected to test in this test class
+ *
+ * @author Erandi Ganepola
+ */
+public class SuccessAsyncResponseTest extends AbstractRestServerTest {
+
+ @Test
+ public void testSimpleQuery001() throws Exception {
+ QueryRequest request = new QueryRequest("1+1");
+ request.setShowAbstractSyntaxTree(true);
+ request.setShowOptimizedExpressionTree(true);
+ request.setShowRuntimePlan(true);
+ request.setShowTranslatedExpressionTree(true);
+ request.setShowMetrics(false);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSimpleQuery002() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1, 2.0, 3) return $x");
+ request.setShowAbstractSyntaxTree(true);
+ request.setShowOptimizedExpressionTree(true);
+ request.setShowRuntimePlan(true);
+ request.setShowTranslatedExpressionTree(true);
+ request.setShowMetrics(true);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSimpleQuery003() throws Exception {
+ QueryRequest request = new QueryRequest("1+2+3");
+ request.setShowAbstractSyntaxTree(false);
+ request.setShowOptimizedExpressionTree(false);
+ request.setShowRuntimePlan(false);
+ request.setShowTranslatedExpressionTree(false);
+ request.setShowMetrics(false);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSimpleQuery004() throws Exception {
+ QueryRequest request = new QueryRequest("fn:true()");
+ request.setShowAbstractSyntaxTree(false);
+ request.setShowOptimizedExpressionTree(false);
+ request.setShowRuntimePlan(true);
+ request.setShowTranslatedExpressionTree(false);
+ request.setShowMetrics(false);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSingleParameterNone() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1, 2.0, 3) return $x");
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSingleParameterMetrics() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1, 2.0, 3) return $x");
+ request.setShowMetrics(true);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSingleParameterAST() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1, 2.0, 3) return $x");
+ request.setShowAbstractSyntaxTree(true);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSingleParameterOptimization() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1, 2.0, 3) return $x");
+ request.setOptimization(10000);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSingleParameterFrameSize() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1, 2.0, 3) return $x");
+ request.setFrameSize((int) Math.pow(2, 12));
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSingleParameterCompileOnly() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1, 2.0, 3) return $x");
+ request.setCompileOnly(true);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSingleParameterOET() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1, 2.0, 3) return $x");
+ request.setShowOptimizedExpressionTree(true);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSingleParameterTET() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1, 2.0, 3) return $x");
+ request.setShowTranslatedExpressionTree(true);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSingleParameterRP() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1, 2.0, 3) return $x");
+ request.setShowRuntimePlan(true);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ private void runTest(String contentType, QueryRequest request) throws Exception {
+ runTest(contentType, request, HttpMethod.GET);
+ runTest(contentType, request, HttpMethod.POST);
+ }
+
+ private void runTest(String contentType, QueryRequest request, String httpMethod) throws Exception {
+ URI queryEndpointUri = RestUtils.buildQueryURI(request, restIpAddress, restPort);
+
+ /*
+ * ========== Query Response Testing ==========
+ */
+ // Testing the accuracy of VXQueryService class
+ AsyncQueryResponse expectedAsyncQueryResponse = (AsyncQueryResponse) vxQueryService.execute(request);
+
+ Assert.assertEquals(Status.SUCCESS.toString(), expectedAsyncQueryResponse.getStatus());
+ Assert.assertEquals(request.getStatement(), expectedAsyncQueryResponse.getStatement());
+ checkResults(expectedAsyncQueryResponse, request.isCompileOnly());
+ checkMetrics(expectedAsyncQueryResponse, request.isShowMetrics());
+ if (request.isShowMetrics()) {
+ Assert.assertTrue(expectedAsyncQueryResponse.getMetrics().getCompileTime() > 0);
+ } else {
+ Assert.assertTrue(expectedAsyncQueryResponse.getMetrics().getCompileTime() == 0);
+ }
+ if (request.isShowAbstractSyntaxTree()) {
+ Assert.assertNotNull(expectedAsyncQueryResponse.getAbstractSyntaxTree());
+ } else {
+ Assert.assertNull(expectedAsyncQueryResponse.getAbstractSyntaxTree());
+ }
+ if (request.isShowTranslatedExpressionTree()) {
+ Assert.assertNotNull(expectedAsyncQueryResponse.getTranslatedExpressionTree());
+ } else {
+ Assert.assertNull(expectedAsyncQueryResponse.getTranslatedExpressionTree());
+ }
+ if (request.isShowOptimizedExpressionTree()) {
+ Assert.assertNotNull(expectedAsyncQueryResponse.getOptimizedExpressionTree());
+ } else {
+ Assert.assertNull(expectedAsyncQueryResponse.getOptimizedExpressionTree());
+ }
+ if (request.isShowRuntimePlan()) {
+ Assert.assertNotNull(expectedAsyncQueryResponse.getRuntimePlan());
+ } else {
+ Assert.assertNull(expectedAsyncQueryResponse.getRuntimePlan());
+ }
+
+ // Testing the accuracy of REST server and servlets
+ AsyncQueryResponse actualAsyncQueryResponse =
+ getQuerySuccessResponse(queryEndpointUri, contentType, AsyncQueryResponse.class, httpMethod);
+
+ Assert.assertNotNull(actualAsyncQueryResponse.getRequestId());
+ Assert.assertEquals(request.getStatement(), actualAsyncQueryResponse.getStatement());
+ Assert.assertEquals(Status.SUCCESS.toString(), actualAsyncQueryResponse.getStatus());
+ checkResults(actualAsyncQueryResponse, request.isCompileOnly());
+ checkMetrics(actualAsyncQueryResponse, request.isShowMetrics());
+ // Cannot check this because Runtime plan include some object IDs which differ
+ // Assert.assertEquals(expectedAsyncQueryResponse.getRuntimePlan(),
+ // actualAsyncQueryResponse.getRuntimePlan());
+ if (request.isShowRuntimePlan()) {
+ Assert.assertNotNull(actualAsyncQueryResponse.getRuntimePlan());
+ } else {
+ Assert.assertNull(actualAsyncQueryResponse.getRuntimePlan());
+ }
+ Assert.assertEquals(normalize(expectedAsyncQueryResponse.getOptimizedExpressionTree()),
+ normalize(actualAsyncQueryResponse.getOptimizedExpressionTree()));
+ Assert.assertEquals(normalize(expectedAsyncQueryResponse.getTranslatedExpressionTree()),
+ normalize(actualAsyncQueryResponse.getTranslatedExpressionTree()));
+ Assert.assertEquals(normalize(expectedAsyncQueryResponse.getAbstractSyntaxTree()),
+ normalize(actualAsyncQueryResponse.getAbstractSyntaxTree()));
+
+ /*
+ * ========== Query Result Response Testing ========
+ */
+ QueryResultRequest resultRequest = new QueryResultRequest(actualAsyncQueryResponse.getResultId());
+ resultRequest.setShowMetrics(true);
+
+ if (request.isCompileOnly()) {
+ APIResponse resultResponse = vxQueryService.getResult(resultRequest);
+ Assert.assertTrue(resultResponse instanceof ErrorResponse);
+ } else {
+ QueryResultResponse expectedResultResponse = (QueryResultResponse) vxQueryService.getResult(resultRequest);
+ Assert.assertEquals(expectedResultResponse.getStatus(), Status.SUCCESS.toString());
+ Assert.assertNotNull(expectedResultResponse.getResults());
+
+ QueryResultResponse actualResultResponse = getQueryResultResponse(resultRequest, contentType, httpMethod);
+ Assert.assertEquals(actualResultResponse.getStatus(), Status.SUCCESS.toString());
+ Assert.assertNotNull(actualResultResponse.getResults());
+ Assert.assertNotNull(actualResultResponse.getRequestId());
+ Assert.assertEquals(normalize(expectedResultResponse.getResults()),
+ normalize(actualResultResponse.getResults()));
+ if (resultRequest.isShowMetrics()) {
+ Assert.assertTrue(actualResultResponse.getMetrics().getElapsedTime() > 0);
+ } else {
+ Assert.assertTrue(actualResultResponse.getMetrics().getElapsedTime() == 0);
+ }
+
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-rest/src/test/java/org/apache/vxquery/rest/SuccessSyncResponseTest.java
----------------------------------------------------------------------
diff --git a/vxquery-rest/src/test/java/org/apache/vxquery/rest/SuccessSyncResponseTest.java b/vxquery-rest/src/test/java/org/apache/vxquery/rest/SuccessSyncResponseTest.java
new file mode 100644
index 0000000..31e0162
--- /dev/null
+++ b/vxquery-rest/src/test/java/org/apache/vxquery/rest/SuccessSyncResponseTest.java
@@ -0,0 +1,215 @@
+/*
+ * 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.vxquery.rest;
+
+import static org.apache.vxquery.rest.Constants.HttpHeaderValues.CONTENT_TYPE_JSON;
+import static org.apache.vxquery.rest.Constants.HttpHeaderValues.CONTENT_TYPE_XML;
+
+import java.net.URI;
+
+import javax.ws.rs.HttpMethod;
+
+import org.apache.vxquery.app.util.RestUtils;
+import org.apache.vxquery.rest.request.QueryRequest;
+import org.apache.vxquery.rest.response.SyncQueryResponse;
+import org.apache.vxquery.rest.service.Status;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * This class tests the success responses received for XQueries submitted. i.e
+ * we are submitting correct queries which are expected to return a predictable
+ * result. All the parameters that are expected to be sent with query requests
+ * are subjected to test in this test class
+ *
+ * @author Erandi Ganepola
+ */
+public class SuccessSyncResponseTest extends AbstractRestServerTest {
+
+ @Test
+ public void testSimpleQuery001() throws Exception {
+ QueryRequest request = new QueryRequest("1+1");
+ request.setShowAbstractSyntaxTree(true);
+ request.setShowOptimizedExpressionTree(true);
+ request.setShowRuntimePlan(true);
+ request.setShowTranslatedExpressionTree(true);
+ request.setShowMetrics(false);
+ request.setAsync(false);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSimpleQuery002() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1, 2.0, 3) return $x");
+ request.setShowAbstractSyntaxTree(true);
+ request.setShowOptimizedExpressionTree(true);
+ request.setShowRuntimePlan(true);
+ request.setShowTranslatedExpressionTree(true);
+ request.setShowMetrics(true);
+ request.setAsync(false);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSimpleQuery003() throws Exception {
+ QueryRequest request = new QueryRequest("1+2+3");
+ request.setShowAbstractSyntaxTree(false);
+ request.setShowOptimizedExpressionTree(false);
+ request.setShowRuntimePlan(false);
+ request.setShowTranslatedExpressionTree(false);
+ request.setShowMetrics(false);
+ request.setAsync(false);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSimpleQuery004() throws Exception {
+ QueryRequest request = new QueryRequest("fn:true()");
+ request.setShowAbstractSyntaxTree(false);
+ request.setShowOptimizedExpressionTree(false);
+ request.setShowRuntimePlan(true);
+ request.setShowTranslatedExpressionTree(false);
+ request.setShowMetrics(false);
+ request.setAsync(false);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSingleParameterNone() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1, 2.0, 3) return $x");
+ request.setAsync(false);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSingleParameterCompileOnly() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1, 2.0, 3) return $x");
+ request.setCompileOnly(true);
+ request.setAsync(false);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ @Test
+ public void testSingleParameterRepeatExecutions() throws Exception {
+ QueryRequest request = new QueryRequest("for $x in (1, 2.0, 3) return $x");
+ request.setRepeatExecutions(5);
+ request.setAsync(false);
+
+ runTest(null, request);
+ runTest(CONTENT_TYPE_JSON, request);
+ runTest(CONTENT_TYPE_XML, request);
+ }
+
+ private void runTest(String contentType, QueryRequest request) throws Exception {
+ runTest(contentType, request, HttpMethod.GET);
+ runTest(contentType, request, HttpMethod.POST);
+ }
+
+ private void runTest(String contentType, QueryRequest request, String httpMethod) throws Exception {
+ URI queryEndpointUri = RestUtils.buildQueryURI(request, restIpAddress, restPort);
+
+ /*
+ * ========== Query Response Testing ==========
+ */
+ // Testing the accuracy of VXQueryService class
+ SyncQueryResponse expectedSyncQueryResponse = (SyncQueryResponse) vxQueryService.execute(request);
+
+ Assert.assertEquals(Status.SUCCESS.toString(), expectedSyncQueryResponse.getStatus());
+ Assert.assertEquals(request.getStatement(), expectedSyncQueryResponse.getStatement());
+ checkResults(expectedSyncQueryResponse, request.isCompileOnly());
+ checkMetrics(expectedSyncQueryResponse, request.isShowMetrics());
+ if (request.isShowMetrics()) {
+ Assert.assertTrue(expectedSyncQueryResponse.getMetrics().getCompileTime() > 0);
+ } else {
+ Assert.assertTrue(expectedSyncQueryResponse.getMetrics().getCompileTime() == 0);
+ }
+ if (request.isShowAbstractSyntaxTree()) {
+ Assert.assertNotNull(expectedSyncQueryResponse.getAbstractSyntaxTree());
+ } else {
+ Assert.assertNull(expectedSyncQueryResponse.getAbstractSyntaxTree());
+ }
+ if (request.isShowTranslatedExpressionTree()) {
+ Assert.assertNotNull(expectedSyncQueryResponse.getTranslatedExpressionTree());
+ } else {
+ Assert.assertNull(expectedSyncQueryResponse.getTranslatedExpressionTree());
+ }
+ if (request.isShowOptimizedExpressionTree()) {
+ Assert.assertNotNull(expectedSyncQueryResponse.getOptimizedExpressionTree());
+ } else {
+ Assert.assertNull(expectedSyncQueryResponse.getOptimizedExpressionTree());
+ }
+ if (request.isShowRuntimePlan()) {
+ Assert.assertNotNull(expectedSyncQueryResponse.getRuntimePlan());
+ } else {
+ Assert.assertNull(expectedSyncQueryResponse.getRuntimePlan());
+ }
+
+ // Testing the accuracy of REST server and servlets
+ SyncQueryResponse actualSyncQueryResponse =
+ getQuerySuccessResponse(queryEndpointUri, contentType, SyncQueryResponse.class, httpMethod);
+
+ Assert.assertNotNull(actualSyncQueryResponse.getRequestId());
+ Assert.assertEquals(request.getStatement(), actualSyncQueryResponse.getStatement());
+ Assert.assertEquals(Status.SUCCESS.toString(), actualSyncQueryResponse.getStatus());
+ checkMetrics(actualSyncQueryResponse, request.isShowMetrics());
+ checkResults(actualSyncQueryResponse, request.isCompileOnly());
+ // Cannot check this because Runtime plan include some object IDs which differ
+ // Assert.assertEquals(expectedSyncQueryResponse.getRuntimePlan(),
+ // actualSyncQueryResponse.getRuntimePlan());
+ if (request.isShowRuntimePlan()) {
+ Assert.assertNotNull(actualSyncQueryResponse.getRuntimePlan());
+ } else {
+ Assert.assertNull(actualSyncQueryResponse.getRuntimePlan());
+ }
+ Assert.assertEquals(normalize(expectedSyncQueryResponse.getOptimizedExpressionTree()),
+ normalize(actualSyncQueryResponse.getOptimizedExpressionTree()));
+ Assert.assertEquals(normalize(expectedSyncQueryResponse.getTranslatedExpressionTree()),
+ normalize(actualSyncQueryResponse.getTranslatedExpressionTree()));
+ Assert.assertEquals(normalize(expectedSyncQueryResponse.getAbstractSyntaxTree()),
+ normalize(actualSyncQueryResponse.getAbstractSyntaxTree()));
+
+ /*
+ * ========== Query Result Response Testing ========
+ */
+ String expectedResults = expectedSyncQueryResponse.getResults();
+ String actualResults = actualSyncQueryResponse.getResults();
+ if (!request.isCompileOnly()) {
+ Assert.assertNotNull(expectedResults);
+ Assert.assertNotNull(actualResults);
+ }
+ Assert.assertEquals(normalize(expectedResults), normalize(actualResults));
+ }
+}
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-rest/src/test/resources/vxquery.properties
----------------------------------------------------------------------
diff --git a/vxquery-rest/src/test/resources/vxquery.properties b/vxquery-rest/src/test/resources/vxquery.properties
new file mode 100644
index 0000000..8870f79
--- /dev/null
+++ b/vxquery-rest/src/test/resources/vxquery.properties
@@ -0,0 +1,30 @@
+#
+# 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.
+
+# Number of processors to be used for query processing
+#org.apache.vxquery.available_processors=-1
+
+# Number of local node controllers to be created when creating a local hyracks cluster
+org.apache.vxquery.local_nc=1
+
+# Join hash size
+#org.apache.vxquery.join_hash=-1
+
+# Maximum Data Size
+#org.apache.vxquery.data_size=-1
+
+# hdfs config directory
+#org.apache.vxquery.hdfs_config=foo/bar
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-server/pom.xml
----------------------------------------------------------------------
diff --git a/vxquery-server/pom.xml b/vxquery-server/pom.xml
index e572c36..7331fde 100644
--- a/vxquery-server/pom.xml
+++ b/vxquery-server/pom.xml
@@ -41,7 +41,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
- <version>1.1.1</version>
+ <version>2.0.0</version>
<executions>
<execution>
<configuration>
@@ -53,6 +53,10 @@
<program>
<mainClass>org.apache.hyracks.control.cc.CCDriver</mainClass>
<name>vxquerycc</name>
+ <commandLineArguments>
+ <commandLineArgument>-app-cc-main-class</commandLineArgument>
+ <commandLineArgument>org.apache.vxquery.app.VXQueryApplication</commandLineArgument>
+ </commandLineArguments>
</program>
<program>
<mainClass>org.apache.hyracks.control.nc.NCDriver</mainClass>
@@ -139,15 +143,13 @@
<dependencies>
<dependency>
<groupId>org.apache.vxquery</groupId>
- <artifactId>apache-vxquery-core</artifactId>
+ <artifactId>apache-vxquery-rest</artifactId>
<version>0.7-SNAPSHOT</version>
</dependency>
-
<dependency>
<groupId>org.apache.hyracks</groupId>
<artifactId>hyracks-control-cc</artifactId>
</dependency>
-
<dependency>
<groupId>org.apache.hyracks</groupId>
<artifactId>hyracks-control-nc</artifactId>
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-xtest/pom.xml
----------------------------------------------------------------------
diff --git a/vxquery-xtest/pom.xml b/vxquery-xtest/pom.xml
index a00bec2..a32d913 100644
--- a/vxquery-xtest/pom.xml
+++ b/vxquery-xtest/pom.xml
@@ -144,6 +144,12 @@
</dependency>
<dependency>
+ <groupId>org.apache.vxquery</groupId>
+ <artifactId>apache-vxquery-rest</artifactId>
+ <version>0.7-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
<groupId>org.apache.hyracks</groupId>
<artifactId>hyracks-api</artifactId>
</dependency>
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/TestClusterUtil.java
----------------------------------------------------------------------
diff --git a/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/TestClusterUtil.java b/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/TestClusterUtil.java
index 0e5b481..4d2ae8a 100644
--- a/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/TestClusterUtil.java
+++ b/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/TestClusterUtil.java
@@ -19,81 +19,45 @@ package org.apache.vxquery.xtest;
import org.apache.hyracks.api.client.HyracksConnection;
import org.apache.hyracks.client.dataset.HyracksDataset;
-import org.apache.hyracks.control.cc.ClusterControllerService;
-import org.apache.hyracks.control.common.controllers.CCConfig;
-import org.apache.hyracks.control.common.controllers.NCConfig;
-import org.apache.hyracks.control.nc.NodeControllerService;
+import org.apache.vxquery.app.util.LocalClusterUtil;
+import org.apache.vxquery.rest.service.VXQueryConfig;
-import java.io.File;
import java.io.IOException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
public class TestClusterUtil {
- private static final int CLIENT_NET_PORT = 39000;
- private static final int CLUSTER_NET_PORT = 39001;
- private static final int PROFILE_DUMP_PERIOD = 10000;
- private static final String CC_HOST = "localhost";
- private static final String NODE_ID = "nc1";
- private static final String IO_DEVICES = "target/tmp/indexFolder";
-
private static HyracksConnection hcc;
private static HyracksDataset hds;
+ public static final LocalClusterUtil localClusterUtil = new LocalClusterUtil();
+
private TestClusterUtil() {
}
- public static CCConfig createCCConfig() throws UnknownHostException {
- String publicAddress = InetAddress.getLocalHost().getHostAddress();
- CCConfig ccConfig = new CCConfig();
- ccConfig.clientNetIpAddress = publicAddress;
- ccConfig.clientNetPort = CLIENT_NET_PORT;
- ccConfig.clusterNetIpAddress = publicAddress;
- ccConfig.clusterNetPort = CLUSTER_NET_PORT;
- ccConfig.profileDumpPeriod = PROFILE_DUMP_PERIOD;
- return ccConfig;
- }
+ private static VXQueryConfig loadConfiguration(XTestOptions opts) {
+ VXQueryConfig vxqConfig = new VXQueryConfig();
- public static NCConfig createNCConfig() throws UnknownHostException {
- String publicAddress = InetAddress.getLocalHost().getHostAddress();
- NCConfig ncConfig1 = new NCConfig();
- ncConfig1.ccHost = CC_HOST;
- ncConfig1.ccPort = CLUSTER_NET_PORT;
- ncConfig1.clusterNetIPAddress = publicAddress;
- ncConfig1.dataIPAddress = publicAddress;
- ncConfig1.resultIPAddress = publicAddress;
- ncConfig1.nodeId = NODE_ID;
- ncConfig1.ioDevices = IO_DEVICES;
- return ncConfig1;
+ vxqConfig.setAvailableProcessors(opts.threads);
+ vxqConfig.setFrameSize(opts.frameSize);
+ vxqConfig.setHdfsConf(opts.hdfsConf);
+
+ return vxqConfig;
}
- public static ClusterControllerService startCC(XTestOptions opts) throws IOException {
- CCConfig ccConfig = createCCConfig();
- File outDir = new File("target/ClusterController");
- outDir.mkdirs();
- File ccRoot = File.createTempFile(TestRunner.class.getName(), ".data", outDir);
- ccRoot.delete();
- ccRoot.mkdir();
- ccConfig.ccRoot = ccRoot.getAbsolutePath();
+ public static void startCluster(XTestOptions opts, LocalClusterUtil localClusterUtil) throws IOException {
try {
- ClusterControllerService cc = new ClusterControllerService(ccConfig);
- cc.start();
- hcc = new HyracksConnection(ccConfig.clientNetIpAddress, ccConfig.clientNetPort);
- hds = new HyracksDataset(hcc, opts.frameSize, opts.threads);
- return cc;
+ VXQueryConfig config = loadConfiguration(opts);
+ localClusterUtil.init(config);
+ hcc = (HyracksConnection) localClusterUtil.getConnection();
+ hds = (HyracksDataset) localClusterUtil.getDataset();
} catch (Exception e) {
throw new IOException(e);
}
-
}
- public static NodeControllerService startNC() throws IOException {
- NCConfig ncConfig = createNCConfig();
+ public static void stopCluster(LocalClusterUtil localClusterUtil) throws IOException {
try {
- NodeControllerService nc = new NodeControllerService(ncConfig);
- nc.start();
- return nc;
+ localClusterUtil.deinit();
} catch (Exception e) {
throw new IOException(e);
}
@@ -107,13 +71,4 @@ public class TestClusterUtil {
return hds;
}
- public static void stopCluster(ClusterControllerService cc, NodeControllerService nc) throws IOException {
- try {
- nc.stop();
- cc.stop();
- } catch (Exception e) {
- throw new IOException(e);
- }
- }
-
}
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/TestRunner.java
----------------------------------------------------------------------
diff --git a/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/TestRunner.java b/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/TestRunner.java
index fa0a900..8ef9426 100644
--- a/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/TestRunner.java
+++ b/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/TestRunner.java
@@ -14,101 +14,54 @@
*/
package org.apache.vxquery.xtest;
+import static org.apache.vxquery.rest.Constants.HttpHeaderValues.CONTENT_TYPE_JSON;
+
import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Reader;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.EnumSet;
-import java.util.List;
+import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.hyracks.api.client.IHyracksClientConnection;
-import org.apache.hyracks.api.client.NodeControllerInfo;
-import org.apache.hyracks.api.comm.IFrame;
-import org.apache.hyracks.api.comm.IFrameTupleAccessor;
-import org.apache.hyracks.api.comm.VSizeFrame;
-import org.apache.hyracks.api.dataset.DatasetJobRecord;
-import org.apache.hyracks.api.dataset.IHyracksDataset;
-import org.apache.hyracks.api.dataset.IHyracksDatasetReader;
-import org.apache.hyracks.api.dataset.ResultSetId;
-import org.apache.hyracks.api.exceptions.HyracksException;
-import org.apache.hyracks.api.job.JobFlag;
-import org.apache.hyracks.api.job.JobId;
-import org.apache.hyracks.api.job.JobSpecification;
-import org.apache.hyracks.control.nc.resources.memory.FrameManager;
-import org.apache.hyracks.dataflow.common.comm.io.ResultFrameTupleAccessor;
-import org.apache.vxquery.compiler.CompilerControlBlock;
-import org.apache.vxquery.compiler.algebricks.VXQueryGlobalDataFactory;
-import org.apache.vxquery.context.DynamicContext;
-import org.apache.vxquery.context.DynamicContextImpl;
-import org.apache.vxquery.context.RootStaticContextImpl;
-import org.apache.vxquery.context.StaticContextImpl;
+import javax.xml.bind.JAXBException;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.utils.HttpClientUtils;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.vxquery.app.util.RestUtils;
import org.apache.vxquery.exceptions.ErrorCode;
import org.apache.vxquery.exceptions.SystemException;
-import org.apache.vxquery.result.ResultUtils;
-import org.apache.vxquery.xmlquery.query.VXQueryCompilationListener;
-import org.apache.vxquery.xmlquery.query.XMLQueryCompiler;
+import org.apache.vxquery.rest.request.QueryRequest;
+import org.apache.vxquery.rest.response.APIResponse;
+import org.apache.vxquery.rest.response.ErrorResponse;
+import org.apache.vxquery.rest.response.SyncQueryResponse;
+import org.codehaus.jackson.map.ObjectMapper;
public class TestRunner {
+
private static final Pattern EMBEDDED_SYSERROR_PATTERN = Pattern.compile("(\\p{javaUpperCase}{4}\\d{4})");
- private List<String> collectionList;
+
private XTestOptions opts;
- private IHyracksClientConnection hcc;
- private IHyracksDataset hds;
public TestRunner(XTestOptions opts) throws UnknownHostException {
this.opts = opts;
- this.collectionList = new ArrayList<String>();
}
public void open() throws Exception {
- hcc = TestClusterUtil.getConnection();
- hds = TestClusterUtil.getDataset();
- }
-
- protected static TestConfiguration getIndexConfiguration(TestCase testCase) {
- XTestOptions opts = new XTestOptions();
- opts.verbose = false;
- opts.threads = 1;
- opts.showQuery = true;
- opts.showResult = true;
- opts.hdfsConf = "src/test/resources/hadoop/conf";
- opts.catalog = StringUtils.join(new String[] { "src", "test", "resources", "VXQueryCatalog.xml" },
- File.separator);
- TestConfiguration indexConf = new TestConfiguration();
- indexConf.options = opts;
- String baseDir = new File(opts.catalog).getParent();
- try {
- String root = new File(baseDir).getCanonicalPath();
- indexConf.testRoot = new File(root + "/./");
- indexConf.resultOffsetPath = new File(root + "/./ExpectedResults/");
- indexConf.sourceFileMap = testCase.getSourceFileMap();
- indexConf.xqueryFileExtension = ".xq";
- indexConf.xqueryxFileExtension = "xqx";
- indexConf.xqueryQueryOffsetPath = new File(root + "/./Queries/XQuery/");
- } catch (IOException e) {
- e.printStackTrace();
- }
- return indexConf;
-
}
public TestCaseResult run(final TestCase testCase) {
TestCaseResult res = new TestCaseResult(testCase);
- TestCase testCaseIndex = new TestCase(getIndexConfiguration(testCase));
- testCaseIndex.setFolder("Indexing/Partition-1/");
- testCaseIndex.setName("showIndexes");
- runQuery(testCaseIndex, res);
- String[] collections = res.result.split("\n");
- this.collectionList = Arrays.asList(collections);
runQueries(testCase, res);
return res;
}
@@ -121,83 +74,32 @@ public class TestRunner {
long start = System.currentTimeMillis();
try {
- try {
- if (opts.showQuery) {
+ String query = FileUtils.readFileToString(testCase.getXQueryFile(), "UTF-8");
- FileInputStream query = new FileInputStream(testCase.getXQueryFile());
- System.err.println("***Query for " + testCase.getXQueryDisplayName() + ": ");
- System.err.println(IOUtils.toString(query, "UTF-8"));
- query.close();
- }
-
- VXQueryCompilationListener listener = new VXQueryCompilationListener(opts.showAST, opts.showTET,
- opts.showOET, opts.showRP);
-
- Map<String, NodeControllerInfo> nodeControllerInfos = null;
- if (hcc != null) {
- nodeControllerInfos = hcc.getNodeControllerInfos();
- }
+ if (opts.showQuery) {
+ System.err.println("***Query for " + testCase.getXQueryDisplayName() + ": ");
+ System.err.println(query);
+ }
- XMLQueryCompiler compiler = new XMLQueryCompiler(listener, nodeControllerInfos, opts.frameSize,
- opts.hdfsConf);
- Reader in = new InputStreamReader(new FileInputStream(testCase.getXQueryFile()), "UTF-8");
- CompilerControlBlock ccb = new CompilerControlBlock(
- new StaticContextImpl(RootStaticContextImpl.INSTANCE),
- new ResultSetId(testCase.getXQueryDisplayName().hashCode()), testCase.getSourceFileMap());
- compiler.compile(testCase.getXQueryDisplayName(), in, ccb, opts.optimizationLevel, collectionList);
- JobSpecification spec = compiler.getModule().getHyracksJobSpecification();
- in.close();
-
- DynamicContext dCtx = new DynamicContextImpl(compiler.getModule().getModuleContext());
- spec.setGlobalJobDataFactory(new VXQueryGlobalDataFactory(dCtx.createFactory()));
-
- spec.setMaxReattempts(0);
- JobId jobId = hcc.startJob(spec, EnumSet.of(JobFlag.PROFILE_RUNTIME));
-
- FrameManager resultDisplayFrameMgr = new FrameManager(spec.getFrameSize());
- IFrame frame = new VSizeFrame(resultDisplayFrameMgr);
- IHyracksDatasetReader reader = hds.createReader(jobId, ccb.getResultSetId());
- // TODO(tillw) remove this loop once the IHyracksDatasetReader reliably returns the correct exception
- while (reader.getResultStatus() == DatasetJobRecord.Status.RUNNING) {
- Thread.sleep(1);
- }
- IFrameTupleAccessor frameTupleAccessor = new ResultFrameTupleAccessor();
- res.result = "";
- while (reader.read(frame) > 0) {
- res.result += ResultUtils.getStringFromBuffer(frame.getBuffer(), frameTupleAccessor);
- frame.getBuffer().clear();
- }
- res.result.trim();
- hcc.waitForCompletion(jobId);
- } catch (HyracksException e) {
- Throwable t = e;
- while (t.getCause() != null) {
- t = t.getCause();
- }
- final String message = t.getMessage();
- if (message != null) {
- Matcher m = EMBEDDED_SYSERROR_PATTERN.matcher(message);
- if (m.find()) {
- String eCode = m.group(1);
- throw new SystemException(ErrorCode.valueOf(eCode), e);
- }
+ QueryRequest request = createQueryRequest(opts, query);
+ APIResponse response = sendQueryRequest(request, testCase.getSourceFileMap());
+ if (response instanceof SyncQueryResponse) {
+ res.result = ((SyncQueryResponse) response).getResults();
+ } else {
+ System.err.println("Error response: Failure when running the query");
+ ErrorResponse errorResponse = (ErrorResponse) response;
+ Matcher m = EMBEDDED_SYSERROR_PATTERN.matcher(errorResponse.getError().getMessage());
+
+ Exception e = new RuntimeException("Failed to run the query");
+ if (m.find()) {
+ String eCode = m.group(1);
+ throw new SystemException(ErrorCode.valueOf(eCode), e);
+ } else {
+ throw e;
}
- throw e;
}
} catch (Throwable e) {
- // Check for nested SystemExceptions.
- Throwable error = e;
- while (error != null) {
- if (error instanceof SystemException) {
- res.error = error;
- break;
- }
- error = error.getCause();
- }
- // Default
- if (res.error == null) {
- res.error = e;
- }
+ res.error = e;
} finally {
try {
res.compare();
@@ -208,6 +110,7 @@ public class TestRunner {
long end = System.currentTimeMillis();
res.time = end - start;
}
+
if (opts.showResult) {
if (res.result == null) {
System.err.println("***Error: ");
@@ -218,7 +121,55 @@ public class TestRunner {
System.err.println(res.result);
}
}
+ }
+
+ private static QueryRequest createQueryRequest(XTestOptions opts, String query) {
+ QueryRequest request = new QueryRequest(query);
+ request.setCompileOnly(opts.compileOnly);
+ request.setOptimization(opts.optimizationLevel);
+ request.setFrameSize(opts.frameSize);
+ request.setShowAbstractSyntaxTree(opts.showAST);
+ request.setShowTranslatedExpressionTree(opts.showTET);
+ request.setShowOptimizedExpressionTree(opts.showOET);
+ request.setShowRuntimePlan(opts.showRP);
+ request.setAsync(false);
+
+ return request;
+ }
+
+ private static APIResponse sendQueryRequest(QueryRequest request, Map<String, File> sourceFileMap)
+ throws IOException, URISyntaxException {
+
+ URI uri = RestUtils.buildQueryURI(request, TestClusterUtil.localClusterUtil.getIpAddress(),
+ TestClusterUtil.localClusterUtil.getRestPort());
+ CloseableHttpClient httpClient = HttpClients.custom().build();
+
+ try {
+ HttpPost httpRequest = new HttpPost(uri);
+ httpRequest.setHeader(HttpHeaders.ACCEPT, CONTENT_TYPE_JSON);
+
+ ObjectMapper mapper = new ObjectMapper();
+ String fileMap = mapper.writeValueAsString(sourceFileMap);
+ httpRequest.setEntity(new StringEntity(fileMap, StandardCharsets.UTF_8));
+
+ try (CloseableHttpResponse httpResponse = httpClient.execute(httpRequest)) {
+ HttpEntity entity = httpResponse.getEntity();
+ String response = RestUtils.readEntity(entity);
+ if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ return RestUtils.mapEntity(response, SyncQueryResponse.class, CONTENT_TYPE_JSON);
+ } else {
+ return RestUtils.mapEntity(response, ErrorResponse.class, CONTENT_TYPE_JSON);
+ }
+ } catch (IOException e) {
+ System.err.println("Error occurred when reading entity: " + e.getMessage());
+ } catch (JAXBException e) {
+ System.err.println("Error occurred when mapping query response: " + e.getMessage());
+ }
+ } finally {
+ HttpClientUtils.closeQuietly(httpClient);
+ }
+ return null;
}
public void runQueries(TestCase testCase, TestCaseResult res) {
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/XTest.java
----------------------------------------------------------------------
diff --git a/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/XTest.java b/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/XTest.java
index 5aae691..df7a71d 100644
--- a/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/XTest.java
+++ b/vxquery-xtest/src/main/java/org/apache/vxquery/xtest/XTest.java
@@ -16,10 +16,6 @@
*/
package org.apache.vxquery.xtest;
-import org.apache.hyracks.control.cc.ClusterControllerService;
-import org.apache.hyracks.control.nc.NodeControllerService;
-import org.mortbay.jetty.Server;
-
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -28,6 +24,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import org.mortbay.jetty.Server;
+
public class XTest {
private XTestOptions opts;
private Server server;
@@ -36,8 +34,6 @@ public class XTest {
private TestRunnerFactory trf;
private int count;
private int finishCount;
- private static NodeControllerService nc;
- private static ClusterControllerService cc;
XTest(XTestOptions opts) {
this.opts = opts;
@@ -81,8 +77,7 @@ public class XTest {
}
}
});
- cc = TestClusterUtil.startCC(opts);
- nc = TestClusterUtil.startNC();
+ TestClusterUtil.startCluster(opts, TestClusterUtil.localClusterUtil);
trf = new TestRunnerFactory(opts);
trf.registerReporters(reporters);
TestCaseFactory tcf = new TestCaseFactory(trf, eSvc, opts);
@@ -104,7 +99,7 @@ public class XTest {
r.close();
}
try {
- TestClusterUtil.stopCluster(cc, nc);
+ TestClusterUtil.stopCluster(TestClusterUtil.localClusterUtil);
} catch (IOException e) {
e.printStackTrace();
}
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-xtest/src/test/java/org/apache/vxquery/xtest/AbstractXQueryTest.java
----------------------------------------------------------------------
diff --git a/vxquery-xtest/src/test/java/org/apache/vxquery/xtest/AbstractXQueryTest.java b/vxquery-xtest/src/test/java/org/apache/vxquery/xtest/AbstractXQueryTest.java
index 1e2dcf6..8f77de4 100644
--- a/vxquery-xtest/src/test/java/org/apache/vxquery/xtest/AbstractXQueryTest.java
+++ b/vxquery-xtest/src/test/java/org/apache/vxquery/xtest/AbstractXQueryTest.java
@@ -22,8 +22,6 @@ import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
-import org.apache.hyracks.control.cc.ClusterControllerService;
-import org.apache.hyracks.control.nc.NodeControllerService;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
@@ -38,8 +36,6 @@ public abstract class AbstractXQueryTest {
private TestRunner tr;
private static MiniDFS dfs;
private final static String TMP = "target/tmp";
- private static NodeControllerService nc;
- private static ClusterControllerService cc;
protected abstract XTestOptions getTestOptions();
@@ -92,8 +88,7 @@ public abstract class AbstractXQueryTest {
@BeforeClass
public static void setup() throws IOException {
- cc = TestClusterUtil.startCC(getDefaultTestOptions());
- nc = TestClusterUtil.startNC();
+ TestClusterUtil.startCluster(getDefaultTestOptions(), TestClusterUtil.localClusterUtil);
setupFS();
}
@@ -116,7 +111,7 @@ public abstract class AbstractXQueryTest {
@AfterClass
public static void shutdown() throws IOException {
removeFS();
- TestClusterUtil.stopCluster(cc, nc);
+ TestClusterUtil.stopCluster(TestClusterUtil.localClusterUtil);
}
public static void removeFS() throws IOException {
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-1.txt
----------------------------------------------------------------------
diff --git a/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-1.txt b/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-1.txt
new file mode 100644
index 0000000..b1db973
--- /dev/null
+++ b/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-1.txt
@@ -0,0 +1,3 @@
+<value>33</value>
+<value>32</value>
+<value>31</value>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-2.txt
----------------------------------------------------------------------
diff --git a/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-2.txt b/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-2.txt
new file mode 100644
index 0000000..d93567e
--- /dev/null
+++ b/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-2.txt
@@ -0,0 +1,3 @@
+<value>33</value>
+<value>31</value>
+<value>32</value>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-3.txt
----------------------------------------------------------------------
diff --git a/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-3.txt b/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-3.txt
new file mode 100644
index 0000000..2ab8764
--- /dev/null
+++ b/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-3.txt
@@ -0,0 +1,3 @@
+<value>32</value>
+<value>33</value>
+<value>31</value>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/vxquery/blob/f2e5fd90/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-4.txt
----------------------------------------------------------------------
diff --git a/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-4.txt b/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-4.txt
new file mode 100644
index 0000000..d1d6bb7
--- /dev/null
+++ b/vxquery-xtest/src/test/resources/ExpectedTestResults/GhcndRecords/Partition-2/q03_records-4.txt
@@ -0,0 +1,3 @@
+<value>32</value>
+<value>31</value>
+<value>33</value>
\ No newline at end of file