Loading tests/DumpRenderTree2/AndroidManifest.xml +5 −5 Original line number Diff line number Diff line Loading @@ -25,13 +25,13 @@ limitations under the License. </intent-filter> </activity> <activity android:name=".LayoutTestsRunner" android:label="Layout tests' runner"> <activity android:name=".TestsListActivity" android:label="Tests' list activity"> </activity> <activity android:name=".LayoutTestsExecuter" android:label="Layout tests' executer" android:process=":executer"> <activity android:name=".LayoutTestsExecutor" android:label="Layout tests' executor" android:process=":executor"> </activity> <service android:name="ManagerService"> Loading tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java +17 −2 Original line number Diff line number Diff line Loading @@ -27,8 +27,21 @@ import android.webkit.WebView; public abstract class AbstractResult { public enum TestType { TEXT, PIXEL TEXT { @Override public AbstractResult createResult(Bundle bundle) { return new TextResult(bundle); } }, RENDER_TREE { @Override public AbstractResult createResult(Bundle bundle) { /** TODO: RenderTree tests are not yet supported */ return null; } }; public abstract AbstractResult createResult(Bundle bundle); } public enum ResultCode { Loading Loading @@ -101,6 +114,8 @@ public abstract class AbstractResult { */ public abstract TestType getType(); public abstract String getRelativePath(); /** * Returns a piece of HTML code that presents a visual diff between a result and * the expected result. Loading tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTest.javadeleted 100644 → 0 +0 −183 Original line number Diff line number Diff line /* * 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.dumprendertree2; import android.app.Activity; import android.net.Uri; import android.os.Handler; import android.os.Message; import android.webkit.JsPromptResult; import android.webkit.JsResult; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.webkit.WebStorage.QuotaUpdater; import java.io.File; /** * A class that represents a single layout test. It is responsible for running the test, * checking its result and creating an AbstractResult object. */ public class LayoutTest { private static final String LOG_TAG = "LayoutTest"; public static final int MSG_ACTUAL_RESULT_OBTAINED = 0; private String mRelativePath; private String mTestsRootDirPath; private String mUrl; private boolean mOnTestFinishedCalled; private Message mTestFinishedMsg; private AbstractResult mResult; private WebView mWebView; private Activity mActivity; private final Handler mResultHandler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == MSG_ACTUAL_RESULT_OBTAINED) { mResult.setExpectedTextResult(LayoutTestsRunnerThread .getExpectedTextResult(mRelativePath)); mResult.setExpectedImageResult(LayoutTestsRunnerThread .getExpectedImageResult(mRelativePath)); mTestFinishedMsg.sendToTarget(); } } }; private WebViewClient mWebViewClient = new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { /** Some tests fire up many page loads, we don't want to detect them */ if (!url.equals(mUrl)) { return; } onTestFinished(); } }; private WebChromeClient mWebChromeClient = new WebChromeClient() { @Override public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize, long totalUsedQuota, QuotaUpdater quotaUpdater) { /** TODO: This should be recorded as part of the text result */ quotaUpdater.updateQuota(currentQuota + 5 * 1024 * 1024); } @Override public boolean onJsAlert(WebView view, String url, String message, JsResult result) { /** TODO: Alerts should be recorded as part of text result */ result.confirm(); return true; } @Override public boolean onJsConfirm(WebView view, String url, String message, JsResult result) { /** TODO: Alerts should be recorded as part of text result */ result.confirm(); return true; } @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { /** TODO: Alerts should be recorded as part of text result */ result.confirm(); return true; } }; public LayoutTest(String relativePath, String testsRootDirPath, Message testFinishedMsg, LayoutTestsRunner activity) { mRelativePath = relativePath; mTestsRootDirPath = testsRootDirPath; mTestFinishedMsg = testFinishedMsg; mActivity = activity; } public LayoutTest(AbstractResult result, String relativePath) { mResult = result; mRelativePath = relativePath; } public void run() { mWebView = new WebView(mActivity); mActivity.setContentView(mWebView); setupWebView(); /** TODO: Add timeout msg */ mUrl = Uri.fromFile(new File(mTestsRootDirPath, mRelativePath)).toString(); mWebView.loadUrl(mUrl); } private void onTestFinished() { if (mOnTestFinishedCalled) { return; } mOnTestFinishedCalled = true; /** * If the result has not been set by the time the test finishes we create * a default type of result. */ if (mResult == null) { /** TODO: Default type should be RenderTreeResult. We don't support it now. */ mResult = new TextResult(mRelativePath); } /** TODO: Implement waitUntilDone */ mResult.obtainActualResults(mWebView, mResultHandler.obtainMessage(MSG_ACTUAL_RESULT_OBTAINED)); } private void setupWebView() { WebSettings webViewSettings = mWebView.getSettings(); webViewSettings.setAppCacheEnabled(true); webViewSettings.setAppCachePath(mActivity.getApplicationContext().getCacheDir().getPath()); webViewSettings.setAppCacheMaxSize(Long.MAX_VALUE); webViewSettings.setJavaScriptEnabled(true); webViewSettings.setJavaScriptCanOpenWindowsAutomatically(true); webViewSettings.setSupportMultipleWindows(true); webViewSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); webViewSettings.setDatabaseEnabled(true); webViewSettings.setDatabasePath(mActivity.getDir("databases", 0).getAbsolutePath()); webViewSettings.setDomStorageEnabled(true); webViewSettings.setWorkersEnabled(false); webViewSettings.setXSSAuditorEnabled(false); mWebView.setWebViewClient(mWebViewClient); mWebView.setWebChromeClient(mWebChromeClient); } public AbstractResult getResult() { return mResult; } public String getRelativePath() { return mRelativePath; } } No newline at end of file tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecuter.java→tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java +34 −5 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.util.Log; import android.view.Window; import android.webkit.JsPromptResult; import android.webkit.JsResult; import android.webkit.WebChromeClient; Loading @@ -47,7 +48,7 @@ import java.util.List; * to ManagerService. The reason why is to handle crashing (test that crashes brings down * whole process with it). */ public class LayoutTestsExecuter extends Activity { public class LayoutTestsExecutor extends Activity { /** TODO: make it a setting */ static final String TESTS_ROOT_DIR_PATH = Loading @@ -55,14 +56,23 @@ public class LayoutTestsExecuter extends Activity { File.separator + "android" + File.separator + "LayoutTests"; private static final String LOG_TAG = "LayoutTestExecuter"; private static final String LOG_TAG = "LayoutTestExecutor"; public static final String EXTRA_TESTS_LIST = "TestsList"; public static final String EXTRA_TEST_INDEX = "TestIndex"; private static final int MSG_ACTUAL_RESULT_OBTAINED = 0; private List<String> mTestsList; private int mCurrentTestCount = 0; /** * This is a number of currently running test. It is 0-based and doesn't reset after * the crash. Initial index is passed to LayoutTestsExecuter in the intent that starts * it. */ private int mCurrentTestIndex; private int mTotalTestCount; private WebView mCurrentWebView; private String mCurrentTestRelativePath; Loading Loading @@ -94,6 +104,8 @@ public class LayoutTestsExecuter extends Activity { public void handleMessage(Message msg) { if (msg.what == MSG_ACTUAL_RESULT_OBTAINED) { reportResultToService(); mCurrentTestIndex++; updateProgressBar(); runNextTest(); } } Loading Loading @@ -153,8 +165,12 @@ public class LayoutTestsExecuter extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_PROGRESS); Intent intent = getIntent(); mTestsList = intent.getStringArrayListExtra(EXTRA_TESTS_LIST); mCurrentTestIndex = intent.getIntExtra(EXTRA_TEST_INDEX, -1); mTotalTestCount = mCurrentTestIndex + mTestsList.size(); bindService(new Intent(this, ManagerService.class), mServiceConnection, Context.BIND_AUTO_CREATE); Loading Loading @@ -191,7 +207,6 @@ public class LayoutTestsExecuter extends Activity { return; } mCurrentTestCount++; mCurrentTestRelativePath = mTestsList.remove(0); mCurrentTestUri = Uri.fromFile(new File(TESTS_ROOT_DIR_PATH, mCurrentTestRelativePath)).toString(); Loading Loading @@ -226,6 +241,7 @@ public class LayoutTestsExecuter extends Activity { Message serviceMsg = Message.obtain(null, ManagerService.MSG_PROCESS_ACTUAL_RESULTS); Bundle bundle = mCurrentResult.getBundle(); bundle.putInt("testIndex", mCurrentTestIndex); /** TODO: Add timeout info to bundle */ serviceMsg.setData(bundle); mManagerServiceMessenger.send(serviceMsg); Loading @@ -234,7 +250,20 @@ public class LayoutTestsExecuter extends Activity { } } private void updateProgressBar() { getWindow().setFeatureInt(Window.FEATURE_PROGRESS, mCurrentTestIndex * Window.PROGRESS_END / mTotalTestCount); setTitle(mCurrentTestIndex * 100 / mTotalTestCount + "% " + "(" + mCurrentTestIndex + "/" + mTotalTestCount + ")"); } private void onAllTestsFinished() { Log.d(LOG_TAG + "::onAllTestsFisnihed", "Begin."); try { Message serviceMsg = Message.obtain(null, ManagerService.MSG_ALL_TESTS_FINISHED); mManagerServiceMessenger.send(serviceMsg); } catch (RemoteException e) { Log.e(LOG_TAG + "::onAllTestsFinished", e.getMessage()); } } } No newline at end of file tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunnerThread.javadeleted 100644 → 0 +0 −304 Original line number Diff line number Diff line /* * 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.dumprendertree2; import android.content.Intent; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import java.io.File; import java.util.ArrayList; import java.util.LinkedList; /** * A Thread that is responsible for finding and loading the tests, starting them and * generating summaries. The actual running of the test is delegated to LayoutTestsRunner * activity (a UI thread) because of a WebView object that need to be created in UI thread * so it can be displayed on the screen. However, the logic for doing this remains in * this class (in handler created in constructor). */ public class LayoutTestsRunnerThread extends Thread { private static final String LOG_TAG = "LayoutTestsRunnerThread"; /** Messages for handler on this thread */ public static final int MSG_TEST_FINISHED = 0; /** Messages for our handler running on UI thread */ public static final int MSG_RUN_TEST = 0; /** TODO: make it a setting */ private static final String TESTS_ROOT_DIR_PATH = Environment.getExternalStorageDirectory() + File.separator + "android" + File.separator + "LayoutTests"; /** TODO: make it a setting */ private static final String RESULTS_ROOT_DIR_PATH = Environment.getExternalStorageDirectory() + File.separator + "android" + File.separator + "LayoutTests-results"; /** TODO: Make it a setting */ private static final String EXPECTED_RESULT_SECONDARY_LOCATION_RELATIVE_DIR_PREFIX = "platform" + File.separator + "android-v8" + File.separator; /** TODO: Make these settings */ private static final String TEXT_RESULT_EXTENSION = "txt"; private static final String IMAGE_RESULT_EXTENSION = "png"; /** A list containing relative paths of tests to run */ private LinkedList<String> mTestsList = new LinkedList<String>(); private FileFilter mFileFilter; private Summarizer mSummarizer; /** Our handler running on this thread. Created in run() method. */ private Handler mHandler; /** Our handler running on UI thread. Created in constructor of this thread. */ private Handler mHandlerOnUiThread; /** * A relative path to the folder with the tests we want to run or particular test. * Used up to and including preloadTests(). */ private String mRelativePath; private LayoutTestsRunner mActivity; private LayoutTest mCurrentTest; private String mCurrentTestPath; private int mCurrentTestCount = 0; private int mTotalTestCount; /** * The given path must be relative to the root dir. The given handler must be * able to handle messages that update the display (UI thread). * * @param path * @param uiDisplayHandler */ public LayoutTestsRunnerThread(String path, LayoutTestsRunner activity) { mFileFilter = new FileFilter(TESTS_ROOT_DIR_PATH); mRelativePath = path; mActivity = activity; /** This creates a handler that runs on the thread that _created_ this thread */ mHandlerOnUiThread = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_RUN_TEST: ((LayoutTest) msg.obj).run(); break; } } }; } @Override public void run() { Looper.prepare(); mSummarizer = new Summarizer(mFileFilter, RESULTS_ROOT_DIR_PATH); /** A handler obtained from UI thread to handle messages concerning updating the display */ final Handler uiDisplayHandler = mActivity.getHandler(); /** Creates a new handler in _this_ thread */ mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_TEST_FINISHED: onTestFinished(mCurrentTest); uiDisplayHandler.obtainMessage(LayoutTestsRunner.MSG_UPDATE_PROGRESS, mCurrentTestCount, mTotalTestCount).sendToTarget(); runNextTest(); break; } } }; /** Check if the path is correct */ File file = new File(TESTS_ROOT_DIR_PATH, mRelativePath); if (!file.exists()) { Log.e(LOG_TAG + "::run", "Path does not exist: " + mRelativePath); return; } /** Populate the tests' list accordingly */ if (file.isDirectory()) { uiDisplayHandler.sendEmptyMessage(LayoutTestsRunner.MSG_SHOW_PROGRESS_DIALOG); preloadTests(mRelativePath); uiDisplayHandler.sendEmptyMessage(LayoutTestsRunner.MSG_DISMISS_PROGRESS_DIALOG); } else { mTestsList.addLast(mRelativePath); mTotalTestCount = 1; } /** * Instead of running next test here, we send a tests' list to Executer activity. * Rest of the code is never executed and will be gradually moved to the service. */ Intent intent = new Intent(); intent.setClass(mActivity, LayoutTestsExecuter.class); intent.setAction(Intent.ACTION_RUN); intent.putStringArrayListExtra(LayoutTestsExecuter.EXTRA_TESTS_LIST, new ArrayList<String>(mTestsList)); mActivity.startActivity(intent); Looper.loop(); } /** * Loads all the tests from the given folders and all the subfolders * into mTestsList. * * @param dirRelativePath */ private void preloadTests(String dirRelativePath) { LinkedList<String> foldersList = new LinkedList<String>(); foldersList.add(dirRelativePath); String relativePath; String currentDirRelativePath; String itemName; File[] items; while (!foldersList.isEmpty()) { currentDirRelativePath = foldersList.removeFirst(); items = new File(TESTS_ROOT_DIR_PATH, currentDirRelativePath).listFiles(); for (File item : items) { itemName = item.getName(); relativePath = currentDirRelativePath + File.separator + itemName; if (item.isDirectory() && FileFilter.isTestDir(itemName)) { foldersList.add(relativePath); continue; } if (FileFilter.isTestFile(itemName)) { if (!mFileFilter.isSkip(relativePath)) { mTestsList.addLast(relativePath); } else { mSummarizer.addSkippedTest(relativePath); } } } } mTotalTestCount = mTestsList.size(); } private void runNextTest() { if (mTestsList.isEmpty()) { onFinishedTests(); return; } mCurrentTestCount++; mCurrentTestPath = mTestsList.removeFirst(); mCurrentTest = new LayoutTest(mCurrentTestPath, TESTS_ROOT_DIR_PATH, mHandler.obtainMessage(MSG_TEST_FINISHED), mActivity); /** * This will run the test on UI thread. The reason why we need to run the test * on UI thread is because of the WebView. If we want to display the webview on * the screen it needs to be in the UI thread. WebView should be created as * part of the LayoutTest.run() method. */ mHandlerOnUiThread.obtainMessage(MSG_RUN_TEST, mCurrentTest).sendToTarget(); } private void onTestFinished(LayoutTest test) { String testPath = test.getRelativePath(); /** Obtain the result */ AbstractResult result = test.getResult(); if (result == null) { Log.e(LOG_TAG + "::runTests", testPath + ": result NULL!!"); return; } dumpResultData(result, testPath); mSummarizer.appendTest(test); } private void dumpResultData(AbstractResult result, String testPath) { dumpActualTextResult(result, testPath); dumpActualImageResult(result, testPath); } private void dumpActualTextResult(AbstractResult result, String testPath) { String actualTextResult = result.getActualTextResult(); if (actualTextResult == null) { return; } String resultPath = FileFilter.setPathEnding(testPath, "-actual." + TEXT_RESULT_EXTENSION); FsUtils.writeDataToStorage(new File(RESULTS_ROOT_DIR_PATH, resultPath), actualTextResult.getBytes(), false); } private void dumpActualImageResult(AbstractResult result, String testPath) { byte[] actualImageResult = result.getActualImageResult(); if (actualImageResult == null) { return; } String resultPath = FileFilter.setPathEnding(testPath, "-actual." + IMAGE_RESULT_EXTENSION); FsUtils.writeDataToStorage(new File(RESULTS_ROOT_DIR_PATH, resultPath), actualImageResult, false); } private void onFinishedTests() { Log.d(LOG_TAG + "::onFinishedTests", "Begin."); Looper.myLooper().quit(); mSummarizer.summarize(); /** TODO: Present some kind of notification to the user that * allows to chose next action, e.g: * - go to html view of results * - zip results * - run more tests before zipping */ } public static String getExpectedTextResult(String relativePath) { return new String(getExpectedResult(relativePath, TEXT_RESULT_EXTENSION)); } public static byte[] getExpectedImageResult(String relativePath) { return getExpectedResult(relativePath, IMAGE_RESULT_EXTENSION); } private static byte[] getExpectedResult(String relativePath, String extension) { relativePath = FileFilter.setPathEnding(relativePath, "-expected." + extension); byte[] bytes = FsUtils.readDataFromStorage(new File(TESTS_ROOT_DIR_PATH, relativePath)); if (bytes == null) { relativePath = EXPECTED_RESULT_SECONDARY_LOCATION_RELATIVE_DIR_PREFIX + relativePath; bytes = FsUtils.readDataFromStorage(new File(TESTS_ROOT_DIR_PATH, relativePath)); } return bytes; } } No newline at end of file Loading
tests/DumpRenderTree2/AndroidManifest.xml +5 −5 Original line number Diff line number Diff line Loading @@ -25,13 +25,13 @@ limitations under the License. </intent-filter> </activity> <activity android:name=".LayoutTestsRunner" android:label="Layout tests' runner"> <activity android:name=".TestsListActivity" android:label="Tests' list activity"> </activity> <activity android:name=".LayoutTestsExecuter" android:label="Layout tests' executer" android:process=":executer"> <activity android:name=".LayoutTestsExecutor" android:label="Layout tests' executor" android:process=":executor"> </activity> <service android:name="ManagerService"> Loading
tests/DumpRenderTree2/src/com/android/dumprendertree2/AbstractResult.java +17 −2 Original line number Diff line number Diff line Loading @@ -27,8 +27,21 @@ import android.webkit.WebView; public abstract class AbstractResult { public enum TestType { TEXT, PIXEL TEXT { @Override public AbstractResult createResult(Bundle bundle) { return new TextResult(bundle); } }, RENDER_TREE { @Override public AbstractResult createResult(Bundle bundle) { /** TODO: RenderTree tests are not yet supported */ return null; } }; public abstract AbstractResult createResult(Bundle bundle); } public enum ResultCode { Loading Loading @@ -101,6 +114,8 @@ public abstract class AbstractResult { */ public abstract TestType getType(); public abstract String getRelativePath(); /** * Returns a piece of HTML code that presents a visual diff between a result and * the expected result. Loading
tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTest.javadeleted 100644 → 0 +0 −183 Original line number Diff line number Diff line /* * 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.dumprendertree2; import android.app.Activity; import android.net.Uri; import android.os.Handler; import android.os.Message; import android.webkit.JsPromptResult; import android.webkit.JsResult; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.webkit.WebStorage.QuotaUpdater; import java.io.File; /** * A class that represents a single layout test. It is responsible for running the test, * checking its result and creating an AbstractResult object. */ public class LayoutTest { private static final String LOG_TAG = "LayoutTest"; public static final int MSG_ACTUAL_RESULT_OBTAINED = 0; private String mRelativePath; private String mTestsRootDirPath; private String mUrl; private boolean mOnTestFinishedCalled; private Message mTestFinishedMsg; private AbstractResult mResult; private WebView mWebView; private Activity mActivity; private final Handler mResultHandler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == MSG_ACTUAL_RESULT_OBTAINED) { mResult.setExpectedTextResult(LayoutTestsRunnerThread .getExpectedTextResult(mRelativePath)); mResult.setExpectedImageResult(LayoutTestsRunnerThread .getExpectedImageResult(mRelativePath)); mTestFinishedMsg.sendToTarget(); } } }; private WebViewClient mWebViewClient = new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { /** Some tests fire up many page loads, we don't want to detect them */ if (!url.equals(mUrl)) { return; } onTestFinished(); } }; private WebChromeClient mWebChromeClient = new WebChromeClient() { @Override public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize, long totalUsedQuota, QuotaUpdater quotaUpdater) { /** TODO: This should be recorded as part of the text result */ quotaUpdater.updateQuota(currentQuota + 5 * 1024 * 1024); } @Override public boolean onJsAlert(WebView view, String url, String message, JsResult result) { /** TODO: Alerts should be recorded as part of text result */ result.confirm(); return true; } @Override public boolean onJsConfirm(WebView view, String url, String message, JsResult result) { /** TODO: Alerts should be recorded as part of text result */ result.confirm(); return true; } @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { /** TODO: Alerts should be recorded as part of text result */ result.confirm(); return true; } }; public LayoutTest(String relativePath, String testsRootDirPath, Message testFinishedMsg, LayoutTestsRunner activity) { mRelativePath = relativePath; mTestsRootDirPath = testsRootDirPath; mTestFinishedMsg = testFinishedMsg; mActivity = activity; } public LayoutTest(AbstractResult result, String relativePath) { mResult = result; mRelativePath = relativePath; } public void run() { mWebView = new WebView(mActivity); mActivity.setContentView(mWebView); setupWebView(); /** TODO: Add timeout msg */ mUrl = Uri.fromFile(new File(mTestsRootDirPath, mRelativePath)).toString(); mWebView.loadUrl(mUrl); } private void onTestFinished() { if (mOnTestFinishedCalled) { return; } mOnTestFinishedCalled = true; /** * If the result has not been set by the time the test finishes we create * a default type of result. */ if (mResult == null) { /** TODO: Default type should be RenderTreeResult. We don't support it now. */ mResult = new TextResult(mRelativePath); } /** TODO: Implement waitUntilDone */ mResult.obtainActualResults(mWebView, mResultHandler.obtainMessage(MSG_ACTUAL_RESULT_OBTAINED)); } private void setupWebView() { WebSettings webViewSettings = mWebView.getSettings(); webViewSettings.setAppCacheEnabled(true); webViewSettings.setAppCachePath(mActivity.getApplicationContext().getCacheDir().getPath()); webViewSettings.setAppCacheMaxSize(Long.MAX_VALUE); webViewSettings.setJavaScriptEnabled(true); webViewSettings.setJavaScriptCanOpenWindowsAutomatically(true); webViewSettings.setSupportMultipleWindows(true); webViewSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); webViewSettings.setDatabaseEnabled(true); webViewSettings.setDatabasePath(mActivity.getDir("databases", 0).getAbsolutePath()); webViewSettings.setDomStorageEnabled(true); webViewSettings.setWorkersEnabled(false); webViewSettings.setXSSAuditorEnabled(false); mWebView.setWebViewClient(mWebViewClient); mWebView.setWebChromeClient(mWebChromeClient); } public AbstractResult getResult() { return mResult; } public String getRelativePath() { return mRelativePath; } } No newline at end of file
tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecuter.java→tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java +34 −5 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.util.Log; import android.view.Window; import android.webkit.JsPromptResult; import android.webkit.JsResult; import android.webkit.WebChromeClient; Loading @@ -47,7 +48,7 @@ import java.util.List; * to ManagerService. The reason why is to handle crashing (test that crashes brings down * whole process with it). */ public class LayoutTestsExecuter extends Activity { public class LayoutTestsExecutor extends Activity { /** TODO: make it a setting */ static final String TESTS_ROOT_DIR_PATH = Loading @@ -55,14 +56,23 @@ public class LayoutTestsExecuter extends Activity { File.separator + "android" + File.separator + "LayoutTests"; private static final String LOG_TAG = "LayoutTestExecuter"; private static final String LOG_TAG = "LayoutTestExecutor"; public static final String EXTRA_TESTS_LIST = "TestsList"; public static final String EXTRA_TEST_INDEX = "TestIndex"; private static final int MSG_ACTUAL_RESULT_OBTAINED = 0; private List<String> mTestsList; private int mCurrentTestCount = 0; /** * This is a number of currently running test. It is 0-based and doesn't reset after * the crash. Initial index is passed to LayoutTestsExecuter in the intent that starts * it. */ private int mCurrentTestIndex; private int mTotalTestCount; private WebView mCurrentWebView; private String mCurrentTestRelativePath; Loading Loading @@ -94,6 +104,8 @@ public class LayoutTestsExecuter extends Activity { public void handleMessage(Message msg) { if (msg.what == MSG_ACTUAL_RESULT_OBTAINED) { reportResultToService(); mCurrentTestIndex++; updateProgressBar(); runNextTest(); } } Loading Loading @@ -153,8 +165,12 @@ public class LayoutTestsExecuter extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_PROGRESS); Intent intent = getIntent(); mTestsList = intent.getStringArrayListExtra(EXTRA_TESTS_LIST); mCurrentTestIndex = intent.getIntExtra(EXTRA_TEST_INDEX, -1); mTotalTestCount = mCurrentTestIndex + mTestsList.size(); bindService(new Intent(this, ManagerService.class), mServiceConnection, Context.BIND_AUTO_CREATE); Loading Loading @@ -191,7 +207,6 @@ public class LayoutTestsExecuter extends Activity { return; } mCurrentTestCount++; mCurrentTestRelativePath = mTestsList.remove(0); mCurrentTestUri = Uri.fromFile(new File(TESTS_ROOT_DIR_PATH, mCurrentTestRelativePath)).toString(); Loading Loading @@ -226,6 +241,7 @@ public class LayoutTestsExecuter extends Activity { Message serviceMsg = Message.obtain(null, ManagerService.MSG_PROCESS_ACTUAL_RESULTS); Bundle bundle = mCurrentResult.getBundle(); bundle.putInt("testIndex", mCurrentTestIndex); /** TODO: Add timeout info to bundle */ serviceMsg.setData(bundle); mManagerServiceMessenger.send(serviceMsg); Loading @@ -234,7 +250,20 @@ public class LayoutTestsExecuter extends Activity { } } private void updateProgressBar() { getWindow().setFeatureInt(Window.FEATURE_PROGRESS, mCurrentTestIndex * Window.PROGRESS_END / mTotalTestCount); setTitle(mCurrentTestIndex * 100 / mTotalTestCount + "% " + "(" + mCurrentTestIndex + "/" + mTotalTestCount + ")"); } private void onAllTestsFinished() { Log.d(LOG_TAG + "::onAllTestsFisnihed", "Begin."); try { Message serviceMsg = Message.obtain(null, ManagerService.MSG_ALL_TESTS_FINISHED); mManagerServiceMessenger.send(serviceMsg); } catch (RemoteException e) { Log.e(LOG_TAG + "::onAllTestsFinished", e.getMessage()); } } } No newline at end of file
tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsRunnerThread.javadeleted 100644 → 0 +0 −304 Original line number Diff line number Diff line /* * 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.dumprendertree2; import android.content.Intent; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import java.io.File; import java.util.ArrayList; import java.util.LinkedList; /** * A Thread that is responsible for finding and loading the tests, starting them and * generating summaries. The actual running of the test is delegated to LayoutTestsRunner * activity (a UI thread) because of a WebView object that need to be created in UI thread * so it can be displayed on the screen. However, the logic for doing this remains in * this class (in handler created in constructor). */ public class LayoutTestsRunnerThread extends Thread { private static final String LOG_TAG = "LayoutTestsRunnerThread"; /** Messages for handler on this thread */ public static final int MSG_TEST_FINISHED = 0; /** Messages for our handler running on UI thread */ public static final int MSG_RUN_TEST = 0; /** TODO: make it a setting */ private static final String TESTS_ROOT_DIR_PATH = Environment.getExternalStorageDirectory() + File.separator + "android" + File.separator + "LayoutTests"; /** TODO: make it a setting */ private static final String RESULTS_ROOT_DIR_PATH = Environment.getExternalStorageDirectory() + File.separator + "android" + File.separator + "LayoutTests-results"; /** TODO: Make it a setting */ private static final String EXPECTED_RESULT_SECONDARY_LOCATION_RELATIVE_DIR_PREFIX = "platform" + File.separator + "android-v8" + File.separator; /** TODO: Make these settings */ private static final String TEXT_RESULT_EXTENSION = "txt"; private static final String IMAGE_RESULT_EXTENSION = "png"; /** A list containing relative paths of tests to run */ private LinkedList<String> mTestsList = new LinkedList<String>(); private FileFilter mFileFilter; private Summarizer mSummarizer; /** Our handler running on this thread. Created in run() method. */ private Handler mHandler; /** Our handler running on UI thread. Created in constructor of this thread. */ private Handler mHandlerOnUiThread; /** * A relative path to the folder with the tests we want to run or particular test. * Used up to and including preloadTests(). */ private String mRelativePath; private LayoutTestsRunner mActivity; private LayoutTest mCurrentTest; private String mCurrentTestPath; private int mCurrentTestCount = 0; private int mTotalTestCount; /** * The given path must be relative to the root dir. The given handler must be * able to handle messages that update the display (UI thread). * * @param path * @param uiDisplayHandler */ public LayoutTestsRunnerThread(String path, LayoutTestsRunner activity) { mFileFilter = new FileFilter(TESTS_ROOT_DIR_PATH); mRelativePath = path; mActivity = activity; /** This creates a handler that runs on the thread that _created_ this thread */ mHandlerOnUiThread = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_RUN_TEST: ((LayoutTest) msg.obj).run(); break; } } }; } @Override public void run() { Looper.prepare(); mSummarizer = new Summarizer(mFileFilter, RESULTS_ROOT_DIR_PATH); /** A handler obtained from UI thread to handle messages concerning updating the display */ final Handler uiDisplayHandler = mActivity.getHandler(); /** Creates a new handler in _this_ thread */ mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_TEST_FINISHED: onTestFinished(mCurrentTest); uiDisplayHandler.obtainMessage(LayoutTestsRunner.MSG_UPDATE_PROGRESS, mCurrentTestCount, mTotalTestCount).sendToTarget(); runNextTest(); break; } } }; /** Check if the path is correct */ File file = new File(TESTS_ROOT_DIR_PATH, mRelativePath); if (!file.exists()) { Log.e(LOG_TAG + "::run", "Path does not exist: " + mRelativePath); return; } /** Populate the tests' list accordingly */ if (file.isDirectory()) { uiDisplayHandler.sendEmptyMessage(LayoutTestsRunner.MSG_SHOW_PROGRESS_DIALOG); preloadTests(mRelativePath); uiDisplayHandler.sendEmptyMessage(LayoutTestsRunner.MSG_DISMISS_PROGRESS_DIALOG); } else { mTestsList.addLast(mRelativePath); mTotalTestCount = 1; } /** * Instead of running next test here, we send a tests' list to Executer activity. * Rest of the code is never executed and will be gradually moved to the service. */ Intent intent = new Intent(); intent.setClass(mActivity, LayoutTestsExecuter.class); intent.setAction(Intent.ACTION_RUN); intent.putStringArrayListExtra(LayoutTestsExecuter.EXTRA_TESTS_LIST, new ArrayList<String>(mTestsList)); mActivity.startActivity(intent); Looper.loop(); } /** * Loads all the tests from the given folders and all the subfolders * into mTestsList. * * @param dirRelativePath */ private void preloadTests(String dirRelativePath) { LinkedList<String> foldersList = new LinkedList<String>(); foldersList.add(dirRelativePath); String relativePath; String currentDirRelativePath; String itemName; File[] items; while (!foldersList.isEmpty()) { currentDirRelativePath = foldersList.removeFirst(); items = new File(TESTS_ROOT_DIR_PATH, currentDirRelativePath).listFiles(); for (File item : items) { itemName = item.getName(); relativePath = currentDirRelativePath + File.separator + itemName; if (item.isDirectory() && FileFilter.isTestDir(itemName)) { foldersList.add(relativePath); continue; } if (FileFilter.isTestFile(itemName)) { if (!mFileFilter.isSkip(relativePath)) { mTestsList.addLast(relativePath); } else { mSummarizer.addSkippedTest(relativePath); } } } } mTotalTestCount = mTestsList.size(); } private void runNextTest() { if (mTestsList.isEmpty()) { onFinishedTests(); return; } mCurrentTestCount++; mCurrentTestPath = mTestsList.removeFirst(); mCurrentTest = new LayoutTest(mCurrentTestPath, TESTS_ROOT_DIR_PATH, mHandler.obtainMessage(MSG_TEST_FINISHED), mActivity); /** * This will run the test on UI thread. The reason why we need to run the test * on UI thread is because of the WebView. If we want to display the webview on * the screen it needs to be in the UI thread. WebView should be created as * part of the LayoutTest.run() method. */ mHandlerOnUiThread.obtainMessage(MSG_RUN_TEST, mCurrentTest).sendToTarget(); } private void onTestFinished(LayoutTest test) { String testPath = test.getRelativePath(); /** Obtain the result */ AbstractResult result = test.getResult(); if (result == null) { Log.e(LOG_TAG + "::runTests", testPath + ": result NULL!!"); return; } dumpResultData(result, testPath); mSummarizer.appendTest(test); } private void dumpResultData(AbstractResult result, String testPath) { dumpActualTextResult(result, testPath); dumpActualImageResult(result, testPath); } private void dumpActualTextResult(AbstractResult result, String testPath) { String actualTextResult = result.getActualTextResult(); if (actualTextResult == null) { return; } String resultPath = FileFilter.setPathEnding(testPath, "-actual." + TEXT_RESULT_EXTENSION); FsUtils.writeDataToStorage(new File(RESULTS_ROOT_DIR_PATH, resultPath), actualTextResult.getBytes(), false); } private void dumpActualImageResult(AbstractResult result, String testPath) { byte[] actualImageResult = result.getActualImageResult(); if (actualImageResult == null) { return; } String resultPath = FileFilter.setPathEnding(testPath, "-actual." + IMAGE_RESULT_EXTENSION); FsUtils.writeDataToStorage(new File(RESULTS_ROOT_DIR_PATH, resultPath), actualImageResult, false); } private void onFinishedTests() { Log.d(LOG_TAG + "::onFinishedTests", "Begin."); Looper.myLooper().quit(); mSummarizer.summarize(); /** TODO: Present some kind of notification to the user that * allows to chose next action, e.g: * - go to html view of results * - zip results * - run more tests before zipping */ } public static String getExpectedTextResult(String relativePath) { return new String(getExpectedResult(relativePath, TEXT_RESULT_EXTENSION)); } public static byte[] getExpectedImageResult(String relativePath) { return getExpectedResult(relativePath, IMAGE_RESULT_EXTENSION); } private static byte[] getExpectedResult(String relativePath, String extension) { relativePath = FileFilter.setPathEnding(relativePath, "-expected." + extension); byte[] bytes = FsUtils.readDataFromStorage(new File(TESTS_ROOT_DIR_PATH, relativePath)); if (bytes == null) { relativePath = EXPECTED_RESULT_SECONDARY_LOCATION_RELATIVE_DIR_PREFIX + relativePath; bytes = FsUtils.readDataFromStorage(new File(TESTS_ROOT_DIR_PATH, relativePath)); } return bytes; } } No newline at end of file