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