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

Commit b346d762 authored by Julia Tuttle's avatar Julia Tuttle Committed by Android (Google) Code Review
Browse files

Merge "Convert ShadeListBuilderTest to use assertLogsWtfs" into main

parents e4405de5 f3f21501
Loading
Loading
Loading
Loading
+81 −112
Original line number Diff line number Diff line
@@ -48,7 +48,6 @@ import android.os.SystemClock;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArrayMap;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -56,6 +55,7 @@ import androidx.test.filters.SmallTest;

import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.log.LogAssertKt;
import com.android.systemui.statusbar.NotificationInteractionTracker;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
@@ -76,6 +76,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
import com.android.systemui.util.time.FakeSystemClock;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -129,10 +130,6 @@ public class ShadeListBuilderTest extends SysuiTestCase {
    private Map<String, Integer> mNextIdMap = new ArrayMap<>();
    private int mNextRank = 0;

    private Log.TerribleFailureHandler mOldWtfHandler = null;
    private Log.TerribleFailure mLastWtf = null;
    private int mWtfCount = 0;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
@@ -1756,20 +1753,19 @@ public class ShadeListBuilderTest extends SysuiTestCase {
        mListBuilder.addPreGroupFilter(filter);
        mListBuilder.addOnBeforeTransformGroupsListener(listener);

        interceptWtfs();

        // WHEN we try to run the pipeline and the filter is invalidated exactly
        // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
        addNotif(0, PACKAGE_2);
        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
        dispatchBuild();
        runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);

        // THEN an exception is NOT thrown directly, but a WTF IS logged.
        expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
        LogAssertKt.assertLogsWtfs(() -> {
            dispatchBuild();
            runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
        });
    }

    @Test(expected = IllegalStateException.class)
    @Test
    public void testOutOfOrderPreGroupFilterInvalidationThrowsAfterTooManyRuns() {
        // GIVEN a PreGroupNotifFilter that gets invalidated during the grouping stage,
        NotifFilter filter = new PackageFilter(PACKAGE_1);
@@ -1778,20 +1774,20 @@ public class ShadeListBuilderTest extends SysuiTestCase {
        mListBuilder.addPreGroupFilter(filter);
        mListBuilder.addOnBeforeTransformGroupsListener(listener);

        interceptWtfs();

        // WHEN we try to run the pipeline and the filter is invalidated more than
        // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,

        // THEN an exception IS thrown.

        addNotif(0, PACKAGE_2);
        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);

        LogAssertKt.assertLogsWtfs(() -> {
            Assert.assertThrows(IllegalStateException.class, () -> {
                dispatchBuild();
        try {
                runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
        } finally {
            expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
        }

        // THEN an exception IS thrown.
            });
        });
    }

    @Test
@@ -1803,26 +1799,30 @@ public class ShadeListBuilderTest extends SysuiTestCase {
        mListBuilder.addPreGroupFilter(filter);
        mListBuilder.addOnBeforeTransformGroupsListener(listener);

        interceptWtfs();

        // WHEN we try to run the pipeline and the filter is invalidated
        // MAX_CONSECUTIVE_REENTRANT_REBUILDS times, the pipeline runs for a non-reentrant reason,
        // and then the filter is invalidated MAX_CONSECUTIVE_REENTRANT_REBUILDS times again,

        // THEN an exception is NOT thrown, but WTFs ARE logged.

        addNotif(0, PACKAGE_2);

        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
        LogAssertKt.assertLogsWtfs(() -> {
            dispatchBuild();
            runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
        });

        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
        LogAssertKt.assertLogsWtfs(() -> {
            // Note: dispatchBuild itself triggers a non-reentrant pipeline run.
            dispatchBuild();
            runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);

        // THEN an exception is NOT thrown, but WTFs ARE logged.
        expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS * 2);
        });
    }

    @Test
    public void testOutOfOrderPrompterInvalidationDoesNotThrowBeforeTooManyRuns() {
    public void testOutOfOrderPromoterInvalidationDoesNotThrowBeforeTooManyRuns() {
        // GIVEN a NotifPromoter that gets invalidated during the sorting stage,
        NotifPromoter promoter = new IdPromoter(47);
        CountingInvalidator invalidator = new CountingInvalidator(promoter);
@@ -1830,22 +1830,22 @@ public class ShadeListBuilderTest extends SysuiTestCase {
        mListBuilder.addPromoter(promoter);
        mListBuilder.addOnBeforeSortListener(listener);

        interceptWtfs();

        // WHEN we try to run the pipeline and the promoter is invalidated exactly
        // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,

        // THEN an exception is NOT thrown directly, but a WTF IS logged.

        addNotif(0, PACKAGE_1);
        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);

        LogAssertKt.assertLogsWtfs(() -> {
            dispatchBuild();
            runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);

        // THEN an exception is NOT thrown directly, but a WTF IS logged.
        expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);

        });
    }

    @Test(expected = IllegalStateException.class)
    public void testOutOfOrderPrompterInvalidationThrowsAfterTooManyRuns() {
    @Test
    public void testOutOfOrderPromoterInvalidationThrowsAfterTooManyRuns() {
        // GIVEN a NotifPromoter that gets invalidated during the sorting stage,
        NotifPromoter promoter = new IdPromoter(47);
        CountingInvalidator invalidator = new CountingInvalidator(promoter);
@@ -1853,20 +1853,20 @@ public class ShadeListBuilderTest extends SysuiTestCase {
        mListBuilder.addPromoter(promoter);
        mListBuilder.addOnBeforeSortListener(listener);

        interceptWtfs();

        // WHEN we try to run the pipeline and the promoter is invalidated more than
        // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,

        // THEN an exception IS thrown.

        addNotif(0, PACKAGE_1);
        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);

        LogAssertKt.assertLogsWtfs(() -> {
            Assert.assertThrows(IllegalStateException.class, () -> {
                dispatchBuild();
        try {
                runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
        } finally {
            expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
        }

        // THEN an exception IS thrown.
            });
        });
    }

    @Test
@@ -1878,20 +1878,21 @@ public class ShadeListBuilderTest extends SysuiTestCase {
        mListBuilder.setComparators(singletonList(comparator));
        mListBuilder.addOnBeforeRenderListListener(listener);

        interceptWtfs();

        // WHEN we try to run the pipeline and the comparator is invalidated exactly
        // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,

        // THEN an exception is NOT thrown directly, but a WTF IS logged.

        addNotif(0, PACKAGE_2);
        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);

        LogAssertKt.assertLogsWtfs(() -> {
            dispatchBuild();
            runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);

        // THEN an exception is NOT thrown directly, but a WTF IS logged.
        expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
        });
    }

    @Test(expected = IllegalStateException.class)
    @Test
    public void testOutOfOrderComparatorInvalidationThrowsAfterTooManyRuns() {
        // GIVEN a NotifComparator that gets invalidated during the finalizing stage,
        NotifComparator comparator = new HypeComparator(PACKAGE_1);
@@ -1900,16 +1901,20 @@ public class ShadeListBuilderTest extends SysuiTestCase {
        mListBuilder.setComparators(singletonList(comparator));
        mListBuilder.addOnBeforeRenderListListener(listener);

        interceptWtfs();

        // WHEN we try to run the pipeline and the comparator is invalidated more than
        // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,

        // THEN an exception IS thrown.

        addNotif(0, PACKAGE_2);
        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);

        LogAssertKt.assertLogsWtfs(() -> {
            Assert.assertThrows(IllegalStateException.class, () -> {
                dispatchBuild();
                runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);

        // THEN an exception IS thrown.
            });
        });
    }

    @Test
