// 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.lang.String; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; 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.eventcore.Event; import de.ugoe.cs.autoquest.eventcore.HierarchicalEventTargetModel; import de.ugoe.cs.autoquest.eventcore.IEventTarget; import de.ugoe.cs.autoquest.eventcore.StringEventType; import de.ugoe.cs.autoquest.genericeventmonitor.GenericEventMonitor; import de.ugoe.cs.autoquest.plugin.genericevents.GenericEventLogParser; import de.ugoe.cs.autoquest.plugin.genericevents.eventCore.GenericEventTarget; 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()); GenericEventLogParser parser = new GenericEventLogParser(new HashSet()); parser.parseFile(logFile); // check the GUI model HierarchicalEventTargetModel guiModel = parser.getHierarchicalEventTargetModel(); assertNotNull(guiModel); List nodes = guiModel.getRootElements(); assertNotNull(nodes); assertEquals(1, nodes.size()); // get root node GenericEventTarget node = nodes.get(0); assertNotNull(node); assertEquals("target1", node.getStringIdentifier()); assertEquals("Generic Event", node.getPlatform()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(2, nodes.size()); // get children node node = nodes.get(0); assertNotNull(node); assertTrue("target2".equals(node.getStringIdentifier()) || "target3".equals(node.getStringIdentifier())); assertEquals("Generic Event", node.getPlatform()); node = nodes.get(1); assertNotNull(node); assertTrue("target2".equals(node.getStringIdentifier()) || "target3".equals(node.getStringIdentifier())); assertEquals("Generic Event", node.getPlatform()); 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()); IEventTarget target = null; for (IEventTarget candidate : nodes) { if ("target2".equals(candidate.getStringIdentifier())) { target = candidate; break; } } assertEvent(sequence.get(0), "gaze", target); } /** * */ @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\":" + " [ {" + " \"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()); GenericEventLogParser parser = new GenericEventLogParser(new HashSet()); parser.parseFile(logFile); // check the GUI model HierarchicalEventTargetModel guiModel = parser.getHierarchicalEventTargetModel(); assertNotNull(guiModel); List nodes = guiModel.getRootElements(); assertNotNull(nodes); assertEquals(1, nodes.size()); // get root node GenericEventTarget node = nodes.get(0); assertNotNull(node); assertEquals("html", node.getStringIdentifier()); assertEquals("Generic Event", node.getPlatform()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(1, nodes.size()); // get root child node GenericEventTarget body = nodes.get(0); assertNotNull(body); assertEquals("gsr", body.getStringIdentifier()); assertEquals("Generic Event", body.getPlatform()); nodes = guiModel.getChildren(body); assertNotNull(nodes); assertEquals(10, nodes.size()); // get children node Map inputs = new HashMap<>(); for (GenericEventTarget candidate: nodes) { assertNotNull(candidate); assertTrue(candidate.getStringIdentifier().startsWith("input")); assertEquals("Generic Event", candidate.getPlatform()); inputs.put(candidate.getStringIdentifier(), candidate); assertNotNull(guiModel.getChildren(candidate)); assertEquals(0, guiModel.getChildren(candidate).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), "onclick", inputs.get("input1")); assertEvent(sequence.get(1), "ondblclick", inputs.get("input2")); assertEvent(sequence.get(2), "onfocus", inputs.get("input3")); assertEvent(sequence.get(3), "onclick", inputs.get("input4")); assertEvent(sequence.get(4), "onfocus", inputs.get("input5")); assertEvent(sequence.get(5), "onfocus", inputs.get("input6")); assertEvent(sequence.get(6), "onfocus", inputs.get("input7")); assertEvent(sequence.get(7), "onclick", inputs.get("input8")); assertEvent(sequence.get(8), "onscroll", inputs.get("input9")); assertEvent(sequence.get(9), "onclick", inputs.get("input10")); } /** * */ @Test public void testSeveralSessions() 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); 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; GenericEventLogParser parser = new GenericEventLogParser(new HashSet()); // assert 9 already rotated log files for (int i = 0; i < numberOfSessions; i++) { File logFile = new File(LOG_FILE_DIR + File.separator + appId + File.separator + clientId + File.separator + "genericevents_" + clientId + "_00" + i + ".log"); assertTrue(logFile.exists()); parser.parseFile(logFile); } // check the GUI model HierarchicalEventTargetModel guiModel = parser.getHierarchicalEventTargetModel(); assertNotNull(guiModel); List nodes = guiModel.getRootElements(); assertNotNull(nodes); assertEquals(1, nodes.size()); // get root node GenericEventTarget node = nodes.get(0); assertNotNull(node); assertEquals("target1", node.getStringIdentifier()); assertEquals("Generic Event", node.getPlatform()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(2, nodes.size()); // get children node node = nodes.get(0); assertNotNull(node); assertTrue("target2".equals(node.getStringIdentifier()) || "target3".equals(node.getStringIdentifier())); assertEquals("Generic Event", node.getPlatform()); node = nodes.get(1); assertNotNull(node); assertTrue("target2".equals(node.getStringIdentifier()) || "target3".equals(node.getStringIdentifier())); assertEquals("Generic Event", node.getPlatform()); // check the sequences Collection> sequences = parser.getSequences(); assertNotNull(sequences); assertEquals(numberOfSessions, sequences.size()); Iterator> iterator = sequences.iterator(); IEventTarget target = null; for (IEventTarget candidate : nodes) { if ("target2".equals(candidate.getStringIdentifier())) { target = candidate; break; } } while (iterator.hasNext()) { List sequence = iterator.next(); assertNotNull(sequence); assertEquals(1, sequence.size()); assertEvent(sequence.get(0), "gaze", target); } } /** * */ @Test public void testManyRequestsInOneSession() throws Exception { int noOfMessages = 100; int noOfEventsPerMessage = 1000; String clientId = "123"; String appId = "456"; List messages = new ArrayList<>(); int eventId = 0; for (int i = 0; i < noOfMessages; i++) { StringBuffer message = new StringBuffer( "{" + " \"message\": {" + " \"clientInfos\": {" + " \"clientId\":\"" + clientId + "\"," + " \"appId\":\"" + appId + "\"," + " }," + " \"targetStructure\": [{" + " \"targetId\":\"target1\"," + " \"children\":" + " [ {" + " \"targetId\":\"target2\"," + " }" + " ]" + " }]," + " \"events\":" + " ["); for (int j = 0; j < noOfEventsPerMessage; j++) { message.append( " {" + " \"time\":\"" + eventId++ + "\"," + " \"targetId\":\"target2\"," + " \"type\":\"gaze\"," + " },"); } message.append( " ]" + " }" + "}"); messages.add(message.toString()); } List threads = new ArrayList<>(); for (String message : messages) { threads.add(sendMessage(message)); } for (Thread thread : threads) { thread.join(); } genericEventMonitor.stop(); genericEventMonitor = null; GenericEventLogParser parser = new GenericEventLogParser(new HashSet()); File logFile = new File(LOG_FILE_DIR + File.separator + appId + File.separator + clientId + File.separator + "genericevents_" + clientId + "_000.log"); assertTrue(logFile.exists()); parser.parseFile(logFile); // check the GUI model HierarchicalEventTargetModel guiModel = parser.getHierarchicalEventTargetModel(); assertNotNull(guiModel); List nodes = guiModel.getRootElements(); assertNotNull(nodes); assertEquals(1, nodes.size()); // get root node GenericEventTarget node = nodes.get(0); assertNotNull(node); assertEquals("target1", node.getStringIdentifier()); assertEquals("Generic Event", node.getPlatform()); nodes = guiModel.getChildren(node); assertNotNull(nodes); assertEquals(1, nodes.size()); // get children node GenericEventTarget target = nodes.get(0); assertNotNull(target); assertEquals("target2", target.getStringIdentifier()); assertEquals("Generic Event", target.getPlatform()); // check the sequences Collection> sequences = parser.getSequences(); assertNotNull(sequences); assertEquals(1, sequences.size()); Iterator> iterator = sequences.iterator(); while (iterator.hasNext()) { List sequence = iterator.next(); assertNotNull(sequence); assertEquals(noOfMessages * noOfEventsPerMessage, sequence.size()); for (Event event : sequence) { assertEvent(event, "gaze", target); } } } /** * */ private void sendMessageAndAssertResponse(String message) throws Exception { DefaultHttpClient httpclient = new DefaultHttpClient(); //HttpPost httpPost = new HttpPost("https://swe-tooling.informatik.uni-goettingen.de/autoquest-genericmonitor/"); 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 Thread sendMessage(final String message) throws Exception { Thread thread = new Thread(new Runnable() { @Override public void run() { try { System.out.println("sending data"); sendMessageAndAssertResponse(message); System.out.println("data send"); } catch (Exception e) { e.printStackTrace(); } } }); thread.start(); return thread; } /** * */ private void assertEvent(Event event, String name, IEventTarget target) { assertEquals(StringEventType.class, event.getType().getClass()); assertEquals(name, ((StringEventType) event.getType()).toString()); assertEquals(target, event.getTarget()); } /** * */ 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 } } } }