blob: f43552f1258b11c2149f4a70787a1aa7d8f1b42a [file] [log] [blame]
/*
* Copyright 2009 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.shell;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.shell.BrowserChannel.CheckVersionsMessage;
import com.google.gwt.dev.shell.BrowserChannel.LoadModuleMessage;
import com.google.gwt.dev.shell.BrowserChannel.MessageType;
import com.google.gwt.dev.shell.BrowserChannel.OldLoadModuleMessage;
import com.google.gwt.dev.shell.BrowserChannel.ProtocolVersionMessage;
import com.google.gwt.dev.shell.BrowserChannel.QuitMessage;
import com.google.gwt.dev.shell.BrowserChannel.RequestIconMessage;
import com.google.gwt.dev.shell.BrowserChannel.ReturnMessage;
import com.google.gwt.dev.shell.BrowserChannel.UserAgentIconMessage;
import com.google.gwt.dev.shell.BrowserChannel.Value;
import com.google.gwt.dev.shell.BrowserChannelServer.SessionHandlerServer;
import com.google.gwt.dev.util.log.dashboard.DashboardNotifier;
import junit.framework.TestCase;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.Semaphore;
/**
* Test that the protocol startup of BrowserChannelworks for all supported
* protocol versions.
*/
public class BrowserChannelServerTest extends TestCase {
/**
* A BrowserChannelServer that can notify when the connection is closed. It
* also uses a custom {@code DashboardNotifier} in order to test notification
* calls.
*/
private class TestBrowserChannelServer extends BrowserChannelServer {
TestDashboardNotifier notifier = new TestDashboardNotifier();
private final Semaphore finishNotify = new Semaphore(0);
public TestBrowserChannelServer(TreeLogger logger,
InputStream inputStream, OutputStream outputStream,
SessionHandlerServer handler) {
super(logger, inputStream, outputStream, handler, true);
}
@Override
public void run() {
super.run();
finishNotify.release();
}
@Override
DashboardNotifier getDashboardNotifier() {
return notifier;
}
public void waitForClose() throws InterruptedException {
finishNotify.acquire();
}
}
/**
* Maintains a connected pair of piped streams.
*/
private class PipedStreamPair {
private final PipedOutputStream output;
private final PipedInputStream input;
public PipedStreamPair() {
PipedOutputStream out = null;
PipedInputStream in = null;
try {
out = new PipedOutputStream();
in = new PipedInputStream(out);
} catch (IOException e) {
}
output = out;
input = in;
}
public PipedInputStream getInputStream() {
return input;
}
public PipedOutputStream getOutputStream() {
return output;
}
}
/**
* A SessionHandler which keeps track of parameters from the LoadModule
* message, but mocks out everything else.
*/
private static class TestSessionHandler extends SessionHandlerServer {
private String loadedModule;
private String userAgent;
private String url;
private String tabKey;
private String sessionKey;
private byte[] userAgentIcon;
private String moduleName;
@Override
public void freeValue(BrowserChannelServer channel, int[] ids) {
}
public String getLoadedModule() {
return loadedModule;
}
public String getModuleName() {
return moduleName;
}
@Override
public ExceptionOrReturnValue getProperty(BrowserChannelServer channel,
int refId, int dispId) {
return new ExceptionOrReturnValue(false, new Value());
}
public String getSessionKey() {
return sessionKey;
}
public String getTabKey() {
return tabKey;
}
public String getUrl() {
return url;
}
public String getUserAgent() {
return userAgent;
}
public byte[] getUserAgentIcon() {
return userAgentIcon;
}
@Override
public ExceptionOrReturnValue invoke(BrowserChannelServer channel, Value thisObj,
int dispId, Value[] args) {
return new ExceptionOrReturnValue(false, new Value());
}
@Override
public TreeLogger loadModule(BrowserChannelServer channel, String moduleName,
String userAgent, String url, String tabKey, String sessionKey,
byte[] userAgentIcon) {
loadedModule = moduleName;
this.moduleName = moduleName;
this.userAgent = userAgent;
this.url = url;
this.tabKey = tabKey;
this.sessionKey = sessionKey;
this.userAgentIcon = userAgentIcon;
return new FailErrorLogger();
}
@Override
public ExceptionOrReturnValue setProperty(BrowserChannelServer channel,
int refId, int dispId, Value newValue) {
return new ExceptionOrReturnValue(false, new Value());
}
@Override
public void unloadModule(BrowserChannelServer channel, String moduleName) {
loadedModule = null;
}
}
/**
* A dashboard notifier that enforces the correct method calls.
*/
private static class TestDashboardNotifier implements DashboardNotifier {
DevModeSession currentSession;
boolean started;
boolean ended;
@Override
public void devModeEvent(DevModeSession session, String eventType, long startTimeNanos,
long durationNanos) {
fail("BrowserChannelServer should not be calling DashboardNotifier.devModeEvent()");
}
@Override
public void devModeSession(DevModeSession session) {
currentSession = session;
assertFalse("DashboardNotifier.devModeSession() called more than once", started);
started = true;
}
@Override
public void devModeSessionEnded(DevModeSession session) {
assertTrue("DashboardNotifier.devModeSessionEnded() without prior call to "
+ "DashboardNotifier.devModeSession()", started);
assertFalse("DashboardNotifier.devModeSessionEnded() called more than once", ended);
assertEquals("Wrong session passed to DashboardNotifier.devModeSessionEnded()",
currentSession, session);
ended = true;
}
public void verify(String moduleName, String userAgent) {
assertTrue(started);
assertTrue(ended);
assertEquals(moduleName, currentSession.getModuleName());
assertEquals(userAgent, currentSession.getUserAgent());
}
}
private PipedStreamPair clientToServer = new PipedStreamPair();
private PipedStreamPair serverToClient = new PipedStreamPair();
/**
* Test a version 1 client interacting with the server.
*
* @throws IOException
* @throws BrowserChannelException
* @throws InterruptedException
*/
public void testVersion1() throws IOException, BrowserChannelException,
InterruptedException {
TestSessionHandler handler = new TestSessionHandler();
TestBrowserChannelServer server = new TestBrowserChannelServer(
new FailErrorLogger(), clientToServer.getInputStream(),
serverToClient.getOutputStream(), handler);
TestBrowserChannel client = new TestBrowserChannel(
serverToClient.getInputStream(), clientToServer.getOutputStream());
new OldLoadModuleMessage(client, 1, "testModule", "userAgent").send();
MessageType type = client.readMessageType();
assertEquals("testModule", handler.getModuleName());
assertEquals("userAgent", handler.getUserAgent());
assertNull(handler.getUrl());
assertNull(handler.getTabKey());
assertNull(handler.getSessionKey());
assertNull(handler.getUserAgentIcon());
assertEquals(MessageType.RETURN, type);
DevModeSession session = server.getDevModeSession();
assertNotNull(session);
assertEquals("testModule", session.getModuleName());
assertEquals("userAgent", session.getUserAgent());
ReturnMessage.receive(client);
QuitMessage.send(client);
server.waitForClose();
assertNull(handler.getLoadedModule());
server.notifier.verify("testModule", "userAgent");
}
/**
* Test a version 2 client interacting with the server.
*
* @throws IOException
* @throws BrowserChannelException
* @throws InterruptedException
*/
public void testVersion2() throws IOException, BrowserChannelException,
InterruptedException {
TestSessionHandler handler = new TestSessionHandler();
TestBrowserChannelServer server = new TestBrowserChannelServer(
new FailErrorLogger(), clientToServer.getInputStream(),
serverToClient.getOutputStream(), handler);
TestBrowserChannel client = new TestBrowserChannel(
serverToClient.getInputStream(), clientToServer.getOutputStream());
new CheckVersionsMessage(client, 2, 2,
HostedHtmlVersion.EXPECTED_GWT_ONLOAD_VERSION).send();
MessageType type = client.readMessageType();
assertEquals(MessageType.PROTOCOL_VERSION, type);
ProtocolVersionMessage protocolMessage = ProtocolVersionMessage.receive(
client);
assertEquals(2, protocolMessage.getProtocolVersion());
new LoadModuleMessage(client, "url", "tabkey", "session", "testModule",
"userAgent").send();
type = client.readMessageType();
assertEquals("testModule", handler.getModuleName());
assertEquals("userAgent", handler.getUserAgent());
assertEquals("url", handler.getUrl());
assertEquals("tabkey", handler.getTabKey());
assertEquals("session", handler.getSessionKey());
assertNull(handler.getUserAgentIcon());
assertEquals(MessageType.RETURN, type);
DevModeSession session = server.getDevModeSession();
assertNotNull(session);
assertEquals("testModule", session.getModuleName());
assertEquals("userAgent", session.getUserAgent());
ReturnMessage.receive(client);
QuitMessage.send(client);
server.waitForClose();
assertNull(handler.getLoadedModule());
server.notifier.verify("testModule", "userAgent");
}
/**
* Test a version 3 client interacting with the server.
*
* @throws IOException
* @throws BrowserChannelException
* @throws InterruptedException
*/
public void testVersion3() throws IOException, BrowserChannelException,
InterruptedException {
TestSessionHandler handler = new TestSessionHandler();
TestBrowserChannelServer server = new TestBrowserChannelServer(
new FailErrorLogger(), clientToServer.getInputStream(),
serverToClient.getOutputStream(), handler);
TestBrowserChannel client = new TestBrowserChannel(
serverToClient.getInputStream(), clientToServer.getOutputStream());
new CheckVersionsMessage(client, 2, 3,
HostedHtmlVersion.EXPECTED_GWT_ONLOAD_VERSION).send();
MessageType type = client.readMessageType();
assertEquals(MessageType.PROTOCOL_VERSION, type);
ProtocolVersionMessage protocolMessage = ProtocolVersionMessage.receive(
client);
assertEquals(3, protocolMessage.getProtocolVersion());
new LoadModuleMessage(client, "url", "tabkey", "session", "testModule",
"userAgent").send();
type = client.readMessageType();
byte[] iconBytes = null;
if (type == MessageType.REQUEST_ICON) {
RequestIconMessage.receive(client);
iconBytes = new byte[] { 0, 1, 2, 3, 4, 5 };
UserAgentIconMessage.send(client, iconBytes);
type = client.readMessageType();
}
assertEquals("testModule", handler.getModuleName());
assertEquals("userAgent", handler.getUserAgent());
assertEquals("url", handler.getUrl());
assertEquals("tabkey", handler.getTabKey());
assertEquals("session", handler.getSessionKey());
byte[] receivedIcon = handler.getUserAgentIcon();
assertNotNull(receivedIcon);
assertEquals(iconBytes.length, receivedIcon.length);
for (int i = 0; i < iconBytes.length; ++i) {
assertEquals(iconBytes[i], receivedIcon[i]);
}
assertEquals(MessageType.RETURN, type);
DevModeSession session = server.getDevModeSession();
assertNotNull(session);
assertEquals("testModule", session.getModuleName());
assertEquals("userAgent", session.getUserAgent());
ReturnMessage.receive(client);
QuitMessage.send(client);
server.waitForClose();
assertNull(handler.getLoadedModule());
server.notifier.verify("testModule", "userAgent");
}
}