From 4c380b426f19899d6b00c940f9f700ce228213fa Mon Sep 17 00:00:00 2001 From: Deklan Dieterly Date: Fri, 11 Jul 2014 14:49:10 -0600 Subject: [PATCH] Add integration tests using docker. --- pom.xml | 11 + .../MeasurementInfluxDbRepositoryImpl.java | 11 + src/main/resources/mon-api-config.yml | 12 +- .../mon/integration/docker/InfluxDBTest.java | 464 ++++++++++++++++++ 4 files changed, 492 insertions(+), 6 deletions(-) create mode 100644 src/test/java/com/hpcloud/mon/integration/docker/InfluxDBTest.java diff --git a/pom.xml b/pom.xml index 4ae97f2b4..69acfb126 100644 --- a/pom.xml +++ b/pom.xml @@ -193,6 +193,17 @@ 1.9.5 test + + com.github.docker-java + docker-java + 0.9.1-SNAPSHOT + test + + + com.jayway.restassured + rest-assured + 2.3.2 + diff --git a/src/main/java/com/hpcloud/mon/infrastructure/persistence/influxdb/MeasurementInfluxDbRepositoryImpl.java b/src/main/java/com/hpcloud/mon/infrastructure/persistence/influxdb/MeasurementInfluxDbRepositoryImpl.java index ef57cb9ce..e63f53882 100644 --- a/src/main/java/com/hpcloud/mon/infrastructure/persistence/influxdb/MeasurementInfluxDbRepositoryImpl.java +++ b/src/main/java/com/hpcloud/mon/infrastructure/persistence/influxdb/MeasurementInfluxDbRepositoryImpl.java @@ -59,7 +59,18 @@ public class MeasurementInfluxDbRepositoryImpl implements MeasurementRepository Map dimensions, DateTime startTime, @Nullable DateTime endTime) throws Exception { + logger.debug("tenantId: {}", tenantId); + logger.debug("name: {}", name); + if (dimensions != null) { + for (String key : dimensions.keySet()) { + logger.debug("key: {}, value: {}", key, dimensions.get(key)); + } + } + logger.debug("startTime: {}", startTime); + logger.debug("endTime: {}", endTime); + String dimsPart = Utils.WhereClauseBuilder.buildDimsPart(dimensions); + String timePart = Utils.WhereClauseBuilder.buildTimePart(startTime, endTime); String query = String.format("select value " + "from %1$s " + "where tenant_id = '%2$s' %3$s %4$s", diff --git a/src/main/resources/mon-api-config.yml b/src/main/resources/mon-api-config.yml index 261b53ad8..5dc877cc0 100644 --- a/src/main/resources/mon-api-config.yml +++ b/src/main/resources/mon-api-config.yml @@ -13,18 +13,18 @@ eventsTopic: events databaseConfiguration: # vertica | influxdb #databaseType: influxdb - databaseType: vertica + databaseType: influxdb kafka: brokerUris: - - 192.168.10.4:9092 + - 192.168.59.103:9092 zookeeperUris: - - 192.168.10.4:2181 + - 192.168.59.103:2181 healthCheckTopic: healthcheck mysql: driverClass: com.mysql.jdbc.Driver - url: jdbc:mysql://192.168.10.4:3306/mon?connectTimeout=5000&autoReconnect=true + url: jdbc:mysql://192.168.59.103:3306/mon?connectTimeout=5000&autoReconnect=true user: monapi password: password maxWaitForConnection: 1s @@ -49,12 +49,12 @@ vertica: influxDB: name: mon replicationFactor: 1 - url: http://localhost:8086 + url: http://192.168.59.103:8086 user: root password: root middleware: - enabled: true + enabled: false serviceIds: 100 endpointIds: 160 serverVIP: 192.168.10.5 diff --git a/src/test/java/com/hpcloud/mon/integration/docker/InfluxDBTest.java b/src/test/java/com/hpcloud/mon/integration/docker/InfluxDBTest.java new file mode 100644 index 000000000..7911a4b6f --- /dev/null +++ b/src/test/java/com/hpcloud/mon/integration/docker/InfluxDBTest.java @@ -0,0 +1,464 @@ +package com.hpcloud.mon.integration.docker; + +import com.github.dockerjava.client.DockerClient; +import com.github.dockerjava.client.DockerException; +import com.github.dockerjava.client.model.ContainerCreateResponse; +import com.github.dockerjava.client.model.ExposedPort; +import com.github.dockerjava.client.model.Ports; +import com.sun.jersey.api.client.ClientResponse; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; + +import static com.jayway.restassured.RestAssured.given; +import static com.jayway.restassured.path.json.JsonPath.from; + +@Test(groups = "integration", enabled = false) +public class InfluxDBTest { + + private final static String DDIETERLY_INFLUXDB_V1 = "ddieterly/influxdb:v1"; + private static final String DDIETERLY_MYSQL_V1 = "ddieterly/mysql:v1"; + private static final String DDIETERLY_MYSQL_V1_RUN_CMD = "/usr/bin/mysqld_safe"; + private static final String DDIETERLY_KAFKA_V1 = "ddieterly/kafka:v1"; + private static final String DDIETERLY_KAFKA_V1_RUN_CMD = "/run.sh"; + private static final String DOCKER_IP = "192.168.59.103"; + private static final String DOCKER_PORT = "2375"; + private static final String DOCKER_URL = "http://" + DOCKER_IP + ":" + DOCKER_PORT; + private static final int MAX_CONNECT_PORT_TRIES = 20000; + + private static final String API_JAR = "./target/mon-api-0.1.0-1405013923672-ddd828.jar"; + + private final static DockerClient dockerClient = new DockerClient(DOCKER_URL); + private Process apiProcess = null; + private ContainerCreateResponse influxDBContainer; + private ContainerCreateResponse mysqlContainer; + private ContainerCreateResponse kafkaContainer; + + @BeforeClass + public void setup() throws DockerException, IOException { + + runKafka(); + + runInfluxDB(); + + runMYSQL(); + + runAPI(); + + } + + private void runAPI() throws IOException { + + apiProcess = Runtime.getRuntime().exec(new String[]{"java", "-cp", API_JAR, + "com.hpcloud.mon.MonApiApplication", "server", "src/test/resources/mon-api-config.yml"}); + + waitForPortReady("localhost", 8080); + } + + private void waitForPortReady(String host, int port) { + + Socket s = null; + boolean isPortReady = false; + int tryCount = 0; + while (!isPortReady) { + + if (tryCount >= MAX_CONNECT_PORT_TRIES) { + System.err.println("Failed to connect to host [" + host + "] on port [" + port + "] in " + + "[" + tryCount + "] tries"); + tearDown(); + System.exit(-1); + } + + try { + s = new Socket(); + s.setReuseAddress(true); + SocketAddress sa = new InetSocketAddress(host, port); + s.connect(sa, 50000); + isPortReady = true; + System.out.println("Took " + tryCount + " tries to connect to host [" + host + "] on port" + + "[" + port + "]"); + } catch (Exception e) { + tryCount++; + } + } + + if (s != null) { + try { + s.close(); + } catch (Exception e) { + System.err.print(e); + } + } + } + + private void runKafka() { + + ClientResponse response = dockerClient.pullImageCmd(DDIETERLY_KAFKA_V1).exec(); + + ExposedPort tcp2181 = ExposedPort.tcp(2181); + ExposedPort tcp9092 = ExposedPort.tcp(9092); + + kafkaContainer = dockerClient.createContainerCmd(DDIETERLY_KAFKA_V1).withCmd(new + String[]{DDIETERLY_KAFKA_V1_RUN_CMD, DOCKER_IP}).withExposedPorts(tcp2181, tcp9092).exec(); + + Ports portBindings2 = new Ports(); + portBindings2.bind(tcp2181, Ports.Binding(2181)); + portBindings2.bind(tcp9092, Ports.Binding(9092)); + + dockerClient.startContainerCmd(kafkaContainer.getId()).withPortBindings(portBindings2).exec(); + + waitForPortReady(DOCKER_IP, 2181); + waitForPortReady(DOCKER_IP, 9092); + } + + private void runMYSQL() { + + ClientResponse response = dockerClient.pullImageCmd(DDIETERLY_MYSQL_V1).exec(); + + ExposedPort tcp3306 = ExposedPort.tcp(3306); + + mysqlContainer = dockerClient.createContainerCmd(DDIETERLY_MYSQL_V1).withCmd(new + String[]{DDIETERLY_MYSQL_V1_RUN_CMD}).withExposedPorts(tcp3306).exec(); + + Ports portBindings1 = new Ports(); + portBindings1.bind(tcp3306, Ports.Binding(3306)); + + dockerClient.startContainerCmd(mysqlContainer.getId()).withPortBindings(portBindings1).exec(); + + waitForPortReady(DOCKER_IP, 3306); + } + + private void runInfluxDB() { + + ClientResponse response = dockerClient.pullImageCmd(DDIETERLY_INFLUXDB_V1).exec(); + + ExposedPort tcp8083 = ExposedPort.tcp(8083); + ExposedPort tcp8086 = ExposedPort.tcp(8086); + ExposedPort tcp8090 = ExposedPort.tcp(8090); + ExposedPort tcp8099 = ExposedPort.tcp(8099); + + influxDBContainer = dockerClient.createContainerCmd(DDIETERLY_INFLUXDB_V1).withExposedPorts + (tcp8083, tcp8086, tcp8090, tcp8099).exec(); + + Ports portBindings = new Ports(); + portBindings.bind(tcp8083, Ports.Binding(8083)); + portBindings.bind(tcp8086, Ports.Binding(8086)); + portBindings.bind(tcp8090, Ports.Binding(8090)); + portBindings.bind(tcp8099, Ports.Binding(8099)); + + dockerClient.startContainerCmd(influxDBContainer.getId()).withPortBindings(portBindings).exec(); + + waitForPortReady(DOCKER_IP, 8086); + } + + @Test + public void alarmCreateTest() { + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").body("{\"alarm_actions\": " + + "[\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "" + "\"ok_actions\": [\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "\"name\": \"test-alarm-1\", \"description\": \"test-alarm-description\", " + + "\"undetermined_actions\": [\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "\"expression\": \"max(cpu_system_perc) > 0 and max(load_avg_1_min{hostname=mini-mon}) > " + + "0\", \"severity\": \"low\"}").post("/v2.0/alarms").then().assertThat().statusCode(201); + + } + + @Test + public void alarmDeleteTest() { + + String json = given().headers("Accept", "application/json", "Content-Type", + "application/json", "X-Auth-Token", "82510970543135").body("{\"alarm_actions\": " + + "[\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "" + "\"ok_actions\": [\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "\"name\": \"test-alarm-2\", \"description\": \"test-alarm-description\", " + + "\"undetermined_actions\": [\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "\"expression\": \"max(cpu_system_perc) > 0 and max(load_avg_1_min{hostname=mini-mon}) > " + + "0\", \"severity\": \"low\"}").post("/v2.0/alarms").asString(); + + String alarmId = from(json).get("id"); + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").delete("/v2.0/alarms/" + alarmId).then().assertThat() + .statusCode(204); + + } + + @Test + public void alarmHistoryTest() { + + String json = given().headers("Accept", "application/json", "Content-Type", + "application/json", "X-Auth-Token", "82510970543135").body("{\"alarm_actions\": " + + "[\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "" + "\"ok_actions\": [\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "\"name\": \"test-alarm-3\", \"description\": \"test-alarm-description\", " + + "\"undetermined_actions\": [\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "\"expression\": \"max(cpu_system_perc) > 0 and max(load_avg_1_min{hostname=mini-mon}) > " + + "0\", \"severity\": \"low\"}").post("/v2.0/alarms").asString(); + + String alarmId = from(json).get("id"); + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").get("v2.0/alarms/" + alarmId + "/state-history").then() + .assertThat().statusCode(200); + + } + + @Test + public void alarmListTest() { + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").get("/v2.0/alarms").then().assertThat().statusCode(200); + + } + + @Test + public void alarmPatchTest() { + + String json = given().headers("Accept", "application/json", "Content-Type", + "application/json", "X-Auth-Token", "82510970543135").body("{\"alarm_actions\": " + + "[\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "" + "\"ok_actions\": [\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "\"name\": \"test-alarm-4\", \"description\": \"test-alarm-description\", " + + "\"undetermined_actions\": [\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "\"expression\": \"max(cpu_system_perc) > 0 and max(load_avg_1_min{hostname=mini-mon}) > " + + "0\", \"severity\": \"low\"}").post("/v2.0/alarms").asString(); + + String alarmId = from(json).get("id"); + + given().headers("Accept", "application/json", "Content-Type", "application/json-patch+json", + "X-Auth-Token", "82510970543135").body("{}").patch("v2.0/alarms/" + alarmId).then() + .assertThat().statusCode(200); + + } + + @Test + public void alarmShowTest() { + + String json = given().headers("Accept", "application/json", "Content-Type", + "application/json", "X-Auth-Token", "82510970543135").body("{\"alarm_actions\": " + + "[\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "" + "\"ok_actions\": [\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "\"name\": \"test-alarm-5\", \"description\": \"test-alarm-description\", " + + "\"undetermined_actions\": [\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "\"expression\": \"max(cpu_system_perc) > 0 and max(load_avg_1_min{hostname=mini-mon}) > " + + "0\", \"severity\": \"low\"}").post("/v2.0/alarms").asString(); + + String alarmId = from(json).get("id"); + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").get("v2.0/alarms/" + alarmId).then().assertThat() + .statusCode(200); + + } + + @Test + public void alarmUpdateTest() { + + String json = given().headers("Accept", "application/json", "Content-Type", + "application/json", "X-Auth-Token", "82510970543135").body("{\"alarm_actions\": " + + "[\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "" + "\"ok_actions\": [\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "\"name\": \"test-alarm-6\", \"description\": \"test-alarm-description\", " + + "\"undetermined_actions\": [\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "\"expression\": \"max(cpu_system_perc) > 0 and max(load_avg_1_min{hostname=mini-mon}) > " + + "0\", \"severity\": \"low\"}").post("/v2.0/alarms").asString(); + + String alarmId = from(json).get("id"); + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").body("{\"alarm_actions\": " + + "[\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "" + "\"ok_actions\": [\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "\"name\": \"test-alarm-6\", \"description\": \"test-alarm-description\", " + + "\"undetermined_actions\": [\"044fa9be-36ef-4e51-a1d9-67ec31734908\"], " + + "\"expression\": \"max(cpu_system_perc) > 0 and max(load_avg_1_min{hostname=mini-mon}) > " + + "0\", \"severity\": \"low\", \"actions_enabled\":\"true\", " + + "\"state\": \"alarm\"}").put("/v2" + + ".0/alarms/" + alarmId).then().assertThat().statusCode(200); + + } + + @Test + public void measurementListTest() { + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").param("start_time", "1970-01-01T00:00:00Z").param + ("name", "cpu_system_perc").get("v2.0/metrics/measurements").then().assertThat() + .statusCode(200); + + } + + @Test + public void metricCreateTest() { + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").body("{\"timestamp\": 0, \"name\": \"test-metric-1\", " + + "\"value\": 1234.5678, \"dimensions\": {\"foo\": \"bar\", " + + "\"biz\": \"baz\"}}").post("/v2.0/metrics ").then().assertThat().statusCode(204); + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").param("start_time", "1970-01-01T00:00:00Z").param + ("name", "test-metric-1").get("v2.0/metrics/measurements").then().assertThat().statusCode + (200); + + + } + + @Test + public void metricCreateRawTest() { + + long unixTime = System.currentTimeMillis() / 1000L; + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").body("{\"timestamp\":\"" + unixTime + "\" , " + + "\"name\": \"test-metric-2\", " + + "\"value\": 1234.5678, \"dimensions\": {\"foo\": \"bar\", " + + "\"biz\": \"baz\"}}").post("/v2.0/metrics ").then().assertThat().statusCode(204); + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").param("start_time", "1970-01-01T00:00:00Z").param + ("name", "test-metric-2").get("v2.0/metrics/measurements").then().assertThat().statusCode + (200); + + } + + @Test + public void metricList() { + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").get("/v2.0/metrics").then().assertThat().statusCode(200); + + } + + @Test + public void metricStatisticsTest() { + + String[] stats = new String[]{"avg", "min", "max", "count", "sum"}; + + for (String stat : stats) { + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").param("start_time", "1970-01-01T00:00:00Z").param + ("statistics", stat).param("name", "cpu_system_perc").get("/v2.0/metrics/statistics") + .then().assertThat().statusCode(200); + } + + } + + @Test + public void notificationCreateTest() { + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").body("{\"type\": \"email\", " + + "" + "\"name\": \"test-notification-1\", \"address\": \"jdoe@gmail.com\"}").post("/v2" + + ".0/notification-methods").then().assertThat().statusCode(201); + } + + @Test + public void notificationDeleteTest() { + + String json = given().headers("Accept", "application/json", "Content-Type", + "application/json", "X-Auth-Token", "82510970543135").body("{\"type\": \"email\", " + + "" + "\"name\": \"test-notification-2\", \"address\": \"jdoe@gmail.com\"}").post("/v2" + + ".0/notification-methods").asString(); + + String notificationId = from(json).get("id"); + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").delete("/v2.0/notification-methods/" + notificationId) + .then().assertThat().statusCode(204); + + + } + + @Test + public void notificationList() { + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").get("/v2.0/notification-methods").then().assertThat() + .statusCode(200); + + } + + @Test + public void notificationShowTest() { + + String json = given().headers("Accept", "application/json", "Content-Type", + "application/json", "X-Auth-Token", "82510970543135").body("{\"type\": \"email\", " + + "" + "\"name\": \"test-notification-3\", \"address\": \"jdoe@gmail.com\"}").post("/v2" + + ".0/notification-methods").asString(); + + String notificationId = from(json).get("id"); + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").get("/v2.0/notification-methods/" + notificationId) + .then().assertThat().statusCode(200); + + } + + @Test + public void notificationUpdateTest() { + + String json = given().headers("Accept", "application/json", "Content-Type", + "application/json", "X-Auth-Token", "82510970543135").body("{\"type\": \"email\", " + + "" + "\"name\": \"test-notification-4\", \"address\": \"jdoe@gmail.com\"}").post("/v2" + + ".0/notification-methods").asString(); + + String notificationId = from(json).get("id"); + + given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").body("{\"type\": \"email\", " + + "" + "\"name\": \"test-notification-4\", \"address\": \"jsmith@gmail.com\"}").put("/v2" + + ".0/notification-methods/" + notificationId).then().assertThat().statusCode(200); + + json = given().headers("Accept", "application/json", "Content-Type", "application/json", + "X-Auth-Token", "82510970543135").get("/v2.0/notification-methods/" + notificationId) + .asString(); + + String address = from(json).get("address"); + + assert (address.equals("jsmith@gmail.com")); + + + } + + @AfterClass + public void tearDown() { + + stopAPI(); + + stopMYSQL(); + + stopInfluxDB(); + + stopKafka(); + + + } + + private void stopAPI() { + apiProcess.destroy(); + } + + private void stopKafka() { + dockerClient.stopContainerCmd(kafkaContainer.getId()).withTimeout(2).exec(); + + } + + private void stopMYSQL() { + dockerClient.stopContainerCmd(mysqlContainer.getId()).withTimeout(2).exec(); + + + } + + private void stopInfluxDB() { + dockerClient.stopContainerCmd(influxDBContainer.getId()).withTimeout(2).exec(); + + } +}