BaseWifiScannerImplTest.java revision 00b3049b477728d3fb2424b9ffaac67b19dea348
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
17package com.android.server.wifi.scanner;
18
19import static com.android.server.wifi.ScanTestUtil.NativeScanSettingsBuilder;
20import static com.android.server.wifi.ScanTestUtil.assertScanDataEquals;
21import static com.android.server.wifi.ScanTestUtil.createFreqSet;
22
23import static org.junit.Assert.*;
24import static org.mockito.Mockito.*;
25
26import android.app.test.TestAlarmManager;
27import android.content.Context;
28import android.net.wifi.ScanResult;
29import android.net.wifi.WifiScanner;
30import android.net.wifi.WifiScanner.ScanData;
31import android.net.wifi.WifiSsid;
32import android.os.SystemClock;
33import android.os.test.TestLooper;
34
35import com.android.server.wifi.Clock;
36import com.android.server.wifi.MockResources;
37import com.android.server.wifi.MockWifiMonitor;
38import com.android.server.wifi.ScanDetail;
39import com.android.server.wifi.ScanResults;
40import com.android.server.wifi.WifiMonitor;
41import com.android.server.wifi.WifiNative;
42import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection;
43
44import org.junit.Before;
45import org.junit.Test;
46import org.mockito.InOrder;
47import org.mockito.Mock;
48import org.mockito.MockitoAnnotations;
49
50import java.util.ArrayList;
51import java.util.Arrays;
52import java.util.Collections;
53import java.util.HashSet;
54import java.util.Set;
55
56/**
57 * Base unit tests that should pass for all implementations of
58 * {@link com.android.server.wifi.scanner.WifiScannerImpl}.
59 */
60public abstract class BaseWifiScannerImplTest {
61    @Mock Context mContext;
62    TestAlarmManager mAlarmManager;
63    MockWifiMonitor mWifiMonitor;
64    TestLooper mLooper;
65    @Mock WifiNative mWifiNative;
66    MockResources mResources;
67    @Mock Clock mClock;
68
69    /**
70     * mScanner implementation should be filled in by derived test class
71     */
72    WifiScannerImpl mScanner;
73
74    @Before
75    public void setUpBase() throws Exception {
76        MockitoAnnotations.initMocks(this);
77
78        mLooper = new TestLooper();
79        mAlarmManager = new TestAlarmManager();
80        mWifiMonitor = new MockWifiMonitor();
81        mResources = new MockResources();
82
83        when(mWifiNative.getInterfaceName()).thenReturn("a_test_interface_name");
84
85        when(mContext.getSystemService(Context.ALARM_SERVICE))
86                .thenReturn(mAlarmManager.getAlarmManager());
87
88        when(mContext.getResources()).thenReturn(mResources);
89        when(mClock.getElapsedSinceBootMillis()).thenReturn(SystemClock.elapsedRealtime());
90    }
91
92    protected boolean isAllChannelsScanned(int band) {
93        ChannelCollection collection = mScanner.getChannelHelper().createChannelCollection();
94        collection.addBand(band);
95        return collection.isAllChannels();
96    }
97
98    protected Set<Integer> expectedBandScanFreqs(int band) {
99        ChannelCollection collection = mScanner.getChannelHelper().createChannelCollection();
100        collection.addBand(band);
101        return collection.getSupplicantScanFreqs();
102    }
103
104    protected Set<Integer> expectedBandAndChannelScanFreqs(int band, int... channels) {
105        ChannelCollection collection = mScanner.getChannelHelper().createChannelCollection();
106        collection.addBand(band);
107        for (int channel : channels) {
108            collection.addChannel(channel);
109        }
110        return collection.getSupplicantScanFreqs();
111    }
112
113    @Test
114    public void singleScanSuccess() {
115        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
116                .withBasePeriod(10000) // ms
117                .withMaxApPerScan(10)
118                .addBucketWithBand(10000 /* ms */, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
119                        WifiScanner.WIFI_BAND_24_GHZ)
120                .build();
121
122        doSuccessfulSingleScanTest(settings, expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ),
123                new HashSet<Integer>(),
124                ScanResults.create(0, isAllChannelsScanned(WifiScanner.WIFI_BAND_24_GHZ),
125                        2400, 2450, 2450, 2400, 2450, 2450, 2400, 2450, 2450), false);
126    }
127
128    @Test
129    public void singleScanSuccessWithChannels() {
130        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
131                .withBasePeriod(10000)
132                .withMaxApPerScan(10)
133                .addBucketWithChannels(20000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, 5650)
134                .build();
135
136        doSuccessfulSingleScanTest(settings, createFreqSet(5650),
137                new HashSet<Integer>(),
138                ScanResults.create(0, 5650, 5650, 5650, 5650, 5650, 5650, 5650, 5650), false);
139    }
140
141    @Test
142    public void singleScanSuccessWithFullResults() {
143        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
144                .withBasePeriod(10000)
145                .withMaxApPerScan(10)
146                .addBucketWithBand(10000,
147                        WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
148                        | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
149                        WifiScanner.WIFI_BAND_24_GHZ)
150                .build();
151
152        doSuccessfulSingleScanTest(settings, expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ),
153                new HashSet<Integer>(),
154                ScanResults.create(0, isAllChannelsScanned(WifiScanner.WIFI_BAND_24_GHZ),
155                        2400, 2450, 2450, 2400, 2450, 2450, 2400, 2450, 2450), true);
156    }
157
158    /**
159     * Tests whether the provided hidden networkId's in scan settings is correctly passed along
160     * when invoking native scan.
161     */
162    @Test
163    public void singleScanSuccessWithHiddenNetworkIds() {
164        int[] hiddenNetworkIds = {0, 5};
165        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
166                .withBasePeriod(10000)
167                .withMaxApPerScan(10)
168                .withHiddenNetworkIds(hiddenNetworkIds)
169                .addBucketWithChannels(20000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, 5650)
170                .build();
171
172        Set<Integer> hiddenNetworkIdSet = new HashSet<Integer>();
173        for (int i = 0; i < hiddenNetworkIds.length; i++) {
174            hiddenNetworkIdSet.add(hiddenNetworkIds[i]);
175        }
176        doSuccessfulSingleScanTest(settings, createFreqSet(5650),
177                hiddenNetworkIdSet,
178                ScanResults.create(0, 5650, 5650, 5650, 5650, 5650, 5650, 5650, 5650), false);
179    }
180
181    /**
182     * Tests whether the provided hidden networkId's in scan settings is truncated to max size
183     * supported by wpa_supplicant when invoking native scan.
184     */
185    @Test
186    public void singleScanSuccessWithTruncatedHiddenNetworkIds() {
187        int[] hiddenNetworkIds = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
188        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
189                .withBasePeriod(10000)
190                .withMaxApPerScan(10)
191                .withHiddenNetworkIds(hiddenNetworkIds)
192                .addBucketWithChannels(20000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN, 5650)
193                .build();
194
195        Set<Integer> hiddenNetworkIdSet = new HashSet<Integer>();
196        for (int i = 0; i < SupplicantWifiScannerImpl.MAX_HIDDEN_NETWORK_IDS_PER_SCAN; i++) {
197            hiddenNetworkIdSet.add(hiddenNetworkIds[i]);
198        }
199        doSuccessfulSingleScanTest(settings, createFreqSet(5650),
200                hiddenNetworkIdSet,
201                ScanResults.create(0, 5650, 5650, 5650, 5650, 5650, 5650, 5650, 5650), false);
202    }
203
204    @Test
205    public void overlappingSingleScanFails() {
206        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
207                .withBasePeriod(10000) // ms
208                .withMaxApPerScan(10)
209                .addBucketWithBand(10000 /* ms */, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
210                        WifiScanner.WIFI_BAND_24_GHZ)
211                .build();
212        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
213
214        WifiNative.ScanSettings settings2 = new NativeScanSettingsBuilder()
215                .withBasePeriod(10000) // ms
216                .withMaxApPerScan(10)
217                .addBucketWithBand(10000 /* ms */, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
218                        WifiScanner.WIFI_BAND_5_GHZ)
219                .build();
220        WifiNative.ScanEventHandler eventHandler2 = mock(WifiNative.ScanEventHandler.class);
221
222        // scan start succeeds
223        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true);
224
225        assertTrue(mScanner.startSingleScan(settings, eventHandler));
226        assertFalse("second scan while first scan running should fail immediately",
227                mScanner.startSingleScan(settings2, eventHandler2));
228    }
229
230    @Test
231    public void singleScanFailOnExecute() {
232        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
233                .withBasePeriod(10000)
234                .withMaxApPerScan(10)
235                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
236                        WifiScanner.WIFI_BAND_24_GHZ)
237                .build();
238
239        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
240
241        ScanResults results = ScanResults.create(0, 2400, 2450, 2450);
242
243        InOrder order = inOrder(eventHandler, mWifiNative);
244
245        // scan fails
246        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(false);
247
248        // start scan
249        assertTrue(mScanner.startSingleScan(settings, eventHandler));
250
251        mLooper.dispatchAll();
252        order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_FAILED);
253
254        verifyNoMoreInteractions(eventHandler);
255    }
256
257    /**
258     * Test that a scan failure is reported if a scan times out
259     */
260    @Test
261    public void singleScanFailOnTimeout() {
262        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
263                .withBasePeriod(10000)
264                .withMaxApPerScan(10)
265                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
266                        WifiScanner.WIFI_BAND_24_GHZ)
267                .build();
268
269        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
270
271        ScanResults results = ScanResults.create(0, 2400, 2450, 2450);
272
273        InOrder order = inOrder(eventHandler, mWifiNative);
274
275        // scan succeeds
276        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true);
277
278        // start scan
279        assertTrue(mScanner.startSingleScan(settings, eventHandler));
280        mLooper.dispatchAll();
281
282        // Fire timeout
283        mAlarmManager.dispatch(SupplicantWifiScannerImpl.TIMEOUT_ALARM_TAG);
284        mLooper.dispatchAll();
285
286        order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_FAILED);
287
288        verifyNoMoreInteractions(eventHandler);
289    }
290
291    /**
292     * Test that a scan failure is reported if supplicant sends a scan failed event
293     */
294    @Test
295    public void singleScanFailOnFailedEvent() {
296        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
297                .withBasePeriod(10000)
298                .withMaxApPerScan(10)
299                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
300                        WifiScanner.WIFI_BAND_24_GHZ)
301                .build();
302
303        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
304
305        ScanResults results = ScanResults.create(0, 2400, 2450, 2450);
306
307        InOrder order = inOrder(eventHandler, mWifiNative);
308
309        // scan succeeds
310        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true);
311
312        // start scan
313        assertTrue(mScanner.startSingleScan(settings, eventHandler));
314        mLooper.dispatchAll();
315
316        // Fire failed event
317        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_FAILED_EVENT);
318        mLooper.dispatchAll();
319
320        order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_FAILED);
321
322        verifyNoMoreInteractions(eventHandler);
323    }
324
325    @Test
326    public void singleScanNullEventHandler() {
327        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
328                .withBasePeriod(10000)
329                .withMaxApPerScan(10)
330                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
331                        WifiScanner.WIFI_BAND_24_GHZ)
332                .build();
333        assertFalse(mScanner.startSingleScan(settings, null));
334    }
335
336    @Test
337    public void singleScanNullSettings() {
338        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
339
340        assertFalse(mScanner.startSingleScan(null, eventHandler));
341
342        verifyNoMoreInteractions(eventHandler);
343    }
344
345    @Test
346    public void multipleSingleScanSuccess() {
347        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
348                .withBasePeriod(10000)
349                .withMaxApPerScan(10)
350                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
351                        WifiScanner.WIFI_BAND_24_GHZ)
352                .build();
353        WifiNative.ScanSettings settings2 = new NativeScanSettingsBuilder()
354                .withBasePeriod(10000)
355                .withMaxApPerScan(10)
356                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
357                        WifiScanner.WIFI_BAND_BOTH_WITH_DFS)
358                .build();
359
360        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
361        InOrder order = inOrder(eventHandler, mWifiNative);
362
363        // scans succeed
364        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true);
365
366        // start first scan
367        assertTrue(mScanner.startSingleScan(settings, eventHandler));
368
369        expectSuccessfulSingleScan(order, eventHandler,
370                expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ),
371                new HashSet<Integer>(),
372                ScanResults.create(0, isAllChannelsScanned(WifiScanner.WIFI_BAND_24_GHZ),
373                        2400, 2450, 2450), false);
374
375        // start second scan
376        assertTrue(mScanner.startSingleScan(settings2, eventHandler));
377
378        expectSuccessfulSingleScan(order, eventHandler,
379                expectedBandScanFreqs(WifiScanner.WIFI_BAND_BOTH_WITH_DFS),
380                new HashSet<Integer>(),
381                ScanResults.create(0, true,
382                        5150, 5175), false);
383
384        verifyNoMoreInteractions(eventHandler);
385    }
386
387    /**
388     * Validate that scan results that are returned from supplicant, which are timestamped prior to
389     * the start of the scan, are ignored.
390     */
391    @Test
392    public void singleScanWhereSupplicantReturnsSomeOldResults() {
393        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
394                .withBasePeriod(10000)
395                .withMaxApPerScan(2)
396                .addBucketWithBand(10000,
397                        WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN
398                        | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT,
399                        WifiScanner.WIFI_BAND_24_GHZ)
400                .build();
401
402        long approxScanStartUs = mClock.getElapsedSinceBootMillis() * 1000;
403        ArrayList<ScanDetail> rawResults = new ArrayList<>(Arrays.asList(
404                        new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 1"),
405                                "00:00:00:00:00:00", "", -70, 2450,
406                                approxScanStartUs + 2000 * 1000, 0),
407                        new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 2"),
408                                "AA:BB:CC:DD:EE:FF", "", -66, 2400,
409                                approxScanStartUs + 2500 * 1000, 0),
410                        new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 3"),
411                                "00:00:00:00:00:00", "", -80, 2450,
412                                approxScanStartUs - 2000 * 1000, 0), // old result will be filtered
413                        new ScanDetail(WifiSsid.createFromAsciiEncoded("TEST AP 4"),
414                                "AA:BB:CC:11:22:33", "", -65, 2450,
415                                approxScanStartUs + 4000 * 1000, 0)));
416
417        ArrayList<ScanResult> fullResults = new ArrayList<>();
418        for (ScanDetail detail : rawResults) {
419            if (detail.getScanResult().timestamp > approxScanStartUs) {
420                fullResults.add(detail.getScanResult());
421            }
422        }
423        ArrayList<ScanResult> scanDataResults = new ArrayList<>(fullResults);
424        Collections.sort(scanDataResults, ScanResults.SCAN_RESULT_RSSI_COMPARATOR);
425        ScanData scanData = new ScanData(0, 0, 0,
426                isAllChannelsScanned(WifiScanner.WIFI_BAND_24_GHZ),
427                scanDataResults.toArray(new ScanResult[scanDataResults.size()]));
428        Set<Integer> expectedScan = expectedBandScanFreqs(WifiScanner.WIFI_BAND_24_GHZ);
429
430        // Actual test
431
432        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
433
434        InOrder order = inOrder(eventHandler, mWifiNative);
435
436        // scan succeeds
437        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true);
438
439        // start scan
440        assertTrue(mScanner.startSingleScan(settings, eventHandler));
441
442        order.verify(mWifiNative).scan(eq(expectedScan), any(Set.class));
443
444        when(mWifiNative.getScanResults()).thenReturn(rawResults);
445
446        // Notify scan has finished
447        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
448
449        mLooper.dispatchAll();
450
451        for (ScanResult result : fullResults) {
452            order.verify(eventHandler).onFullScanResult(eq(result), eq(0));
453        }
454
455        order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
456        assertScanDataEquals(scanData, mScanner.getLatestSingleScanResults());
457
458        verifyNoMoreInteractions(eventHandler);
459    }
460
461    @Test
462    public void backgroundScanNullEventHandler() {
463        WifiNative.ScanSettings settings = new NativeScanSettingsBuilder()
464                .withBasePeriod(10000)
465                .withMaxApPerScan(10)
466                .addBucketWithBand(10000, WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN,
467                        WifiScanner.WIFI_BAND_24_GHZ)
468                .build();
469        assertFalse(mScanner.startBatchedScan(settings, null));
470    }
471
472    @Test
473    public void backgroundScanNullSettings() {
474        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
475
476        assertFalse(mScanner.startBatchedScan(null, eventHandler));
477
478        verifyNoMoreInteractions(eventHandler);
479    }
480
481    protected void doSuccessfulSingleScanTest(WifiNative.ScanSettings settings,
482            Set<Integer> expectedScan, Set<Integer> expectedHiddenNetIds, ScanResults results,
483            boolean expectFullResults) {
484        WifiNative.ScanEventHandler eventHandler = mock(WifiNative.ScanEventHandler.class);
485
486        InOrder order = inOrder(eventHandler, mWifiNative);
487
488        // scan succeeds
489        when(mWifiNative.scan(any(Set.class), any(Set.class))).thenReturn(true);
490
491        // start scan
492        assertTrue(mScanner.startSingleScan(settings, eventHandler));
493
494        expectSuccessfulSingleScan(order, eventHandler, expectedScan, expectedHiddenNetIds,
495                results, expectFullResults);
496
497        verifyNoMoreInteractions(eventHandler);
498    }
499
500    protected void expectSuccessfulSingleScan(InOrder order,
501            WifiNative.ScanEventHandler eventHandler, Set<Integer> expectedScan,
502            Set<Integer> expectedHiddenNetIds, ScanResults results, boolean expectFullResults) {
503        order.verify(mWifiNative).scan(eq(expectedScan), eq(expectedHiddenNetIds));
504
505        when(mWifiNative.getScanResults()).thenReturn(results.getScanDetailArrayList());
506
507        // Notify scan has finished
508        mWifiMonitor.sendMessage(mWifiNative.getInterfaceName(), WifiMonitor.SCAN_RESULTS_EVENT);
509
510        mLooper.dispatchAll();
511
512        if (expectFullResults) {
513            for (ScanResult result : results.getRawScanResults()) {
514                order.verify(eventHandler).onFullScanResult(eq(result), eq(0));
515            }
516        }
517
518        order.verify(eventHandler).onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
519        assertScanDataEquals(results.getScanData(), mScanner.getLatestSingleScanResults());
520    }
521}
522