WifiDiagnosticsTest.java revision 3bbf564af91515b33fcba33e7039ffe09c8c025c
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 17package com.android.server.wifi; 18 19import static org.junit.Assert.assertArrayEquals; 20import static org.junit.Assert.assertEquals; 21import static org.junit.Assert.assertFalse; 22import static org.junit.Assert.assertTrue; 23import static org.mockito.Matchers.anyString; 24import static org.mockito.Matchers.contains; 25import static org.mockito.Mockito.anyInt; 26import static org.mockito.Mockito.anyObject; 27import static org.mockito.Mockito.eq; 28import static org.mockito.Mockito.never; 29import static org.mockito.Mockito.reset; 30import static org.mockito.Mockito.verify; 31import static org.mockito.Mockito.when; 32 33import android.app.test.MockAnswerUtil.AnswerWithArguments; 34import android.content.Context; 35import android.test.suitebuilder.annotation.SmallTest; 36import android.util.LocalLog; 37 38import com.android.internal.R; 39 40import org.junit.Before; 41import org.junit.Test; 42import org.mockito.Mock; 43import org.mockito.MockitoAnnotations; 44import org.mockito.Spy; 45 46import java.io.ByteArrayInputStream; 47import java.io.FileDescriptor; 48import java.io.PrintWriter; 49import java.io.StringWriter; 50import java.util.regex.Pattern; 51 52/** 53 * Unit tests for {@link WifiDiagnostics}. 54 */ 55@SmallTest 56public class WifiDiagnosticsTest { 57 @Mock WifiStateMachine mWsm; 58 @Mock WifiNative mWifiNative; 59 @Mock BuildProperties mBuildProperties; 60 @Mock Context mContext; 61 @Mock WifiInjector mWifiInjector; 62 @Spy FakeWifiLog mLog; 63 @Mock LastMileLogger mLastMileLogger; 64 @Mock Runtime mJavaRuntime; 65 @Mock Process mExternalProcess; 66 WifiDiagnostics mWifiDiagnostics; 67 68 private static final String FAKE_RING_BUFFER_NAME = "fake-ring-buffer"; 69 private static final int SMALL_RING_BUFFER_SIZE_KB = 32; 70 private static final int LARGE_RING_BUFFER_SIZE_KB = 1024; 71 private static final int BYTES_PER_KBYTE = 1024; 72 private static final long FAKE_CONNECTION_ID = 1; 73 private LocalLog mWifiNativeLocalLog; 74 75 private WifiNative.RingBufferStatus mFakeRbs; 76 /** 77 * Returns the data that we would dump in a bug report, for our ring buffer. 78 * @return a 2-D byte array, where the first dimension is the record number, and the second 79 * dimension is the byte index within that record. 80 */ 81 private final byte[][] getLoggerRingBufferData() throws Exception { 82 return mWifiDiagnostics.getBugReports().get(0).ringBuffers.get(FAKE_RING_BUFFER_NAME); 83 } 84 85 /** 86 * Initializes common state (e.g. mocks) needed by test cases. 87 */ 88 @Before 89 public void setUp() throws Exception { 90 MockitoAnnotations.initMocks(this); 91 92 mFakeRbs = new WifiNative.RingBufferStatus(); 93 mFakeRbs.name = FAKE_RING_BUFFER_NAME; 94 WifiNative.RingBufferStatus[] ringBufferStatuses = new WifiNative.RingBufferStatus[] { 95 mFakeRbs 96 }; 97 mWifiNativeLocalLog = new LocalLog(8192); 98 99 when(mWifiNative.getRingBufferStatus()).thenReturn(ringBufferStatuses); 100 when(mWifiNative.readKernelLog()).thenReturn(""); 101 when(mWifiNative.getLocalLog()).thenReturn(mWifiNativeLocalLog); 102 when(mBuildProperties.isEngBuild()).thenReturn(false); 103 when(mBuildProperties.isUserdebugBuild()).thenReturn(false); 104 when(mBuildProperties.isUserBuild()).thenReturn(true); 105 when(mExternalProcess.getInputStream()).thenReturn(new ByteArrayInputStream(new byte[0])); 106 when(mExternalProcess.getErrorStream()).thenReturn(new ByteArrayInputStream(new byte[0])); 107 when(mJavaRuntime.exec(anyString())).thenReturn(mExternalProcess); 108 109 MockResources resources = new MockResources(); 110 resources.setInteger(R.integer.config_wifi_logger_ring_buffer_default_size_limit_kb, 111 SMALL_RING_BUFFER_SIZE_KB); 112 resources.setInteger(R.integer.config_wifi_logger_ring_buffer_verbose_size_limit_kb, 113 LARGE_RING_BUFFER_SIZE_KB); 114 when(mContext.getResources()).thenReturn(resources); 115 when(mWifiInjector.makeLog(anyString())).thenReturn(mLog); 116 when(mWifiInjector.getJavaRuntime()).thenReturn(mJavaRuntime); 117 118 mWifiDiagnostics = new WifiDiagnostics( 119 mContext, mWifiInjector, mWsm, mWifiNative, mBuildProperties, mLastMileLogger); 120 mWifiNative.enableVerboseLogging(0); 121 } 122 123 /** Verifies that startLogging() registers a logging event handler. */ 124 @Test 125 public void startLoggingRegistersLogEventHandler() throws Exception { 126 final boolean verbosityToggle = false; // even default mode wants log events from HAL 127 mWifiDiagnostics.startLogging(verbosityToggle); 128 verify(mWifiNative).setLoggingEventHandler(anyObject()); 129 } 130 131 /** 132 * Verifies that a failure to set the logging event handler does not prevent a future 133 * startLogging() from setting the logging event handler. 134 */ 135 @Test 136 public void startLoggingRegistersLogEventHandlerIfPriorAttemptFailed() 137 throws Exception { 138 final boolean verbosityToggle = false; // even default mode wants log events from HAL 139 140 when(mWifiNative.setLoggingEventHandler(anyObject())).thenReturn(false); 141 mWifiDiagnostics.startLogging(verbosityToggle); 142 verify(mWifiNative).setLoggingEventHandler(anyObject()); 143 reset(mWifiNative); 144 145 when(mWifiNative.setLoggingEventHandler(anyObject())).thenReturn(true); 146 mWifiDiagnostics.startLogging(verbosityToggle); 147 verify(mWifiNative).setLoggingEventHandler(anyObject()); 148 } 149 150 /** Verifies that startLogging() does not make redundant calls to setLoggingEventHandler(). */ 151 @Test 152 public void startLoggingDoesNotRegisterLogEventHandlerIfPriorAttemptSucceeded() 153 throws Exception { 154 final boolean verbosityToggle = false; // even default mode wants log events from HAL 155 156 when(mWifiNative.setLoggingEventHandler(anyObject())).thenReturn(true); 157 mWifiDiagnostics.startLogging(verbosityToggle); 158 verify(mWifiNative).setLoggingEventHandler(anyObject()); 159 reset(mWifiNative); 160 161 mWifiDiagnostics.startLogging(verbosityToggle); 162 verify(mWifiNative, never()).setLoggingEventHandler(anyObject()); 163 } 164 165 /** 166 * Verifies that startLogging() restarts HAL ringbuffers. 167 * 168 * Specifically: verifies that startLogging() 169 * a) stops any ring buffer logging that might be already running, 170 * b) instructs WifiNative to enable ring buffers of the appropriate log level. 171 */ 172 @Test 173 public void startLoggingStopsAndRestartsRingBufferLogging() throws Exception { 174 final boolean verbosityToggle = false; 175 mWifiDiagnostics.startLogging(verbosityToggle); 176 verify(mWifiNative).startLoggingRingBuffer( 177 eq(WifiDiagnostics.VERBOSE_NO_LOG), anyInt(), anyInt(), anyInt(), 178 eq(FAKE_RING_BUFFER_NAME)); 179 verify(mWifiNative).startLoggingRingBuffer( 180 eq(WifiDiagnostics.VERBOSE_NORMAL_LOG), anyInt(), anyInt(), anyInt(), 181 eq(FAKE_RING_BUFFER_NAME)); 182 } 183 184 /** Verifies that, if a log handler was registered, then stopLogging() resets it. */ 185 @Test 186 public void stopLoggingResetsLogHandlerIfHandlerWasRegistered() throws Exception { 187 final boolean verbosityToggle = false; // even default mode wants log events from HAL 188 189 when(mWifiNative.setLoggingEventHandler(anyObject())).thenReturn(true); 190 mWifiDiagnostics.startLogging(verbosityToggle); 191 reset(mWifiNative); 192 193 mWifiDiagnostics.stopLogging(); 194 verify(mWifiNative).resetLogHandler(); 195 } 196 197 /** Verifies that, if a log handler is not registered, stopLogging() skips resetLogHandler(). */ 198 @Test 199 public void stopLoggingOnlyResetsLogHandlerIfHandlerWasRegistered() throws Exception { 200 final boolean verbosityToggle = false; // even default mode wants log events from HAL 201 mWifiDiagnostics.stopLogging(); 202 verify(mWifiNative, never()).resetLogHandler(); 203 } 204 205 /** Verifies that stopLogging() remembers that we've reset the log handler. */ 206 @Test 207 public void multipleStopLoggingCallsOnlyResetLogHandlerOnce() throws Exception { 208 final boolean verbosityToggle = false; // even default mode wants log events from HAL 209 210 when(mWifiNative.setLoggingEventHandler(anyObject())).thenReturn(true); 211 mWifiDiagnostics.startLogging(verbosityToggle); 212 reset(mWifiNative); 213 214 when(mWifiNative.resetLogHandler()).thenReturn(true); 215 mWifiDiagnostics.stopLogging(); 216 verify(mWifiNative).resetLogHandler(); 217 reset(mWifiNative); 218 219 mWifiDiagnostics.stopLogging(); 220 verify(mWifiNative, never()).resetLogHandler(); 221 } 222 223 /** 224 * Verifies that we capture ring-buffer data. 225 */ 226 @Test 227 public void canCaptureAndStoreRingBufferData() throws Exception { 228 final boolean verbosityToggle = false; 229 mWifiDiagnostics.startLogging(verbosityToggle); 230 231 final byte[] data = new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE]; 232 mWifiDiagnostics.onRingBufferData(mFakeRbs, data); 233 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 234 235 byte[][] ringBufferData = getLoggerRingBufferData(); 236 assertEquals(1, ringBufferData.length); 237 assertArrayEquals(data, ringBufferData[0]); 238 } 239 240 /** 241 * Verifies that we discard extraneous ring-buffer data. 242 */ 243 @Test 244 public void loggerDiscardsExtraneousData() throws Exception { 245 final boolean verbosityToggle = false; 246 mWifiDiagnostics.startLogging(verbosityToggle); 247 248 final byte[] data1 = new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE]; 249 final byte[] data2 = {1, 2, 3}; 250 mWifiDiagnostics.onRingBufferData(mFakeRbs, data1); 251 mWifiDiagnostics.onRingBufferData(mFakeRbs, data2); 252 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 253 254 byte[][] ringBufferData = getLoggerRingBufferData(); 255 assertEquals(1, ringBufferData.length); 256 assertArrayEquals(data2, ringBufferData[0]); 257 } 258 259 /** 260 * Verifies that, when verbose mode is not enabled, startLogging() calls 261 * startPktFateMonitoring(). 262 */ 263 @Test 264 public void startLoggingStartsPacketFateWithoutVerboseMode() { 265 final boolean verbosityToggle = false; 266 mWifiDiagnostics.startLogging(verbosityToggle); 267 verify(mWifiNative).startPktFateMonitoring(); 268 } 269 270 /** 271 * Verifies that, when verbose mode is enabled, startLogging() calls 272 * startPktFateMonitoring(). 273 */ 274 @Test 275 public void startLoggingStartsPacketFateInVerboseMode() { 276 final boolean verbosityToggle = true; 277 mWifiDiagnostics.startLogging(verbosityToggle); 278 verify(mWifiNative).startPktFateMonitoring(); 279 } 280 281 // Verifies that startLogging() reports failure of startPktFateMonitoring(). 282 @Test 283 public void startLoggingReportsFailureOfStartPktFateMonitoring() { 284 final boolean verbosityToggle = true; 285 when(mWifiNative.startPktFateMonitoring()).thenReturn(false); 286 mWifiDiagnostics.startLogging(verbosityToggle); 287 verify(mLog).wC(contains("Failed")); 288 } 289 290 /** 291 * Verifies that, when verbose mode is not enabled, 292 * reportConnectionEvent(WifiDiagnostics.CONNECTION_EVENT_FAILED) still fetches packet fates. 293 */ 294 @Test 295 public void reportConnectionFailureIsIgnoredWithoutVerboseMode() { 296 final boolean verbosityToggle = false; 297 mWifiDiagnostics.startLogging(verbosityToggle); 298 mWifiDiagnostics.reportConnectionEvent( 299 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 300 verify(mWifiNative).getTxPktFates(anyObject()); 301 verify(mWifiNative).getRxPktFates(anyObject()); 302 } 303 304 /** 305 * Verifies that, when verbose mode is enabled, reportConnectionFailure() fetches packet fates. 306 */ 307 @Test 308 public void reportConnectionFailureFetchesFatesInVerboseMode() { 309 final boolean verbosityToggle = true; 310 mWifiDiagnostics.startLogging(verbosityToggle); 311 mWifiDiagnostics.reportConnectionEvent( 312 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 313 verify(mWifiNative).getTxPktFates(anyObject()); 314 verify(mWifiNative).getRxPktFates(anyObject()); 315 } 316 317 @Test 318 public void reportConnectionEventPropagatesStartToLastMileLogger() { 319 final boolean verbosityToggle = false; 320 mWifiDiagnostics.startLogging(verbosityToggle); 321 mWifiDiagnostics.reportConnectionEvent( 322 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_STARTED); 323 verify(mLastMileLogger).reportConnectionEvent( 324 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_STARTED); 325 } 326 327 @Test 328 public void reportConnectionEventPropagatesSuccessToLastMileLogger() { 329 final boolean verbosityToggle = false; 330 mWifiDiagnostics.startLogging(verbosityToggle); 331 mWifiDiagnostics.reportConnectionEvent( 332 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_SUCCEEDED); 333 verify(mLastMileLogger).reportConnectionEvent( 334 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_SUCCEEDED); 335 } 336 337 @Test 338 public void reportConnectionEventPropagatesFailureToLastMileLogger() { 339 final boolean verbosityToggle = false; 340 mWifiDiagnostics.startLogging(verbosityToggle); 341 mWifiDiagnostics.reportConnectionEvent( 342 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 343 verify(mLastMileLogger).reportConnectionEvent( 344 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 345 } 346 347 /** 348 * Verifies that we try to fetch TX fates, even if fetching RX fates failed. 349 */ 350 @Test 351 public void loggerFetchesTxFatesEvenIfFetchingRxFatesFails() { 352 final boolean verbosityToggle = true; 353 when(mWifiNative.getRxPktFates(anyObject())).thenReturn(false); 354 mWifiDiagnostics.startLogging(verbosityToggle); 355 mWifiDiagnostics.reportConnectionEvent( 356 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 357 verify(mWifiNative).getTxPktFates(anyObject()); 358 verify(mWifiNative).getRxPktFates(anyObject()); 359 } 360 361 /** 362 * Verifies that we try to fetch RX fates, even if fetching TX fates failed. 363 */ 364 @Test 365 public void loggerFetchesRxFatesEvenIfFetchingTxFatesFails() { 366 final boolean verbosityToggle = true; 367 when(mWifiNative.getTxPktFates(anyObject())).thenReturn(false); 368 mWifiDiagnostics.startLogging(verbosityToggle); 369 mWifiDiagnostics.reportConnectionEvent( 370 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 371 verify(mWifiNative).getTxPktFates(anyObject()); 372 verify(mWifiNative).getRxPktFates(anyObject()); 373 } 374 375 /** Verifies that dump() fetches the latest fates. */ 376 @Test 377 public void dumpFetchesFates() { 378 final boolean verbosityToggle = false; 379 StringWriter sw = new StringWriter(); 380 PrintWriter pw = new PrintWriter(sw); 381 mWifiDiagnostics.startLogging(verbosityToggle); 382 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{"bogus", "args"}); 383 verify(mWifiNative).getTxPktFates(anyObject()); 384 verify(mWifiNative).getRxPktFates(anyObject()); 385 } 386 387 /** 388 * Verifies that dump() doesn't crash, or generate garbage, in the case where we haven't fetched 389 * any fates. 390 */ 391 @Test 392 public void dumpSucceedsWhenNoFatesHaveNotBeenFetched() { 393 StringWriter sw = new StringWriter(); 394 PrintWriter pw = new PrintWriter(sw); 395 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{"bogus", "args"}); 396 397 String fateDumpString = sw.toString(); 398 assertTrue(fateDumpString.contains("Last failed")); 399 // Verify dump terminator is present 400 assertTrue(fateDumpString.contains( 401 "--------------------------------------------------------------------")); 402 } 403 404 /** 405 * Verifies that dump() doesn't crash, or generate garbage, in the case where the fates that 406 * the HAL-provided fates are empty. 407 */ 408 @Test 409 public void dumpSucceedsWhenFatesHaveBeenFetchedButAreEmpty() { 410 final boolean verbosityToggle = true; 411 mWifiDiagnostics.startLogging(verbosityToggle); 412 mWifiDiagnostics.reportConnectionEvent( 413 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 414 verify(mWifiNative).getTxPktFates(anyObject()); 415 verify(mWifiNative).getRxPktFates(anyObject()); 416 417 StringWriter sw = new StringWriter(); 418 PrintWriter pw = new PrintWriter(sw); 419 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{"bogus", "args"}); 420 421 String fateDumpString = sw.toString(); 422 assertTrue(fateDumpString.contains("Last failed")); 423 // Verify dump terminator is present 424 assertTrue(fateDumpString.contains( 425 "--------------------------------------------------------------------")); 426 } 427 428 private String getDumpString(boolean verbose) { 429 mWifiDiagnostics.startLogging(verbose); 430 mWifiNative.enableVerboseLogging(verbose ? 1 : 0); 431 when(mWifiNative.getTxPktFates(anyObject())).then(new AnswerWithArguments() { 432 public boolean answer(WifiNative.TxFateReport[] fates) { 433 fates[0] = new WifiNative.TxFateReport( 434 WifiLoggerHal.TX_PKT_FATE_ACKED, 2, WifiLoggerHal.FRAME_TYPE_ETHERNET_II, 435 new byte[0] 436 ); 437 fates[1] = new WifiNative.TxFateReport( 438 WifiLoggerHal.TX_PKT_FATE_ACKED, 0, WifiLoggerHal.FRAME_TYPE_ETHERNET_II, 439 new byte[0] 440 ); 441 return true; 442 } 443 }); 444 when(mWifiNative.getRxPktFates(anyObject())).then(new AnswerWithArguments() { 445 public boolean answer(WifiNative.RxFateReport[] fates) { 446 fates[0] = new WifiNative.RxFateReport( 447 WifiLoggerHal.RX_PKT_FATE_SUCCESS, 3, WifiLoggerHal.FRAME_TYPE_ETHERNET_II, 448 new byte[0] 449 ); 450 fates[1] = new WifiNative.RxFateReport( 451 WifiLoggerHal.RX_PKT_FATE_SUCCESS, 1, WifiLoggerHal.FRAME_TYPE_ETHERNET_II, 452 new byte[0] 453 ); 454 return true; 455 } 456 }); 457 mWifiDiagnostics.reportConnectionEvent( 458 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 459 460 StringWriter sw = new StringWriter(); 461 PrintWriter pw = new PrintWriter(sw); 462 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{"bogus", "args"}); 463 return sw.toString(); 464 } 465 466 /** 467 * Verifies that dump() shows both TX, and RX fates in only table form, when verbose 468 * logging is not enabled. 469 */ 470 @Test 471 public void dumpShowsTxAndRxFates() { 472 final boolean verbosityToggle = false; 473 String dumpString = getDumpString(verbosityToggle); 474 assertTrue(dumpString.contains(WifiNative.FateReport.getTableHeader())); 475 assertTrue(Pattern.compile("0 .* TX ").matcher(dumpString).find()); 476 assertTrue(Pattern.compile("1 .* RX ").matcher(dumpString).find()); 477 assertTrue(Pattern.compile("2 .* TX ").matcher(dumpString).find()); 478 assertTrue(Pattern.compile("3 .* RX ").matcher(dumpString).find()); 479 assertFalse(dumpString.contains("VERBOSE PACKET FATE DUMP")); 480 assertFalse(dumpString.contains("Frame bytes")); 481 } 482 483 /** 484 * Verifies that dump() shows both TX, and RX fates in table and verbose forms, when verbose 485 * logging is enabled. 486 */ 487 @Test 488 public void dumpShowsTxAndRxFatesVerbose() { 489 final boolean verbosityToggle = true; 490 String dumpString = getDumpString(verbosityToggle); 491 assertTrue(dumpString.contains(WifiNative.FateReport.getTableHeader())); 492 assertTrue(Pattern.compile("0 .* TX ").matcher(dumpString).find()); 493 assertTrue(Pattern.compile("1 .* RX ").matcher(dumpString).find()); 494 assertTrue(Pattern.compile("2 .* TX ").matcher(dumpString).find()); 495 assertTrue(Pattern.compile("3 .* RX ").matcher(dumpString).find()); 496 assertTrue(dumpString.contains("VERBOSE PACKET FATE DUMP")); 497 assertTrue(dumpString.contains("Frame bytes")); 498 } 499 500 /** 501 * Verifies that dump() outputs frames in timestamp order, even though the HAL provided the 502 * data out-of-order (order is specified in getDumpString()). 503 */ 504 @Test 505 public void dumpIsSortedByTimestamp() { 506 final boolean verbosityToggle = true; 507 String dumpString = getDumpString(verbosityToggle); 508 assertTrue(dumpString.contains(WifiNative.FateReport.getTableHeader())); 509 assertTrue(Pattern.compile( 510 "0 .* TX .*\n" + 511 "1 .* RX .*\n" + 512 "2 .* TX .*\n" + 513 "3 .* RX " 514 ).matcher(dumpString).find()); 515 516 int expected_index_of_verbose_frame_0 = dumpString.indexOf( 517 "Frame direction: TX\nFrame timestamp: 0\n"); 518 int expected_index_of_verbose_frame_1 = dumpString.indexOf( 519 "Frame direction: RX\nFrame timestamp: 1\n"); 520 int expected_index_of_verbose_frame_2 = dumpString.indexOf( 521 "Frame direction: TX\nFrame timestamp: 2\n"); 522 int expected_index_of_verbose_frame_3 = dumpString.indexOf( 523 "Frame direction: RX\nFrame timestamp: 3\n"); 524 assertFalse(-1 == expected_index_of_verbose_frame_0); 525 assertFalse(-1 == expected_index_of_verbose_frame_1); 526 assertFalse(-1 == expected_index_of_verbose_frame_2); 527 assertFalse(-1 == expected_index_of_verbose_frame_3); 528 assertTrue(expected_index_of_verbose_frame_0 < expected_index_of_verbose_frame_1); 529 assertTrue(expected_index_of_verbose_frame_1 < expected_index_of_verbose_frame_2); 530 assertTrue(expected_index_of_verbose_frame_2 < expected_index_of_verbose_frame_3); 531 } 532 533 /** Verifies that eng builds do not show fate detail outside of verbose mode. */ 534 @Test 535 public void dumpOmitsFateDetailInEngBuildsOutsideOfVerboseMode() throws Exception { 536 final boolean verbosityToggle = false; 537 when(mBuildProperties.isEngBuild()).thenReturn(true); 538 when(mBuildProperties.isUserdebugBuild()).thenReturn(false); 539 when(mBuildProperties.isUserBuild()).thenReturn(false); 540 String dumpString = getDumpString(verbosityToggle); 541 assertFalse(dumpString.contains("VERBOSE PACKET FATE DUMP")); 542 assertFalse(dumpString.contains("Frame bytes")); 543 } 544 545 /** Verifies that userdebug builds do not show fate detail outside of verbose mode. */ 546 @Test 547 public void dumpOmitsFateDetailInUserdebugBuildsOutsideOfVerboseMode() throws Exception { 548 final boolean verbosityToggle = false; 549 when(mBuildProperties.isUserdebugBuild()).thenReturn(true); 550 when(mBuildProperties.isEngBuild()).thenReturn(false); 551 when(mBuildProperties.isUserBuild()).thenReturn(false); 552 String dumpString = getDumpString(verbosityToggle); 553 assertFalse(dumpString.contains("VERBOSE PACKET FATE DUMP")); 554 assertFalse(dumpString.contains("Frame bytes")); 555 } 556 557 /** 558 * Verifies that, if verbose is disabled after fetching fates, the dump does not include 559 * verbose fate logs. 560 */ 561 @Test 562 public void dumpOmitsFatesIfVerboseIsDisabledAfterFetch() { 563 final boolean verbosityToggle = true; 564 mWifiDiagnostics.startLogging(verbosityToggle); 565 when(mWifiNative.getTxPktFates(anyObject())).then(new AnswerWithArguments() { 566 public boolean answer(WifiNative.TxFateReport[] fates) { 567 fates[0] = new WifiNative.TxFateReport( 568 WifiLoggerHal.TX_PKT_FATE_ACKED, 0, WifiLoggerHal.FRAME_TYPE_ETHERNET_II, 569 new byte[0] 570 ); 571 return true; 572 } 573 }); 574 when(mWifiNative.getRxPktFates(anyObject())).then(new AnswerWithArguments() { 575 public boolean answer(WifiNative.RxFateReport[] fates) { 576 fates[0] = new WifiNative.RxFateReport( 577 WifiLoggerHal.RX_PKT_FATE_SUCCESS, 1, WifiLoggerHal.FRAME_TYPE_ETHERNET_II, 578 new byte[0] 579 ); 580 return true; 581 } 582 }); 583 mWifiDiagnostics.reportConnectionEvent( 584 FAKE_CONNECTION_ID, WifiDiagnostics.CONNECTION_EVENT_FAILED); 585 verify(mWifiNative).getTxPktFates(anyObject()); 586 verify(mWifiNative).getRxPktFates(anyObject()); 587 588 final boolean newVerbosityToggle = false; 589 mWifiDiagnostics.startLogging(newVerbosityToggle); 590 591 StringWriter sw = new StringWriter(); 592 PrintWriter pw = new PrintWriter(sw); 593 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{"bogus", "args"}); 594 595 String fateDumpString = sw.toString(); 596 assertFalse(fateDumpString.contains("VERBOSE PACKET FATE DUMP")); 597 assertFalse(fateDumpString.contains("Frame bytes")); 598 } 599 600 /** Verifies that the default size of our ring buffers is small. */ 601 @Test 602 public void ringBufferSizeIsSmallByDefault() throws Exception { 603 final boolean verbosityToggle = false; 604 mWifiDiagnostics.startLogging(verbosityToggle); 605 mWifiDiagnostics.onRingBufferData( 606 mFakeRbs, new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE + 1]); 607 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 608 assertEquals(0, getLoggerRingBufferData().length); 609 } 610 611 /** Verifies that we use small ring buffers by default, on userdebug builds. */ 612 @Test 613 public void ringBufferSizeIsSmallByDefaultOnUserdebugBuilds() throws Exception { 614 final boolean verbosityToggle = false; 615 when(mBuildProperties.isUserdebugBuild()).thenReturn(true); 616 when(mBuildProperties.isEngBuild()).thenReturn(false); 617 when(mBuildProperties.isUserBuild()).thenReturn(false); 618 mWifiDiagnostics.startLogging(verbosityToggle); 619 mWifiDiagnostics.onRingBufferData( 620 mFakeRbs, new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE + 1]); 621 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 622 assertEquals(0, getLoggerRingBufferData().length); 623 } 624 625 /** Verifies that we use small ring buffers by default, on eng builds. */ 626 @Test 627 public void ringBufferSizeIsSmallByDefaultOnEngBuilds() throws Exception { 628 final boolean verbosityToggle = false; 629 when(mBuildProperties.isEngBuild()).thenReturn(true); 630 when(mBuildProperties.isUserdebugBuild()).thenReturn(false); 631 when(mBuildProperties.isUserBuild()).thenReturn(false); 632 mWifiDiagnostics.startLogging(verbosityToggle); 633 mWifiDiagnostics.onRingBufferData( 634 mFakeRbs, new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE + 1]); 635 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 636 assertEquals(0, getLoggerRingBufferData().length); 637 } 638 639 /** Verifies that we use large ring buffers when initially started in verbose mode. */ 640 @Test 641 public void ringBufferSizeIsLargeInVerboseMode() throws Exception { 642 final boolean verbosityToggle = true; 643 mWifiDiagnostics.startLogging(verbosityToggle); 644 mWifiDiagnostics.onRingBufferData( 645 mFakeRbs, new byte[LARGE_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE]); 646 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 647 assertEquals(1, getLoggerRingBufferData().length); 648 } 649 650 /** Verifies that we use large ring buffers when switched from normal to verbose mode. */ 651 @Test 652 public void startLoggingGrowsRingBuffersIfNeeded() throws Exception { 653 mWifiDiagnostics.startLogging(false /* verbose disabled */); 654 mWifiDiagnostics.startLogging(true /* verbose enabled */); 655 mWifiDiagnostics.onRingBufferData( 656 mFakeRbs, new byte[LARGE_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE]); 657 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 658 assertEquals(1, getLoggerRingBufferData().length); 659 } 660 661 /** Verifies that we use small ring buffers when switched from verbose to normal mode. */ 662 @Test 663 public void startLoggingShrinksRingBuffersIfNeeded() throws Exception { 664 mWifiDiagnostics.startLogging(true /* verbose enabled */); 665 mWifiDiagnostics.onRingBufferData( 666 mFakeRbs, new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE + 1]); 667 668 // Existing data is nuked (too large). 669 mWifiDiagnostics.startLogging(false /* verbose disabled */); 670 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 671 assertEquals(0, getLoggerRingBufferData().length); 672 673 // New data must obey limit as well. 674 mWifiDiagnostics.onRingBufferData( 675 mFakeRbs, new byte[SMALL_RING_BUFFER_SIZE_KB * BYTES_PER_KBYTE + 1]); 676 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 677 assertEquals(0, getLoggerRingBufferData().length); 678 } 679 680 /** Verifies that we skip the firmware and driver dumps if verbose is not enabled. */ 681 @Test 682 public void captureBugReportSkipsFirmwareAndDriverDumpsByDefault() { 683 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 684 verify(mWifiNative, never()).getFwMemoryDump(); 685 verify(mWifiNative, never()).getDriverStateDump(); 686 } 687 688 /** Verifies that we capture the firmware and driver dumps if verbose is enabled. */ 689 @Test 690 public void captureBugReportTakesFirmwareAndDriverDumpsInVerboseMode() { 691 mWifiDiagnostics.startLogging(true /* verbose enabled */); 692 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 693 verify(mWifiNative).getFwMemoryDump(); 694 verify(mWifiNative).getDriverStateDump(); 695 } 696 697 /** Verifies that the dump includes driver state, if driver state was provided by HAL. */ 698 @Test 699 public void dumpIncludesDriverStateDumpIfAvailable() { 700 when(mWifiNative.getDriverStateDump()).thenReturn(new byte[]{0, 1, 2}); 701 702 mWifiDiagnostics.startLogging(true /* verbose enabled */); 703 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 704 verify(mWifiNative).getDriverStateDump(); 705 706 StringWriter sw = new StringWriter(); 707 PrintWriter pw = new PrintWriter(sw); 708 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{}); 709 assertTrue(sw.toString().contains(WifiDiagnostics.DRIVER_DUMP_SECTION_HEADER)); 710 } 711 712 /** Verifies that the dump skips driver state, if driver state was not provided by HAL. */ 713 @Test 714 public void dumpOmitsDriverStateDumpIfUnavailable() { 715 mWifiDiagnostics.startLogging(true /* verbose enabled */); 716 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 717 verify(mWifiNative).getDriverStateDump(); 718 719 StringWriter sw = new StringWriter(); 720 PrintWriter pw = new PrintWriter(sw); 721 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{}); 722 assertFalse(sw.toString().contains(WifiDiagnostics.DRIVER_DUMP_SECTION_HEADER)); 723 } 724 725 /** Verifies that the dump omits driver state, if verbose was disabled after capture. */ 726 @Test 727 public void dumpOmitsDriverStateDumpIfVerboseDisabledAfterCapture() { 728 when(mWifiNative.getDriverStateDump()).thenReturn(new byte[]{0, 1, 2}); 729 730 mWifiDiagnostics.startLogging(true /* verbose enabled */); 731 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 732 verify(mWifiNative).getDriverStateDump(); 733 734 mWifiDiagnostics.startLogging(false /* verbose no longer enabled */); 735 736 StringWriter sw = new StringWriter(); 737 PrintWriter pw = new PrintWriter(sw); 738 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{}); 739 assertFalse(sw.toString().contains(WifiDiagnostics.DRIVER_DUMP_SECTION_HEADER)); 740 } 741 742 /** Verifies that the dump includes firmware dump, if firmware dump was provided by HAL. */ 743 @Test 744 public void dumpIncludesFirmwareMemoryDumpIfAvailable() { 745 when(mWifiNative.getFwMemoryDump()).thenReturn(new byte[]{0, 1, 2}); 746 747 mWifiDiagnostics.startLogging(true /* verbose enabled */); 748 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 749 verify(mWifiNative).getFwMemoryDump(); 750 751 StringWriter sw = new StringWriter(); 752 PrintWriter pw = new PrintWriter(sw); 753 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{}); 754 assertTrue(sw.toString().contains(WifiDiagnostics.FIRMWARE_DUMP_SECTION_HEADER)); 755 } 756 757 /** Verifies that the dump skips firmware memory, if firmware memory was not provided by HAL. */ 758 @Test 759 public void dumpOmitsFirmwareMemoryDumpIfUnavailable() { 760 mWifiDiagnostics.startLogging(true /* verbose enabled */); 761 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 762 verify(mWifiNative).getFwMemoryDump(); 763 764 StringWriter sw = new StringWriter(); 765 PrintWriter pw = new PrintWriter(sw); 766 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{}); 767 assertFalse(sw.toString().contains(WifiDiagnostics.FIRMWARE_DUMP_SECTION_HEADER)); 768 } 769 770 /** Verifies that the dump omits firmware memory, if verbose was disabled after capture. */ 771 @Test 772 public void dumpOmitsFirmwareMemoryDumpIfVerboseDisabledAfterCapture() { 773 when(mWifiNative.getFwMemoryDump()).thenReturn(new byte[]{0, 1, 2}); 774 775 mWifiDiagnostics.startLogging(true /* verbose enabled */); 776 mWifiDiagnostics.captureBugReportData(WifiDiagnostics.REPORT_REASON_NONE); 777 verify(mWifiNative).getFwMemoryDump(); 778 779 mWifiDiagnostics.startLogging(false /* verbose no longer enabled */); 780 781 StringWriter sw = new StringWriter(); 782 PrintWriter pw = new PrintWriter(sw); 783 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{}); 784 assertFalse(sw.toString().contains(WifiDiagnostics.FIRMWARE_DUMP_SECTION_HEADER)); 785 } 786 787 /** Verifies that the dump() includes contents of WifiNative's LocalLog. */ 788 @Test 789 public void dumpIncludesContentOfWifiNativeLocalLog() { 790 final String wifiNativeLogMessage = "This is a message"; 791 mWifiNativeLocalLog.log(wifiNativeLogMessage); 792 793 mWifiDiagnostics.startLogging(false /* verbose disabled */); 794 StringWriter sw = new StringWriter(); 795 PrintWriter pw = new PrintWriter(sw); 796 mWifiDiagnostics.dump(new FileDescriptor(), pw, new String[]{}); 797 assertTrue(sw.toString().contains(wifiNativeLogMessage)); 798 } 799 800 @Test 801 public void dumpRequestsLastMileLoggerDump() { 802 mWifiDiagnostics.dump( 803 new FileDescriptor(), new PrintWriter(new StringWriter()), new String[]{}); 804 verify(mLastMileLogger).dump(anyObject()); 805 } 806} 807