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

Commit 3c49a206 authored by Jack He's avatar Jack He
Browse files

Test: Fix broken tests in RemoteDevicesTest

* Refactor RemoteDevices.java to apply dependency injection design
  pattern: User an explicity looper passed through the class constructor
  so that a user of the class can choose which thread it runs on
* By default, it runs on the main service thread in AdapterService.java
* During test, it runs on a HanlderThread created during the test
* A TestLooperManager is used to mannually intercept and execute
  messages on the handler to guarantee timing consistency

Bug: 67942165
Test: runtest -i -j40 bluetooth; adb shell am instrument -w -e timeout_msec 300000
     'com.android.bluetooth.tests/android.support.test.runner.AndroidJUnitRunne

Change-Id: Ieab21b428e74eb84766a7be835d1bf07471743bc
parent ab41fd13
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.ParcelUuid;
@@ -394,7 +395,7 @@ public class AdapterService extends Service {
    public void onCreate() {
        super.onCreate();
        debugLog("onCreate()");
        mRemoteDevices = new RemoteDevices(this);
        mRemoteDevices = new RemoteDevices(this, Looper.getMainLooper());
        mRemoteDevices.init();
        mBinder = new AdapterServiceBinder(this);
        mAdapterProperties = new AdapterProperties(this);
+27 −15
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelUuid;
import android.support.annotation.VisibleForTesting;
@@ -59,6 +60,30 @@ final class RemoteDevices {
    private final HashMap<String, DeviceProperties> mDevices;
    private Queue<String> mDeviceQueue;

    private final Handler mHandler;
    private class RemoteDevicesHandler extends Handler {

        /**
         * Handler must be created from an explicit looper to avoid threading ambiguity
         * @param looper The looper that this handler should be executed on
         */
        RemoteDevicesHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MESSAGE_UUID_INTENT:
                    BluetoothDevice device = (BluetoothDevice) msg.obj;
                    if (device != null) {
                        sendUuidIntent(device);
                    }
                    break;
            }
        }
    }

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
@@ -80,12 +105,13 @@ final class RemoteDevices {
        }
    };

    RemoteDevices(AdapterService service) {
    RemoteDevices(AdapterService service, Looper looper) {
        sAdapter = BluetoothAdapter.getDefaultAdapter();
        sAdapterService = service;
        sSdpTracker = new ArrayList<BluetoothDevice>();
        mDevices = new HashMap<String, DeviceProperties>();
        mDeviceQueue = new LinkedList<String>();
        mHandler = new RemoteDevicesHandler(looper);
    }

    /**
@@ -782,20 +808,6 @@ final class RemoteDevices {
        return batteryLevel * 100 / numberOfLevels;
    }

    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MESSAGE_UUID_INTENT:
                    BluetoothDevice device = (BluetoothDevice) msg.obj;
                    if (device != null) {
                        sendUuidIntent(device);
                    }
                    break;
            }
        }
    };

    private static void errorLog(String msg) {
        Log.e(TAG, msg);
    }
+23 −9
Original line number Diff line number Diff line
@@ -8,13 +8,17 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.os.Looper;
import android.os.HandlerThread;
import android.os.Message;
import android.os.TestLooperManager;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;

import com.android.bluetooth.Utils;
import com.android.bluetooth.hfp.HeadsetHalConstants;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -34,27 +38,37 @@ public class RemoteDevicesTest {
    private ArgumentCaptor<String> mStringArgument = ArgumentCaptor.forClass(String.class);
    private BluetoothDevice mDevice1;
    private RemoteDevices mRemoteDevices;
    private HandlerThread mHandlerThread;
    private TestLooperManager mTestLooperManager;

    @Mock private AdapterService mAdapterService;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        if (Looper.myLooper() == null) {
            Looper.prepare();
        }
        mDevice1 = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(TEST_BT_ADDR_1);
        mRemoteDevices = new RemoteDevices(mAdapterService);
        mHandlerThread = new HandlerThread("RemoteDevicesTestHandlerThread");
        mHandlerThread.start();
        mTestLooperManager = InstrumentationRegistry.getInstrumentation()
                .acquireLooperManager(mHandlerThread.getLooper());
        mRemoteDevices = new RemoteDevices(mAdapterService, mHandlerThread.getLooper());
    }

    @After
    public void tearDown() {
        mTestLooperManager.release();
        mHandlerThread.quit();
    }

    @Test
    public void testSendUuidIntent() {
        // Verify that a handler message is sent by the method call
        mRemoteDevices.updateUuids(mDevice1);
        if (Looper.myLooper() != null) {
            Looper.myLooper().quitSafely();
        }
        Looper.loop();
        Message msg = mTestLooperManager.next();
        Assert.assertNotNull(msg);

        // Verify that executing that message results in a broadcast intent
        mTestLooperManager.execute(msg);
        verify(mAdapterService).sendBroadcast(any(), anyString());
        verifyNoMoreInteractions(mAdapterService);
    }