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

Commit f31c001c authored by Fyodor Kupolov's avatar Fyodor Kupolov Committed by Android (Google) Code Review
Browse files

Merge "More tests for UserController"

parents d2a4944d 3b24e5b9
Loading
Loading
Loading
Loading
+148 −5
Original line number Diff line number Diff line
@@ -16,13 +16,18 @@

package com.android.server.am;

import android.app.IUserSwitchObserver;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.UserManagerInternal;
import android.test.AndroidTestCase;
@@ -35,16 +40,30 @@ import org.mockito.Mockito;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.android.server.am.ActivityManagerService.CONTINUE_USER_SWITCH_MSG;
import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_COMPLETE_MSG;
import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_MSG;
import static com.android.server.am.ActivityManagerService.SYSTEM_USER_CURRENT_MSG;
import static com.android.server.am.ActivityManagerService.SYSTEM_USER_START_MSG;
import static com.android.server.am.ActivityManagerService.USER_SWITCH_TIMEOUT_MSG;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;

public class UserControllerTest extends AndroidTestCase {
    private static final int TEST_USER_ID = 10;
    private static String TAG = UserControllerTest.class.getSimpleName();
    private UserController mUserController;
    private TestInjector mInjector;
@@ -54,7 +73,7 @@ public class UserControllerTest extends AndroidTestCase {
        super.setUp();
        mInjector = new TestInjector(getContext());
        mUserController = new UserController(mInjector);
        setUpUser(10, 0);
        setUpUser(TEST_USER_ID, 0);
    }

    @Override
@@ -65,13 +84,100 @@ public class UserControllerTest extends AndroidTestCase {
    }

    public void testStartUser() throws RemoteException {
        mUserController.startUser(10, true);

        mUserController.startUser(TEST_USER_ID, true);
        Mockito.verify(mInjector.getWindowManager()).startFreezingScreen(anyInt(), anyInt());
        Mockito.verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
        List<String> expectedActions = Arrays.asList(Intent.ACTION_USER_STARTED,
                Intent.ACTION_USER_SWITCHED, Intent.ACTION_USER_STARTING);
        assertEquals(expectedActions, getActions(mInjector.sentIntents));
        Set<Integer> expectedCodes = new HashSet<>(
                Arrays.asList(REPORT_USER_SWITCH_MSG, USER_SWITCH_TIMEOUT_MSG,
                        SYSTEM_USER_START_MSG, SYSTEM_USER_CURRENT_MSG));
        Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
        assertEquals("Unexpected message sent", expectedCodes, actualCodes);
        Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
        assertNotNull(reportMsg);
        UserState userState = (UserState) reportMsg.obj;
        assertNotNull(userState);
        assertEquals(TEST_USER_ID, userState.mHandle.getIdentifier());
        assertEquals("User must be in STATE_BOOTING", UserState.STATE_BOOTING, userState.state);
        assertEquals("Unexpected old user id", 0, reportMsg.arg1);
        assertEquals("Unexpected new user id", TEST_USER_ID, reportMsg.arg2);
    }

    public void testDispatchUserSwitch() throws RemoteException {
        // Prepare mock observer and register it
        IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
        when(observer.asBinder()).thenReturn(new Binder());
        doAnswer(invocation -> {
            IRemoteCallback callback = (IRemoteCallback) invocation.getArguments()[1];
            callback.sendResult(null);
            return null;
        }).when(observer).onUserSwitching(anyInt(), any());
        mUserController.registerUserSwitchObserver(observer, "mock");
        // Start user -- this will update state of mUserController
        mUserController.startUser(TEST_USER_ID, true);
        Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
        assertNotNull(reportMsg);
        UserState userState = (UserState) reportMsg.obj;
        int oldUserId = reportMsg.arg1;
        int newUserId = reportMsg.arg2;
        // Call dispatchUserSwitch and verify that observer was called only once
        mInjector.handler.clearAllRecordedMessages();
        mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
        Mockito.verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
        Set<Integer> expectedCodes = Collections.singleton(CONTINUE_USER_SWITCH_MSG);
        Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
        assertEquals("Unexpected message sent", expectedCodes, actualCodes);
        Message conMsg = mInjector.handler.getMessageForCode(CONTINUE_USER_SWITCH_MSG);
        assertNotNull(conMsg);
        userState = (UserState) conMsg.obj;
        assertNotNull(userState);
        assertEquals(TEST_USER_ID, userState.mHandle.getIdentifier());
        assertEquals("User must be in STATE_BOOTING", UserState.STATE_BOOTING, userState.state);
        assertEquals("Unexpected old user id", 0, conMsg.arg1);
        assertEquals("Unexpected new user id", TEST_USER_ID, conMsg.arg2);
    }

    public void testDispatchUserSwitchBadReceiver() throws RemoteException {
        // Prepare mock observer which doesn't notify the callback and register it
        IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
        when(observer.asBinder()).thenReturn(new Binder());
        mUserController.registerUserSwitchObserver(observer, "mock");
        // Start user -- this will update state of mUserController
        mUserController.startUser(TEST_USER_ID, true);
        Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
        assertNotNull(reportMsg);
        UserState userState = (UserState) reportMsg.obj;
        int oldUserId = reportMsg.arg1;
        int newUserId = reportMsg.arg2;
        // Call dispatchUserSwitch and verify that observer was called only once
        mInjector.handler.clearAllRecordedMessages();
        mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
        Mockito.verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
        // Verify that CONTINUE_USER_SWITCH_MSG is not sent (triggers timeout)
        Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
        assertTrue("No messages should be sent", actualCodes.isEmpty());
    }

    public void testContinueUserSwitch() throws RemoteException {
        // Start user -- this will update state of mUserController
        mUserController.startUser(TEST_USER_ID, true);
        Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
        assertNotNull(reportMsg);
        UserState userState = (UserState) reportMsg.obj;
        int oldUserId = reportMsg.arg1;
        int newUserId = reportMsg.arg2;
        mInjector.handler.clearAllRecordedMessages();
        // Verify that continueUserSwitch worked as expected
        mUserController.continueUserSwitch(userState, oldUserId, newUserId);
        Mockito.verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen();
        Set<Integer> expectedCodes = Collections.singleton(REPORT_USER_SWITCH_COMPLETE_MSG);
        Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
        assertEquals("Unexpected message sent", expectedCodes, actualCodes);
        Message msg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_COMPLETE_MSG);
        assertNotNull(msg);
        assertEquals("Unexpected userId", TEST_USER_ID, msg.arg1);
    }

    private void setUpUser(int userId, int flags) {
@@ -89,7 +195,7 @@ public class UserControllerTest extends AndroidTestCase {

    private static class TestInjector extends UserController.Injector {
        final Object lock = new Object();
        Handler handler;
        TestHandler handler;
        HandlerThread handlerThread;
        UserManagerService userManagerMock;
        UserManagerInternal userManagerInternalMock;
@@ -102,7 +208,7 @@ public class UserControllerTest extends AndroidTestCase {
            mCtx = ctx;
            handlerThread = new HandlerThread(TAG);
            handlerThread.start();
            handler = new Handler(handlerThread.getLooper());
            handler = new TestHandler(handlerThread.getLooper());
            userManagerMock = mock(UserManagerService.class);
            userManagerInternalMock = mock(UserManagerInternal.class);
            windowManagerMock = mock(WindowManagerService.class);
@@ -176,4 +282,41 @@ public class UserControllerTest extends AndroidTestCase {
            Log.i(TAG, "startHomeActivityLocked " + userId);
        }
   }

    private static class TestHandler extends Handler {
        private final List<Message> mMessages = new ArrayList<>();

        TestHandler(Looper looper) {
            super(looper);
        }

        Set<Integer> getMessageCodes() {
            Set<Integer> result = new LinkedHashSet<>();
            for (Message msg : mMessages) {
                result.add(msg.what);
            }
            return result;
        }

        Message getMessageForCode(int what) {
            for (Message msg : mMessages) {
                if (msg.what == what) {
                    return msg;
                }
            }
            return null;
        }

        void clearAllRecordedMessages() {
            mMessages.clear();
        }

        @Override
        public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
            Message copy = new Message();
            copy.copyFrom(msg);
            mMessages.add(copy);
            return super.sendMessageAtTime(msg, uptimeMillis);
        }
    }
}
 No newline at end of file