Add integration tests for Hyracks' HTTP APIs

Change-Id: Ib135ead7896a2b66735eb7325babe15b18a29bed
Reviewed-on: https://asterix-gerrit.ics.uci.edu/1498
Reviewed-by: abdullah alamoudi <bamousaa@gmail.com>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
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
index 8399f7a..daea5cc 100644
--- 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
@@ -46,7 +46,6 @@
 
     public static InputStream extract(InputStream resultStream) throws Exception {
         ObjectMapper om = new ObjectMapper();
-        StringWriter sw = new StringWriter();
         String resultStr = IOUtils.toString(resultStream, Charset.defaultCharset());
         PrettyPrinter singleLine = new SingleLinePrettyPrinter();
         ObjectNode result = om.readValue(resultStr, ObjectNode.class);
diff --git a/hyracks-fullstack/hyracks/hyracks-api/pom.xml b/hyracks-fullstack/hyracks/hyracks-api/pom.xml
index 2bb6cc2..cde607f 100644
--- a/hyracks-fullstack/hyracks/hyracks-api/pom.xml
+++ b/hyracks-fullstack/hyracks/hyracks-api/pom.xml
@@ -59,10 +59,11 @@
   <dependencies>
     <dependency>
       <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpcore</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
       <artifactId>httpclient</artifactId>
-      <version>4.5.2</version>
-      <type>jar</type>
-      <scope>compile</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.hyracks</groupId>
@@ -74,11 +75,6 @@
       <artifactId>commons-lang3</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.httpcomponents</groupId>
-      <artifactId>httpcore</artifactId>
-      <version>4.4.5</version>
-    </dependency>
-    <dependency>
       <groupId>org.apache.hyracks</groupId>
       <artifactId>hyracks-util</artifactId>
       <version>${project.version}</version>
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/GatherStateDumpsWork.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/GatherStateDumpsWork.java
index 7709a2b..d827eba 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/GatherStateDumpsWork.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/work/GatherStateDumpsWork.java
@@ -20,7 +20,9 @@
 package org.apache.hyracks.control.cc.work;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.UUID;
 
@@ -43,7 +45,9 @@
     public void doRun() throws Exception {
         ccs.addStateDumpRun(sdr.stateDumpId, sdr);
         INodeManager nodeManager = ccs.getNodeManager();
-        sdr.setNCs(nodeManager.getAllNodeIds());
+        Collection<String> nodeIds = new HashSet<>();
+        nodeIds.addAll(nodeManager.getAllNodeIds());
+        sdr.setNCs(nodeIds);
         for (NodeControllerState ncs : nodeManager.getAllNodeControllerStates()) {
             ncs.getNodeController().dumpState(sdr.stateDumpId);
         }
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/pom.xml b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/pom.xml
index 2f6bd31..08783cc 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/pom.xml
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/pom.xml
@@ -58,12 +58,10 @@
     <dependency>
       <groupId>org.apache.httpcomponents</groupId>
       <artifactId>httpcore</artifactId>
-      <version>4.4.5</version>
     </dependency>
     <dependency>
       <groupId>org.apache.httpcomponents</groupId>
       <artifactId>httpclient</artifactId>
-      <version>4.5.2</version>
     </dependency>
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/dataset/ResultStateSweeper.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/dataset/ResultStateSweeper.java
index 67b87f5..cd2ebd4 100644
--- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/dataset/ResultStateSweeper.java
+++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-common/src/main/java/org/apache/hyracks/control/common/dataset/ResultStateSweeper.java
@@ -59,7 +59,7 @@
                 Thread.sleep(resultSweepThreshold);
                 sweep();
             } catch (InterruptedException e) {
-                logger.log(Level.SEVERE, "Result cleaner thread interrupted, shutting down.", e);
+                logger.log(Level.WARNING, "Result cleaner thread interrupted, shutting down.");
                 break; // the interrupt was explicit from another thread. This thread should shut down...
             }
         }
