Commit e1799e66 authored by jbudorick's avatar jbudorick Committed by Commit bot

[Android] Add a java version of the test server spawner.

BUG=448626

Review URL: https://codereview.chromium.org/867073002

Cr-Commit-Position: refs/heads/master@{#313532}
parent 61288e6c
......@@ -587,7 +587,7 @@ class DeviceUtils(object):
if raw:
cmd.append('-r')
for k, v in extras.iteritems():
cmd.extend(['-e', k, v])
cmd.extend(['-e', str(k), str(v)])
cmd.append(component)
return self.RunShellCommand(cmd, check_return=True)
......
......@@ -24,6 +24,9 @@ _EXTRA_COMMAND_LINE_FILE = (
'org.chromium.native_test.ChromeNativeTestActivity.CommandLineFile')
_EXTRA_COMMAND_LINE_FLAGS = (
'org.chromium.native_test.ChromeNativeTestActivity.CommandLineFlags')
_EXTRA_ENABLE_TEST_SERVER_SPAWNER = (
'org.chromium.native_test.ChromeNativeTestInstrumentationTestRunner'
'.EnableTestServerSpawner')
_MAX_SHARD_SIZE = 256
......@@ -39,6 +42,10 @@ class _ApkDelegate(object):
self._package = apk_helper.GetPackageName(self._apk)
self._runner = apk_helper.GetInstrumentationName(self._apk)
self._component = '%s/%s' % (self._package, self._runner)
self._enable_test_server_spawner = False
def EnableTestServerSpawner(self):
self._enable_test_server_spawner = True
def Install(self, device):
device.Install(self._apk)
......@@ -47,11 +54,14 @@ class _ApkDelegate(object):
with device_temp_file.DeviceTempFile(device.adb) as command_line_file:
device.WriteFile(command_line_file.name, '_ %s' % flags)
extras = {
_EXTRA_COMMAND_LINE_FILE: command_line_file.name,
}
if self._enable_test_server_spawner:
extras[_EXTRA_ENABLE_TEST_SERVER_SPAWNER] = '1'
return device.StartInstrumentation(
self._component,
extras={_EXTRA_COMMAND_LINE_FILE: command_line_file.name},
raw=False,
**kwargs)
self._component, extras=extras, raw=False, **kwargs)
def Clear(self, device):
device.ClearApplicationState(self._package)
......@@ -71,6 +81,9 @@ class _ExeDelegate(object):
self._deps_host_path = None
self._test_run = tr
def EnableTestServerSpawner(self):
pass
def Install(self, device):
# TODO(jbudorick): Look into merging this with normal data deps pushing if
# executables become supported on nonlocal environments.
......@@ -130,8 +143,6 @@ class LocalDeviceGtestRun(local_device_test_run.LocalDeviceTestRun):
elif self._test_instance.exe:
self._delegate = _ExeDelegate(self, self._test_instance.exe)
self._servers = {}
#override
def TestPackage(self):
return self._test_instance._suite
......@@ -150,14 +161,8 @@ class LocalDeviceGtestRun(local_device_test_run.LocalDeviceTestRun):
for h, d in host_device_tuples]
dev.PushChangedFiles(host_device_tuples)
self._servers[str(dev)] = []
if self.TestPackage() in _SUITE_REQUIRES_TEST_SERVER_SPAWNER:
self._servers[str(dev)].append(
local_test_server_spawner.LocalTestServerSpawner(
ports.AllocateTestServerPort(), dev, self.GetTool(dev)))
for s in self._servers[str(dev)]:
s.SetUp()
self._delegate.EnableTestServerSpawner()
self._env.parallel_devices.pMap(individual_device_set_up,
self._test_instance.GetDataDependencies())
......@@ -189,8 +194,6 @@ class LocalDeviceGtestRun(local_device_test_run.LocalDeviceTestRun):
# Run the test.
output = self._delegate.RunWithFlags(device, '--gtest_filter=%s' % test,
timeout=900, retries=0)
for s in self._servers[str(device)]:
s.Reset()
self._delegate.Clear(device)
# Parse the output.
......@@ -200,9 +203,5 @@ class LocalDeviceGtestRun(local_device_test_run.LocalDeviceTestRun):
#override
def TearDown(self):
def individual_device_tear_down(dev):
for s in self._servers[str(dev)]:
s.TearDown()
self._env.parallel_devices.pMap(individual_device_tear_down)
pass
......@@ -22,6 +22,7 @@
'<(DEPTH)/base/base.gyp:base_java',
'<(DEPTH)/build/android/pylib/device/commands/commands.gyp:chromium_commands',
'<(DEPTH)/build/android/pylib/remote/device/dummy/dummy.gyp:remote_device_dummy_apk',
'<(DEPTH)/net/net.gyp:net_java_test_support',
'<(DEPTH)/tools/android/android_tools.gyp:android_tools',
],
'conditions': [
......
......@@ -1490,6 +1490,7 @@ template("unittest_apk") {
deps = [
"//base:base_java",
"//build/android/pylib/remote/device/dummy:remote_device_dummy_apk",
"//net/android:net_java_test_support",
]
if (defined(invoker.deps)) {
deps += invoker.deps
......
......@@ -3043,6 +3043,7 @@
'dependencies': [
'chrome_java',
'../content/content_shell_and_tests.gyp:content_java_test_support',
'../net/net.gyp:net_java_test_support',
'../sync/sync.gyp:sync_java',
'../sync/sync.gyp:sync_java_test_support',
],
......
......@@ -16,6 +16,7 @@ android_library("chrome_java_test_support") {
"//components/invalidation:java",
"//content/public/android:content_java",
"//content/public/test/android:content_java_test_support",
"//net/android:net_java_test_support",
"//sync/android:sync_java",
"//sync:sync_java_test_support",
"//ui/android:ui_java",
......
......@@ -4,6 +4,7 @@
package org.chromium.chrome.test;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
......@@ -16,9 +17,7 @@ import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.RequestLine;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.DefaultHttpServerConnection;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.message.BasicStatusLine;
import org.apache.http.params.BasicHttpParams;
......@@ -26,15 +25,14 @@ import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.chromium.base.test.BaseInstrumentationTestRunner;
import org.chromium.net.test.BaseHttpTestServer;
import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
/**
......@@ -74,38 +72,30 @@ public class ChromeInstrumentationTestRunner extends BaseInstrumentationTestRunn
@Override
public void onStart() {
if (mRunTestHttpServer) startTestHttpServer();
if (mRunTestHttpServer) {
try {
startTestHttpServer();
} catch (IOException e) {
Log.e(TAG, "Failed to start HTTP test server", e);
finish(Activity.RESULT_CANCELED, null);
}
}
super.onStart();
}
private void startTestHttpServer() {
Object startLock = new Object();
mHttpServer = new TestHttpServer(Environment.getExternalStorageDirectory(), 8000,
startLock);
private void startTestHttpServer() throws IOException {
mHttpServer = new TestHttpServer(Environment.getExternalStorageDirectory(), 8000);
mHttpServerThread = new Thread(mHttpServer);
mHttpServerThread.start();
synchronized (startLock) {
try {
while (!mHttpServer.hasStarted()) {
startLock.wait();
}
} catch (InterruptedException e) {
Log.e(TAG, "Interrupted while starting test http server: " + e.toString());
}
}
}
private static class TestHttpServer implements Runnable {
private static class TestHttpServer extends BaseHttpTestServer {
private static final String TAG = "ChromeInstrumentationTestRunner.TestHttpServer";
private AtomicBoolean mHasStarted;
private AtomicBoolean mKeepRunning;
private int mPort;
private final File mRootDirectory;
private final String mRootPath;
private ServerSocket mServerSocket;
private Object mStartLock;
private static final int ACCEPT_TIMEOUT_MS = 5000;
private static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
private static final Map<String, String> EXTENSION_CONTENT_TYPE_MAP;
static {
......@@ -132,62 +122,26 @@ public class ChromeInstrumentationTestRunner extends BaseInstrumentationTestRunn
EXTENSION_CONTENT_TYPE_MAP = Collections.unmodifiableMap(m);
}
public TestHttpServer(File rootDirectory, int port, Object startLock) {
mHasStarted = new AtomicBoolean(false);
mKeepRunning = new AtomicBoolean(true);
mPort = port;
public TestHttpServer(File rootDirectory, int port) throws IOException {
super(port, ACCEPT_TIMEOUT_MS);
mRootDirectory = rootDirectory;
mRootPath = mRootDirectory.getAbsolutePath();
mServerSocket = null;
mStartLock = startLock;
}
@Override
public void run() {
synchronized (mStartLock) {
try {
mServerSocket = new ServerSocket(mPort);
} catch (IOException e) {
Log.e(TAG, "Could not open server socket on " + Integer.toString(mPort)
+ ": " + e.toString());
return;
} finally {
mHasStarted.set(true);
mStartLock.notify();
}
}
protected boolean validateSocket(Socket sock) {
return !sock.getInetAddress().isLoopbackAddress();
}
@Override
protected HttpParams getConnectionParams() {
HttpParams httpParams = new BasicHttpParams();
httpParams.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_0);
while (mKeepRunning.get()) {
try {
Socket sock = mServerSocket.accept();
if (!sock.getInetAddress().isLoopbackAddress()) {
Log.w(TAG, "Remote connections forbidden.");
sock.close();
continue;
}
DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
conn.bind(sock, httpParams);
HttpRequest request = conn.receiveRequestHeader();
HttpResponse response = generateResponse(request);
conn.sendResponseHeader(response);
conn.sendResponseEntity(response);
conn.close();
sock.close();
} catch (IOException e) {
Log.e(TAG, "Error while handling incoming connection: " + e.toString());
} catch (HttpException e) {
Log.e(TAG, "Error while handling HTTP request: " + e.toString());
}
}
return httpParams;
}
private HttpResponse generateResponse(HttpRequest request) {
@Override
protected HttpResponse handleGet(HttpRequest request) throws HttpException {
RequestLine requestLine = request.getRequestLine();
String requestPath = requestLine.getUri();
......@@ -200,11 +154,7 @@ public class ChromeInstrumentationTestRunner extends BaseInstrumentationTestRunn
int status = HttpStatus.SC_INTERNAL_SERVER_ERROR;
String reason = "";
HttpEntity entity = null;
if (!HttpGet.METHOD_NAME.equals(requestLine.getMethod())) {
Log.w(TAG, "Client made request using unsupported method: "
+ requestLine.getMethod());
status = HttpStatus.SC_METHOD_NOT_ALLOWED;
} else if (!requestedPath.startsWith(mRootPath)) {
if (!requestedPath.startsWith(mRootPath)) {
Log.w(TAG, "Client tried to request something outside of " + mRootPath + ": "
+ requestedPath);
status = HttpStatus.SC_FORBIDDEN;
......@@ -239,14 +189,6 @@ public class ChromeInstrumentationTestRunner extends BaseInstrumentationTestRunn
}
return response;
}
public boolean hasStarted() {
return mHasStarted.get();
}
public void stopServer() {
mKeepRunning.set(false);
}
}
@Override
......@@ -256,7 +198,7 @@ public class ChromeInstrumentationTestRunner extends BaseInstrumentationTestRunn
}
private void stopTestHttpServer() {
mHttpServer.stopServer();
mHttpServer.stop();
try {
mHttpServerThread.join();
} catch (InterruptedException e) {
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.net.test;
import android.util.Log;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.DefaultHttpServerConnection;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import java.io.IOException;
import java.net.Socket;
/** A base class for simple HTTP test servers. */
public abstract class BaseHttpTestServer extends BaseTcpTestServer {
private static final String TAG = "BaseHttpTestServer";
/**
* Create an HTTP test server on the given port.
*
* @param serverPort The port to listen on for incoming HTTP connections.
* @param acceptTimeoutMs The timeout for calls to ServerSocket.accept(), in milliseconds.
* @throws IOException If the server port can't be bound.
*/
public BaseHttpTestServer(int serverPort, int acceptTimeoutMs) throws IOException {
super(serverPort, acceptTimeoutMs);
}
/**
* Handle an incoming connection on |sock|.
*
* This will bind the socket, receive the request header (and entity, if applicable),
* dispatch the request to a handler based on the request method, and send the response
* generated by the handler.
*
* @param sock The socket for the incoming connection.
* @throws IOException If an error occurs while reading from or writing to the socket.
*/
@Override
protected final void handle(Socket sock) throws IOException {
HttpParams httpParams = getConnectionParams();
DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
conn.bind(sock, httpParams);
try {
HttpRequest request = conn.receiveRequestHeader();
if (request instanceof HttpEntityEnclosingRequest) {
conn.receiveRequestEntity((HttpEntityEnclosingRequest) request);
}
HttpResponse response = null;
switch (request.getRequestLine().getMethod()) {
case HttpGet.METHOD_NAME:
response = handleGet(request);
break;
case HttpPost.METHOD_NAME:
response = handlePost((HttpEntityEnclosingRequest) request);
break;
default:
response = handleUnsupported(request);
break;
}
conn.sendResponseHeader(response);
conn.sendResponseEntity(response);
} catch (HttpException e) {
Log.e(TAG, "Error while handling HTTP request", e);
} finally {
conn.close();
}
}
/**
* Returns the parameters used to establish the HTTP connection.
*
* The default implementation returns a default BasicHttpParams instance.
*
* @return The HttpParams to use to establish the HTTP connection.
*/
protected HttpParams getConnectionParams() {
return new BasicHttpParams();
}
/**
* Handle a GET request.
*
* The default implementation returns a 405. Override this function if you want to support
* GET.
*
* @param request The GET request to handle.
* @return The response to the GET request.
*/
protected HttpResponse handleGet(HttpRequest request) throws HttpException {
return handleUnsupported(request);
}
/**
* Handle a POST request.
*
* The default implementation returns a 405. Override this function if you want to support
* POST.
*
* @param request The POST request to handle.
* @return The response to the POST request.
*/
protected HttpResponse handlePost(HttpEntityEnclosingRequest request) throws HttpException {
return handleUnsupported(request);
}
/** Handle an unsupported HTTP request.
*
* @param request The unsupported HTTP request.
* @return A 405 Method Not Allowed response.
*/
protected HttpResponse handleUnsupported(HttpRequest request) {
return new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_METHOD_NOT_ALLOWED, "");
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.net.test;
import android.util.Log;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
/** A base class for simple TCP test servers. */
public abstract class BaseTcpTestServer extends BaseTestServer {
private static final String TAG = "BaseTcpTestServer";
private ServerSocket mServerSocket;
/**
* Creates a TCP test server on the given port.
*
* @param serverPort The port to listen on for incoming TCP connections.
* @param acceptTimeoutMs The timeout for calls to ServerSocket.accept(), in milliseconds.
* @throws IOException If the server port can't be bound.
*/
public BaseTcpTestServer(int serverPort, int acceptTimeoutMs) throws IOException {
mServerSocket = new ServerSocket(serverPort);
mServerSocket.setSoTimeout(acceptTimeoutMs);
}
/** Returns the port on which this server is listening for connections. */
@Override
public int getServerPort() {
return mServerSocket.getLocalPort();
}
/** Waits for and handles an incoming request. */
protected final void accept() {
try {
Socket sock = mServerSocket.accept();
if (!validateSocket(sock)) {
Log.e(TAG, "Socket failed validation.");
sock.close();
return;
}
handle(sock);
} catch (SocketTimeoutException e) {
Log.i(TAG, "Timed out waiting for incoming connection.");
} catch (IOException e) {
Log.e(TAG, "Error while handling incoming connection", e);
}
}
/**
* Returns whether the connection open on the given socket should be handled.
*
* @param sock The socket to validate.
*/
protected abstract boolean validateSocket(Socket sock);
/**
* Handles the connection open on the given socket.
*
* @param sock The socket to handle.
* @throws IOException If an error occurs while reading from or writing to the socket.
*/
protected abstract void handle(Socket sock) throws IOException;
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.net.test;
import java.util.concurrent.atomic.AtomicBoolean;
/** A base class for simple test servers. */
public abstract class BaseTestServer implements Runnable {
private AtomicBoolean mKeepRunning;
/** Creates a test server. */
public BaseTestServer() {
mKeepRunning = new AtomicBoolean(true);
}
/** Accepts incoming connections until stopped via stop(). */
public void run() {
mKeepRunning.set(true);
while (mKeepRunning.get()) {
accept();
}
}
/** Waits for and handles an incoming request. */
protected abstract void accept();
/** Returns the port on which this server is listening for connections. */
public abstract int getServerPort();
/** Stops the server. */
public void stop() {
mKeepRunning.set(false);
}
}
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.net.test;
import android.util.Log;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.RequestLine;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHttpResponse;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
/**
* A server that spawns test servers based on request JSONs.
*
* This communicates with net::SpawnerCommunicator according to the protocol specified in
* //net/test/spawned_test_server/spawner_communicator.h. It spawns test servers on the device.
*/
public class TestServerSpawner extends BaseHttpTestServer {
private static final String TAG = "TestServerSpawner";
private static final int ARBITRARY_MAX_JSON_SIZE = 65536;
private static final String COMMAND_KILL = "/kill";
private static final String COMMAND_PING = "/ping";
private static final String COMMAND_START = "/start";
private BaseTestServer mTestServer;
private Thread mTestServerThread;
/**
* Creates a test server spawner on the given port.
*
* @param serverPort The port to listen on for incoming connections.
* @param acceptTimeoutMs The timeout for calls to ServerSocket.accept(), in milliseconds.
* @throws IOException If the server port can't be bound.
*/
public TestServerSpawner(int serverPort, int acceptTimeoutMs) throws IOException {
super(serverPort, acceptTimeoutMs);
mTestServer = null;
mTestServerThread = null;
}
/**
* Returns true if the socket is coming from a local address.
*
* @param sock The socket to validate.
* @return True if the remote endpoint is local, false otherwise.
*/
@Override
protected boolean validateSocket(Socket sock) {
return sock.getInetAddress().isLoopbackAddress();
}
/**
* Handles a GET request.
*
* This handles the /kill and /ping commands. It returns 403s for anything else.
*
* @param request The GET request to handle.
* @return The response to |request|.
*/
@Override
protected HttpResponse handleGet(HttpRequest request) {
RequestLine requestLine = request.getRequestLine();
String uri = requestLine.getUri();
int status = HttpStatus.SC_INTERNAL_SERVER_ERROR;
String reason = "";
HttpEntity entity = null;
try {
// TODO(jbudorick): Refactor how this communicates with RemoteTestServer and
// SpawnerCommunicator (or maybe how we spawn and manage test servers on android
// entirely) once tests are no longer using chrome_test_server_spawner.py.
// The server startup and shutdown processes should be done in code (e.g. with events)
// rather than over HTTP. crbug/452596
if (COMMAND_KILL.equals(uri)) {
Log.i(TAG, "Received GET /kill request.");
if (mTestServer != null) {
mTestServer.stop();
mTestServerThread.join();
status = HttpStatus.SC_OK;
entity = new StringEntity("killed");
mTestServer = null;
} else {
status = HttpStatus.SC_BAD_REQUEST;
reason = "Test server does not exist.";
}
} else if (COMMAND_PING.equals(uri)) {
Log.i(TAG, "Received GET /ping request.");
status = HttpStatus.SC_OK;
entity = new StringEntity("ready");
} else {
status = HttpStatus.SC_FORBIDDEN;
}
} catch (InterruptedException e) {
Log.e(TAG, "Interrupted while joining test server thread: " + e.toString());
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unsupported encoding while writing response entity: " + e.toString());
entity = null;
}
BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_0, status, reason);
response.setEntity(entity);
return response;
}
/**
* Handles a POST request.
*
* This handles the /start command. It returns 403s for anything else.
*
* @param request The POST request to handle.
* @return The response to |request|.
*/
@Override
protected HttpResponse handlePost(HttpEntityEnclosingRequest request) throws HttpException {
RequestLine requestLine = request.getRequestLine();
String uri = requestLine.getUri();
int status = HttpStatus.SC_INTERNAL_SERVER_ERROR;
String reason = "";
HttpEntity responseEntity = null;
if (COMMAND_START.equals(uri)) {
Log.i(TAG, "Received POST /start request.");
BufferedReader entityReader = null;
try {
HttpEntity requestEntity = request.getEntity();
if (requestEntity.getContentLength() > ARBITRARY_MAX_JSON_SIZE) {
throw new HttpException("Request JSON too long ("
+ Long.toString(requestEntity.getContentLength()) + " bytes)");
}
entityReader = new BufferedReader(
new InputStreamReader(new BufferedInputStream(requestEntity.getContent())));
StringBuilder rawJson = new StringBuilder();
for (String line = entityReader.readLine(); line != null;
line = entityReader.readLine()) {
rawJson.append(line);
}
mTestServer = new TestServerBuilder(new JSONObject(rawJson.toString())).build();
mTestServerThread = new Thread(mTestServer);
mTestServerThread.start();
status = HttpStatus.SC_OK;
JSONObject entityJson = new JSONObject();
entityJson.put("port", mTestServer.getServerPort());
entityJson.put("message", "started");
responseEntity = new StringEntity(entityJson.toString());
} catch (UnsupportedOperationException e) {
// TODO(jbudorick): Remove this catch block once TestServerFactory.createTestServer
// is fully implemented.
throw new HttpException("Error creating test server", e);
} catch (JSONException e) {
throw new HttpException("Error handling JSON", e);
} catch (UnsupportedEncodingException e) {
throw new HttpException("Error generating response", e);
} catch (IOException e) {
throw new HttpException("Error while reading HTTP entity", e);
} finally {
try {
if (entityReader != null) entityReader.close();
} catch (IOException e) {
Log.e(TAG, "Unable to close entity input stream", e);
}
}
} else {
status = HttpStatus.SC_FORBIDDEN;
}
BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_0, status, reason);
response.setEntity(responseEntity);
return response;
}
}
......@@ -12,13 +12,17 @@ import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import org.chromium.net.test.TestServerSpawner;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
......@@ -32,9 +36,15 @@ public class ChromeNativeTestInstrumentationTestRunner extends Instrumentation {
public static final String EXTRA_ONLY_OUTPUT_FAILURES =
"org.chromium.native_test.ChromeNativeTestInstrumentationTestRunner."
+ "OnlyOutputFailures";
public static final String EXTRA_ENABLE_TEST_SERVER_SPAWNER =
"org.chromium.native_test.ChromeNativeTestInstrumentationTestRunner."
+ "EnableTestServerSpawner";
private static final String TAG = "ChromeNativeTestInstrumentationTestRunner";
private static final int ACCEPT_TIMEOUT_MS = 5000;
private static final Pattern RE_TEST_OUTPUT = Pattern.compile("\\[ *([^ ]*) *\\] ?([^ ]+) .*");
private static final int SERVER_SPAWNER_PORT = 0;
private static interface ResultsBundleGenerator {
public Bundle generate(Map<String, TestResult> rawResults);
......@@ -47,6 +57,10 @@ public class ChromeNativeTestInstrumentationTestRunner extends Instrumentation {
private ResultsBundleGenerator mBundleGenerator;
private boolean mOnlyOutputFailures;
private boolean mEnableTestServerSpawner;
private TestServerSpawner mTestServerSpawner;
private Thread mTestServerSpawnerThread;
@Override
public void onCreate(Bundle arguments) {
mCommandLineFile = arguments.getString(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FILE);
......@@ -63,16 +77,55 @@ public class ChromeNativeTestInstrumentationTestRunner extends Instrumentation {
mLogBundle = new Bundle();
mBundleGenerator = new RobotiumBundleGenerator();
mOnlyOutputFailures = arguments.containsKey(EXTRA_ONLY_OUTPUT_FAILURES);
mEnableTestServerSpawner = arguments.containsKey(EXTRA_ENABLE_TEST_SERVER_SPAWNER);
mTestServerSpawner = null;
mTestServerSpawnerThread = null;
start();
}
@Override
public void onStart() {
super.onStart();
setUp();
Bundle results = runTests();
tearDown();
finish(Activity.RESULT_OK, results);
}
private void setUp() {
if (mEnableTestServerSpawner) {
Log.i(TAG, "Test server spawner enabled.");
try {
mTestServerSpawner = new TestServerSpawner(SERVER_SPAWNER_PORT, ACCEPT_TIMEOUT_MS);
File portFile = new File(
Environment.getExternalStorageDirectory(), "net-test-server-ports");
OutputStreamWriter writer =
new OutputStreamWriter(new FileOutputStream(portFile));
writer.write(Integer.toString(mTestServerSpawner.getServerPort()) + ":0");
writer.close();
mTestServerSpawnerThread = new Thread(mTestServerSpawner);
mTestServerSpawnerThread.start();
} catch (IOException e) {
Log.e(TAG, "Error creating TestServerSpawner: " + e.toString());
}
}
}
private void tearDown() {
if (mTestServerSpawnerThread != null) {
try {
mTestServerSpawner.stop();
mTestServerSpawnerThread.join();
} catch (InterruptedException e) {
Log.e(TAG, "Interrupted while shutting down test server spawner: " + e.toString());
}
}
}
/** Runs the tests in the ChromeNativeTestActivity and returns a Bundle containing the results.
*/
private Bundle runTests() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment