From 606e9392b3585a5ca401d65e1515963390b5e8ff Mon Sep 17 00:00:00 2001 From: Andrei Popescu Date: Tue, 9 Feb 2010 16:59:58 +0000 Subject: Implement test to iterate over list of URLs and store load times. Also patch makefiles to correctly build tests and allow for hidden API calls in test. --- tests/Android.mk | 3 - tests/src/com/android/browser/PopularUrlsTest.java | 249 +++++++++++++++++++++ .../com/android/browser/TestWebChromeClient.java | 201 +++++++++++++++++ .../src/com/android/browser/TestWebViewClient.java | 127 +++++++++++ 4 files changed, 577 insertions(+), 3 deletions(-) create mode 100644 tests/src/com/android/browser/PopularUrlsTest.java create mode 100644 tests/src/com/android/browser/TestWebChromeClient.java create mode 100644 tests/src/com/android/browser/TestWebViewClient.java (limited to 'tests') diff --git a/tests/Android.mk b/tests/Android.mk index f86942d..ce9acbd 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -31,7 +31,4 @@ LOCAL_PACKAGE_NAME := BrowserTests LOCAL_INSTRUMENTATION_FOR := Browser -LOCAL_SDK_VERSION := current - include $(BUILD_PACKAGE) - diff --git a/tests/src/com/android/browser/PopularUrlsTest.java b/tests/src/com/android/browser/PopularUrlsTest.java new file mode 100644 index 0000000..4ae69c7 --- /dev/null +++ b/tests/src/com/android/browser/PopularUrlsTest.java @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * 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.android.browser; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.concurrent.CountDownLatch; + +import android.app.Instrumentation; +import android.content.Intent; +import android.net.Uri; +import android.net.http.SslError; +import android.os.Environment; +import android.test.ActivityInstrumentationTestCase2; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.Log; +import android.webkit.JsPromptResult; +import android.webkit.JsResult; +import android.webkit.SslErrorHandler; +import android.webkit.WebView; + +/** + * + * Iterates over a list of URLs from a file and outputs the time to load each. + */ +public class PopularUrlsTest extends ActivityInstrumentationTestCase2 { + + private final static String TAG = "PopularUrlsTest"; + private final static String newLine = System.getProperty("line.separator"); + private final static String sInputFile = "popular_urls.txt"; + private final static String sOutputFile = "test_output.txt"; + private final static File sExternalStorage = Environment.getExternalStorageDirectory(); + private BrowserActivity mActivity = null; + private Instrumentation mInst = null; + private CountDownLatch mLatch = new CountDownLatch(1); + + public PopularUrlsTest() { + super("com.android.browser", BrowserActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mActivity = getActivity(); + mInst = getInstrumentation(); + mInst.waitForIdleSync(); + } + + static BufferedReader getInputStream() throws FileNotFoundException { + String path = sExternalStorage + File.separator + sInputFile; + FileReader fileReader = new FileReader(path); + BufferedReader bufferedReader = new BufferedReader(fileReader); + + return bufferedReader; + } + + static OutputStreamWriter getOutputStream() throws IOException { + String path = sExternalStorage + File.separator + sOutputFile; + + File file = new File(path); + if (file.exists()) { + file.delete(); + } + + return new FileWriter(file); + } + + /** + * Gets the browser ready for testing by starting the application + * and wrapping the WebView's helper clients. + */ + void setUpBrowser() { + Tab tab = mActivity.getTabControl().getCurrentTab(); + WebView webView = tab.getWebView(); + + webView.setWebChromeClient(new TestWebChromeClient(webView.getWebChromeClient()) { + + /** + * Reset the latch whenever page progress reaches 100%. + */ + @Override + public void onProgressChanged(WebView view, int newProgress) { + super.onProgressChanged(view, newProgress); + if (newProgress >= 100) { + resetLatch(); + } + } + + /** + * Dismisses and logs Javascript alerts. + */ + @Override + public boolean onJsAlert(WebView view, String url, String message, + JsResult result) { + String logMsg = String.format("JS Alert '%s' received from %s", message, url); + Log.w(TAG, logMsg); + result.confirm(); + + return true; + } + + /** + * Confirms and logs Javascript alerts. + */ + @Override + public boolean onJsConfirm(WebView view, String url, String message, + JsResult result) { + String logMsg = String.format("JS Confirmation '%s' received from %s", + message, url); + Log.w(TAG, logMsg); + result.confirm(); + + return true; + } + + /** + * Confirms and logs Javascript alerts, providing the default value. + */ + @Override + public boolean onJsPrompt(WebView view, String url, String message, + String defaultValue, JsPromptResult result) { + String logMsg = String.format("JS Prompt '%s' received from %s; " + + "Giving default value '%s'", message, url, defaultValue); + Log.w(TAG, logMsg); + result.confirm(defaultValue); + + return true; + } + }); + + webView.setWebViewClient(new TestWebViewClient(webView.getWebViewClient()) { + + /** + * Bypasses and logs errors. + */ + @Override + public void onReceivedError(WebView view, int errorCode, + String description, String failingUrl) { + String message = String.format("Error '%s' (%d) loading url: %s", + description, errorCode, failingUrl); + Log.w(TAG, message); + } + + /** + * Ignores and logs SSL errors. + */ + @Override + public void onReceivedSslError(WebView view, SslErrorHandler handler, + SslError error) { + Log.w(TAG, "SSL error: " + error); + handler.proceed(); + } + + }); + } + + void resetLatch() { + CountDownLatch temp = mLatch; + mLatch = new CountDownLatch(1); + if (temp != null) { + // Notify existing latch that it's done. + while (temp.getCount() > 0) { + temp.countDown(); + } + } + } + + void waitForLoad() throws InterruptedException { + mLatch.await(); + } + + /** + * Loops over a list of URLs, points the browser to each one, and records the time elapsed. + * + * @param input the reader from which to get the URLs. + * @param writer the writer to which to output the results. + * @throws IOException unable to read from input or write to writer. + * @throws InterruptedException the thread was interrupted waiting for the page to load. + */ + void loopUrls(BufferedReader input, OutputStreamWriter writer) + throws IOException, InterruptedException { + Tab tab = mActivity.getTabControl().getCurrentTab(); + WebView webView = tab.getWebView(); + String page; + + while (null != (page = input.readLine())) { + Uri uri = Uri.parse(page); + webView.clearCache(true); + final Intent intent = new Intent(Intent.ACTION_VIEW, uri); + writer.write(uri.toString()); + + long startTime = System.nanoTime(); + mInst.runOnMainSync(new Runnable() { + + public void run() { + mActivity.onNewIntent(intent); + } + + }); + waitForLoad(); + long stopTime = System.nanoTime(); + + String url = webView.getUrl(); + Log.i(TAG, "Loaded url: " + url); + writer.write("|" + (stopTime - startTime) + newLine); + } + } + + public void testLoadPerformance() throws IOException, InterruptedException { + setUpBrowser(); + + OutputStreamWriter writer = getOutputStream(); + try { + BufferedReader bufferedReader = getInputStream(); + try { + loopUrls(bufferedReader, writer); + } finally { + if (bufferedReader != null) { + bufferedReader.close(); + } + } + } finally { + if (writer != null) { + writer.close(); + } + } + } +} + diff --git a/tests/src/com/android/browser/TestWebChromeClient.java b/tests/src/com/android/browser/TestWebChromeClient.java new file mode 100644 index 0000000..d78eaed --- /dev/null +++ b/tests/src/com/android/browser/TestWebChromeClient.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * 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.android.browser; + +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Message; +import android.view.View; +import android.webkit.ConsoleMessage; +import android.webkit.GeolocationPermissions; +import android.webkit.JsPromptResult; +import android.webkit.JsResult; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient; +import android.webkit.WebStorage; +import android.webkit.WebView; + +/** + * + * WebChromeClient for browser tests. + * Wraps around existing client so that specific methods can be overridden if needed. + * + */ +abstract class TestWebChromeClient extends WebChromeClient { + + private WebChromeClient mWrappedClient; + + protected TestWebChromeClient(WebChromeClient wrappedClient) { + mWrappedClient = wrappedClient; + } + + /** {@inheritDoc} */ + @Override + public void onProgressChanged(WebView view, int newProgress) { + mWrappedClient.onProgressChanged(view, newProgress); + } + + /** {@inheritDoc} */ + @Override + public void onReceivedTitle(WebView view, String title) { + mWrappedClient.onReceivedTitle(view, title); + } + + /** {@inheritDoc} */ + @Override + public void onReceivedIcon(WebView view, Bitmap icon) { + mWrappedClient.onReceivedIcon(view, icon); + } + + /** {@inheritDoc} */ + @Override + public void onReceivedTouchIconUrl(WebView view, String url, + boolean precomposed) { + mWrappedClient.onReceivedTouchIconUrl(view, url, precomposed); + } + + /** {@inheritDoc} */ + @Override + public void onShowCustomView(View view, CustomViewCallback callback) { + mWrappedClient.onShowCustomView(view, callback); + } + + /** {@inheritDoc} */ + @Override + public void onHideCustomView() { + mWrappedClient.onHideCustomView(); + } + + /** {@inheritDoc} */ + @Override + public boolean onCreateWindow(WebView view, boolean dialog, + boolean userGesture, Message resultMsg) { + return mWrappedClient.onCreateWindow(view, dialog, userGesture, resultMsg); + } + + /** {@inheritDoc} */ + @Override + public void onRequestFocus(WebView view) { + mWrappedClient.onRequestFocus(view); + } + + /** {@inheritDoc} */ + @Override + public void onCloseWindow(WebView window) { + mWrappedClient.onCloseWindow(window); + } + + /** {@inheritDoc} */ + @Override + public boolean onJsAlert(WebView view, String url, String message, + JsResult result) { + return mWrappedClient.onJsAlert(view, url, message, result); + } + + /** {@inheritDoc} */ + @Override + public boolean onJsConfirm(WebView view, String url, String message, + JsResult result) { + return mWrappedClient.onJsConfirm(view, url, message, result); + } + + /** {@inheritDoc} */ + @Override + public boolean onJsPrompt(WebView view, String url, String message, + String defaultValue, JsPromptResult result) { + return mWrappedClient.onJsPrompt(view, url, message, defaultValue, result); + } + + /** {@inheritDoc} */ + @Override + public boolean onJsBeforeUnload(WebView view, String url, String message, + JsResult result) { + return mWrappedClient.onJsBeforeUnload(view, url, message, result); + } + + /** {@inheritDoc} */ + @Override + public void onExceededDatabaseQuota(String url, String databaseIdentifier, + long currentQuota, long estimatedSize, long totalUsedQuota, + WebStorage.QuotaUpdater quotaUpdater) { + mWrappedClient.onExceededDatabaseQuota(url, databaseIdentifier, currentQuota, + estimatedSize, totalUsedQuota, quotaUpdater); + } + + /** {@inheritDoc} */ + @Override + public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota, + WebStorage.QuotaUpdater quotaUpdater) { + mWrappedClient.onReachedMaxAppCacheSize(spaceNeeded, totalUsedQuota, quotaUpdater); + } + + /** {@inheritDoc} */ + @Override + public void onGeolocationPermissionsShowPrompt(String origin, + GeolocationPermissions.Callback callback) { + mWrappedClient.onGeolocationPermissionsShowPrompt(origin, callback); + } + + /** {@inheritDoc} */ + @Override + public void onGeolocationPermissionsHidePrompt() { + mWrappedClient.onGeolocationPermissionsHidePrompt(); + } + + /** {@inheritDoc} */ + @Override + public boolean onJsTimeout() { + return mWrappedClient.onJsTimeout(); + } + + /** {@inheritDoc} */ + @Override + @Deprecated + public void onConsoleMessage(String message, int lineNumber, String sourceID) { + mWrappedClient.onConsoleMessage(message, lineNumber, sourceID); + } + + /** {@inheritDoc} */ + @Override + public boolean onConsoleMessage(ConsoleMessage consoleMessage) { + return mWrappedClient.onConsoleMessage(consoleMessage); + } + + /** {@inheritDoc} */ + @Override + public Bitmap getDefaultVideoPoster() { + return mWrappedClient.getDefaultVideoPoster(); + } + + /** {@inheritDoc} */ + @Override + public View getVideoLoadingProgressView() { + return mWrappedClient.getVideoLoadingProgressView(); + } + + /** {@inheritDoc} */ + @Override + public void getVisitedHistory(ValueCallback callback) { + mWrappedClient.getVisitedHistory(callback); + } + + /** {@inheritDoc} */ + @Override + public void openFileChooser(ValueCallback uploadFile) { + mWrappedClient.openFileChooser(uploadFile); + } +} diff --git a/tests/src/com/android/browser/TestWebViewClient.java b/tests/src/com/android/browser/TestWebViewClient.java new file mode 100644 index 0000000..7159a7e --- /dev/null +++ b/tests/src/com/android/browser/TestWebViewClient.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * 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.android.browser; + +import android.graphics.Bitmap; +import android.net.http.SslError; +import android.os.Message; +import android.view.KeyEvent; +import android.webkit.HttpAuthHandler; +import android.webkit.SslErrorHandler; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +/** + * + * + * WebViewClient for browser tests. + * Wraps around existing client so that specific methods can be overridden if needed. + * + */ +abstract class TestWebViewClient extends WebViewClient { + + private WebViewClient mWrappedClient; + + protected TestWebViewClient(WebViewClient wrappedClient) { + mWrappedClient = wrappedClient; + } + + /** {@inheritDoc} */ + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + return mWrappedClient.shouldOverrideUrlLoading(view, url); + } + + /** {@inheritDoc} */ + @Override + public void onPageStarted(WebView view, String url, Bitmap favicon) { + mWrappedClient.onPageStarted(view, url, favicon); + } + + /** {@inheritDoc} */ + @Override + public void onPageFinished(WebView view, String url) { + mWrappedClient.onPageFinished(view, url); + } + + /** {@inheritDoc} */ + @Override + public void onLoadResource(WebView view, String url) { + mWrappedClient.onLoadResource(view, url); + } + + /** {@inheritDoc} */ + @Deprecated + @Override + public void onTooManyRedirects(WebView view, Message cancelMsg, + Message continueMsg) { + mWrappedClient.onTooManyRedirects(view, cancelMsg, continueMsg); + } + + /** {@inheritDoc} */ + @Override + public void onReceivedError(WebView view, int errorCode, + String description, String failingUrl) { + mWrappedClient.onReceivedError(view, errorCode, description, failingUrl); + } + + /** {@inheritDoc} */ + @Override + public void onFormResubmission(WebView view, Message dontResend, + Message resend) { + mWrappedClient.onFormResubmission(view, dontResend, resend); + } + + /** {@inheritDoc} */ + @Override + public void doUpdateVisitedHistory(WebView view, String url, + boolean isReload) { + mWrappedClient.doUpdateVisitedHistory(view, url, isReload); + } + + /** {@inheritDoc} */ + @Override + public void onReceivedSslError(WebView view, SslErrorHandler handler, + SslError error) { + mWrappedClient.onReceivedSslError(view, handler, error); + } + + /** {@inheritDoc} */ + @Override + public void onReceivedHttpAuthRequest(WebView view, + HttpAuthHandler handler, String host, String realm) { + mWrappedClient.onReceivedHttpAuthRequest(view, handler, host, realm); + } + + /** {@inheritDoc} */ + @Override + public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) { + return mWrappedClient.shouldOverrideKeyEvent(view, event); + } + + /** {@inheritDoc} */ + @Override + public void onUnhandledKeyEvent(WebView view, KeyEvent event) { + mWrappedClient.onUnhandledKeyEvent(view, event); + } + + /** {@inheritDoc} */ + @Override + public void onScaleChanged(WebView view, float oldScale, float newScale) { + mWrappedClient.onScaleChanged(view, oldScale, newScale); + } +} -- cgit v1.1