1 /* 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 17 package com.android; 18 19 import static org.mockito.Mockito.spy; 20 21 import android.os.Handler; 22 import android.os.Looper; 23 import android.util.Log; 24 25 import com.android.internal.telephony.PhoneConfigurationManager; 26 27 import org.junit.After; 28 import org.junit.Before; 29 import org.junit.Rule; 30 import org.mockito.junit.MockitoJUnit; 31 import org.mockito.junit.MockitoRule; 32 33 import java.lang.reflect.Field; 34 import java.util.HashMap; 35 import java.util.Iterator; 36 import java.util.LinkedList; 37 import java.util.concurrent.CountDownLatch; 38 import java.util.concurrent.Executor; 39 import java.util.concurrent.TimeUnit; 40 41 /** 42 * Helper class to load Mockito Resources into a test. 43 */ 44 public class TelephonyTestBase { 45 @Rule public final MockitoRule mocks = MockitoJUnit.rule(); 46 47 protected TestContext mContext; 48 49 private final HashMap<InstanceKey, Object> mOldInstances = new HashMap<>(); 50 private final LinkedList<InstanceKey> mInstanceKeys = new LinkedList<>(); 51 52 @Before setUp()53 public void setUp() throws Exception { 54 mContext = spy(new TestContext()); 55 // Set up the looper if it does not exist on the test thread. 56 if (Looper.myLooper() == null) { 57 Looper.prepare(); 58 // Wait until the looper is not null anymore 59 for(int i = 0; i < 5; i++) { 60 if (Looper.myLooper() != null) { 61 break; 62 } 63 Looper.prepare(); 64 Thread.sleep(100); 65 } 66 } 67 } 68 69 @After tearDown()70 public void tearDown() throws Exception { 71 // Ensure there are no static references to handlers after test completes. 72 PhoneConfigurationManager.unregisterAllMultiSimConfigChangeRegistrants(); 73 restoreInstances(); 74 } 75 waitForExecutorAction(Executor executor, long timeoutMillis)76 protected final boolean waitForExecutorAction(Executor executor, long timeoutMillis) { 77 final CountDownLatch lock = new CountDownLatch(1); 78 executor.execute(() -> { 79 lock.countDown(); 80 }); 81 while (lock.getCount() > 0) { 82 try { 83 return lock.await(timeoutMillis, TimeUnit.MILLISECONDS); 84 } catch (InterruptedException e) { 85 // do nothing 86 } 87 } 88 return true; 89 } 90 waitForHandlerAction(Handler h, long timeoutMillis)91 protected final void waitForHandlerAction(Handler h, long timeoutMillis) { 92 final CountDownLatch lock = new CountDownLatch(1); 93 h.post(lock::countDown); 94 while (lock.getCount() > 0) { 95 try { 96 lock.await(timeoutMillis, TimeUnit.MILLISECONDS); 97 } catch (InterruptedException e) { 98 // do nothing 99 } 100 } 101 } 102 waitForHandlerActionDelayed(Handler h, long timeoutMillis, long delayMs)103 protected final void waitForHandlerActionDelayed(Handler h, long timeoutMillis, long delayMs) { 104 final CountDownLatch lock = new CountDownLatch(1); 105 h.postDelayed(lock::countDown, delayMs); 106 while (lock.getCount() > 0) { 107 try { 108 lock.await(timeoutMillis, TimeUnit.MILLISECONDS); 109 } catch (InterruptedException e) { 110 // do nothing 111 } 112 } 113 } 114 waitForMs(long ms)115 protected void waitForMs(long ms) { 116 try { 117 Thread.sleep(ms); 118 } catch (InterruptedException e) { 119 Log.e("TelephonyTestBase", "InterruptedException while waiting: " + e); 120 } 121 } 122 replaceInstance(final Class c, final String instanceName, final Object obj, final Object newValue)123 protected synchronized void replaceInstance(final Class c, final String instanceName, 124 final Object obj, final Object newValue) 125 throws Exception { 126 Field field = c.getDeclaredField(instanceName); 127 field.setAccessible(true); 128 129 InstanceKey key = new InstanceKey(c, instanceName, obj); 130 if (!mOldInstances.containsKey(key)) { 131 mOldInstances.put(key, field.get(obj)); 132 mInstanceKeys.add(key); 133 } 134 field.set(obj, newValue); 135 } 136 restoreInstances()137 private synchronized void restoreInstances() throws Exception { 138 Iterator<InstanceKey> it = mInstanceKeys.descendingIterator(); 139 140 while (it.hasNext()) { 141 InstanceKey key = it.next(); 142 Field field = key.mClass.getDeclaredField(key.mInstName); 143 field.setAccessible(true); 144 field.set(key.mObj, mOldInstances.get(key)); 145 } 146 147 mInstanceKeys.clear(); 148 mOldInstances.clear(); 149 } 150 151 private static class InstanceKey { 152 public final Class mClass; 153 public final String mInstName; 154 public final Object mObj; InstanceKey(final Class c, final String instName, final Object obj)155 InstanceKey(final Class c, final String instName, final Object obj) { 156 mClass = c; 157 mInstName = instName; 158 mObj = obj; 159 } 160 161 @Override hashCode()162 public int hashCode() { 163 return (mClass.getName().hashCode() * 31 + mInstName.hashCode()) * 31; 164 } 165 166 @Override equals(Object obj)167 public boolean equals(Object obj) { 168 if (obj == null || obj.getClass() != getClass()) { 169 return false; 170 } 171 172 InstanceKey other = (InstanceKey) obj; 173 return (other.mClass == mClass && other.mInstName.equals(mInstName) 174 && other.mObj == mObj); 175 } 176 } 177 getTestContext()178 protected TestContext getTestContext() { 179 return mContext; 180 } 181 } 182