Repository: asterixdb
Updated Branches:
  refs/heads/master 71e4b4c00 -> 90883159b


[NO ISSUE][TEST] Introduce dynamic expected result poll test type

- user model changes: no
- storage format changes: no
- interface changes: no

Details:
- This change allows for a new type of tests. The new test can
  poll for both expected results and a query and compare the two
  values.
- A test case is added.

Change-Id: Ifc132b2d2286eea1d1e119984c33ca5eef9be92a
Reviewed-on: https://asterix-gerrit.ics.uci.edu/2438
Sonar-Qube: Jenkins <jenk...@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenk...@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenk...@fulliautomatix.ics.uci.edu>
Reviewed-by: abdullah alamoudi <bamou...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/90883159
Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/90883159
Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/90883159

Branch: refs/heads/master
Commit: 90883159b99f12d98b648dff112605863822a0ac
Parents: 71e4b4c
Author: Abdullah Alamoudi <bamou...@gmail.com>
Authored: Thu Mar 1 15:56:00 2018 -0800
Committer: abdullah alamoudi <bamou...@gmail.com>
Committed: Thu Mar 1 21:35:24 2018 -0800

----------------------------------------------------------------------
 .../test/common/IExpectedResultPoller.java      |  27 +++++
 .../apache/asterix/test/common/IPollTask.java   |  51 ++++++++
 .../asterix/test/common/TestExecutor.java       | 116 ++++++++++++++++---
 .../poll-dynamic.1.polldynamic.sqlpp            |  22 ++++
 .../resources/runtimets/testsuite_sqlpp.xml     |   5 +
 5 files changed, 203 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/asterixdb/blob/90883159/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/IExpectedResultPoller.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/IExpectedResultPoller.java
 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/IExpectedResultPoller.java
