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

Commit c39b6444 authored by Nataniel Borges's avatar Nataniel Borges
Browse files

Use FlickerParametersRunnerFactory

JUnit4 Parameterized runner allows us to create custom UseParametersRunnerFactory classes. Flicker now uses this method for better compatibility with Flaky Failure FingerPrinting and Crystalball

Bug: 162923992
Test: atest FlickerTests
Change-Id: Iac3e9972b39fb96bf7fe85beac16728c5947766b
parent d358a9f6
Loading
Loading
Loading
Loading
+34 −181
Original line number Diff line number Diff line
@@ -18,239 +18,92 @@ package com.android.wm.shell.flicker

import android.graphics.Region
import android.view.Surface
import com.android.server.wm.flicker.dsl.LayersAssertionBuilder
import com.android.server.wm.flicker.dsl.LayersAssertionBuilderLegacy
import com.android.server.wm.flicker.APP_PAIR_SPLIT_DIVIDER
import com.android.server.wm.flicker.DOCKED_STACK_DIVIDER
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.traces.layers.getVisibleBounds

@JvmOverloads
fun LayersAssertionBuilder.appPairsDividerIsVisible(bugId: Int = 0) {
    end("appPairsDividerIsVisible", bugId) {
fun FlickerTestParameter.appPairsDividerIsVisible() {
    assertLayersEnd {
        this.isVisible(APP_PAIR_SPLIT_DIVIDER)
    }
}

@JvmOverloads
fun LayersAssertionBuilder.appPairsDividerIsInvisible(bugId: Int = 0) {
    end("appPairsDividerIsInVisible", bugId) {
fun FlickerTestParameter.appPairsDividerIsInvisible() {
    assertLayersEnd {
        this.notExists(APP_PAIR_SPLIT_DIVIDER)
    }
}

@JvmOverloads
fun LayersAssertionBuilder.appPairsDividerBecomesVisible(bugId: Int = 0) {
    all("dividerLayerBecomesVisible", bugId) {
fun FlickerTestParameter.appPairsDividerBecomesVisible() {
    assertLayers {
        this.hidesLayer(DOCKED_STACK_DIVIDER)
            .then()
            .showsLayer(DOCKED_STACK_DIVIDER)
    }
}

@JvmOverloads
fun LayersAssertionBuilder.dockedStackDividerIsVisible(bugId: Int = 0) {
    end("dockedStackDividerIsVisible", bugId) {
fun FlickerTestParameter.dockedStackDividerIsVisible() {
    assertLayersEnd {
        this.isVisible(DOCKED_STACK_DIVIDER)
    }
}

@JvmOverloads
fun LayersAssertionBuilder.dockedStackDividerBecomesVisible(bugId: Int = 0) {
    all("dividerLayerBecomesVisible", bugId) {
fun FlickerTestParameter.dockedStackDividerBecomesVisible() {
    assertLayers {
        this.hidesLayer(DOCKED_STACK_DIVIDER)
            .then()
            .showsLayer(DOCKED_STACK_DIVIDER)
    }
}

@JvmOverloads
fun LayersAssertionBuilder.dockedStackDividerBecomesInvisible(bugId: Int = 0) {
    all("dividerLayerBecomesInvisible", bugId) {
fun FlickerTestParameter.dockedStackDividerBecomesInvisible() {
    assertLayers {
        this.showsLayer(DOCKED_STACK_DIVIDER)
            .then()
            .hidesLayer(DOCKED_STACK_DIVIDER)
    }
}

@JvmOverloads
fun LayersAssertionBuilder.dockedStackDividerIsInvisible(bugId: Int = 0) {
    end("dockedStackDividerIsInvisible", bugId) {
fun FlickerTestParameter.dockedStackDividerIsInvisible() {
    assertLayersEnd {
        this.notExists(DOCKED_STACK_DIVIDER)
    }
}

@JvmOverloads
fun LayersAssertionBuilder.appPairsPrimaryBoundsIsVisible(
    rotation: Int,
    primaryLayerName: String,
    bugId: Int = 0
) {
    end("PrimaryAppBounds", bugId) {
fun FlickerTestParameter.appPairsPrimaryBoundsIsVisible(rotation: Int, primaryLayerName: String) {
    assertLayersEnd {
        val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
        this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation))
    }
}

@JvmOverloads
fun LayersAssertionBuilder.appPairsSecondaryBoundsIsVisible(
    rotation: Int,
    secondaryLayerName: String,
    bugId: Int = 0
) {
    end("SecondaryAppBounds", bugId) {
        val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
        this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation))
    }
}

@JvmOverloads
fun LayersAssertionBuilder.dockedStackPrimaryBoundsIsVisible(
fun FlickerTestParameter.dockedStackPrimaryBoundsIsVisible(
    rotation: Int,
    primaryLayerName: String,
    bugId: Int = 0
    primaryLayerName: String
) {
    end("PrimaryAppBounds", bugId) {
    assertLayersEnd {
        val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER)
        this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation))
    }
}

@JvmOverloads
fun LayersAssertionBuilder.dockedStackSecondaryBoundsIsVisible(
fun FlickerTestParameter.appPairsSecondaryBoundsIsVisible(
    rotation: Int,
    secondaryLayerName: String,
    bugId: Int = 0
) {
    end("SecondaryAppBounds", bugId) {
        val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER)
        this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation))
    }
}

@JvmOverloads
fun LayersAssertionBuilderLegacy.appPairsDividerIsVisible(
    bugId: Int = 0,
    enabled: Boolean = bugId == 0
) {
    end("appPairsDividerIsVisible", bugId, enabled) {
        this.isVisible(APP_PAIR_SPLIT_DIVIDER)
    }
}

@JvmOverloads
fun LayersAssertionBuilderLegacy.appPairsDividerIsInvisible(
    bugId: Int = 0,
    enabled: Boolean = bugId == 0
) {
    end("appPairsDividerIsInVisible", bugId, enabled) {
        this.notExists(APP_PAIR_SPLIT_DIVIDER)
    }
}

@JvmOverloads
fun LayersAssertionBuilderLegacy.appPairsDividerBecomesVisible(
    bugId: Int = 0,
    enabled: Boolean = bugId == 0
) {
    all("dividerLayerBecomesVisible", bugId, enabled) {
        this.hidesLayer(DOCKED_STACK_DIVIDER)
            .then()
            .showsLayer(DOCKED_STACK_DIVIDER)
    }
}

@JvmOverloads
fun LayersAssertionBuilderLegacy.dockedStackDividerIsVisible(
    bugId: Int = 0,
    enabled: Boolean = bugId == 0
    secondaryLayerName: String
) {
    end("dockedStackDividerIsVisible", bugId, enabled) {
        this.isVisible(DOCKED_STACK_DIVIDER)
    }
}

@JvmOverloads
fun LayersAssertionBuilderLegacy.dockedStackDividerBecomesVisible(
    bugId: Int = 0,
    enabled: Boolean = bugId == 0
) {
    all("dividerLayerBecomesVisible", bugId, enabled) {
        this.hidesLayer(DOCKED_STACK_DIVIDER)
            .then()
            .showsLayer(DOCKED_STACK_DIVIDER)
    }
}

@JvmOverloads
fun LayersAssertionBuilderLegacy.dockedStackDividerBecomesInvisible(
    bugId: Int = 0,
    enabled: Boolean = bugId == 0
) {
    all("dividerLayerBecomesInvisible", bugId, enabled) {
        this.showsLayer(DOCKED_STACK_DIVIDER)
            .then()
            .hidesLayer(DOCKED_STACK_DIVIDER)
    }
}

@JvmOverloads
fun LayersAssertionBuilderLegacy.dockedStackDividerIsInvisible(
    bugId: Int = 0,
    enabled: Boolean = bugId == 0
) {
    end("dockedStackDividerIsInvisible", bugId, enabled) {
        this.notExists(DOCKED_STACK_DIVIDER)
    }
}

@JvmOverloads
fun LayersAssertionBuilderLegacy.appPairsPrimaryBoundsIsVisible(
    rotation: Int,
    primaryLayerName: String,
    bugId: Int = 0,
    enabled: Boolean = bugId == 0
) {
    end("PrimaryAppBounds", bugId, enabled) {
        val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
        this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation))
    }
}

@JvmOverloads
fun LayersAssertionBuilderLegacy.appPairsSecondaryBoundsIsVisible(
    rotation: Int,
    secondaryLayerName: String,
    bugId: Int = 0,
    enabled: Boolean = bugId == 0
) {
    end("SecondaryAppBounds", bugId, enabled) {
    assertLayersEnd {
        val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
        this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation))
    }
}

@JvmOverloads
fun LayersAssertionBuilderLegacy.dockedStackPrimaryBoundsIsVisible(
    rotation: Int,
    primaryLayerName: String,
    bugId: Int = 0,
    enabled: Boolean = bugId == 0
) {
    end("PrimaryAppBounds", bugId, enabled) {
        val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER)
        this.hasVisibleRegion(primaryLayerName, getPrimaryRegion(dividerRegion, rotation))
    }
}

@JvmOverloads
fun LayersAssertionBuilderLegacy.dockedStackSecondaryBoundsIsVisible(
fun FlickerTestParameter.dockedStackSecondaryBoundsIsVisible(
    rotation: Int,
    secondaryLayerName: String,
    bugId: Int = 0,
    enabled: Boolean = bugId == 0
    secondaryLayerName: String
) {
    end("SecondaryAppBounds", bugId, enabled) {
    assertLayersEnd {
        val dividerRegion = entry.getVisibleBounds(DOCKED_STACK_DIVIDER)
        this.hasVisibleRegion(secondaryLayerName, getSecondaryRegion(dividerRegion, rotation))
    }
+15 −86
Original line number Diff line number Diff line
@@ -16,33 +16,33 @@

package com.android.wm.shell.flicker

import android.app.Instrumentation
import android.content.pm.PackageManager
import android.content.pm.PackageManager.FEATURE_LEANBACK
import android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY
import android.os.RemoteException
import android.os.SystemClock
import android.platform.helpers.IAppHelper
import android.view.Surface
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.server.wm.flicker.Flicker
import org.junit.Assume.assumeFalse
import org.junit.Before
import org.junit.runners.Parameterized

/**
 * Base class of all Flicker test that performs common functions for all flicker tests:
 *
 *
 * - Caches transitions so that a transition is run once and the transition results are used by
 * tests multiple times. This is needed for parameterized tests which call the BeforeClass methods
 * multiple times.
 * - Keeps track of all test artifacts and deletes ones which do not need to be reviewed.
 * - Fails tests if results are not available for any test due to jank.
 */
abstract class FlickerTestBase {
    val instrumentation by lazy { InstrumentationRegistry.getInstrumentation() }
    val uiDevice by lazy { UiDevice.getInstance(instrumentation) }
    val packageManager: PackageManager by lazy { instrumentation.context.getPackageManager() }
abstract class FlickerTestBase(
    protected val rotationName: String,
    protected val rotation: Int
) {
    val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
    val uiDevice = UiDevice.getInstance(instrumentation)
    val packageManager: PackageManager = instrumentation.context.packageManager
    protected val isTelevision: Boolean by lazy {
        packageManager.run {
            hasSystemFeature(FEATURE_LEANBACK) || hasSystemFeature(FEATURE_LEANBACK_ONLY)
@@ -56,83 +56,12 @@ abstract class FlickerTestBase {
    @Before
    open fun televisionSetUp() = assumeFalse(isTelevision)

    /**
     * Build a test tag for the test
     * @param testName Name of the transition(s) being tested
     * @param app App being launcher
     * @param rotation Initial screen rotation
     *
     * @return test tag with pattern <NAME>__<APP>__<ROTATION>
    </ROTATION></APP></NAME> */
    protected fun buildTestTag(testName: String, app: IAppHelper, rotation: Int): String {
        return buildTestTag(
                testName, app, rotation, rotation, app2 = null, extraInfo = "")
    }

    /**
     * Build a test tag for the test
     * @param testName Name of the transition(s) being tested
     * @param app App being launcher
     * @param beginRotation Initial screen rotation
     * @param endRotation End screen rotation (if any, otherwise use same as initial)
     *
     * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
    </END_ROTATION></BEGIN_ROTATION></APP></NAME> */
    protected fun buildTestTag(
        testName: String,
        app: IAppHelper,
        beginRotation: Int,
        endRotation: Int
    ): String {
        return buildTestTag(
                testName, app, beginRotation, endRotation, app2 = null, extraInfo = "")
    }

    /**
     * Build a test tag for the test
     * @param testName Name of the transition(s) being tested
     * @param app App being launcher
     * @param app2 Second app being launched (if any)
     * @param beginRotation Initial screen rotation
     * @param endRotation End screen rotation (if any, otherwise use same as initial)
     * @param extraInfo Additional information to append to the tag
     *
     * @return test tag with pattern <NAME>__<APP></APP>(S)>__<ROTATION></ROTATION>(S)>[__<EXTRA>]
    </EXTRA></NAME> */
    protected fun buildTestTag(
        testName: String,
        app: IAppHelper,
        beginRotation: Int,
        endRotation: Int,
        app2: IAppHelper?,
        extraInfo: String
    ): String {
        var testTag = "${testName}__${app.launcherName}"
        if (app2 != null) {
            testTag += "-${app2.launcherName}"
        }
        testTag += "__${Surface.rotationToString(beginRotation)}"
        if (endRotation != beginRotation) {
            testTag += "-${Surface.rotationToString(endRotation)}"
        }
        if (extraInfo.isNotEmpty()) {
            testTag += "__$extraInfo"
        }
        return testTag
    }

    protected fun Flicker.setRotation(rotation: Int) {
        try {
            when (rotation) {
                Surface.ROTATION_270 -> device.setOrientationLeft()
                Surface.ROTATION_90 -> device.setOrientationRight()
                Surface.ROTATION_0 -> device.setOrientationNatural()
                else -> device.setOrientationNatural()
            }
            // Wait for animation to complete
            SystemClock.sleep(1000)
        } catch (e: RemoteException) {
            throw RuntimeException(e)
    companion object {
        @Parameterized.Parameters(name = "{0}")
        @JvmStatic
        fun getParams(): Collection<Array<Any>> {
            val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
            return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
        }
    }
}
+42 −41
Original line number Diff line number Diff line
@@ -18,15 +18,16 @@ package com.android.wm.shell.flicker.apppairs

import android.os.Bundle
import android.os.SystemClock
import android.platform.test.annotations.Presubmit
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.FlickerTestRunner
import com.android.server.wm.flicker.FlickerTestRunnerFactory
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.appPairsDividerIsInvisible
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -41,18 +42,15 @@ import org.junit.runners.Parameterized
 */
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class AppPairsTestCannotPairNonResizeableApps(
    testSpec: FlickerTestRunnerFactory.TestSpec
) : FlickerTestRunner(testSpec) {
    companion object : AppPairsTransition(InstrumentationRegistry.getInstrumentation()) {
        @Parameterized.Parameters(name = "{0}")
        @JvmStatic
        fun getParams(): List<Array<Any>> {
            val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
                withTestName {
                    buildTestTag(configuration)
                }
    testSpec: FlickerTestParameter
) : AppPairsTransition(testSpec) {

    override val transition: FlickerBuilder.(Bundle) -> Unit
        get() = {
            super.transition(this, it)
            transitions {
                nonResizeableApp?.launchViaIntent(wmHelper)
                // TODO pair apps through normal UX flow
@@ -60,28 +58,31 @@ class AppPairsTestCannotPairNonResizeableApps(
                    composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
                SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
            }
                assertions {
                    presubmit {
                        layersTrace {
                            appPairsDividerIsInvisible()
        }
                        windowManagerTrace {

    @Presubmit
    @Test
    fun appPairsDividerIsInvisible() = testSpec.appPairsDividerIsInvisible()

    @Presubmit
    @Test
    fun onlyResizeableAppWindowVisible() {
        val nonResizeableApp = nonResizeableApp
        require(nonResizeableApp != null) {
            "Non resizeable app not initialized"
        }

                            end("onlyResizeableAppWindowVisible") {
        testSpec.assertWmEnd {
            isVisible(nonResizeableApp.defaultWindowName)
            isInvisible(primaryApp.defaultWindowName)
        }
    }
                    }
                }
            }

            return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation,
                transition, testSpec, repetitions = AppPairsHelper.TEST_REPETITIONS)
    companion object {
        @Parameterized.Parameters(name = "{0}")
        @JvmStatic
        fun getParams(): List<FlickerTestParameter> {
            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
                repetitions = AppPairsHelper.TEST_REPETITIONS)
        }
    }
}
 No newline at end of file
+49 −46
Original line number Diff line number Diff line
@@ -18,17 +18,19 @@ package com.android.wm.shell.flicker.apppairs

import android.os.Bundle
import android.os.SystemClock
import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.APP_PAIR_SPLIT_DIVIDER
import com.android.server.wm.flicker.FlickerTestRunner
import com.android.server.wm.flicker.FlickerTestRunnerFactory
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.buildTestTag
import com.android.server.wm.flicker.traces.layers.getVisibleBounds
import com.android.wm.shell.flicker.appPairsDividerIsVisible
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -39,40 +41,39 @@ import org.junit.runners.Parameterized
 */
@RequiresDevice
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class AppPairsTestPairPrimaryAndSecondaryApps(
    testSpec: FlickerTestRunnerFactory.TestSpec
) : FlickerTestRunner(testSpec) {
    companion object : AppPairsTransition(InstrumentationRegistry.getInstrumentation()) {
        @Parameterized.Parameters(name = "{0}")
        @JvmStatic
        fun getParams(): List<Array<Any>> {
            val testSpec: FlickerBuilder.(Bundle) -> Unit = { configuration ->
                withTestName {
                    buildTestTag(configuration)
                }
    testSpec: FlickerTestParameter
) : AppPairsTransition(testSpec) {
    override val transition: FlickerBuilder.(Bundle) -> Unit
        get() = {
            super.transition(this, it)
            transitions {
                // TODO pair apps through normal UX flow
                executeShellCommand(
                    composePairsCommand(primaryTaskId, secondaryTaskId, pair = true))
                SystemClock.sleep(AppPairsHelper.TIMEOUT_MS)
            }
                assertions {
                    presubmit {
                        layersTrace {
                            appPairsDividerIsVisible()
        }
                        windowManagerTrace {
                            end("bothAppWindowsVisible") {

    @Presubmit
    @Test
    fun appPairsDividerIsVisible() = testSpec.appPairsDividerIsVisible()

    @Presubmit
    @Test
    fun bothAppWindowsVisible() {
        testSpec.assertWmEnd {
            isVisible(primaryApp.defaultWindowName)
            isVisible(secondaryApp.defaultWindowName)
        }
    }
                    }

                    flaky {
                        layersTrace {
                            end("appsEndingBounds") {
    @FlakyTest
    @Test
    fun appsEndingBounds() {
        testSpec.assertLayersEnd {
            val dividerRegion = entry.getVisibleBounds(APP_PAIR_SPLIT_DIVIDER)
            this.hasVisibleRegion(primaryApp.defaultWindowName,
                appPairsHelper.getPrimaryBounds(dividerRegion))
@@ -80,11 +81,13 @@ class AppPairsTestPairPrimaryAndSecondaryApps(
                    appPairsHelper.getSecondaryBounds(dividerRegion))
        }
    }
                    }
                }
            }
            return FlickerTestRunnerFactory.getInstance().buildTest(instrumentation, transition,
                testSpec, repetitions = AppPairsHelper.TEST_REPETITIONS)

    companion object {
        @Parameterized.Parameters(name = "{0}")
        @JvmStatic
        fun getParams(): List<FlickerTestParameter> {
            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
                repetitions = AppPairsHelper.TEST_REPETITIONS)
        }
    }
}
+63 −55

File changed.

Preview size limit exceeded, changes collapsed.

Loading