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

Commit 71045287 authored by Bill Lin's avatar Bill Lin
Browse files

DO NOT MERGE Fix flaky tests in OverheatAlarm feature

TestableContext may be null that impact TestableSettingsProvider assert
fail in clearValuesAndCheck()

TestRunner could run in multiple thread, that could meet thread
asynchronization issue to meet flaky test

Tweak TestCase implementation to avoid flaky SystemUITests
1. Remove unnecessary complex testCase such as popup overheat twice
2. Reduce the life cycle of static singleton instance
   Mock Context for OverheatAlarmController
3. Implement tearDown() in PowerUITest to free PowerUI instance

Change-Id: I865bd0b53636a8bbd54fc3ca447b5b035207669c
Fix: 121351779
Fix: 122535130
Test: Build x86 emulator and manual run atest SystemUITests for
rundreds of times
parent e5324699
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -53,7 +53,8 @@ public class OverheatAlarmController {
    /**
     * The constructor only used to create singleton sInstance.
     */
    private OverheatAlarmController(Context context) {
    @VisibleForTesting
    public OverheatAlarmController(Context context) {
        mVibrator = (Vibrator) context.getSystemService(VIBRATOR_SERVICE);
    }

+28 −20
Original line number Diff line number Diff line
@@ -18,9 +18,13 @@ package com.android.systemui.power;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.os.PowerManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
@@ -31,56 +35,60 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;

@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@RunWithLooper(setAsMainLooper = true)
@SmallTest
public class OverheatAlarmControllerTest extends SysuiTestCase {
    OverheatAlarmController mOverheatAlarmController;
    @Mock
    Context mMockContext;
    @Mock
    PowerManager mMockPowerManager;

    OverheatAlarmController mSpyOverheatAlarmController;

    @Before
    public void setUp() {
        mOverheatAlarmController = OverheatAlarmController.getInstance(mContext);
        mSpyOverheatAlarmController = spy(mOverheatAlarmController);
        mMockContext = mock(Context.class);
        mMockPowerManager = mock(PowerManager.class);
        mSpyOverheatAlarmController = spy(new OverheatAlarmController(mMockContext));
        when(mMockContext.getSystemService(Context.POWER_SERVICE)).thenReturn(mMockPowerManager);
    }

    @After
    public void tearDown() {
        mSpyOverheatAlarmController.stopAlarm();
    }

    @Test
    public void testGetInstance() {
        assertThat(mOverheatAlarmController).isNotNull();
        mMockContext = null;
        mMockPowerManager = null;
        mSpyOverheatAlarmController = null;
    }

    @Test
    public void testStartAlarm_PlaySound() {
        mSpyOverheatAlarmController.startAlarm(mContext);
        verify(mSpyOverheatAlarmController).playSound(mContext);
    public void testStartAlarm_shouldPlaySound() {
        mSpyOverheatAlarmController.startAlarm(mMockContext);
        verify(mSpyOverheatAlarmController).playSound(mMockContext);
    }

    @Test
    public void testStartAlarm_InitVibrate() {
        mSpyOverheatAlarmController.startAlarm(mContext);
    public void testStartAlarm_shouldStartVibrate() {
        mSpyOverheatAlarmController.startAlarm(mMockContext);
        verify(mSpyOverheatAlarmController).startVibrate();
    }

    @Test
    public void testStartAlarm_StartVibrate() {
        mSpyOverheatAlarmController.startAlarm(mContext);
    public void testStartVibrate_shouldPerformVibrate() {
        mSpyOverheatAlarmController.startVibrate();
        verify(mSpyOverheatAlarmController).performVibrate();
    }

    @Test
    public void testStopAlarm_StopPlayer() {
    public void testStopAlarm_shouldStopPlay() {
        mSpyOverheatAlarmController.stopAlarm();
        verify(mSpyOverheatAlarmController).stopPlayer();
    }

    @Test
    public void testStopAlarm_StopVibrate() {
    public void testStopAlarm_shouldStopVibrate() {
        mSpyOverheatAlarmController.stopAlarm();
        verify(mSpyOverheatAlarmController).stopVibrate();
    }
+25 −98
Original line number Diff line number Diff line
@@ -16,20 +16,20 @@

package com.android.systemui.power;

import static com.google.common.truth.Truth.assertThat;

import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;

import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.support.test.runner.AndroidJUnit4;
@@ -52,11 +52,13 @@ public class PowerNotificationWarningsTest extends SysuiTestCase {
    public static final String FORMATTED_45M = "0h 45m";
    public static final String FORMATTED_HOUR = "1h 0m";
    private final NotificationManager mMockNotificationManager = mock(NotificationManager.class);
    private final KeyguardManager mMockKeyguardManager = mock(KeyguardManager.class);
    private PowerNotificationWarnings mPowerNotificationWarnings, mSpyPowerNotificationWarnings;

    @Before
    public void setUp() throws Exception {
        // Test Instance.
        mContext.addMockSystemService(KeyguardManager.class, mMockKeyguardManager);
        mContext.addMockSystemService(NotificationManager.class, mMockNotificationManager);
        mPowerNotificationWarnings = new PowerNotificationWarnings(mContext);
        mSpyPowerNotificationWarnings = spy(mPowerNotificationWarnings);
@@ -166,10 +168,9 @@ public class PowerNotificationWarningsTest extends SysuiTestCase {
    public void testSetOverheatAlarmDialog_Overheat_ShouldShowing() {
        final boolean overheat = true;
        final boolean shouldBeepSound = false;
        mContext.getMainThreadHandler().post(
                () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
                        shouldBeepSound));
        waitForIdleSync();
        mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat, shouldBeepSound);
        waitForIdleSync(mContext.getMainThreadHandler());

        verify(mSpyPowerNotificationWarnings, times(1)).setOverheatAlarmDialogShowing(overheat);
        verify(mSpyPowerNotificationWarnings, times(1)).setAlarmShouldSound(shouldBeepSound);
    }
@@ -178,10 +179,9 @@ public class PowerNotificationWarningsTest extends SysuiTestCase {
    public void testSetOverheatAlarmDialog_Overheat_ShouldShowingWithBeepSound() {
        final boolean overheat = true;
        final boolean shouldBeepSound = true;
        mContext.getMainThreadHandler().post(
                () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
                        shouldBeepSound));
        waitForIdleSync();
        mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat, shouldBeepSound);
        waitForIdleSync(mContext.getMainThreadHandler());

        verify(mSpyPowerNotificationWarnings, times(1)).setOverheatAlarmDialogShowing(overheat);
        verify(mSpyPowerNotificationWarnings, times(1)).setAlarmShouldSound(shouldBeepSound);
    }
@@ -190,10 +190,9 @@ public class PowerNotificationWarningsTest extends SysuiTestCase {
    public void testSetOverheatAlarmDialog_NotOverheat_ShouldNotShowing() {
        final boolean overheat = false;
        final boolean shouldBeepSound = false;
        mContext.getMainThreadHandler().post(
                () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
                        shouldBeepSound));
        waitForIdleSync();
        mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat, shouldBeepSound);
        waitForIdleSync(mContext.getMainThreadHandler());

        verify(mSpyPowerNotificationWarnings, never()).setOverheatAlarmDialogShowing(overheat);
        verify(mSpyPowerNotificationWarnings, never()).setAlarmShouldSound(shouldBeepSound);
    }
@@ -202,105 +201,33 @@ public class PowerNotificationWarningsTest extends SysuiTestCase {
    public void testSetOverheatAlarmDialog_NotOverheat_ShouldNotAlarmBeepSound() {
        final boolean overheat = false;
        final boolean configBeepSound = true;
        mContext.getMainThreadHandler().post(
                () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
                        configBeepSound));
        waitForIdleSync();
        mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat, configBeepSound);
        waitForIdleSync(mContext.getMainThreadHandler());

        verify(mSpyPowerNotificationWarnings, never()).setOverheatAlarmDialogShowing(overheat);
        verify(mSpyPowerNotificationWarnings, never()).setAlarmShouldSound(configBeepSound);
    }

    @Test
    public void testSetAlarmShouldSound_OverheatDrop_ShouldNotSound() {
        final boolean overheat = true;
        final boolean shouldBeepSound = true;
        mContext.getMainThreadHandler().post(
                () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
                        shouldBeepSound));
        waitForIdleSync();
        // First time overheat, show overheat alarm dialog with alarm beep sound
        verify(mSpyPowerNotificationWarnings, times(1)).setOverheatAlarmDialogShowing(overheat);
        verify(mSpyPowerNotificationWarnings, times(1)).setAlarmShouldSound(shouldBeepSound);

        // After disconnected cable or temperature drop
        mContext.getMainThreadHandler().post(
                () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(!overheat,
                        !shouldBeepSound));
        waitForIdleSync();
        verify(mSpyPowerNotificationWarnings, times(1)).setOverheatAlarmDialogShowing(!overheat);
        verify(mSpyPowerNotificationWarnings, times(1)).setAlarmShouldSound(!shouldBeepSound);
    }

    @Test
    public void testSetAlarmShouldSound_Overheat_Twice_ShouldShowOverheatDialogAgain() {
        final boolean overheat = true;
        final boolean shouldBeepSound = true;
        // First time overheat, show mAlarmDialog and alarm beep sound
        mContext.getMainThreadHandler().post(
                () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
                        shouldBeepSound));
        waitForIdleSync();
        verify(mSpyPowerNotificationWarnings, times(1)).setOverheatAlarmDialogShowing(overheat);
        verify(mSpyPowerNotificationWarnings, times(1)).setAlarmShouldSound(shouldBeepSound);

        // After disconnected cable or temperature drop, stop beep sound
        mContext.getMainThreadHandler().post(
                () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(!overheat,
                        !shouldBeepSound));
        waitForIdleSync();
        verify(mSpyPowerNotificationWarnings, times(1)).setOverheatAlarmDialogShowing(!overheat);
        verify(mSpyPowerNotificationWarnings, times(1)).setAlarmShouldSound(!shouldBeepSound);

        // Overheat again, ensure the previous dialog do not auto-dismiss
        mContext.getMainThreadHandler().post(
                () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
                        shouldBeepSound));
        waitForIdleSync();
        verify(mSpyPowerNotificationWarnings, times(1)).setOverheatAlarmDialogShowing(overheat);
        verify(mSpyPowerNotificationWarnings, times(1)).setAlarmShouldSound(shouldBeepSound);
    }

    @Test
    public void testOverheatAlarmDialogShowing() {
        final boolean overheat = true;
        final boolean shouldBeepSound = false;
        mContext.getMainThreadHandler().post(
                () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
                        shouldBeepSound));
        waitForIdleSync();
        assertThat(mSpyPowerNotificationWarnings.mOverheatAlarmDialog).isNotNull();
    }
        mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat, shouldBeepSound);
        waitForIdleSync(mContext.getMainThreadHandler());

    @Test
    public void testOverheatAlarmDialogShowingWithBeepSound() {
        final boolean overheat = true;
        final boolean shouldBeepSound = true;
        mContext.getMainThreadHandler().post(
                () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
                        shouldBeepSound));
        waitForIdleSync();
        assertThat(mSpyPowerNotificationWarnings.mOverheatAlarmDialog).isNotNull();
        verify(mSpyPowerNotificationWarnings, atLeastOnce()).setOverheatAlarmDialogShowing(
                overheat);
    }

    @Test
    public void testOverheatAlarmDialogNotShowing() {
        final boolean overheat = false;
        final boolean shouldBeepSound = false;
        mContext.getMainThreadHandler().post(
                () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
                        shouldBeepSound));
        waitForIdleSync();
        assertThat(mSpyPowerNotificationWarnings.mOverheatAlarmDialog).isNull();
    }
        mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat, shouldBeepSound);

    @Test
    public void testOverheatAlarmDialogNotShowingWithBeepSound() {
        final boolean overheat = false;
        final boolean shouldBeepSound = true;
        mContext.getMainThreadHandler().post(
                () -> mSpyPowerNotificationWarnings.notifyHighTemperatureAlarm(overheat,
                        shouldBeepSound));
        waitForIdleSync();
        assertThat(mSpyPowerNotificationWarnings.mOverheatAlarmDialog).isNull();
        waitForIdleSync(mContext.getMainThreadHandler());
        verify(mSpyPowerNotificationWarnings, never()).setOverheatAlarmDialogShowing(
                overheat);
    }

}
+7 −14
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@ import com.android.systemui.statusbar.phone.StatusBar;
import java.time.Duration;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -92,6 +94,11 @@ public class PowerUITest extends SysuiTestCase {
        createPowerUi();
    }

    @After
    public void tearDown() throws Exception {
        mPowerUI = null;
    }

    @Test
    public void testNoConfig_NoWarnings() {
        setOverThreshold();
@@ -202,20 +209,6 @@ public class PowerUITest extends SysuiTestCase {
        verify(mMockWarnings).notifyHighTemperatureAlarm(overheat, shouldBeepSound);
    }

    @Test
    public void testConfig_alarmsWithBeepSound() {
        setOverThreshold();
        final Boolean overheat = true;
        final Boolean shouldBeepSound = true;
        TestableResources resources = mContext.getOrCreateTestableResources();
        resources.addOverride(R.integer.config_showTemperatureAlarm, 1);
        resources.addOverride(R.integer.config_alarmTemperature, 58);
        resources.addOverride(R.bool.config_alarmTemperatureBeepSound, shouldBeepSound);

        mPowerUI.start();
        verify(mMockWarnings).notifyHighTemperatureAlarm(overheat, shouldBeepSound);
    }

    @Test
    public void testHardPropsThrottlingThreshold_alarms() {
        setThrottlingThreshold(DEFAULT_OVERHEAT_ALARM_THRESHOLD);