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

Commit ccedde80 authored by Ats Jenk's avatar Ats Jenk
Browse files

Helper to verify ui event has bubble info

Create a custom Subject implementation to verify that FakeUiEvent
includes the correct fields from a Bubble.
Allows us to verify bubble data with one call vs checking 3 fields in
every test.

Bug: 349845968
Test: atest BubbleBarExpandedViewTest
Test: atest UiEventSubjectTest
Flag: EXEMPT test only
Change-Id: I16e452b6480bd84a2e1a62e011e67950a6417a4a
parent cd4ca00a
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.wm.shell.bubbles

import com.android.internal.logging.testing.UiEventLoggerFake.FakeUiEvent
import com.google.common.truth.FailureMetadata
import com.google.common.truth.Subject
import com.google.common.truth.Truth

/** Subclass of [Subject] to simplify verifying [FakeUiEvent] data */
class UiEventSubject(metadata: FailureMetadata, private val actual: FakeUiEvent) :
    Subject(metadata, actual) {

    /** Check that [FakeUiEvent] contains the expected data from the [bubble] passed id */
    fun hasBubbleInfo(bubble: Bubble) {
        check("uid").that(actual.uid).isEqualTo(bubble.appUid)
        check("packageName").that(actual.packageName).isEqualTo(bubble.packageName)
        check("instanceId").that(actual.instanceId).isEqualTo(bubble.instanceId)
    }

    companion object {
        @JvmStatic
        fun assertThat(event: FakeUiEvent): UiEventSubject =
            Truth.assertAbout(Factory(::UiEventSubject)).that(event)
    }
}
+147 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.wm.shell.bubbles

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.internal.logging.testing.UiEventLoggerFake.FakeUiEvent
import com.android.wm.shell.bubbles.UiEventSubject.Companion.assertThat
import com.google.common.truth.ExpectFailure.assertThat
import com.google.common.truth.ExpectFailure.expectFailure
import com.google.common.truth.Subject
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
import org.mockito.kotlin.whenever

/** Test for [UiEventSubject] */
@SmallTest
@RunWith(AndroidJUnit4::class)
class UiEventSubjectTest {

    private val uiEventSubjectFactory =
        Subject.Factory<UiEventSubject, FakeUiEvent> { metadata, actual ->
            UiEventSubject(metadata, actual)
        }

    private lateinit var uiEventLoggerFake: UiEventLoggerFake

    @Before
    fun setUp() {
        uiEventLoggerFake = UiEventLoggerFake()
    }

    @Test
    fun test_bubbleLogEvent_hasBubbleInfo() {
        val bubble =
            createBubble(
                appUid = 1,
                packageName = "test",
                instanceId = InstanceId.fakeInstanceId(2),
            )
        BubbleLogger(uiEventLoggerFake).log(bubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_POSTED)
        val uiEvent = uiEventLoggerFake.logs.first()

        // Check that fields match the expected values
        assertThat(uiEvent.uid).isEqualTo(1)
        assertThat(uiEvent.packageName).isEqualTo("test")
        assertThat(uiEvent.instanceId.id).isEqualTo(2)

        // Check that hasBubbleInfo condition passes
        assertThat(uiEvent).hasBubbleInfo(bubble)
    }

    @Test
    fun test_bubbleLogEvent_uidMismatch() {
        val bubble =
            createBubble(
                appUid = 1,
                packageName = "test",
                instanceId = InstanceId.fakeInstanceId(2),
            )
        BubbleLogger(uiEventLoggerFake).log(bubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_POSTED)
        val uiEvent = uiEventLoggerFake.logs.first()

        // Change uid to have a mismatch
        val otherBubble = bubble.copy(appUid = 99)

        val failure = expectFailure { test ->
            test.about(uiEventSubjectFactory).that(uiEvent).hasBubbleInfo(otherBubble)
        }
        assertThat(failure).factValue("value of").isEqualTo("uiEvent.uid")
    }

