| /* |
| * Copyright 2011 Google Inc. |
| * |
| * 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 com.google.gwt.dev.util.log.speedtracer; |
| |
| import com.google.gwt.dev.json.JsonArray; |
| import com.google.gwt.dev.json.JsonException; |
| import com.google.gwt.dev.json.JsonObject; |
| import com.google.gwt.dev.shell.DevModeSession; |
| import com.google.gwt.dev.shell.DevModeSessionTestUtil; |
| import com.google.gwt.dev.util.log.dashboard.SpeedTracerLoggerTestMockNotifier; |
| import com.google.gwt.dev.util.log.dashboard.SpeedTracerLoggerTestMockNotifier.DevModeEvent; |
| import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event; |
| import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.EventType; |
| import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Format; |
| |
| import junit.framework.TestCase; |
| |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.Reader; |
| import java.io.StringReader; |
| import java.io.StringWriter; |
| import java.io.Writer; |
| import java.util.LinkedList; |
| import java.util.Properties; |
| |
| /** |
| * Tests the SpeedTracerLogger class. |
| */ |
| public class SpeedTracerLoggerTest extends TestCase { |
| private static class DummyEventType implements EventType { |
| private final String color; |
| private final String name; |
| |
| public DummyEventType(String name, String color) { |
| this.name = name; |
| this.color = color; |
| } |
| |
| @Override |
| public String getColor() { |
| return color; |
| } |
| |
| @Override |
| public String getName() { |
| return name; |
| } |
| } |
| private class TestLoggerThreadedThread extends Thread { |
| |
| private final EventType event; |
| private final SpeedTracerLogger logger; |
| |
| public TestLoggerThreadedThread(EventType event, SpeedTracerLogger logger) { |
| super(); |
| this.event = event; |
| this.logger = logger; |
| } |
| |
| @Override |
| public void run() { |
| for (int i = 0; i < MAX_EVENT_LOGS; i++) { |
| Event e = logger.startImpl(null, event); |
| logger.endImpl(e); |
| } |
| } |
| } |
| |
| private static final EventType dummyOne = new DummyEventType("Larry", "Red"); |
| |
| private static final EventType dummyThree = new DummyEventType("Moe", "Blue"); |
| |
| private static final EventType dummyTwo = new DummyEventType("Curly", "Green"); |
| |
| private static final int MAX_EVENT_LOGS = 10000; |
| |
| public void testSpeedTracerLogger() throws IOException, JsonException { |
| Writer writer = new StringWriter(); |
| SpeedTracerLogger logger = new SpeedTracerLogger(writer, Format.HTML); |
| Event dummyOneEvent = logger.startImpl(null, dummyOne); |
| Event dummyTwoEvent = logger.startImpl(null, dummyTwo); |
| logger.endImpl(dummyTwoEvent); |
| Event dummyThreeEvent = logger.startImpl(null, dummyThree); |
| logger.endImpl(dummyThreeEvent); |
| logger.endImpl(dummyOneEvent); |
| logger.flush(); |
| |
| Reader jsonReader = extractJsonFromWriter(writer); |
| JsonObject parsedObject = JsonObject.parse(jsonReader); |
| assertTrue("dummyOne", compareJsonToEvent(parsedObject, dummyOne)); |
| |
| JsonObject dataObject = parsedObject.get("data").asObject(); |
| assertNotNull(dataObject); |
| |
| JsonArray childArray = parsedObject.get("children").asArray(); |
| assertNotNull(childArray); |
| assertEquals(2, childArray.getLength()); |
| |
| JsonObject child = childArray.get(0).asObject(); |
| assertTrue("dummyTwo", compareJsonToEvent(child, dummyTwo)); |
| |
| child = childArray.get(1).asObject(); |
| assertTrue("dummyThree", compareJsonToEvent(child, dummyThree)); |
| } |
| |
| public void testSpeedTracerLoggerExtraData() throws IOException, |
| JsonException { |
| Writer writer = new StringWriter(); |
| SpeedTracerLogger logger = new SpeedTracerLogger(writer, Format.HTML); |
| Event dummyOneEvent = logger.startImpl(null, dummyOne, "extraStart", "valueStart"); |
| logger.addDataImpl("extraMiddle", "valueMiddle"); |
| logger.endImpl(dummyOneEvent, "extraEnd", "valueEnd"); |
| logger.flush(); |
| |
| Reader jsonReader = extractJsonFromWriter(writer); |
| JsonObject parsedObject = JsonObject.parse(jsonReader); |
| assertEquals("valueStart", parsedObject.get("data").asObject().get( |
| "extraStart").asString().getString()); |
| assertEquals( |
| "valueMiddle", |
| parsedObject.get("data").asObject().get("extraMiddle").asString().getString()); |
| assertEquals( |
| "valueEnd", |
| parsedObject.get("data").asObject().get("extraEnd").asString().getString()); |
| } |
| |
| public void testSpeedTracerLoggerMultiple() throws IOException, JsonException { |
| Writer writer = new StringWriter(); |
| SpeedTracerLogger logger = new SpeedTracerLogger(writer, Format.HTML); |
| Event dummyOneEvent = logger.startImpl(null, dummyOne); |
| logger.endImpl(dummyOneEvent); |
| Event dummyTwoEvent = logger.startImpl(null, dummyTwo); |
| logger.endImpl(dummyTwoEvent); |
| Event dummyThreeEvent = logger.startImpl(null, dummyThree); |
| logger.endImpl(dummyThreeEvent); |
| logger.flush(); |
| |
| Reader jsonReader = extractJsonFromWriter(writer); |
| JsonObject dummyOneObject = JsonObject.parse(jsonReader).asObject(); |
| JsonObject dummyTwoObject = JsonObject.parse(jsonReader).asObject(); |
| JsonObject dummyThreeObject = JsonObject.parse(jsonReader).asObject(); |
| |
| assertTrue(compareJsonToEvent(dummyOneObject, dummyOne)); |
| assertTrue(compareJsonToEvent(dummyTwoObject, dummyTwo)); |
| assertTrue(compareJsonToEvent(dummyThreeObject, dummyThree)); |
| } |
| |
| public void testSpeedTracerLoggerThreaded() throws InterruptedException, |
| IOException { |
| final int NUM_THREADS = 3; |
| Writer writer = new StringWriter(); |
| SpeedTracerLogger logger = new SpeedTracerLogger(writer, Format.HTML); |
| Thread threads[] = new Thread[NUM_THREADS]; |
| threads[0] = new TestLoggerThreadedThread(dummyOne, logger); |
| threads[1] = new TestLoggerThreadedThread(dummyTwo, logger); |
| threads[2] = new TestLoggerThreadedThread(dummyThree, logger); |
| for (int i = 0; i < NUM_THREADS; i++) { |
| threads[i].start(); |
| } |
| for (int i = 0; i < NUM_THREADS; i++) { |
| threads[i].join(); |
| } |
| logger.flush(); |
| BufferedReader jsonReader = extractJsonFromWriter(writer); |
| |
| int tally[] = new int[NUM_THREADS]; |
| for (int i = 0; i < MAX_EVENT_LOGS * NUM_THREADS; i++) { |
| JsonObject result = null; |
| try { |
| result = JsonObject.parse(jsonReader).asObject(); |
| } catch (JsonException ex) { |
| fail("Failed to parse json after " + i + " iterations. " |
| + ex.toString()); |
| } |
| if (compareJsonToEvent(result, dummyOne)) { |
| tally[0]++; |
| } else if (compareJsonToEvent(result, dummyTwo)) { |
| tally[1]++; |
| } else if (compareJsonToEvent(result, dummyThree)) { |
| tally[2]++; |
| } else { |
| fail("Node with typeName " |
| + result.get("typeName").asString().getString() |
| + " doesn't match expected"); |
| } |
| } |
| for (int i = 0; i < NUM_THREADS; i++) { |
| assertEquals("dummy" + i + " has the wrong number of logs.", tally[i], |
| MAX_EVENT_LOGS); |
| } |
| } |
| |
| public void testSpeedTracerLoggerMarkTimeline() throws IOException, JsonException { |
| Writer writer = new StringWriter(); |
| SpeedTracerLogger logger = new SpeedTracerLogger(writer, Format.RAW); |
| Event dummyOneEvent = logger.startImpl(null, dummyOne); |
| logger.markTimelineImpl("Test Message"); |
| dummyOneEvent.end(); |
| logger.flush(); |
| |
| // There should be no HTML in here |
| String logString = writer.toString(); |
| BufferedReader jsonReader = new BufferedReader(new StringReader(logString)); |
| JsonObject dummyOneObject = JsonObject.parse(jsonReader).asObject(); |
| assertTrue(compareJsonToEvent(dummyOneObject, dummyOne)); |
| JsonArray children = dummyOneObject.get("children").asArray(); |
| assertEquals(1, children.getLength()); |
| JsonObject markTimelineObject = children.get(0).asObject(); |
| assertEquals(11.0, markTimelineObject.get("type").asNumber().getDecimal(), .001); |
| JsonObject dataObject = markTimelineObject.get("data").asObject(); |
| assertEquals("json=" + logString, "Test Message", |
| dataObject.get("message").asString().getString()); |
| } |
| |
| |
| public void testSpeedTracerLoggerRaw() throws IOException, JsonException { |
| Writer writer = new StringWriter(); |
| SpeedTracerLogger logger = new SpeedTracerLogger(writer, Format.RAW); |
| Event dummyOneEvent = logger.startImpl(null, dummyOne); |
| dummyOneEvent.end(); |
| logger.flush(); |
| |
| // There should be no HTML in here |
| String logString = writer.toString(); |
| assertTrue(logString.trim().startsWith("{")); |
| assertTrue(logString.trim().endsWith("}")); |
| BufferedReader jsonReader = new BufferedReader(new StringReader(logString)); |
| JsonObject dummyOneObject = JsonObject.parse(jsonReader).asObject(); |
| assertTrue(compareJsonToEvent(dummyOneObject, dummyOne)); |
| } |
| |
| private boolean compareJsonToEvent(JsonObject jsonObject, EventType eventType) { |
| String typeName = jsonObject.get("typeName").asString().getString(); |
| String color = jsonObject.get("color").asString().getString(); |
| return typeName.equals(eventType.getName()) |
| && color.equals(eventType.getColor()); |
| } |
| |
| private BufferedReader extractJsonFromWriter(Writer writer) |
| throws IOException { |
| String jsonString = writer.toString(); |
| assertTrue(jsonString.substring(0,5).toLowerCase().startsWith("<html")); |
| BufferedReader jsonReader = new BufferedReader(new StringReader(jsonString)); |
| // Skip ahead to start of JSON |
| while (true) { |
| jsonReader.mark(16 * 1024); |
| String line = jsonReader.readLine(); |
| if (line == null) { |
| fail("Didn't find start of JSON string"); |
| } |
| if (line.startsWith("{")) { |
| jsonReader.reset(); |
| break; |
| } |
| } |
| return jsonReader; |
| } |
| |
| public void testSpeedTracerWhenOnlyDashboardEnabled() { |
| // backup system properties before making changes to them |
| Properties props = (Properties) System.getProperties().clone(); |
| |
| try { |
| // no logging to file! |
| System.clearProperty("gwt.speedtracerlog"); |
| // we don't capture GC events in dashboard, so setting this will allow us |
| // to confirm that they *don't* show up in dashboard notices |
| System.setProperty("gwt.speedtracer.logGcTime", "yes"); |
| |
| // now enable the mock dashboard notifier |
| SpeedTracerLoggerTestMockNotifier notifier = SpeedTracerLoggerTestMockNotifier.enable(); |
| |
| // create "sessions" |
| DevModeSession session1 = DevModeSessionTestUtil.createSession("test1", "test", true); |
| DevModeSession session2 = DevModeSessionTestUtil.createSession("test2", "test", false); |
| |
| // expected values (used in final assertions below) |
| LinkedList<DevModeEvent> expectedEvents = new LinkedList<DevModeEvent>(); |
| LinkedList<DevModeSession> expectedSessions = new LinkedList<DevModeSession>(); |
| |
| Event evt1, evt2; |
| |
| // test events with no session specified |
| evt1 = SpeedTracerLogger.start(DevModeEventType.MODULE_INIT, "k1", "v1", "k2", "v2"); |
| // also test that child events aren't posted (only top-level events) |
| evt2 = SpeedTracerLogger.start(DevModeEventType.CLASS_BYTES_REWRITE); |
| evt2.end(); |
| evt1.end(); |
| // expect only first event |
| expectedEvents.add(new DevModeEvent(evt1)); |
| expectedSessions.add(session1); // event should get "default" session |
| |
| // now with session specified |
| evt1 = SpeedTracerLogger.start(session2, DevModeEventType.JAVA_TO_JS_CALL, "k1", "v1"); |
| // also test that child events aren't posted (only top-level events) |
| evt2 = SpeedTracerLogger.start(DevModeEventType.CREATE_UI); |
| evt2.end(); |
| evt1.end(); |
| // expect only first event |
| expectedEvents.add(new DevModeEvent(evt1)); |
| expectedSessions.add(session2); |
| |
| evt1 = SpeedTracerLogger.start(session1, DevModeEventType.JS_TO_JAVA_CALL, "k1", "v1"); |
| evt1.end(); |
| expectedEvents.add(new DevModeEvent(evt1)); |
| expectedSessions.add(session1); |
| |
| // Finally, assert that the events and corresponding sessions sent to the |
| // notifier are exactly as expected |
| assertEquals("Events posted to dashboard do not match expected events!", expectedEvents, |
| notifier.getEventSequence()); |
| |
| // Collect sessions associated with each event |
| LinkedList<DevModeSession> actualSessions = new LinkedList<DevModeSession>(); |
| for (DevModeEvent event : notifier.getEventSequence()) { |
| actualSessions.add(event.getDevModeSession()); |
| } |
| |
| // and confirm the sessions are correct |
| assertEquals("Events posted to dashboard are associated with incorrect sessions!", |
| expectedSessions, actualSessions); |
| |
| } finally { |
| // restore system properties |
| System.setProperties(props); |
| } |
| } |
| } |