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