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