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

Commit 70dffbe8 authored by Vadim Tryshev's avatar Vadim Tryshev Committed by Android (Google) Code Review
Browse files

Merge "Sampling too long Launcher tests" into tm-dev

parents 37edea67 25fbd5b0
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.testcomponent.TestCommandReceiver;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.FailureWatcher;
import com.android.launcher3.util.rule.SamplerRule;
import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.quickstep.views.RecentsView;

@@ -111,7 +112,8 @@ public class FallbackRecentsTest {
        }

        mOrderSensitiveRules = RuleChain
                .outerRule(new NavigationModeSwitchRule(mLauncher))
                .outerRule(new SamplerRule())
                .around(new NavigationModeSwitchRule(mLauncher))
                .around(new FailureWatcher(mDevice, mLauncher));

        mOtherLauncherActivity = context.getPackageManager().queryIntentActivities(
+1 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ filegroup {
      "src/com/android/launcher3/util/WidgetUtils.java",
      "src/com/android/launcher3/util/rule/FailureWatcher.java",
      "src/com/android/launcher3/util/rule/LauncherActivityRule.java",
      "src/com/android/launcher3/util/rule/SamplerRule.java",
      "src/com/android/launcher3/util/rule/ScreenRecordRule.java",
      "src/com/android/launcher3/util/rule/ShellCommandRule.java",
      "src/com/android/launcher3/util/rule/SimpleActivityRule.java",
+3 −1
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ import com.android.launcher3.util.Wait;
import com.android.launcher3.util.WidgetUtils;
import com.android.launcher3.util.rule.FailureWatcher;
import com.android.launcher3.util.rule.LauncherActivityRule;
import com.android.launcher3.util.rule.SamplerRule;
import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.util.rule.TestStabilityRule;
@@ -227,7 +228,8 @@ public abstract class AbstractLauncherUiTest {

    @Rule
    public TestRule mOrderSensitiveRules = RuleChain
            .outerRule(new TestStabilityRule())
            .outerRule(new SamplerRule())
            .around(new TestStabilityRule())
            .around(mActivityMonitor)
            .around(getRulesInsideActivityMonitor());

+129 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.launcher3.util.rule;

import android.os.SystemClock;

import androidx.test.InstrumentationRegistry;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * A rule that generates a file that helps diagnosing cases when the test process was terminated
 * because the test execution took too long, and tests that ran for too long even without being
 * terminated. If the process was terminated or the test was long, the test leaves an artifact with
 * stack traces of all threads, every SAMPLE_INTERVAL_MS. This will help understanding where we
 * stuck.
 */
public class SamplerRule implements TestRule {
    private static final int TOO_LONG_TEST_MS = 180000;
    private static final int SAMPLE_INTERVAL_MS = 3000;

    public static Thread startThread(Description description) {
        Thread thread =
                new Thread() {
                    @Override
                    public void run() {
                        // Write all-threads stack stace every SAMPLE_INTERVAL_MS while the test
                        // is running.
                        // After the test finishes, delete that file. If the test process is
                        // terminated due to timeout, the trace file won't be deleted.
                        final File file = getFile();

                        final long startTime = SystemClock.elapsedRealtime();
                        try (OutputStreamWriter outputStreamWriter =
                                     new OutputStreamWriter(
                                             new BufferedOutputStream(
                                                     new FileOutputStream(file)))) {
                            writeSamples(outputStreamWriter);
                        } catch (IOException | InterruptedException e) {
                            // Simply suppressing the exceptions, nothing to do here.
                        } finally {
                            // If the process is not killed, then there was no test timeout, and
                            // we are not interested in the trace file, unless the test ran too
                            // long.
                            if (SystemClock.elapsedRealtime() - startTime < TOO_LONG_TEST_MS) {
                                file.delete();
                            }
                        }
                    }

                    private File getFile() {
                        final String strDate = new SimpleDateFormat("HH:mm:ss").format(new Date());

                        final String descStr = description.getTestClass().getSimpleName() + "."
                                + description.getMethodName();
                        return artifactFile(
                                "ThreadStackSamples-" + strDate + "-" + descStr + ".txt");
                    }

                    private void writeSamples(OutputStreamWriter writer)
                            throws IOException, InterruptedException {
                        int count = 0;
                        while (true) {
                            writer.write(
                                    "#"
                                            + (count++)
                                            + " =============================================\r\n");
                            for (StackTraceElement[] stack : getAllStackTraces().values()) {
                                writer.write("---------------------\r\n");
                                for (StackTraceElement frame : stack) {
                                    writer.write(frame.toString() + "\r\n");
                                }
                            }
                            writer.flush();

                            sleep(SAMPLE_INTERVAL_MS);
                        }
                    }
                };

        thread.start();
        return thread;
    }

    @Override
    public Statement apply(Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                final Thread traceThread = startThread(description);
                try {
                    base.evaluate();
                } finally {
                    traceThread.interrupt();
                    traceThread.join();
                }
            }
        };
    }

    private static File artifactFile(String fileName) {
        return new File(
                InstrumentationRegistry.getInstrumentation().getTargetContext().getFilesDir(),
                fileName);
    }
}