blob: 3e74eb7392a961f89051148397b06e9858132591 [file] [log] [blame]
Brad Ebinger12ec7f22016-05-05 10:40:57 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android;
18
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070019import static org.junit.Assert.assertNotNull;
Brad Ebingera68a4972020-01-30 17:31:23 -080020import static org.mockito.Mockito.spy;
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070021import static org.mockito.Mockito.doCallRealMethod;
22import static org.mockito.Mockito.doReturn;
Brad Ebingera68a4972020-01-30 17:31:23 -080023
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070024import android.content.ContextWrapper;
25import android.content.res.Resources;
Brad Ebinger12ec7f22016-05-05 10:40:57 -070026import android.os.Handler;
Brad Ebinger32925b82016-12-02 13:01:49 -080027import android.os.Looper;
Sanket Padawed9a427e2017-06-08 12:03:07 -070028import android.util.Log;
Brad Ebinger12ec7f22016-05-05 10:40:57 -070029
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070030import androidx.test.InstrumentationRegistry;
31
32import com.android.internal.telephony.GsmCdmaPhone;
33import com.android.internal.telephony.Phone;
Brad Ebingera15005b2020-04-29 15:20:38 -070034import com.android.internal.telephony.PhoneConfigurationManager;
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070035import com.android.internal.telephony.PhoneFactory;
36import com.android.internal.telephony.data.DataConfigManager;
37import com.android.internal.telephony.data.DataNetworkController;
38import com.android.phone.PhoneGlobals;
39import com.android.phone.PhoneInterfaceManager;
Brad Ebingera15005b2020-04-29 15:20:38 -070040
Sarah Chine04784a2022-10-31 20:32:34 -070041import org.junit.After;
42import org.junit.Before;
tom hsu0b59d292022-09-29 23:49:21 +080043import org.junit.Rule;
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070044import org.mockito.Mock;
45import org.mockito.Mockito;
tom hsu0b59d292022-09-29 23:49:21 +080046import org.mockito.junit.MockitoJUnit;
47import org.mockito.junit.MockitoRule;
Brad Ebinger12ec7f22016-05-05 10:40:57 -070048
Sarah Chine04784a2022-10-31 20:32:34 -070049import java.lang.reflect.Field;
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070050import java.util.Collections;
Sarah Chine04784a2022-10-31 20:32:34 -070051import java.util.HashMap;
52import java.util.Iterator;
53import java.util.LinkedList;
Brad Ebinger12ec7f22016-05-05 10:40:57 -070054import java.util.concurrent.CountDownLatch;
Brad Ebinger63b6f5a2020-10-27 11:43:35 -070055import java.util.concurrent.Executor;
Brad Ebinger12ec7f22016-05-05 10:40:57 -070056import java.util.concurrent.TimeUnit;
57
58/**
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070059 * Helper class to load Mockito Resources into Telephony unit tests.
Brad Ebinger12ec7f22016-05-05 10:40:57 -070060 */
61public class TelephonyTestBase {
tom hsu0b59d292022-09-29 23:49:21 +080062 @Rule public final MockitoRule mocks = MockitoJUnit.rule();
Brad Ebinger12ec7f22016-05-05 10:40:57 -070063
Brad Ebinger792729e2019-12-09 16:12:57 -080064 protected TestContext mContext;
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070065 @Mock protected PhoneGlobals mPhoneGlobals;
66 @Mock protected GsmCdmaPhone mPhone;
67 @Mock protected DataNetworkController mDataNetworkController;
Brad Ebinger12ec7f22016-05-05 10:40:57 -070068
Sarah Chine04784a2022-10-31 20:32:34 -070069 private final HashMap<InstanceKey, Object> mOldInstances = new HashMap<>();
70 private final LinkedList<InstanceKey> mInstanceKeys = new LinkedList<>();
71
72 @Before
Brad Ebinger12ec7f22016-05-05 10:40:57 -070073 public void setUp() throws Exception {
Brad Ebinger32925b82016-12-02 13:01:49 -080074 if (Looper.myLooper() == null) {
75 Looper.prepare();
76 }
Tomasz Wasilczyk1c8068b2024-10-29 15:10:04 -070077
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070078 doCallRealMethod().when(mPhoneGlobals).getBaseContext();
79 doCallRealMethod().when(mPhoneGlobals).getResources();
80 doCallRealMethod().when(mPhone).getServiceState();
81
Tomasz Wasilczyk1c8068b2024-10-29 15:10:04 -070082 mContext = spy(new TestContext());
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070083 doReturn(mContext).when(mPhone).getContext();
84 replaceInstance(ContextWrapper.class, "mBase", mPhoneGlobals, mContext);
85
86 Resources resources = InstrumentationRegistry.getTargetContext().getResources();
87 assertNotNull(resources);
88 doReturn(resources).when(mContext).getResources();
89
90 replaceInstance(Handler.class, "mLooper", mPhone, Looper.myLooper());
91 replaceInstance(PhoneFactory.class, "sMadeDefaults", null, true);
92 replaceInstance(PhoneFactory.class, "sPhone", null, mPhone);
93 replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
94 replaceInstance(PhoneGlobals.class, "sMe", null, mPhoneGlobals);
95
96 doReturn(mDataNetworkController).when(mPhone).getDataNetworkController();
97 doReturn(Collections.emptyList()).when(mDataNetworkController)
98 .getInternetDataDisallowedReasons();
99 doReturn(Mockito.mock(DataConfigManager.class)).when(mDataNetworkController)
100 .getDataConfigManager();
101
102 mPhoneGlobals.phoneMgr = Mockito.mock(PhoneInterfaceManager.class);
Brad Ebinger12ec7f22016-05-05 10:40:57 -0700103 }
104
Sarah Chine04784a2022-10-31 20:32:34 -0700105 @After
Brad Ebinger12ec7f22016-05-05 10:40:57 -0700106 public void tearDown() throws Exception {
Brad Ebingera15005b2020-04-29 15:20:38 -0700107 // Ensure there are no static references to handlers after test completes.
108 PhoneConfigurationManager.unregisterAllMultiSimConfigChangeRegistrants();
Sarah Chine04784a2022-10-31 20:32:34 -0700109 restoreInstances();
Brad Ebinger12ec7f22016-05-05 10:40:57 -0700110 }
111
Brad Ebinger63b6f5a2020-10-27 11:43:35 -0700112 protected final boolean waitForExecutorAction(Executor executor, long timeoutMillis) {
113 final CountDownLatch lock = new CountDownLatch(1);
Brad Ebinger63b6f5a2020-10-27 11:43:35 -0700114 executor.execute(() -> {
Brad Ebinger63b6f5a2020-10-27 11:43:35 -0700115 lock.countDown();
116 });
117 while (lock.getCount() > 0) {
118 try {
119 return lock.await(timeoutMillis, TimeUnit.MILLISECONDS);
120 } catch (InterruptedException e) {
121 // do nothing
122 }
123 }
124 return true;
125 }
126
Brad Ebinger12ec7f22016-05-05 10:40:57 -0700127 protected final void waitForHandlerAction(Handler h, long timeoutMillis) {
128 final CountDownLatch lock = new CountDownLatch(1);
129 h.post(lock::countDown);
130 while (lock.getCount() > 0) {
131 try {
132 lock.await(timeoutMillis, TimeUnit.MILLISECONDS);
133 } catch (InterruptedException e) {
134 // do nothing
135 }
136 }
137 }
138
139 protected final void waitForHandlerActionDelayed(Handler h, long timeoutMillis, long delayMs) {
140 final CountDownLatch lock = new CountDownLatch(1);
141 h.postDelayed(lock::countDown, delayMs);
142 while (lock.getCount() > 0) {
143 try {
144 lock.await(timeoutMillis, TimeUnit.MILLISECONDS);
145 } catch (InterruptedException e) {
146 // do nothing
147 }
148 }
149 }
Sanket Padawed9a427e2017-06-08 12:03:07 -0700150
151 protected void waitForMs(long ms) {
152 try {
153 Thread.sleep(ms);
154 } catch (InterruptedException e) {
155 Log.e("TelephonyTestBase", "InterruptedException while waiting: " + e);
156 }
157 }
Brad Ebinger792729e2019-12-09 16:12:57 -0800158
Sarah Chine04784a2022-10-31 20:32:34 -0700159 protected synchronized void replaceInstance(final Class c, final String instanceName,
160 final Object obj, final Object newValue)
161 throws Exception {
162 Field field = c.getDeclaredField(instanceName);
163 field.setAccessible(true);
164
165 InstanceKey key = new InstanceKey(c, instanceName, obj);
166 if (!mOldInstances.containsKey(key)) {
167 mOldInstances.put(key, field.get(obj));
168 mInstanceKeys.add(key);
169 }
170 field.set(obj, newValue);
171 }
172
173 private synchronized void restoreInstances() throws Exception {
174 Iterator<InstanceKey> it = mInstanceKeys.descendingIterator();
175
176 while (it.hasNext()) {
177 InstanceKey key = it.next();
178 Field field = key.mClass.getDeclaredField(key.mInstName);
179 field.setAccessible(true);
180 field.set(key.mObj, mOldInstances.get(key));
181 }
182
183 mInstanceKeys.clear();
184 mOldInstances.clear();
185 }
186
187 private static class InstanceKey {
188 public final Class mClass;
189 public final String mInstName;
190 public final Object mObj;
191 InstanceKey(final Class c, final String instName, final Object obj) {
192 mClass = c;
193 mInstName = instName;
194 mObj = obj;
195 }
196
197 @Override
198 public int hashCode() {
199 return (mClass.getName().hashCode() * 31 + mInstName.hashCode()) * 31;
200 }
201
202 @Override
203 public boolean equals(Object obj) {
204 if (obj == null || obj.getClass() != getClass()) {
205 return false;
206 }
207
208 InstanceKey other = (InstanceKey) obj;
209 return (other.mClass == mClass && other.mInstName.equals(mInstName)
210 && other.mObj == mObj);
211 }
212 }
213
Brad Ebinger792729e2019-12-09 16:12:57 -0800214 protected TestContext getTestContext() {
215 return mContext;
216 }
Brad Ebinger12ec7f22016-05-05 10:40:57 -0700217}