http://git-wip-us.apache.org/repos/asf/asterixdb/blob/452ec9f6/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..f5d97ba
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
@@ -0,0 +1,1258 @@
+/*
+ * 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.asterix.test.common;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.Inet4Address;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.asterix.common.config.GlobalConfig;
+import org.apache.asterix.common.utils.Servlets;
+import org.apache.asterix.test.server.ITestServer;
+import org.apache.asterix.test.server.TestServerProvider;
+import org.apache.asterix.testframework.context.TestCaseContext;
+import org.apache.asterix.testframework.context.TestCaseContext.OutputFormat;
+import org.apache.asterix.testframework.context.TestFileContext;
+import org.apache.asterix.testframework.xml.TestCase.CompilationUnit;
+import org.apache.asterix.testframework.xml.TestGroup;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.mutable.MutableInt;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.client.StandardHttpRequestRetryHandler;
+import org.apache.http.util.EntityUtils;
+import org.apache.hyracks.util.StorageUtil;
+import org.junit.Assert;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class TestExecutor {
+
+    /*
+     * Static variables
+     */
+    protected static final Logger LOGGER = 
Logger.getLogger(TestExecutor.class.getName());
+    // see
+    // 
https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers/417184
+    private static final long MAX_URL_LENGTH = 2000l;
+    private static final Pattern JAVA_BLOCK_COMMENT_PATTERN =
+            Pattern.compile("/\\*.*\\*/", Pattern.MULTILINE | Pattern.DOTALL);
+    private static final Pattern JAVA_LINE_COMMENT_PATTERN = 
Pattern.compile("//.*$", Pattern.MULTILINE);
+    private static final Pattern SHELL_LINE_COMMENT_PATTERN = 
Pattern.compile("#.*$", Pattern.MULTILINE);
+    private static final Pattern REGEX_LINES_PATTERN = 
Pattern.compile("^(-)?/(.*)/([im]*)$");
+    private static final Pattern POLL_TIMEOUT_PATTERN =
+            Pattern.compile("polltimeoutsecs=(\\d+)(\\D|$)", 
Pattern.MULTILINE);
+    private static final Pattern POLL_DELAY_PATTERN =
+            Pattern.compile("polldelaysecs=(\\d+)(\\D|$)", Pattern.MULTILINE);
+    private static final Pattern HANDLE_VARIABLE_PATTERN = 
Pattern.compile("handlevariable=(\\w+)");
+    private static final Pattern VARIABLE_REF_PATTERN = 
Pattern.compile("\\$(\\w+)");
+
+    public static final int TRUNCATE_THRESHOLD = 16384;
+
+    public static final String DELIVERY_ASYNC = "async";
+    public static final String DELIVERY_DEFERRED = "deferred";
+    public static final String DELIVERY_IMMEDIATE = "immediate";
+
+    private static Method managixExecuteMethod = null;
+    private static final HashMap<Integer, ITestServer> runningTestServers = 
new HashMap<>();
+
+    /*
+     * Instance members
+     */
+    protected final String host;
+    protected final int port;
+    protected ITestLibrarian librarian;
+
+    public TestExecutor(String host, int port) {
+        this.host = host;
+        this.port = port;
+    }
+
+    public TestExecutor() {
+        this(Inet4Address.getLoopbackAddress().getHostAddress(), 19002);
+    }
+
+    public void setLibrarian(ITestLibrarian librarian) {
+        this.librarian = librarian;
+    }
+
+    /**
+     * Probably does not work well with symlinks.
+     */
+    public boolean deleteRec(File path) {
+        if (path.isDirectory()) {
+            for (File f : path.listFiles()) {
+                if (!deleteRec(f)) {
+                    return false;
+                }
+            }
+        }
+        return path.delete();
+    }
+
+    public void runScriptAndCompareWithResult(File scriptFile, PrintWriter 
print, File expectedFile, File actualFile)
+            throws Exception {
+        System.err.println("Expected results file: " + 
expectedFile.toString());
+        BufferedReader readerExpected =
+                new BufferedReader(new InputStreamReader(new 
FileInputStream(expectedFile), "UTF-8"));
+        BufferedReader readerActual =
+                new BufferedReader(new InputStreamReader(new 
FileInputStream(actualFile), "UTF-8"));
+        boolean regex = false;
+        try {
+            if (actualFile.toString().endsWith(".regex")) {
+                runScriptAndCompareWithResultRegex(scriptFile, expectedFile, 
actualFile);
+                return;
+            } else if (actualFile.toString().endsWith(".regexadm")) {
+                runScriptAndCompareWithResultRegexAdm(scriptFile, 
expectedFile, actualFile);
+                return;
+            }
+            String lineExpected, lineActual;
+            int num = 1;
+            while ((lineExpected = readerExpected.readLine()) != null) {
+                lineActual = readerActual.readLine();
+                // Assert.assertEquals(lineExpected, lineActual);
+                if (lineActual == null) {
+                    if (lineExpected.isEmpty()) {
+                        continue;
+                    }
+                    throwLineChanged(scriptFile, lineExpected, "<EOF>", num);
+                }
+
+                // Comparing result equality but ignore "Time"-prefixed 
fields. (for metadata tests.)
+                String[] lineSplitsExpected = lineExpected.split("Time");
+                String[] lineSplitsActual = lineActual.split("Time");
+                if (lineSplitsExpected.length != lineSplitsActual.length) {
+                    throwLineChanged(scriptFile, lineExpected, lineActual, 
num);
+                }
+                if (!equalStrings(lineSplitsExpected[0], lineSplitsActual[0], 
regex)) {
+                    throwLineChanged(scriptFile, lineExpected, lineActual, 
num);
+                }
+
+                for (int i = 1; i < lineSplitsExpected.length; i++) {
+                    String[] splitsByCommaExpected = 
lineSplitsExpected[i].split(",");
+                    String[] splitsByCommaActual = 
lineSplitsActual[i].split(",");
+                    if (splitsByCommaExpected.length != 
splitsByCommaActual.length) {
+                        throwLineChanged(scriptFile, lineExpected, lineActual, 
num);
+                    }
+                    for (int j = 1; j < splitsByCommaExpected.length; j++) {
+                        if (splitsByCommaExpected[j].indexOf("DatasetId") >= 
0) {
+                            // Ignore the field "DatasetId", which is 
different for different runs.
+                            // (for metadata tests)
+                            continue;
+                        }
+                        if (!equalStrings(splitsByCommaExpected[j], 
splitsByCommaActual[j], regex)) {
+                            throwLineChanged(scriptFile, lineExpected, 
lineActual, num);
+                        }
+                    }
+                }
+
+                ++num;
+            }
+            lineActual = readerActual.readLine();
+            if (lineActual != null) {
+                throwLineChanged(scriptFile, "<EOF>", lineActual, num);
+            }
+        } catch (Exception e) {
+            System.err.println("Actual results file: " + 
actualFile.toString());
+            throw e;
+        } finally {
+            readerExpected.close();
+            readerActual.close();
+        }
+
+    }
+
+    private void throwLineChanged(File scriptFile, String lineExpected, String 
lineActual, int num)
+            throws ComparisonException {
+        throw new ComparisonException("Result for " + scriptFile + " changed 
at line " + num + ":\n< "
+                + truncateIfLong(lineExpected) + "\n> " + 
truncateIfLong(lineActual));
+    }
+
+    private String truncateIfLong(String string) {
+        if (string.length() < TRUNCATE_THRESHOLD) {
+            return string;
+        }
+        final StringBuilder truncatedString = new StringBuilder(string);
+        truncatedString.setLength(TRUNCATE_THRESHOLD);
+        truncatedString.append("\n<truncated ")
+                .append(StorageUtil.toHumanReadableSize(string.length() - 
TRUNCATE_THRESHOLD)).append("...>");
+        return truncatedString.toString();
+    }
+
+    private boolean equalStrings(String expected, String actual, boolean 
regexMatch) {
+        String[] rowsExpected = expected.split("\n");
+        String[] rowsActual = actual.split("\n");
+
+        for (int i = 0; i < rowsExpected.length; i++) {
+            String expectedRow = rowsExpected[i];
+            String actualRow = rowsActual[i];
+
+            if (regexMatch) {
+                if (actualRow.matches(expectedRow)) {
+                    continue;
+                }
+            } else if (actualRow.equals(expectedRow)) {
+                continue;
+            }
+
+            String[] expectedFields = expectedRow.split(" ");
+            String[] actualFields = actualRow.split(" ");
+
+            boolean bagEncountered = false;
+            Set<String> expectedBagElements = new HashSet<>();
+            Set<String> actualBagElements = new HashSet<>();
+
+            for (int j = 0; j < expectedFields.length; j++) {
+                if (j >= actualFields.length) {
+                    return false;
+                } else if (expectedFields[j].equals(actualFields[j])) {
+                    bagEncountered = expectedFields[j].equals("{{");
+                    if (expectedFields[j].startsWith("}}")) {
+                        if (regexMatch) {
+                            if (expectedBagElements.size() != 
actualBagElements.size()) {
+                                return false;
+                            }
+                            int[] expectedHits = new 
int[expectedBagElements.size()];
+                            int[] actualHits = new 
int[actualBagElements.size()];
+                            int k = 0;
+                            for (String expectedElement : expectedBagElements) 
{
+                                int l = 0;
+                                for (String actualElement : actualBagElements) 
{
+                                    if 
(actualElement.matches(expectedElement)) {
+                                        expectedHits[k]++;
+                                        actualHits[l]++;
+                                    }
+                                    l++;
+                                }
+                                k++;
+                            }
+                            for (int m = 0; m < expectedHits.length; m++) {
+                                if (expectedHits[m] == 0 || actualHits[m] == 
0) {
+                                    return false;
+                                }
+                            }
+                        } else if 
(!expectedBagElements.equals(actualBagElements)) {
+                            return false;
+                        }
+                        bagEncountered = false;
+                        expectedBagElements.clear();
+                        actualBagElements.clear();
+                    }
+                } else if (expectedFields[j].indexOf('.') < 0) {
+                    if (bagEncountered) {
+                        
expectedBagElements.add(expectedFields[j].replaceAll(",$", ""));
+                        actualBagElements.add(actualFields[j].replaceAll(",$", 
""));
+                        continue;
+                    }
+                    return false;
+                } else {
+                    // If the fields are floating-point numbers, test them
+                    // for equality safely
+                    expectedFields[j] = expectedFields[j].split(",")[0];
+                    actualFields[j] = actualFields[j].split(",")[0];
+                    try {
+                        Double double1 = Double.parseDouble(expectedFields[j]);
+                        Double double2 = Double.parseDouble(actualFields[j]);
+                        float float1 = (float) double1.doubleValue();
+                        float float2 = (float) double2.doubleValue();
+
+                        if (Math.abs(float1 - float2) == 0) {
+                            continue;
+                        } else {
+                            return false;
+                        }
+                    } catch (NumberFormatException ignored) {
+                        // Guess they weren't numbers - must simply not be 
equal
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    public void runScriptAndCompareWithResultRegex(File scriptFile, File 
expectedFile, File actualFile)
+            throws Exception {
+        System.err.println("Expected results file: " + 
expectedFile.toString());
+        String lineExpected, lineActual;
+        try (BufferedReader readerExpected =
+                new BufferedReader(new InputStreamReader(new 
FileInputStream(expectedFile), "UTF-8"));
+                BufferedReader readerActual =
+                        new BufferedReader(new InputStreamReader(new 
FileInputStream(actualFile), "UTF-8"))) {
+            StringBuilder actual = new StringBuilder();
+            while ((lineActual = readerActual.readLine()) != null) {
+                actual.append(lineActual).append('\n');
+            }
+            while ((lineExpected = readerExpected.readLine()) != null) {
+                if ("".equals(lineExpected.trim())) {
+                    continue;
+                }
+                Matcher m = REGEX_LINES_PATTERN.matcher(lineExpected);
+                if (!m.matches()) {
+                    throw new IllegalArgumentException(
+                            "Each line of regex file must conform to: 
[-]/regex/[flags]: " + expectedFile);
+                }
+                String negateStr = m.group(1);
+                String expression = m.group(2);
+                String flagStr = m.group(3);
+                boolean negate = "-".equals(negateStr);
+                int flags = Pattern.MULTILINE;
+                if (flagStr.contains("m")) {
+                    flags |= Pattern.DOTALL;
+                }
+                if (flagStr.contains("i")) {
+                    flags |= Pattern.CASE_INSENSITIVE;
+                }
+                Pattern linePattern = Pattern.compile(expression, flags);
+                boolean match = linePattern.matcher(actual).find();
+                if (match && !negate || negate && !match) {
+                    continue;
+                }
+                throw new Exception(
+                        "Result for " + scriptFile + ": expected pattern '" + 
expression + "' not found in result.");
+            }
+        } catch (Exception e) {
+            System.err.println("Actual results file: " + 
actualFile.toString());
+            throw e;
+        }
+
+    }
+
+    public void runScriptAndCompareWithResultRegexAdm(File scriptFile, File 
expectedFile, File actualFile)
+            throws Exception {
+        StringWriter actual = new StringWriter();
+        StringWriter expected = new StringWriter();
+        IOUtils.copy(new FileInputStream(actualFile), actual, 
StandardCharsets.UTF_8);
+        IOUtils.copy(new FileInputStream(expectedFile), expected, 
StandardCharsets.UTF_8);
+        Pattern pattern = Pattern.compile(expected.toString(), Pattern.DOTALL 
| Pattern.MULTILINE);
+        if (!pattern.matcher(actual.toString()).matches()) {
+            throw new Exception("Result for " + scriptFile + ": actual file 
did not match expected result");
+        }
+    }
+
+    // For tests where you simply want the byte-for-byte output.
+    private static void writeOutputToFile(File actualFile, InputStream 
resultStream) throws Exception {
+        final File parentDir = actualFile.getParentFile();
+        if (!parentDir.isDirectory()) {
+            if (parentDir.exists()) {
+                LOGGER.warning("Actual file parent \"" + parentDir + "\" 
exists but is not a directory");
+            } else if (!parentDir.mkdirs()) {
+                LOGGER.warning("Unable to create actual file parent dir: " + 
parentDir);
+            }
+        }
+        try (FileOutputStream out = new FileOutputStream(actualFile)) {
+            IOUtils.copy(resultStream, out);
+        }
+    }
+
+    protected HttpResponse executeAndCheckHttpRequest(HttpUriRequest method) 
throws Exception {
+        return checkResponse(executeHttpRequest(method));
+    }
+
+    protected HttpResponse executeHttpRequest(HttpUriRequest method) throws 
Exception {
+        HttpClient client = 
HttpClients.custom().setRetryHandler(StandardHttpRequestRetryHandler.INSTANCE).build();
+        try {
+            return client.execute(method);
+        } catch (Exception e) {
+            GlobalConfig.ASTERIX_LOGGER.log(Level.SEVERE, e.getMessage(), e);
+            e.printStackTrace();
+            throw e;
+        }
+    }
+
+    protected HttpResponse checkResponse(HttpResponse httpResponse) throws 
Exception {
+        if (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+            String errorBody = EntityUtils.toString(httpResponse.getEntity());
+            String exceptionMsg;
+            try {
+                // First try to parse the response for a JSON error response.
+
+                ObjectMapper om = new ObjectMapper();
+                JsonNode result = om.readTree(errorBody);
+                String[] errors = { result.get("error-code").asText(), 
result.get("summary").asText(),
+                        result.get("stacktrace").asText() };
+                GlobalConfig.ASTERIX_LOGGER.log(Level.SEVERE, errors[2]);
+                exceptionMsg = "HTTP operation failed: " + errors[0] + 
"\nSTATUS LINE: " + httpResponse.getStatusLine()
+                        + "\nSUMMARY: " + errors[1] + "\nSTACKTRACE: " + 
errors[2];
+            } catch (Exception e) {
+                // whoops, not JSON (e.g. 404) - just include the body
+                GlobalConfig.ASTERIX_LOGGER.log(Level.SEVERE, errorBody);
+                exceptionMsg = "HTTP operation failed:" + "\nSTATUS LINE: " + 
httpResponse.getStatusLine()
+                        + "\nERROR_BODY: " + errorBody;
+            }
+            throw new Exception(exceptionMsg);
+        }
+        return httpResponse;
+    }
+
+    public InputStream executeQuery(String str, OutputFormat fmt, URI uri, 
List<CompilationUnit.Parameter> params)
+            throws Exception {
+        HttpUriRequest method = constructHttpMethod(str, uri, "query", false, 
params);
+        // Set accepted output response type
+        method.setHeader("Accept", fmt.mimeType());
+        HttpResponse response = executeAndCheckHttpRequest(method);
+        return response.getEntity().getContent();
+    }
+
+    public InputStream executeQueryService(String str, URI uri) throws 
Exception {
+        return executeQueryService(str, OutputFormat.CLEAN_JSON, uri, new 
ArrayList<>(), false);
+    }
+
+    public InputStream executeQueryService(String str, OutputFormat fmt, URI 
uri,
+            List<CompilationUnit.Parameter> params, boolean jsonEncoded) 
throws Exception {
+        setParam(params, "format", fmt.mimeType());
+        HttpUriRequest method = jsonEncoded ? constructPostMethodJson(str, 
uri, "statement", params)
+                : constructPostMethodUrl(str, uri, "statement", params);
+        // Set accepted output response type
+        method.setHeader("Accept", OutputFormat.CLEAN_JSON.mimeType());
+        HttpResponse response = executeHttpRequest(method);
+        return response.getEntity().getContent();
+    }
+
+    protected void setParam(List<CompilationUnit.Parameter> params, String 
name, String value) {
+        for (CompilationUnit.Parameter param : params) {
+            if (name.equals(param.getName())) {
+                param.setValue(value);
+                return;
+            }
+        }
+        CompilationUnit.Parameter formatParam = new 
CompilationUnit.Parameter();
+        formatParam.setName(name);
+        formatParam.setValue(value);
+        params.add(formatParam);
+    }
+
+    private List<CompilationUnit.Parameter> injectStatement(String statement, 
String stmtParamName,
+            List<CompilationUnit.Parameter> otherParams) {
+        CompilationUnit.Parameter stmtParam = new CompilationUnit.Parameter();
+        stmtParam.setName(stmtParamName);
+        stmtParam.setValue(statement);
+        List<CompilationUnit.Parameter> params = new ArrayList<>(otherParams);
+        params.add(stmtParam);
+        return params;
+    }
+
+    private HttpUriRequest constructHttpMethod(String statement, URI uri, 
String stmtParam, boolean postStmtAsParam,
+            List<CompilationUnit.Parameter> otherParams) throws 
URISyntaxException {
+        if (statement.length() + uri.toString().length() < MAX_URL_LENGTH) {
+            // Use GET for small-ish queries
+            return constructGetMethod(uri, injectStatement(statement, 
stmtParam, otherParams));
+        } else {
+            // Use POST for bigger ones to avoid 413 FULL_HEAD
+            String stmtParamName = (postStmtAsParam ? stmtParam : null);
+            return constructPostMethodUrl(statement, uri, stmtParamName, 
otherParams);
+        }
+    }
+
+    private HttpUriRequest constructGetMethod(URI endpoint, 
List<CompilationUnit.Parameter> params) {
+        RequestBuilder builder = RequestBuilder.get(endpoint);
+        for (CompilationUnit.Parameter param : params) {
+            builder.addParameter(param.getName(), param.getValue());
+        }
+        builder.setCharset(StandardCharsets.UTF_8);
+        return builder.build();
+    }
+
+    private HttpUriRequest constructGetMethod(URI endpoint, OutputFormat fmt, 
List<CompilationUnit.Parameter> params) {
+        HttpUriRequest method = constructGetMethod(endpoint, params);
+        // Set accepted output response type
+        method.setHeader("Accept", fmt.mimeType());
+        return method;
+    }
+
+    private HttpUriRequest constructPostMethod(URI uri, 
List<CompilationUnit.Parameter> params) {
+        RequestBuilder builder = RequestBuilder.post(uri);
+        for (CompilationUnit.Parameter param : params) {
+            builder.addParameter(param.getName(), param.getValue());
+        }
+        builder.setCharset(StandardCharsets.UTF_8);
+        return builder.build();
+    }
+
+    private HttpUriRequest constructPostMethod(URI uri, OutputFormat fmt, 
List<CompilationUnit.Parameter> params) {
+        HttpUriRequest method = constructPostMethod(uri, params);
+        // Set accepted output response type
+        method.setHeader("Accept", fmt.mimeType());
+        return method;
+    }
+
+    protected HttpUriRequest constructPostMethodUrl(String statement, URI uri, 
String stmtParam,
+            List<CompilationUnit.Parameter> otherParams) {
+        RequestBuilder builder = RequestBuilder.post(uri);
+        if (stmtParam != null) {
+            for (CompilationUnit.Parameter param : injectStatement(statement, 
stmtParam, otherParams)) {
+                builder.addParameter(param.getName(), param.getValue());
+            }
+            builder.addParameter(stmtParam, statement);
+        } else {
+            // this seems pretty bad - we should probably fix the API and not 
the client
+            builder.setEntity(new StringEntity(statement, 
StandardCharsets.UTF_8));
+        }
+        builder.setCharset(StandardCharsets.UTF_8);
+        return builder.build();
+    }
+
+    protected HttpUriRequest constructPostMethodJson(String statement, URI 
uri, String stmtParam,
+            List<CompilationUnit.Parameter> otherParams) {
+        if (stmtParam == null) {
+            throw new NullPointerException("Statement parameter required.");
+        }
+        RequestBuilder builder = RequestBuilder.post(uri);
+        ObjectMapper om = new ObjectMapper();
+        ObjectNode content = om.createObjectNode();
+        for (CompilationUnit.Parameter param : injectStatement(statement, 
stmtParam, otherParams)) {
+            content.put(param.getName(), param.getValue());
+        }
+        try {
+            builder.setEntity(new StringEntity(om.writeValueAsString(content), 
ContentType.APPLICATION_JSON));
+        } catch (JsonProcessingException e) {
+            e.printStackTrace();
+        }
+        builder.setCharset(StandardCharsets.UTF_8);
+        return builder.build();
+    }
+
+    public InputStream executeJSONGet(OutputFormat fmt, URI uri) throws 
Exception {
+        HttpUriRequest request = constructGetMethod(uri, fmt, new 
ArrayList<>());
+        HttpResponse response = executeAndCheckHttpRequest(request);
+        return response.getEntity().getContent();
+    }
+
+    public InputStream executeJSONPost(OutputFormat fmt, URI uri) throws 
Exception {
+        HttpUriRequest request = constructPostMethod(uri, fmt, new 
ArrayList<>());
+        HttpResponse response = executeAndCheckHttpRequest(request);
+        return response.getEntity().getContent();
+    }
+
+    // To execute Update statements
+    // Insert and Delete statements are executed here
+    public void executeUpdate(String str, URI uri) throws Exception {
+        // Create a method instance.
+        HttpUriRequest request =
+                RequestBuilder.post(uri).setEntity(new StringEntity(str, 
StandardCharsets.UTF_8)).build();
+
+        // Execute the method.
+        executeAndCheckHttpRequest(request);
+    }
+
+    // Executes AQL in either async or async-defer mode.
+    public InputStream executeAnyAQLAsync(String statement, boolean defer, 
OutputFormat fmt, URI uri,
+            Map<String, Object> variableCtx) throws Exception {
+        // Create a method instance.
+        HttpUriRequest request =
+                RequestBuilder.post(uri).addParameter("mode", defer ? 
"asynchronous-deferred" : "asynchronous")
+                        .setEntity(new StringEntity(statement, 
StandardCharsets.UTF_8))
+                        .setHeader("Accept", fmt.mimeType()).build();
+
+        String handleVar = getHandleVariable(statement);
+
+        HttpResponse response = executeAndCheckHttpRequest(request);
+        InputStream resultStream = response.getEntity().getContent();
+        String handle = IOUtils.toString(resultStream, "UTF-8");
+
+        if (handleVar != null) {
+            variableCtx.put(handleVar, handle);
+            return resultStream;
+        }
+        return null;
+    }
+
+    // To execute DDL and Update statements
+    // create type statement
+    // create dataset statement
+    // create index statement
+    // create dataverse statement
+    // create function statement
+    public void executeDDL(String str, URI uri) throws Exception {
+        // Create a method instance.
+        HttpUriRequest request =
+                RequestBuilder.post(uri).setEntity(new StringEntity(str, 
StandardCharsets.UTF_8)).build();
+
+        // Execute the method.
+        executeAndCheckHttpRequest(request);
+    }
+
+    // Method that reads a DDL/Update/Query File
+    // and returns the contents as a string
+    // This string is later passed to REST API for execution.
+    public String readTestFile(File testFile) throws Exception {
+        BufferedReader reader =
+                new BufferedReader(new InputStreamReader(new 
FileInputStream(testFile), StandardCharsets.UTF_8));
+        String line;
+        StringBuilder stringBuilder = new StringBuilder();
+        String ls = System.getProperty("line.separator");
+        while ((line = reader.readLine()) != null) {
+            stringBuilder.append(line);
+            stringBuilder.append(ls);
+        }
+        reader.close();
+        return stringBuilder.toString();
+    }
+
+    public static void executeManagixCommand(String command) throws 
ClassNotFoundException, NoSuchMethodException,
+            SecurityException, IllegalAccessException, 
IllegalArgumentException, InvocationTargetException {
+        if (managixExecuteMethod == null) {
+            Class<?> clazz = 
Class.forName("org.apache.asterix.installer.test.AsterixInstallerIntegrationUtil");
+            managixExecuteMethod = clazz.getMethod("executeCommand", 
String.class);
+        }
+        managixExecuteMethod.invoke(null, command);
+    }
+
+    public static String executeScript(ProcessBuilder pb, String scriptPath) 
throws Exception {
+        LOGGER.info("Executing script: " + scriptPath);
+        pb.command(scriptPath);
+        Process p = pb.start();
+        return getProcessOutput(p);
+    }
+
+    private static String executeVagrantScript(ProcessBuilder pb, String node, 
String scriptName) throws Exception {
+        pb.command("vagrant", "ssh", node, "--", 
pb.environment().get("SCRIPT_HOME") + scriptName);
+        Process p = pb.start();
+        p.waitFor();
+        InputStream input = p.getInputStream();
+        return IOUtils.toString(input, StandardCharsets.UTF_8.name());
+    }
+
+    private static String executeVagrantManagix(ProcessBuilder pb, String 
command) throws Exception {
+        pb.command("vagrant", "ssh", "cc", "--", 
pb.environment().get("MANAGIX_HOME") + command);
+        Process p = pb.start();
+        p.waitFor();
+        InputStream input = p.getInputStream();
+        return IOUtils.toString(input, StandardCharsets.UTF_8.name());
+    }
+
+    private static String getScriptPath(String queryPath, String 
scriptBasePath, String scriptFileName) {
+        String targetWord = "queries" + File.separator;
+        int targetWordSize = targetWord.lastIndexOf(File.separator);
+        int beginIndex = queryPath.lastIndexOf(targetWord) + targetWordSize;
+        int endIndex = queryPath.lastIndexOf(File.separator);
+        String prefix = queryPath.substring(beginIndex, endIndex);
+        return scriptBasePath + prefix + File.separator + scriptFileName;
+    }
+
+    private static String getProcessOutput(Process p) throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Future<Integer> future =
+                Executors.newSingleThreadExecutor().submit(() -> 
IOUtils.copy(p.getInputStream(), new OutputStream() {
+                    @Override
+                    public void write(int b) throws IOException {
+                        baos.write(b);
+                        System.out.write(b);
+                    }
+
+                    @Override
+                    public void flush() throws IOException {
+                        baos.flush();
+                        System.out.flush();
+                    }
+
+                    @Override
+                    public void close() throws IOException {
+                        baos.close();
+                        System.out.close();
+                    }
+                }));
+        p.waitFor();
+        future.get();
+        ByteArrayInputStream bisIn = new 
ByteArrayInputStream(baos.toByteArray());
+        StringWriter writerIn = new StringWriter();
+        IOUtils.copy(bisIn, writerIn, StandardCharsets.UTF_8);
+        StringWriter writerErr = new StringWriter();
+        IOUtils.copy(p.getErrorStream(), writerErr, StandardCharsets.UTF_8);
+
+        StringBuffer stdOut = writerIn.getBuffer();
+        if (writerErr.getBuffer().length() > 0) {
+            StringBuilder sbErr = new StringBuilder();
+            sbErr.append("script execution failed - error message:\n" + 
"-------------------------------------------\n"
+                    + "stdout: ").append(stdOut).append("\nstderr: 
").append(writerErr.getBuffer())
+                    .append("-------------------------------------------");
+            LOGGER.info(sbErr.toString());
+            throw new Exception(sbErr.toString());
+        }
+        return stdOut.toString();
+    }
+
+    public void executeTest(String actualPath, TestCaseContext testCaseCtx, 
ProcessBuilder pb,
+            boolean isDmlRecoveryTest) throws Exception {
+        executeTest(actualPath, testCaseCtx, pb, isDmlRecoveryTest, null);
+    }
+
+    public void executeTestFile(TestCaseContext testCaseCtx, TestFileContext 
ctx, Map<String, Object> variableCtx,
+            String statement, boolean isDmlRecoveryTest, ProcessBuilder pb, 
CompilationUnit cUnit,
+            MutableInt queryCount, List<TestFileContext> 
expectedResultFileCtxs, File testFile, String actualPath)
+            throws Exception {
+        File qbcFile;
+        boolean failed = false;
+        File expectedResultFile;
+        switch (ctx.getType()) {
+            case "ddl":
+                if (ctx.getFile().getName().endsWith("aql")) {
+                    executeDDL(statement, getEndpoint(Servlets.AQL_DDL));
+                } else {
+                    InputStream resultStream =
+                            executeQueryService(statement, 
getEndpoint(Servlets.QUERY_SERVICE));
+                    ResultExtractor.extract(resultStream);
+                }
+                break;
+            case "update":
+                // isDmlRecoveryTest: set IP address
+                if (isDmlRecoveryTest && statement.contains("nc1://")) {
+                    statement = statement.replaceAll("nc1://", 
"127.0.0.1://../../../../../../asterix-app/");
+                }
+                if (ctx.getFile().getName().endsWith("aql")) {
+                    executeUpdate(statement, getEndpoint(Servlets.AQL_UPDATE));
+                } else {
+                    InputStream resultStream =
+                            executeQueryService(statement, 
getEndpoint(Servlets.QUERY_SERVICE));
+                    ResultExtractor.extract(resultStream);
+                }
+                break;
+            case "pollget":
+            case "pollquery":
+                // polltimeoutsecs=nnn, polldelaysecs=nnn
+                int timeoutSecs = getTimeoutSecs(statement);
+                int retryDelaySecs = getRetryDelaySecs(statement);
+                long startTime = System.currentTimeMillis();
+                long limitTime = startTime + 
TimeUnit.SECONDS.toMillis(timeoutSecs);
+                ctx.setType(ctx.getType().substring("poll".length()));
+                Exception finalException;
+                LOGGER.fine("polling for up to " + timeoutSecs + " seconds w/ 
" + retryDelaySecs + " second(s) delay");
+                while (true) {
+                    try {
+                        executeTestFile(testCaseCtx, ctx, variableCtx, 
statement, isDmlRecoveryTest, pb, cUnit,
+                                queryCount, expectedResultFileCtxs, testFile, 
actualPath);
+                        finalException = null;
+                        break;
+                    } catch (Exception e) {
+                        if ((System.currentTimeMillis() > limitTime)) {
+                            finalException = e;
+                            break;
+                        }
+                        LOGGER.fine("sleeping " + retryDelaySecs + " second(s) 
before polling again");
+                        
Thread.sleep(TimeUnit.SECONDS.toMillis(retryDelaySecs));
+                    }
+                }
+                if (finalException != null) {
+                    throw new Exception("Poll limit (" + timeoutSecs + "s) 
exceeded without obtaining expected result",
+                            finalException);
+                }
+                break;
+            case "query":
+            case "async":
+            case "deferred":
+                // isDmlRecoveryTest: insert Crash and Recovery
+                if (isDmlRecoveryTest) {
+                    executeScript(pb, pb.environment().get("SCRIPT_HOME") + 
File.separator + "dml_recovery"
+                            + File.separator + "kill_cc_and_nc.sh");
+                    executeScript(pb, pb.environment().get("SCRIPT_HOME") + 
File.separator + "dml_recovery"
+                            + File.separator + "stop_and_start.sh");
+                }
+                InputStream resultStream = null;
+                OutputFormat fmt = OutputFormat.forCompilationUnit(cUnit);
+                final String reqType = ctx.getType();
+                final List<CompilationUnit.Parameter> params = 
cUnit.getParameter();
+                if (ctx.getFile().getName().endsWith("aql")) {
+                    if (reqType.equalsIgnoreCase("query")) {
+                        resultStream = executeQuery(statement, fmt, 
getEndpoint(Servlets.AQL_QUERY), params);
+                    } else {
+                        final URI endpoint = getEndpoint(Servlets.AQL);
+                        if (reqType.equalsIgnoreCase("async")) {
+                            resultStream = executeAnyAQLAsync(statement, 
false, fmt, endpoint, variableCtx);
+                        } else if (reqType.equalsIgnoreCase("deferred")) {
+                            resultStream = executeAnyAQLAsync(statement, true, 
fmt, endpoint, variableCtx);
+                        }
+                        Assert.assertNotNull("no handle for " + reqType + " 
test " + testFile.toString(),
+                                resultStream);
+                    }
+                } else {
+                    String delivery = DELIVERY_IMMEDIATE;
+                    if (reqType.equalsIgnoreCase("async")) {
+                        delivery = DELIVERY_ASYNC;
+                    } else if (reqType.equalsIgnoreCase("deferred")) {
+                        delivery = DELIVERY_DEFERRED;
+                    }
+                    final URI uri = getEndpoint(Servlets.QUERY_SERVICE);
+                    if (DELIVERY_IMMEDIATE.equals(delivery)) {
+                        resultStream = executeQueryService(statement, fmt, 
uri, params, true);
+                        resultStream = ResultExtractor.extract(resultStream);
+                    } else {
+                        String handleVar = getHandleVariable(statement);
+                        setParam(params, "mode", delivery);
+                        resultStream = executeQueryService(statement, fmt, 
uri, params, true);
+                        String handle = 
ResultExtractor.extractHandle(resultStream);
+                        Assert.assertNotNull("no handle for " + reqType + " 
test " + testFile.toString(), handleVar);
+                        variableCtx.put(handleVar, handle);
+                    }
+                }
+                if (queryCount.intValue() >= expectedResultFileCtxs.size()) {
+                    Assert.fail("no result file for " + testFile.toString() + 
"; queryCount: " + queryCount
+                            + ", filectxs.size: " + 
expectedResultFileCtxs.size());
+                }
+                expectedResultFile = 
expectedResultFileCtxs.get(queryCount.intValue()).getFile();
+
+                File actualResultFile =
+                        testCaseCtx.getActualResultFile(cUnit, 
expectedResultFile, new File(actualPath));
+                writeOutputToFile(actualResultFile, resultStream);
+
+                runScriptAndCompareWithResult(testFile, new 
PrintWriter(System.err), expectedResultFile,
+                        actualResultFile);
+                queryCount.increment();
+
+                // Deletes the matched result file.
+                actualResultFile.getParentFile().delete();
+                break;
+            case "mgx":
+                executeManagixCommand(statement);
+                break;
+            case "txnqbc": // qbc represents query before crash
+                resultStream = executeQuery(statement, 
OutputFormat.forCompilationUnit(cUnit),
+                        getEndpoint(Servlets.AQL_QUERY), cUnit.getParameter());
+                qbcFile = getTestCaseQueryBeforeCrashFile(actualPath, 
testCaseCtx, cUnit);
+                writeOutputToFile(qbcFile, resultStream);
+                break;
+            case "txnqar": // qar represents query after recovery
+                resultStream = executeQuery(statement, 
OutputFormat.forCompilationUnit(cUnit),
+                        getEndpoint(Servlets.AQL_QUERY), cUnit.getParameter());
+                File qarFile = new File(actualPath + File.separator
+                        + 
testCaseCtx.getTestCase().getFilePath().replace(File.separator, "_") + "_" + 
cUnit.getName()
+                        + "_qar.adm");
+                writeOutputToFile(qarFile, resultStream);
+                qbcFile = getTestCaseQueryBeforeCrashFile(actualPath, 
testCaseCtx, cUnit);
+                runScriptAndCompareWithResult(testFile, new 
PrintWriter(System.err), qbcFile, qarFile);
+                break;
+            case "txneu": // eu represents erroneous update
+                try {
+                    executeUpdate(statement, getEndpoint(Servlets.AQL_UPDATE));
+                } catch (Exception e) {
+                    // An exception is expected.
+                    failed = true;
+                    e.printStackTrace();
+                }
+                if (!failed) {
+                    throw new Exception("Test \"" + testFile + "\" FAILED!\n  
An exception" + "is expected.");
+                }
+                System.err.println("...but that was expected.");
+                break;
+            case "script":
+                try {
+                    String output = executeScript(pb, 
getScriptPath(testFile.getAbsolutePath(),
+                            pb.environment().get("SCRIPT_HOME"), 
statement.trim()));
+                    if (output.contains("ERROR")) {
+                        throw new Exception(output);
+                    }
+                } catch (Exception e) {
+                    throw new Exception("Test \"" + testFile + "\" FAILED!\n", 
e);
+                }
+                break;
+            case "sleep":
+                String[] lines = statement.split("\n");
+                Thread.sleep(Long.parseLong(lines[lines.length - 1].trim()));
+                break;
+            case "errddl": // a ddlquery that expects error
+                try {
+                    executeDDL(statement, getEndpoint(Servlets.AQL_DDL));
+                } catch (Exception e) {
+                    // expected error happens
+                    failed = true;
+                    e.printStackTrace();
+                }
+                if (!failed) {
+                    throw new Exception("Test \"" + testFile + "\" FAILED!\n  
An exception is expected.");
+                }
+                System.err.println("...but that was expected.");
+                break;
+            case "vscript": // a script that will be executed on a vagrant 
virtual node
+                try {
+                    String[] command = statement.trim().split(" ");
+                    if (command.length != 2) {
+                        throw new Exception("invalid vagrant script format");
+                    }
+                    String nodeId = command[0];
+                    String scriptName = command[1];
+                    String output = executeVagrantScript(pb, nodeId, 
scriptName);
+                    if (output.contains("ERROR")) {
+                        throw new Exception(output);
+                    }
+                } catch (Exception e) {
+                    throw new Exception("Test \"" + testFile + "\" FAILED!\n", 
e);
+                }
+                break;
+            case "vmgx": // a managix command that will be executed on vagrant 
cc node
+                String output = executeVagrantManagix(pb, statement);
+                if (output.contains("ERROR")) {
+                    throw new Exception(output);
+                }
+                break;
+            case "get":
+            case "post":
+                if (!"http".equals(ctx.extension())) {
+                    throw new IllegalArgumentException(
+                            "Unexpected format for method " + ctx.getType() + 
": " + ctx.extension());
+                }
+                fmt = OutputFormat.forCompilationUnit(cUnit);
+                final String trimmedPathAndQuery = 
stripLineComments(stripJavaComments(statement)).trim();
+                final String variablesReplaced = 
replaceVarRef(trimmedPathAndQuery, variableCtx);
+                resultStream = executeHttp(ctx.getType(), variablesReplaced, 
fmt);
+                expectedResultFile = 
expectedResultFileCtxs.get(queryCount.intValue()).getFile();
+                actualResultFile = testCaseCtx.getActualResultFile(cUnit, 
expectedResultFile, new File(actualPath));
+                writeOutputToFile(actualResultFile, resultStream);
+                runScriptAndCompareWithResult(testFile, new 
PrintWriter(System.err), expectedResultFile,
+                        actualResultFile);
+                queryCount.increment();
+                break;
+            case "server": // (start <test server name> <port>
+                               // [<arg1>][<arg2>][<arg3>]...|stop 
(<port>|all))
+                try {
+                    lines = statement.trim().split("\n");
+                    String[] command = lines[lines.length - 1].trim().split(" 
");
+                    if (command.length < 2) {
+                        throw new Exception("invalid server command format. 
expected format ="
+                                + " (start <test server name> <port> 
[<arg1>][<arg2>][<arg3>]"
+                                + "...|stop (<port>|all))");
+                    }
+                    String action = command[0];
+                    if (action.equals("start")) {
+                        if (command.length < 3) {
+                            throw new Exception("invalid server start command. 
expected format ="
+                                    + " (start <test server name> <port> 
[<arg1>][<arg2>][<arg3>]...");
+                        }
+                        String name = command[1];
+                        Integer port = new Integer(command[2]);
+                        if (runningTestServers.containsKey(port)) {
+                            throw new Exception("server with port " + port + " 
is already running");
+                        }
+                        ITestServer server = 
TestServerProvider.createTestServer(name, port);
+                        server.configure(Arrays.copyOfRange(command, 3, 
command.length));
+                        server.start();
+                        runningTestServers.put(port, server);
+                    } else if (action.equals("stop")) {
+                        String target = command[1];
+                        if (target.equals("all")) {
+                            for (ITestServer server : 
runningTestServers.values()) {
+                                server.stop();
+                            }
+                            runningTestServers.clear();
+                        } else {
+                            Integer port = new Integer(command[1]);
+                            ITestServer server = runningTestServers.get(port);
+                            if (server == null) {
+                                throw new Exception("no server is listening to 
port " + port);
+                            }
+                            server.stop();
+                            runningTestServers.remove(port);
+                        }
+                    } else {
+                        throw new Exception("unknown server action");
+                    }
+                } catch (Exception e) {
+                    throw new Exception("Test \"" + testFile + "\" FAILED!\n", 
e);
+                }
+                break;
+            case "lib": // expected format <dataverse-name> <library-name>
+                            // <library-directory>
+                        // TODO: make this case work well with entity names 
containing spaces by
+                        // looking for \"
+                lines = statement.split("\n");
+                String lastLine = lines[lines.length - 1];
+                String[] command = lastLine.trim().split(" ");
+                if (command.length < 3) {
+                    throw new Exception("invalid library format");
+                }
+                String dataverse = command[1];
+                String library = command[2];
+                switch (command[0]) {
+                    case "install":
+                        if (command.length != 4) {
+                            throw new Exception("invalid library format");
+                        }
+                        String libPath = command[3];
+                        librarian.install(dataverse, library, libPath);
+                        break;
+                    case "uninstall":
+                        if (command.length != 3) {
+                            throw new Exception("invalid library format");
+                        }
+                        librarian.uninstall(dataverse, library);
+                        break;
+                    default:
+                        throw new Exception("invalid library format");
+                }
+                break;
+            case "node":
+                command = stripJavaComments(statement).trim().split(" ");
+                String commandType = command[0];
+                String nodeId = command[1];
+                if (commandType.equals("kill")) {
+                    killNC(nodeId, cUnit);
+                }
+                break;
+            default:
+                throw new IllegalArgumentException("No statements of type " + 
ctx.getType());
+        }
+    }
+
+    protected int getTimeoutSecs(String statement) {
+        final Matcher timeoutMatcher = POLL_TIMEOUT_PATTERN.matcher(statement);
+        if (timeoutMatcher.find()) {
+            return Integer.parseInt(timeoutMatcher.group(1));
+        } else {
+            throw new IllegalArgumentException("ERROR: polltimeoutsecs=nnn 
must be present in poll file");
+        }
+    }
+
+    protected static int getRetryDelaySecs(String statement) {
+        final Matcher retryDelayMatcher = 
POLL_DELAY_PATTERN.matcher(statement);
+        return retryDelayMatcher.find() ? 
Integer.parseInt(retryDelayMatcher.group(1)) : 1;
+    }
+
+    protected static String getHandleVariable(String statement) {
+        final Matcher handleVariableMatcher = 
HANDLE_VARIABLE_PATTERN.matcher(statement);
+        return handleVariableMatcher.find() ? handleVariableMatcher.group(1) : 
null;
+    }
+
+    protected static String replaceVarRef(String statement, Map<String, 
Object> variableCtx) {
+        String tmpStmt = statement;
+        Matcher variableReferenceMatcher = 
VARIABLE_REF_PATTERN.matcher(tmpStmt);
+        while (variableReferenceMatcher.find()) {
+            String var = variableReferenceMatcher.group(1);
+            Object value = variableCtx.get(var);
+            Assert.assertNotNull("No value for variable reference $" + var, 
value);
+            tmpStmt = tmpStmt.replace("$" + var, String.valueOf(value));
+            variableReferenceMatcher = VARIABLE_REF_PATTERN.matcher(tmpStmt);
+        }
+        return tmpStmt;
+    }
+
+    protected InputStream executeHttp(String ctxType, String endpoint, 
OutputFormat fmt) throws Exception {
+        String[] split = endpoint.split("\\?");
+        URI uri = new URI("http", null, host, port, split[0], split.length > 1 
? split[1] : null, null);
+        switch (ctxType) {
+            case "get":
+                return executeJSONGet(fmt, uri);
+            case "post":
+                return executeJSONPost(fmt, uri);
+            default:
+                throw new AssertionError("Not implemented: " + ctxType);
+        }
+    }
+
+    private void killNC(String nodeId, CompilationUnit cUnit) throws Exception 
{
+        //get node process id
+        OutputFormat fmt = OutputFormat.forCompilationUnit(cUnit);
+        String endpoint = "/admin/cluster/node/" + nodeId + "/config";
+        InputStream executeJSONGet = executeJSONGet(fmt, new URI("http", null, 
host, port, endpoint, null, null));
+        StringWriter actual = new StringWriter();
+        IOUtils.copy(executeJSONGet, actual, StandardCharsets.UTF_8);
+        String config = actual.toString();
+        int nodePid = new ObjectMapper().readValue(config, 
ObjectNode.class).get("pid").asInt();
+        if (nodePid <= 1) {
+            throw new IllegalArgumentException("Could not retrieve node pid 
from admin API");
+        }
+        ProcessBuilder pb = new ProcessBuilder("kill", "-9", 
Integer.toString(nodePid));
+        pb.start().waitFor();
+        // Delete NC's transaction logs to re-initialize it as a new NC.
+        deleteNCTxnLogs(nodeId, cUnit);
+    }
+
+    private void deleteNCTxnLogs(String nodeId, CompilationUnit cUnit) throws 
Exception {
+        OutputFormat fmt = OutputFormat.forCompilationUnit(cUnit);
+        String endpoint = "/admin/cluster";
+        InputStream executeJSONGet = executeJSONGet(fmt, new URI("http://"; + 
host + ":" + port + endpoint));
+        StringWriter actual = new StringWriter();
+        IOUtils.copy(executeJSONGet, actual, StandardCharsets.UTF_8);
+        String config = actual.toString();
+        ObjectMapper om = new ObjectMapper();
+        String logDir = 
om.readTree(config).findPath("transaction.log.dirs").get(nodeId).asText();
+        ProcessBuilder pb = new ProcessBuilder("rm", "-rf", logDir);
+        pb.start().waitFor();
+    }
+
+    public void executeTest(String actualPath, TestCaseContext testCaseCtx, 
ProcessBuilder pb,
+            boolean isDmlRecoveryTest, TestGroup failedGroup) throws Exception 
{
+        MutableInt queryCount = new MutableInt(0);
+        int numOfErrors = 0;
+        int numOfFiles = 0;
+        List<CompilationUnit> cUnits = 
testCaseCtx.getTestCase().getCompilationUnit();
+        for (CompilationUnit cUnit : cUnits) {
+            LOGGER.info(
+                    "Starting [TEST]: " + 
testCaseCtx.getTestCase().getFilePath() + "/" + cUnit.getName() + " ... ");
+            Map<String, Object> variableCtx = new HashMap<>();
+            List<TestFileContext> testFileCtxs = 
testCaseCtx.getTestFiles(cUnit);
+            List<TestFileContext> expectedResultFileCtxs = 
testCaseCtx.getExpectedResultFiles(cUnit);
+            for (TestFileContext ctx : testFileCtxs) {
+                numOfFiles++;
+                final File testFile = ctx.getFile();
+                final String statement = readTestFile(testFile);
+                try {
+                    executeTestFile(testCaseCtx, ctx, variableCtx, statement, 
isDmlRecoveryTest, pb, cUnit, queryCount,
+                            expectedResultFileCtxs, testFile, actualPath);
+                } catch (Exception e) {
+                    System.err.println("testFile " + testFile.toString() + " 
raised an exception: " + e);
+                    boolean unExpectedFailure = false;
+                    numOfErrors++;
+                    String expectedError = null;
+                    if (cUnit.getExpectedError().size() < numOfErrors) {
+                        unExpectedFailure = true;
+                    } else {
+                        // Get the expected exception
+                        expectedError = 
cUnit.getExpectedError().get(numOfErrors - 1);
+                        if (e.toString().contains(expectedError)) {
+                            System.err.println("...but that was expected.");
+                        } else {
+                            unExpectedFailure = true;
+                        }
+                    }
+                    if (unExpectedFailure) {
+                        e.printStackTrace();
+                        System.err.println("...Unexpected!");
+                        if (expectedError != null) {
+                            System.err.println("Expected to find the following 
in error text:\n+++++\n" + expectedError
+                                    + "\n+++++");
+                        }
+                        if (failedGroup != null) {
+                            
failedGroup.getTestCase().add(testCaseCtx.getTestCase());
+                        }
+                        throw new Exception("Test \"" + testFile + "\" 
FAILED!", e);
+                    }
+                } finally {
+                    if (numOfFiles == testFileCtxs.size() && numOfErrors < 
cUnit.getExpectedError().size()) {
+                        System.err.println("...Unexpected!");
+                        Exception e = new Exception(
+                                "Test \"" + cUnit.getName() + "\" 
FAILED!\nExpected error was not thrown...");
+                        e.printStackTrace();
+                        throw e;
+                    } else if (numOfFiles == testFileCtxs.size()) {
+                        LOGGER.info("[TEST]: " + 
testCaseCtx.getTestCase().getFilePath() + "/" + cUnit.getName()
+                                + " PASSED ");
+                    }
+                }
+            }
+        }
+    }
+
+    private static File getTestCaseQueryBeforeCrashFile(String actualPath, 
TestCaseContext testCaseCtx,
+            CompilationUnit cUnit) {
+        return new File(
+                actualPath + File.separator + 
testCaseCtx.getTestCase().getFilePath().replace(File.separator, "_")
+                        + "_" + cUnit.getName() + "_qbc.adm");
+    }
+
+    protected URI getEndpoint(String servlet) throws URISyntaxException {
+        return new URI("http", null, host, port, 
getPath(servlet).replaceAll("/\\*$", ""), null, null);
+    }
+
+    public static String stripJavaComments(String text) {
+        return JAVA_BLOCK_COMMENT_PATTERN.matcher(text).replaceAll("");
+    }
+
+    public static String stripLineComments(String text) {
+        final String s = 
SHELL_LINE_COMMENT_PATTERN.matcher(text).replaceAll("");
+        return JAVA_LINE_COMMENT_PATTERN.matcher(s).replaceAll("");
+    }
+
+    public void cleanup(String testCase, List<String> badtestcases) throws 
Exception {
+        try {
+            ArrayList<String> toBeDropped = new ArrayList<>();
+            InputStream resultStream = executeQueryService("select 
dv.DataverseName from Metadata.`Dataverse` as dv;",
+                    getEndpoint(Servlets.QUERY_SERVICE));
+            String out = IOUtils.toString(resultStream);
+            ObjectMapper om = new ObjectMapper();
+            om.setConfig(
+                    
om.getDeserializationConfig().with(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT));
+            JsonNode result;
+            try {
+                result = om.readValue(out, ObjectNode.class).get("results");
+            } catch (JsonMappingException e) {
+                result = om.createArrayNode();
+            }
+            for (int i = 0; i < result.size(); i++) {
+                JsonNode json = result.get(i);
+                if (json != null) {
+                    String dvName = json.get("DataverseName").asText();
+                    if (!dvName.equals("Metadata") && 
!dvName.equals("Default")) {
+                        toBeDropped.add(dvName);
+                    }
+                }
+            }
+            if (!toBeDropped.isEmpty()) {
+                badtestcases.add(testCase);
+                LOGGER.warning(
+                        "Last test left some garbage. Dropping dataverses: " + 
StringUtils.join(toBeDropped, ','));
+                StringBuilder dropStatement = new StringBuilder();
+                for (String dv : toBeDropped) {
+                    dropStatement.append("drop dataverse ");
+                    dropStatement.append(dv);
+                    dropStatement.append(";\n");
+                }
+                resultStream =
+                        executeQueryService(dropStatement.toString(), 
getEndpoint(Servlets.QUERY_SERVICE));
+                ResultExtractor.extract(resultStream);
+            }
+        } catch (Throwable th) {
+            th.printStackTrace();
+            throw th;
+        }
+    }
+
+    //This method is here to enable extension
+    protected String getPath(String servlet) {
+        return servlet;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/452ec9f6/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/dml/DmlTest.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/dml/DmlTest.java 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/dml/DmlTest.java
index 1158611..4702b1d 100644
--- 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/dml/DmlTest.java
+++ 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/dml/DmlTest.java
@@ -31,8 +31,8 @@ import 
org.apache.asterix.app.translator.DefaultStatementExecutorFactory;
 import org.apache.asterix.common.exceptions.AsterixException;
 import org.apache.asterix.compiler.provider.AqlCompilationProvider;
 import org.apache.asterix.file.StorageComponentProvider;
-import org.apache.asterix.test.aql.TestExecutor;
 import org.apache.asterix.test.base.AsterixTestHelper;
+import org.apache.asterix.test.common.TestExecutor;
 import org.junit.Test;
 
 public class DmlTest {

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/452ec9f6/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/metadata/MetadataTest.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/metadata/MetadataTest.java
 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/metadata/MetadataTest.java
index 6392410..f75942d 100644
--- 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/metadata/MetadataTest.java
+++ 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/metadata/MetadataTest.java
@@ -24,7 +24,7 @@ import java.util.Collection;
 
 import org.apache.asterix.api.common.AsterixHyracksIntegrationUtil;
 import org.apache.asterix.common.config.GlobalConfig;
-import org.apache.asterix.test.aql.TestExecutor;
+import org.apache.asterix.test.common.TestExecutor;
 import org.apache.asterix.testframework.context.TestCaseContext;
 import org.apache.commons.lang3.StringUtils;
 import org.junit.AfterClass;

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/452ec9f6/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/LangExecutionUtil.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/LangExecutionUtil.java
 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/LangExecutionUtil.java
index a20ecc5..4db00c8 100644
--- 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/LangExecutionUtil.java
+++ 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/runtime/LangExecutionUtil.java
@@ -26,7 +26,7 @@ import java.util.List;
 
 import org.apache.asterix.app.external.TestLibrarian;
 import org.apache.asterix.common.library.ILibraryManager;
-import org.apache.asterix.test.aql.TestExecutor;
+import org.apache.asterix.test.common.TestExecutor;
 import org.apache.asterix.testframework.context.TestCaseContext;
 import org.apache.commons.lang3.StringUtils;
 import org.junit.runner.RunWith;

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/452ec9f6/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
index 2b9b357..0789fa0 100644
--- 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
+++ 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
@@ -47,8 +47,8 @@ import org.apache.asterix.lang.sqlpp.util.SqlppAstPrintUtil;
 import org.apache.asterix.lang.sqlpp.util.SqlppRewriteUtil;
 import org.apache.asterix.metadata.declared.MetadataProvider;
 import org.apache.asterix.metadata.entities.Dataset;
-import org.apache.asterix.test.aql.TestExecutor;
-import org.apache.asterix.test.base.ComparisonException;
+import org.apache.asterix.test.common.ComparisonException;
+import org.apache.asterix.test.common.TestExecutor;
 import org.apache.asterix.testframework.context.TestCaseContext;
 import org.apache.asterix.testframework.context.TestFileContext;
 import org.apache.asterix.testframework.xml.TestCase.CompilationUnit;

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/452ec9f6/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/RuntimeParserTest.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/RuntimeParserTest.java
 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/RuntimeParserTest.java
index 99fde7d..0cac0c5 100644
--- 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/RuntimeParserTest.java
+++ 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/RuntimeParserTest.java
@@ -23,7 +23,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.logging.Logger;
 
-import org.apache.asterix.test.aql.TestExecutor;
+import org.apache.asterix.test.common.TestExecutor;
 import org.apache.asterix.testframework.context.TestCaseContext;
 import org.apache.commons.lang3.StringUtils;
 import org.junit.AfterClass;

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/452ec9f6/asterixdb/asterix-common/pom.xml
----------------------------------------------------------------------
diff --git a/asterixdb/asterix-common/pom.xml b/asterixdb/asterix-common/pom.xml
index d642b57..65e82a2 100644
--- a/asterixdb/asterix-common/pom.xml
+++ b/asterixdb/asterix-common/pom.xml
@@ -180,14 +180,6 @@
       <artifactId>commons-lang3</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.httpcomponents</groupId>
-      <artifactId>httpclient</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.httpcomponents</groupId>
-      <artifactId>httpcore</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.apache.hyracks</groupId>
       <artifactId>algebricks-common</artifactId>
     </dependency>
@@ -240,20 +232,12 @@
       <artifactId>hyracks-api</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.asterix</groupId>
-      <artifactId>asterix-test-framework</artifactId>
-      <version>${project.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
       <groupId>org.apache.hyracks</groupId>
       <artifactId>hyracks-storage-am-lsm-btree</artifactId>
     </dependency>
     <dependency>
       <groupId>org.apache.hyracks</groupId>
-      <artifactId>
-        hyracks-storage-am-lsm-invertedindex
-      </artifactId>
+      <artifactId>hyracks-storage-am-lsm-invertedindex</artifactId>
     </dependency>
     <dependency>
       <groupId>org.apache.hyracks</groupId>
@@ -281,10 +265,6 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>com.google.guava</groupId>
-      <artifactId>guava</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.apache.hyracks</groupId>
       <artifactId>hyracks-data-std</artifactId>
     </dependency>

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/452ec9f6/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/aql/ITestLibrarian.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/aql/ITestLibrarian.java
 
b/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/aql/ITestLibrarian.java
deleted file mode 100644
index bbbd14e..0000000
--- 
a/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/aql/ITestLibrarian.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.asterix.test.aql;
-
-import java.io.IOException;
-import java.rmi.RemoteException;
-
-import org.apache.asterix.common.exceptions.ACIDException;
-import org.apache.asterix.common.exceptions.AsterixException;
-
-public interface ITestLibrarian {
-    public void install(String dvName, String libName, String libPath) throws 
IOException, Exception;
-
-    public void uninstall(String dvName, String libName) throws 
RemoteException, AsterixException, ACIDException;
-}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/452ec9f6/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/aql/ResultExtractor.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/aql/ResultExtractor.java
 
b/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/aql/ResultExtractor.java
deleted file mode 100644
index daea5cc..0000000
--- 
a/asterixdb/asterix-common/src/test/java/org/apache/asterix/test/aql/ResultExtractor.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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.asterix.test.aql;
-
-import java.io.InputStream;
-import java.io.StringWriter;
-import java.nio.charset.Charset;
-import java.util.Iterator;
-import java.util.logging.Logger;
-
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.core.PrettyPrinter;
-import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.collect.Iterators;
-import org.apache.asterix.common.exceptions.AsterixException;
-import org.apache.commons.io.IOUtils;
-
-/**
- * extracts results from the response of the QueryServiceServlet.
- * As the response is not necessarily valid JSON, non-JSON content has to be 
extracted in some cases.
- * The current implementation creates a toomany copies of the data to be 
usable for larger results.
- */
-public class ResultExtractor {
-
-    private static final Logger LOGGER = 
Logger.getLogger(ResultExtractor.class.getName());
-
-    public static InputStream extract(InputStream resultStream) throws 
Exception {
-        ObjectMapper om = new ObjectMapper();
-        String resultStr = IOUtils.toString(resultStream, 
Charset.defaultCharset());
-        PrettyPrinter singleLine = new SingleLinePrettyPrinter();
-        ObjectNode result = om.readValue(resultStr, ObjectNode.class);
-
-        LOGGER.fine("+++++++\n" + result + "\n+++++++\n");
-
-        String type = "";
-        String status = "";
-        String results = "";
-        String field = "";
-        for (Iterator<String> sIter = result.fieldNames(); sIter.hasNext();) {
-            field = sIter.next();
-            switch (field) {
-                case "requestID":
-                    break;
-                case "signature":
-                    break;
-                case "status":
-                    status = om.writeValueAsString(result.get(field));
-                    break;
-                case "type":
-                    type = om.writeValueAsString(result.get(field));
-                    break;
-                case "metrics":
-                    LOGGER.fine(om.writeValueAsString(result.get(field)));
-                    break;
-                case "errors":
-                    JsonNode errors = result.get(field).get(0).get("msg");
-                    throw new AsterixException(errors.asText());
-                case "results":
-                    if (result.get(field).size() <= 1) {
-                        if (result.get(field).size() == 0) {
-                            results = "";
-                        } else if (result.get(field).isArray()) {
-                            if (result.get(field).get(0).isTextual()) {
-                                results = result.get(field).get(0).asText();
-                            } else {
-                                ObjectMapper omm = new ObjectMapper();
-                                omm.setDefaultPrettyPrinter(singleLine);
-                                omm.enable(SerializationFeature.INDENT_OUTPUT);
-                                results = 
omm.writer(singleLine).writeValueAsString(result.get(field));
-                            }
-                        } else {
-                            results = om.writeValueAsString(result.get(field));
-                        }
-                    } else {
-                        StringBuilder sb = new StringBuilder();
-                        JsonNode[] fields = 
Iterators.toArray(result.get(field).elements(), JsonNode.class);
-                        if (fields.length > 1) {
-                            for (JsonNode f : fields) {
-                                if (f.isObject()) {
-                                    sb.append(om.writeValueAsString(f));
-                                } else {
-                                    sb.append(f.asText());
-                                }
-                            }
-                        }
-                        results = sb.toString();
-                    }
-                    break;
-                default:
-                    throw new AsterixException(field + "unanticipated field");
-            }
-        }
-
-        return IOUtils.toInputStream(results);
-    }
-
-    public static String extractHandle(InputStream resultStream) throws 
Exception {
-        final Charset utf8 = Charset.forName("UTF-8");
-        ObjectMapper om = new ObjectMapper();
-        String result = IOUtils.toString(resultStream, utf8);
-        ObjectNode resultJson = om.readValue(result, ObjectNode.class);
-        JsonNode handle = resultJson.get("handle");
-        ObjectNode res = om.createObjectNode();
-        res.set("handle", handle);
-        return om.writeValueAsString(res);
-    }
-}

Reply via email to