blob: 94e91d33148df7c3dfd63a006f8081ef34e5a904 [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;
Tomasz Wasilczykf7b28c52024-11-11 15:55:27 -080038import com.android.internal.telephony.metrics.MetricsCollector;
39import com.android.internal.telephony.metrics.PersistAtomsStorage;
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070040import com.android.phone.PhoneGlobals;
41import com.android.phone.PhoneInterfaceManager;
Brad Ebingera15005b2020-04-29 15:20:38 -070042
Sarah Chine04784a2022-10-31 20:32:34 -070043import org.junit.After;
44import org.junit.Before;
tom hsu0b59d292022-09-29 23:49:21 +080045import org.junit.Rule;
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070046import org.mockito.Mock;
47import org.mockito.Mockito;
tom hsu0b59d292022-09-29 23:49:21 +080048import org.mockito.junit.MockitoJUnit;
49import org.mockito.junit.MockitoRule;
Brad Ebinger12ec7f22016-05-05 10:40:57 -070050
Sarah Chine04784a2022-10-31 20:32:34 -070051import java.lang.reflect.Field;
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070052import java.util.Collections;
Sarah Chine04784a2022-10-31 20:32:34 -070053import java.util.HashMap;
54import java.util.Iterator;
55import java.util.LinkedList;
Brad Ebinger12ec7f22016-05-05 10:40:57 -070056import java.util.concurrent.CountDownLatch;
Brad Ebinger63b6f5a2020-10-27 11:43:35 -070057import java.util.concurrent.Executor;
Brad Ebinger12ec7f22016-05-05 10:40:57 -070058import java.util.concurrent.TimeUnit;
59
60/**
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070061 * Helper class to load Mockito Resources into Telephony unit tests.
Brad Ebinger12ec7f22016-05-05 10:40:57 -070062 */
63public class TelephonyTestBase {
tom hsu0b59d292022-09-29 23:49:21 +080064 @Rule public final MockitoRule mocks = MockitoJUnit.rule();
Brad Ebinger12ec7f22016-05-05 10:40:57 -070065
Brad Ebinger792729e2019-12-09 16:12:57 -080066 protected TestContext mContext;
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070067 @Mock protected PhoneGlobals mPhoneGlobals;
68 @Mock protected GsmCdmaPhone mPhone;
69 @Mock protected DataNetworkController mDataNetworkController;
Tomasz Wasilczykf7b28c52024-11-11 15:55:27 -080070 @Mock private MetricsCollector mMetricsCollector;
Brad Ebinger12ec7f22016-05-05 10:40:57 -070071
Sarah Chine04784a2022-10-31 20:32:34 -070072 private final HashMap<InstanceKey, Object> mOldInstances = new HashMap<>();
73 private final LinkedList<InstanceKey> mInstanceKeys = new LinkedList<>();
74
75 @Before
Brad Ebinger12ec7f22016-05-05 10:40:57 -070076 public void setUp() throws Exception {
Brad Ebinger32925b82016-12-02 13:01:49 -080077 if (Looper.myLooper() == null) {
78 Looper.prepare();
79 }
Tomasz Wasilczyk1c8068b2024-10-29 15:10:04 -070080
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070081 doCallRealMethod().when(mPhoneGlobals).getBaseContext();
82 doCallRealMethod().when(mPhoneGlobals).getResources();
83 doCallRealMethod().when(mPhone).getServiceState();
84
Tomasz Wasilczyk1c8068b2024-10-29 15:10:04 -070085 mContext = spy(new TestContext());
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -070086 doReturn(mContext).when(mPhone).getContext();
87 replaceInstance(ContextWrapper.class, "mBase", mPhoneGlobals, mContext);
88
89 Resources resources = InstrumentationRegistry.getTargetContext().getResources();
90 assertNotNull(resources);
91 doReturn(resources).when(mContext).getResources();
92
93 replaceInstance(Handler.class, "mLooper", mPhone, Looper.myLooper());
94 replaceInstance(PhoneFactory.class, "sMadeDefaults", null, true);
95 replaceInstance(PhoneFactory.class, "sPhone", null, mPhone);
96 replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
97 replaceInstance(PhoneGlobals.class, "sMe", null, mPhoneGlobals);
Tomasz Wasilczykf7b28c52024-11-11 15:55:27 -080098 replaceInstance(PhoneFactory.class, "sMetricsCollector", null, mMetricsCollector);
99
100 doReturn(Mockito.mock(PersistAtomsStorage.class)).when(mMetricsCollector).getAtomsStorage();
Tomasz Wasilczyk7db47c22024-10-25 13:26:53 -0700101
102 doReturn(mDataNetworkController).when(mPhone).getDataNetworkController();
103 doReturn(Collections.emptyList()).when(mDataNetworkController)
104 .getInternetDataDisallowedReasons();
105 doReturn(Mockito.mock(DataConfigManager.class)).when(mDataNetworkController)
106 .getDataConfigManager();
107
108 mPhoneGlobals.phoneMgr = Mockito.mock(PhoneInterfaceManager.class);
Brad Ebinger12ec7f22016-05-05 10:40:57 -0700109 }
110
Sarah Chine04784a2022-10-31 20:32:34 -0700111 @After
Brad Ebinger12ec7f22016-05-05 10:40:57 -0700112 public void tearDown() throws Exception {
Brad Ebingera15005b2020-04-29 15:20:38 -0700113 // Ensure there are no static references to handlers after test completes.
114 PhoneConfigurationManager.unregisterAllMultiSimConfigChangeRegistrants();
Sarah Chine04784a2022-10-31 20:32:34 -0700115 restoreInstances();
Brad Ebinger12ec7f22016-05-05 10:40:57 -0700116 }
117
Brad Ebinger63b6f5a2020-10-27 11:43:35 -0700118 protected final boolean waitForExecutorAction(Executor executor, long timeoutMillis) {
119 final CountDownLatch lock = new CountDownLatch(1);
Brad Ebinger63b6f5a2020-10-27 11:43:35 -0700120 executor.execute(() -> {
Brad Ebinger63b6f5a2020-10-27 11:43:35 -0700121 lock.countDown();
122 });
123 while (lock.getCount() > 0) {
124 try {
125 return lock.await(timeoutMillis, TimeUnit.MILLISECONDS);
126 } catch (InterruptedException e) {
127 // do nothing
128 }
129 }
130 return true;
131 }
132
Brad Ebinger12ec7f22016-05-05 10:40:57 -0700133 protected final void waitForHandlerAction(Handler h, long timeoutMillis) {
134 final CountDownLatch lock = new CountDownLatch(1);
135 h.post(lock::countDown);
136 while (lock.getCount() > 0) {
137 try {
138 lock.await(timeoutMillis, TimeUnit.MILLISECONDS);
139 } catch (InterruptedException e) {
140 // do nothing
141 }
142 }
143 }
144
145 protected final void waitForHandlerActionDelayed(Handler h, long timeoutMillis, long delayMs) {
146 final CountDownLatch lock = new CountDownLatch(1);
147 h.postDelayed(lock::countDown, delayMs);
148 while (lock.getCount() > 0) {
149 try {
150 lock.await(timeoutMillis, TimeUnit.MILLISECONDS);
151 } catch (InterruptedException e) {
152 // do nothing
153 }
154 }
155 }
Sanket Padawed9a427e2017-06-08 12:03:07 -0700156
157 protected void waitForMs(long ms) {
158 try {
159 Thread.sleep(ms);
160 } catch (InterruptedException e) {
161 Log.e("TelephonyTestBase", "InterruptedException while waiting: " + e);
162 }
163 }
Brad Ebinger792729e2019-12-09 16:12:57 -0800164
Sarah Chine04784a2022-10-31 20:32:34 -0700165 protected synchronized void replaceInstance(final Class c, final String instanceName,
166 final Object obj, final Object newValue)
167 throws Exception {
168 Field field = c.getDeclaredField(instanceName);
169 field.setAccessible(true);
170
171 InstanceKey key = new InstanceKey(c, instanceName, obj);
172 if (!mOldInstances.containsKey(key)) {
173 mOldInstances.put(key, field.get(obj));
174 mInstanceKeys.add(key);
175 }
176 field.set(obj, newValue);
177 }
178
179 private synchronized void restoreInstances() throws Exception {
180 Iterator<InstanceKey> it = mInstanceKeys.descendingIterator();
181
182 while (it.hasNext()) {
183 InstanceKey key = it.next();
184 Field field = key.mClass.getDeclaredField(key.mInstName);
185 field.setAccessible(true);
186 field.set(key.mObj, mOldInstances.get(key));
187 }
188
189 mInstanceKeys.clear();
190 mOldInstances.clear();
191 }
192
193 private static class InstanceKey {
194 public final Class mClass;
195 public final String mInstName;
196 public final Object mObj;
197 InstanceKey(final Class c, final String instName, final Object obj) {
198 mClass = c;
199 mInstName = instName;
200 mObj = obj;
201 }
202
203 @Override
204 public int hashCode() {
205 return (mClass.getName().hashCode() * 31 + mInstName.hashCode()) * 31;
206 }
207
208 @Override
209 public boolean equals(Object obj) {
210 if (obj == null || obj.getClass() != getClass()) {
211 return false;
212 }
213
214 InstanceKey other = (InstanceKey) obj;
215 return (other.mClass == mClass && other.mInstName.equals(mInstName)
216 && other.mObj == mObj);
217 }
218 }
219
Brad Ebinger792729e2019-12-09 16:12:57 -0800220 protected TestContext getTestContext() {
221 return mContext;
222 }
Brad Ebinger12ec7f22016-05-05 10:40:57 -0700223}