blob: f340e94eb2b70572c4162880a8c6a36a71e1895f [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.services.telephony.domainselection;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.telephony.BarringInfo;
import android.telephony.DomainSelectionService;
import android.telephony.DomainSelectionService.SelectionAttributes;
import android.telephony.DomainSelectionService.SelectorType;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TransportSelectorCallback;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.TestableLooper;
import androidx.test.runner.AndroidJUnit4;
import com.android.TestContext;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
/**
* Unit tests for TelephonyDomainSelectionService.
*/
@RunWith(AndroidJUnit4.class)
public class TelephonyDomainSelectionServiceTest {
private TelephonyDomainSelectionService.ImsStateTrackerFactory mImsStateTrackerFactory =
new TelephonyDomainSelectionService.ImsStateTrackerFactory() {
@Override
public ImsStateTracker create(Context context, int slotId,
@NonNull Looper looper) {
return mImsStateTracker;
}
};
private TelephonyDomainSelectionService.DomainSelectorFactory mDomainSelectorFactory =
new TelephonyDomainSelectionService.DomainSelectorFactory() {
@Override
public DomainSelectorBase create(Context context, int slotId, int subId,
@SelectorType int selectorType, boolean isEmergency,
@NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker,
@NonNull DomainSelectorBase.DestroyListener listener,
@NonNull CrossSimRedialingController crossSimRedialingController) {
switch (selectorType) {
case DomainSelectionService.SELECTOR_TYPE_CALLING: // fallthrough
case DomainSelectionService.SELECTOR_TYPE_SMS: // fallthrough
case DomainSelectionService.SELECTOR_TYPE_UT:
mDomainSelectorDestroyListener = listener;
if (subId == SUB_1) {
return mDomainSelectorBase1;
} else {
return mDomainSelectorBase2;
}
default:
return null;
}
}
};
private static final int SLOT_0 = 0;
private static final int SUB_1 = 1;
private static final int SUB_2 = 2;
private static final String CALL_ID = "Call_1";
private static final @SelectorType int TEST_SELECTOR_TYPE =
DomainSelectionService.SELECTOR_TYPE_CALLING;
private static final @SelectorType int INVALID_SELECTOR_TYPE = -1;
@Mock private DomainSelectorBase mDomainSelectorBase1;
@Mock private DomainSelectorBase mDomainSelectorBase2;
@Mock private TransportSelectorCallback mSelectorCallback1;
@Mock private TransportSelectorCallback mSelectorCallback2;
@Mock private ImsStateTracker mImsStateTracker;
private final ServiceState mServiceState = new ServiceState();
private final BarringInfo mBarringInfo = new BarringInfo();
private Context mContext;
private Handler mServiceHandler;
private TestableLooper mTestableLooper;
private SubscriptionManager mSubscriptionManager;
private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener;
private DomainSelectorBase.DestroyListener mDomainSelectorDestroyListener;
private TelephonyDomainSelectionService mDomainSelectionService;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
if (Looper.myLooper() == null) {
Looper.prepare();
}
mContext = new TestContext();
mDomainSelectionService = new TelephonyDomainSelectionService(mContext,
mImsStateTrackerFactory, mDomainSelectorFactory);
mServiceHandler = new Handler(mDomainSelectionService.getLooper());
mTestableLooper = new TestableLooper(mDomainSelectionService.getLooper());
mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
ArgumentCaptor<OnSubscriptionsChangedListener> listenerCaptor =
ArgumentCaptor.forClass(OnSubscriptionsChangedListener.class);
verify(mSubscriptionManager).addOnSubscriptionsChangedListener(
any(Executor.class), listenerCaptor.capture());
mOnSubscriptionsChangedListener = listenerCaptor.getValue();
}
@After
public void tearDown() throws Exception {
if (mTestableLooper != null) {
mTestableLooper.destroy();
mTestableLooper = null;
}
mServiceHandler = null;
if (mDomainSelectionService != null) {
mDomainSelectionService.onDestroy();
mDomainSelectionService = null;
}
mDomainSelectorBase1 = null;
mDomainSelectorBase2 = null;
mSelectorCallback1 = null;
mSelectorCallback2 = null;
mImsStateTracker = null;
mSubscriptionManager = null;
mOnSubscriptionsChangedListener = null;
mDomainSelectorDestroyListener = null;
}
@Test
@SmallTest
public void testGetExecutor() {
assertNotNull(mDomainSelectionService.getExecutor());
}
@Test
@SmallTest
public void testOnDomainSelection() {
SelectionAttributes attr1 = new SelectionAttributes.Builder(
SLOT_0, SUB_1, TEST_SELECTOR_TYPE)
.setCallId(CALL_ID)
.setEmergency(true)
.build();
mServiceHandler.post(() -> {
mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
});
processAllMessages();
verify(mImsStateTracker).start(eq(SUB_1));
verify(mSelectorCallback1).onCreated(eq(mDomainSelectorBase1));
verifyNoMoreInteractions(mSelectorCallback1);
verify(mDomainSelectorBase1).selectDomain(eq(attr1), eq(mSelectorCallback1));
}
@Test
@SmallTest
public void testOnDomainSelectionWithInvalidSelectorType() {
SelectionAttributes attr1 = new SelectionAttributes.Builder(
SLOT_0, SUB_1, INVALID_SELECTOR_TYPE)
.setCallId(CALL_ID)
.setEmergency(true)
.build();
mServiceHandler.post(() -> {
mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
});
processAllMessages();
verify(mImsStateTracker, never()).start(anyInt());
verify(mSelectorCallback1).onSelectionTerminated(anyInt());
verifyNoMoreInteractions(mSelectorCallback1);
verify(mDomainSelectorBase1, never()).selectDomain(eq(attr1), eq(mSelectorCallback1));
}
@Test
@SmallTest
public void testOnDomainSelectionTwiceWithDestroy() {
SelectionAttributes attr1 = new SelectionAttributes.Builder(
SLOT_0, SUB_1, TEST_SELECTOR_TYPE)
.setCallId(CALL_ID)
.setEmergency(true)
.build();
mServiceHandler.post(() -> {
mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
});
processAllMessages();
verify(mImsStateTracker).start(eq(SUB_1));
verify(mSelectorCallback1).onCreated(eq(mDomainSelectorBase1));
verifyNoMoreInteractions(mSelectorCallback1);
verify(mDomainSelectorBase1).selectDomain(eq(attr1), eq(mSelectorCallback1));
// Notify the domain selection service that this domain selector is destroyed.
mDomainSelectorDestroyListener.onDomainSelectorDestroyed(mDomainSelectorBase1);
SelectionAttributes attr2 = new SelectionAttributes.Builder(
SLOT_0, SUB_2, TEST_SELECTOR_TYPE)
.setCallId(CALL_ID)
.setEmergency(true)
.build();
mServiceHandler.post(() -> {
mDomainSelectionService.onDomainSelection(attr2, mSelectorCallback2);
});
processAllMessages();
verify(mImsStateTracker).start(eq(SUB_2));
verify(mSelectorCallback2).onCreated(eq(mDomainSelectorBase2));
verifyNoMoreInteractions(mSelectorCallback2);
verify(mDomainSelectorBase2).selectDomain(eq(attr2), eq(mSelectorCallback2));
}
@Test
@SmallTest
public void testOnDomainSelectionTwiceWithoutDestroy() {
SelectionAttributes attr1 = new SelectionAttributes.Builder(
SLOT_0, SUB_1, TEST_SELECTOR_TYPE)
.setCallId(CALL_ID)
.setEmergency(true)
.build();
mServiceHandler.post(() -> {
mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
});
processAllMessages();
verify(mImsStateTracker).start(eq(SUB_1));
verify(mSelectorCallback1).onCreated(eq(mDomainSelectorBase1));
verifyNoMoreInteractions(mSelectorCallback1);
verify(mDomainSelectorBase1).selectDomain(eq(attr1), eq(mSelectorCallback1));
SelectionAttributes attr2 = new SelectionAttributes.Builder(
SLOT_0, SUB_2, TEST_SELECTOR_TYPE)
.setCallId(CALL_ID)
.setEmergency(true)
.build();
mServiceHandler.post(() -> {
mDomainSelectionService.onDomainSelection(attr2, mSelectorCallback2);
});
processAllMessages();
verify(mImsStateTracker).start(eq(SUB_2));
verify(mSelectorCallback2).onCreated(eq(mDomainSelectorBase2));
verifyNoMoreInteractions(mSelectorCallback2);
verify(mDomainSelectorBase2).selectDomain(eq(attr2), eq(mSelectorCallback2));
}
@Test
@SmallTest
public void testOnServiceStateUpdated() {
mDomainSelectionService.onServiceStateUpdated(SLOT_0, SUB_1, mServiceState);
verify(mImsStateTracker).updateServiceState(eq(mServiceState));
}
@Test
@SmallTest
public void testOnBarringInfoUpdated() {
mDomainSelectionService.onBarringInfoUpdated(SLOT_0, SUB_1, mBarringInfo);
verify(mImsStateTracker).updateBarringInfo(eq(mBarringInfo));
}
@Test
@SmallTest
public void testOnDestroy() {
SelectionAttributes attr1 = new SelectionAttributes.Builder(
SLOT_0, SUB_1, TEST_SELECTOR_TYPE)
.setCallId(CALL_ID)
.setEmergency(true)
.build();
mServiceHandler.post(() -> {
mDomainSelectionService.onDomainSelection(attr1, mSelectorCallback1);
});
processAllMessages();
mDomainSelectionService.onDestroy();
verify(mImsStateTracker).destroy();
verify(mDomainSelectorBase1).destroy();
verify(mSubscriptionManager).removeOnSubscriptionsChangedListener(any());
}
@Test
@SmallTest
public void testHandleSubscriptionsChangedWithEmptySubscriptionInfo() {
when(mSubscriptionManager.getActiveSubscriptionInfoList())
.thenReturn(null, new ArrayList<SubscriptionInfo>());
mOnSubscriptionsChangedListener.onSubscriptionsChanged();
mOnSubscriptionsChangedListener.onSubscriptionsChanged();
verify(mImsStateTracker, never()).start(anyInt());
}
@Test
@SmallTest
public void testHandleSubscriptionsChangedWithActiveSubscriptionInfoAndInvalidSlotIndex() {
SubscriptionInfo subsInfo = Mockito.mock(SubscriptionInfo.class);
List<SubscriptionInfo> subsInfoList = new ArrayList<>();
subsInfoList.add(subsInfo);
when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(subsInfoList);
when(subsInfo.getSimSlotIndex()).thenReturn(SubscriptionManager.INVALID_SIM_SLOT_INDEX);
mOnSubscriptionsChangedListener.onSubscriptionsChanged();
verify(mImsStateTracker, never()).start(anyInt());
}
@Test
@SmallTest
public void testHandleSubscriptionsChangedWithActiveSubscriptionInfo() {
SubscriptionInfo subsInfo = Mockito.mock(SubscriptionInfo.class);
List<SubscriptionInfo> subsInfoList = new ArrayList<>();
subsInfoList.add(subsInfo);
when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(subsInfoList);
when(subsInfo.getSubscriptionId())
.thenReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID, SUB_1);
when(subsInfo.getSimSlotIndex()).thenReturn(SLOT_0);
mOnSubscriptionsChangedListener.onSubscriptionsChanged();
mOnSubscriptionsChangedListener.onSubscriptionsChanged();
verify(mImsStateTracker).start(eq(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
verify(mImsStateTracker).start(eq(SUB_1));
}
private void processAllMessages() {
while (!mTestableLooper.getLooper().getQueue().isIdle()) {
mTestableLooper.processAllMessages();
}
}
}