// 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.genericeventmonitor; import static org.junit.Assert.*; import java.io.File; 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.autoquest.genericeventmonitor.GenericEventMonitor; import de.ugoe.cs.util.console.TextConsole; /** * * @author Patrick Harms */ public class GenericEventMonitorTest { /** * */ public static final TextConsole CONSOLE = new TextConsole(); /** * */ private final static String LOG_FILE_DIR = "target/tmp/logfiles/"; /** * */ private static final int PORT = 19098; /** * */ private GenericEventMonitor genericEventMonitor; /** * */ @Before public void setUp() throws Exception { genericEventMonitor = new GenericEventMonitor(new String[] { LOG_FILE_DIR, Integer.toString(PORT) }); genericEventMonitor.init(); genericEventMonitor.start(); } /** * */ @After public void tearDown() throws Exception { if (genericEventMonitor != null) { try { genericEventMonitor.stop(); } finally { genericEventMonitor = null; } } deleteFiles(new File(LOG_FILE_DIR)); } /** * */ @Test public void testOneSimpleMessage() throws Exception { String clientId = "123"; String appId = "456"; String message = "{" + " \"message\": {" + " \"clientInfos\": {" + " \"clientId\":\"" + clientId + "\"," + " \"appId\":\"" + appId + "\"," + " }," + " \"targetStructure\": [{" + " \"targetId\":\"target1\"," + " \"param1\":\"value1\"," + " \"param3\":\"value3\"," + " \"param2\":\"value2\"," + " \"children\":" + " [ {" + " \"targetId\":\"target3\"," + " \"index\":\"0\"," + " }," + " {" + " \"targetId\":\"target2\"," + " \"htmlId\":\"gsr\"," + " }" + " ]" + " }]," + " \"events\":" + " [ {" + " \"time\":\"12345\"," + " \"targetId\":\"target2\"," + " \"type\":\"gaze\"," + " \"xcoordinate\": \"194\"," + " \"ycoordinate\": \"12\"" + " }" + " ]" + " }" + "}"; sendMessageAndAssertResponse(message); genericEventMonitor.stop(); genericEventMonitor = null; File logFile = new File(LOG_FILE_DIR + File.separator + appId + File.separator + clientId + File.separator + "genericevents_" + clientId + "_000.log"); assertTrue(logFile.exists()); /*HTMLLogParser parser = new HTMLLogParser(null); parser.parseFile(logFile); // check the GUI model GUIModel guiModel = parser.getGuiModel(); assertNotNull(guiModel); List nodes = guiModel.getRootElements(); assertNotNull(nodes); assertEquals(1, nodes.size()); // get server node IGUIElement node = nodes.get(0); assertNotNull(node); assertTrue(node instanceof HTMLServer); assertEquals("HTML", node.getPlatform()); assertFalse(node.isUsed()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(1, nodes.size()); // get document node node = nodes.get(0); assertNotNull(node); assertTrue(node instanceof HTMLDocument); assertEquals("HTML", node.getPlatform()); assertFalse(node.isUsed()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(1, nodes.size()); // get html node node = nodes.get(0); assertNotNull(node); assertTrue(node instanceof HTMLPageElement); assertEquals("HTML", node.getPlatform()); assertFalse(node.isUsed()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(1, nodes.size()); // only one child as the head tag should have been ignored // get body node node = nodes.get(0); assertNotNull(node); assertTrue(node instanceof HTMLPageElement); assertEquals("HTML", node.getPlatform()); assertTrue(node.isUsed()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(0, nodes.size()); // check the sequences Collection> sequences = parser.getSequences(); assertNotNull(sequences); Iterator> iterator = sequences.iterator(); assertTrue(iterator.hasNext()); List sequence = iterator.next(); assertFalse(iterator.hasNext()); assertNotNull(sequence); assertEquals(1, sequence.size()); assertEvent(sequence.get(0), 12345, MouseClick.class, node, 194, 7);*/ } /** * */ @Test public void testSeveralMessagesInOneSession() throws Exception { String clientId = "123"; String appId = "456"; String message = "{" + " \"message\": {" + " \"clientInfos\": {" + " \"clientId\":\"" + clientId + "\"," + " \"appId\":\"" + appId + "\"," + " }," + " \"targetStructure\": [{" + " \"targetId\":\"html\"," + " \"index\":\"0\"," + " \"children\":" + " [ {" + " \"targetId\":\"head\"," + " \"index\":\"0\"," + " }," + " {" + " \"tagName\":\"body\"," + " \"targetId\":\"gsr\"," + " \"children\":" + " [ {" + " \"tagName\":\"input_button\"," + " \"targetId\":\"input1\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"targetId\":\"input2\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"targetId\":\"input3\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"targetId\":\"input4\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"targetId\":\"input5\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"targetId\":\"input6\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"targetId\":\"input7\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"targetId\":\"input8\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"targetId\":\"input9\"," + " }," + " {" + " \"tagName\":\"input_button\"," + " \"targetId\":\"input10\"," + " }," + " ]" + " }" + " ]" + " }]," + " \"events\":" + " [ {" + " \"time\":\"1\"," + " \"targetId\":\"input1\"," + " \"type\":\"onclick\"," + " \"coordinates\": \"194\"" + " }," + " {" + " \"time\":\"2\"," + " \"targetId\":\"input2\"," + " \"type\":\"ondblclick\"," + " \"coordinates\": \"194\"" + " }," + " {" + " \"time\":\"3\"," + " \"targetId\":\"input3\"," + " \"type\":\"onfocus\"" + " }," + " {" + " \"time\":\"4\"," + " \"targetId\":\"input4\"," + " \"type\":\"onclick\"," + " \"coordinates\": \"255\"" + " }," + " {" + " \"time\":\"5\"," + " \"targetId\":\"input5\"," + " \"type\":\"onfocus\"" + " }," + " {" + " \"time\":\"6\"," + " \"targetId\":\"input6\"," + " \"type\":\"onfocus\"" + " }," + " {" + " \"time\":\"7\"," + " \"targetId\":\"input7\"," + " \"type\":\"onfocus\"" + " }," + " {" + " \"time\":\"8\"," + " \"targetId\":\"input8\"," + " \"type\":\"onclick\"," + " \"coordinates\": \"255\"" + " }," + " {" + " \"time\":\"9\"," + " \"targetId\":\"input9\"," + " \"type\":\"onscroll\"," + " \"scrollPosition\": \"194\"" + " }," + " {" + " \"time\":\"10\"," + " \"targetId\":\"input10\"," + " \"type\":\"onclick\"," + " \"coordinates\": \"194\"" + " }" + " ]" + " }" + "}"; sendMessageAndAssertResponse(message); genericEventMonitor.stop(); genericEventMonitor = null; File logFile = new File(LOG_FILE_DIR + File.separator + appId + File.separator + clientId + File.separator + "genericevents_" + clientId + "_000.log"); assertTrue(logFile.exists()); /*HTMLLogParser parser = new HTMLLogParser(null); parser.parseFile(logFile); // check the GUI model GUIModel guiModel = parser.getGuiModel(); assertNotNull(guiModel); List nodes = guiModel.getRootElements(); assertNotNull(nodes); assertEquals(1, nodes.size()); // get server node IGUIElement node = nodes.get(0); assertNotNull(node); assertTrue(node instanceof HTMLServer); assertEquals("HTML", node.getPlatform()); assertFalse(node.isUsed()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(1, nodes.size()); // get document node node = nodes.get(0); assertNotNull(node); assertTrue(node instanceof HTMLDocument); assertEquals("HTML", node.getPlatform()); assertFalse(node.isUsed()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(1, nodes.size()); // get html node node = nodes.get(0); assertNotNull(node); assertTrue(node instanceof HTMLPageElement); assertEquals("HTML", node.getPlatform()); assertFalse(node.isUsed()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(1, nodes.size()); // only one child as the head tag should have been ignored // get body node IGUIElement body = nodes.get(0); assertNotNull(body); assertTrue(body instanceof HTMLPageElement); assertEquals("HTML", body.getPlatform()); assertTrue(body.isUsed()); nodes = guiModel.getChildren(body); assertNotNull(nodes); // wait for all 10 GUI elements on the same page to be logged although only 9 are used assertEquals(10, nodes.size()); Map inputs = new HashMap<>(); // get input nodes for (int i = 0; i < nodes.size(); i++) { node = nodes.get(i); assertNotNull(node); assertTrue(node instanceof HTMLPageElement); assertEquals("HTML", node.getPlatform()); if (!"input9".equals(((HTMLPageElement) node).getHtmlId())) { assertTrue(node.isUsed()); } else { assertFalse(node.isUsed()); } inputs.put(((HTMLPageElement) node).getHtmlId(), node); assertNotNull(guiModel.getChildren(node)); assertEquals(0, guiModel.getChildren(node).size()); } // check the sequences Collection> sequences = parser.getSequences(); assertNotNull(sequences); Iterator> iterator = sequences.iterator(); assertTrue(iterator.hasNext()); List sequence = iterator.next(); assertFalse(iterator.hasNext()); assertNotNull(sequence); assertEquals(10, sequence.size()); assertEvent(sequence.get(0), 1, MouseClick.class, inputs.get("input1"), 194, 7); assertEvent(sequence.get(1), 2, MouseDoubleClick.class, inputs.get("input2"), 194, 7); assertEvent(sequence.get(2), 3, KeyboardFocusChange.class, inputs.get("input3"), 0, 0); assertEvent(sequence.get(3), 4, MouseClick.class, inputs.get("input4"), 125, 14); assertEvent(sequence.get(4), 5, KeyboardFocusChange.class, inputs.get("input5"), 0, 0); assertEvent(sequence.get(5), 6, KeyboardFocusChange.class, inputs.get("input6"), 0, 0); assertEvent(sequence.get(6), 7, KeyboardFocusChange.class, inputs.get("input7"), 0, 0); assertEvent(sequence.get(7), 8, MouseClick.class, inputs.get("input8"), 255, 4); assertEvent(sequence.get(8), 9, Scroll.class, body, 0, 0); assertEvent(sequence.get(9), 10, MouseClick.class, inputs.get("input10"), 516, 154);*/ } /** * */ @Test public void testSeveralSessions() 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)\"," + " \"type\":\"onclick\"" + " \"coordinates\": [\"194\", \"7\"]" + " }" + " ]" + " }" + "}"; sendMessageAndAssertResponse(message); int numberOfSessions = 10; for (int i = 0; i < numberOfSessions; i++) { genericEventMonitor.stop(); genericEventMonitor = new GenericEventMonitor(new String[] { LOG_FILE_DIR, Integer.toString(PORT) }); genericEventMonitor.init(); genericEventMonitor.start(); sendMessageAndAssertResponse(message); } genericEventMonitor.stop(); genericEventMonitor = null; /*HTMLLogParser parser = new HTMLLogParser(null); // assert 9 already rotated log files for (int i = 0; i < numberOfSessions; i++) { File logFile = new File(LOG_FILE_DIR + File.separator + "host" + File.separator + clientId + File.separator + "htmlmonitor_" + clientId + "_00" + i + ".log"); assertTrue(logFile.exists()); parser.parseFile(logFile); } // check the GUI model GUIModel guiModel = parser.getGuiModel(); assertNotNull(guiModel); List nodes = guiModel.getRootElements(); assertNotNull(nodes); assertEquals(1, nodes.size()); // get server node IGUIElement node = nodes.get(0); assertNotNull(node); assertTrue(node instanceof HTMLServer); assertEquals("HTML", node.getPlatform()); assertFalse(node.isUsed()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(1, nodes.size()); // get document node node = nodes.get(0); assertNotNull(node); assertTrue(node instanceof HTMLDocument); assertEquals("HTML", node.getPlatform()); assertFalse(node.isUsed()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(1, nodes.size()); // get html node node = nodes.get(0); assertNotNull(node); assertTrue(node instanceof HTMLPageElement); assertEquals("HTML", node.getPlatform()); assertFalse(node.isUsed()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(1, nodes.size()); // only one child as the head tag should have been ignored // get body node node = nodes.get(0); assertNotNull(node); assertTrue(node instanceof HTMLPageElement); assertEquals("HTML", node.getPlatform()); assertTrue(node.isUsed()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(0, nodes.size()); // check the sequences Collection> sequences = parser.getSequences(); assertNotNull(sequences); assertEquals(numberOfSessions, sequences.size()); Iterator> iterator = sequences.iterator(); while (iterator.hasNext()) { List sequence = iterator.next(); assertNotNull(sequence); assertEquals(1, sequence.size()); assertEvent(sequence.get(0), 12345, MouseClick.class, node, 194, 7); }*/ } /** * */ 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) || ((response.getEntity().getContentLength() == 1) && (response.getEntity().getContent().read() == ' '))); } finally { httpPost.releaseConnection(); } } /** * */ /*private void assertEvent(Event event, int timestamp, Class eventType, IGUIElement eventTarget, int xCoordinate, int yCoordinate) { assertEquals(timestamp, event.getTimestamp()); assertTrue(eventType.isInstance(event.getType())); assertEquals(eventTarget, event.getTarget()); if (event.getType() instanceof MouseButtonInteraction) { assertEquals(xCoordinate, ((MouseButtonInteraction) event.getType()).getX()); assertEquals(yCoordinate, ((MouseButtonInteraction) event.getType()).getY()); } } /** * */ private void deleteFiles(File file) { if (file.exists()) { if (file.isDirectory()) { File[] files = file.listFiles(); if (files != null) { for (File child : files) { deleteFiles(child); } } } try { file.delete(); } catch (Exception e) { // ignore and delete as much as possible } } } }