You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metron.apache.org by ce...@apache.org on 2017/03/02 20:51:48 UTC

[02/10] incubator-metron git commit: METRON-503: Metron REST API this closes apache/incubator-metron#316

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/KafkaControllerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/KafkaControllerIntegrationTest.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/KafkaControllerIntegrationTest.java
new file mode 100644
index 0000000..0299708
--- /dev/null
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/KafkaControllerIntegrationTest.java
@@ -0,0 +1,188 @@
+/**
+ * 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.metron.rest.controller;
+
+import org.adrianwalker.multilinestring.Multiline;
+import org.apache.metron.integration.components.KafkaComponent;
+import org.apache.metron.rest.generator.SampleDataGenerator;
+import org.apache.metron.rest.service.KafkaService;
+import org.hamcrest.Matchers;
+import org.json.simple.parser.ParseException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import java.io.IOException;
+
+import static org.apache.metron.rest.MetronRestConstants.TEST_PROFILE;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
+import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles(TEST_PROFILE)
+public class KafkaControllerIntegrationTest {
+
+    @Autowired
+    private KafkaComponent kafkaWithZKComponent;
+
+    class SampleDataRunner implements Runnable {
+
+        private boolean stop = false;
+        private String path = "../../metron-platform/metron-integration-test/src/main/sample/data/bro/raw/BroExampleOutput";
+
+        @Override
+        public void run() {
+            SampleDataGenerator broSampleDataGenerator = new SampleDataGenerator();
+            broSampleDataGenerator.setBrokerUrl(kafkaWithZKComponent.getBrokerList());
+            broSampleDataGenerator.setNum(1);
+            broSampleDataGenerator.setSelectedSensorType("bro");
+            broSampleDataGenerator.setDelay(0);
+            try {
+                while(!stop) {
+                    broSampleDataGenerator.generateSampleData(path);
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            } catch (ParseException e) {
+                e.printStackTrace();
+            }
+        }
+
+        public void stop() {
+            stop = true;
+        }
+    }
+
+    private SampleDataRunner sampleDataRunner =  new SampleDataRunner();
+    private Thread sampleDataThread = new Thread(sampleDataRunner);
+
+    /**
+     {
+     "name": "bro",
+     "numPartitions": 1,
+     "properties": {},
+     "replicationFactor": 1
+     }
+     */
+    @Multiline
+    public static String broTopic;
+
+    @Autowired
+    private WebApplicationContext wac;
+
+    @Autowired
+    private KafkaService kafkaService;
+
+    private MockMvc mockMvc;
+
+    private String kafkaUrl = "/api/v1/kafka";
+    private String user = "user";
+    private String password = "password";
+
+    @Before
+    public void setup() throws Exception {
+        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).apply(springSecurity()).build();
+    }
+
+    @Test
+    public void testSecurity() throws Exception {
+        this.mockMvc.perform(post(kafkaUrl + "/topic").with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(broTopic))
+                .andExpect(status().isUnauthorized());
+
+        this.mockMvc.perform(get(kafkaUrl + "/topic/bro"))
+                .andExpect(status().isUnauthorized());
+
+        this.mockMvc.perform(get(kafkaUrl + "/topic"))
+                .andExpect(status().isUnauthorized());
+
+        this.mockMvc.perform(get(kafkaUrl + "/topic/bro/sample"))
+                .andExpect(status().isUnauthorized());
+
+        this.mockMvc.perform(delete(kafkaUrl + "/topic/bro").with(csrf()))
+                .andExpect(status().isUnauthorized());
+    }
+
+    @Test
+    public void test() throws Exception {
+        this.kafkaService.deleteTopic("bro");
+        this.kafkaService.deleteTopic("someTopic");
+        Thread.sleep(1000);
+
+        this.mockMvc.perform(delete(kafkaUrl + "/topic/bro").with(httpBasic(user,password)).with(csrf()))
+                .andExpect(status().isNotFound());
+
+        this.mockMvc.perform(post(kafkaUrl + "/topic").with(httpBasic(user,password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(broTopic))
+                .andExpect(status().isCreated())
+                .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+                .andExpect(jsonPath("$.name").value("bro"))
+                .andExpect(jsonPath("$.numPartitions").value(1))
+                .andExpect(jsonPath("$.replicationFactor").value(1));
+
+        sampleDataThread.start();
+        Thread.sleep(1000);
+
+        this.mockMvc.perform(get(kafkaUrl + "/topic/bro").with(httpBasic(user,password)))
+                .andExpect(status().isOk())
+                .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+                .andExpect(jsonPath("$.name").value("bro"))
+                .andExpect(jsonPath("$.numPartitions").value(1))
+                .andExpect(jsonPath("$.replicationFactor").value(1));
+
+        this.mockMvc.perform(get(kafkaUrl + "/topic/someTopic").with(httpBasic(user,password)))
+                .andExpect(status().isNotFound());
+
+        this.mockMvc.perform(get(kafkaUrl + "/topic").with(httpBasic(user,password)))
+                .andExpect(status().isOk())
+                .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+                .andExpect(jsonPath("$", Matchers.hasItem("bro")));
+
+
+        this.mockMvc.perform(get(kafkaUrl + "/topic/bro/sample").with(httpBasic(user,password)))
+                .andExpect(status().isOk())
+                .andExpect(content().contentType(MediaType.parseMediaType("text/plain;charset=UTF-8")))
+                .andExpect(jsonPath("$").isNotEmpty());
+
+        this.mockMvc.perform(get(kafkaUrl + "/topic/someTopic/sample").with(httpBasic(user,password)))
+                .andExpect(status().isNotFound());
+
+        this.mockMvc.perform(delete(kafkaUrl + "/topic/bro").with(httpBasic(user,password)).with(csrf()))
+                .andExpect(status().isOk());
+    }
+
+    @After
+    public void tearDown() {
+        sampleDataRunner.stop();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorEnrichmentConfigControllerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorEnrichmentConfigControllerIntegrationTest.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorEnrichmentConfigControllerIntegrationTest.java
new file mode 100644
index 0000000..a659772
--- /dev/null
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorEnrichmentConfigControllerIntegrationTest.java
@@ -0,0 +1,240 @@
+/**
+ * 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.metron.rest.controller;
+
+import org.adrianwalker.multilinestring.Multiline;
+import org.apache.metron.rest.service.SensorEnrichmentConfigService;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import static org.apache.metron.rest.MetronRestConstants.TEST_PROFILE;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
+import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles(TEST_PROFILE)
+public class SensorEnrichmentConfigControllerIntegrationTest {
+
+  /**
+   {
+   "enrichment": {
+   "fieldMap": {
+   "geo": [
+   "ip_dst_addr"
+   ],
+   "host": [
+   "ip_dst_addr"
+   ],
+   "hbaseEnrichment": [
+   "ip_src_addr"
+   ],
+   "stellar": {
+   "config": {
+   "group1": {
+   "foo": "1 + 1",
+   "bar": "foo"
+   },
+   "group2": {
+   "ALL_CAPS": "TO_UPPER(source.type)"
+   }
+   }
+   }
+   },
+   "fieldToTypeMap": {
+   "ip_src_addr": [
+   "sample"
+   ]
+   }
+   },
+   "threatIntel": {
+   "fieldMap": {
+   "hbaseThreatIntel": [
+   "ip_src_addr",
+   "ip_dst_addr"
+   ]
+   },
+   "fieldToTypeMap": {
+   "ip_src_addr": [
+   "malicious_ip"
+   ],
+   "ip_dst_addr": [
+   "malicious_ip"
+   ]
+   },
+   "triageConfig": {
+   "riskLevelRules": {
+   "ip_src_addr == '10.122.196.204' or ip_dst_addr == '10.122.196.204'": 10
+   },
+   "aggregator": "MAX"
+   }
+   }
+   }
+   */
+  @Multiline
+  public static String broJson;
+
+  @Autowired
+  private SensorEnrichmentConfigService sensorEnrichmentConfigService;
+
+  @Autowired
+  private WebApplicationContext wac;
+
+  private MockMvc mockMvc;
+
+  private String sensorEnrichmentConfigUrl = "/api/v1/sensor/enrichment/config";
+  private String user = "user";
+  private String password = "password";
+
+  @Before
+  public void setup() throws Exception {
+    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).apply(springSecurity()).build();
+  }
+
+  @Test
+  public void testSecurity() throws Exception {
+    this.mockMvc.perform(post(sensorEnrichmentConfigUrl).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(broJson))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(sensorEnrichmentConfigUrl + "/broTest"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(sensorEnrichmentConfigUrl))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(delete(sensorEnrichmentConfigUrl + "/broTest").with(csrf()))
+            .andExpect(status().isUnauthorized());
+  }
+
+  @Test
+  public void test() throws Exception {
+    sensorEnrichmentConfigService.delete("broTest");
+
+    this.mockMvc.perform(get(sensorEnrichmentConfigUrl).with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(content().bytes("{}".getBytes()));
+
+    this.mockMvc.perform(post(sensorEnrichmentConfigUrl + "/broTest").with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(broJson))
+            .andExpect(status().isCreated())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.enrichment.fieldMap.geo[0]").value("ip_dst_addr"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.host[0]").value("ip_dst_addr"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.hbaseEnrichment[0]").value("ip_src_addr"))
+            .andExpect(jsonPath("$.enrichment.fieldToTypeMap.ip_src_addr[0]").value("sample"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.stellar.config.group1.foo").value("1 + 1"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.stellar.config.group1.bar").value("foo"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.stellar.config.group2.ALL_CAPS").value("TO_UPPER(source.type)"))
+            .andExpect(jsonPath("$.threatIntel.fieldMap.hbaseThreatIntel[0]").value("ip_src_addr"))
+            .andExpect(jsonPath("$.threatIntel.fieldMap.hbaseThreatIntel[1]").value("ip_dst_addr"))
+            .andExpect(jsonPath("$.threatIntel.fieldToTypeMap.ip_src_addr[0]").value("malicious_ip"))
+            .andExpect(jsonPath("$.threatIntel.fieldToTypeMap.ip_dst_addr[0]").value("malicious_ip"))
+            .andExpect(jsonPath("$.threatIntel.triageConfig.riskLevelRules[\"ip_src_addr == '10.122.196.204' or ip_dst_addr == '10.122.196.204'\"]").value(10))
+            .andExpect(jsonPath("$.threatIntel.triageConfig.aggregator").value("MAX"));
+
+    this.mockMvc.perform(post(sensorEnrichmentConfigUrl + "/broTest").with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(broJson))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.enrichment.fieldMap.geo[0]").value("ip_dst_addr"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.host[0]").value("ip_dst_addr"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.hbaseEnrichment[0]").value("ip_src_addr"))
+            .andExpect(jsonPath("$.enrichment.fieldToTypeMap.ip_src_addr[0]").value("sample"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.stellar.config.group1.foo").value("1 + 1"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.stellar.config.group1.bar").value("foo"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.stellar.config.group2.ALL_CAPS").value("TO_UPPER(source.type)"))
+            .andExpect(jsonPath("$.threatIntel.fieldMap.hbaseThreatIntel[0]").value("ip_src_addr"))
+            .andExpect(jsonPath("$.threatIntel.fieldMap.hbaseThreatIntel[1]").value("ip_dst_addr"))
+            .andExpect(jsonPath("$.threatIntel.fieldToTypeMap.ip_src_addr[0]").value("malicious_ip"))
+            .andExpect(jsonPath("$.threatIntel.fieldToTypeMap.ip_dst_addr[0]").value("malicious_ip"))
+            .andExpect(jsonPath("$.threatIntel.triageConfig.riskLevelRules[\"ip_src_addr == '10.122.196.204' or ip_dst_addr == '10.122.196.204'\"]").value(10))
+            .andExpect(jsonPath("$.threatIntel.triageConfig.aggregator").value("MAX"));
+
+    this.mockMvc.perform(get(sensorEnrichmentConfigUrl + "/broTest").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.enrichment.fieldMap.geo[0]").value("ip_dst_addr"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.host[0]").value("ip_dst_addr"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.hbaseEnrichment[0]").value("ip_src_addr"))
+            .andExpect(jsonPath("$.enrichment.fieldToTypeMap.ip_src_addr[0]").value("sample"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.stellar.config.group1.foo").value("1 + 1"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.stellar.config.group1.bar").value("foo"))
+            .andExpect(jsonPath("$.enrichment.fieldMap.stellar.config.group2.ALL_CAPS").value("TO_UPPER(source.type)"))
+            .andExpect(jsonPath("$.threatIntel.fieldMap.hbaseThreatIntel[0]").value("ip_src_addr"))
+            .andExpect(jsonPath("$.threatIntel.fieldMap.hbaseThreatIntel[1]").value("ip_dst_addr"))
+            .andExpect(jsonPath("$.threatIntel.fieldToTypeMap.ip_src_addr[0]").value("malicious_ip"))
+            .andExpect(jsonPath("$.threatIntel.fieldToTypeMap.ip_dst_addr[0]").value("malicious_ip"))
+            .andExpect(jsonPath("$.threatIntel.triageConfig.riskLevelRules[\"ip_src_addr == '10.122.196.204' or ip_dst_addr == '10.122.196.204'\"]").value(10))
+            .andExpect(jsonPath("$.threatIntel.triageConfig.aggregator").value("MAX"));
+
+    this.mockMvc.perform(get(sensorEnrichmentConfigUrl).with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$[?(@.broTest.enrichment.fieldMap.geo[0] == 'ip_dst_addr' &&" +
+                    "@.broTest.enrichment.fieldMap.host[0] == 'ip_dst_addr' &&" +
+                    "@.broTest.enrichment.fieldMap.hbaseEnrichment[0] == 'ip_src_addr' &&" +
+                    "@.broTest.enrichment.fieldToTypeMap.ip_src_addr[0] == 'sample' &&" +
+                    "@.broTest.enrichment.fieldMap.stellar.config.group1.foo == '1 + 1' &&" +
+                    "@.broTest.enrichment.fieldMap.stellar.config.group1.bar == 'foo' &&" +
+                    "@.broTest.enrichment.fieldMap.stellar.config.group2.ALL_CAPS == 'TO_UPPER(source.type)' &&" +
+                    "@.broTest.threatIntel.fieldMap.hbaseThreatIntel[0] == 'ip_src_addr' &&" +
+                    "@.broTest.threatIntel.fieldMap.hbaseThreatIntel[1] == 'ip_dst_addr' &&" +
+                    "@.broTest.threatIntel.fieldToTypeMap.ip_src_addr[0] == 'malicious_ip' &&" +
+                    "@.broTest.threatIntel.fieldToTypeMap.ip_dst_addr[0] == 'malicious_ip' &&" +
+                    "@.broTest.threatIntel.triageConfig.riskLevelRules[\"ip_src_addr == '10.122.196.204' or ip_dst_addr == '10.122.196.204'\"] == 10 &&" +
+                    "@.broTest.threatIntel.triageConfig.aggregator == 'MAX'" +
+                    ")]").exists());
+
+    this.mockMvc.perform(delete(sensorEnrichmentConfigUrl + "/broTest").with(httpBasic(user,password)).with(csrf()))
+            .andExpect(status().isOk());
+
+    this.mockMvc.perform(get(sensorEnrichmentConfigUrl + "/broTest").with(httpBasic(user,password)))
+            .andExpect(status().isNotFound());
+
+    this.mockMvc.perform(delete(sensorEnrichmentConfigUrl + "/broTest").with(httpBasic(user,password)).with(csrf()))
+            .andExpect(status().isNotFound());
+
+    this.mockMvc.perform(get(sensorEnrichmentConfigUrl).with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$[?(@.sensorTopic == 'broTest')]").doesNotExist());
+
+    this.mockMvc.perform(get(sensorEnrichmentConfigUrl + "/list/available").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$[0]").value("geo"))
+            .andExpect(jsonPath("$[1]").value("host"))
+            .andExpect(jsonPath("$[2]").value("whois"));
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorIndexingConfigControllerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorIndexingConfigControllerIntegrationTest.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorIndexingConfigControllerIntegrationTest.java
new file mode 100644
index 0000000..10edadc
--- /dev/null
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorIndexingConfigControllerIntegrationTest.java
@@ -0,0 +1,140 @@
+/**
+ * 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.metron.rest.controller;
+
+import org.adrianwalker.multilinestring.Multiline;
+import org.apache.metron.rest.service.SensorIndexingConfigService;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import static org.apache.metron.rest.MetronRestConstants.TEST_PROFILE;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
+import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles(TEST_PROFILE)
+public class SensorIndexingConfigControllerIntegrationTest {
+
+  /**
+   {
+   "index": "broTest",
+   "batchSize": 1
+   }
+   */
+  @Multiline
+  public static String broJson;
+
+  @Autowired
+  private SensorIndexingConfigService sensorIndexingConfigService;
+
+  @Autowired
+  private WebApplicationContext wac;
+
+  private MockMvc mockMvc;
+
+  private String sensorIndexingConfigUrl = "/api/v1/sensor/indexing/config";
+  private String user = "user";
+  private String password = "password";
+
+  @Before
+  public void setup() throws Exception {
+    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).apply(springSecurity()).build();
+  }
+
+  @Test
+  public void testSecurity() throws Exception {
+    this.mockMvc.perform(post(sensorIndexingConfigUrl).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(broJson))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(sensorIndexingConfigUrl + "/broTest"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(sensorIndexingConfigUrl))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(delete(sensorIndexingConfigUrl + "/broTest").with(csrf()))
+            .andExpect(status().isUnauthorized());
+  }
+
+  @Test
+  public void test() throws Exception {
+    sensorIndexingConfigService.delete("broTest");
+
+    this.mockMvc.perform(get(sensorIndexingConfigUrl).with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(content().bytes("{}".getBytes()));
+
+    this.mockMvc.perform(post(sensorIndexingConfigUrl + "/broTest").with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(broJson))
+            .andExpect(status().isCreated())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.index").value("broTest"))
+            .andExpect(jsonPath("$.batchSize").value(1));
+
+    this.mockMvc.perform(post(sensorIndexingConfigUrl + "/broTest").with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(broJson))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.index").value("broTest"))
+            .andExpect(jsonPath("$.batchSize").value(1));
+
+    this.mockMvc.perform(get(sensorIndexingConfigUrl + "/broTest").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.index").value("broTest"))
+            .andExpect(jsonPath("$.batchSize").value(1));
+
+    this.mockMvc.perform(get(sensorIndexingConfigUrl).with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$[?(@.broTest.index == 'broTest' &&" +
+                    "@.broTest.batchSize == 1" +
+                    ")]").exists());
+
+    this.mockMvc.perform(delete(sensorIndexingConfigUrl + "/broTest").with(httpBasic(user,password)).with(csrf()))
+            .andExpect(status().isOk());
+
+    this.mockMvc.perform(get(sensorIndexingConfigUrl + "/broTest").with(httpBasic(user,password)))
+            .andExpect(status().isNotFound());
+
+    this.mockMvc.perform(delete(sensorIndexingConfigUrl + "/broTest").with(httpBasic(user,password)).with(csrf()))
+            .andExpect(status().isNotFound());
+
+    this.mockMvc.perform(get(sensorIndexingConfigUrl).with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$[?(@.sensorTopic == 'broTest')]").doesNotExist());
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorParserConfigControllerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorParserConfigControllerIntegrationTest.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorParserConfigControllerIntegrationTest.java
new file mode 100644
index 0000000..09b1b0a
--- /dev/null
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/SensorParserConfigControllerIntegrationTest.java
@@ -0,0 +1,368 @@
+/**
+ * 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.metron.rest.controller;
+
+import org.adrianwalker.multilinestring.Multiline;
+import org.apache.commons.io.FileUtils;
+import org.apache.metron.rest.MetronRestConstants;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.env.Environment;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.apache.metron.rest.MetronRestConstants.TEST_PROFILE;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
+import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles(TEST_PROFILE)
+public class SensorParserConfigControllerIntegrationTest {
+
+  /**
+   {
+   "parserClassName": "org.apache.metron.parsers.GrokParser",
+   "sensorTopic": "squidTest",
+   "parserConfig": {
+   "patternLabel": "SQUIDTEST",
+   "grokStatement": "%{NUMBER:timestamp} %{INT:elapsed} %{IPV4:ip_src_addr} %{WORD:action}/%{NUMBER:code} %{NUMBER:bytes} %{WORD:method} %{NOTSPACE:url} - %{WORD:UNWANTED}\/%{IPV4:ip_dst_addr} %{WORD:UNWANTED}\/%{WORD:UNWANTED}",
+   "timestampField": "timestamp"
+   },
+   "fieldTransformations" : [
+   {
+   "transformation" : "STELLAR"
+   ,"output" : [ "full_hostname", "domain_without_subdomains" ]
+   ,"config" : {
+   "full_hostname" : "URL_TO_HOST(url)"
+   ,"domain_without_subdomains" : "DOMAIN_REMOVE_SUBDOMAINS(full_hostname)"
+   }
+   }
+   ]
+   }
+   */
+  @Multiline
+  public static String squidJson;
+
+  /**
+   {
+   "parserClassName": "org.apache.metron.parsers.GrokParser",
+   "sensorTopic": "squidTest",
+   "parserConfig": {
+   "patternLabel": "SQUIDTEST",
+   "timestampField": "timestamp"
+   }
+   }
+   */
+  @Multiline
+  public static String missingGrokJson;
+
+  /**
+   {
+   "parserClassName":"org.apache.metron.parsers.bro.BasicBroParser",
+   "sensorTopic":"broTest",
+   "parserConfig": {}
+   }
+   */
+  @Multiline
+  public static String broJson;
+
+  /**
+   {
+   "sensorParserConfig":
+   {
+   "parserClassName": "org.apache.metron.parsers.GrokParser",
+   "sensorTopic": "squidTest",
+   "parserConfig": {
+   "grokStatement": "%{NUMBER:timestamp} %{INT:elapsed} %{IPV4:ip_src_addr} %{WORD:action}/%{NUMBER:code} %{NUMBER:bytes} %{WORD:method} %{NOTSPACE:url} - %{WORD:UNWANTED}\/%{IPV4:ip_dst_addr} %{WORD:UNWANTED}\/%{WORD:UNWANTED}",
+   "patternLabel": "SQUIDTEST",
+   "grokPath":"./squidTest",
+   "timestampField": "timestamp"
+   }
+   },
+   "sampleData":"1467011157.401 415 127.0.0.1 TCP_MISS/200 337891 GET http://www.aliexpress.com/af/shoes.html? - DIRECT/207.109.73.154 text/html"
+   }
+   */
+  @Multiline
+  public static String parseRequest;
+
+  /**
+   {
+   "sensorParserConfig": null,
+   "sampleData":"1467011157.401 415 127.0.0.1 TCP_MISS/200 337891 GET http://www.aliexpress.com/af/shoes.html? - DIRECT/207.109.73.154 text/html"
+   }
+   */
+  @Multiline
+  public static String missingConfigParseRequest;
+
+  /**
+   {
+   "sensorParserConfig":
+   {
+   "sensorTopic": "squidTest",
+   "parserConfig": {
+   "grokStatement": "%{NUMBER:timestamp} %{INT:elapsed} %{IPV4:ip_src_addr} %{WORD:action}/%{NUMBER:code} %{NUMBER:bytes} %{WORD:method} %{NOTSPACE:url} - %{WORD:UNWANTED}\/%{IPV4:ip_dst_addr} %{WORD:UNWANTED}\/%{WORD:UNWANTED}",
+   "patternLabel": "SQUIDTEST",
+   "grokPath":"./squidTest",
+   "timestampField": "timestamp"
+   }
+   },
+   "sampleData":"1467011157.401 415 127.0.0.1 TCP_MISS/200 337891 GET http://www.aliexpress.com/af/shoes.html? - DIRECT/207.109.73.154 text/html"
+   }
+   */
+  @Multiline
+  public static String missingClassParseRequest;
+
+  /**
+   {
+   "sensorParserConfig":
+   {
+   "parserClassName": "badClass",
+   "sensorTopic": "squidTest",
+   "parserConfig": {
+   "grokStatement": "%{NUMBER:timestamp} %{INT:elapsed} %{IPV4:ip_src_addr} %{WORD:action}/%{NUMBER:code} %{NUMBER:bytes} %{WORD:method} %{NOTSPACE:url} - %{WORD:UNWANTED}\/%{IPV4:ip_dst_addr} %{WORD:UNWANTED}\/%{WORD:UNWANTED}",
+   "patternLabel": "SQUIDTEST",
+   "grokPath":"./squidTest",
+   "timestampField": "timestamp"
+   }
+   },
+   "sampleData":"1467011157.401 415 127.0.0.1 TCP_MISS/200 337891 GET http://www.aliexpress.com/af/shoes.html? - DIRECT/207.109.73.154 text/html"
+   }
+   */
+  @Multiline
+  public static String badClassParseRequest;
+
+  @Autowired
+  private Environment environment;
+
+  @Autowired
+  private WebApplicationContext wac;
+
+  private MockMvc mockMvc;
+
+  private String sensorParserConfigUrl = "/api/v1/sensor/parser/config";
+  private String user = "user";
+  private String password = "password";
+
+  @Before
+  public void setup() throws Exception {
+    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).apply(springSecurity()).build();
+  }
+
+  @Test
+  public void testSecurity() throws Exception {
+    this.mockMvc.perform(post(sensorParserConfigUrl).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(squidJson))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(sensorParserConfigUrl + "/squidTest"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(sensorParserConfigUrl))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(delete(sensorParserConfigUrl + "/squidTest").with(csrf()))
+            .andExpect(status().isUnauthorized());
+  }
+
+  @Test
+  public void test() throws Exception {
+    cleanFileSystem();
+
+    this.mockMvc.perform(post(sensorParserConfigUrl).with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(squidJson))
+            .andExpect(status().isCreated())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.parserClassName").value("org.apache.metron.parsers.GrokParser"))
+            .andExpect(jsonPath("$.sensorTopic").value("squidTest"))
+            .andExpect(jsonPath("$.parserConfig.grokPath").value("target/patterns/squidTest"))
+            .andExpect(jsonPath("$.parserConfig.patternLabel").value("SQUIDTEST"))
+            .andExpect(jsonPath("$.parserConfig.grokStatement").value("%{NUMBER:timestamp} %{INT:elapsed} %{IPV4:ip_src_addr} %{WORD:action}/%{NUMBER:code} %{NUMBER:bytes} %{WORD:method} %{NOTSPACE:url} - %{WORD:UNWANTED}/%{IPV4:ip_dst_addr} %{WORD:UNWANTED}/%{WORD:UNWANTED}"))
+            .andExpect(jsonPath("$.parserConfig.timestampField").value("timestamp"))
+            .andExpect(jsonPath("$.fieldTransformations[0].transformation").value("STELLAR"))
+            .andExpect(jsonPath("$.fieldTransformations[0].output[0]").value("full_hostname"))
+            .andExpect(jsonPath("$.fieldTransformations[0].output[1]").value("domain_without_subdomains"))
+            .andExpect(jsonPath("$.fieldTransformations[0].config.full_hostname").value("URL_TO_HOST(url)"))
+            .andExpect(jsonPath("$.fieldTransformations[0].config.domain_without_subdomains").value("DOMAIN_REMOVE_SUBDOMAINS(full_hostname)"));
+
+    this.mockMvc.perform(post(sensorParserConfigUrl).with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(missingGrokJson))
+            .andExpect(status().isInternalServerError())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.responseCode").value(500))
+            .andExpect(jsonPath("$.message").value("A grokStatement must be provided"));
+
+    this.mockMvc.perform(get(sensorParserConfigUrl + "/squidTest").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.parserClassName").value("org.apache.metron.parsers.GrokParser"))
+            .andExpect(jsonPath("$.sensorTopic").value("squidTest"))
+            .andExpect(jsonPath("$.parserConfig.grokPath").value("target/patterns/squidTest"))
+            .andExpect(jsonPath("$.parserConfig.patternLabel").value("SQUIDTEST"))
+            .andExpect(jsonPath("$.parserConfig.grokStatement").value("%{NUMBER:timestamp} %{INT:elapsed} %{IPV4:ip_src_addr} %{WORD:action}/%{NUMBER:code} %{NUMBER:bytes} %{WORD:method} %{NOTSPACE:url} - %{WORD:UNWANTED}/%{IPV4:ip_dst_addr} %{WORD:UNWANTED}/%{WORD:UNWANTED}"))
+            .andExpect(jsonPath("$.parserConfig.timestampField").value("timestamp"))
+            .andExpect(jsonPath("$.fieldTransformations[0].transformation").value("STELLAR"))
+            .andExpect(jsonPath("$.fieldTransformations[0].output[0]").value("full_hostname"))
+            .andExpect(jsonPath("$.fieldTransformations[0].output[1]").value("domain_without_subdomains"))
+            .andExpect(jsonPath("$.fieldTransformations[0].config.full_hostname").value("URL_TO_HOST(url)"))
+            .andExpect(jsonPath("$.fieldTransformations[0].config.domain_without_subdomains").value("DOMAIN_REMOVE_SUBDOMAINS(full_hostname)"));
+
+    this.mockMvc.perform(get(sensorParserConfigUrl).with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$[?(@.parserClassName == 'org.apache.metron.parsers.GrokParser' &&" +
+                    "@.sensorTopic == 'squidTest' &&" +
+                    "@.parserConfig.grokPath == 'target/patterns/squidTest' &&" +
+                    "@.parserConfig.patternLabel == 'SQUIDTEST' &&" +
+                    "@.parserConfig.timestampField == 'timestamp' &&" +
+                    "@.fieldTransformations[0].transformation == 'STELLAR' &&" +
+                    "@.fieldTransformations[0].output[0] == 'full_hostname' &&" +
+                    "@.fieldTransformations[0].output[1] == 'domain_without_subdomains' &&" +
+                    "@.fieldTransformations[0].config.full_hostname == 'URL_TO_HOST(url)' &&" +
+                    "@.fieldTransformations[0].config.domain_without_subdomains == 'DOMAIN_REMOVE_SUBDOMAINS(full_hostname)')]").exists());
+
+    this.mockMvc.perform(post(sensorParserConfigUrl).with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(broJson))
+            .andExpect(status().isCreated())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.parserClassName").value("org.apache.metron.parsers.bro.BasicBroParser"))
+            .andExpect(jsonPath("$.sensorTopic").value("broTest"))
+            .andExpect(jsonPath("$.parserConfig").isEmpty());
+
+    this.mockMvc.perform(post(sensorParserConfigUrl).with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(broJson))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.parserClassName").value("org.apache.metron.parsers.bro.BasicBroParser"))
+            .andExpect(jsonPath("$.sensorTopic").value("broTest"))
+            .andExpect(jsonPath("$.parserConfig").isEmpty());
+
+    this.mockMvc.perform(get(sensorParserConfigUrl).with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$[?(@.parserClassName == 'org.apache.metron.parsers.GrokParser' &&" +
+                    "@.sensorTopic == 'squidTest' &&" +
+                    "@.parserConfig.grokPath == 'target/patterns/squidTest' &&" +
+                    "@.parserConfig.patternLabel == 'SQUIDTEST' &&" +
+                    "@.parserConfig.timestampField == 'timestamp' &&" +
+                    "@.fieldTransformations[0].transformation == 'STELLAR' &&" +
+                    "@.fieldTransformations[0].output[0] == 'full_hostname' &&" +
+                    "@.fieldTransformations[0].output[1] == 'domain_without_subdomains' &&" +
+                    "@.fieldTransformations[0].config.full_hostname == 'URL_TO_HOST(url)' &&" +
+                    "@.fieldTransformations[0].config.domain_without_subdomains == 'DOMAIN_REMOVE_SUBDOMAINS(full_hostname)')]").exists())
+            .andExpect(jsonPath("$[?(@.parserClassName == 'org.apache.metron.parsers.bro.BasicBroParser' && " +
+                    "@.sensorTopic == 'broTest')]").exists());
+
+    this.mockMvc.perform(delete(sensorParserConfigUrl + "/squidTest").with(httpBasic(user,password)).with(csrf()))
+            .andExpect(status().isOk());
+
+    this.mockMvc.perform(get(sensorParserConfigUrl + "/squidTest").with(httpBasic(user,password)))
+            .andExpect(status().isNotFound());
+
+    this.mockMvc.perform(delete(sensorParserConfigUrl + "/squidTest").with(httpBasic(user,password)).with(csrf()))
+            .andExpect(status().isNotFound());
+
+    this.mockMvc.perform(get(sensorParserConfigUrl).with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$[?(@.sensorTopic == 'squidTest')]").doesNotExist())
+            .andExpect(jsonPath("$[?(@.sensorTopic == 'broTest')]").exists());
+
+    this.mockMvc.perform(delete(sensorParserConfigUrl + "/broTest").with(httpBasic(user,password)).with(csrf()))
+            .andExpect(status().isOk());
+
+    this.mockMvc.perform(delete(sensorParserConfigUrl + "/broTest").with(httpBasic(user,password)).with(csrf()))
+            .andExpect(status().isNotFound());
+
+    this.mockMvc.perform(get(sensorParserConfigUrl).with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$[?(@.sensorTopic == 'squidTest')]").doesNotExist())
+            .andExpect(jsonPath("$[?(@.sensorTopic == 'broTest')]").doesNotExist());
+
+    this.mockMvc.perform(get(sensorParserConfigUrl + "/list/available").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.Bro").value("org.apache.metron.parsers.bro.BasicBroParser"))
+            .andExpect(jsonPath("$.Grok").value("org.apache.metron.parsers.GrokParser"));
+
+    this.mockMvc.perform(get(sensorParserConfigUrl + "/reload/available").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.Bro").value("org.apache.metron.parsers.bro.BasicBroParser"))
+            .andExpect(jsonPath("$.Grok").value("org.apache.metron.parsers.GrokParser"));
+
+    this.mockMvc.perform(post(sensorParserConfigUrl + "/parseMessage").with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(parseRequest))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.elapsed").value(415))
+            .andExpect(jsonPath("$.code").value(200))
+            .andExpect(jsonPath("$.ip_dst_addr").value("207.109.73.154"))
+            .andExpect(jsonPath("$.method").value("GET"))
+            .andExpect(jsonPath("$.bytes").value(337891))
+            .andExpect(jsonPath("$.action").value("TCP_MISS"))
+            .andExpect(jsonPath("$.ip_src_addr").value("127.0.0.1"))
+            .andExpect(jsonPath("$.url").value("http://www.aliexpress.com/af/shoes.html?"))
+            .andExpect(jsonPath("$.timestamp").value(1467011157401L));
+
+    this.mockMvc.perform(post(sensorParserConfigUrl + "/parseMessage").with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(missingConfigParseRequest))
+            .andExpect(status().isInternalServerError())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.responseCode").value(500))
+            .andExpect(jsonPath("$.message").value("SensorParserConfig is missing from ParseMessageRequest"));
+
+    this.mockMvc.perform(post(sensorParserConfigUrl + "/parseMessage").with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(missingClassParseRequest))
+            .andExpect(status().isInternalServerError())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.responseCode").value(500))
+            .andExpect(jsonPath("$.message").value("SensorParserConfig must have a parserClassName"));
+
+    this.mockMvc.perform(post(sensorParserConfigUrl + "/parseMessage").with(httpBasic(user, password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(badClassParseRequest))
+            .andExpect(status().isInternalServerError())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.responseCode").value(500))
+            .andExpect(jsonPath("$.message").value("java.lang.ClassNotFoundException: badClass"));
+
+  }
+
+  private void cleanFileSystem() throws IOException {
+    File grokTempPath = new File(environment.getProperty(MetronRestConstants.GROK_TEMP_PATH_SPRING_PROPERTY));
+    if (grokTempPath.exists()) {
+      FileUtils.cleanDirectory(grokTempPath);
+      FileUtils.deleteDirectory(grokTempPath);
+    }
+    File grokPath = new File(environment.getProperty(MetronRestConstants.GROK_DEFAULT_PATH_SPRING_PROPERTY));
+    if (grokPath.exists()) {
+      FileUtils.cleanDirectory(grokPath);
+      FileUtils.deleteDirectory(grokPath);
+    }
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/StormControllerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/StormControllerIntegrationTest.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/StormControllerIntegrationTest.java
new file mode 100644
index 0000000..c592159
--- /dev/null
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/StormControllerIntegrationTest.java
@@ -0,0 +1,320 @@
+/**
+ * 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.metron.rest.controller;
+
+import org.apache.metron.common.configuration.SensorParserConfig;
+import org.apache.metron.rest.model.TopologyStatusCode;
+import org.apache.metron.rest.service.GlobalConfigService;
+import org.apache.metron.rest.service.SensorParserConfigService;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.env.Environment;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.apache.metron.rest.MetronRestConstants.TEST_PROFILE;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.hasSize;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
+import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles(TEST_PROFILE)
+public class StormControllerIntegrationTest {
+
+  @Autowired
+  private Environment environment;
+
+  @Autowired
+  private WebApplicationContext wac;
+
+  @Autowired
+  private GlobalConfigService globalConfigService;
+
+  @Autowired
+  private SensorParserConfigService sensorParserConfigService;
+
+  private MockMvc mockMvc;
+
+  private String stormUrl = "/api/v1/storm";
+  private String user = "user";
+  private String password = "password";
+
+  private String metronVersion;
+
+  @Before
+  public void setup() throws Exception {
+    this.metronVersion = this.environment.getProperty("metron.version");
+    this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).apply(springSecurity()).build();
+  }
+
+  @Test
+  public void testSecurity() throws Exception {
+    this.mockMvc.perform(get(stormUrl))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(stormUrl + "/broTest"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(stormUrl + "/parser/start/broTest"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(stormUrl + "/parser/stop/broTest"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(stormUrl + "/parser/activate/broTest"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(stormUrl + "/parser/deactivate/broTest"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get("/enrichment"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(stormUrl + "/enrichment/start"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(stormUrl + "/enrichment/stop"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(stormUrl + "/enrichment/activate"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(stormUrl + "/enrichment/deactivate"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get("/indexing"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(stormUrl + "/indexing/start"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(stormUrl + "/indexing/stop"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(stormUrl + "/indexing/activate"))
+            .andExpect(status().isUnauthorized());
+
+    this.mockMvc.perform(get(stormUrl + "/indexing/deactivate"))
+            .andExpect(status().isUnauthorized());
+  }
+
+  @Test
+  public void test() throws Exception {
+    this.mockMvc.perform(get(stormUrl).with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$", hasSize(0)));
+
+    this.mockMvc.perform(get(stormUrl + "/broTest").with(httpBasic(user,password)))
+            .andExpect(status().isNotFound());
+
+    Map<String, Object> globalConfig = globalConfigService.get();
+    if (globalConfig == null) {
+      globalConfig = new HashMap<>();
+    }
+    globalConfigService.delete();
+    sensorParserConfigService.delete("broTest");
+
+    this.mockMvc.perform(get(stormUrl + "/parser/stop/broTest?stopNow=true").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("ERROR"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.STOP_ERROR.toString()));
+
+    this.mockMvc.perform(get(stormUrl + "/parser/activate/broTest").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("ERROR"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.TOPOLOGY_NOT_FOUND.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/parser/deactivate/broTest").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("ERROR"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.TOPOLOGY_NOT_FOUND.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/parser/start/broTest").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("ERROR"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.GLOBAL_CONFIG_MISSING.name()));
+
+    globalConfigService.save(globalConfig);
+
+    this.mockMvc.perform(get(stormUrl + "/parser/start/broTest").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("ERROR"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.SENSOR_PARSER_CONFIG_MISSING.name()));
+
+    SensorParserConfig sensorParserConfig = new SensorParserConfig();
+    sensorParserConfig.setParserClassName("org.apache.metron.parsers.bro.BasicBroParser");
+    sensorParserConfig.setSensorTopic("broTest");
+    sensorParserConfigService.save(sensorParserConfig);
+
+    this.mockMvc.perform(get(stormUrl + "/parser/start/broTest").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("SUCCESS"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.STARTED.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/broTest").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.name").value("broTest"))
+            .andExpect(jsonPath("$.id", containsString("broTest")))
+            .andExpect(jsonPath("$.status").value("ACTIVE"))
+            .andExpect(jsonPath("$.latency").exists())
+            .andExpect(jsonPath("$.throughput").exists());
+
+    this.mockMvc.perform(get(stormUrl).with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$[?(@.name == 'broTest' && @.status == 'ACTIVE')]").exists());
+
+    this.mockMvc.perform(get(stormUrl + "/parser/stop/broTest?stopNow=true").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("SUCCESS"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.STOPPED.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/enrichment").with(httpBasic(user,password)))
+            .andExpect(status().isNotFound());
+
+    this.mockMvc.perform(get(stormUrl + "/enrichment/activate").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("ERROR"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.TOPOLOGY_NOT_FOUND.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/enrichment/deactivate").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("ERROR"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.TOPOLOGY_NOT_FOUND.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/enrichment/stop?stopNow=true").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("ERROR"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.STOP_ERROR.toString()));
+
+    this.mockMvc.perform(get(stormUrl + "/enrichment/start").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("SUCCESS"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.STARTED.toString()));
+
+    this.mockMvc.perform(get(stormUrl + "/enrichment/deactivate").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("SUCCESS"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.INACTIVE.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/enrichment/deactivate").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("SUCCESS"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.INACTIVE.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/enrichment/activate").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("SUCCESS"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.ACTIVE.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/enrichment").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.name").value("enrichment"))
+            .andExpect(jsonPath("$.id", containsString("enrichment")))
+            .andExpect(jsonPath("$.status").value("ACTIVE"))
+            .andExpect(jsonPath("$.latency").exists())
+            .andExpect(jsonPath("$.throughput").exists());
+
+    this.mockMvc.perform(get(stormUrl).with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$[?(@.name == 'enrichment' && @.status == 'ACTIVE')]").exists());
+
+    this.mockMvc.perform(get(stormUrl + "/enrichment/stop").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("SUCCESS"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.STOPPED.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/indexing").with(httpBasic(user,password)))
+            .andExpect(status().isNotFound());
+
+    this.mockMvc.perform(get(stormUrl + "/indexing/activate").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("ERROR"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.TOPOLOGY_NOT_FOUND.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/indexing/deactivate").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("ERROR"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.TOPOLOGY_NOT_FOUND.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/indexing/stop?stopNow=true").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("ERROR"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.STOP_ERROR.toString()));
+
+    this.mockMvc.perform(get(stormUrl + "/indexing/start").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("SUCCESS"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.STARTED.toString()));
+
+    this.mockMvc.perform(get(stormUrl + "/indexing/deactivate").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("SUCCESS"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.INACTIVE.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/indexing/activate").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("SUCCESS"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.ACTIVE.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/indexing").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$.name").value("indexing"))
+            .andExpect(jsonPath("$.id", containsString("indexing")))
+            .andExpect(jsonPath("$.status").value("ACTIVE"))
+            .andExpect(jsonPath("$.latency").exists())
+            .andExpect(jsonPath("$.throughput").exists());
+
+    this.mockMvc.perform(get(stormUrl).with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+            .andExpect(jsonPath("$[?(@.name == 'indexing' && @.status == 'ACTIVE')]").exists());
+
+    this.mockMvc.perform(get(stormUrl + "/indexing/stop").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.status").value("SUCCESS"))
+            .andExpect(jsonPath("$.message").value(TopologyStatusCode.STOPPED.name()));
+
+    this.mockMvc.perform(get(stormUrl + "/client/status").with(httpBasic(user,password)))
+            .andExpect(status().isOk())
+            .andExpect(jsonPath("$.stormClientVersionInstalled").value("1.0.1"))
+            .andExpect(jsonPath("$.parserScriptPath").value("/usr/metron/" + metronVersion + "/bin/start_parser_topology.sh"))
+            .andExpect(jsonPath("$.enrichmentScriptPath").value("/usr/metron/" + metronVersion + "/bin/start_enrichment_topology.sh"))
+            .andExpect(jsonPath("$.indexingScriptPath").value("/usr/metron/" + metronVersion + "/bin/start_elasticsearch_topology.sh"));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/TransformationControllerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/TransformationControllerIntegrationTest.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/TransformationControllerIntegrationTest.java
new file mode 100644
index 0000000..ec987e0
--- /dev/null
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/TransformationControllerIntegrationTest.java
@@ -0,0 +1,122 @@
+/**
+ * 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.metron.rest.controller;
+
+import org.adrianwalker.multilinestring.Multiline;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import static org.apache.metron.rest.MetronRestConstants.TEST_PROFILE;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.hasSize;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
+import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles(TEST_PROFILE)
+public class TransformationControllerIntegrationTest {
+
+    private String valid = "TO_LOWER(test)";
+    private String invalid = "BAD_FUNCTION(test)";
+    private String rulesJson = "[\"" + valid + "\",\"" + invalid + "\"]";
+
+    /**
+     {
+     "sensorParserConfig": { "fieldTransformations" : [{"transformation" : "STELLAR","output" : ["url_host"],"config" : {"url_host" : "TO_LOWER(URL_TO_HOST(url))"}}]},
+     "sampleData": {"url": "https://caseystella.com/blog"}
+     }
+     */
+    @Multiline
+    public static String sensorParseConfigJson;
+
+
+    @Autowired
+    private WebApplicationContext wac;
+
+    private MockMvc mockMvc;
+
+    private String transformationUrl = "/api/v1/transformation";
+    private String user = "user";
+    private String password = "password";
+
+    @Before
+    public void setup() throws Exception {
+        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).apply(springSecurity()).build();
+    }
+
+    @Test
+    public void testSecurity() throws Exception {
+        this.mockMvc.perform(post(transformationUrl + "/validate/rules").with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(rulesJson))
+                .andExpect(status().isUnauthorized());
+
+        this.mockMvc.perform(post(transformationUrl + "/validate").with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(sensorParseConfigJson))
+                .andExpect(status().isUnauthorized());
+
+        this.mockMvc.perform(get(transformationUrl + "/list"))
+                .andExpect(status().isUnauthorized());
+
+        this.mockMvc.perform(get(transformationUrl + "/list/functions"))
+                .andExpect(status().isUnauthorized());
+    }
+
+    @Test
+    public void test() throws Exception {
+        this.mockMvc.perform(post(transformationUrl + "/validate/rules").with(httpBasic(user,password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(rulesJson))
+                .andExpect(status().isOk())
+                .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+                .andExpect(jsonPath("$.['" + valid + "']").value(Boolean.TRUE))
+                .andExpect(jsonPath("$.['" + invalid + "']").value(Boolean.FALSE));
+
+        this.mockMvc.perform(post(transformationUrl + "/validate").with(httpBasic(user,password)).with(csrf()).contentType(MediaType.parseMediaType("application/json;charset=UTF-8")).content(sensorParseConfigJson))
+                .andExpect(status().isOk())
+                .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+                .andExpect(jsonPath("$.url").value("https://caseystella.com/blog"))
+                .andExpect(jsonPath("$.url_host").value("caseystella.com"));
+
+        this.mockMvc.perform(get(transformationUrl + "/list").with(httpBasic(user,password)))
+                .andExpect(status().isOk())
+                .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+                .andExpect(jsonPath("$", hasSize(greaterThan(0))));
+
+        this.mockMvc.perform(get(transformationUrl + "/list/functions").with(httpBasic(user,password)))
+                .andExpect(status().isOk())
+                .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+                .andExpect(jsonPath("$", hasSize(greaterThan(0))));
+
+        this.mockMvc.perform(get(transformationUrl + "/list/simple/functions").with(httpBasic(user,password)))
+                .andExpect(status().isOk())
+                .andExpect(content().contentType(MediaType.parseMediaType("application/json;charset=UTF-8")))
+                .andExpect(jsonPath("$", hasSize(greaterThan(0))));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/UserControllerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/UserControllerIntegrationTest.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/UserControllerIntegrationTest.java
new file mode 100644
index 0000000..9bdd439
--- /dev/null
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/controller/UserControllerIntegrationTest.java
@@ -0,0 +1,65 @@
+/**
+ * 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.metron.rest.controller;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import static org.apache.metron.rest.MetronRestConstants.TEST_PROFILE;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
+import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles(TEST_PROFILE)
+public class UserControllerIntegrationTest {
+
+    private MockMvc mockMvc;
+
+    @Autowired
+    private WebApplicationContext wac;
+
+    private String user = "user";
+    private String password = "password";
+
+    @Before
+    public void setup() throws Exception {
+        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).apply(springSecurity()).build();
+    }
+
+    @Test
+    public void test() throws Exception {
+        this.mockMvc.perform(get("/api/v1/user"))
+                .andExpect(status().isUnauthorized());
+
+        this.mockMvc.perform(get("/api/v1/user").with(httpBasic(user,password)))
+                .andExpect(status().isOk())
+                .andExpect(content().string(user));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/generator/SampleDataGenerator.java
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/generator/SampleDataGenerator.java b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/generator/SampleDataGenerator.java
new file mode 100644
index 0000000..8557035
--- /dev/null
+++ b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/generator/SampleDataGenerator.java
@@ -0,0 +1,170 @@
+/**
+ * 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.metron.rest.generator;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.PosixParser;
+import org.apache.commons.io.FileUtils;
+import org.apache.kafka.clients.producer.KafkaProducer;
+import org.apache.kafka.clients.producer.ProducerRecord;
+import org.json.simple.parser.ParseException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class SampleDataGenerator {
+
+    private Logger LOG = LoggerFactory.getLogger(SampleDataGenerator.class);
+
+    private Map<String, List<String>> sampleData = new HashMap<>();
+    private Map<String, Integer> indexes = new HashMap<>();
+    private KafkaProducer kafkaProducer;
+    private String brokerUrl;
+    private Integer num = -1;
+    private String selectedSensorType = null;
+    private Integer delay = 1000;
+
+    public void setBrokerUrl(String brokerUrl) {
+        this.brokerUrl = brokerUrl;
+    }
+
+    public void setNum(Integer num) {
+        this.num = num;
+    }
+
+    public void setSelectedSensorType(String selectedSensorType) {
+        this.selectedSensorType = selectedSensorType;
+    }
+
+    public void setDelay(Integer delay) {
+        this.delay = delay;
+    }
+
+    public static void main(String[] args) throws org.apache.commons.cli.ParseException, IOException, ParseException {
+        CommandLineParser parser = new PosixParser();
+        CommandLine cli = parser.parse(getOptions(), args);
+        Integer num = Integer.parseInt(cli.getOptionValue("n", "-1"));
+        String selectedSensorType = cli.getOptionValue("s");
+        Integer delay = Integer.parseInt(cli.getOptionValue("d", "1000"));
+        String path = cli.getOptionValue("p");
+        if (selectedSensorType == null || path == null) {
+            HelpFormatter formatter = new HelpFormatter();
+            formatter.printHelp( "sample_data_generator", getOptions());
+        } else {
+            SampleDataGenerator sampleDataGenerator = new SampleDataGenerator();
+            sampleDataGenerator.setNum(num);
+            sampleDataGenerator.setSelectedSensorType(selectedSensorType);
+            sampleDataGenerator.setDelay(delay);
+            sampleDataGenerator.generateSampleData(path);
+        }
+
+    }
+
+    private static Options getOptions() {
+        Options options = new Options();
+        options.addOption("b", "brokerUrl", true, "Kafka Broker Url");
+        options.addOption("n", "num", false, "Number of messages to emit");
+        options.addOption("s", "sensorType", true, "Emit messages to this topic");
+        options.addOption("d", "delay", false, "Number of milliseconds to wait between each message.  Defaults to 1 second");
+        options.addOption("p", "path", true, "Local path to data file");
+        return options;
+    }
+
+    public void generateSampleData(String path) throws IOException, ParseException {
+        loadData(path);
+        startClients();
+        try {
+            emitData(num, selectedSensorType, delay);
+        } finally {
+            stopClients();
+        }
+    }
+
+    private void loadData(String sampleDataPath) throws IOException, ParseException {
+        sampleData.put(selectedSensorType, FileUtils.readLines(new File(sampleDataPath)));
+        indexes.put(selectedSensorType, 0);
+    }
+
+    private void emitData(int num, String selectedSensorType, int delay) {
+        int count = 0;
+        boolean continueEmitting = false;
+        do {
+            for (String sensorType : sampleData.keySet()) {
+                if (selectedSensorType == null || selectedSensorType.equals(sensorType)) {
+                    List<String> sensorData = sampleData.get(sensorType);
+                    int index = indexes.get(sensorType);
+                    String message = sensorData.get(index++);
+                    emitSensorData(sensorType, message, delay);
+                    if (num != -1 && ++count >= num) {
+                        continueEmitting = false;
+                        break;
+                    }
+                    continueEmitting = true;
+                    if (index == sensorData.size()) {
+                        index = 0;
+                    }
+                    indexes.put(sensorType, index);
+                }
+            }
+        } while (continueEmitting);
+    }
+
+    private void emitSensorData(String sensorType, String message, int delay) {
+        try {
+            Thread.sleep(delay);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        LOG.info("Emitting " + sensorType + " message " + message);
+        emitToKafka(sensorType, message);
+    }
+
+    private void startClients() {
+        startKafka();
+    }
+
+    private void startKafka() {
+        Map<String, Object> producerConfig = new HashMap<>();
+        producerConfig.put("bootstrap.servers", brokerUrl);
+        producerConfig.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
+        producerConfig.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
+        kafkaProducer = new KafkaProducer<>(producerConfig);
+    }
+
+    private void stopClients() {
+        stopKafka();
+    }
+
+    private void stopKafka() {
+        LOG.info("Stopping Kafka producer");
+        kafkaProducer.close();
+    }
+
+    private void emitToKafka(String topic, String message) {
+        kafkaProducer.send(new ProducerRecord<String, String>(topic, message));
+    }
+
+}