    @Test
    fun test_bubbleLogEvent_packageNameMismatch() {
        val bubble =
            createBubble(
                appUid = 1,
                packageName = "test",
                instanceId = InstanceId.fakeInstanceId(2),
            )
        BubbleLogger(uiEventLoggerFake).log(bubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_POSTED)
        val uiEvent = uiEventLoggerFake.logs.first()

        // Change package name to have a mismatch
        val otherBubble = bubble.copy(packageName = "somethingelse")

        val failure = expectFailure { test ->
            test.about(uiEventSubjectFactory).that(uiEvent).hasBubbleInfo(otherBubble)
        }
        assertThat(failure).factValue("value of").isEqualTo("uiEvent.packageName")
    }

    @Test
    fun test_bubbleLogEvent_instanceIdMismatch() {
        val bubble =
            createBubble(
                appUid = 1,
                packageName = "test",
                instanceId = InstanceId.fakeInstanceId(2),
            )
        BubbleLogger(uiEventLoggerFake).log(bubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_POSTED)
        val uiEvent = uiEventLoggerFake.logs.first()

        // Change instance id to have a mismatch
        val otherBubble = bubble.copy(instanceId = InstanceId.fakeInstanceId(99))

        val failure = expectFailure { test ->
            test.about(uiEventSubjectFactory).that(uiEvent).hasBubbleInfo(otherBubble)
        }
        assertThat(failure).factValue("value of").isEqualTo("uiEvent.instanceId")
    }

    private fun createBubble(appUid: Int, packageName: String, instanceId: InstanceId): Bubble {
        return mock(Bubble::class.java).apply {
            whenever(getAppUid()).thenReturn(appUid)
            whenever(getPackageName()).thenReturn(packageName)
            whenever(getInstanceId()).thenReturn(instanceId)
        }
    }

    private fun Bubble.copy(
        appUid: Int = this.appUid,
        packageName: String = this.packageName,
        instanceId: InstanceId = this.instanceId,
    ): Bubble {
        return createBubble(appUid, packageName, instanceId)
    }
}
+9 −7
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.wm.shell.bubbles.BubbleTaskView
import com.android.wm.shell.bubbles.BubbleTaskViewFactory
import com.android.wm.shell.bubbles.DeviceConfig
import com.android.wm.shell.bubbles.RegionSamplingProvider
import com.android.wm.shell.bubbles.UiEventSubject.Companion.assertThat
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.shared.bubbles.BubbleBarLocation
import com.android.wm.shell.shared.handles.RegionSamplingHelper
@@ -47,16 +48,14 @@ import com.android.wm.shell.taskview.TaskView
import com.android.wm.shell.taskview.TaskViewTaskController
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors.directExecutor
import java.util.Collections
import java.util.concurrent.Executor
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import java.util.Collections
import java.util.concurrent.Executor

/** Tests for [BubbleBarExpandedViewTest] */
@SmallTest
@@ -82,7 +81,7 @@ class BubbleBarExpandedViewTest {
    private var testableRegionSamplingHelper: TestableRegionSamplingHelper? = null
    private var regionSamplingProvider: TestRegionSamplingProvider? = null

    private val bubbleLogger = spy(BubbleLogger(UiEventLoggerFake()))
    private val uiEventLoggerFake = UiEventLoggerFake()

    @Before
    fun setUp() {
@@ -116,7 +115,7 @@ class BubbleBarExpandedViewTest {
        bubbleExpandedView.initialize(
            expandedViewManager,
            positioner,
            bubbleLogger,
            BubbleLogger(uiEventLoggerFake),
            false /* isOverflow */,
            bubbleTaskView,
            mainExecutor,
@@ -223,7 +222,10 @@ class BubbleBarExpandedViewTest {
            bubbleExpandedView.findViewWithTag<View>(BubbleBarMenuView.DISMISS_ACTION_TAG)
        assertThat(dismissMenuItem).isNotNull()
        getInstrumentation().runOnMainSync { dismissMenuItem.performClick() }
        verify(bubbleLogger).log(bubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_DISMISSED_APP_MENU)
        assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
        assertThat(uiEventLoggerFake.logs[0].eventId)
            .isEqualTo(BubbleLogger.Event.BUBBLE_BAR_BUBBLE_DISMISSED_APP_MENU.id)
        assertThat(uiEventLoggerFake.logs[0]).hasBubbleInfo(bubble)
    }

    private inner class FakeBubbleTaskViewFactory : BubbleTaskViewFactory {