summaryrefslogtreecommitdiffstats
path: root/tests/DumpRenderTree
diff options
context:
space:
mode:
Diffstat (limited to 'tests/DumpRenderTree')
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java29
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java19
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java5
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java147
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java203
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java112
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java117
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java92
8 files changed, 637 insertions, 87 deletions
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
index a389461..97a8b25 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
@@ -18,6 +18,7 @@ package com.android.dumprendertree;
import android.os.Handler;
import android.os.Message;
+import android.webkit.WebStorage;
import java.util.HashMap;
@@ -25,7 +26,7 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon
private EventSender mEventSender;
private LayoutTestController mLayoutTestController;
-
+
private static final int EVENT_DOM_LOG = 1;
private static final int EVENT_FIRE_KBD = 2;
private static final int EVENT_KEY_DOWN_1 = 3;
@@ -57,6 +58,8 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon
private static final int LAYOUT_SET_WINDOW_KEY = 38;
private static final int LAYOUT_TEST_REPAINT = 39;
private static final int LAYOUT_WAIT_UNTIL_DONE = 40;
+ private static final int LAYOUT_DUMP_DATABASE_CALLBACKS = 41;
+ private static final int LAYOUT_SET_CAN_OPEN_WINDOWS = 42;
CallbackProxy(EventSender eventSender,
LayoutTestController layoutTestController) {
@@ -190,6 +193,14 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon
case LAYOUT_WAIT_UNTIL_DONE:
mLayoutTestController.waitUntilDone();
break;
+
+ case LAYOUT_DUMP_DATABASE_CALLBACKS:
+ mLayoutTestController.dumpDatabaseCallbacks();
+ break;
+
+ case LAYOUT_SET_CAN_OPEN_WINDOWS:
+ mLayoutTestController.setCanOpenWindows();
+ break;
}
}
@@ -325,4 +336,20 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon
obtainMessage(LAYOUT_WAIT_UNTIL_DONE).sendToTarget();
}
+ public void dumpDatabaseCallbacks() {
+ obtainMessage(LAYOUT_DUMP_DATABASE_CALLBACKS).sendToTarget();
+ }
+
+ public void clearAllDatabases() {
+ WebStorage.getInstance().deleteAllData();
+ }
+
+ public void setDatabaseQuota(long quota) {
+ WebStorage.getInstance().setQuotaForOrigin("file://", quota);
+ }
+
+ public void setCanOpenWindows() {
+ obtainMessage(LAYOUT_SET_CAN_OPEN_WINDOWS).sendToTarget();
+ }
+
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 4f162b3..ede5197 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -83,7 +83,20 @@ public class FileFilter {
};
static final String [] ignoreTestList = {
- };
+ // RegExp is exponatal
+ "fast/regex/test1.html",
+ "fast/regex/slow.html",
+ // RegExp is too large, causing OOM
+ "fast/js/regexp-charclass-crash.html",
+ // The Android browser has no notion of private browsing.
+ "storage/private-browsing-readonly.html",
+ "storage/domstorage/localstorage/private-browsing-affects-storage.html",
+ "storage/domstorage/sessionstorage/private-browsing-affects-storage.html",
+ // Android layout tests are stored in "layout_tests". The following two
+ // tests expect "LayoutTests" in their output.
+ "storage/domstorage/localstorage/iframe-events.html",
+ "storage/domstorage/sessionstorage/iframe-events.html"
+ };
static void fillIgnoreResultSet() {
// need test plugin
@@ -195,11 +208,7 @@ public class FileFilter {
ignoreResultList.add("fast/loader/local-iFrame-source-from-local.html");
// extra spacing because iFrames rendered next to each other on Apple
ignoreResultList.add("fast/loader/opaque-base-url.html");
- // RegExp is too large, causing OOM
- ignoreResultList.add("fast/js/regexp-charclass-crash.html");
ignoreResultList.add("fast/text/plain-text-line-breaks.html");
-
-
}
static void fillBugTable() {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
index 6166dd0..e1d802a 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
@@ -58,5 +58,8 @@ public interface LayoutTestController {
public void queueLoad(String Url, String frameTarget);
public void setAcceptsEditing(boolean b);
-
+
+ // For storage tests
+ public void dumpDatabaseCallbacks();
+ public void setCanOpenWindows();
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index a03490d..2eecef8 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -16,6 +16,9 @@
package com.android.dumprendertree;
+import com.android.dumprendertree.forwarder.AdbUtils;
+import com.android.dumprendertree.forwarder.ForwardServer;
+
import android.app.Instrumentation;
import android.content.Intent;
import android.os.Bundle;
@@ -42,7 +45,7 @@ class MyTestRecorder {
private BufferedOutputStream mBufferedOutputFailedStream;
private BufferedOutputStream mBufferedOutputNoresultStream;
private BufferedOutputStream mBufferedOutputTimedoutStream;
-
+
public void passed(String layout_file) {
try {
mBufferedOutputPassedStream.write(layout_file.getBytes());
@@ -52,7 +55,7 @@ class MyTestRecorder {
e.printStackTrace();
}
}
-
+
public void failed(String layout_file) {
try {
mBufferedOutputFailedStream.write(layout_file.getBytes());
@@ -62,7 +65,7 @@ class MyTestRecorder {
e.printStackTrace();
}
}
-
+
public void noresult(String layout_file) {
try {
mBufferedOutputNoresultStream.write(layout_file.getBytes());
@@ -72,7 +75,7 @@ class MyTestRecorder {
e.printStackTrace();
}
}
-
+
public void timedout(String url) {
try {
mBufferedOutputTimedoutStream.write(url.getBytes());
@@ -82,14 +85,14 @@ class MyTestRecorder {
e.printStackTrace();
}
}
-
+
public MyTestRecorder(boolean resume) {
try {
File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt");
File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt");
File noExpectedResultFile = new File("/sdcard/layout_tests_nontext.txt");
File resultTimedoutFile = new File("/sdcard/layout_tests_timedout.txt");
-
+
mBufferedOutputPassedStream =
new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume));
mBufferedOutputFailedStream =
@@ -102,7 +105,7 @@ class MyTestRecorder {
e.printStackTrace();
}
}
-
+
public void close() {
try {
mBufferedOutputPassedStream.close();
@@ -120,7 +123,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
private static final String LOGTAG = "LayoutTests";
static final int DEFAULT_TIMEOUT_IN_MILLIS = 5000;
-
+
static final String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/";
static final String LAYOUT_TESTS_RESULT_DIR = "/sdcard/android/layout_tests_results/";
static final String ANDROID_EXPECTED_RESULT_DIR = "/sdcard/android/expected_results/";
@@ -139,14 +142,35 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
static final String LAYOUT_RESULTS_CRASHED_RESULT_FILE = "results/layout_tests_crashed.txt";
static final String LAYOUT_TESTS_RUNNER = "run_layout_tests.py";
+ static final String HTTP_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/";
+ static final String HTTPS_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/ssl/";
+ static final String HTTP_LOCAL_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/local/";
+ static final String HTTP_MEDIA_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/media/";
+ static final String HTTP_WML_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/wml/";
+
+
+ private ForwardServer fs8000, fs8080, fs8443;
+
private MyTestRecorder mResultRecorder;
private Vector<String> mTestList;
private boolean mRebaselineResults;
private String mTestPathPrefix;
private boolean mFinished;
-
+
public LayoutTestsAutoTest() {
super("com.android.dumprendertree", TestShellActivity.class);
+
+ int addr = -1;
+ try {
+ addr = AdbUtils.resolve("android-browser-test.mtv.corp.google.com");
+ } catch (IOException ioe) {
+ Log.e(LOGTAG, "failed to resolve server address.", ioe);
+ }
+ if(addr != -1) {
+ fs8000 = new ForwardServer(8000, addr, 8000);
+ fs8080 = new ForwardServer(8080, addr, 8080);
+ fs8443 = new ForwardServer(8443, addr, 8443);
+ }
}
// This function writes the result of the layout test to
@@ -157,7 +181,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
bundle.putBoolean(file, result);
inst.sendStatus(0, bundle);
}
-
+
private void getTestList() {
// Read test list.
try {
@@ -174,7 +198,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
}
}
-
+
private void resumeTestList() {
// read out the test name it stoped last time.
try {
@@ -189,7 +213,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE);
}
}
-
+
private void clearTestStatus() {
// Delete TEST_STATUS_FILE
try {
@@ -208,13 +232,13 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
// Write actual results to result directory.
return shortName.replaceFirst(LAYOUT_TESTS_ROOT, LAYOUT_TESTS_RESULT_DIR) + "-result.txt";
}
-
+
private String getExpectedResultFile(String test) {
int pos = test.lastIndexOf('.');
if(pos == -1)
return null;
String shortName = test.substring(0, pos);
- return shortName + "-expected.txt";
+ return shortName + "-expected.txt";
}
private String getAndroidExpectedResultFile(String expectedResultFile) {
@@ -224,7 +248,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
// Wrap up
private void failedCase(String file) {
Log.w("Layout test: ", file + " failed");
- mResultRecorder.failed(file);
+ mResultRecorder.failed(file);
}
private void passedCase(String file) {
@@ -236,7 +260,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
Log.v("Layout test:", file + " no expected result");
mResultRecorder.noresult(file);
}
-
+
private void processResult(String testFile, String actualResultFile, String expectedResultFile) {
Log.v(LOGTAG, " Processing result: " + testFile);
@@ -257,13 +281,13 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
break;
}
}
-
+
if (passing) {
passedCase(testFile);
} else {
failedCase(testFile);
}
-
+
fe.close();
fr.close();
} catch (FileNotFoundException ex) {
@@ -278,7 +302,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
noresultCase(testFile);
}
}
-
+
private void runTestAndWaitUntilDone(TestShellActivity activity, String test, int timeout) {
activity.setCallback(new TestShellCallback() {
public void finished() {
@@ -287,7 +311,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
LayoutTestsAutoTest.this.notifyAll();
}
}
-
+
public void timedOut(String url) {
}
});
@@ -306,16 +330,16 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
resultFile = getAndroidExpectedResultFile(expectedResultFile);
}
-
+
mFinished = false;
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setClass(activity, TestShellActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
- intent.putExtra(TestShellActivity.TEST_URL, "file://" + test);
+ intent.putExtra(TestShellActivity.TEST_URL, getTestUrl(test));
intent.putExtra(TestShellActivity.RESULT_FILE, resultFile);
intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
activity.startActivity(intent);
-
+
// Wait until done.
synchronized (this) {
while(!mFinished){
@@ -324,18 +348,18 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
} catch (InterruptedException e) { }
}
}
-
+
if (!mRebaselineResults) {
String expectedResultFile = getExpectedResultFile(test);
File f = new File(expectedResultFile);
if (!f.exists()) {
expectedResultFile = getAndroidExpectedResultFile(expectedResultFile);
}
-
+
processResult(test, resultFile, expectedResultFile);
}
- }
-
+ }
+
// Invokes running of layout tests
// and waits till it has finished running.
public void executeLayoutTests(boolean resume) {
@@ -348,28 +372,28 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
}
this.mTestList = new Vector<String>();
-
+
// Read settings
try {
this.mTestPathPrefix =
(new File(LAYOUT_TESTS_ROOT + runner.mTestPath)).getCanonicalPath();
- } catch (IOException e) {
+ } catch (IOException e) {
Log.e(LOGTAG, "Cannot find test path prefix: " + e.getMessage());
return;
}
-
+
this.mRebaselineResults = runner.mRebaseline;
-
+
int timeout = runner.mTimeoutInMillis;
if (timeout <= 0) {
timeout = DEFAULT_TIMEOUT_IN_MILLIS;
}
-
+
this.mResultRecorder = new MyTestRecorder(resume);
-
+
if (!resume)
clearTestStatus();
-
+
getTestList();
if (resume)
resumeTestList();
@@ -377,6 +401,15 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
TestShellActivity activity = (TestShellActivity) getActivity();
// Run tests.
+ int addr = -1;
+ try{
+ addr = AdbUtils.resolve("android-browser-test.mtv.corp.google.com");
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error while resolving test host name", ioe);
+ }
+ if(addr == -1) {
+ Log.w(LOGTAG, "failed to resolve test host. http tests will fail.");
+ }
for (int i = 0; i < mTestList.size(); i++) {
String s = mTestList.elementAt(i);
FsUtils.updateTestStatus(TEST_STATUS_FILE, s);
@@ -385,10 +418,48 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
}
FsUtils.updateTestStatus(TEST_STATUS_FILE, "#DONE");
-
+ if(fs8000 != null)
+ fs8000.stop();
+ if(fs8080 != null)
+ fs8080.stop();
+ if(fs8443 != null)
+ fs8443.stop();
+
activity.finish();
}
+ private void startForwardServerIfNeeded() {
+ try {
+ if(fs8000 != null)
+ fs8000.start();
+ if(fs8080 != null)
+ fs8080.start();
+ if(fs8443 != null)
+ fs8443.start();
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "failed to start forwarder. http tests will fail.", ioe);
+ }
+ }
+
+ private String getTestUrl(String path) {
+ String url = null;
+ if (!path.startsWith(HTTP_TESTS_PREFIX)) {
+ url = "file://" + path;
+ } else {
+ startForwardServerIfNeeded();
+ if (path.startsWith(HTTPS_TESTS_PREFIX)) {
+ // still cut the URL after "http/tests/"
+ url = "https://127.0.0.1:8443/" + path.substring(HTTP_TESTS_PREFIX.length());
+ } else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX)
+ && !path.startsWith(HTTP_MEDIA_TESTS_PREFIX)
+ && !path.startsWith(HTTP_WML_TESTS_PREFIX)) {
+ url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length());
+ } else {
+ url = "file://" + path;
+ }
+ }
+ return url;
+ }
private String getTestPath() {
LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
@@ -403,10 +474,10 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
Log.e("LayoutTestsAutoTest", "Cannot get cannonical path " + e.getMessage());
}
Log.v("LayoutTestsAutoTest", " Test path : " + test_path);
-
+
return test_path;
}
-
+
public void generateTestList() {
try {
File tests_list = new File(LAYOUT_TESTS_LIST_FILE);
@@ -431,7 +502,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
} catch (Exception e) {
e.printStackTrace();
}
-
+
executeLayoutTests(false);
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 09f7cbc..30e1d99 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -34,6 +34,7 @@ import android.webkit.JsResult;
import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
+import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.LinearLayout;
@@ -43,6 +44,8 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.util.Vector;
public class TestShellActivity extends Activity implements LayoutTestController {
@@ -88,7 +91,7 @@ public class TestShellActivity extends Activity implements LayoutTestController
}
public void clearCache() {
- mWebView.clearCache(true);
+ mWebView.freeMemory();
}
@Override
@@ -100,48 +103,11 @@ public class TestShellActivity extends Activity implements LayoutTestController
setContentView(contentView);
mWebView = new WebView(this);
- mWebView.getSettings().setJavaScriptEnabled(true);
- mWebView.setWebChromeClient(mChromeClient);
- mWebView.setWebViewClient(new WebViewClient(){
-
- @Override
- public void onPageFinished(WebView view, String url) {
- Log.v(LOGTAG, "onPageFinished, url=" + url);
- super.onPageFinished(view, url);
- }
-
- @Override
- public void onPageStarted(WebView view, String url, Bitmap favicon) {
- Log.v(LOGTAG, "onPageStarted, url=" + url);
- super.onPageStarted(view, url, favicon);
- }
-
- @Override
- public void onReceivedError(WebView view, int errorCode, String description,
- String failingUrl) {
- Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode
- + ", desc=" + description + ", url=" + failingUrl);
- super.onReceivedError(view, errorCode, description, failingUrl);
- }
-
- @Override
- public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
- String host, String realm) {
- handler.cancel();
- }
-
- @Override
- public void onReceivedSslError(WebView view, SslErrorHandler handler,
- SslError error) {
- handler.proceed();
- }
-
- });
mEventSender = new WebViewEventSender(mWebView);
mCallbackProxy = new CallbackProxy(mEventSender, this);
- mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController");
- mWebView.addJavascriptInterface(mCallbackProxy, "eventSender");
+ setupWebViewForLayoutTests(mWebView, mCallbackProxy);
+
contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0f));
mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
@@ -262,8 +228,8 @@ public class TestShellActivity extends Activity implements LayoutTestController
@Override
public void onLowMemory() {
super.onLowMemory();
- Log.e(LOGTAG, "Low memory, kill self");
- System.exit(1);
+ Log.e(LOGTAG, "Low memory, clearing caches");
+ mWebView.freeMemory();
}
// Dump the page
@@ -290,6 +256,12 @@ public class TestShellActivity extends Activity implements LayoutTestController
if (mDialogStrings != null)
os.write(mDialogStrings.toString().getBytes());
mDialogStrings = null;
+ if (mDatabaseCallbackStrings != null)
+ os.write(mDatabaseCallbackStrings.toString().getBytes());
+ mDatabaseCallbackStrings = null;
+ if (mConsoleMessages != null)
+ os.write(mConsoleMessages.toString().getBytes());
+ mConsoleMessages = null;
if (webkitData != null)
os.write(webkitData.getBytes());
os.flush();
@@ -438,6 +410,51 @@ public class TestShellActivity extends Activity implements LayoutTestController
mWebView.invalidate();
}
+ public void dumpDatabaseCallbacks() {
+ Log.v(LOGTAG, "dumpDatabaseCallbacks called.");
+ mDumpDatabaseCallbacks = true;
+ }
+
+ public void setCanOpenWindows() {
+ Log.v(LOGTAG, "setCanOpenWindows called.");
+ mCanOpenWindows = true;
+ }
+
+ private final WebViewClient mViewClient = new WebViewClient(){
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ Log.v(LOGTAG, "onPageFinished, url=" + url);
+ super.onPageFinished(view, url);
+ }
+
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ Log.v(LOGTAG, "onPageStarted, url=" + url);
+ super.onPageStarted(view, url, favicon);
+ }
+
+ @Override
+ public void onReceivedError(WebView view, int errorCode, String description,
+ String failingUrl) {
+ Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode
+ + ", desc=" + description + ", url=" + failingUrl);
+ super.onReceivedError(view, errorCode, description, failingUrl);
+ }
+
+ @Override
+ public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
+ String host, String realm) {
+ handler.cancel();
+ }
+
+ @Override
+ public void onReceivedSslError(WebView view, SslErrorHandler handler,
+ SslError error) {
+ handler.proceed();
+ }
+ };
+
+
private final WebChromeClient mChromeClient = new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
@@ -512,6 +529,78 @@ public class TestShellActivity extends Activity implements LayoutTestController
result.confirm();
return true;
}
+
+ @Override
+ public boolean onJsTimeout() {
+ Log.v(LOGTAG, "JavaScript timeout");
+ return false;
+ }
+
+ @Override
+ public void onExceededDatabaseQuota(String url_str,
+ String databaseIdentifier, long currentQuota, long totalUsedQuota,
+ WebStorage.QuotaUpdater callback) {
+ if (mDumpDatabaseCallbacks) {
+ if (mDatabaseCallbackStrings == null) {
+ mDatabaseCallbackStrings = new StringBuffer();
+ }
+
+ String protocol = "";
+ String host = "";
+ int port = 0;
+
+ try {
+ URL url = new URL(url_str);
+ protocol = url.getProtocol();
+ host = url.getHost();
+ if (url.getPort() > -1) {
+ port = url.getPort();
+ }
+ } catch (MalformedURLException e) {}
+
+ String databaseCallbackString =
+ "UI DELEGATE DATABASE CALLBACK: " +
+ "exceededDatabaseQuotaForSecurityOrigin:{" + protocol +
+ ", " + host + ", " + port + "} database:" +
+ databaseIdentifier + "\n";
+ Log.v(LOGTAG, "LOG: "+databaseCallbackString);
+ mDatabaseCallbackStrings.append(databaseCallbackString);
+ }
+ // Give 5MB more quota.
+ callback.updateQuota(currentQuota + 1024 * 1024 * 5);
+ }
+
+ @Override
+ public void addMessageToConsole(String message, int lineNumber,
+ String sourceID) {
+ if (mConsoleMessages == null) {
+ mConsoleMessages = new StringBuffer();
+ }
+ String consoleMessage = "CONSOLE MESSAGE: line "
+ + lineNumber +": "+ message +"\n";
+ mConsoleMessages.append(consoleMessage);
+ Log.v(LOGTAG, "LOG: "+consoleMessage);
+ }
+
+ @Override
+ public boolean onCreateWindow(WebView view, boolean dialog,
+ boolean userGesture, Message resultMsg) {
+ if (!mCanOpenWindows) {
+ return false;
+ }
+
+ // We never display the new window, just create the view and
+ // allow it's content to execute and be recorded by the test
+ // runner.
+
+ WebView newWindowView = new WebView(TestShellActivity.this);
+ setupWebViewForLayoutTests(newWindowView, mCallbackProxy);
+ WebView.WebViewTransport transport =
+ (WebView.WebViewTransport) resultMsg.obj;
+ transport.setWebView(newWindowView);
+ resultMsg.sendToTarget();
+ return true;
+ }
};
private void resetTestStatus() {
@@ -520,9 +609,35 @@ public class TestShellActivity extends Activity implements LayoutTestController
mTimedOut = false;
mDumpTitleChanges = false;
mRequestedWebKitData = false;
+ mDumpDatabaseCallbacks = false;
+ mCanOpenWindows = false;
mEventSender.resetMouse();
}
+ private void setupWebViewForLayoutTests(WebView webview, CallbackProxy callbackProxy) {
+ if (webview == null) {
+ return;
+ }
+
+ WebSettings settings = webview.getSettings();
+ settings.setAppCacheEnabled(true);
+ settings.setAppCachePath(getApplicationContext().getCacheDir().getPath());
+ settings.setAppCacheMaxSize(Long.MAX_VALUE);
+ settings.setJavaScriptEnabled(true);
+ settings.setJavaScriptCanOpenWindowsAutomatically(true);
+ settings.setSupportMultipleWindows(true);
+ settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
+ settings.setDatabaseEnabled(true);
+ settings.setDatabasePath(getDir("databases",0).getAbsolutePath());
+ settings.setDomStorageEnabled(true);
+
+ webview.addJavascriptInterface(callbackProxy, "layoutTestController");
+ webview.addJavascriptInterface(callbackProxy, "eventSender");
+
+ webview.setWebChromeClient(mChromeClient);
+ webview.setWebViewClient(mViewClient);
+ }
+
private WebView mWebView;
private WebViewEventSender mEventSender;
private AsyncHandler mHandler;
@@ -550,6 +665,10 @@ public class TestShellActivity extends Activity implements LayoutTestController
private StringBuffer mDialogStrings;
private boolean mKeepWebHistory;
private Vector mWebHistory;
+ private boolean mDumpDatabaseCallbacks;
+ private StringBuffer mDatabaseCallbackStrings;
+ private StringBuffer mConsoleMessages;
+ private boolean mCanOpenWindows;
static final String TIMEOUT_STR = "**Test timeout";
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
new file mode 100644
index 0000000..9a3e9c2
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
@@ -0,0 +1,112 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+public class AdbUtils {
+
+ private static final String ADB_OK = "OKAY";
+ private static final int ADB_PORT = 5037;
+ private static final String ADB_HOST = "127.0.0.1";
+ private static final int ADB_RESPONSE_SIZE = 4;
+
+ private static final String LOGTAG = "AdbUtils";
+
+ /**
+ *
+ * Convert integer format IP into xxx.xxx.xxx.xxx format
+ *
+ * @param host IP address in integer format
+ * @return human readable format
+ */
+ public static String convert(int host) {
+ return ((host >> 24) & 0xFF) + "."
+ + ((host >> 16) & 0xFF) + "."
+ + ((host >> 8) & 0xFF) + "."
+ + (host & 0xFF);
+ }
+
+ /**
+ *
+ * Resolve DNS name into IP address
+ *
+ * @param host DNS name
+ * @return IP address in integer format
+ * @throws IOException
+ */
+ public static int resolve(String host) throws IOException {
+ Socket localSocket = new Socket(ADB_HOST, ADB_PORT);
+ DataInputStream dis = new DataInputStream(localSocket.getInputStream());
+ OutputStream os = localSocket.getOutputStream();
+ int count_read = 0;
+ byte[] buf = new byte[128];
+
+ if (localSocket == null || dis == null || os == null)
+ return -1;
+ String cmd = "dns:" + host;
+
+ if(!sendAdbCmd(dis, os, cmd))
+ return -1;
+
+ count_read = dis.readInt();
+ localSocket.close();
+ return count_read;
+ }
+
+ /**
+ *
+ * Send an ADB command using existing socket connection
+ *
+ * the streams provided must be from a socket connected to adbd already
+ *
+ * @param is input stream of the socket connection
+ * @param os output stream of the socket
+ * @param cmd the adb command to send
+ * @return if adb gave a success response
+ * @throws IOException
+ */
+ public static boolean sendAdbCmd(InputStream is, OutputStream os,
+ String cmd) throws IOException {
+ byte[] buf = new byte[ADB_RESPONSE_SIZE];
+
+ cmd = String.format("%04X", cmd.length()) + cmd;
+ os.write(cmd.getBytes());
+ int read = is.read(buf);
+ if(read != ADB_RESPONSE_SIZE || !ADB_OK.equals(new String(buf))) {
+ Log.w(LOGTAG, "adb cmd faild.");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ *
+ * Get a tcp socket connection to specified IP address and port proxied by adb
+ *
+ * The proxying is transparent, e.g. if a socket is returned, then it can be written to and
+ * read from as if it is directly connected to the target
+ *
+ * @param remoteAddress IP address of the host to connect to
+ * @param remotePort port of the host to connect to
+ * @return a valid Socket instance if successful, null otherwise
+ */
+ public static Socket getForwardedSocket(int remoteAddress, int remotePort) {
+ try {
+ Socket socket = new Socket(ADB_HOST, ADB_PORT);
+ String cmd = "tcp:" + remotePort + ":" + convert(remoteAddress);
+ if(!sendAdbCmd(socket.getInputStream(), socket.getOutputStream(), cmd)) {
+ socket.close();
+ return null;
+ }
+ return socket;
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error creating adb socket", ioe);
+ return null;
+ }
+ }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
new file mode 100644
index 0000000..74e018e
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
@@ -0,0 +1,117 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ *
+ * A port forwarding server. Listens at specified local port and forward the tcp communications to
+ * external host/port via adb networking proxy.
+ *
+ */
+public class ForwardServer {
+
+ private static final String LOGTAG = "ForwardServer";
+
+ private int remotePort;
+ private int remoteAddress;
+ private int localPort;
+ private ServerSocket serverSocket;
+ private boolean started;
+
+ private Set<Forwarder> forwarders;
+
+ public ForwardServer(int localPort, int remoteAddress, int remotePort) {
+ this.localPort = localPort;
+ this.remoteAddress = remoteAddress;
+ this.remotePort = remotePort;
+ started = false;
+ forwarders = new HashSet<Forwarder>();
+ }
+
+ public synchronized void start() throws IOException {
+ if(!started) {
+ serverSocket = new ServerSocket(localPort);
+ Thread serverThread = new Thread(new ServerRunner(serverSocket));
+ serverThread.setName(LOGTAG);
+ serverThread.start();
+ started = true;
+ }
+ }
+
+ public synchronized void stop() {
+ if(started) {
+ synchronized (forwarders) {
+ for(Forwarder forwarder : forwarders)
+ forwarder.stop();
+ forwarders.clear();
+ }
+ try {
+ serverSocket.close();
+ } catch (IOException ioe) {
+ Log.v(LOGTAG, "exception while closing", ioe);
+ } finally {
+ started = false;
+ }
+ }
+ }
+
+ public synchronized boolean isRunning() {
+ return started;
+ }
+
+ private class ServerRunner implements Runnable {
+
+ private ServerSocket socket;
+
+ public ServerRunner(ServerSocket socket) {
+ this.socket = socket;
+ }
+
+ public void run() {
+ try {
+ while (true) {
+ Socket localSocket = socket.accept();
+ Socket remoteSocket = AdbUtils.getForwardedSocket(remoteAddress, remotePort);
+ if(remoteSocket == null) {
+ try {
+ localSocket.close();
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "error while closing socket", ioe);
+ } finally {
+ Log.w(LOGTAG, "failed to start forwarding from " + localSocket);
+ }
+ } else {
+ Forwarder forwarder = new Forwarder(localSocket, remoteSocket,
+ ForwardServer.this);
+ forwarder.start();
+ }
+ }
+ } catch (IOException ioe) {
+ return;
+ }
+ }
+ }
+
+ public void register(Forwarder forwarder) {
+ synchronized (forwarders) {
+ if(!forwarders.contains(forwarder)) {
+ forwarders.add(forwarder);
+ }
+ }
+ }
+
+ public void unregister(Forwarder recyclable) {
+ synchronized (forwarders) {
+ if(forwarders.contains(recyclable)) {
+ recyclable.stop();
+ forwarders.remove(recyclable);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
new file mode 100644
index 0000000..e1e04a7
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
@@ -0,0 +1,92 @@
+package com.android.dumprendertree.forwarder;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/**
+ *
+ * Worker class for {@link ForwardServer}. A Forwarder will be created once the ForwardServer
+ * accepts an incoming connection, and it will then forward the incoming/outgoing streams to a
+ * connection already proxied by adb networking (see also {@link AdbUtils}).
+ *
+ */
+public class Forwarder {
+
+ private ForwardServer server;
+ private Socket from, to;
+
+ private static final String LOGTAG = "Forwarder";
+
+ public Forwarder (Socket from, Socket to, ForwardServer server) {
+ this.server = server;
+ this.from = from;
+ this.to = to;
+ server.register(this);
+ }
+
+ public void start() {
+ Thread outgoing = new Thread(new SocketPipe(from, to));
+ Thread incoming = new Thread(new SocketPipe(to, from));
+ outgoing.setName(LOGTAG);
+ incoming.setName(LOGTAG);
+ outgoing.start();
+ incoming.start();
+ }
+
+ public void stop() {
+ shutdown(from);
+ shutdown(to);
+ }
+
+ private void shutdown(Socket socket) {
+ try {
+ socket.shutdownInput();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#shutdownInput", e);
+ }
+ try {
+ socket.shutdownOutput();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#shutdownOutput", e);
+ }
+ try {
+ socket.close();
+ } catch (IOException e) {
+ Log.v(LOGTAG, "Socket#close", e);
+ }
+ }
+
+ private class SocketPipe implements Runnable {
+
+ private Socket in, out;
+
+ public SocketPipe(Socket in, Socket out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ public void run() {
+ try {
+ int length;
+ InputStream is = in.getInputStream();
+ OutputStream os = out.getOutputStream();
+ byte[] buffer = new byte[4096];
+ while ((length = is.read(buffer)) > 0) {
+ os.write(buffer, 0, length);
+ }
+ } catch (IOException ioe) {
+ } finally {
+ server.unregister(Forwarder.this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "SocketPipe{" + in + "=>" + out + "}";
+ }
+ }
+}