Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a7137538 authored by Maksymilian Osowski's avatar Maksymilian Osowski Committed by Android (Google) Code Review
Browse files

Merge "First stage of refactoring the code to handle crashes gracefully."

parents e164eda9 7ddc0b7a
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -28,6 +28,14 @@ limitations under the License.
        <activity android:name=".LayoutTestsRunner"
                  android:label="Layout tests' runner">
        </activity>

        <activity android:name=".LayoutTestsExecuter"
                  android:label="Layout tests' executer"
                  android:process=":executer">
        </activity>

        <service android:name="ManagerService">
        </service>
    </application>

    <uses-permission android:name="android.permission.INTERNET" />
+6 −3
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.dumprendertree2;

import android.os.Bundle;
import android.os.Message;
import android.webkit.WebView;

@@ -50,15 +51,15 @@ public abstract class AbstractResult {
    }

    /**
     * Makes the result object obtain the result of the test from the webview
     * and store it in the format that suits itself bests. This method is asynchronous.
     * Makes the result object obtain the results of the test from the webview
     * and store them in the format that suits itself bests. This method is asynchronous.
     * The message passed as a parameter is a message that should be sent to its target
     * when the result finishes obtaining the result.
     *
     * @param webview
     * @param resultObtainedMsg
     */
    public abstract void obtainActualResult(WebView webview, Message resultObtainedMsg);
    public abstract void obtainActualResults(WebView webview, Message resultObtainedMsg);

    public abstract void setExpectedImageResult(byte[] expectedResult);

@@ -108,4 +109,6 @@ public abstract class AbstractResult {
     *      a piece of HTML code with a visual diff between the result and the expected result
     */
    public abstract String getDiffAsHtml();

    public abstract Bundle getBundle();
}
 No newline at end of file
+10 −3
Original line number Diff line number Diff line
@@ -54,8 +54,10 @@ public class LayoutTest {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == MSG_ACTUAL_RESULT_OBTAINED) {
                mResult.setExpectedTextResult(LayoutTestsRunnerThread.getExpectedTextResult(mRelativePath));
                mResult.setExpectedImageResult(LayoutTestsRunnerThread.getExpectedImageResult(mRelativePath));
                mResult.setExpectedTextResult(LayoutTestsRunnerThread
                        .getExpectedTextResult(mRelativePath));
                mResult.setExpectedImageResult(LayoutTestsRunnerThread
                        .getExpectedImageResult(mRelativePath));
                mTestFinishedMsg.sendToTarget();
            }
        }
@@ -114,6 +116,11 @@ public class LayoutTest {
        mActivity = activity;
    }

    public LayoutTest(AbstractResult result, String relativePath) {
        mResult = result;
        mRelativePath = relativePath;
    }

    public void run() {
        mWebView = new WebView(mActivity);
        mActivity.setContentView(mWebView);
@@ -143,7 +150,7 @@ public class LayoutTest {

        /** TODO: Implement waitUntilDone */

        mResult.obtainActualResult(mWebView,
        mResult.obtainActualResults(mWebView,
                mResultHandler.obtainMessage(MSG_ACTUAL_RESULT_OBTAINED));
    }

+240 −0
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.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
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;
import java.util.List;

/**
 * This activity executes the test. It contains WebView and logic of LayoutTestController
 * functions. It runs in a separate process and sends the results of running the test
 * to ManagerService. The reason why is to handle crashing (test that crashes brings down
 * whole process with it).
 */
public class LayoutTestsExecuter extends Activity {

    /** TODO: make it a setting */
    static final String TESTS_ROOT_DIR_PATH =
            Environment.getExternalStorageDirectory() +
            File.separator + "android" +
            File.separator + "LayoutTests";

    private static final String LOG_TAG = "LayoutTestExecuter";

    public static final String EXTRA_TESTS_LIST = "TestsList";

    private static final int MSG_ACTUAL_RESULT_OBTAINED = 0;

    private List<String> mTestsList;
    private int mCurrentTestCount = 0;

    private WebView mCurrentWebView;
    private String mCurrentTestRelativePath;
    private String mCurrentTestUri;

    private boolean mOnTestFinishedCalled;
    private AbstractResult mCurrentResult;

    /** COMMUNICATION WITH ManagerService */

    private Messenger mManagerServiceMessenger;

    private ServiceConnection mServiceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mManagerServiceMessenger = new Messenger(service);
            runNextTest();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            /** TODO */
        }
    };

    private final Handler mResultHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == MSG_ACTUAL_RESULT_OBTAINED) {
                reportResultToService();
                runNextTest();
            }
        }
    };

    /** WEBVIEW CONFIGURATION */

    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(mCurrentTestUri)) {
                return;
            }

            /** TODO: Implement waitUntilDone */
            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;
        }

    };

    /** IMPLEMENTATION */

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = getIntent();
        mTestsList = intent.getStringArrayListExtra(EXTRA_TESTS_LIST);

        bindService(new Intent(this, ManagerService.class), mServiceConnection,
                Context.BIND_AUTO_CREATE);
    }

    private void reset() {
        mOnTestFinishedCalled = false;
        mCurrentResult = null;

        mCurrentWebView = new WebView(this);
        mCurrentWebView.setWebViewClient(mWebViewClient);
        mCurrentWebView.setWebChromeClient(mWebChromeClient);

        WebSettings webViewSettings = mCurrentWebView.getSettings();
        webViewSettings.setAppCacheEnabled(true);
        webViewSettings.setAppCachePath(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(getDir("databases", 0).getAbsolutePath());
        webViewSettings.setDomStorageEnabled(true);
        webViewSettings.setWorkersEnabled(false);
        webViewSettings.setXSSAuditorEnabled(false);

        setContentView(mCurrentWebView);
    }

    private void runNextTest() {
        if (mTestsList.isEmpty()) {
            onAllTestsFinished();
            return;
        }

        mCurrentTestCount++;
        mCurrentTestRelativePath = mTestsList.remove(0);
        mCurrentTestUri =
                Uri.fromFile(new File(TESTS_ROOT_DIR_PATH, mCurrentTestRelativePath)).toString();

        reset();
        /** TODO: Implement timeout */
        mCurrentWebView.loadUrl(mCurrentTestUri);
    }

    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 (mCurrentResult == null) {
            /** TODO: Default type should be RenderTreeResult. We don't support it now. */
            mCurrentResult = new TextResult(mCurrentTestRelativePath);
        }

        mCurrentResult.obtainActualResults(mCurrentWebView,
                mResultHandler.obtainMessage(MSG_ACTUAL_RESULT_OBTAINED));
    }

    private void reportResultToService() {
        try {
            Message serviceMsg =
                    Message.obtain(null, ManagerService.MSG_PROCESS_ACTUAL_RESULTS);
            Bundle bundle = mCurrentResult.getBundle();
            /** TODO: Add timeout info to bundle */
            serviceMsg.setData(bundle);
            mManagerServiceMessenger.send(serviceMsg);
        } catch (RemoteException e) {
            Log.e(LOG_TAG + "::reportResultToService", e.getMessage());
        }
    }

    private void onAllTestsFinished() {
        Log.d(LOG_TAG + "::onAllTestsFisnihed", "Begin.");
    }
}
 No newline at end of file
+13 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.dumprendertree2;

import android.content.Intent;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
@@ -23,6 +24,7 @@ import android.os.Message;
import android.util.Log;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;

/**
@@ -154,7 +156,17 @@ public class LayoutTestsRunnerThread extends Thread {
            mTotalTestCount = 1;
        }

        runNextTest();
        /**
         * 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();
    }

Loading