[NO ISSUE][TEST] Expose loop iteration for test framework

- also += NetworkUtil javadocs

Change-Id: I91c22e4c4f457b7896f05c10460d671677b6bf9f
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/9344
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Michael Blow <mblow@apache.org>
Reviewed-by: Ali Alsuliman <ali.al.solaiman@gmail.com>
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 614b0a9..00d1034 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
@@ -215,6 +215,7 @@
     protected IExternalUDFLibrarian librarian;
     private Map<File, TestLoop> testLoops = new HashMap<>();
     private double timeoutMultiplier = 1;
+    protected int loopIteration;
 
     public TestExecutor() {
         this(Inet4Address.getLoopbackAddress().getHostAddress(), 19002);
@@ -1272,6 +1273,9 @@
                                     throw new IllegalArgumentException("duration cannot be exceed 1d");
                                 }
                                 break;
+                            case "":
+                                // ignore blank lines;
+                                break;
                             default:
                                 throw new IllegalArgumentException("unknown directive: " + command[0]);
                         }
@@ -1756,7 +1760,7 @@
             String name = m.group("name");
             param.setName(name);
             String value = m.group("value");
-            param.setValue(value);
+            param.setValue(value.replace("\\n", "\n"));
             String type = m.group("type");
             if (type != null) {
                 try {
@@ -1896,6 +1900,7 @@
             }
             List<TestFileContext> expectedResultFileCtxs = testCaseCtx.getExpectedResultFiles(cUnit);
             int[] savedQueryCounts = new int[numOfFiles + testFileCtxs.size()];
+            loopIteration = 0;
             for (ListIterator<TestFileContext> iter = testFileCtxs.listIterator(); iter.hasNext();) {
                 TestFileContext ctx = iter.next();
                 savedQueryCounts[numOfFiles] = queryCount.getValue();
@@ -1903,10 +1908,15 @@
                 final File testFile = ctx.getFile();
                 final String statement = readTestFile(testFile);
                 try {
+                    boolean loopCmd = testFile.getName().endsWith(".loop.cmd");
                     if (!testFile.getName().startsWith(DIAGNOSE)) {
                         executeTestFile(testCaseCtx, ctx, variableCtx, statement, isDmlRecoveryTest, pb, cUnit,
                                 queryCount, expectedResultFileCtxs, testFile, actualPath, expectedWarnings);
                     }
+                    if (loopCmd) {
+                        // this was a loop file and we have exited the loop; reset the loop iteration
+                        loopIteration = 0;
+                    }
                 } catch (TestLoop loop) {
                     // rewind the iterator until we find our target
                     while (!ctx.getFile().getName().equals(loop.getTarget())) {
@@ -1917,6 +1927,7 @@
                         numOfFiles--;
                         queryCount.setValue(savedQueryCounts[numOfFiles]);
                     }
+                    loopIteration++;
                 } catch (Exception e) {
                     numOfErrors++;
                     boolean unexpected = isUnExpected(e, expectedErrors, numOfErrors, queryCount,
diff --git a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/NetworkUtil.java b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/NetworkUtil.java
index 1bab960..958310d 100644
--- a/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/NetworkUtil.java
+++ b/hyracks-fullstack/hyracks/hyracks-util/src/main/java/org/apache/hyracks/util/NetworkUtil.java
@@ -66,10 +66,23 @@
         return builderFrom(host).build();
     }
 
+    /**
+     * @param host the host for this uri
+     * @param path the path for this uri: this value is expected to be unescaped and may contain non ASCII characters
+     * @return
+     * @throws URISyntaxException
+     */
     public static URI toUri(HttpHost host, String path) throws URISyntaxException {
         return builderFrom(host).setPath(path).build();
     }
 
+    /**
+     * @param uri the uri to append to
+     * @param pathSegments the path segments to append to the supplied uri: the segments are expected to be
+     *                     unescaped and may contain non ASCII characters
+     * @return the new uri i.e. original uri with appended path segment(s)
+     * @throws URISyntaxException
+     */
     public static URI appendUriPath(URI uri, String... pathSegments) throws URISyntaxException {
         URIBuilder builder = new URIBuilder(uri);
         List<String> path = builder.getPathSegments();