Skip to content
Snippets Groups Projects
Commit 4b4c1b0f authored by René Schöne's avatar René Schöne
Browse files

Begin with integration test.

parent 051b33d4
No related branches found
No related tags found
No related merge requests found
......@@ -24,6 +24,7 @@ import java.util.Objects;
*/
public class ParserUtils {
public static final String UNKNOWN_GROUP_NAME = "Unknown";
private static boolean verboseLoading = false;
private static final Logger logger = LogManager.getLogger(ParserUtils.class);
......@@ -172,7 +173,7 @@ public class ParserUtils {
*/
public static void createUnknownGroup(OpenHAB2Model model, Collection<Item> danglingItems) {
Group unknownGroup = new Group();
unknownGroup.setID("Unknown");
unknownGroup.setID(UNKNOWN_GROUP_NAME);
model.addGroup(unknownGroup);
danglingItems.forEach(unknownGroup::addItem);
logger.info("Created new {}", unknownGroup.prettyPrint().trim());
......@@ -234,4 +235,21 @@ public class ParserUtils {
return result;
}
public static Item parseItem(String definition)
throws IllegalArgumentException, IOException, Parser.Exception {
StringReader reader = new StringReader(definition);
EraserScanner scanner = new EraserScanner(reader);
EraserParser parser = new EraserParser();
Root root = (Root) parser.parse(scanner);
reader.close();
int size = root.getOpenHAB2Model().items().size();
if (size == 0) {
throw new IllegalArgumentException("Model does not contain any items!");
}
if (size > 1) {
logger.warn("Model does contain {} items, ignoring all but the first.", size);
}
return root.getOpenHAB2Model().items().get(0);
}
}
......@@ -3,12 +3,15 @@ package de.tudresden.inf.st.eraser.spark;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.tudresden.inf.st.eraser.jastadd.model.*;
import de.tudresden.inf.st.eraser.util.JavaUtils;
import de.tudresden.inf.st.eraser.util.ParserUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.jetty.http.HttpStatus;
import spark.Request;
import spark.Response;
import spark.Spark;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
......@@ -41,14 +44,20 @@ public class Application {
Spark.path("/", () -> Spark.before((request, response) -> logger.debug(request.pathInfo())));
Spark.path("/activity", () -> {
//--- GET /activity ---
Spark.get("",
(request, response) -> wrapActivityList(root.getMachineLearningRoot().getActivityList()),
mapper::writeValueAsString);
//--- GET /activity/current ---
Spark.get("/current",
(request, response) -> JavaUtils.ifPresentOrElseReturn(root.currentActivity(),
this::wrapActivity,
() -> makeError(response, 204, "No activity recognized.")),
mapper::writeValueAsString);
//--- PUT /activity/current ---
Spark.put("/current", (request, response) -> {
logger.info("request body: '{}', params: '{}', length={}", request.body(), request.params(), request.contentLength());
if (!root.getMachineLearningRoot().hasActivityRecognition()) {
......@@ -62,6 +71,8 @@ public class Application {
return makeError(response, 501, "Activity not editable for " + activityRecognition.getClass().getSimpleName());
}
});
//--- GET /activity/:identifier ---
Spark.get("/:identifier",
(request, response) ->
JavaUtils.ifPresentOrElseReturn(root.resolveActivity(paramAsInt(request, "identifier")),
......@@ -71,9 +82,13 @@ public class Application {
});
Spark.path("/events", () -> {
//--- GET /events ---
Spark.get("",
(request, response) -> wrapChangeEventList(root.getMachineLearningRoot().getChangeEventList()),
mapper::writeValueAsString);
//--- GET /events/:identifier ---
Spark.get("/:identifier",
(request, response) ->
JavaUtils.ifPresentOrElseReturn(root.resolveChangeEvent(paramAsInt(request, "identifier")),
......@@ -83,14 +98,39 @@ public class Application {
});
Spark.path("/model", () -> {
//--- GET /model/full ---
Spark.get("/full", (request, response) -> {
response.type("text/plain");
return root.prettyPrint();
});
Spark.get("/items",
Spark.path("/items", () -> {
//--- GET /model/items ---
Spark.get("",
(request, response) -> wrapItemList(root.getOpenHAB2Model().items()),
mapper::writeValueAsString);
Spark.put("/items/:identifier/state", (request, response) -> {
Spark.path("/:identifier", () -> {
Spark.put("", (request, response) -> {
OpenHAB2Model openHAB2Model = root.getOpenHAB2Model();
Item item = ParserUtils.parseItem(request.body());
if (!openHAB2Model.resolveItem(item.getID()).isPresent()) {
JavaUtils.ifPresentOrElse(
root.getOpenHAB2Model().resolveGroup(ParserUtils.UNKNOWN_GROUP_NAME),
group -> group.addItem(item),
() -> ParserUtils.createUnknownGroup(root.getOpenHAB2Model(), Collections.singletonList(item)));
response.status(201);
}
return "OK";
});
//--- GET /model/items/:identifier/state ---
Spark.get("/state", (request, response) ->
safeItemRoute(request, response, Item::getStateAsString));
//--- PUT /model/items/:identifier/state ---
Spark.put("/state", (request, response) -> {
logger.info("request body: '{}', params: '{}', length={}", request.body(), request.params(), request.contentLength());
return safeItemRoute(request, response,
item -> {
......@@ -103,13 +143,18 @@ public class Application {
}
});
});
Spark.get("/items/:identifier/history",
});
//--- GET /model/items/:identifier/history ---
Spark.get("/:identifier/history",
(request, response) -> {
logger.info("request body: '{}', params: '{}', length={}", request.body(), request.params(), request.contentLength());
return safeItemRoute(request, response, item -> makeHistory(item, response));
});
});
});
//--- POST /system/exit ---
Spark.post("/system/exit", (request, response) -> {
try {
lock.lock();
......
/build/
logs/
apply plugin: 'application'
dependencies {
testCompile project(':eraser-base')
testCompile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.8'
testCompile group: 'org.apache.httpcomponents', name: 'fluent-hc', version: '4.5.8'
testCompile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.8'
}
run {
mainClassName = 'de.tudresden.inf.st.eraser.integration_test.Main'
standardInput = System.in
if (project.hasProperty("appArgs")) {
args Eval.me(appArgs)
}
}
sourceSets {
main {
java {
srcDir 'src/main/java'
}
}
}
package de.tudresden.inf.st.eraser.integration_test;
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="Console">
<PatternLayout pattern="%highlight{%d{HH:mm:ss.SSS} %-5level} %c{1.} - %msg%n"/>
</Console>
<RollingFile name="RollingFile" fileName="logs/eraser.log"
filePattern="logs/eraser-%i.log">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n"/>
<Policies>
<OnStartupTriggeringPolicy/>
</Policies>
<DefaultRolloverStrategy max="20"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
package de.tudresden.inf.st.eraser.integration_test;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.tudresden.inf.st.eraser.openhab2.data.ItemData;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.fluent.Form;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
import org.apache.http.util.EntityUtils;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.io.IOException;
import java.util.Arrays;
import java.util.function.Function;
import static org.hamcrest.Matchers.either;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
/**
* Integration test to check openHAB-binding for eraser works well together with eraser itself.
*
* @author rschoene - Initial contribution
*/
@RunWith(Parameterized.class)
public class ItemTest {
private static final String OPENHAB_ITEM_URI = "http://localhost:8080/rest/items/";
private static final String ERASER_ITEM_URI = "http://localhost:4567/model/items/";
private static final String DIMMER_ITEM = "dimmer_item";
private static final String NUMBER_ITEM = "number_item";
private static final String SWITCH_ITEM = "switch_item";
private static final String COLOR_ITEM = "color_item";
@BeforeClass
public static void ensureItemsAreCreated() throws IOException {
ensureItemCreated(DIMMER_ITEM, "Dimmer");
ensureItemCreated(NUMBER_ITEM, "Number");
ensureItemCreated(SWITCH_ITEM, "Switch");
ensureItemCreated(COLOR_ITEM, "Color");
}
private static void ensureItemCreated(String name, String type) throws IOException {
// Create at openHAB
HttpResponse responseOpenHAB = Request.Put(OPENHAB_ITEM_URI + name)
.bodyForm(Form.form().add("type", type).add("name", name).build())
.execute().returnResponse();
assertThat(
responseOpenHAB.getStatusLine().getStatusCode(),
either(equalTo(HttpStatus.SC_CREATED))
.or(equalTo(HttpStatus.SC_OK)));
// Create at eraser
HttpResponse responseEraser = Request.Put(ERASER_ITEM_URI + name)
.bodyString(type + " Item: id=\"" + name + "\"", ContentType.TEXT_PLAIN)
.execute().returnResponse();
assertThat(
responseEraser.getStatusLine().getStatusCode(),
equalTo(HttpStatus.SC_CREATED));
}
@Test
public void itemAvailable() throws IOException {
String name = "Tradfri_2_small_tv";
ItemData itemData = Request.Get( OPENHAB_ITEM_URI + name )
.execute().handleResponse(
response -> retrieveResourceFromResponse(response, ItemData.class));
assertThat(itemData.type, equalTo("Dimmer"));
}
@Test
public void dimmerSetStateAtOpenHAB() throws IOException {
String name = "Tradfri_2_small_tv";
double newValue = 3.0;
// set item state with openHAB REST API
HttpResponse httpResponse = Request.Put(OPENHAB_ITEM_URI + name + "/state")
.bodyString(Double.toString(newValue), ContentType.TEXT_PLAIN)
.execute().returnResponse();
assertThat(
httpResponse.getStatusLine().getStatusCode(),
equalTo(HttpStatus.SC_ACCEPTED));
// check whether state was set correctly
String responseOpenHAB = Request.Get(OPENHAB_ITEM_URI + name + "/state")
.execute().returnContent().asString();
assertThat(Double.parseDouble(responseOpenHAB), equalTo(newValue));
// check whether state was updated on eraser side
String responseEraser = Request.Get(ERASER_ITEM_URI + name + "/state")
.execute().returnContent().asString();
assertThat(Double.parseDouble(responseEraser), equalTo(newValue));
}
@Test
public void dimmerSetStateAtEraser() throws IOException {
String name = "Tradfri_2_small_tv";
double newValue = 25.0;
// set item state with eraser REST API
String uri = ERASER_ITEM_URI + name + "/state";
System.out.println(uri);
HttpResponse httpResponse = Request.Put(uri)
.bodyString(Double.toString(newValue), ContentType.TEXT_PLAIN)
.execute().returnResponse();
assertThat(
httpResponse.getStatusLine().getStatusCode(),
equalTo(HttpStatus.SC_OK));
// check whether state was set correctly
String responseEraser = Request.Get(ERASER_ITEM_URI + name + "/state")
.execute().returnContent().asString();
assertThat(Double.parseDouble(responseEraser), equalTo(newValue));
// check whether state was updated on openHAB side
String responseOpenHAB = Request.Get(OPENHAB_ITEM_URI + name + "/state")
.execute().returnContent().asString();
assertThat(Double.parseDouble(responseOpenHAB), equalTo(newValue));
}
private static <T> T retrieveResourceFromResponse(HttpResponse response, Class<T> clazz)
throws IOException {
String jsonFromResponse = EntityUtils.toString(response.getEntity());
ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return mapper.readValue(jsonFromResponse, clazz);
}
private static <T> Object[] d(String name, T initialValue, Function<T, String> toString,
Function<String, T> fromString) {
return new Object[]{name, initialValue, toString, fromString};
}
@Parameterized.Parameters(name= "{index}: {0}")
public static Iterable<Object[]> data() {
return Arrays.asList(
d(DIMMER_ITEM, 25.0, d -> Double.toString(d), Double::parseDouble),
d(NUMBER_ITEM, 4, i -> Integer.toString(i), Integer::parseInt),
d(SWITCH_ITEM, "ON", Function.identity(), Function.identity()),
d(COLOR_ITEM, "1,2,3", Function.identity(), Function.identity())
);
}
}
......@@ -19,3 +19,4 @@ include ':feedbackloop.learner'
include ':influx_test'
include ':eraser.spark'
include ':eraser.starter'
include ':integration_test'
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment