1 /* 2 * Copyright (C) 2016 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.assertArrayEquals; 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertFalse; 22 import static org.junit.Assert.assertTrue; 23 import static org.mockito.Mockito.anyInt; 24 import static org.mockito.Mockito.anyString; 25 import static org.mockito.Mockito.spy; 26 import static org.mockito.Mockito.verify; 27 import static org.mockito.Mockito.when; 28 29 import android.test.suitebuilder.annotation.SmallTest; 30 31 import org.junit.Before; 32 import org.junit.Test; 33 34 import java.lang.reflect.Constructor; 35 import java.util.HashMap; 36 import java.util.Map; 37 import java.util.regex.Pattern; 38 39 /** 40 * Unit tests for {@link com.android.server.wifi.WifiNative}. 41 */ 42 @SmallTest 43 public class WifiNativeTest { 44 private static final int NETWORK_ID = 0; 45 private static final String NETWORK_EXTRAS_VARIABLE = "test"; 46 private static final Map<String, String> NETWORK_EXTRAS_VALUES = new HashMap<>(); 47 static { 48 NETWORK_EXTRAS_VALUES.put("key1", "value1"); 49 NETWORK_EXTRAS_VALUES.put("key2", "value2"); 50 } 51 private static final String NETWORK_EXTRAS_SERIALIZED = 52 "\"%7B%22key2%22%3A%22value2%22%2C%22key1%22%3A%22value1%22%7D\""; 53 54 private static final long FATE_REPORT_DRIVER_TIMESTAMP_USEC = 12345; 55 private static final byte[] FATE_REPORT_FRAME_BYTES = new byte[] { 56 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 0, 1, 2, 3, 4, 5, 6, 7}; 57 private static final WifiNative.TxFateReport TX_FATE_REPORT = new WifiNative.TxFateReport( 58 WifiLoggerHal.TX_PKT_FATE_SENT, 59 FATE_REPORT_DRIVER_TIMESTAMP_USEC, 60 WifiLoggerHal.FRAME_TYPE_ETHERNET_II, 61 FATE_REPORT_FRAME_BYTES 62 ); 63 private static final WifiNative.RxFateReport RX_FATE_REPORT = new WifiNative.RxFateReport( 64 WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID, 65 FATE_REPORT_DRIVER_TIMESTAMP_USEC, 66 WifiLoggerHal.FRAME_TYPE_ETHERNET_II, 67 FATE_REPORT_FRAME_BYTES 68 ); 69 private static final FrameTypeMapping[] FRAME_TYPE_MAPPINGS = new FrameTypeMapping[] { 70 new FrameTypeMapping(WifiLoggerHal.FRAME_TYPE_UNKNOWN, "unknown", "N/A"), 71 new FrameTypeMapping(WifiLoggerHal.FRAME_TYPE_ETHERNET_II, "data", "Ethernet"), 72 new FrameTypeMapping(WifiLoggerHal.FRAME_TYPE_80211_MGMT, "802.11 management", 73 "802.11 Mgmt"), 74 new FrameTypeMapping((byte) 42, "42", "N/A") 75 }; 76 private static final FateMapping[] TX_FATE_MAPPINGS = new FateMapping[] { 77 new FateMapping(WifiLoggerHal.TX_PKT_FATE_ACKED, "acked"), 78 new FateMapping(WifiLoggerHal.TX_PKT_FATE_SENT, "sent"), 79 new FateMapping(WifiLoggerHal.TX_PKT_FATE_FW_QUEUED, "firmware queued"), 80 new FateMapping(WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID, 81 "firmware dropped (invalid frame)"), 82 new FateMapping( 83 WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS, "firmware dropped (no bufs)"), 84 new FateMapping( 85 WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER, "firmware dropped (other)"), 86 new FateMapping(WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED, "driver queued"), 87 new FateMapping(WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID, 88 "driver dropped (invalid frame)"), 89 new FateMapping(WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS, 90 "driver dropped (no bufs)"), 91 new FateMapping(WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER, "driver dropped (other)"), 92 new FateMapping((byte) 42, "42") 93 }; 94 private static final FateMapping[] RX_FATE_MAPPINGS = new FateMapping[] { 95 new FateMapping(WifiLoggerHal.RX_PKT_FATE_SUCCESS, "success"), 96 new FateMapping(WifiLoggerHal.RX_PKT_FATE_FW_QUEUED, "firmware queued"), 97 new FateMapping( 98 WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER, "firmware dropped (filter)"), 99 new FateMapping(WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID, 100 "firmware dropped (invalid frame)"), 101 new FateMapping( 102 WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS, "firmware dropped (no bufs)"), 103 new FateMapping( 104 WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER, "firmware dropped (other)"), 105 new FateMapping(WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED, "driver queued"), 106 new FateMapping( 107 WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER, "driver dropped (filter)"), 108 new FateMapping(WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID, 109 "driver dropped (invalid frame)"), 110 new FateMapping( 111 WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS, "driver dropped (no bufs)"), 112 new FateMapping(WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER, "driver dropped (other)"), 113 new FateMapping((byte) 42, "42") 114 }; 115 116 private WifiNative mWifiNative; 117 118 @Before setUp()119 public void setUp() throws Exception { 120 final Constructor<WifiNative> wifiNativeConstructor = 121 WifiNative.class.getDeclaredConstructor(String.class, Boolean.TYPE); 122 wifiNativeConstructor.setAccessible(true); 123 mWifiNative = spy(wifiNativeConstructor.newInstance("test", true)); 124 } 125 126 /** 127 * Verifies that setNetworkExtra() correctly writes a serialized and URL-encoded JSON object. 128 */ 129 @Test testSetNetworkExtra()130 public void testSetNetworkExtra() { 131 when(mWifiNative.setNetworkVariable(anyInt(), anyString(), anyString())).thenReturn(true); 132 assertTrue(mWifiNative.setNetworkExtra(NETWORK_ID, NETWORK_EXTRAS_VARIABLE, 133 NETWORK_EXTRAS_VALUES)); 134 verify(mWifiNative).setNetworkVariable(NETWORK_ID, NETWORK_EXTRAS_VARIABLE, 135 NETWORK_EXTRAS_SERIALIZED); 136 } 137 138 /** 139 * Verifies that getNetworkExtra() correctly reads a serialized and URL-encoded JSON object. 140 */ 141 @Test testGetNetworkExtra()142 public void testGetNetworkExtra() { 143 when(mWifiNative.getNetworkVariable(NETWORK_ID, NETWORK_EXTRAS_VARIABLE)) 144 .thenReturn(NETWORK_EXTRAS_SERIALIZED); 145 final Map<String, String> actualValues = 146 mWifiNative.getNetworkExtra(NETWORK_ID, NETWORK_EXTRAS_VARIABLE); 147 assertEquals(NETWORK_EXTRAS_VALUES, actualValues); 148 } 149 150 /** 151 * Verifies that TxFateReport's constructor sets all of the TxFateReport fields. 152 */ 153 @Test testTxFateReportCtorSetsFields()154 public void testTxFateReportCtorSetsFields() { 155 WifiNative.TxFateReport fateReport = new WifiNative.TxFateReport( 156 WifiLoggerHal.TX_PKT_FATE_SENT, // non-zero value 157 FATE_REPORT_DRIVER_TIMESTAMP_USEC, 158 WifiLoggerHal.FRAME_TYPE_ETHERNET_II, // non-zero value 159 FATE_REPORT_FRAME_BYTES 160 ); 161 assertEquals(WifiLoggerHal.TX_PKT_FATE_SENT, fateReport.mFate); 162 assertEquals(FATE_REPORT_DRIVER_TIMESTAMP_USEC, fateReport.mDriverTimestampUSec); 163 assertEquals(WifiLoggerHal.FRAME_TYPE_ETHERNET_II, fateReport.mFrameType); 164 assertArrayEquals(FATE_REPORT_FRAME_BYTES, fateReport.mFrameBytes); 165 } 166 167 /** 168 * Verifies that RxFateReport's constructor sets all of the RxFateReport fields. 169 */ 170 @Test testRxFateReportCtorSetsFields()171 public void testRxFateReportCtorSetsFields() { 172 WifiNative.RxFateReport fateReport = new WifiNative.RxFateReport( 173 WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID, // non-zero value 174 FATE_REPORT_DRIVER_TIMESTAMP_USEC, 175 WifiLoggerHal.FRAME_TYPE_ETHERNET_II, // non-zero value 176 FATE_REPORT_FRAME_BYTES 177 ); 178 assertEquals(WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID, fateReport.mFate); 179 assertEquals(FATE_REPORT_DRIVER_TIMESTAMP_USEC, fateReport.mDriverTimestampUSec); 180 assertEquals(WifiLoggerHal.FRAME_TYPE_ETHERNET_II, fateReport.mFrameType); 181 assertArrayEquals(FATE_REPORT_FRAME_BYTES, fateReport.mFrameBytes); 182 } 183 184 // Support classes for test{Tx,Rx}FateReportToString. 185 private static class FrameTypeMapping { 186 byte mTypeNumber; 187 String mExpectedTypeText; 188 String mExpectedProtocolText; FrameTypeMapping(byte typeNumber, String expectedTypeText, String expectedProtocolText)189 FrameTypeMapping(byte typeNumber, String expectedTypeText, String expectedProtocolText) { 190 this.mTypeNumber = typeNumber; 191 this.mExpectedTypeText = expectedTypeText; 192 this.mExpectedProtocolText = expectedProtocolText; 193 } 194 } 195 private static class FateMapping { 196 byte mFateNumber; 197 String mExpectedText; FateMapping(byte fateNumber, String expectedText)198 FateMapping(byte fateNumber, String expectedText) { 199 this.mFateNumber = fateNumber; 200 this.mExpectedText = expectedText; 201 } 202 } 203 204 /** 205 * Verifies that FateReport.getTableHeader() prints the right header. 206 */ 207 @Test testFateReportTableHeader()208 public void testFateReportTableHeader() { 209 final String header = WifiNative.FateReport.getTableHeader(); 210 assertEquals( 211 "\nTime usec Walltime Direction Fate " 212 + "Protocol Type Result\n" 213 + "--------- -------- --------- ---- " 214 + "-------- ---- ------\n", header); 215 } 216 217 /** 218 * Verifies that TxFateReport.toTableRowString() includes the information we care about. 219 */ 220 @Test testTxFateReportToTableRowString()221 public void testTxFateReportToTableRowString() { 222 WifiNative.TxFateReport fateReport = TX_FATE_REPORT; 223 assertTrue( 224 fateReport.toTableRowString().replaceAll("\\s+", " ").trim().matches( 225 FATE_REPORT_DRIVER_TIMESTAMP_USEC + " " // timestamp 226 + "\\d{2}:\\d{2}:\\d{2}\\.\\d{3} " // walltime 227 + "TX " // direction 228 + "sent " // fate 229 + "Ethernet " // type 230 + "N/A " // protocol 231 + "N/A" // result 232 ) 233 ); 234 235 for (FrameTypeMapping frameTypeMapping : FRAME_TYPE_MAPPINGS) { 236 fateReport = new WifiNative.TxFateReport( 237 WifiLoggerHal.TX_PKT_FATE_SENT, 238 FATE_REPORT_DRIVER_TIMESTAMP_USEC, 239 frameTypeMapping.mTypeNumber, 240 FATE_REPORT_FRAME_BYTES 241 ); 242 assertTrue( 243 fateReport.toTableRowString().replaceAll("\\s+", " ").trim().matches( 244 FATE_REPORT_DRIVER_TIMESTAMP_USEC + " " // timestamp 245 + "\\d{2}:\\d{2}:\\d{2}\\.\\d{3} " // walltime 246 + "TX " // direction 247 + "sent " // fate 248 + frameTypeMapping.mExpectedProtocolText + " " // type 249 + "N/A " // protocol 250 + "N/A" // result 251 ) 252 ); 253 } 254 255 for (FateMapping fateMapping : TX_FATE_MAPPINGS) { 256 fateReport = new WifiNative.TxFateReport( 257 fateMapping.mFateNumber, 258 FATE_REPORT_DRIVER_TIMESTAMP_USEC, 259 WifiLoggerHal.FRAME_TYPE_80211_MGMT, 260 FATE_REPORT_FRAME_BYTES 261 ); 262 assertTrue( 263 fateReport.toTableRowString().replaceAll("\\s+", " ").trim().matches( 264 FATE_REPORT_DRIVER_TIMESTAMP_USEC + " " // timestamp 265 + "\\d{2}:\\d{2}:\\d{2}\\.\\d{3} " // walltime 266 + "TX " // direction 267 + Pattern.quote(fateMapping.mExpectedText) + " " // fate 268 + "802.11 Mgmt " // type 269 + "N/A " // protocol 270 + "N/A" // result 271 ) 272 ); 273 } 274 } 275 276 /** 277 * Verifies that TxFateReport.toVerboseStringWithPiiAllowed() includes the information we care 278 * about. 279 */ 280 @Test testTxFateReportToVerboseStringWithPiiAllowed()281 public void testTxFateReportToVerboseStringWithPiiAllowed() { 282 WifiNative.TxFateReport fateReport = TX_FATE_REPORT; 283 284 String verboseFateString = fateReport.toVerboseStringWithPiiAllowed(); 285 assertTrue(verboseFateString.contains("Frame direction: TX")); 286 assertTrue(verboseFateString.contains("Frame timestamp: 12345")); 287 assertTrue(verboseFateString.contains("Frame fate: sent")); 288 assertTrue(verboseFateString.contains("Frame type: data")); 289 assertTrue(verboseFateString.contains("Frame protocol: Ethernet")); 290 assertTrue(verboseFateString.contains("Frame protocol type: N/A")); 291 assertTrue(verboseFateString.contains("Frame length: 16")); 292 assertTrue(verboseFateString.contains( 293 "61 62 63 64 65 66 67 68 00 01 02 03 04 05 06 07")); // hex dump 294 // TODO(quiche): uncomment this, once b/27975149 is fixed. 295 // assertTrue(verboseFateString.contains("abcdefgh........")); // hex dump 296 297 for (FrameTypeMapping frameTypeMapping : FRAME_TYPE_MAPPINGS) { 298 fateReport = new WifiNative.TxFateReport( 299 WifiLoggerHal.TX_PKT_FATE_SENT, 300 FATE_REPORT_DRIVER_TIMESTAMP_USEC, 301 frameTypeMapping.mTypeNumber, 302 FATE_REPORT_FRAME_BYTES 303 ); 304 verboseFateString = fateReport.toVerboseStringWithPiiAllowed(); 305 assertTrue(verboseFateString.contains("Frame type: " 306 + frameTypeMapping.mExpectedTypeText)); 307 } 308 309 for (FateMapping fateMapping : TX_FATE_MAPPINGS) { 310 fateReport = new WifiNative.TxFateReport( 311 fateMapping.mFateNumber, 312 FATE_REPORT_DRIVER_TIMESTAMP_USEC, 313 WifiLoggerHal.FRAME_TYPE_80211_MGMT, 314 FATE_REPORT_FRAME_BYTES 315 ); 316 verboseFateString = fateReport.toVerboseStringWithPiiAllowed(); 317 assertTrue(verboseFateString.contains("Frame fate: " + fateMapping.mExpectedText)); 318 } 319 } 320 321 /** 322 * Verifies that RxFateReport.toTableRowString() includes the information we care about. 323 */ 324 @Test testRxFateReportToTableRowString()325 public void testRxFateReportToTableRowString() { 326 WifiNative.RxFateReport fateReport = RX_FATE_REPORT; 327 assertTrue( 328 fateReport.toTableRowString().replaceAll("\\s+", " ").trim().matches( 329 FATE_REPORT_DRIVER_TIMESTAMP_USEC + " " // timestamp 330 + "\\d{2}:\\d{2}:\\d{2}\\.\\d{3} " // walltime 331 + "RX " // direction 332 + Pattern.quote("firmware dropped (invalid frame) ") // fate 333 + "Ethernet " // type 334 + "N/A " // protocol 335 + "N/A" // result 336 ) 337 ); 338 339 // FrameTypeMappings omitted, as they're the same as for TX. 340 341 for (FateMapping fateMapping : RX_FATE_MAPPINGS) { 342 fateReport = new WifiNative.RxFateReport( 343 fateMapping.mFateNumber, 344 FATE_REPORT_DRIVER_TIMESTAMP_USEC, 345 WifiLoggerHal.FRAME_TYPE_80211_MGMT, 346 FATE_REPORT_FRAME_BYTES 347 ); 348 assertTrue( 349 fateReport.toTableRowString().replaceAll("\\s+", " ").trim().matches( 350 FATE_REPORT_DRIVER_TIMESTAMP_USEC + " " // timestamp 351 + "\\d{2}:\\d{2}:\\d{2}\\.\\d{3} " // walltime 352 + "RX " // direction 353 + Pattern.quote(fateMapping.mExpectedText) + " " // fate 354 + "802.11 Mgmt " // type 355 + "N/A " // protocol 356 + "N/A" // result 357 ) 358 ); 359 } 360 } 361 362 /** 363 * Verifies that RxFateReport.toVerboseStringWithPiiAllowed() includes the information we care 364 * about. 365 */ 366 @Test testRxFateReportToVerboseStringWithPiiAllowed()367 public void testRxFateReportToVerboseStringWithPiiAllowed() { 368 WifiNative.RxFateReport fateReport = RX_FATE_REPORT; 369 370 String verboseFateString = fateReport.toVerboseStringWithPiiAllowed(); 371 assertTrue(verboseFateString.contains("Frame direction: RX")); 372 assertTrue(verboseFateString.contains("Frame timestamp: 12345")); 373 assertTrue(verboseFateString.contains("Frame fate: firmware dropped (invalid frame)")); 374 assertTrue(verboseFateString.contains("Frame type: data")); 375 assertTrue(verboseFateString.contains("Frame protocol: Ethernet")); 376 assertTrue(verboseFateString.contains("Frame protocol type: N/A")); 377 assertTrue(verboseFateString.contains("Frame length: 16")); 378 assertTrue(verboseFateString.contains( 379 "61 62 63 64 65 66 67 68 00 01 02 03 04 05 06 07")); // hex dump 380 // TODO(quiche): uncomment this, once b/27975149 is fixed. 381 // assertTrue(verboseFateString.contains("abcdefgh........")); // hex dump 382 383 // FrameTypeMappings omitted, as they're the same as for TX. 384 385 for (FateMapping fateMapping : RX_FATE_MAPPINGS) { 386 fateReport = new WifiNative.RxFateReport( 387 fateMapping.mFateNumber, 388 FATE_REPORT_DRIVER_TIMESTAMP_USEC, 389 WifiLoggerHal.FRAME_TYPE_80211_MGMT, 390 FATE_REPORT_FRAME_BYTES 391 ); 392 verboseFateString = fateReport.toVerboseStringWithPiiAllowed(); 393 assertTrue(verboseFateString.contains("Frame fate: " + fateMapping.mExpectedText)); 394 } 395 } 396 397 /** 398 * Verifies that startPktFateMonitoring returns false when HAL is not started. 399 */ 400 @Test testStartPktFateMonitoringReturnsFalseWhenHalIsNotStarted()401 public void testStartPktFateMonitoringReturnsFalseWhenHalIsNotStarted() { 402 assertFalse(mWifiNative.isHalStarted()); 403 assertFalse(mWifiNative.startPktFateMonitoring()); 404 } 405 406 /** 407 * Verifies that getTxPktFates returns error when HAL is not started. 408 */ 409 @Test testGetTxPktFatesReturnsErrorWhenHalIsNotStarted()410 public void testGetTxPktFatesReturnsErrorWhenHalIsNotStarted() { 411 WifiNative.TxFateReport[] fateReports = null; 412 assertFalse(mWifiNative.isHalStarted()); 413 assertFalse(mWifiNative.getTxPktFates(fateReports)); 414 } 415 416 /** 417 * Verifies that getRxPktFates returns error when HAL is not started. 418 */ 419 @Test testGetRxPktFatesReturnsErrorWhenHalIsNotStarted()420 public void testGetRxPktFatesReturnsErrorWhenHalIsNotStarted() { 421 WifiNative.RxFateReport[] fateReports = null; 422 assertFalse(mWifiNative.isHalStarted()); 423 assertFalse(mWifiNative.getRxPktFates(fateReports)); 424 } 425 426 // TODO(quiche): Add tests for the success cases (when HAL has been started). Specifically: 427 // - testStartPktFateMonitoringCallsHalIfHalIsStarted() 428 // - testGetTxPktFatesCallsHalIfHalIsStarted() 429 // - testGetRxPktFatesCallsHalIfHalIsStarted() 430 // 431 // Adding these tests is difficult to do at the moment, because we can't mock out the HAL 432 // itself. Also, we can't mock out the native methods, because those methods are private. 433 // b/28005116. 434 435 /** Verifies that getDriverStateDumpNative returns null when HAL is not started. */ 436 @Test testGetDriverStateDumpReturnsNullWhenHalIsNotStarted()437 public void testGetDriverStateDumpReturnsNullWhenHalIsNotStarted() { 438 assertEquals(null, mWifiNative.getDriverStateDump()); 439 } 440 441 // TODO(b/28005116): Add test for the success case of getDriverStateDump(). 442 } 443