new file mode 100644
index 0000000..ce2760d
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/IExpectedResultPoller.java
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+@FunctionalInterface
+public interface IExpectedResultPoller {
+    /**
+     * @return the expected result as a string
+     */
+    String poll() throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/90883159/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/IPollTask.java
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/IPollTask.java
 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/IPollTask.java
new file mode 100644
index 0000000..6d32518
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/IPollTask.java
@@ -0,0 +1,51 @@
+/*
+ * 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.File;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.asterix.testframework.context.TestCaseContext;
+import org.apache.asterix.testframework.context.TestFileContext;
+import org.apache.asterix.testframework.xml.TestCase.CompilationUnit;
+import org.apache.commons.lang3.mutable.MutableInt;
+
+public interface IPollTask {
+
+    /**
+     * Execute the poll task
+     *
+     * @param testCaseCtx
+     * @param ctx
+     * @param variableCtx
+     * @param statement
+     * @param isDmlRecoveryTest
+     * @param pb
+     * @param cUnit
+     * @param queryCount
+     * @param expectedResultFileCtxs
+     * @param testFile
+     * @param actualPath
+     */
+    void execute(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;
+
+}

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/90883159/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
index e39a9f3..48603a5 100644
--- 
a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
+++ 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
@@ -50,6 +50,7 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
+import java.util.concurrent.Semaphore;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.function.Predicate;
@@ -129,6 +130,12 @@ public class TestExecutor {
     public static final Set<String> NON_CANCELLABLE =
             Collections.unmodifiableSet(new HashSet<>(Arrays.asList("store", 
"validate")));
 
+    private final IPollTask plainExecutor = (testCaseCtx, ctx, variableCtx, 
statement, isDmlRecoveryTest, pb, cUnit,
+            queryCount, expectedResultFileCtxs, testFile, actualPath) -> {
+        executeTestFile(testCaseCtx, ctx, variableCtx, statement, 
isDmlRecoveryTest, pb, cUnit, queryCount,
+                expectedResultFileCtxs, testFile, actualPath);
+    };
+
     public static final String DELIVERY_ASYNC = "async";
     public static final String DELIVERY_DEFERRED = "deferred";
     public static final String DELIVERY_IMMEDIATE = "immediate";
@@ -886,6 +893,11 @@ public class TestExecutor {
             case "pollget":
             case "pollquery":
                 poll(testCaseCtx, ctx, variableCtx, statement, 
isDmlRecoveryTest, pb, cUnit, queryCount,
+                        expectedResultFileCtxs, testFile, actualPath, 
ctx.getType().substring("poll".length()),
+                        plainExecutor);
+                break;
+            case "polldynamic":
+                polldynamic(testCaseCtx, ctx, variableCtx, statement, 
isDmlRecoveryTest, pb, cUnit, queryCount,
                         expectedResultFileCtxs, testFile, actualPath);
                 break;
             case "query":
@@ -923,16 +935,8 @@ public class TestExecutor {
                 break;
             case "validate":
                 // This is a query that validates the output against a 
previously executed query
-                key = getKey(statement);
-                expectedResultFile = (File) variableCtx.remove(key);
-                if (expectedResultFile == null) {
-                    throw new IllegalStateException("There is no stored result 
with the key: " + key);
-                }
-                actualResultFile = new File(actualPath, 
testCaseCtx.getTestCase().getFilePath() + File.separatorChar
-                        + cUnit.getName() + '.' + ctx.getSeqNum() + ".adm");
-                executeQuery(OutputFormat.forCompilationUnit(cUnit), 
statement, variableCtx, ctx.getType(), testFile,
-                        expectedResultFile, actualResultFile, queryCount, 
expectedResultFileCtxs.size(),
-                        cUnit.getParameter(), ComparisonEnum.TEXT);
+                validate(actualPath, testCaseCtx, cUnit, statement, 
variableCtx, testFile, ctx, queryCount,
+                        expectedResultFileCtxs);
                 break;
             case "txnqbc": // qbc represents query before crash
                 InputStream resultStream = executeQuery(statement, 
OutputFormat.forCompilationUnit(cUnit),
@@ -1158,6 +1162,21 @@ public class TestExecutor {
         }
     }
 
+    private void validate(String actualPath, TestCaseContext testCaseCtx, 
CompilationUnit cUnit, String statement,
+            Map<String, Object> variableCtx, File testFile, TestFileContext 
ctx, MutableInt queryCount,
+            List<TestFileContext> expectedResultFileCtxs) throws Exception {
+        String key = getKey(statement);
+        File expectedResultFile = (File) variableCtx.remove(key);
+        if (expectedResultFile == null) {
+            throw new IllegalStateException("There is no stored result with 
the key: " + key);
+        }
+        File actualResultFile = new File(actualPath, 
testCaseCtx.getTestCase().getFilePath() + File.separatorChar
+                + cUnit.getName() + '.' + ctx.getSeqNum() + ".adm");
+        executeQuery(OutputFormat.forCompilationUnit(cUnit), statement, 
variableCtx, "validate", testFile,
+                expectedResultFile, actualResultFile, queryCount, 
expectedResultFileCtxs.size(), cUnit.getParameter(),
+                ComparisonEnum.TEXT);
+    }
+
     protected void executeHttpRequest(OutputFormat fmt, String statement, 
Map<String, Object> variableCtx,
             String reqType, File testFile, File expectedResultFile, File 
actualResultFile, MutableInt queryCount,
             int numResultFiles, String extension, ComparisonEnum compare) 
throws Exception {
@@ -1259,29 +1278,88 @@ public class TestExecutor {
         actualResultFile.getParentFile().delete();
     }
 
-    private void poll(TestCaseContext testCaseCtx, TestFileContext ctx, 
Map<String, Object> variableCtx,
+    private void polldynamic(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 {
+        IExpectedResultPoller poller = getExpectedResultPoller(statement);
+        final String key = getKey(statement);
+        poll(testCaseCtx, ctx, variableCtx, statement, isDmlRecoveryTest, pb, 
cUnit, queryCount, expectedResultFileCtxs,
+                testFile, actualPath, "validate", new IPollTask() {
+                    @Override
+                    public void execute(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 actualResultFile = new File(actualPath, 
testCaseCtx.getTestCase().getFilePath()
+                                + File.separatorChar + cUnit.getName() + '.' + 
ctx.getSeqNum() + ".polled.adm");
+                        if (actualResultFile.exists() && 
!actualResultFile.delete()) {
+                            throw new Exception(
+                                    "Failed to delete an existing result file: 
" + actualResultFile.getAbsolutePath());
+                        }
+                        writeOutputToFile(actualResultFile,
+                                new 
ByteArrayInputStream(poller.poll().getBytes(StandardCharsets.UTF_8)));
+                        variableCtx.put(key, actualResultFile);
+                        validate(actualPath, testCaseCtx, cUnit, statement, 
variableCtx, testFile, ctx, queryCount,
+                                expectedResultFileCtxs);
+                    }
+                });
+    }
+
+    protected IExpectedResultPoller getExpectedResultPoller(String statement) {
+        String key = "poller=";
+        String value = null;
+        String[] lines = statement.split("\n");
+        for (String line : lines) {
+            if (line.contains(key)) {
+                value = line.substring(line.indexOf(key) + 
key.length()).trim();
+            }
+        }
+        if (value == null) {
+            throw new IllegalArgumentException("ERROR: poller=<...> must be 
present in poll-dynamic file");
+        }
+        String staticPoller = "static:";
+        if (value.startsWith(staticPoller)) {
+            String polled = value.substring(staticPoller.length());
+            return () -> polled;
+        }
+        throw new IllegalArgumentException("ERROR: unknown poller: " + value);
+    }
+
+    private void poll(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,
+            String newType, IPollTask pollTask) throws Exception {
         // 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()));
+        Semaphore endSemaphore = new Semaphore(1);
+        final ExecutorService executorService = 
Executors.newSingleThreadExecutor();
+        String originalType = ctx.getType();
+        ctx.setType(newType);
         try {
             boolean expectedException = false;
             Exception finalException = null;
             LOGGER.debug("polling for up to " + timeoutSecs + " seconds w/ " + 
retryDelaySecs + " second(s) delay");
             int responsesReceived = 0;
-            final ExecutorService executorService = 
Executors.newSingleThreadExecutor();
             while (true) {
                 try {
+                    endSemaphore.acquire();
+                    Semaphore startSemaphore = new Semaphore(0);
                     Future<Void> execution = executorService.submit(() -> {
-                        executeTestFile(testCaseCtx, ctx, variableCtx, 
statement, isDmlRecoveryTest, pb, cUnit,
-                                queryCount, expectedResultFileCtxs, testFile, 
actualPath);
+                        try {
+                            startSemaphore.release();
+                            pollTask.execute(testCaseCtx, ctx, variableCtx, 
statement, isDmlRecoveryTest, pb, cUnit,
+                                    queryCount, expectedResultFileCtxs, 
testFile, actualPath);
+                        } finally {
+                            endSemaphore.release();
+                        }
                         return null;
                     });
+                    startSemaphore.acquire();
                     execution.get(limitTime - System.currentTimeMillis(), 
TimeUnit.MILLISECONDS);
                     responsesReceived++;
                     finalException = null;
@@ -1334,11 +1412,13 @@ public class TestExecutor {
                 throw new Exception("Poll limit (" + timeoutSecs + "s) 
exceeded without obtaining expected result",
                         finalException);
             }
-
         } finally {
-            ctx.setType("poll" + ctx.getType());
+            executorService.shutdownNow();
+            // ensure no leftover task is running. This avoids re-polling due 
to
+            // resetting the ctx type to poll while the last attempt is being 
made
+            endSemaphore.acquire();
+            ctx.setType(originalType);
         }
-
     }
 
     public InputStream executeSqlppUpdateOrDdl(String statement, OutputFormat 
outputFormat) throws Exception {

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/90883159/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/poll-dynamic/poll-dynamic.1.polldynamic.sqlpp
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/poll-dynamic/poll-dynamic.1.polldynamic.sqlpp
 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/poll-dynamic/poll-dynamic.1.polldynamic.sqlpp
new file mode 100644
index 0000000..e8dc9e8
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/poll-dynamic/poll-dynamic.1.polldynamic.sqlpp
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+-- key=aKey
+-- poller=static:{ "one": 1 }
+-- polltimeoutsecs=120
+select 1 as one;

http://git-wip-us.apache.org/repos/asf/asterixdb/blob/90883159/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
----------------------------------------------------------------------
diff --git 
a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml 
b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
index 09fc832..dd1ae0c 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
@@ -3538,6 +3538,11 @@
   </test-group>
   <test-group name="misc">
     <test-case FilePath="misc">
+      <compilation-unit name="poll-dynamic">
+        <output-dir compare="Text">poll-dynamic</output-dir>
+      </compilation-unit>
+    </test-case>
+    <test-case FilePath="misc">
       <compilation-unit name="validate-expected">
         <output-dir compare="Text">validate-expected</output-dir>
       </compilation-unit>

Reply via email to