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