LayoutTestsExecutor.java revision 5f0ccd76a88586ce85c17cb4db058934e693a4fc
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.dumprendertree2; 18 19import android.app.Activity; 20import android.content.ComponentName; 21import android.content.Context; 22import android.content.Intent; 23import android.content.ServiceConnection; 24import android.net.Uri; 25import android.os.Bundle; 26import android.os.Environment; 27import android.os.Handler; 28import android.os.IBinder; 29import android.os.Message; 30import android.os.Messenger; 31import android.os.RemoteException; 32import android.util.Log; 33import android.view.Window; 34import android.webkit.JsPromptResult; 35import android.webkit.JsResult; 36import android.webkit.WebChromeClient; 37import android.webkit.WebSettings; 38import android.webkit.WebView; 39import android.webkit.WebViewClient; 40import android.webkit.WebStorage.QuotaUpdater; 41 42import java.io.File; 43import java.util.List; 44 45/** 46 * This activity executes the test. It contains WebView and logic of LayoutTestController 47 * functions. It runs in a separate process and sends the results of running the test 48 * to ManagerService. The reason why is to handle crashing (test that crashes brings down 49 * whole process with it). 50 */ 51public class LayoutTestsExecutor extends Activity { 52 53 /** TODO: make it a setting */ 54 static final String TESTS_ROOT_DIR_PATH = 55 Environment.getExternalStorageDirectory() + 56 File.separator + "android" + 57 File.separator + "LayoutTests"; 58 59 private static final String LOG_TAG = "LayoutTestExecutor"; 60 61 public static final String EXTRA_TESTS_LIST = "TestsList"; 62 public static final String EXTRA_TEST_INDEX = "TestIndex"; 63 64 private static final int MSG_ACTUAL_RESULT_OBTAINED = 0; 65 66 private List<String> mTestsList; 67 68 /** 69 * This is a number of currently running test. It is 0-based and doesn't reset after 70 * the crash. Initial index is passed to LayoutTestsExecuter in the intent that starts 71 * it. 72 */ 73 private int mCurrentTestIndex; 74 75 private int mTotalTestCount; 76 77 private WebView mCurrentWebView; 78 private String mCurrentTestRelativePath; 79 private String mCurrentTestUri; 80 81 private boolean mOnTestFinishedCalled; 82 private AbstractResult mCurrentResult; 83 84 /** COMMUNICATION WITH ManagerService */ 85 86 private Messenger mManagerServiceMessenger; 87 88 private ServiceConnection mServiceConnection = new ServiceConnection() { 89 90 @Override 91 public void onServiceConnected(ComponentName name, IBinder service) { 92 mManagerServiceMessenger = new Messenger(service); 93 runNextTest(); 94 } 95 96 @Override 97 public void onServiceDisconnected(ComponentName name) { 98 /** TODO */ 99 } 100 }; 101 102 private final Handler mResultHandler = new Handler() { 103 @Override 104 public void handleMessage(Message msg) { 105 if (msg.what == MSG_ACTUAL_RESULT_OBTAINED) { 106 reportResultToService(); 107 mCurrentTestIndex++; 108 updateProgressBar(); 109 runNextTest(); 110 } 111 } 112 }; 113 114 /** WEBVIEW CONFIGURATION */ 115 116 private WebViewClient mWebViewClient = new WebViewClient() { 117 @Override 118 public void onPageFinished(WebView view, String url) { 119 /** Some tests fire up many page loads, we don't want to detect them */ 120 if (!url.equals(mCurrentTestUri)) { 121 return; 122 } 123 124 /** TODO: Implement waitUntilDone */ 125 onTestFinished(); 126 } 127 }; 128 129 private WebChromeClient mWebChromeClient = new WebChromeClient() { 130 @Override 131 public void onExceededDatabaseQuota(String url, String databaseIdentifier, 132 long currentQuota, long estimatedSize, long totalUsedQuota, 133 QuotaUpdater quotaUpdater) { 134 /** TODO: This should be recorded as part of the text result */ 135 quotaUpdater.updateQuota(currentQuota + 5 * 1024 * 1024); 136 } 137 138 @Override 139 public boolean onJsAlert(WebView view, String url, String message, JsResult result) { 140 /** TODO: Alerts should be recorded as part of text result */ 141 result.confirm(); 142 return true; 143 } 144 145 @Override 146 public boolean onJsConfirm(WebView view, String url, String message, JsResult result) { 147 /** TODO: Alerts should be recorded as part of text result */ 148 result.confirm(); 149 return true; 150 } 151 152 @Override 153 public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, 154 JsPromptResult result) { 155 /** TODO: Alerts should be recorded as part of text result */ 156 result.confirm(); 157 return true; 158 } 159 160 }; 161 162 /** IMPLEMENTATION */ 163 164 @Override 165 protected void onCreate(Bundle savedInstanceState) { 166 super.onCreate(savedInstanceState); 167 168 requestWindowFeature(Window.FEATURE_PROGRESS); 169 170 Intent intent = getIntent(); 171 mTestsList = intent.getStringArrayListExtra(EXTRA_TESTS_LIST); 172 mCurrentTestIndex = intent.getIntExtra(EXTRA_TEST_INDEX, -1); 173 mTotalTestCount = mCurrentTestIndex + mTestsList.size(); 174 175 bindService(new Intent(this, ManagerService.class), mServiceConnection, 176 Context.BIND_AUTO_CREATE); 177 } 178 179 private void reset() { 180 mOnTestFinishedCalled = false; 181 mCurrentResult = null; 182 183 mCurrentWebView = new WebView(this); 184 mCurrentWebView.setWebViewClient(mWebViewClient); 185 mCurrentWebView.setWebChromeClient(mWebChromeClient); 186 187 WebSettings webViewSettings = mCurrentWebView.getSettings(); 188 webViewSettings.setAppCacheEnabled(true); 189 webViewSettings.setAppCachePath(getApplicationContext().getCacheDir().getPath()); 190 webViewSettings.setAppCacheMaxSize(Long.MAX_VALUE); 191 webViewSettings.setJavaScriptEnabled(true); 192 webViewSettings.setJavaScriptCanOpenWindowsAutomatically(true); 193 webViewSettings.setSupportMultipleWindows(true); 194 webViewSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); 195 webViewSettings.setDatabaseEnabled(true); 196 webViewSettings.setDatabasePath(getDir("databases", 0).getAbsolutePath()); 197 webViewSettings.setDomStorageEnabled(true); 198 webViewSettings.setWorkersEnabled(false); 199 webViewSettings.setXSSAuditorEnabled(false); 200 201 setContentView(mCurrentWebView); 202 } 203 204 private void runNextTest() { 205 if (mTestsList.isEmpty()) { 206 onAllTestsFinished(); 207 return; 208 } 209 210 mCurrentTestRelativePath = mTestsList.remove(0); 211 mCurrentTestUri = 212 Uri.fromFile(new File(TESTS_ROOT_DIR_PATH, mCurrentTestRelativePath)).toString(); 213 214 reset(); 215 /** TODO: Implement timeout */ 216 mCurrentWebView.loadUrl(mCurrentTestUri); 217 } 218 219 private void onTestFinished() { 220 if (mOnTestFinishedCalled) { 221 return; 222 } 223 224 mOnTestFinishedCalled = true; 225 226 /** 227 * If the result has not been set by the time the test finishes we create 228 * a default type of result. 229 */ 230 if (mCurrentResult == null) { 231 /** TODO: Default type should be RenderTreeResult. We don't support it now. */ 232 mCurrentResult = new TextResult(mCurrentTestRelativePath); 233 } 234 235 mCurrentResult.obtainActualResults(mCurrentWebView, 236 mResultHandler.obtainMessage(MSG_ACTUAL_RESULT_OBTAINED)); 237 } 238 239 private void reportResultToService() { 240 try { 241 Message serviceMsg = 242 Message.obtain(null, ManagerService.MSG_PROCESS_ACTUAL_RESULTS); 243 Bundle bundle = mCurrentResult.getBundle(); 244 bundle.putInt("testIndex", mCurrentTestIndex); 245 /** TODO: Add timeout info to bundle */ 246 serviceMsg.setData(bundle); 247 mManagerServiceMessenger.send(serviceMsg); 248 } catch (RemoteException e) { 249 Log.e(LOG_TAG + "::reportResultToService", e.getMessage()); 250 } 251 } 252 253 private void updateProgressBar() { 254 getWindow().setFeatureInt(Window.FEATURE_PROGRESS, 255 mCurrentTestIndex * Window.PROGRESS_END / mTotalTestCount); 256 setTitle(mCurrentTestIndex * 100 / mTotalTestCount + "% " + 257 "(" + mCurrentTestIndex + "/" + mTotalTestCount + ")"); 258 } 259 260 private void onAllTestsFinished() { 261 try { 262 Message serviceMsg = 263 Message.obtain(null, ManagerService.MSG_ALL_TESTS_FINISHED); 264 mManagerServiceMessenger.send(serviceMsg); 265 } catch (RemoteException e) { 266 Log.e(LOG_TAG + "::onAllTestsFinished", e.getMessage()); 267 } 268 } 269}