blob: 0cb34de09466691859ffd2b4b57f452446858990 [file] [log] [blame]
/*
* 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);
}
}
}