abdullah alamoudi has uploaded a new change for review.

  https://asterix-gerrit.ics.uci.edu/2438

Change subject: [NO ISSUE][TEST] Introduce dynamic expected result poll test 
type
......................................................................

[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
---
A 
asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/IExpectedResultPoller.java
M 
asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/TestExecutor.java
A 
asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/misc/poll-dynamic/poll-dynamic.1.polldynamic.sqlpp
M asterixdb/asterix-app/src/test/resources/runtimets/testsuite_sqlpp.xml
4 files changed, 167 insertions(+), 3 deletions(-)


  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb 
refs/changes/38/2438/1

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..5d7be49
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/common/IExpectedResultPoller.java
@@ -0,0 +1,9 @@
+package org.apache.asterix.test.common;
+
+@FunctionalInterface
+public interface IExpectedResultPoller {
+    /**
+     * @return the expected result as a string
+     */
+    String poll();
+}
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..f53628d 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
@@ -460,6 +460,20 @@
         }
     }
 
+    private static void writeOutputToFile(File actualFile, String result) 
throws Exception {
+        final File parentDir = actualFile.getParentFile();
+        if (!parentDir.isDirectory()) {
+            if (parentDir.exists()) {
+                LOGGER.warn("Actual file parent \"" + parentDir + "\" exists 
but is not a directory");
+            } else if (!parentDir.mkdirs()) {
+                LOGGER.warn("Unable to create actual file parent dir: " + 
parentDir);
+            }
+        }
+        try (FileOutputStream out = new FileOutputStream(actualFile)) {
+            out.write(result.getBytes(StandardCharsets.UTF_8));
+        }
+    }
+
     protected HttpResponse executeAndCheckHttpRequest(HttpUriRequest method) 
throws Exception {
         return checkResponse(executeHttpRequest(method), code -> code == 
HttpStatus.SC_OK);
     }
@@ -888,6 +902,10 @@
                 poll(testCaseCtx, ctx, variableCtx, statement, 
isDmlRecoveryTest, pb, cUnit, queryCount,
                         expectedResultFileCtxs, testFile, actualPath);
                 break;
+            case "polldynamic":
+                polldynamic(testCaseCtx, ctx, variableCtx, statement, 
isDmlRecoveryTest, pb, cUnit, queryCount,
+                        expectedResultFileCtxs, testFile, actualPath);
+                break;
             case "query":
             case "async":
             case "deferred":
@@ -1003,7 +1021,7 @@
                         ctx.extension(), cUnit.getOutputDir().getCompare());
                 break;
             case "server": // (start <test server name> <port>
-                               // [<arg1>][<arg2>][<arg3>]...|stop 
(<port>|all))
+                           // [<arg1>][<arg2>][<arg3>]...|stop (<port>|all))
                 try {
                     lines = statement.trim().split("\n");
                     String[] command = lines[lines.length - 1].trim().split(" 
");
@@ -1051,7 +1069,7 @@
                 }
                 break;
             case "lib": // expected format <dataverse-name> <library-name>
-                            // <library-directory>
+                        // <library-directory>
                         // TODO: make this case work well with entity names 
containing spaces by
                         // looking for \"
                 lines = statement.split("\n");
@@ -1259,6 +1277,117 @@
         actualResultFile.getParentFile().delete();
     }
 
+    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);
+        int timeoutSecs = getTimeoutSecs(statement);
+        int retryDelaySecs = getRetryDelaySecs(statement);
+        long startTime = System.currentTimeMillis();
+        long limitTime = startTime + TimeUnit.SECONDS.toMillis(timeoutSecs);
+        ctx.setType("validate");
+        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 {
+                    Future<Void> execution = executorService.submit(() -> {
+                        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, poller.poll());
+                        variableCtx.put(key, actualResultFile);
+                        actualResultFile = new File(actualPath, 
testCaseCtx.getTestCase().getFilePath()
+                                + File.separatorChar + cUnit.getName() + '.' + 
ctx.getSeqNum() + ".adm");
+                        executeTestFile(testCaseCtx, ctx, variableCtx, 
statement, isDmlRecoveryTest, pb, cUnit,
+                                queryCount, expectedResultFileCtxs, testFile, 
actualPath);
+                        return null;
+                    });
+                    execution.get(limitTime - System.currentTimeMillis(), 
TimeUnit.MILLISECONDS);
+                    responsesReceived++;
+                    finalException = null;
+                    break;
+                } catch (TimeoutException e) {
+                    if (responsesReceived == 0) {
+                        throw new Exception("Poll limit (" + timeoutSecs
+                                + "s) exceeded without obtaining *any* result 
from server");
+                    } else if (finalException != null) {
+                        throw new Exception(
+                                "Poll limit (" + timeoutSecs
+                                        + "s) exceeded without obtaining 
expected result; last exception:",
+                                finalException);
+                    } else {
+                        throw new Exception(
+                                "Poll limit (" + timeoutSecs + "s) exceeded 
without obtaining expected result");
+
+                    }
+                } catch (ExecutionException ee) {
+                    Exception e;
+                    if (ee.getCause() instanceof Exception) {
+                        e = (Exception) ee.getCause();
+                    } else {
+                        e = ee;
+                    }
+                    if (e instanceof ComparisonException) {
+                        LOGGER.info("Comparison failure on poll: {}", 
e::getMessage);
+                    } else if (LOGGER.isDebugEnabled()) {
+                        LOGGER.debug("Received exception on poll", e);
+                    } else {
+                        LOGGER.info("Received exception on poll: {}", 
e::toString);
+                    }
+                    responsesReceived++;
+                    if (isExpected(e, cUnit)) {
+                        expectedException = true;
+                        finalException = e;
+                        break;
+                    }
+                    if ((System.currentTimeMillis() > limitTime)) {
+                        finalException = e;
+                        break;
+                    }
+                    LOGGER.debug("sleeping " + retryDelaySecs + " second(s) 
before polling again");
+                    TimeUnit.SECONDS.sleep(retryDelaySecs);
+                }
+            }
+            if (expectedException) {
+                throw finalException;
+            } else if (finalException != null) {
+                throw new Exception("Poll limit (" + timeoutSecs + "s) 
exceeded without obtaining expected result",
+                        finalException);
+            }
+        } finally {
+            ctx.setType("polldynamic");
+        }
+    }
+
+    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)
@@ -1338,7 +1467,6 @@
         } finally {
             ctx.setType("poll" + ctx.getType());
         }
-
     }
 
     public InputStream executeSqlppUpdateOrDdl(String statement, OutputFormat 
outputFormat) throws Exception {
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;
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 4265163..cf01567 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>

-- 
To view, visit https://asterix-gerrit.ics.uci.edu/2438
To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifc132b2d2286eea1d1e119984c33ca5eef9be92a
Gerrit-PatchSet: 1
Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Owner: abdullah alamoudi <[email protected]>

Reply via email to