@@ -1921,20 +1926,21 @@ public class ShadeListBuilderTest extends SysuiTestCase {
        mListBuilder.addFinalizeFilter(filter);
        mListBuilder.addOnBeforeRenderListListener(listener);

        interceptWtfs();

        // WHEN we try to run the pipeline and the PreRenderFilter is invalidated exactly
        // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,

        // THEN an exception is NOT thrown directly, but a WTF IS logged.

        addNotif(0, PACKAGE_2);
        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);

        LogAssertKt.assertLogsWtfs(() -> {
            dispatchBuild();
            runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);

        // THEN an exception is NOT thrown directly, but a WTF IS logged.
        expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
        });
    }

    @Test(expected = IllegalStateException.class)
    @Test
    public void testOutOfOrderPreRenderFilterInvalidationThrowsAfterTooManyRuns() {
        // GIVEN a PreRenderNotifFilter that gets invalidated during the finalizing stage,
        NotifFilter filter = new PackageFilter(PACKAGE_1);
@@ -1943,57 +1949,20 @@ public class ShadeListBuilderTest extends SysuiTestCase {
        mListBuilder.addFinalizeFilter(filter);
        mListBuilder.addOnBeforeRenderListListener(listener);

        interceptWtfs();

        // WHEN we try to run the pipeline and the PreRenderFilter is invalidated more than
        // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
        addNotif(0, PACKAGE_2);
        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
        dispatchBuild();
        try {
            runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
        } finally {
            expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
        }

        // THEN an exception IS thrown.
    }

    private void interceptWtfs() {
        assertNull(mOldWtfHandler);

        mLastWtf = null;
        mWtfCount = 0;
        addNotif(0, PACKAGE_2);
        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);

        mOldWtfHandler = Log.setWtfHandler((tag, e, system) -> {
            Log.e("ShadeListBuilderTest", "Observed WTF: " + e);
            mLastWtf = e;
            mWtfCount++;
        LogAssertKt.assertLogsWtfs(() -> {
            Assert.assertThrows(IllegalStateException.class, () -> {
                dispatchBuild();
                runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
            });
        });
    }

    private void expectNoWtfs() {
        assertNull(expectWtfs(0));
    }

    private Log.TerribleFailure expectWtf() {
        return expectWtfs(1);
    }

    private Log.TerribleFailure expectWtfs(int expectedWtfCount) {
        assertNotNull(mOldWtfHandler);

        Log.setWtfHandler(mOldWtfHandler);
        mOldWtfHandler = null;

        Log.TerribleFailure wtf = mLastWtf;
        int wtfCount = mWtfCount;

        mLastWtf = null;
        mWtfCount = 0;

        assertEquals(expectedWtfCount, wtfCount);
        return wtf;
    }

    @Test
+11 −0
Original line number Diff line number Diff line
@@ -59,6 +59,17 @@ fun assertLogsWtf(
): TerribleFailureLog =
    assertLogsWtf(message = message, allowMultiple = allowMultiple) { loggingRunnable.run() }

fun assertLogsWtfs(
    message: String = "Expected Log.wtf to be called once or more",
    loggingBlock: () -> Unit,
): TerribleFailureLog = assertLogsWtf(message, allowMultiple = true, loggingBlock)

@JvmOverloads
fun assertLogsWtfs(
    message: String = "Expected Log.wtf to be called once or more",
    loggingRunnable: Runnable,
): TerribleFailureLog = assertLogsWtfs(message) { loggingRunnable.run() }

/** The data passed to [TerribleFailureHandler.onTerribleFailure] */
data class TerribleFailureLog(
    val tag: String,