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

Commit 5817192b authored by Shai Barack's avatar Shai Barack
Browse files

Relax test assertion in intrinsically racy concurrency test

Bug: 402537016
Flag: EXEMPT test-only
Change-Id: I54eebd7d66eb23c7412db201f6a5ff1c2c46d312
parent a9fcfe02
Loading
Loading
Loading
Loading
+43 −29
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ import android.platform.test.annotations.Presubmit;

import androidx.test.runner.AndroidJUnit4;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.CountDownLatch;
@@ -43,7 +45,7 @@ public class RateLimitingCacheTest {

    @Before
    public void before() {
        mCounter = -1;
        mCounter = 0;
    }

    private final RateLimitingCache.ValueFetcher<Integer> mFetcher = () -> {
@@ -59,12 +61,12 @@ public class RateLimitingCacheTest {
        TestRateLimitingCache<Integer> s = new TestRateLimitingCache<>(0);

        int first = s.get(mFetcher);
        assertEquals(0, first);
        assertEquals(1, first);
        int second = s.get(mFetcher);
        assertEquals(1, second);
        assertEquals(2, second);
        s.advanceTime(20);
        int third = s.get(mFetcher);
        assertEquals(2, third);
        assertEquals(3, third);
    }

    /**
@@ -76,17 +78,17 @@ public class RateLimitingCacheTest {
        TestRateLimitingCache<Integer> s = new TestRateLimitingCache<>(100);

        int first = s.get(mFetcher);
        assertEquals(0, first);
        assertEquals(1, first);
        int second = s.get(mFetcher);
        // Too early to change
        assertEquals(0, second);
        assertEquals(1, second);
        s.advanceTime(150);
        int third = s.get(mFetcher);
        // Changed by now
        assertEquals(1, third);
        assertEquals(2, third);
        int fourth = s.get(mFetcher);
        // Too early to change again
        assertEquals(1, fourth);
        assertEquals(2, fourth);
    }

    /**
@@ -98,11 +100,11 @@ public class RateLimitingCacheTest {
        TestRateLimitingCache<Integer> s = new TestRateLimitingCache<>(-1);

        int first = s.get(mFetcher);
        assertEquals(0, first);
        assertEquals(1, first);
        s.advanceTime(200);
        // Should return the original value every time
        int second = s.get(mFetcher);
        assertEquals(0, second);
        assertEquals(1, second);
    }

    /**
@@ -132,32 +134,44 @@ public class RateLimitingCacheTest {
     */
    @Test
    public void testMultipleThreads() throws InterruptedException {
        final long periodMillis = 1000;
        // Definitely won't have more than one period elapsed during the test.
        final long periodMillis = 1_000 * 60 * 10;  // 10 minutes
        final int maxCountPerPeriod = 10;
        final RateLimitingCache<Integer> s =
                new RateLimitingCache<>(periodMillis, maxCountPerPeriod);

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
        final int maxIncrementsPerWorker = 1_000;
        Runnable work = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < maxIncrementsPerWorker; i++) {
                    s.get(mFetcher);
                }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                s.get(mFetcher);
            }
        });
        };

        final long startTimeMillis = SystemClock.elapsedRealtime();
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        final long endTimeMillis = SystemClock.elapsedRealtime();
        final int numWorkers = 5;
        List<Thread> workers = new ArrayList<>(numWorkers);
        for (int i = 0; i < numWorkers; i++) {
            workers.add(new Thread(work));
        }
        for (Thread worker : workers) {
            worker.start();
        }
        for (Thread worker : workers) {
            worker.join();
        }

        final long periodsElapsed = 1 + ((endTimeMillis - startTimeMillis) / periodMillis);
        final long expected = Math.min(100 + 100, periodsElapsed * maxCountPerPeriod) - 1;
        assertEquals(expected, mCounter);
        final long expectedAtMost =
                Math.min(
                        // No more than the max increments that each worker can do
                        // times the number of workers
                        maxIncrementsPerWorker * numWorkers,
                        // Workers may race and get at most one more increment each
                        maxCountPerPeriod + numWorkers);
        assertTrue(
                "mCounter should be <=" + expectedAtMost + " but was " + mCounter,
                mCounter <= expectedAtMost);
    }

    /**