Repository: incubator-metron
Updated Branches:
  refs/heads/master e416a7d78 -> e66284993


http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/mock/MockStormCLIClientWrapper.java
----------------------------------------------------------------------
diff --git 
a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/mock/MockStormCLIClientWrapper.java
 
b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/mock/MockStormCLIClientWrapper.java
new file mode 100644
index 0000000..dd21095
--- /dev/null
+++ 
b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/mock/MockStormCLIClientWrapper.java
@@ -0,0 +1,177 @@
+/**
+ * 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.mock;
+
+import org.apache.metron.rest.RestException;
+import org.apache.metron.rest.model.TopologyStatusCode;
+import org.apache.metron.rest.service.impl.StormCLIWrapper;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class MockStormCLIClientWrapper extends StormCLIWrapper {
+
+  private final Map<String, TopologyStatusCode> parsersStatus = new 
HashMap<>();
+  private TopologyStatusCode enrichmentStatus = 
TopologyStatusCode.TOPOLOGY_NOT_FOUND;
+  private TopologyStatusCode indexingStatus = 
TopologyStatusCode.TOPOLOGY_NOT_FOUND;
+
+  public Set<String> getParserTopologyNames() {
+    return parsersStatus.keySet();
+  }
+
+  public TopologyStatusCode getParserStatus(String name) {
+    TopologyStatusCode parserStatus = parsersStatus.get(name);
+    if (parserStatus == null) {
+      return TopologyStatusCode.TOPOLOGY_NOT_FOUND;
+    } else {
+      return parserStatus;
+    }
+  }
+
+  @Override
+  public int startParserTopology(String name) throws RestException {
+    TopologyStatusCode parserStatus = parsersStatus.get(name);
+    if (parserStatus == null || parserStatus == 
TopologyStatusCode.TOPOLOGY_NOT_FOUND) {
+      parsersStatus.put(name, TopologyStatusCode.ACTIVE);
+      return 0;
+    } else {
+      return 1;
+    }
+  }
+
+  @Override
+  public int stopParserTopology(String name, boolean stopNow) throws 
RestException {
+    TopologyStatusCode parserStatus = parsersStatus.get(name);
+    if (parserStatus == TopologyStatusCode.ACTIVE) {
+      parsersStatus.put(name, TopologyStatusCode.TOPOLOGY_NOT_FOUND);
+      return 0;
+    } else {
+      return 1;
+    }
+  }
+
+  public int activateParserTopology(String name) {
+    TopologyStatusCode parserStatus = parsersStatus.get(name);
+    if (parserStatus == TopologyStatusCode.INACTIVE || parserStatus == 
TopologyStatusCode.ACTIVE) {
+      parsersStatus.put(name, TopologyStatusCode.ACTIVE);
+      return 0;
+    } else {
+      return 1;
+    }
+  }
+
+  public int deactivateParserTopology(String name) {
+    TopologyStatusCode parserStatus = parsersStatus.get(name);
+    if (parserStatus == TopologyStatusCode.INACTIVE || parserStatus == 
TopologyStatusCode.ACTIVE) {
+      parsersStatus.put(name, TopologyStatusCode.INACTIVE);
+      return 0;
+    } else {
+      return 1;
+    }
+  }
+
+  public TopologyStatusCode getEnrichmentStatus() {
+    return enrichmentStatus;
+  }
+
+  @Override
+  public int startEnrichmentTopology() throws RestException {
+    if (enrichmentStatus == TopologyStatusCode.TOPOLOGY_NOT_FOUND) {
+      enrichmentStatus = TopologyStatusCode.ACTIVE;
+      return 0;
+    } else {
+      return 1;
+    }
+  }
+
+  @Override
+  public int stopEnrichmentTopology(boolean stopNow) throws RestException {
+    if (enrichmentStatus == TopologyStatusCode.ACTIVE) {
+      enrichmentStatus = TopologyStatusCode.TOPOLOGY_NOT_FOUND;
+      return 0;
+    } else {
+      return 1;
+    }
+  }
+
+  public int activateEnrichmentTopology() {
+    if (enrichmentStatus == TopologyStatusCode.INACTIVE || enrichmentStatus == 
TopologyStatusCode.ACTIVE) {
+      enrichmentStatus = TopologyStatusCode.ACTIVE;
+      return 0;
+    } else {
+      return 1;
+    }
+  }
+
+  public int deactivateEnrichmentTopology() {
+    if (enrichmentStatus == TopologyStatusCode.INACTIVE || enrichmentStatus == 
TopologyStatusCode.ACTIVE) {
+      enrichmentStatus = TopologyStatusCode.INACTIVE;
+      return 0;
+    } else {
+      return 1;
+    }
+  }
+
+  public TopologyStatusCode getIndexingStatus() {
+    return indexingStatus;
+  }
+
+  @Override
+  public int startIndexingTopology() throws RestException {
+    if (indexingStatus == TopologyStatusCode.TOPOLOGY_NOT_FOUND) {
+      indexingStatus = TopologyStatusCode.ACTIVE;
+      return 0;
+    } else {
+      return 1;
+    }
+  }
+
+  @Override
+  public int stopIndexingTopology(boolean stopNow) throws RestException {
+    if (indexingStatus == TopologyStatusCode.ACTIVE) {
+      indexingStatus = TopologyStatusCode.TOPOLOGY_NOT_FOUND;
+      return 0;
+    } else {
+      return 1;
+    }
+  }
+
+  public int activateIndexingTopology() {
+    if (indexingStatus == TopologyStatusCode.INACTIVE || indexingStatus == 
TopologyStatusCode.ACTIVE) {
+      indexingStatus = TopologyStatusCode.ACTIVE;
+      return 0;
+    } else {
+      return 1;
+    }
+  }
+
+  public int deactivateIndexingTopology() {
+    if (indexingStatus == TopologyStatusCode.INACTIVE || indexingStatus == 
TopologyStatusCode.ACTIVE) {
+      indexingStatus = TopologyStatusCode.INACTIVE;
+      return 0;
+    } else {
+      return 1;
+    }
+  }
+
+  @Override
+  protected String stormClientVersionInstalled() throws RestException {
+    return "1.0.1";
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/mock/MockStormRestTemplate.java
----------------------------------------------------------------------
diff --git 
a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/mock/MockStormRestTemplate.java
 
b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/mock/MockStormRestTemplate.java
new file mode 100644
index 0000000..ca5c1c9
--- /dev/null
+++ 
b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/mock/MockStormRestTemplate.java
@@ -0,0 +1,116 @@
+/**
+ * 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.mock;
+
+import org.apache.metron.rest.MetronRestConstants;
+import org.apache.metron.rest.model.TopologyStatus;
+import org.apache.metron.rest.model.TopologyStatusCode;
+import org.apache.metron.rest.model.TopologySummary;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.web.client.RestClientException;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class MockStormRestTemplate extends RestTemplate {
+
+  @Autowired
+  private Environment environment;
+
+  private MockStormCLIClientWrapper mockStormCLIClientWrapper;
+
+  public void setMockStormCLIClientWrapper(MockStormCLIClientWrapper 
mockStormCLIClientWrapper) {
+    this.mockStormCLIClientWrapper = mockStormCLIClientWrapper;
+  }
+
+  @Override
+  public Object getForObject(String url, Class responseType, Object... 
urlVariables) throws RestClientException {
+    Object response = null;
+    if (url.equals("http://"; + 
environment.getProperty(MetronRestConstants.STORM_UI_SPRING_PROPERTY) + 
MetronRestConstants.TOPOLOGY_SUMMARY_URL)) {
+      TopologySummary topologySummary = new TopologySummary();
+      List<TopologyStatus> topologyStatusList = new ArrayList<>();
+      for(String name: mockStormCLIClientWrapper.getParserTopologyNames()) {
+        topologyStatusList.add(getTopologyStatus(name));
+      }
+      TopologyStatusCode enrichmentStatus = 
mockStormCLIClientWrapper.getEnrichmentStatus();
+      if (enrichmentStatus != TopologyStatusCode.TOPOLOGY_NOT_FOUND) {
+        topologyStatusList.add(getTopologyStatus("enrichment"));
+      }
+      TopologyStatusCode indexingStatus = 
mockStormCLIClientWrapper.getIndexingStatus();
+      if (indexingStatus != TopologyStatusCode.TOPOLOGY_NOT_FOUND) {
+        topologyStatusList.add(getTopologyStatus("indexing"));
+      }
+      topologySummary.setTopologies(topologyStatusList.toArray(new 
TopologyStatus[topologyStatusList.size()]));
+      response =  topologySummary;
+    } else if (url.startsWith("http://"; + 
environment.getProperty(MetronRestConstants.STORM_UI_SPRING_PROPERTY) + 
MetronRestConstants.TOPOLOGY_URL + "/")){
+      String name = url.substring(url.lastIndexOf('/') + 1, 
url.length()).replaceFirst("-id", "");
+      response = getTopologyStatus(name);
+    }
+    return response;
+  }
+
+  private TopologyStatus getTopologyStatus(String name) {
+    TopologyStatus topologyStatus = new TopologyStatus();
+    topologyStatus.setName(name);
+    topologyStatus.setId(name + "-id");
+    if ("enrichment".equals(name)) {
+      
topologyStatus.setStatus(mockStormCLIClientWrapper.getEnrichmentStatus());
+    } else if ("indexing".equals(name)) {
+      topologyStatus.setStatus(mockStormCLIClientWrapper.getIndexingStatus());
+    } else {
+      
topologyStatus.setStatus(mockStormCLIClientWrapper.getParserStatus(name));
+    }
+    return topologyStatus;
+  }
+
+  @Override
+  public Object postForObject(String url, Object request, Class responseType, 
Object... uriVariables) throws RestClientException {
+    Map<String, String> result = new HashMap<>();
+    String[] urlParts = url.split("/");
+    String name = urlParts[urlParts.length - 2].replaceFirst("-id", "");
+    String action = urlParts[urlParts.length - 1];
+    int returnCode = 0;
+    if (action.equals("activate")) {
+      if (name.equals("enrichment")) {
+        returnCode = mockStormCLIClientWrapper.activateEnrichmentTopology();
+      } else if (name.equals("indexing")) {
+        returnCode = mockStormCLIClientWrapper.activateIndexingTopology();
+      } else {
+        returnCode = mockStormCLIClientWrapper.activateParserTopology(name);
+      }
+    } else if (action.equals("deactivate")){
+      if (name.equals("enrichment")) {
+        returnCode = mockStormCLIClientWrapper.deactivateEnrichmentTopology();
+      } else if (name.equals("indexing")) {
+        returnCode = mockStormCLIClientWrapper.deactivateIndexingTopology();
+      } else {
+        returnCode = mockStormCLIClientWrapper.deactivateParserTopology(name);
+      }
+    }
+    if (returnCode == 0) {
+      result.put("status", "success");
+    } else {
+      result.put("status", "error");
+    }
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/HdfsServiceTest.java
----------------------------------------------------------------------
diff --git 
a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/HdfsServiceTest.java
 
b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/HdfsServiceTest.java
new file mode 100644
index 0000000..f7e43ab
--- /dev/null
+++ 
b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/HdfsServiceTest.java
@@ -0,0 +1,117 @@
+/**
+ * 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.service;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.Path;
+import org.apache.metron.rest.config.HadoopConfig;
+import org.apache.metron.rest.service.impl.HdfsServiceImpl;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.apache.metron.rest.MetronRestConstants.TEST_PROFILE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes={HadoopConfig.class, 
HdfsServiceTest.HdfsServiceTestContextConfiguration.class})
+@ActiveProfiles(TEST_PROFILE)
+public class HdfsServiceTest {
+
+    @Configuration
+    @Profile("test")
+    static class HdfsServiceTestContextConfiguration {
+
+        @Bean
+        public HdfsService hdfsService() {
+            return new HdfsServiceImpl();
+        }
+    }
+
+    @Autowired
+    private HdfsService hdfsService;
+
+    @Test
+    public void test() throws IOException {
+        String rootDir = "./src/test/tmp";
+        File rootFile = new File(rootDir);
+        Path rootPath = new Path(rootDir);
+        if (rootFile.exists()) {
+            FileUtils.cleanDirectory(rootFile);
+            FileUtils.deleteDirectory(rootFile);
+        }
+        assertEquals(true, rootFile.mkdir());
+        String fileName1 = "fileName1";
+        String fileName2 = "fileName2";
+        Path path1 = new Path(rootDir, fileName1);
+        String value1 = "value1";
+        String value2 = "value2";
+        Path path2 = new Path(rootDir, fileName2);
+        String invalidFile = "invalidFile";
+        Path pathInvalidFile = new Path(rootDir, invalidFile);
+
+        FileStatus[] fileStatuses = hdfsService.list(new Path(rootDir));
+        assertEquals(0, fileStatuses.length);
+
+
+        hdfsService.write(path1, value1.getBytes());
+        assertEquals(value1, FileUtils.readFileToString(new File(rootDir, 
fileName1)));
+        assertEquals(value1, new String(hdfsService.read(path1)));
+
+        fileStatuses = hdfsService.list(rootPath);
+        assertEquals(1, fileStatuses.length);
+        assertEquals(fileName1, fileStatuses[0].getPath().getName());
+
+        hdfsService.write(path2, value2.getBytes());
+        assertEquals(value2, FileUtils.readFileToString(new File(rootDir, 
fileName2)));
+        assertEquals(value2, new String(hdfsService.read(path2)));
+
+        fileStatuses = hdfsService.list(rootPath);
+        assertEquals(2, fileStatuses.length);
+        assertEquals(fileName1, fileStatuses[0].getPath().getName());
+        assertEquals(fileName1, fileStatuses[0].getPath().getName());
+
+        assertEquals(true, hdfsService.delete(path1, false));
+        fileStatuses = hdfsService.list(rootPath);
+        assertEquals(1, fileStatuses.length);
+        assertEquals(fileName2, fileStatuses[0].getPath().getName());
+        assertEquals(true, hdfsService.delete(path2, false));
+        fileStatuses = hdfsService.list(rootPath);
+        assertEquals(0, fileStatuses.length);
+
+        try {
+            hdfsService.read(pathInvalidFile);
+            fail("Exception should be thrown when reading invalid file name");
+        } catch(IOException e) {
+        }
+        assertEquals(false, hdfsService.delete(pathInvalidFile, false));
+
+        FileUtils.deleteDirectory(new File(rootDir));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/SensorParserConfigTest.java
----------------------------------------------------------------------
diff --git 
a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/SensorParserConfigTest.java
 
b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/SensorParserConfigTest.java
new file mode 100644
index 0000000..561548e
--- /dev/null
+++ 
b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/service/SensorParserConfigTest.java
@@ -0,0 +1,116 @@
+/**
+ * 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.service;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.api.DeleteBuilder;
+import org.apache.curator.framework.api.GetChildrenBuilder;
+import org.apache.metron.common.configuration.ConfigurationType;
+import org.apache.metron.common.configuration.ConfigurationsUtils;
+import org.apache.metron.common.configuration.SensorParserConfig;
+import org.apache.metron.common.utils.JSONUtils;
+import org.apache.metron.rest.service.impl.SensorParserConfigServiceImpl;
+import org.apache.zookeeper.KeeperException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.powermock.api.mockito.PowerMockito.mockStatic;
+import static org.powermock.api.mockito.PowerMockito.verifyStatic;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({ConfigurationsUtils.class})
+public class SensorParserConfigTest {
+
+  @Mock
+  private GetChildrenBuilder getChildrenBuilder;
+
+  @Mock
+  private DeleteBuilder deleteBuilder;
+
+  @Mock
+  private ObjectMapper objectMapper;
+
+  @Mock
+  private CuratorFramework client;
+
+  @Mock
+  private GrokService grokService;
+
+  @InjectMocks
+  private SensorParserConfigServiceImpl sensorParserConfigService;
+
+  @Before
+  public void setUp() throws Exception {
+    MockitoAnnotations.initMocks(this);
+    Mockito.when(client.getChildren()).thenReturn(getChildrenBuilder);
+    Mockito.when(client.delete()).thenReturn(deleteBuilder);
+
+  }
+
+  @Test
+  public void test() throws Exception {
+    mockStatic(ConfigurationsUtils.class);
+    SensorParserConfig broParserConfig = new SensorParserConfig();
+    
broParserConfig.setParserClassName("org.apache.metron.parsers.bro.BasicBroParser");
+    broParserConfig.setSensorTopic("broTest");
+    
Mockito.when(objectMapper.writeValueAsString(broParserConfig)).thenReturn(new 
String(JSONUtils.INSTANCE.toJSON(broParserConfig)));
+    sensorParserConfigService.save(broParserConfig);
+    verifyStatic(times(1));
+    ConfigurationsUtils.writeSensorParserConfigToZookeeper("broTest", 
JSONUtils.INSTANCE.toJSON(broParserConfig), client);
+
+    
PowerMockito.when(ConfigurationsUtils.readSensorParserConfigFromZookeeper("broTest",
 client)).thenReturn(broParserConfig);
+    assertEquals(broParserConfig, 
sensorParserConfigService.findOne("broTest"));
+
+    SensorParserConfig squidParserConfig = new SensorParserConfig();
+    
squidParserConfig.setParserClassName("org.apache.metron.parsers.GrokParser");
+    squidParserConfig.setSensorTopic("squid");
+    
PowerMockito.when(ConfigurationsUtils.readSensorParserConfigFromZookeeper("squidTest",
 client)).thenReturn(squidParserConfig);
+
+    List<String> allTypes = new ArrayList<String>() {{
+      add("broTest");
+      add("squidTest");
+    }};
+    
Mockito.when(getChildrenBuilder.forPath(ConfigurationType.PARSER.getZookeeperRoot())).thenReturn(allTypes);
+    assertEquals(new ArrayList<SensorParserConfig>() {{ add(broParserConfig); 
add(squidParserConfig); }}, sensorParserConfigService.getAll());
+
+    
Mockito.when(getChildrenBuilder.forPath(ConfigurationType.PARSER.getZookeeperRoot())).thenThrow(new
 KeeperException.NoNodeException());
+    assertEquals(new ArrayList<>(), sensorParserConfigService.getAll());
+
+    assertTrue(sensorParserConfigService.delete("broTest"));
+    verify(deleteBuilder, 
times(1)).forPath(ConfigurationType.PARSER.getZookeeperRoot() + "/broTest");
+    
Mockito.when(deleteBuilder.forPath(ConfigurationType.PARSER.getZookeeperRoot() 
+ "/broTest")).thenThrow(new KeeperException.NoNodeException());
+    assertFalse(sensorParserConfigService.delete("broTest"));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/utils/ReadMeUtils.java
----------------------------------------------------------------------
diff --git 
a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/utils/ReadMeUtils.java
 
b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/utils/ReadMeUtils.java
new file mode 100644
index 0000000..d9522f2
--- /dev/null
+++ 
b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/utils/ReadMeUtils.java
@@ -0,0 +1,130 @@
+/**
+ * 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.utils;
+
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
+import org.reflections.Reflections;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.FileWriter;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+public class ReadMeUtils {
+
+  public static void main(String[] args) throws Exception {
+    String path;
+    if (args.length == 0) {
+      System.out.println("README output path was not set. Defaulting to 
'metron-interface/metron-rest/README.md'");
+      path = "metron-interface/metron-rest/README.md";
+    } else {
+      path = args[0];
+    }
+
+    Reflections reflections = new 
Reflections("org.apache.metron.rest.controller");
+    List<RestControllerInfo> endpoints = new ArrayList<>();
+    Set<Class<?>> controllers = 
reflections.getTypesAnnotatedWith(RestController.class);
+    for(Class<?> controller: controllers) {
+      RequestMapping controllerRequestMapping = 
controller.getAnnotation(RequestMapping.class);
+      String pathPrefix;
+      if (controllerRequestMapping == null) {
+        pathPrefix = "";
+      } else {
+        pathPrefix = controllerRequestMapping.value()[0];
+      }
+      for(Method method: controller.getDeclaredMethods()) {
+        RestControllerInfo restControllerInfo = new RestControllerInfo();
+        RequestMapping requestMapping = 
method.getAnnotation(RequestMapping.class);
+        if (requestMapping == null) {
+          throw new Exception(String.format("@RequestMapping annotation 
missing from method %s.%s. Every controller method must have a @RequestMapping 
annotation.", controller.getSimpleName(), method.getName()));
+        }
+        ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
+        if (apiOperation == null) {
+          throw new Exception(String.format("@ApiOperation annotation missing 
from method %s.%s. Every controller method must have an @ApiOperation 
annotation.", controller.getSimpleName(), method.getName()));
+        }
+        ApiResponse[] apiResponseArray;
+        ApiResponses apiResponses = method.getAnnotation(ApiResponses.class);
+        if (apiResponses == null) {
+          ApiResponse apiResponse = method.getAnnotation(ApiResponse.class);
+          if (apiResponse == null) {
+            throw new Exception(String.format("@ApiResponses or @ApiResponse 
annotation missing from method %s.%s. Every controller method must have an 
@ApiResponses or @ApiResponse annotation.", controller.getSimpleName(), 
method.getName()));
+          } else {
+            apiResponseArray = new ApiResponse[]{ apiResponse };
+          }
+        } else {
+          apiResponseArray = apiResponses.value();
+        }
+        String[] requestMappingValue = requestMapping.value();
+        if (requestMappingValue.length == 0) {
+          restControllerInfo.setPath(pathPrefix);
+        } else {
+          restControllerInfo.setPath(pathPrefix + requestMappingValue[0]);
+        }
+        restControllerInfo.setDescription(apiOperation.value());
+        RequestMethod requestMethod;
+        if (requestMapping.method().length == 0) {
+          requestMethod = RequestMethod.GET;
+        } else {
+          requestMethod = requestMapping.method()[0];
+        }
+        restControllerInfo.setMethod(requestMethod);
+        for (ApiResponse apiResponse: apiResponseArray) {
+          restControllerInfo.addResponse(apiResponse.message(), 
apiResponse.code());
+        }
+        for(Parameter parameter: method.getParameters()) {
+          if (!parameter.getType().equals(Principal.class)) {
+            ApiParam apiParam = parameter.getAnnotation(ApiParam.class);
+            if (apiParam == null) {
+              throw new Exception(String.format("@ApiParam annotation missing 
from parameter %s.%s.%s. Every controller method parameter must have an 
@ApiParam annotation.", controller.getSimpleName(), method.getName(), 
parameter.getName()));
+            }
+            restControllerInfo.addParameterDescription(apiParam.name(), 
apiParam.value());
+          }
+        }
+        endpoints.add(restControllerInfo);
+      }
+    }
+    Collections.sort(endpoints, (o1, o2) -> 
o1.getPath().compareTo(o2.getPath()));
+
+    Velocity.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
+    Velocity.setProperty("classpath.resource.loader.class", 
ClasspathResourceLoader.class.getName());
+    Velocity.init();
+
+    VelocityContext context = new VelocityContext();
+    context.put( "endpoints", endpoints );
+
+    Template template = Velocity.getTemplate("README.vm");
+    FileWriter fileWriter = new FileWriter(path);
+    template.merge( context, fileWriter );
+    fileWriter.close();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/utils/RestControllerInfo.java
----------------------------------------------------------------------
diff --git 
a/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/utils/RestControllerInfo.java
 
b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/utils/RestControllerInfo.java
new file mode 100644
index 0000000..5b7ac0e
--- /dev/null
+++ 
b/metron-interface/metron-rest/src/test/java/org/apache/metron/rest/utils/RestControllerInfo.java
@@ -0,0 +1,103 @@
+/**
+ * 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.utils;
+
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class RestControllerInfo {
+
+  public class Response {
+
+    private String message;
+    private int code;
+
+    public String getMessage() {
+      return message;
+    }
+
+    public void setMessage(String message) {
+      this.message = message;
+    }
+
+    public int getCode() {
+      return code;
+    }
+
+    public void setCode(int code) {
+      this.code = code;
+    }
+  }
+
+  private String path;
+  private String description;
+  private RequestMethod method;
+  private List<Response> responses = new ArrayList<>();
+  private Map<String, String> parameterDescriptions = new HashMap<>();
+
+  public RestControllerInfo() {}
+
+  public String getPath() {
+    return path;
+  }
+
+  public void setPath(String path) {
+    this.path = path;
+  }
+
+  public String getDescription() {
+    return description;
+  }
+
+  public void setDescription(String description) {
+    this.description = description;
+  }
+
+  public RequestMethod getMethod() {
+    return method;
+  }
+
+  public void setMethod(RequestMethod method) {
+    this.method = method;
+  }
+
+  public List<Response> getResponses() {
+    return responses;
+  }
+
+  public void addResponse(String message, int code) {
+    Response response = new Response();
+    response.setMessage(message);
+    response.setCode(code);
+    this.responses.add(response);
+  }
+
+  public Map<String, String> getParameterDescriptions() {
+    return parameterDescriptions;
+  }
+
+  public void addParameterDescription(String name, String description) {
+    parameterDescriptions.put(name, description);
+  }
+}
+
+

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/resources/README.vm
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/test/resources/README.vm 
b/metron-interface/metron-rest/src/test/resources/README.vm
new file mode 100644
index 0000000..f259a91
--- /dev/null
+++ b/metron-interface/metron-rest/src/test/resources/README.vm
@@ -0,0 +1,92 @@
+#[[#]]# Metron REST and Configuration UI
+
+This UI exposes and aids in sensor configuration.
+
+#[[##]]# Prerequisites
+
+* A running Metron cluster
+* A running instance of MySQL
+* Java 8 installed
+* Storm CLI and Metron topology scripts (start_parser_topology.sh, 
start_enrichment_topology.sh, start_elasticsearch_topology.sh) installed
+
+#[[##]]# Installation
+1. Package the Application with Maven:
+    ```
+    mvn clean package
+    ```
+
+1. Untar the archive in the target directory.  The directory structure will 
look like:
+    ```
+    bin
+      start.sh
+    lib
+      metron-rest-version.jar
+    ```
+
+1. Install Hibernate by downloading version 5.0.11.Final from 
(http://hibernate.org/orm/downloads/).  Unpack the archive and set the 
HIBERNATE_HOME environment variable to the absolute path of the top level 
directory.
+    ```
+    export HIBERNATE_HOME=/path/to/hibernate-release-5.0.11.Final
+    ```
+
+1. Install the MySQL client by downloading version 5.1.40 from 
(https://dev.mysql.com/downloads/connector/j/).  Unpack the archive and set the 
MYSQL_CLIENT_HOME environment variable to the absolute path of the top level 
directory.
+    ```
+    export MYSQL_CLIENT_HOME=/path/to/mysql-connector-java-5.1.40
+    ```
+
+1. Create a MySQL user for the Config UI 
(http://dev.mysql.com/doc/refman/5.7/en/adding-users.html).
+
+1. Create a Config UI database in MySQL with this command:
+    ```
+    CREATE DATABASE IF NOT EXISTS metronrest
+    ```
+
+1. Create an `application.yml` file with the contents of 
[application-docker.yml](src/main/resources/application-docker.yml).  
Substitute the appropriate Metron service urls (Kafka, Zookeeper, Storm, etc) 
in properties containing `${docker.host.address}` and update the 
`spring.datasource.username` and `spring.datasource.password` properties using 
the MySQL credentials from step 4.
+
+1. Start the UI with this command:
+    ```
+    ./bin/start.sh /path/to/application.yml
+    ```
+
+#[[##]]# Usage
+
+The exposed REST endpoints can be accessed with the Swagger UI at 
http://host:port/swagger-ui.html#/.  The default port is 8080 but can be 
changed in application.yml by setting "server.port" to the desired port.  Users 
can be added with this SQL statement:
+```
+use metronrest;
+insert into users (username, password, enabled) values 
('your_username','your_password',1);
+insert into authorities (username, authority) values ('your_username', 
'ROLE_USER');
+```
+Users can be added to additional groups with this SQL statement:
+```
+use metronrest;
+insert into authorities (username, authority) values ('your_username', 
'your_group');
+```
+
+#[[##]]# API
+
+Request and Response objects are JSON formatted.  The JSON schemas are 
available in the Swagger UI.
+
+|            |
+| ---------- |
+#foreach( $restControllerInfo in $endpoints )
+| [ `$restControllerInfo.getMethod().toString() 
$restControllerInfo.getPath()`](#$restControllerInfo.getMethod().toString().toLowerCase()-$restControllerInfo.getPath().toLowerCase().replaceAll("/",
 ""))|
+#end
+
+#foreach( $restControllerInfo in $endpoints )
+#[[###]]# `$restControllerInfo.getMethod().toString() 
$restControllerInfo.getPath()`
+  * Description: $restControllerInfo.getDescription()
+#if($restControllerInfo.getParameterDescriptions().size() > 0)
+  * Input:
+#end
+#foreach( $parameterDescription in 
$restControllerInfo.getParameterDescriptions().entrySet())
+    * $parameterDescription.getKey() - $parameterDescription.getValue()
+#end
+  * Returns:
+#foreach( $response in $restControllerInfo.getResponses())
+    * $response.getCode() - $response.getMessage()
+#end
+
+#end
+
+#[[##]]# License
+
+This project depends on the Java Transaction API.  See 
https://java.net/projects/jta-spec/ for more details.

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/metron-rest/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/metron-interface/metron-rest/src/test/resources/log4j.properties 
b/metron-interface/metron-rest/src/test/resources/log4j.properties
new file mode 100644
index 0000000..492cecf
--- /dev/null
+++ b/metron-interface/metron-rest/src/test/resources/log4j.properties
@@ -0,0 +1,16 @@
+#   Licensed 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.
+
+log4j.rootLogger=ERROR, stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd'T'HH:mm:ss.SSS} 
%-5p [%c] - %m%n
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/metron-interface/pom.xml
----------------------------------------------------------------------
diff --git a/metron-interface/pom.xml b/metron-interface/pom.xml
new file mode 100644
index 0000000..078da19
--- /dev/null
+++ b/metron-interface/pom.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>metron-interface</artifactId>
+    <packaging>pom</packaging>
+    <name>metron-interface</name>
+    <parent>
+        <groupId>org.apache.metron</groupId>
+        <artifactId>Metron</artifactId>
+        <version>0.3.0</version>
+    </parent>
+    <description>Interfaces for Metron</description>
+    <url>https://metron.incubator.apache.org/</url>
+    <scm>
+        
<connection>scm:git:https://git-wip-us.apache.org/repos/asf/incubator-metron.git</connection>
+        
<developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/incubator-metron.git</developerConnection>
+        <tag>HEAD</tag>
+        <url>https://git-wip-us.apache.org/repos/asf/incubator-metron</url>
+    </scm>
+    <licenses>
+        <license>
+            <name>The Apache Software License, Version 2.0</name>
+            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+    <modules>
+        <module>metron-rest</module>
+        <module>metron-rest-client</module>
+    </modules>
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.12</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.adrianwalker</groupId>
+            <artifactId>multiline-string</artifactId>
+            <version>0.1.2</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+        </plugins>
+    </build>
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-pmd-plugin</artifactId>
+                <version>3.3</version>
+                <configuration>
+                    <targetJdk>${global_java_version}</targetJdk>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>emma-maven-plugin</artifactId>
+                <version>1.0-alpha-3</version>
+                <inherited>true</inherited>
+            </plugin>
+        </plugins>
+    </reporting>
+    <repositories>
+        <repository>
+            <id>multiline-release-repo</id>
+            
<url>https://raw.github.com/benelog/multiline/master/maven-repository</url>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-metron/blob/55b3e7ea/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index db28adb..3a8eb9b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,6 +29,7 @@
             <module>metron-platform</module>
             <module>metron-deployment</module>
             <module>metron-docker</module>
+            <module>metron-interface</module>
     </modules>
 
     <repositories>


Reply via email to