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

Commit b6fd86b4 authored by Sarah Chin's avatar Sarah Chin
Browse files

Remove Thread.sleep in Telephony unittests

Add helper methods to TelephonyTest for TestableLooper
Refactor CarrierServiceStateTrackerTest to fix merge conflicts.
Refactor PhoneSwitcherTest to revert previous CL.

Bug: 138886216
Test: atest TelephonyFrameworksTests

Change-Id: Ib3890f0b02695d056c6466573b8b731f76490683
Merged-In: Ib3890f0b02695d056c6466573b8b731f76490683
parent 87909342
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ android_test {
        "services.net",
        "telephony-common",
        "truth-prebuilt",
        "testables",
    ],

    platform_apis: true,
+18 −33
Original line number Diff line number Diff line
@@ -29,17 +29,19 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.os.HandlerThread;
import android.os.Message;
import android.os.PersistableBundle;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;

import java.util.Map;
@@ -47,32 +49,19 @@ import java.util.Map;
/**
 * Unit tests for {@link com.android.internal.telephony.CarrierServiceStateTracker}.
 */
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class CarrierServiceStateTrackerTest extends TelephonyTest {
    public static final String LOG_TAG = "CSST";
    public static final int TEST_TIMEOUT = 5000;

    private CarrierServiceStateTracker mSpyCarrierSST;
    private CarrierServiceStateTracker mCarrierSST;
    private CarrierServiceStateTrackerTestHandler mCarrierServiceStateTrackerTestHandler;

    private static final int SUB_ID = 1;

    NotificationManager mNotificationManager;
    PersistableBundle mBundle;

    private class CarrierServiceStateTrackerTestHandler extends HandlerThread {
        private CarrierServiceStateTrackerTestHandler(String name) {
            super(name);
        }

        @Override
        public void onLooperPrepared() {
            mCarrierSST = new CarrierServiceStateTracker(mPhone, mSST);
            mSpyCarrierSST = spy(mCarrierSST);
            setReady(true);
        }
    }

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
@@ -80,27 +69,23 @@ public class CarrierServiceStateTrackerTest extends TelephonyTest {
        super.setUp(getClass().getSimpleName());
        mBundle = mContextFixture.getCarrierConfigBundle();
        when(mPhone.getSubId()).thenReturn(SUB_ID);
        mCarrierServiceStateTrackerTestHandler =
                new CarrierServiceStateTrackerTestHandler(getClass().getSimpleName());
        mCarrierServiceStateTrackerTestHandler.start();
        mCarrierSST = new CarrierServiceStateTracker(mPhone, mSST);
        mSpyCarrierSST = spy(mCarrierSST);

        mNotificationManager = (NotificationManager) mContext.getSystemService(
                Context.NOTIFICATION_SERVICE);

        setDefaultValues();
        waitUntilReady();
        processAllMessages();
    }

    private void setDefaultValues() {
        mBundle.putInt(CarrierConfigManager.KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT,
                0);
        mBundle.putInt(CarrierConfigManager.KEY_EMERGENCY_NOTIFICATION_DELAY_INT,
                0);
        mBundle.putInt(CarrierConfigManager.KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT, 0);
        mBundle.putInt(CarrierConfigManager.KEY_EMERGENCY_NOTIFICATION_DELAY_INT, 0);
    }

    @After
    public void tearDown() throws Exception {
        mCarrierServiceStateTrackerTestHandler.quit();
        super.tearDown();
    }

@@ -113,7 +98,7 @@ public class CarrierServiceStateTrackerTest extends TelephonyTest {
        doReturn(false).when(mSpyCarrierSST).evaluateSendingMessage(any());
        doReturn(mNotificationManager).when(mSpyCarrierSST).getNotificationManager(any());
        mSpyCarrierSST.handleMessage(notificationMsg);
        waitForHandlerAction(mSpyCarrierSST, TEST_TIMEOUT);
        processAllMessages();
        verify(mNotificationManager).cancel(
                CarrierServiceStateTracker.EMERGENCY_NOTIFICATION_TAG, SUB_ID);
        verify(mNotificationManager).cancel(
@@ -134,7 +119,7 @@ public class CarrierServiceStateTrackerTest extends TelephonyTest {
        doReturn(mNotificationBuilder).when(mSpyCarrierSST).getNotificationBuilder(any());
        doReturn(mNotificationManager).when(mSpyCarrierSST).getNotificationManager(any());
        mSpyCarrierSST.handleMessage(notificationMsg);
        waitForHandlerAction(mSpyCarrierSST, TEST_TIMEOUT);
        processAllMessages();
        verify(mNotificationManager).notify(
                eq(CarrierServiceStateTracker.EMERGENCY_NOTIFICATION_TAG),
                eq(SUB_ID), isA(Notification.class));
@@ -149,7 +134,7 @@ public class CarrierServiceStateTrackerTest extends TelephonyTest {
        logd(LOG_TAG + ":testSendPrefNetworkNotification()");
        Intent intent = new Intent().setAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
        mContext.sendBroadcast(intent);
        waitForLastHandlerAction(mCarrierServiceStateTrackerTestHandler.getThreadHandler());
        processAllMessages();

        Map<Integer, CarrierServiceStateTracker.NotificationType> notificationTypeMap =
                mCarrierSST.getNotificationTypeMap();
@@ -170,7 +155,7 @@ public class CarrierServiceStateTrackerTest extends TelephonyTest {
                RILConstants.NETWORK_MODE_LTE_CDMA_EVDO);
        mSpyCarrierSST.getContentObserver().dispatchChange(false,
                Settings.Global.getUriFor(prefNetworkMode));
        waitForLastHandlerAction(mCarrierServiceStateTrackerTestHandler.getThreadHandler());
        processAllMessages();
        verify(mNotificationManager, atLeast(1)).notify(
                eq(CarrierServiceStateTracker.PREF_NETWORK_NOTIFICATION_TAG),
                eq(SUB_ID), isA(Notification.class));
@@ -180,7 +165,7 @@ public class CarrierServiceStateTrackerTest extends TelephonyTest {
                RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA);
        mSpyCarrierSST.getContentObserver().dispatchChange(false,
                Settings.Global.getUriFor(prefNetworkMode));
        waitForLastHandlerAction(mCarrierServiceStateTrackerTestHandler.getThreadHandler());
        processAllMessages();
        verify(mNotificationManager, atLeast(1)).cancel(
                CarrierServiceStateTracker.PREF_NETWORK_NOTIFICATION_TAG, SUB_ID);
    }
@@ -191,7 +176,7 @@ public class CarrierServiceStateTrackerTest extends TelephonyTest {
        logd(LOG_TAG + ":testSendEmergencyNetworkNotification()");
        Intent intent = new Intent().setAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
        mContext.sendBroadcast(intent);
        waitForLastHandlerAction(mCarrierServiceStateTrackerTestHandler.getThreadHandler());
        processAllMessages();

        Map<Integer, CarrierServiceStateTracker.NotificationType> notificationTypeMap =
                mCarrierSST.getNotificationTypeMap();
@@ -210,14 +195,14 @@ public class CarrierServiceStateTrackerTest extends TelephonyTest {
        Message notificationMsg = mSpyCarrierSST.obtainMessage(
                CarrierServiceStateTracker.CARRIER_EVENT_IMS_CAPABILITIES_CHANGED, null);
        mSpyCarrierSST.handleMessage(notificationMsg);
        waitForHandlerAction(mSpyCarrierSST, TEST_TIMEOUT);
        processAllMessages();
        verify(mNotificationManager).notify(
                eq(CarrierServiceStateTracker.EMERGENCY_NOTIFICATION_TAG),
                eq(SUB_ID), isA(Notification.class));

        doReturn(false).when(mPhone).isWifiCallingEnabled();
        mSpyCarrierSST.handleMessage(notificationMsg);
        waitForHandlerAction(mSpyCarrierSST, TEST_TIMEOUT);
        processAllMessages();
        verify(mNotificationManager, atLeast(2)).cancel(
                CarrierServiceStateTracker.EMERGENCY_NOTIFICATION_TAG, SUB_ID);
    }
+97 −182

File changed.

Preview size limit exceeded, changes collapsed.

+108 −2
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.IDeviceIdleController;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import android.os.RegistrantList;
import android.os.ServiceManager;
import android.provider.BlockedNumberContract;
@@ -60,6 +62,7 @@ import android.telephony.euicc.EuiccManager;
import android.telephony.ims.ImsCallProfile;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.testing.TestableLooper;
import android.util.Log;
import android.util.Singleton;

@@ -101,6 +104,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -116,6 +120,23 @@ public abstract class TelephonyTest {
            new ArrayList<String>(), EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING,
            EmergencyNumber.EMERGENCY_CALL_ROUTING_NORMAL);

    private static final Field MESSAGE_QUEUE_FIELD;
    private static final Field MESSAGE_WHEN_FIELD;
    private static final Field MESSAGE_NEXT_FIELD;

    static {
        try {
            MESSAGE_QUEUE_FIELD = MessageQueue.class.getDeclaredField("mMessages");
            MESSAGE_QUEUE_FIELD.setAccessible(true);
            MESSAGE_WHEN_FIELD = Message.class.getDeclaredField("when");
            MESSAGE_WHEN_FIELD.setAccessible(true);
            MESSAGE_NEXT_FIELD = Message.class.getDeclaredField("next");
            MESSAGE_NEXT_FIELD.setAccessible(true);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException("Failed to initialize TelephonyTest", e);
        }
    }

    @Mock
    protected GsmCdmaPhone mPhone;
    @Mock
@@ -261,7 +282,8 @@ public abstract class TelephonyTest {
    private boolean mReady;
    protected HashMap<String, IBinder> mServiceManagerMockedServices = new HashMap<>();
    protected Phone[] mPhones;

    protected List<TestableLooper> mTestableLoopers = new ArrayList<>();
    protected TestableLooper mTestableLooper;

    protected HashMap<Integer, ImsManager> mImsManagerInstances = new HashMap<>();
    private HashMap<InstanceKey, Object> mOldInstances = new HashMap<InstanceKey, Object>();
@@ -592,12 +614,24 @@ public abstract class TelephonyTest {
        assertNotNull("Failed to set up SubscriptionController singleton",
                SubscriptionController.getInstance());
        setReady(false);
        // create default TestableLooper for test and add to list of monitored loopers
        mTestableLooper = TestableLooper.get(TelephonyTest.this);
        if (mTestableLooper != null) {
            monitorTestableLooper(mTestableLooper);
        }
    }

    protected void tearDown() throws Exception {

        // unmonitor TestableLooper
        if (mTestableLooper != null) {
            unmonitorTestableLooper(mTestableLooper);
        }
        mSimulatedCommands.dispose();

        // destroy all created TestableLoopers so they can be reused
        for (TestableLooper looper : mTestableLoopers) {
            looper.destroy();
        }
        SharedPreferences sharedPreferences = mContext.getSharedPreferences((String) null, 0);
        sharedPreferences.edit().clear().commit();

@@ -701,6 +735,7 @@ public abstract class TelephonyTest {
                "mContentProvider", providerHolder, iContentProvider);
    }

    // TODO(b/138886216): remove method after refactor
    protected final void waitForHandlerAction(Handler h, long timeoutMillis) {
        final CountDownLatch lock = new CountDownLatch(1);
        h.post(lock::countDown);
@@ -739,6 +774,7 @@ public abstract class TelephonyTest {
        assertTrue("Handler was not empty before timeout elapsed", timeoutCount < 5);
    }

    // TODO(b/138886216): remove method after refactor
    protected final void waitForHandlerActionDelayed(Handler h, long timeoutMillis, long delayMs) {
        final CountDownLatch lock = new CountDownLatch(1);
        h.postDelayed(lock::countDown, delayMs);
@@ -766,4 +802,74 @@ public abstract class TelephonyTest {
        }
        return null;
    }

    /**
     * Add a TestableLooper to the list of monitored loopers
     * @param looper added if it doesn't already exist
     */
    public void monitorTestableLooper(TestableLooper looper) {
        if (!mTestableLoopers.contains(looper)) {
            mTestableLoopers.add(looper);
        }
    }

    /**
     * Remove a TestableLooper from the list of monitored loopers
     * @param looper removed if it does exist
     */
    public void unmonitorTestableLooper(TestableLooper looper) {
        if (mTestableLoopers.contains(looper)) {
            mTestableLoopers.remove(looper);
        }
    }

    /**
     * Handle all messages that can be processed at the current time
     * for all monitored TestableLoopers
     */
    public void processAllMessages() {
        if (mTestableLoopers.isEmpty()) {
            fail("mTestableLoopers is empty. Please make sure to add @RunWithLooper annotation");
        }
        while (!areAllTestableLoopersIdle()) {
            for (TestableLooper looper : mTestableLoopers) looper.processAllMessages();
        }
    }

    /**
     * Check if there are any messages to be processed in any monitored TestableLooper
     * Delayed messages to be handled at a later time will be ignored
     * @return true if there are no messages that can be handled at the current time
     *         across all monitored TestableLoopers
     */
    private boolean areAllTestableLoopersIdle() {
        for (TestableLooper looper : mTestableLoopers) {
            if (!looper.getLooper().getQueue().isIdle()) return false;
        }
        return true;
    }

    /**
     * Effectively moves time forward by reducing the time of all messages
     * for all monitored TestableLoopers
     * @param milliSeconds number of milliseconds to move time forward by
     */
    public void moveTimeForward(long milliSeconds) {
        for (TestableLooper looper : mTestableLoopers) {
            MessageQueue queue = looper.getLooper().getQueue();
            try {
                Message msg = (Message) MESSAGE_QUEUE_FIELD.get(queue);
                while (msg != null) {
                    long updatedWhen = msg.getWhen() - milliSeconds;
                    if (updatedWhen < 0) {
                        updatedWhen = 0;
                    }
                    MESSAGE_WHEN_FIELD.set(msg, updatedWhen);
                    msg = (Message) MESSAGE_NEXT_FIELD.get(msg);
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException("Access failed in TelephonyTest", e);
            }
        }
    }
}