ScanTestUtil.java revision c343aec32e1d3fe320eb97c527b0bcfb2d334e45
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;
18
19import static org.junit.Assert.*;
20import static org.junit.Assume.*;
21import static org.mockito.Mockito.*;
22
23import android.net.wifi.ScanResult;
24import android.net.wifi.WifiScanner;
25import android.net.wifi.WifiScanner.ScanData;
26import android.net.wifi.WifiSsid;
27
28import org.hamcrest.Description;
29import org.hamcrest.Matcher;
30import org.hamcrest.TypeSafeDiagnosingMatcher;
31
32import java.lang.reflect.Field;
33import java.util.Arrays;
34import java.util.HashSet;
35import java.util.Set;
36
37/**
38 * Utilities for testing Wifi Scanning
39 */
40public class ScanTestUtil {
41
42    public static void installWlanWifiNative(WifiNative wifiNative) throws Exception {
43        Field field = WifiNative.class.getDeclaredField("wlanNativeInterface");
44        field.setAccessible(true);
45        field.set(null, wifiNative);
46    }
47
48    public static void setupMockChannels(WifiNative wifiNative, int[] channels24, int[] channels5,
49            int[] channelsDfs) throws Exception {
50        when(wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ))
51                .thenReturn(channels24);
52        when(wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ))
53                .thenReturn(channels5);
54        when(wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY))
55                .thenReturn(channelsDfs);
56    }
57
58    public static WifiScanner.ScanSettings createRequest(WifiScanner.ChannelSpec[] channels,
59            int period, int batch, int bssidsPerScan, int reportEvents) {
60        WifiScanner.ScanSettings request = new WifiScanner.ScanSettings();
61        request.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
62        request.channels = channels;
63        request.periodInMs = period;
64        request.numBssidsPerScan = bssidsPerScan;
65        request.maxScansToCache = batch;
66        request.reportEvents = reportEvents;
67        return request;
68    }
69
70    public static WifiScanner.ScanSettings createRequest(int band, int period, int batch,
71            int bssidsPerScan, int reportEvents) {
72        return createRequest(band, period, 0, 0, batch, bssidsPerScan, reportEvents);
73    }
74
75    /**
76     * Create an exponential back off scan request if maxPeriod != period && maxPeriod != 0.
77     */
78    public static WifiScanner.ScanSettings createRequest(int band, int period, int maxPeriod,
79            int stepCount, int batch, int bssidsPerScan, int reportEvents) {
80        WifiScanner.ScanSettings request = new WifiScanner.ScanSettings();
81        request.band = band;
82        request.channels = null;
83        request.periodInMs = period;
84        request.maxPeriodInMs = maxPeriod;
85        request.stepCount = stepCount;
86        request.numBssidsPerScan = bssidsPerScan;
87        request.maxScansToCache = batch;
88        request.reportEvents = reportEvents;
89        return request;
90    }
91
92    /**
93     * Builder to create WifiNative.ScanSettings objects for testing
94     */
95    public static class NativeScanSettingsBuilder {
96        private final WifiNative.ScanSettings mSettings = new WifiNative.ScanSettings();
97        public NativeScanSettingsBuilder() {
98            mSettings.buckets = new WifiNative.BucketSettings[0];
99            mSettings.num_buckets = 0;
100            mSettings.report_threshold_percent = 100;
101        }
102
103        public NativeScanSettingsBuilder withBasePeriod(int basePeriod) {
104            mSettings.base_period_ms = basePeriod;
105            return this;
106        }
107        public NativeScanSettingsBuilder withMaxApPerScan(int maxAp) {
108            mSettings.max_ap_per_scan = maxAp;
109            return this;
110        }
111        public NativeScanSettingsBuilder withMaxScansToCache(int maxScans) {
112            mSettings.report_threshold_num_scans = maxScans;
113            return this;
114        }
115        public NativeScanSettingsBuilder withMaxPercentToCache(int percent) {
116            mSettings.report_threshold_percent = percent;
117            return this;
118        }
119
120        /**
121         * Add the provided hidden network IDs to scan request.
122         * @param networkIds List of hidden network IDs
123         * @return builder object
124         */
125        public NativeScanSettingsBuilder withHiddenNetworkIds(int[] networkIds) {
126            mSettings.hiddenNetworkIds = networkIds;
127            return this;
128        }
129
130        public NativeScanSettingsBuilder addBucketWithBand(
131                int period, int reportEvents, int band) {
132            WifiNative.BucketSettings bucket = new WifiNative.BucketSettings();
133            bucket.bucket = mSettings.num_buckets;
134            bucket.band = band;
135            bucket.period_ms = period;
136            bucket.report_events = reportEvents;
137            return addBucket(bucket);
138        }
139
140        public NativeScanSettingsBuilder addBucketWithChannels(
141                int period, int reportEvents, WifiScanner.ChannelSpec... channels) {
142            int[] channelFreqs = new int[channels.length];
143            for (int i = 0; i < channels.length; ++i) {
144                channelFreqs[i] = channels[i].frequency;
145            }
146            return addBucketWithChannels(period, reportEvents, channelFreqs);
147        }
148
149        public NativeScanSettingsBuilder addBucketWithChannels(
150                int period, int reportEvents, int... channels) {
151            WifiNative.BucketSettings bucket = new WifiNative.BucketSettings();
152            bucket.bucket = mSettings.num_buckets;
153            bucket.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
154            bucket.num_channels = channels.length;
155            bucket.channels = channelsToNativeSettings(channels);
156            bucket.period_ms = period;
157            bucket.report_events = reportEvents;
158            return addBucket(bucket);
159        }
160
161        public NativeScanSettingsBuilder addBucket(WifiNative.BucketSettings bucket) {
162            mSettings.buckets = Arrays.copyOf(mSettings.buckets, mSettings.num_buckets + 1);
163            mSettings.buckets[mSettings.num_buckets] = bucket;
164            mSettings.num_buckets = mSettings.num_buckets + 1;
165            return this;
166        }
167
168        public WifiNative.ScanSettings build() {
169            return mSettings;
170        }
171    }
172
173    /**
174     * Compute the expected native scan settings that are expected for the given
175     * WifiScanner.ScanSettings.
176     */
177    public static WifiNative.ScanSettings computeSingleScanNativeSettings(
178            WifiScanner.ScanSettings requestSettings) {
179        int reportEvents = requestSettings.reportEvents | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
180        NativeScanSettingsBuilder builder = new NativeScanSettingsBuilder()
181                .withBasePeriod(0)
182                .withMaxApPerScan(0)
183                .withMaxPercentToCache(0)
184                .withMaxScansToCache(0);
185        if (requestSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
186            builder.addBucketWithChannels(0, reportEvents, requestSettings.channels);
187        } else {
188            builder.addBucketWithBand(0, reportEvents, requestSettings.band);
189        }
190
191        return builder.build();
192    }
193
194    /**
195     * Compute the expected native scan settings that are expected for the given channels.
196     */
197    public static WifiNative.ScanSettings createSingleScanNativeSettingsForChannels(
198            int reportEvents, WifiScanner.ChannelSpec... channels) {
199        int actualReportEvents = reportEvents | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
200        return new NativeScanSettingsBuilder()
201                .withBasePeriod(0)
202                .withMaxApPerScan(0)
203                .withMaxPercentToCache(0)
204                .withMaxScansToCache(0)
205                .addBucketWithChannels(0, actualReportEvents, channels)
206                .build();
207    }
208
209    public static Set<Integer> createFreqSet(int... elements) {
210        Set<Integer> set = new HashSet<>();
211        for (int e : elements) {
212            set.add(e);
213        }
214        return set;
215    }
216
217    public static ScanResult createScanResult(int freq) {
218        return new ScanResult(WifiSsid.createFromAsciiEncoded("AN SSID"), "00:00:00:00:00:00", 0L,
219                -1, null, "", 0, freq, 0);
220    }
221
222    private static ScanData createScanData(int[] freqs, int bucketsScanned) {
223        ScanResult[] results = new ScanResult[freqs.length];
224        for (int i = 0; i < freqs.length; ++i) {
225            results[i] = createScanResult(freqs[i]);
226        }
227        return new ScanData(0, 0, bucketsScanned, results);
228    }
229
230    public static ScanData[] createScanDatas(int[][] freqs, int[] bucketsScanned) {
231        assumeTrue(freqs.length == bucketsScanned.length);
232        ScanData[] data = new ScanData[freqs.length];
233        for (int i = 0; i < freqs.length; ++i) {
234            data[i] = createScanData(freqs[i], bucketsScanned[i]);
235        }
236        return data;
237    }
238
239    public static ScanData[] createScanDatas(int[][] freqs) {
240        return createScanDatas(freqs, new int[freqs.length] /* defaults all 0 */);
241    }
242
243    private static void assertScanResultsEquals(String prefix, ScanResult[] expected,
244            ScanResult[] actual) {
245        assertNotNull(prefix + "expected ScanResults was null", expected);
246        assertNotNull(prefix + "actual ScanResults was null", actual);
247        assertEquals(prefix + "results.length", expected.length, actual.length);
248        for (int j = 0; j < expected.length; ++j) {
249            ScanResult expectedResult = expected[j];
250            ScanResult actualResult = actual[j];
251            assertEquals(prefix + "results[" + j + "].SSID",
252                    expectedResult.SSID, actualResult.SSID);
253            assertEquals(prefix + "results[" + j + "].wifiSsid",
254                    expectedResult.wifiSsid.toString(), actualResult.wifiSsid.toString());
255            assertEquals(prefix + "results[" + j + "].BSSID",
256                    expectedResult.BSSID, actualResult.BSSID);
257            assertEquals(prefix + "results[" + j + "].capabilities",
258                    expectedResult.capabilities, actualResult.capabilities);
259            assertEquals(prefix + "results[" + j + "].level",
260                    expectedResult.level, actualResult.level);
261            assertEquals(prefix + "results[" + j + "].frequency",
262                    expectedResult.frequency, actualResult.frequency);
263            assertEquals(prefix + "results[" + j + "].timestamp",
264                    expectedResult.timestamp, actualResult.timestamp);
265            assertEquals(prefix + "results[" + j + "].seen",
266                    expectedResult.seen, actualResult.seen);
267        }
268    }
269
270    /**
271     * Asserts if the provided scan result arrays are the same.
272     */
273    public static void assertScanResultsEquals(ScanResult[] expected, ScanResult[] actual) {
274        assertScanResultsEquals("", expected, actual);
275    }
276
277    private static void assertScanDataEquals(String prefix, ScanData expected, ScanData actual) {
278        assertNotNull(prefix + "expected ScanData was null", expected);
279        assertNotNull(prefix + "actual ScanData was null", actual);
280        assertEquals(prefix + "id", expected.getId(), actual.getId());
281        assertEquals(prefix + "flags", expected.getFlags(), actual.getFlags());
282        assertScanResultsEquals(prefix, expected.getResults(), actual.getResults());
283    }
284
285    public static void assertScanDataEquals(ScanData expected, ScanData actual) {
286        assertScanDataEquals("", expected, actual);
287    }
288
289    public static void assertScanDatasEquals(String prefix, ScanData[] expected, ScanData[] actual) {
290        assertNotNull("expected " + prefix + "ScanData[] was null", expected);
291        assertNotNull("actaul " + prefix + "ScanData[] was null", actual);
292        assertEquals(prefix + "ScanData.length", expected.length, actual.length);
293        for (int i = 0; i < expected.length; ++i) {
294            assertScanDataEquals(prefix + "ScanData[" + i + "].", expected[i], actual[i]);
295        }
296    }
297
298    public static void assertScanDatasEquals(ScanData[] expected, ScanData[] actual) {
299        assertScanDatasEquals("", expected, actual);
300    }
301
302    public static WifiScanner.ChannelSpec[] channelsToSpec(int... channels) {
303        WifiScanner.ChannelSpec[] channelSpecs = new WifiScanner.ChannelSpec[channels.length];
304        for (int i = 0; i < channels.length; ++i) {
305            channelSpecs[i] = new WifiScanner.ChannelSpec(channels[i]);
306        }
307        return channelSpecs;
308    }
309
310    public static void assertNativeScanSettingsEquals(WifiNative.ScanSettings expected,
311            WifiNative.ScanSettings actual) {
312        assertEquals("bssids per scan", expected.max_ap_per_scan, actual.max_ap_per_scan);
313        assertEquals("scans to cache", expected.report_threshold_num_scans,
314                actual.report_threshold_num_scans);
315        assertEquals("percent to cache", expected.report_threshold_percent,
316                actual.report_threshold_percent);
317        assertEquals("base period", expected.base_period_ms, actual.base_period_ms);
318
319        assertEquals("number of buckets", expected.num_buckets, actual.num_buckets);
320        assertNotNull("buckets was null", actual.buckets);
321        for (int i = 0; i < expected.buckets.length; ++i) {
322            assertNotNull("buckets[" + i + "] was null", actual.buckets[i]);
323            assertEquals("buckets[" + i + "].period",
324                    expected.buckets[i].period_ms, actual.buckets[i].period_ms);
325            assertEquals("buckets[" + i + "].reportEvents",
326                    expected.buckets[i].report_events, actual.buckets[i].report_events);
327
328            assertEquals("buckets[" + i + "].band",
329                    expected.buckets[i].band, actual.buckets[i].band);
330            if (expected.buckets[i].band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
331                Set<Integer> expectedChannels = new HashSet<>();
332                for (WifiNative.ChannelSettings channel : expected.buckets[i].channels) {
333                    expectedChannels.add(channel.frequency);
334                }
335                Set<Integer> actualChannels = new HashSet<>();
336                for (WifiNative.ChannelSettings channel : actual.buckets[i].channels) {
337                    actualChannels.add(channel.frequency);
338                }
339                assertEquals("channels", expectedChannels, actualChannels);
340            } else {
341                // since num_channels and channels are ignored when band is not
342                // WifiScanner.WIFI_BAND_UNSPECIFIED just assert that there are no channels
343                // the band equality was already checked above
344                assertEquals("buckets[" + i + "].num_channels not 0", 0,
345                        actual.buckets[i].num_channels);
346                assertTrue("buckets[" + i + "].channels not null or empty",
347                        actual.buckets[i].channels == null
348                        || actual.buckets[i].channels.length == 0);
349            }
350        }
351    }
352
353    /**
354     * Asserts if the provided pno settings are the same.
355     */
356    public static void assertNativePnoSettingsEquals(WifiNative.PnoSettings expected,
357            WifiNative.PnoSettings actual) {
358        assertNotNull("expected was null", expected);
359        assertNotNull("actaul was null", actual);
360        assertEquals("min5GHzRssi", expected.min5GHzRssi, actual.min5GHzRssi);
361        assertEquals("min24GHzRssi", expected.min24GHzRssi, actual.min24GHzRssi);
362        assertEquals("initialScoreMax", expected.initialScoreMax, actual.initialScoreMax);
363        assertEquals("currentConnectionBonus", expected.currentConnectionBonus,
364                actual.currentConnectionBonus);
365        assertEquals("sameNetworkBonus", expected.sameNetworkBonus, actual.sameNetworkBonus);
366        assertEquals("secureBonus", expected.secureBonus, actual.secureBonus);
367        assertEquals("band5GHzBonus", expected.band5GHzBonus, actual.band5GHzBonus);
368        assertEquals("isConnected", expected.isConnected, actual.isConnected);
369        assertNotNull("expected networkList was null", expected.networkList);
370        assertNotNull("actual networkList was null", actual.networkList);
371        assertEquals("networkList.length", expected.networkList.length, actual.networkList.length);
372        for (int i = 0; i < expected.networkList.length; i++) {
373            assertEquals("networkList[" + i + "].ssid",
374                    expected.networkList[i].ssid, actual.networkList[i].ssid);
375            assertEquals("networkList[" + i + "].networkId",
376                    expected.networkList[i].networkId, actual.networkList[i].networkId);
377            assertEquals("networkList[" + i + "].priority",
378                    expected.networkList[i].priority, actual.networkList[i].priority);
379            assertEquals("networkList[" + i + "].flags",
380                    expected.networkList[i].flags, actual.networkList[i].flags);
381            assertEquals("networkList[" + i + "].auth_bit_field",
382                    expected.networkList[i].auth_bit_field, actual.networkList[i].auth_bit_field);
383        }
384    }
385
386    /**
387     * Convert a list of channel frequencies to an array of equivalent WifiNative.ChannelSettings
388     */
389    public static WifiNative.ChannelSettings[] channelsToNativeSettings(int... channels) {
390        WifiNative.ChannelSettings[] channelSpecs = new WifiNative.ChannelSettings[channels.length];
391        for (int i = 0; i < channels.length; ++i) {
392            channelSpecs[i] = new WifiNative.ChannelSettings();
393            channelSpecs[i].frequency = channels[i];
394        }
395        return channelSpecs;
396    }
397
398    /**
399     * Matcher to check that a BucketSettings has the given band
400     */
401    public static Matcher<WifiNative.BucketSettings> bandIs(final int expectedBand) {
402        return new TypeSafeDiagnosingMatcher<WifiNative.BucketSettings>() {
403            @Override
404            public boolean matchesSafely(WifiNative.BucketSettings bucketSettings,
405                    Description mismatchDescription) {
406                if (bucketSettings.band != expectedBand) {
407                    mismatchDescription
408                            .appendText("did not have expected band ").appendValue(expectedBand)
409                            .appendText(", was ").appendValue(bucketSettings.band);
410                    return false;
411                } else {
412                    return true;
413                }
414            }
415
416            @Override
417            public void describeTo(final Description description) {
418                description.appendText("bucket band is ").appendValue(expectedBand);
419            }
420        };
421    }
422
423    /**
424     * Matcher to check that a BucketSettings has exactly the given channels
425     */
426    public static Matcher<WifiNative.BucketSettings> channelsAre(final int... expectedChannels) {
427        return new TypeSafeDiagnosingMatcher<WifiNative.BucketSettings>() {
428            @Override
429            public boolean matchesSafely(WifiNative.BucketSettings bucketSettings,
430                    Description mismatchDescription) {
431                if (bucketSettings.band != WifiScanner.WIFI_BAND_UNSPECIFIED) {
432                    mismatchDescription.appendText("did not have expected unspecified band, was ")
433                            .appendValue(bucketSettings.band);
434                    return false;
435                } else if (bucketSettings.num_channels != expectedChannels.length) {
436                    mismatchDescription
437                            .appendText("did not have expected num_channels ")
438                            .appendValue(expectedChannels.length)
439                            .appendText(", was ").appendValue(bucketSettings.num_channels);
440                    return false;
441                } else if (bucketSettings.channels == null) {
442                    mismatchDescription.appendText("had null channels array");
443                    return false;
444                } else if (bucketSettings.channels.length != expectedChannels.length) {
445                    mismatchDescription
446                            .appendText("did not have channels array length matching excepted ")
447                            .appendValue(expectedChannels.length)
448                            .appendText(", was ").appendValue(bucketSettings.channels.length);
449                    return false;
450                } else {
451                    Set<Integer> foundChannelsSet = new HashSet<>();
452                    for (int i = 0; i < bucketSettings.channels.length; ++i) {
453                        foundChannelsSet.add(bucketSettings.channels[i].frequency);
454                    }
455                    Set<Integer> expectedChannelsSet = new HashSet<>();
456                    for (int i = 0; i < expectedChannels.length; ++i) {
457                        expectedChannelsSet.add(expectedChannels[i]);
458                    }
459
460                    if (!foundChannelsSet.containsAll(expectedChannelsSet)
461                            || foundChannelsSet.size() != expectedChannelsSet.size()) {
462                        Set<Integer> extraChannelsSet = new HashSet<>(foundChannelsSet);
463                        extraChannelsSet.removeAll(expectedChannelsSet);
464                        expectedChannelsSet.removeAll(foundChannelsSet);
465                        mismatchDescription
466                                .appendText("does not contain expected channels ")
467                                .appendValue(expectedChannelsSet);
468                        if (extraChannelsSet.size() > 0) {
469                            mismatchDescription
470                                    .appendText(", but contains extra channels ")
471                                    .appendValue(extraChannelsSet);
472                        }
473                        return false;
474                    } else {
475                        return true;
476                    }
477                }
478            }
479
480            @Override
481            public void describeTo(final Description description) {
482                description.appendText("bucket channels are ").appendValue(expectedChannels);
483            }
484        };
485    }
486}
487