// Copyright 2012 Georg-August-Universität Göttingen, Germany // // 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. package de.ugoe.cs.autoquest.htmlmonitor; import static org.junit.Assert.*; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.junit.After; import org.junit.Before; import org.junit.Test; import de.ugoe.cs.util.console.TextConsole; /** *

* TODO comment *

* * @author Patrick Harms */ public class HtmlMonitorServerTest implements HtmlMonitorMessageListener { /** * */ public static final TextConsole CONSOLE = new TextConsole(); /** * */ private static final int PORT = 19098; /** * */ private HtmlEvent[] events; /** * */ private HtmlGUIElement guiStructure; /** * */ private String eventHandlingError; /** * */ private HtmlMonitorServer server; /** * */ @Before public void setUp() throws Exception { server = new HtmlMonitorServer(PORT, this); server.init(); server.start(); } /** * */ @After public void tearDown() throws Exception { events = null; eventHandlingError = null; if (server != null) { try { server.stop(); } finally { server = null; } } } /** * */ @Test public void testSimpleMessage() throws Exception { String clientId = "123"; String message = "{" + " \"message\": {" + " \"clientInfos\": {" + " \"clientId\":\"" + clientId + "\"," + " \"userAgent\":\"Agent\"," + " \"title\":\"Title\"," + " \"url\":\"http://host/path\"" + " }," + " \"guiModel\": {" + " \"tagName\":\"html\"," + " \"index\":\"0\"," + " \"children\":" + " [ {" + " \"tagName\":\"head\"," + " \"index\":\"0\"," + " }," + " {" + " \"tagName\":\"body\"," + " \"htmlId\":\"gsr\"," + " }" + " ]" + " }," + " \"events\":" + " [ {" + " \"time\":\"12345\"," + " \"path\":\"/html[0]/body(htmlId=gsr)\"," + " \"eventType\":\"onclick\"" + " \"coordinates\": [\"194\", \"7\"]" + " }" + " ]" + " }" + "}"; sendMessageAndAssertResponse(message); if (eventHandlingError != null) { fail(eventHandlingError); } // check the GUI structure HtmlGUIElement parent = null; HtmlGUIElement element = guiStructure; assertGuiElement(element, HtmlServer.class, parent, 1); parent = element; element = parent.getChildren().get(0); assertGuiElement(element, HtmlDocument.class, parent, 1); HtmlDocument document = (HtmlDocument) element; parent = element; element = parent.getChildren().get(0); assertGuiElement(element, HtmlPageElement.class, parent, 2); parent = element; element = parent.getChildren().get(0); assertGuiElement(element, HtmlPageElement.class, parent, 0); element = parent.getChildren().get(1); assertGuiElement(element, HtmlPageElement.class, parent, 0); // check the event assertNotNull(events); assertEquals(1, events.length); assertEvent(0, 12345, "/html[0]/body(htmlId=gsr)", element, document, "onclick", null, null, new Integer[] {194, 7}, "Title", "Agent", "http://host/path", "123"); } /** * */ @Test public void testComplexMessage() throws Exception { String clientId = "123"; String message = "{" + " \"message\": {" + " \"clientInfos\": {" + " \"clientId\":\"" + clientId + "\"," + " \"userAgent\":\"Agent\"," + " \"title\":\"Title\"," + " \"url\":\"http://host/path\"" + " }," + " \"guiModel\": {" + " \"tagName\":\"html\"," + " \"index\":\"0\"," + " \"children\":" + " [ {" + " \"tagName\":\"head\"," + " \"index\":\"0\"," + " }," + " {" + " \"tagName\":\"body\"," + " \"htmlId\":\"gsr\"," + " \"children\":" + " [ {" + " \"tagName\":\"input_button\"," + " \"htmlId\":\"input1\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"htmlId\":\"input2\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"htmlId\":\"input3\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"htmlId\":\"input4\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"htmlId\":\"input5\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"htmlId\":\"input6\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"htmlId\":\"input7\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"htmlId\":\"input8\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"htmlId\":\"input9\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"htmlId\":\"input10\"," + " }," + " ]" + " }" + " ]" + " }," + " \"events\":" + " [ {" + " \"time\":\"1\"," + " \"path\":\"/html[0]/body(htmlId=gsr)/input_button(htmlId=input1)\"," + " \"eventType\":\"onclick\"," + " \"coordinates\": [\"194\", \"7\"]" + " }," + " {" + " \"time\":\"2\"," + " \"path\":\"/html[0]/body(htmlId=gsr)/input_button(htmlId=input2)\"," + " \"eventType\":\"ondblclick\"," + " \"coordinates\": [\"194\", \"7\"]" + " }," + " {" + " \"time\":\"3\"," + " \"path\":\"/html[0]/body(htmlId=gsr)/input_button(htmlId=input3)\"," + " \"eventType\":\"onfocus\"" + " }," + " {" + " \"time\":\"4\"," + " \"path\":\"/html[0]/body(htmlId=gsr)/input_button(htmlId=input4)\"," + " \"eventType\":\"onclick\"," + " \"coordinates\": [\"125\", \"14\"]" + " }," + " {" + " \"time\":\"5\"," + " \"path\":\"/html[0]/body(htmlId=gsr)/input_button(htmlId=input5)\"," + " \"eventType\":\"onfocus\"" + " }," + " {" + " \"time\":\"6\"," + " \"path\":\"/html[0]/body(htmlId=gsr)/input_button(htmlId=input6)\"," + " \"eventType\":\"onfocus\"" + " }," + " {" + " \"time\":\"7\"," + " \"path\":\"/html[0]/body(htmlId=gsr)/input_button(htmlId=input7)\"," + " \"eventType\":\"onfocus\"" + " }," + " {" + " \"time\":\"8\"," + " \"path\":\"/html[0]/body(htmlId=gsr)/input_button(htmlId=input8)\"," + " \"eventType\":\"onclick\"," + " \"coordinates\": [\"255\", \"4\"]" + " }," + " {" + " \"time\":\"9\"," + " \"path\":\"/html[0]/body(htmlId=gsr)\"," + " \"eventType\":\"onscroll\"," + " \"scrollPosition\": [\"23\", \"567\"]" + " }," + " {" + " \"time\":\"10\"," + " \"path\":\"/html[0]/body(htmlId=gsr)/input_button(htmlId=input10)\"," + " \"eventType\":\"onclick\"," + " \"coordinates\": [\"516\", \"154\"]" + " }" + " ]" + " }" + "}"; sendMessageAndAssertResponse(message); if (eventHandlingError != null) { fail(eventHandlingError); } // check the GUI structure HtmlGUIElement parent = null; HtmlGUIElement element = guiStructure; assertGuiElement(element, HtmlServer.class, parent, 1); parent = element; element = parent.getChildren().get(0); assertGuiElement(element, HtmlDocument.class, parent, 1); HtmlDocument document = (HtmlDocument) element; parent = element; element = parent.getChildren().get(0); assertGuiElement(element, HtmlPageElement.class, parent, 2); parent = element; element = parent.getChildren().get(0); assertGuiElement(element, HtmlPageElement.class, parent, 0); element = parent.getChildren().get(1); assertGuiElement(element, HtmlPageElement.class, parent, 10); parent = element; for (HtmlGUIElement child : parent.getChildren()) { assertGuiElement(child, HtmlPageElement.class, parent, 0); } // check the events assertNotNull(events); assertEquals(10, events.length); for (int i = 0; i < events.length; i++) { String targetDOMPath; HtmlGUIElement target; Integer[] scrollPosition = null; if (i == 8) { targetDOMPath = "/html[0]/body(htmlId=gsr)"; target = parent; scrollPosition = new Integer[] { 23, 567 }; } else { targetDOMPath = "/html[0]/body(htmlId=gsr)/input_button(htmlId=input" + (i + 1) + ")"; target = parent.getChildren().get(i); } String eventType; if ((i == 1)) { eventType = "ondblclick"; } else if ((i == 2) || ((4 <= i) && (i <= 6))) { eventType = "onfocus"; } else if ((i == 8)) { eventType = "onscroll"; } else { eventType = "onclick"; } assertNull("event " + i, events[i].getKey()); Integer[] coordinates = null; if (i <= 1) { coordinates = new Integer[] { 194, 7 }; } else if (i == 3) { coordinates = new Integer[] { 125, 14 }; } else if (i == 7) { coordinates = new Integer[] { 255, 4 }; } else if (i == 9) { coordinates = new Integer[] { 516, 154 }; } assertEvent(i, i + 1, targetDOMPath, target, document, eventType, null, scrollPosition, coordinates, "Title", "Agent", "http://host/path", "123"); } } /** * */ @Test public void testInvalidMessages() throws Exception { String message = "}"; sendMessageAndAssertResponse(message); if (eventHandlingError != null) { fail(eventHandlingError); } assertNull(events); message = "blaublbidalslkdjflqkerowercalksdjfdlkkjdjfk"; sendMessageAndAssertResponse(message); if (eventHandlingError != null) { fail(eventHandlingError); } assertNull(events); // the following message doesn't work because of the missing scroll position in the event message = "{" + " \"message\": {" + " \"clientInfos\": {" + " \"clientId\":\"123\"," + " \"userAgent\":\"Agent\"," + " \"title\":\"Title\"," + " \"url\":\"http://host/path\"" + " }," + " \"guiModel\": {" + " \"tagName\":\"html\"," + " \"index\":\"0\"," + " \"children\":" + " [ {" + " \"tagName\":\"head\"," + " \"index\":\"0\"," + " }," + " {" + " \"tagName\":\"body\"," + " \"htmlId\":\"gsr\"," + " }" + " ]" + " }," + " \"events\":" + " [ {" + " \"time\":\"9\"," + " \"path\":\"/html[0]/body(htmlId=gsr)\"," + " \"eventType\":\"onscroll\"," + " }" + " ]" + " }" + "}"; sendMessageAndAssertResponse(message); if (eventHandlingError != null) { fail(eventHandlingError); } assertNull(events); // the following message doesn't work because of the missing client id message = "{" + " \"message\": {" + " \"clientInfos\": {" + " \"userAgent\":\"Agent\"," + " \"title\":\"Title\"," + " \"url\":\"http://host/path\"" + " }," + " \"guiModel\": {" + " \"tagName\":\"html\"," + " \"index\":\"0\"," + " \"children\":" + " [ {" + " \"tagName\":\"head\"," + " \"index\":\"0\"," + " }," + " {" + " \"tagName\":\"body\"," + " \"htmlId\":\"gsr\"," + " }" + " ]" + " }," + " \"events\":" + " [ {" + " \"time\":\"12345\"," + " \"path\":\"/html[0]/body(htmlId=gsr)\"," + " \"eventType\":\"onunload\"" + " }" + " ]" + " }" + "}"; sendMessageAndAssertResponse(message); if (eventHandlingError != null) { fail(eventHandlingError); } assertNull(events); // the following message doesn't work because of the invalid time stamp message = "{" + " \"message\": {" + " \"clientInfos\": {" + " \"clientId\":\"123\"," + " \"userAgent\":\"Agent\"," + " \"title\":\"Title\"," + " \"url\":\"http://host/path\"" + " }," + " \"guiModel\": {" + " \"tagName\":\"html\"," + " \"index\":\"0\"," + " \"children\":" + " [ {" + " \"tagName\":\"head\"," + " \"index\":\"0\"," + " }," + " {" + " \"tagName\":\"body\"," + " \"htmlId\":\"gsr\"," + " }" + " ]" + " }," + " \"events\":" + " [ {" + " \"time\":\"blub\"," + " \"path\":\"/html[0]/body(htmlId=gsr)\"," + " \"eventType\":\"onunload\"" + " }" + " ]" + " }" + "}"; sendMessageAndAssertResponse(message); if (eventHandlingError != null) { fail(eventHandlingError); } assertNull(events); } /* (non-Javadoc) * @see de.ugoe.cs.autoquest.htmlmonitor.HtmlMonitoringListener#handleEvents(de.ugoe.cs.autoquest.htmlmonitor.HtmlClientInfos, de.ugoe.cs.autoquest.htmlmonitor.HtmlEvent[]) */ @Override public void handleMessage(HtmlClientInfos clientInfos, HtmlGUIElement guiStructure, HtmlEvent[] events) { if (clientInfos == null) { eventHandlingError = "client infos were null"; } else if (guiStructure == null) { eventHandlingError = "gui structure was null"; } else if (events == null) { eventHandlingError = "events were null"; } else { for (HtmlEvent event : events) { if (!clientInfos.equals(event.getClientInfos())) { eventHandlingError = "one of the events did not have a correct client info"; } } this.events = events; this.guiStructure = guiStructure; } } /** *

* TODO: comment *

* * @param message */ private void sendMessageAndAssertResponse(String message) throws Exception { DefaultHttpClient httpclient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost("http://localhost:" + PORT + "/"); HttpEntity entity = new StringEntity(message, ContentType.APPLICATION_JSON); httpPost.setEntity(entity); try { HttpResponse response = httpclient.execute(httpPost); // the monitor always returns 200 without any additional information. The client must // never get more or less information. This is especially important for preventing // hackers from finding out more assertEquals(200, response.getStatusLine().getStatusCode()); assertTrue ((response.getEntity() == null) || (response.getEntity().getContentLength() == 0)); } finally { httpPost.releaseConnection(); } } /** * */ private void assertGuiElement(HtmlGUIElement element, Class type, HtmlGUIElement parent, int noOfChildren) { assertTrue(type.isInstance(element)); if (parent != null) { assertEquals(parent.getId(), element.getParentId()); } else { assertNull(element.getParentId()); } assertNotNull(element.getId()); if (noOfChildren > 0) { assertNotNull(element.getChildren()); assertEquals(noOfChildren, element.getChildren().size()); } else { assertNull(element.getChildren()); } } /** * */ private void assertEvent(int index, long timestamp, String targetDOMPath, HtmlGUIElement target, HtmlDocument document, String eventType, Integer key, Integer[] scrollPosition, Integer[] coordinates, String clientInfoTitle, String clientInfoAgent, String clientInfoURL, String clientId) { assertEquals("event " + index, new Long(timestamp), events[index].getTime()); assertEquals("event " + index, targetDOMPath, events[index].getTargetDOMPath()); assertEquals("event " + index, target, events[index].getTarget()); assertEquals("event " + index, document, events[index].getTargetDocument()); assertEquals("event " + index, eventType, events[index].getEventType()); assertEquals("event " + index, key, events[index].getKey()); assertArrayEquals("event " + index, scrollPosition, events[index].getScrollPosition()); assertArrayEquals("event " + index, coordinates, events[index].getCoordinates()); assertEquals ("event " + index, clientInfoTitle, events[index].getClientInfos().getTitle()); assertEquals ("event " + index, clientInfoAgent, events[index].getClientInfos().getUserAgent()); assertEquals ("event " + index, clientInfoURL, events[index].getClientInfos().getUrl().toString()); assertEquals ("event " + index, clientId, events[index].getClientInfos().getClientId()); } }