1/* 2 * Copyright 2017 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.server.wifi; 18 19import static org.junit.Assert.assertFalse; 20import static org.junit.Assert.assertTrue; 21import static org.mockito.ArgumentMatchers.eq; 22import static org.mockito.Mockito.*; 23 24import org.junit.Before; 25import org.junit.Test; 26import org.mockito.Mock; 27import org.mockito.MockitoAnnotations; 28 29import java.util.Arrays; 30import java.util.Collection; 31import java.util.Collections; 32import java.util.List; 33 34/** 35 * Unit tests for {@link WakeupLock}. 36 */ 37public class WakeupLockTest { 38 39 private static final String SSID_1 = "ssid1"; 40 private static final String SSID_2 = "ssid2"; 41 42 @Mock private WifiConfigManager mWifiConfigManager; 43 @Mock private WifiWakeMetrics mWifiWakeMetrics; 44 @Mock private Clock mClock; 45 46 private ScanResultMatchInfo mNetwork1; 47 private ScanResultMatchInfo mNetwork2; 48 private WakeupLock mWakeupLock; 49 50 /** 51 * Initialize objects before each test run. 52 */ 53 @Before 54 public void setUp() { 55 MockitoAnnotations.initMocks(this); 56 57 when(mClock.getElapsedSinceBootMillis()).thenReturn(0L); 58 59 mNetwork1 = new ScanResultMatchInfo(); 60 mNetwork1.networkSsid = SSID_1; 61 mNetwork1.networkType = ScanResultMatchInfo.NETWORK_TYPE_OPEN; 62 63 mNetwork2 = new ScanResultMatchInfo(); 64 mNetwork2.networkSsid = SSID_2; 65 mNetwork2.networkType = ScanResultMatchInfo.NETWORK_TYPE_EAP; 66 67 mWakeupLock = new WakeupLock(mWifiConfigManager, mWifiWakeMetrics, mClock); 68 } 69 70 /** 71 * Updates the lock enough times to evict any networks not passed in. 72 * 73 * <p>It calls update {@link WakeupLock#CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT} times with 74 * the given network list. It asserts that the lock isn't empty prior to each call to update. 75 */ 76 private void updateEnoughTimesToEvictWithAsserts(Collection<ScanResultMatchInfo> networks) { 77 for (int i = 0; i < WakeupLock.CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT; i++) { 78 assertFalse("Lock empty after " + i + " scans", mWakeupLock.isUnlocked()); 79 mWakeupLock.update(networks); 80 } 81 } 82 83 /** 84 * Updates the lock enough times to evict any networks not passed in. 85 * 86 * <p>It calls update {@link WakeupLock#CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT} times with 87 * the given network list. It does not make any assertions about the state of the lock. 88 */ 89 private void updateEnoughTimesToEvictWithoutAsserts(Collection<ScanResultMatchInfo> networks) { 90 for (int i = 0; i < WakeupLock.CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT; i++) { 91 mWakeupLock.update(networks); 92 } 93 } 94 95 /** 96 * Verify that calling update {@link WakeupLock#CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT} 97 * times sets the lock to be initialized. 98 */ 99 @Test 100 public void verifyInitializingLockByScans() { 101 List<ScanResultMatchInfo> networks = Collections.singletonList(mNetwork1); 102 mWakeupLock.setLock(networks); 103 assertFalse(mWakeupLock.isInitialized()); 104 105 mWakeupLock.update(networks); 106 assertFalse(mWakeupLock.isInitialized()); 107 mWakeupLock.update(networks); 108 assertFalse(mWakeupLock.isInitialized()); 109 mWakeupLock.update(networks); 110 assertTrue(mWakeupLock.isInitialized()); 111 } 112 113 /** 114 * Verify that calling update after {@link WakeupLock#MAX_LOCK_TIME_MILLIS} milliseconds sets 115 * the lock to be initialized and does not add the scans to the lock. 116 */ 117 @Test 118 public void verifyInitializingLockByTimeout() { 119 when(mClock.getElapsedSinceBootMillis()) 120 .thenReturn(0L, WakeupLock.MAX_LOCK_TIME_MILLIS + 1); 121 mWakeupLock.setLock(Collections.emptyList()); 122 assertFalse(mWakeupLock.isInitialized()); 123 124 List<ScanResultMatchInfo> networks = Collections.singletonList(mNetwork1); 125 mWakeupLock.update(networks); 126 assertTrue(mWakeupLock.isInitialized()); 127 assertTrue(mWakeupLock.isUnlocked()); 128 } 129 130 /** 131 * Verify that addToLock saves to the store if it changes the contents of the lock. 132 */ 133 @Test 134 public void addToLockSavesToStore() { 135 mWakeupLock.setLock(Collections.emptyList()); 136 137 List<ScanResultMatchInfo> networks = Collections.singletonList(mNetwork1); 138 mWakeupLock.update(networks); 139 140 // want 2 invocations, once for setLock(), once for addToLock 141 verify(mWifiConfigManager, times(2)).saveToStore(false); 142 } 143 144 /** 145 * Verify that the WakeupLock is not empty immediately after being initialized with networks. 146 */ 147 @Test 148 public void verifyNotEmptyWhenSetWithNetworkList() { 149 setLockAndInitializeByTimeout(Arrays.asList(mNetwork1, mNetwork2)); 150 assertFalse(mWakeupLock.isUnlocked()); 151 } 152 153 /** 154 * Verify that the WakeupLock is unlocked when initialized with an empty list. 155 */ 156 @Test 157 public void isEmptyWhenInitializedWithEmptyList() { 158 setLockAndInitializeByTimeout(Collections.emptyList()); 159 assertTrue(mWakeupLock.isUnlocked()); 160 } 161 162 /** 163 * Verify that setting the lock clears out previous entries. 164 */ 165 @Test 166 public void setLockClearsPreviousNetworks() { 167 setLockAndInitializeByTimeout(Collections.singletonList(mNetwork1)); 168 assertFalse(mWakeupLock.isUnlocked()); 169 170 setLockAndInitializeByTimeout(Collections.emptyList()); 171 assertTrue(mWakeupLock.isUnlocked()); 172 } 173 174 /** 175 * Updating the lock should evict scan results that haven't been seen in 176 * {@link WakeupLock#CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT} scans. 177 */ 178 @Test 179 public void updateShouldRemoveNetworksAfterConsecutiveMissedScans() { 180 setLockAndInitializeByTimeout(Collections.singletonList(mNetwork1)); 181 182 updateEnoughTimesToEvictWithAsserts(Collections.singletonList(mNetwork2)); 183 184 assertTrue(mWakeupLock.isUnlocked()); 185 } 186 187 /** 188 * Ensure that missed scans must be consecutive in order to evict networks from lock. 189 */ 190 @Test 191 public void updateWithLockedNetworkShouldResetRequiredNumberOfScans() { 192 List<ScanResultMatchInfo> lockedNetworks = Collections.singletonList(mNetwork1); 193 List<ScanResultMatchInfo> updateNetworks = Collections.singletonList(mNetwork2); 194 195 setLockAndInitializeByTimeout(lockedNetworks); 196 197 // one update without network 198 mWakeupLock.update(updateNetworks); 199 // one update with network 200 mWakeupLock.update(lockedNetworks); 201 202 updateEnoughTimesToEvictWithAsserts(updateNetworks); 203 204 assertTrue(mWakeupLock.isUnlocked()); 205 } 206 207 /** 208 * Once a network is removed from the lock, it should not be reset even if it's seen again. 209 */ 210 @Test 211 public void updateWithLockedNetworkAfterItIsRemovedDoesNotReset() { 212 List<ScanResultMatchInfo> lockedNetworks = Collections.singletonList(mNetwork1); 213 setLockAndInitializeByTimeout(lockedNetworks); 214 215 updateEnoughTimesToEvictWithAsserts(Collections.emptyList()); 216 217 assertTrue(mWakeupLock.isUnlocked()); 218 mWakeupLock.update(lockedNetworks); 219 assertTrue(mWakeupLock.isUnlocked()); 220 } 221 222 /** 223 * Verify that networks can be incrementally removed from the lock. Their counters should be 224 * independent. 225 */ 226 @Test 227 public void networksCanBeRemovedIncrementallyFromLock() { 228 List<ScanResultMatchInfo> lockedNetworks = Arrays.asList(mNetwork1, mNetwork2); 229 setLockAndInitializeByTimeout(lockedNetworks); 230 231 updateEnoughTimesToEvictWithAsserts(Collections.singletonList(mNetwork1)); 232 assertFalse(mWakeupLock.isUnlocked()); 233 234 updateEnoughTimesToEvictWithAsserts(Collections.singletonList(mNetwork2)); 235 assertTrue(mWakeupLock.isUnlocked()); 236 } 237 238 /** 239 * Verify that initializing the lock persists the SSID list to the config store. 240 */ 241 @Test 242 public void initializeShouldSaveSsidsToStore() { 243 setLockAndInitializeByTimeout(Collections.singletonList(mNetwork1)); 244 verify(mWifiConfigManager).saveToStore(eq(false)); 245 } 246 247 /** 248 * Verify that update saves to store if the lock changes. 249 */ 250 @Test 251 public void updateShouldOnlySaveIfLockChanges() { 252 setLockAndInitializeByTimeout(Collections.singletonList(mNetwork1)); 253 updateEnoughTimesToEvictWithoutAsserts(Collections.emptyList()); 254 255 // need exactly 2 invocations: 1 for initialize, 1 for successful update 256 verify(mWifiConfigManager, times(2)).saveToStore(eq(false)); 257 } 258 259 /** 260 * Verify that update does not save to store if the lock does not change. 261 */ 262 @Test 263 public void updateShouldNotSaveIfLockDoesNotChange() { 264 List<ScanResultMatchInfo> networks = Collections.singletonList(mNetwork1); 265 setLockAndInitializeByTimeout(networks); 266 verify(mWifiConfigManager, times(1)).saveToStore(anyBoolean()); 267 mWakeupLock.update(networks); 268 } 269 270 /** 271 * Verify that on unlock, records the unlock event with WifiWakeMetrics with the correct number 272 * of scans. 273 */ 274 @Test 275 public void unlockingShouldRecordEventInMetrics() { 276 when(mClock.getElapsedSinceBootMillis()) 277 .thenReturn(0L, WakeupLock.MAX_LOCK_TIME_MILLIS + 1); 278 List<ScanResultMatchInfo> networks = Collections.singletonList(mNetwork1); 279 mWakeupLock.setLock(networks); 280 for (int i = 0; i < WakeupLock.CONSECUTIVE_MISSED_SCANS_REQUIRED_TO_EVICT; i++) { 281 mWakeupLock.update(Collections.emptyList()); 282 } 283 verify(mWifiWakeMetrics).recordUnlockEvent(3 /* numScans */); 284 } 285 286 private void setLockAndInitializeByTimeout(Collection<ScanResultMatchInfo> networks) { 287 when(mClock.getElapsedSinceBootMillis()) 288 .thenReturn(0L, WakeupLock.MAX_LOCK_TIME_MILLIS + 1); 289 mWakeupLock.setLock(networks); 290 mWakeupLock.update(networks); 291 assertTrue(mWakeupLock.isInitialized()); 292 } 293} 294