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