diff --git a/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/pom.xml b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/pom.xml
index 21e22ab..630b984 100644
--- a/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/pom.xml
+++ b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/pom.xml
@@ -69,6 +69,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.hyracks</groupId>
+      <artifactId>hyracks-storage-common</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hyracks</groupId>
       <artifactId>hyracks-storage-am-btree</artifactId>
       <version>${project.version}</version>
     </dependency>
@@ -121,10 +126,6 @@
       <version>${project.version}</version>
     </dependency>
     <dependency>
-      <groupId>commons-io</groupId>
-      <artifactId>commons-io</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.apache.hyracks</groupId>
       <artifactId>hyracks-control-common</artifactId>
       <version>${project.version}</version>
@@ -150,9 +151,24 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.apache.hyracks</groupId>
-      <artifactId>hyracks-storage-common</artifactId>
-      <version>${project.version}</version>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpcore</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
+      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
diff --git a/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/ApplicationDeploymentAPIIntegrationTest.java b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/ApplicationDeploymentAPIIntegrationTest.java
new file mode 100644
index 0000000..e1300a3
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/ApplicationDeploymentAPIIntegrationTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.hyracks.tests.integration;
+
+import static org.apache.hyracks.tests.integration.TestUtil.uri;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.entity.ContentType;
+import org.apache.http.impl.client.HttpClients;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ApplicationDeploymentAPIIntegrationTest extends AbstractIntegrationTest {
+
+    @Test
+    public void testApplicationDeploymentSm() throws Exception {
+        final int dataSize = 100;
+        deployApplicationFile(dataSize, "small");
+    }
+
+    @Test
+    public void testApplicationDeploymentMd() throws Exception {
+        final int dataSize = 8 * 1024 * 1024;
+        deployApplicationFile(dataSize, "medium");
+    }
+
+    @Test
+    public void testApplicationDeploymentLg() throws Exception {
+        final int dataSize = 50 * 1024 * 1024;
+        deployApplicationFile(dataSize, "large");
+    }
+
+    protected void deployApplicationFile(int dataSize, String fileName) throws URISyntaxException, IOException {
+        final String deployid = "testApp";
+
+        String path = "/applications/" + deployid + "&" + fileName;
+        URI uri = uri(path);
+
+        byte[] data = new byte[dataSize];
+        for (int i = 0; i < data.length; ++i) {
+            data[i] = (byte) i;
+        }
+
+        HttpClient client = HttpClients.createMinimal();
+
+        // Put the data
+
+        HttpPut put = new HttpPut(uri);
+        HttpEntity entity = new ByteArrayEntity(data, ContentType.APPLICATION_OCTET_STREAM);
+        put.setEntity(entity);
+        client.execute(put);
+
+        // Get it back
+
+        HttpGet get = new HttpGet(uri);
+        HttpResponse response = client.execute(get);
+        HttpEntity respEntity = response.getEntity();
+        Header contentType = respEntity.getContentType();
+
+        // compare results
+
+        Assert.assertEquals(ContentType.APPLICATION_OCTET_STREAM.getMimeType(), contentType.getValue());
+        InputStream is = respEntity.getContent();
+
+        for (int i = 0; i < dataSize; ++i) {
+            Assert.assertEquals(data[i], (byte) is.read());
+        }
+        Assert.assertEquals(-1, is.read());
+        is.close();
+    }
+}
diff --git a/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/JobStatusAPIIntegrationTest.java b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/JobStatusAPIIntegrationTest.java
new file mode 100644
index 0000000..dbc6151
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/JobStatusAPIIntegrationTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.hyracks.tests.integration;
+
+import static org.apache.hyracks.tests.integration.TestUtil.httpGetAsObject;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+
+import org.apache.hyracks.api.constraints.PartitionConstraintHelper;
+import org.apache.hyracks.api.job.JobId;
+import org.apache.hyracks.api.job.JobSpecification;
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class JobStatusAPIIntegrationTest extends AbstractIntegrationTest {
+
+    public static final String ROOT_PATH = "/rest/jobs";
+
+    @Test
+    public void testNoRunningJobs() throws Exception {
+        Assert.assertEquals(0, countJobs("RUNNING"));
+    }
+
+    @Test
+    public void testRunningJob() throws Exception {
+        JobId jId = startJob(); // startJob also checks that the job is running
+        stopJob(jId);
+        Assert.assertEquals("TERMINATED", getJobStatus(jId));
+    }
+
+    @Test
+    public void testJobActivityGraph() throws Exception {
+        JobId jId = startJob();
+        ObjectNode res = getJobActivityGraph(jId);
+        Assert.assertTrue(res.has("result"));
+        ObjectNode actGraph = (ObjectNode) res.get("result");
+        Assert.assertTrue(actGraph.has("version"));
+        checkActivityCluster(actGraph);
+        stopJob(jId);
+        Assert.assertEquals("TERMINATED", getJobStatus(jId));
+    }
+
+    @Test
+    public void testJobRun() throws Exception {
+        JobId jId = startJob();
+        ObjectNode res = getJobRun(jId);
+        Assert.assertTrue(res.has("result"));
+        ObjectNode jobRun = (ObjectNode) res.get("result");
+        Assert.assertTrue(jobRun.has("job-id"));
+        Assert.assertTrue(JobId.parse(jobRun.get("job-id").asText()).equals(jId));
+        checkActivityCluster(jobRun);
+        stopJob(jId);
+        Assert.assertEquals("TERMINATED", getJobStatus(jId));
+    }
+
+    protected void checkActivityCluster(ObjectNode result) {
+        Assert.assertTrue(result.has("activity-clusters"));
+        ArrayNode actClusters = (ArrayNode) result.get("activity-clusters");
+        Assert.assertEquals(1, actClusters.size());
+        ObjectNode actCluster = (ObjectNode) actClusters.get(0);
+        Assert.assertTrue(actCluster.has("activities"));
+    }
+
+    protected JobId startJob() throws Exception {
+        WaitingOperatorDescriptor.CONTINUE_RUNNING.setFalse();
+        JobSpecification spec = new JobSpecification();
+        WaitingOperatorDescriptor sourceOpDesc = new WaitingOperatorDescriptor(spec, 0, 0);
+        PartitionConstraintHelper.addPartitionCountConstraint(spec, sourceOpDesc, 1);
+        spec.addRoot(sourceOpDesc);
+        JobId jId = executeTest(spec);
+        // don't run for more than 100 s
+        int maxLoops = 1000;
+        while (maxLoops > 0 && !"RUNNING".equals(getJobStatus(jId))) {
+            Thread.sleep(100);
+            --maxLoops;
+        }
+        return jId;
+    }
+
+    protected void stopJob(JobId jId) throws Exception {
+        synchronized (WaitingOperatorDescriptor.CONTINUE_RUNNING) {
+            WaitingOperatorDescriptor.CONTINUE_RUNNING.setTrue();
+            WaitingOperatorDescriptor.CONTINUE_RUNNING.notify();
+        }
+        hcc.waitForCompletion(jId);
+    }
+
+    private int countJobs(String status) throws IOException, URISyntaxException {
+        int res = 0;
+        ArrayNode jobArray = getJobs();
+        for (JsonNode n : jobArray) {
+            ObjectNode o = (ObjectNode) n;
+            if (status.equals(o.get("status").asText())) {
+                ++res;
+            }
+        }
+        return res;
+    }
+
+    private String getJobStatus(JobId jid) throws IOException, URISyntaxException {
+        ArrayNode jobArray = getJobs();
+        for (JsonNode n : jobArray) {
+            ObjectNode o = (ObjectNode) n;
+            if (JobId.parse(o.get("job-id").asText()).equals(jid)) {
+                return o.get("status").asText();
+            }
+        }
+        return null;
+    }
+
+    protected ArrayNode getJobs() throws URISyntaxException, IOException {
+        return ((ArrayNode) httpGetAsObject(ROOT_PATH).get("result"));
+    }
+
+    protected ObjectNode getJobActivityGraph(JobId jId) throws URISyntaxException, IOException {
+        return httpGetAsObject(ROOT_PATH + "/" + jId.toString() + "/job-activity-graph");
+    }
+
+    protected ObjectNode getJobRun(JobId jId) throws URISyntaxException, IOException {
+        return httpGetAsObject(ROOT_PATH + "/" + jId.toString() + "/job-run");
+    }
+}
diff --git a/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/NodesAPIIntegrationTest.java b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/NodesAPIIntegrationTest.java
new file mode 100644
index 0000000..ead70b1
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/NodesAPIIntegrationTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.hyracks.tests.integration;
+
+import static org.apache.hyracks.tests.integration.TestUtil.httpGetAsObject;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class NodesAPIIntegrationTest extends AbstractIntegrationTest {
+
+    static final String[] NODE_SUMMARY_FIELDS = { "node-id", "heap-used", "system-load-average" };
+
+    static final String[] NODE_DETAILS_FIELDS = { "node-id", "os-name", "arch", "os-version", "num-processors",
+            "vm-name", "vm-version", "vm-vendor", "classpath", "library-path", "boot-classpath", "input-arguments",
+            "system-properties", "pid", "date", "rrd-ptr", "heartbeat-times", "heap-init-sizes", "heap-used-sizes",
+            "heap-committed-sizes", "heap-max-sizes", "nonheap-init-sizes", "nonheap-used-sizes",
+            "nonheap-committed-sizes", "nonheap-max-sizes", "application-memory-budget", "application-cpu-core-budget",
+            "thread-counts", "peak-thread-counts", "system-load-averages", "gc-names", "gc-collection-counts",
+            "gc-collection-times", "net-payload-bytes-read", "net-payload-bytes-written", "net-signaling-bytes-read",
+            "net-signaling-bytes-written", "dataset-net-payload-bytes-read", "dataset-net-payload-bytes-written",
+            "dataset-net-signaling-bytes-read", "dataset-net-signaling-bytes-written", "ipc-messages-sent",
+            "ipc-message-bytes-sent", "ipc-messages-received", "ipc-message-bytes-received", "disk-reads",
+            "disk-writes", "ini" };
+
+    public static final String ROOT_PATH = "/rest/nodes";
+
+    @Test
+    public void testNodeSummaries() throws Exception {
+        ObjectNode res = httpGetAsObject(ROOT_PATH);
+        Assert.assertTrue(res.has("result"));
+        ArrayNode nodes = (ArrayNode) res.get("result");
+        final int size = nodes.size();
+        Assert.assertEquals(2, size);
+        for (int i = 0; i < size; ++i) {
+            checkNodeFields((ObjectNode) nodes.get(i), NODE_SUMMARY_FIELDS);
+        }
+    }
+
+    @Test
+    public void testNodeDetails() throws Exception {
+        List<String> nodeIds = getNodeIds();
+        for (String nodeId : nodeIds) {
+            ObjectNode res = httpGetAsObject(ROOT_PATH + "/" + nodeId);
+            checkNodeFields((ObjectNode) res.get("result"), NODE_DETAILS_FIELDS);
+        }
+    }
+
+    @Test
+    public void testStatedump() throws Exception {
+        List<String> nodeIds = getNodeIds();
+        ObjectNode res = httpGetAsObject("/rest/statedump");
+        for (String nodeId : nodeIds) {
+            Assert.assertTrue(res.has(nodeId));
+            File dumpFile = new File(res.get(nodeId).asText());
+            /* TODO(tillw) currently doesn't work in the integration tests ...
+            Assert.assertTrue("File '" + dumpFile + "' does not exist", dumpFile.exists());
+            Assert.assertTrue("File '" + dumpFile + "' is empty", dumpFile.length() > 0);
+            Assert.assertTrue("File '" + dumpFile + "' could not be deleted", dumpFile.delete());
+            */
+        }
+    }
+
+    private void checkNodeFields(ObjectNode node, String[] fieldNames) {
+        for (String field : fieldNames) {
+            Assert.assertTrue("field '" + field + "' not found", node.has(field));
+        }
+    }
+
+    private List<String> getNodeIds() throws IOException, URISyntaxException {
+        ObjectNode res = httpGetAsObject(ROOT_PATH);
+        Assert.assertTrue(res.has("result"));
+        ArrayNode nodes = (ArrayNode) res.get("result");
+        final int size = nodes.size();
+        List<String> nodeIds = new ArrayList<>();
+        for (int i = 0; i < size; ++i) {
+            nodeIds.add(nodes.get(i).get("node-id").asText());
+        }
+        return nodeIds;
+    }
+}
diff --git a/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/StaticResourcesAPIIntegrationTest.java b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/StaticResourcesAPIIntegrationTest.java
new file mode 100644
index 0000000..b75c13e
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/StaticResourcesAPIIntegrationTest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.hyracks.tests.integration;
+
+import static org.apache.hyracks.tests.integration.TestUtil.httpGetAsString;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class StaticResourcesAPIIntegrationTest extends AbstractIntegrationTest {
+
+    public static final String ROOT_PATH = "/static/stylesheet/json.human.css";
+
+    @Test
+    public void testStaticResources() throws Exception {
+        String res = httpGetAsString(ROOT_PATH);
+        Assert.assertTrue(res.length() == 3167);
+    }
+
+}
diff --git a/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/TestUtil.java b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/TestUtil.java
new file mode 100644
index 0000000..a855d53
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/TestUtil.java
@@ -0,0 +1,63 @@
+/*
+ * 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.hyracks.tests.integration;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.HttpClients;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+class TestUtil {
+
+    private static final String HOST = "127.0.0.1";
+    private static final int PORT = 16001;
+
+    static URI uri(String path) throws URISyntaxException {
+        return new URI("http", null, HOST, PORT, path, null, null);
+    }
+
+    static InputStream httpGetAsInputStream(String path) throws URISyntaxException, IOException {
+        HttpClient client = HttpClients.createMinimal();
+        HttpResponse response = client.execute(new HttpGet(uri(path)));
+        return response.getEntity().getContent();
+    }
+
+    static String httpGetAsString(String path) throws URISyntaxException, IOException {
+        InputStream resultStream = httpGetAsInputStream(path);
+        return IOUtils.toString(resultStream, Charset.defaultCharset());
+    }
+
+    static ObjectNode getResultAsJson(String resultStr) throws IOException {
+        return new ObjectMapper().readValue(resultStr, ObjectNode.class);
+    }
+
+    static ObjectNode httpGetAsObject(String path) throws URISyntaxException, IOException {
+        return getResultAsJson(httpGetAsString(path));
+    }
+}
diff --git a/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/WaitingOperatorDescriptor.java b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/WaitingOperatorDescriptor.java
new file mode 100644
index 0000000..6503b7b
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-examples/hyracks-integration-tests/src/test/java/org/apache/hyracks/tests/integration/WaitingOperatorDescriptor.java
@@ -0,0 +1,89 @@
+/*
+ * 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.hyracks.tests.integration;
+
+import java.util.logging.Logger;
+
+import org.apache.commons.lang3.mutable.MutableBoolean;
+import org.apache.hyracks.api.comm.IFrameWriter;
+import org.apache.hyracks.api.context.IHyracksTaskContext;
+import org.apache.hyracks.api.dataflow.IOperatorNodePushable;
+import org.apache.hyracks.api.dataflow.value.IRecordDescriptorProvider;
+import org.apache.hyracks.api.dataflow.value.RecordDescriptor;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.api.job.IOperatorDescriptorRegistry;
+import org.apache.hyracks.dataflow.std.base.AbstractSingleActivityOperatorDescriptor;
+
+class WaitingOperatorDescriptor extends AbstractSingleActivityOperatorDescriptor {
+
+    public static final MutableBoolean CONTINUE_RUNNING = new MutableBoolean(false);
+
+    private static final long serialVersionUID = 1L;
+    private static Logger LOGGER = Logger.getLogger(WaitingOperatorDescriptor.class.getName());
+
+    public WaitingOperatorDescriptor(IOperatorDescriptorRegistry spec, int inputArity, int outputArity) {
+        super(spec, inputArity, outputArity);
+    }
+
+    @Override
+    public IOperatorNodePushable createPushRuntime(IHyracksTaskContext ctx,
+            IRecordDescriptorProvider recordDescProvider, int partition, int nPartitions) throws HyracksDataException {
+        try {
+            return new IOperatorNodePushable() {
+                @Override
+                public void setOutputFrameWriter(int index, IFrameWriter writer, RecordDescriptor recordDesc)
+                        throws HyracksDataException {
+                }
+
+                @Override
+                public void initialize() throws HyracksDataException {
+                    synchronized (CONTINUE_RUNNING) {
+                        while (!CONTINUE_RUNNING.booleanValue()) {
+                            try {
+                                CONTINUE_RUNNING.wait();
+                            } catch (InterruptedException e) {
+                                e.printStackTrace();
+                            }
+                        }
+                    }
+                }
+
+                @Override
+                public IFrameWriter getInputFrameWriter(int index) {
+                    return null;
+                }
+
+                @Override
+                public int getInputArity() {
+                    return inputArity;
+                }
+
+                @Override
+                public String getDisplayName() {
+                    return WaitingOperatorDescriptor.class.getSimpleName() + ".OperatorNodePushable:" + partition;
+                }
+
+                @Override
+                public void deinitialize() throws HyracksDataException {
+                }
+            };
+        } finally {
+        }
+    }
+}
diff --git a/hyracks-fullstack/hyracks/hyracks-server/pom.xml b/hyracks-fullstack/hyracks/hyracks-server/pom.xml
index 0cc47ca..ded28ad 100644
--- a/hyracks-fullstack/hyracks/hyracks-server/pom.xml
+++ b/hyracks-fullstack/hyracks/hyracks-server/pom.xml
@@ -155,8 +155,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpcore</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
       <artifactId>httpclient</artifactId>
-      <version>4.5.2</version>
     </dependency>
     <dependency>
       <groupId>junit</groupId>
@@ -164,11 +167,6 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.apache.httpcomponents</groupId>
-      <artifactId>httpcore</artifactId>
-      <version>4.4.5</version>
-    </dependency>
-    <dependency>
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-lang3</artifactId>
     </dependency>
diff --git a/hyracks-fullstack/pom.xml b/hyracks-fullstack/pom.xml
index 5ddbf92..f243f0c 100644
--- a/hyracks-fullstack/pom.xml
+++ b/hyracks-fullstack/pom.xml
@@ -151,6 +151,16 @@
         <version>3.5</version>
       </dependency>
       <dependency>
+        <groupId>org.apache.httpcomponents</groupId>
+        <artifactId>httpcore</artifactId>
+        <version>4.4.5</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.httpcomponents</groupId>
+        <artifactId>httpclient</artifactId>
+        <version>4.5.2</version>
+      </dependency>
+      <dependency>
         <groupId>org.apache.rat</groupId>
         <artifactId>apache-rat-plugin</artifactId>
         <version>0.12</version>