1 /* 2 * Copyright (C) 2015 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.server.wifi.scanner; 18 19 import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder; 20 import static com.android.server.wifi.ScanTestUtil.setupMockChannels; 21 22 import static org.junit.Assert.*; 23 import static org.mockito.Mockito.*; 24 25 import android.app.AlarmManager; 26 import android.app.PendingIntent; 27 import android.net.wifi.WifiScanner; 28 import android.support.test.filters.SmallTest; 29 30 import com.android.server.wifi.ScanResults; 31 import com.android.server.wifi.WifiMonitor; 32 import com.android.server.wifi.WifiNative; 33 import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection; 34 35 import org.junit.Before; 36 import org.junit.Test; 37 38 import java.io.FileDescriptor; 39 import java.io.PrintWriter; 40 import java.io.StringWriter; 41 import java.util.HashSet; 42 import java.util.Set; 43 import java.util.regex.Pattern; 44 45 /** 46 * Unit tests for {@link com.android.server.wifi.scanner.WificondScannerImpl}. 47 */ 48 @SmallTest 49 public class WificondScannerTest extends BaseWifiScannerImplTest { 50 WifiMonitor mWifiMonitorSpy; 51 @Before 52 public void setup() throws Exception { 53 setupMockChannels(mWifiNative, 54 new int[]{2400, 2450}, 55 new int[]{5150, 5175}, 56 new int[]{5600, 5650}); 57 mWifiMonitorSpy = spy(mWifiMonitor); 58 mScanner = new WificondScannerImpl(mContext, BaseWifiScannerImplTest.IFACE_NAME, 59 mWifiNative, mWifiMonitorSpy, new WificondChannelHelper(mWifiNative), 60 mLooper.getLooper(), mClock); 61 } 62 63 /** 64 * Test that WificondScannerImpl will not issue a scan and report scan failure 65 * when there is no channel to scan for. 66 */ 67 @Test 68 public void singleScanNotIssuedIfNoAvailableChannels() { 69 // Use mocked ChannelHelper and ChannelCollection to simulate the scenario 70 // that no channel is available for this request. 71 ChannelHelper channelHelper = mock(ChannelHelper.class); 72 ChannelCollection channelCollection = mock(ChannelCollection.class); 73 when(channelHelper.createChannelCollection()).thenReturn(channelCollection); 74 when(channelCollection.isEmpty()).thenReturn(true); 75 76 mScanner = new WificondScannerImpl(mContext, BaseWifiScannerImplTest.IFACE_NAME, 77 mWifiNative, mWifiMonitor, channelHelper, mLooper.getLooper(), mClock); 78 79 WifiNative.ScanSettings settings = new NativeScanSettingsBuilder() 80 .withBasePeriod(10000) // ms 81 .withMaxApPerScan(10) 82 .addBucketWithBand(10000 /* ms */, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, 83 WifiScanner.WIFI_BAND_5_GHZ) 84 .build(); 85 WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class); 86 mScanner.startSingleScan(settings, eventHandler); 87 88 mLooper.dispatchAll(); 89 90 // No scan is issued to WifiNative. 91 verify(mWifiNative, never()).scan(any(), anyInt(), any(), any(Set.class)); 92 // A scan failed event must be reported. 93 verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_FAILED); 94 } 95 96 @Test 97 public void externalScanResultsDoNotCauseSpuriousTimerCancellationOrCrash() { 98 mWifiMonitor.sendMessage(IFACE_NAME, WifiMonitor.SCAN_RESULTS_EVENT); 99 mLooper.dispatchAll(); 100 verify(mAlarmManager.getAlarmManager(), never()).cancel(any(PendingIntent.class)); 101 verify(mAlarmManager.getAlarmManager(), never()) 102 .cancel(any(AlarmManager.OnAlarmListener.class)); 103 verify(mAlarmManager.getAlarmManager(), never()).cancel(isNull(PendingIntent.class)); 104 verify(mAlarmManager.getAlarmManager(), never()) 105 .cancel(isNull(AlarmManager.OnAlarmListener.class)); 106 } 107 108 @Test 109 public void externalScanResultsAfterOurScanDoNotCauseSpuriousTimerCancellationOrCrash() { 110 WifiNative.ScanSettings settings = new NativeScanSettingsBuilder() 111 .withBasePeriod(10000) // ms 112 .withMaxApPerScan(10) 113 .addBucketWithBand(10000 /* ms */, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, 114 WifiScanner.WIFI_BAND_24_GHZ) 115 .build(); 116 117 doSuccessfulSingleScanTest(settings, 118 expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ), 119 new HashSet<String>(), 120 ScanResults.create(0, isAllChannelsScanned(WifiScanner.WIFI_BAND_24_GHZ), 121 2400, 2450, 2450, 2400, 2450, 2450, 2400, 2450, 2450), false); 122 123 mWifiMonitor.sendMessage(IFACE_NAME, WifiMonitor.SCAN_RESULTS_EVENT); 124 mLooper.dispatchAll(); 125 verify(mAlarmManager.getAlarmManager(), never()).cancel(any(PendingIntent.class)); 126 verify(mAlarmManager.getAlarmManager(), times(1)) 127 .cancel(any(AlarmManager.OnAlarmListener.class)); 128 verify(mAlarmManager.getAlarmManager(), never()).cancel(isNull(PendingIntent.class)); 129 verify(mAlarmManager.getAlarmManager(), never()) 130 .cancel(isNull(AlarmManager.OnAlarmListener.class)); 131 } 132 133 @Test 134 public void lateScanResultsDoNotCauseSpuriousTimerCancellationOrCrash() { 135 WifiNative.ScanSettings settings = new NativeScanSettingsBuilder() 136 .withBasePeriod(10000) // ms 137 .withMaxApPerScan(10) 138 .addBucketWithBand(10000 /* ms */, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, 139 WifiScanner.WIFI_BAND_24_GHZ) 140 .build(); 141 142 // Kick off a scan 143 when(mWifiNative.scan(eq(IFACE_NAME), anyInt(), any(), any(Set.class))).thenReturn(true); 144 WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class); 145 assertTrue(mScanner.startSingleScan(settings, eventHandler)); 146 mLooper.dispatchAll(); 147 148 // Report a timeout 149 mAlarmManager.dispatch(WificondScannerImpl.TIMEOUT_ALARM_TAG); 150 mLooper.dispatchAll(); 151 152 // Now report scan results (results lost the race with timeout) 153 mWifiMonitor.sendMessage(IFACE_NAME, WifiMonitor.SCAN_RESULTS_EVENT); 154 mLooper.dispatchAll(); 155 156 verify(mAlarmManager.getAlarmManager(), never()).cancel(any(PendingIntent.class)); 157 verify(mAlarmManager.getAlarmManager(), never()) 158 .cancel(any(AlarmManager.OnAlarmListener.class)); 159 verify(mAlarmManager.getAlarmManager(), never()).cancel(isNull(PendingIntent.class)); 160 verify(mAlarmManager.getAlarmManager(), never()) 161 .cancel(isNull(AlarmManager.OnAlarmListener.class)); 162 } 163 164 /** 165 * Test that dump() of WificondScannerImpl dumps native scan results. 166 */ 167 @Test 168 public void dumpContainsNativeScanResults() { 169 assertDumpContainsRequestLog("Latest native scan results:"); 170 } 171 172 @Test 173 public void cleanupDeregistersHandlers() { 174 mScanner.cleanup(); 175 verify(mWifiMonitorSpy, times(1)).deregisterHandler(anyString(), 176 eq(WifiMonitor.SCAN_FAILED_EVENT), any()); 177 verify(mWifiMonitorSpy, times(1)).deregisterHandler(anyString(), 178 eq(WifiMonitor.PNO_SCAN_RESULTS_EVENT), any()); 179 verify(mWifiMonitorSpy, times(1)).deregisterHandler(anyString(), 180 eq(WifiMonitor.SCAN_RESULTS_EVENT), any()); 181 } 182 183 private void assertDumpContainsRequestLog(String log) { 184 String objectDump = dumpObject(); 185 Pattern logLineRegex = Pattern.compile(".*" + log + ".*"); 186 assertTrue("dump did not contain log = " + log + "\n " + objectDump + "\n", 187 logLineRegex.matcher(objectDump).find()); 188 } 189 190 private String dumpObject() { 191 StringWriter stringWriter = new StringWriter(); 192 mScanner.dump(new FileDescriptor(), new PrintWriter(stringWriter), 193 new String[0]); 194 return stringWriter.toString(); 195 } 196 } 197