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));
+ }
+
+}