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

Commit 2a94ac55 authored by Hugo Benichi's avatar Hugo Benichi
Browse files

Fix flaky NsdManagerTest

Bad synchronization between the mock handler and the test assertions
were causing testDiscoverService() to sometime fails (1/50 ~ 1/100 repro
rate).

Bug: 32561414
Bug: 62918393
Test: runtest frameworks-net, NsdManager#testDiscoverService now passes
      1000 times without errors.
Change-Id: I0308cdf48fc6bdc2fc9b4e8f7d5241a1cf2ea443
parent c894b123
Loading
Loading
Loading
Loading
+26 −13
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ public class NsdManagerTest {

    NsdManager mManager;

    long mTimeoutMs = 100; // non-final so that tests can adjust the value.
    long mTimeoutMs = 200; // non-final so that tests can adjust the value.

    @Before
    public void setUp() throws Exception {
@@ -74,7 +74,7 @@ public class NsdManagerTest {

    @After
    public void tearDown() throws Exception {
        waitForIdleHandler(mServiceHandler, mTimeoutMs);
        mServiceHandler.waitForIdle(mTimeoutMs);
        mServiceHandler.chan.disconnect();
        mServiceHandler.stop();
        if (mManager != null) {
@@ -334,9 +334,10 @@ public class NsdManagerTest {
    }

    int verifyRequest(int expectedMessageType) {
        mServiceHandler.waitForIdle(mTimeoutMs);
        verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any());
        reset(mServiceHandler);
        Message received = mServiceHandler.lastMessage;
        Message received = mServiceHandler.getLastMessage();
        assertEquals(NsdManager.nameOf(expectedMessageType), NsdManager.nameOf(received.what));
        return received.arg2;
    }
@@ -347,31 +348,43 @@ public class NsdManagerTest {

    // Implements the server side of AsyncChannel connection protocol
    public static class MockServiceHandler extends Handler {
        public Context mContext;
        public final Context context;
        public AsyncChannel chan;
        public volatile Message lastMessage;
        public Message lastMessage;

        MockServiceHandler(Looper looper, Context context) {
            super(looper);
            mContext = context;
        MockServiceHandler(Looper l, Context c) {
            super(l);
            context = c;
        }

        @Override
        public void handleMessage(Message msg) {
        synchronized Message getLastMessage() {
            return lastMessage;
        }

        synchronized void setLastMessage(Message msg) {
            lastMessage = obtainMessage();
            lastMessage.copyFrom(msg);
        }

        void waitForIdle(long timeoutMs) {
            waitForIdleHandler(this, timeoutMs);
        }

        @Override
        public void handleMessage(Message msg) {
            setLastMessage(msg);
            if (msg.what == AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) {
                chan = new AsyncChannel();
                chan.connect(mContext, this, msg.replyTo);
                chan.connect(context, this, msg.replyTo);
                chan.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
            }
        }

        public void stop() {
        void stop() {
            getLooper().quitSafely();
        }

        public static MockServiceHandler create(Context context) {
        static MockServiceHandler create(Context context) {
            HandlerThread t = new HandlerThread("mock-service-handler");
            t.start();
            return new MockServiceHandler(t.getLooper(), context);
+1 −2
Original line number Diff line number Diff line
@@ -30,8 +30,7 @@ public final class TestUtils {
     * Block until the given Handler thread becomes idle, or until timeoutMs has passed.
     */
    public static void waitForIdleHandler(HandlerThread handlerThread, long timeoutMs) {
        // TODO: convert to getThreadHandler once it is available on aosp
        waitForIdleLooper(handlerThread.getLooper(), timeoutMs);
        waitForIdleHandler(handlerThread.getThreadHandler(), timeoutMs);
    }

    /**