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