WifiLastResortWatchdogTest.java revision 5f001750a0ce82a8b3a47ac566117d4de27f3e23
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.assertEquals;
20import static org.mockito.Mockito.*;
21
22import android.net.wifi.WifiConfiguration;
23import android.net.wifi.WifiSsid;
24import android.test.suitebuilder.annotation.SmallTest;
25import android.util.Pair;
26
27import org.junit.Before;
28import org.junit.Test;
29
30import java.util.ArrayList;
31import java.util.Arrays;
32import java.util.List;
33
34/**
35 * Unit tests for {@link com.android.server.wifi.WifiLastResortWatchdog}.
36 */
37@SmallTest
38public class WifiLastResortWatchdogTest {
39    WifiLastResortWatchdog mLastResortWatchdog;
40    WifiMetrics mWifiMetrics;
41    private String[] mSsids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""};
42    private String[] mBssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55",
43            "c0:ff:ee:ee:e3:ee"};
44    private int[] mFrequencies = {2437, 5180, 5180, 2437};
45    private String[] mCaps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]",
46            "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
47    private int[] mLevels = {-60, -86, -50, -62};
48    private boolean[] mIsEphemeral = {false, false, false, false};
49    private boolean[] mHasEverConnected = {false, false, false, false};
50
51    @Before
52    public void setUp() throws Exception {
53        mWifiMetrics = mock(WifiMetrics.class);
54        mLastResortWatchdog = new WifiLastResortWatchdog(mWifiMetrics);
55    }
56
57    private List<Pair<ScanDetail, WifiConfiguration>> createFilteredQnsCandidates(String[] ssids,
58            String[] bssids, int[] frequencies, String[] caps, int[] levels,
59            boolean[] isEphemeral) {
60        List<Pair<ScanDetail, WifiConfiguration>> candidates = new ArrayList<>();
61        long timeStamp = System.currentTimeMillis();
62        for (int index = 0; index < ssids.length; index++) {
63            String ssid = ssids[index].replaceAll("^\"+", "").replaceAll("\"+$", "");
64            ScanDetail scanDetail = new ScanDetail(WifiSsid.createFromAsciiEncoded(ssid),
65                    bssids[index], caps[index], levels[index], frequencies[index], timeStamp,
66                    0);
67            WifiConfiguration config = null;
68            if (!isEphemeral[index]) {
69                config = mock(WifiConfiguration.class);
70                WifiConfiguration.NetworkSelectionStatus networkSelectionStatus =
71                        mock(WifiConfiguration.NetworkSelectionStatus.class);
72                when(config.getNetworkSelectionStatus()).thenReturn(networkSelectionStatus);
73                when(networkSelectionStatus.getHasEverConnected()).thenReturn(true);
74            }
75            candidates.add(Pair.create(scanDetail, config));
76        }
77        return candidates;
78    }
79
80    private List<Pair<ScanDetail, WifiConfiguration>> createFilteredQnsCandidates(String[] ssids,
81            String[] bssids, int[] frequencies, String[] caps, int[] levels,
82            boolean[] isEphemeral, boolean[] hasEverConnected) {
83        List<Pair<ScanDetail, WifiConfiguration>> candidates =
84                new ArrayList<Pair<ScanDetail, WifiConfiguration>>();
85        long timeStamp = System.currentTimeMillis();
86        for (int index = 0; index < ssids.length; index++) {
87            String ssid = ssids[index].replaceAll("^\"+", "").replaceAll("\"+$", "");
88            ScanDetail scanDetail = new ScanDetail(WifiSsid.createFromAsciiEncoded(ssid),
89                    bssids[index], caps[index], levels[index], frequencies[index], timeStamp,
90                    0);
91            WifiConfiguration config = null;
92            if (!isEphemeral[index]) {
93                config = mock(WifiConfiguration.class);
94                WifiConfiguration.NetworkSelectionStatus networkSelectionStatus =
95                        mock(WifiConfiguration.NetworkSelectionStatus.class);
96                when(config.getNetworkSelectionStatus()).thenReturn(networkSelectionStatus);
97                when(networkSelectionStatus.getHasEverConnected())
98                        .thenReturn(hasEverConnected[index]);
99            }
100            candidates.add(Pair.create(scanDetail, config));
101        }
102        return candidates;
103    }
104
105    private void assertFailureCountEquals(
106            String bssid, int associationRejections, int authenticationFailures, int dhcpFailures) {
107        assertEquals(associationRejections, mLastResortWatchdog.getFailureCount(bssid,
108                WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION));
109        assertEquals(authenticationFailures, mLastResortWatchdog.getFailureCount(bssid,
110                WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION));
111        assertEquals(dhcpFailures, mLastResortWatchdog.getFailureCount(bssid,
112                WifiLastResortWatchdog.FAILURE_CODE_DHCP));
113    }
114
115    /**
116     * Case #1: Test aging works in available network buffering
117     * This test simulates 4 networks appearing in a scan result, and then only the first 2
118     * appearing in successive scans results.
119     * Expected Behavior:
120     * 4 networks appear in recentAvailalbeNetworks, after N=MAX_BSSID_AGE scans, only 2 remain
121     */
122    @Test
123    public void testAvailableNetworkBuffering_ageCullingWorks() throws Exception {
124        // Buffer potential candidates 1,2,3 & 4
125        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
126                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral);
127        mLastResortWatchdog.updateAvailableNetworks(candidates);
128        assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4);
129
130        // Repeatedly buffer candidates 1 & 2, MAX_BSSID_AGE - 1 times
131        candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 0, 2),
132                Arrays.copyOfRange(mBssids, 0, 2),
133                Arrays.copyOfRange(mFrequencies, 0, 2),
134                Arrays.copyOfRange(mCaps, 0, 2),
135                Arrays.copyOfRange(mLevels, 0, 2),
136                Arrays.copyOfRange(mIsEphemeral, 0, 2));
137        for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE - 1; i++) {
138            mLastResortWatchdog.updateAvailableNetworks(candidates);
139            assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[0]).age, 0);
140            assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[1]).age, 0);
141            assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[2]).age,
142                    i + 1);
143            assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[3]).age,
144                    i + 1);
145        }
146        assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4);
147
148        // One more buffering should age and cull candidates 2 & 3
149        mLastResortWatchdog.updateAvailableNetworks(candidates);
150        assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 2);
151    };
152
153    /**
154     * Case #2: Culling of old networks
155     * Part 1:
156     * This test starts with 4 networks seen, it then buffers N=MAX_BSSID_AGE empty scans
157     * Expected behaviour: All networks are culled from recentAvailableNetworks
158     *
159     * Part 2:
160     * Buffer some more empty scans just to make sure nothing breaks
161     */
162    @Test
163    public void testAvailableNetworkBuffering_emptyBufferWithEmptyScanResults() throws Exception {
164        // Buffer potential candidates 1,2,3 & 4
165        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
166                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral);
167        mLastResortWatchdog.updateAvailableNetworks(candidates);
168        assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4);
169
170        // Repeatedly buffer with no candidates
171        candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 0, 0),
172                Arrays.copyOfRange(mBssids, 0, 0),
173                Arrays.copyOfRange(mFrequencies, 0, 0),
174                Arrays.copyOfRange(mCaps, 0, 0),
175                Arrays.copyOfRange(mLevels, 0, 0),
176                Arrays.copyOfRange(mIsEphemeral, 0, 0));
177        for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE; i++) {
178            mLastResortWatchdog.updateAvailableNetworks(candidates);
179        }
180        assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 0);
181        for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE; i++) {
182            mLastResortWatchdog.updateAvailableNetworks(candidates);
183        }
184        assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 0);
185    };
186
187    /**
188     * Case 3: Adding more networks over time
189     * In this test, each successive (4 total) scan result buffers one more network.
190     * Expected behavior: recentAvailableNetworks grows with number of scan results
191     */
192    @Test
193    public void testAvailableNetworkBuffering_addNewNetworksOverTime() throws Exception {
194        List<Pair<ScanDetail, WifiConfiguration>> candidates;
195        // Buffer (i) scan results with each successive scan result
196        for (int i = 1; i <= mSsids.length; i++) {
197            candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 0, i),
198                    Arrays.copyOfRange(mBssids, 0, i),
199                    Arrays.copyOfRange(mFrequencies, 0, i),
200                    Arrays.copyOfRange(mCaps, 0, i),
201                    Arrays.copyOfRange(mLevels, 0, i),
202                    Arrays.copyOfRange(mIsEphemeral, 0, i));
203            mLastResortWatchdog.updateAvailableNetworks(candidates);
204            assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), i);
205            for (int j = 0; j < i; j++) {
206                assertEquals(
207                        mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[j]).age, 0);
208            }
209        }
210    };
211
212    /**
213     *  Case 4: Test buffering with ephemeral networks & toString()
214     *  This test is the same as Case 1, but it also includes ephemeral networks. toString is also
215     *  smoke tested at various places in this test
216     *  Expected behaviour: 4 networks added initially (2 ephemeral). After MAX_BSSID_AGE more
217     *  bufferings, 2 are culled (leaving 1 ephemeral, one normal). toString method should execute
218     *  without breaking anything.
219     */
220    @Test
221    public void testAvailableNetworkBuffering_multipleNetworksSomeEphemeral() throws Exception {
222        boolean[] isEphemeral = {true, false, true, false};
223
224        // Buffer potential candidates 1,2,3 & 4
225        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
226                mBssids, mFrequencies, mCaps, mLevels, isEphemeral);
227        mLastResortWatchdog.updateAvailableNetworks(candidates);
228        assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4);
229
230        // Repeatedly buffer candidates 1 & 2, MAX_BSSID_AGE - 1 times
231        candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 0, 2),
232                Arrays.copyOfRange(mBssids, 0, 2),
233                Arrays.copyOfRange(mFrequencies, 0, 2),
234                Arrays.copyOfRange(mCaps, 0, 2),
235                Arrays.copyOfRange(mLevels, 0, 2),
236                Arrays.copyOfRange(isEphemeral, 0, 2));
237        for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE - 1; i++) {
238            mLastResortWatchdog.updateAvailableNetworks(candidates);
239            mLastResortWatchdog.toString();
240            assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[0]).age, 0);
241            assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[1]).age, 0);
242            assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[2]).age,
243                    i + 1);
244            assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().get(mBssids[3]).age,
245                    i + 1);
246        }
247        assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 4);
248
249        // One more buffering should age and cull candidates 2 & 3
250        mLastResortWatchdog.updateAvailableNetworks(candidates);
251        assertEquals(mLastResortWatchdog.getRecentAvailableNetworks().size(), 2);
252        mLastResortWatchdog.toString();
253    };
254
255    /**
256     * Case 5: Test failure counting, incrementing a specific BSSID
257     * Test has 4 networks buffered, increment each different failure type on one of them
258     * Expected behaviour: See failure counts for the specific failures rise to the appropriate
259     * level for the specific network
260     */
261    @Test
262    public void testFailureCounting_countFailuresForSingleBssid() throws Exception {
263        int associationRejections = 5;
264        int authenticationFailures = 9;
265        int dhcpFailures = 11;
266        // Buffer potential candidates 1,2,3 & 4
267        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
268                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
269        mLastResortWatchdog.updateAvailableNetworks(candidates);
270
271        // Ensure new networks have zero'ed failure counts
272        for (int i = 0; i < mSsids.length; i++) {
273            assertFailureCountEquals(mBssids[i], 0, 0, 0);
274        }
275
276        //Increment failure count for each network and failure type
277        int net = 0;
278        for (int i = 0; i < associationRejections; i++) {
279            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
280                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
281            assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
282                    .get(mBssids[net]).associationRejection);
283        }
284        net = 1;
285        for (int i = 0; i < authenticationFailures; i++) {
286            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
287                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
288            assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
289                    .get(mBssids[net]).authenticationFailure);
290        }
291        net = 2;
292        for (int i = 0; i < dhcpFailures; i++) {
293            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
294                    WifiLastResortWatchdog.FAILURE_CODE_DHCP);
295            assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
296                    .get(mBssids[net]).dhcpFailure);
297        }
298        assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
299        assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
300        assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
301        assertFailureCountEquals(mBssids[3], 0, 0, 0);
302    }
303
304    /**
305     * Case 6: Test failure counting, incrementing a specific BSSID, with some ephemeral networks
306     * Almost identical to test case 5.
307     * Test has 4 networks buffered (two are ephemeral), increment each different failure type on
308     * one of them.
309     * Expected behavior: See failure counts for the specific failures rise to the appropriate
310     * level for the specific network
311     */
312    @Test
313    public void testFailureCounting_countFailuresForSingleBssidWithEphemeral() throws Exception {
314        int associationRejections = 5;
315        int authenticationFailures = 9;
316        int dhcpFailures = 11;
317        boolean[] mIsEphemeral = {false, true, false, true};
318        // Buffer potential candidates 1,2,3 & 4
319        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
320                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
321        mLastResortWatchdog.updateAvailableNetworks(candidates);
322
323        // Ensure new networks have zero'ed failure counts
324        for (int i = 0; i < mSsids.length; i++) {
325            assertFailureCountEquals(mBssids[i], 0, 0, 0);
326        }
327
328        //Increment failure count for each network and failure type
329        int net = 0;
330        for (int i = 0; i < associationRejections; i++) {
331            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
332                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
333            assertEquals(mLastResortWatchdog.getRecentAvailableNetworks()
334                    .get(mBssids[net]).associationRejection, i + 1);
335        }
336        net = 1;
337        for (int i = 0; i < authenticationFailures; i++) {
338            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
339                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
340            assertEquals(mLastResortWatchdog.getRecentAvailableNetworks()
341                    .get(mBssids[net]).authenticationFailure, i + 1);
342        }
343        net = 2;
344        for (int i = 0; i < dhcpFailures; i++) {
345            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
346                    WifiLastResortWatchdog.FAILURE_CODE_DHCP);
347            assertEquals(mLastResortWatchdog.getRecentAvailableNetworks()
348                    .get(mBssids[net]).dhcpFailure, i + 1);
349        }
350        assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
351        assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
352        assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
353        assertFailureCountEquals(mBssids[3], 0, 0, 0);
354    }
355
356    /**
357     * Case 7: Test failure counting, incrementing a specific BSSID but with the wrong SSID given
358     * Test has 4 networks buffered, increment each different failure type on one of them but using
359     * the wrong ssid.
360     * Expected behavior: Failure counts will remain at zero for all networks
361     */
362    @Test
363    public void testFailureCounting_countFailuresForSingleBssidWrongSsid() throws Exception {
364        String badSsid = "ItHertzWhenIP";
365        int associationRejections = 5;
366        int authenticationFailures = 9;
367        int dhcpFailures = 11;
368        // Buffer potential candidates 1,2,3 & 4
369        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
370                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
371        mLastResortWatchdog.updateAvailableNetworks(candidates);
372
373        // Ensure new networks have zero'ed failure counts
374        for (int i = 0; i < mSsids.length; i++) {
375            assertFailureCountEquals(mBssids[i], 0, 0, 0);
376        }
377
378        //Increment failure count for each network and failure type
379        int net = 0;
380        for (int i = 0; i < associationRejections; i++) {
381            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(badSsid, mBssids[net],
382                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
383        }
384        net = 1;
385        for (int i = 0; i < authenticationFailures; i++) {
386            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(badSsid, mBssids[net],
387                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
388        }
389        net = 2;
390        for (int i = 0; i < dhcpFailures; i++) {
391            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(badSsid, mBssids[net],
392                    WifiLastResortWatchdog.FAILURE_CODE_DHCP);
393        }
394
395        // Ensure all networks still have zero failure count
396        for (int i = 0; i < mSsids.length; i++) {
397            assertFailureCountEquals(mBssids[i], 0, 0, 0);
398        }
399    }
400
401    /**
402     * Case 8: Test failure counting, increment a bssid that does not exist
403     * Test has 4 networks buffered, increment each failure type, but using the wrong bssid
404     * Expected behavior: Failure counts will remain at zero for all networks
405     */
406    @Test
407    public void testFailureCounting_countFailuresForNonexistentBssid() throws Exception {
408        String badBssid = "de:ad:be:ee:e3:ef";
409        int associationRejections = 5;
410        int authenticationFailures = 9;
411        int dhcpFailures = 11;
412        // Buffer potential candidates 1,2,3 & 4
413        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
414                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
415        mLastResortWatchdog.updateAvailableNetworks(candidates);
416
417        // Ensure new networks have zero'ed failure counts
418        for (int i = 0; i < mSsids.length; i++) {
419            assertFailureCountEquals(mBssids[i], 0, 0, 0);
420        }
421
422        //Increment failure count for each network and failure type
423        int net = 0;
424        for (int i = 0; i < associationRejections; i++) {
425            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], badBssid,
426                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
427        }
428        net = 1;
429        for (int i = 0; i < authenticationFailures; i++) {
430            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], badBssid,
431                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
432        }
433        net = 2;
434        for (int i = 0; i < dhcpFailures; i++) {
435            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], badBssid,
436                    WifiLastResortWatchdog.FAILURE_CODE_DHCP);
437        }
438
439        // Ensure all networks still have zero failure count
440        for (int i = 0; i < mSsids.length; i++) {
441            assertFailureCountEquals(mBssids[i], 0, 0, 0);
442        }
443    }
444
445    /**
446     * Case 9: Test Failure Counting, using the "Any" BSSID
447     * Test has 4 buffered networks, two of which share the same SSID (different mBssids)
448     * Each failure type is incremented for the shared SSID, but with BSSID "any"
449     * Expected Behavior: Both networks increment their counts in tandem
450     */
451    @Test
452    public void testFailureCounting_countFailuresForAnyBssid() throws Exception {
453        String[] ssids = {"\"test1\"", "\"test2\"", "\"test1\"", "\"test4\""};
454        int associationRejections = 5;
455        int authenticationFailures = 9;
456        int dhcpFailures = 11;
457        // Buffer potential candidates 1,2,3 & 4
458        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids,
459                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
460        mLastResortWatchdog.updateAvailableNetworks(candidates);
461
462        // Ensure new networks have zero'ed failure counts
463        for (int i = 0; i < ssids.length; i++) {
464            assertFailureCountEquals(mBssids[i], 0, 0, 0);
465        }
466
467        //Increment failure count for each network and failure type
468        int net = 0;
469        for (int i = 0; i < associationRejections; i++) {
470            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
471                    ssids[0], WifiLastResortWatchdog.BSSID_ANY,
472                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
473        }
474        net = 1;
475        for (int i = 0; i < authenticationFailures; i++) {
476            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
477                    ssids[0], WifiLastResortWatchdog.BSSID_ANY,
478                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
479        }
480        net = 2;
481        for (int i = 0; i < dhcpFailures; i++) {
482            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
483                    ssids[0], WifiLastResortWatchdog.BSSID_ANY,
484                    WifiLastResortWatchdog.FAILURE_CODE_DHCP);
485        }
486        assertFailureCountEquals(mBssids[0], associationRejections, authenticationFailures,
487                dhcpFailures);
488        assertFailureCountEquals(mBssids[1], 0, 0, 0);
489        assertFailureCountEquals(mBssids[2], associationRejections, authenticationFailures,
490                dhcpFailures);
491        assertFailureCountEquals(mBssids[3], 0, 0, 0);
492    }
493
494    /**
495     * Case 10: Test Failure Counting, using the "Any" BSSID for nonexistent SSID
496     * Test has 4 buffered networks, two of which share the same SSID (different mBssids)
497     * Each failure type is incremented for a bad SSID (doesn't exist), but with BSSID "any"
498     * Expected Behavior: No Failures counted
499     */
500    @Test
501    public void testFailureCounting_countFailuresForAnyBssidNonexistentSsid() throws Exception {
502        int associationRejections = 5;
503        int authenticationFailures = 9;
504        int dhcpFailures = 11;
505        String badSsid = "DropItLikeIt'sHotSpot";
506        // Buffer potential candidates 1,2,3 & 4
507        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
508                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
509        mLastResortWatchdog.updateAvailableNetworks(candidates);
510
511        // Ensure new networks have zero'ed failure counts
512        for (int i = 0; i < mSsids.length; i++) {
513            assertFailureCountEquals(mBssids[i], 0, 0, 0);
514        }
515
516        //Increment failure count for each network and failure type
517        int net = 0;
518        for (int i = 0; i < associationRejections; i++) {
519            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
520                    badSsid, WifiLastResortWatchdog.BSSID_ANY,
521                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
522        }
523        net = 1;
524        for (int i = 0; i < authenticationFailures; i++) {
525            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
526                    badSsid, WifiLastResortWatchdog.BSSID_ANY,
527                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
528        }
529        net = 2;
530        for (int i = 0; i < dhcpFailures; i++) {
531            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
532                    badSsid, WifiLastResortWatchdog.BSSID_ANY,
533                    WifiLastResortWatchdog.FAILURE_CODE_DHCP);
534        }
535        // Check that all network failure counts are still zero
536        for (int i = 0; i < mSsids.length; i++) {
537            assertFailureCountEquals(mBssids[i], 0, 0, 0);
538        }
539    }
540
541    /**
542     * Case 11: Test Failure Counting, over failure Threshold check
543     * Test has 4 buffered networks, cause FAILURE_THRESHOLD failures for each failure type to one
544     * of each network (leaving one unfailed).
545     * Expected Behavior: 3 of the Available Networks report OverFailureThreshold
546     */
547    @Test
548    public void testFailureCounting_failureOverThresholdCheck() throws Exception {
549        int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD;
550        int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD;
551        int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD;
552        // Buffer potential candidates 1,2,3 & 4
553        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
554                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
555        mLastResortWatchdog.updateAvailableNetworks(candidates);
556
557        // Ensure new networks have zero'ed failure counts
558        for (int i = 0; i < mSsids.length; i++) {
559            assertFailureCountEquals(mBssids[i], 0, 0, 0);
560        }
561
562        //Increment failure count for each network and failure type
563        int net = 0;
564        for (int i = 0; i < associationRejections; i++) {
565            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
566                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
567        }
568        net = 1;
569        for (int i = 0; i < authenticationFailures; i++) {
570            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
571                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
572        }
573        net = 2;
574        for (int i = 0; i < dhcpFailures; i++) {
575            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
576                    WifiLastResortWatchdog.FAILURE_CODE_DHCP);
577        }
578        assertEquals(true, mLastResortWatchdog.isOverFailureThreshold(mBssids[0]));
579        assertEquals(true, mLastResortWatchdog.isOverFailureThreshold(mBssids[1]));
580        assertEquals(true, mLastResortWatchdog.isOverFailureThreshold(mBssids[2]));
581        assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[3]));
582    }
583
584    /**
585     * Case 12: Test Failure Counting, under failure Threshold check
586     * Test has 4 buffered networks, cause FAILURE_THRESHOLD - 1 failures for each failure type to
587     * one of each network (leaving one unfailed).
588     * Expected Behavior: 0 of the Available Networks report OverFailureThreshold
589     */
590    @Test
591    public void testFailureCounting_failureUnderThresholdCheck() throws Exception {
592        int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD - 1;
593        int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD - 1;
594        int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD - 1;
595        // Buffer potential candidates 1,2,3 & 4
596        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
597                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
598        mLastResortWatchdog.updateAvailableNetworks(candidates);
599
600        // Ensure new networks have zero'ed failure counts
601        for (int i = 0; i < mSsids.length; i++) {
602            assertFailureCountEquals(mBssids[i], 0, 0, 0);
603        }
604
605        //Increment failure count for each network and failure type
606        int net = 0;
607        for (int i = 0; i < associationRejections; i++) {
608            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
609                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
610        }
611        net = 1;
612        for (int i = 0; i < authenticationFailures; i++) {
613            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
614                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
615        }
616        net = 2;
617        for (int i = 0; i < dhcpFailures; i++) {
618            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
619                    WifiLastResortWatchdog.FAILURE_CODE_DHCP);
620        }
621        assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[0]));
622        assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[1]));
623        assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[2]));
624        assertEquals(false, mLastResortWatchdog.isOverFailureThreshold(mBssids[3]));
625    }
626
627    /**
628     * Case 13: Test Failure Counting, available network buffering does not affect counts
629     * In this test:
630     *   4 networks are buffered
631     *   Some number of failures are counted
632     *   networks are buffered again
633     * Expected Behavior: Failure counts are not modified by buffering
634     */
635    @Test
636    public void testAvailableNetworkBuffering_doesNotAffectFailureCounts() throws Exception {
637        int associationRejections = 5;
638        int authenticationFailures = 9;
639        int dhcpFailures = 11;
640        // Buffer potential candidates 1,2,3 & 4
641        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
642                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
643        mLastResortWatchdog.updateAvailableNetworks(candidates);
644
645        // Ensure new networks have zero'ed failure counts
646        for (int i = 0; i < mSsids.length; i++) {
647            assertFailureCountEquals(mBssids[i], 0, 0, 0);
648        }
649
650        //Increment failure count for each network and failure type
651        int net = 0;
652        for (int i = 0; i < associationRejections; i++) {
653            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
654                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
655            assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
656                    .get(mBssids[net]).associationRejection);
657        }
658        net = 1;
659        for (int i = 0; i < authenticationFailures; i++) {
660            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
661                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
662            assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
663                    .get(mBssids[net]).authenticationFailure);
664        }
665        net = 2;
666        for (int i = 0; i < dhcpFailures; i++) {
667            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
668                    WifiLastResortWatchdog.FAILURE_CODE_DHCP);
669            assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
670                    .get(mBssids[net]).dhcpFailure);
671        }
672        // Check Each Network has appropriate failure count
673        assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
674        assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
675        assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
676        assertFailureCountEquals(mBssids[3], 0, 0, 0);
677
678        // Re-buffer all networks
679        for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE; i++) {
680            mLastResortWatchdog.updateAvailableNetworks(candidates);
681        }
682
683        // Check Each Network still has appropriate failure count
684        assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
685        assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
686        assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
687        assertFailureCountEquals(mBssids[3], 0, 0, 0);
688    }
689
690    /**
691     * Case 14: Test Failure Counting, culling of an old network will remove its failure counts
692     * In this test:
693     *   4 networks are buffered
694     *   Some number of failures are counted for all networks
695     *   3 of the networks are buffered until the 4th dies of old age
696     *   The 4th network is re-buffered
697     * Expected Behavior: Failure counts for the 4th network are cleared after re-buffering
698     */
699    @Test
700    public void testAvailableNetworkBuffering_rebufferWipesCounts() throws Exception {
701        int associationRejections = 5;
702        int authenticationFailures = 9;
703        int dhcpFailures = 11;
704        // Buffer potential candidates 1,2,3 & 4
705        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
706                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
707        mLastResortWatchdog.updateAvailableNetworks(candidates);
708
709        // Ensure new networks have zero'ed failure counts
710        for (int i = 0; i < mSsids.length; i++) {
711            assertFailureCountEquals(mBssids[i], 0, 0, 0);
712        }
713
714        //Increment failure count for each network and failure type
715        int net = 0;
716        for (int i = 0; i < associationRejections; i++) {
717            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
718                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
719            assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
720                    .get(mBssids[net]).associationRejection);
721        }
722        net = 1;
723        for (int i = 0; i < authenticationFailures; i++) {
724            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
725                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
726            assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
727                    .get(mBssids[net]).authenticationFailure);
728        }
729        net = 2;
730        for (int i = 0; i < dhcpFailures; i++) {
731            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
732                    WifiLastResortWatchdog.FAILURE_CODE_DHCP);
733            assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
734                    .get(mBssids[net]).dhcpFailure);
735        }
736        // Check Each Network has appropriate failure count
737        assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
738        assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
739        assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
740        assertFailureCountEquals(mBssids[3], 0, 0, 0);
741
742        // Re-buffer all networks except 'test1' until it dies of old age
743        candidates = createFilteredQnsCandidates(Arrays.copyOfRange(mSsids, 1, 4),
744                Arrays.copyOfRange(mBssids, 1, 4),
745                Arrays.copyOfRange(mFrequencies, 1, 4),
746                Arrays.copyOfRange(mCaps, 1, 4),
747                Arrays.copyOfRange(mLevels, 1, 4),
748                Arrays.copyOfRange(mIsEphemeral, 1, 4));
749        for (int i = 0; i < WifiLastResortWatchdog.MAX_BSSID_AGE; i++) {
750            mLastResortWatchdog.updateAvailableNetworks(candidates);
751        }
752        assertEquals(3, mLastResortWatchdog.getRecentAvailableNetworks().size());
753        // Re-buffer All networks, with 'test1' again
754        candidates = createFilteredQnsCandidates(mSsids,
755                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
756        mLastResortWatchdog.updateAvailableNetworks(candidates);
757
758        // Check Each Network has appropriate failure count (network 1 should be zero'd)
759        assertFailureCountEquals(mBssids[0], 0, 0, 0);
760        assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
761        assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
762        assertFailureCountEquals(mBssids[3], 0, 0, 0);
763    }
764
765    /**
766     * Case 26: Test Failure Counting, null failure incrementation
767     * In this test:
768     *   4 networks are buffered
769     *   Attempt to increment failures with null BSSID & SSID
770     * Expected behavior: Nothing breaks, no counts incremented
771     */
772    @Test
773    public void testFailureCounting_nullInputsNoBreaky() {
774        int associationRejections = 5;
775        int authenticationFailures = 9;
776        int dhcpFailures = 11;
777        // Buffer potential candidates 1,2,3 & 4
778        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
779                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
780        mLastResortWatchdog.updateAvailableNetworks(candidates);
781
782        // Ensure new networks have zero'ed failure counts
783        for (int i = 0; i < mSsids.length; i++) {
784            assertFailureCountEquals(mBssids[i], 0, 0, 0);
785        }
786
787        //Increment failure count for each network and failure type
788        int net = 0;
789        for (int i = 0; i < associationRejections; i++) {
790            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(null, mBssids[net],
791                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
792        }
793        net = 1;
794        for (int i = 0; i < authenticationFailures; i++) {
795            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], null,
796                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
797        }
798        net = 2;
799        for (int i = 0; i < dhcpFailures; i++) {
800            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(null, null,
801                    WifiLastResortWatchdog.FAILURE_CODE_DHCP);
802        }
803
804        // Ensure new networks have zero'ed failure counts
805        for (int i = 0; i < mSsids.length; i++) {
806            assertFailureCountEquals(mBssids[i], 0, 0, 0);
807        }
808    }
809
810    /**
811     * Case 27: Test Failure Counting, test all failures are counted across SSID
812     * In this test there are 8 networks,
813     * the first 4 networks have unique SSIDs amongst themselves,
814     * the last 4 networks share these SSIDs respectively, so there are 2 networks per SSID
815     * In this test we increment failure counts for the 'test1' ssid for a specific BSSID, and for
816     * the 'test2' ssid for BSSID_ANY.
817     * Expected behaviour: Failure counts for both networks on the same SSID are mirrored via both
818     * incrementation methods
819     */
820    @Test
821    public void testFailureCounting_countFailuresAcrossSsids() throws Exception {
822        String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\"",
823                "\"test1\"", "\"test2\"", "\"test3\"", "\"test4\""};
824        String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55",
825                "c0:ff:ee:ee:e3:ee", "6c:f3:7f:ae:3c:f3", "6c:f3:7f:ae:3c:f4", "d3:ad:ba:b1:35:55",
826                "c0:ff:ee:ee:33:ee"};
827        int[] frequencies = {2437, 5180, 5180, 2437, 2437, 5180, 5180, 2437};
828        String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]",
829                "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]",
830                "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
831        int[] levels = {-60, -86, -50, -62, -60, -86, -50, -62};
832        boolean[] isEphemeral = {false, false, false, false, false, false, false, false};
833        boolean[] hasEverConnected = {false, false, false, false, false, false, false,
834                false};
835        int firstNetFails = 13;
836        int secondNetFails = 8;
837        // Buffer potential candidates 1,2,3 & 4
838        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids,
839                bssids, frequencies, caps, levels, isEphemeral, hasEverConnected);
840        mLastResortWatchdog.updateAvailableNetworks(candidates);
841
842        // Ensure new networks have zero'ed failure counts
843        for (int i = 0; i < ssids.length; i++) {
844            assertFailureCountEquals(bssids[i], 0, 0, 0);
845        }
846
847        //Increment failure count for the first test network ssid & bssid
848        for (int i = 0; i < firstNetFails; i++) {
849            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
850                    ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
851            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
852                    ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
853            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
854                    ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
855        }
856        //Increment failure count for the first test network ssid & BSSID_ANY
857        for (int i = 0; i < secondNetFails; i++) {
858            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
859                    ssids[1], WifiLastResortWatchdog.BSSID_ANY,
860                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
861            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
862                    ssids[1], WifiLastResortWatchdog.BSSID_ANY,
863                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
864            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
865                    ssids[1], WifiLastResortWatchdog.BSSID_ANY,
866                    WifiLastResortWatchdog.FAILURE_CODE_DHCP);
867        }
868        assertFailureCountEquals(bssids[0], firstNetFails, firstNetFails, firstNetFails);
869        assertFailureCountEquals(bssids[1], secondNetFails, secondNetFails, secondNetFails);
870        assertFailureCountEquals(bssids[2], 0, 0, 0);
871        assertFailureCountEquals(bssids[3], 0, 0, 0);
872        assertFailureCountEquals(bssids[4], firstNetFails, firstNetFails, firstNetFails);
873        assertFailureCountEquals(bssids[5], secondNetFails, secondNetFails, secondNetFails);
874        assertFailureCountEquals(bssids[6], 0, 0, 0);
875        assertFailureCountEquals(bssids[7], 0, 0, 0);
876    }
877
878    /**
879     * Case 15: Test failure counting, ensure failures still counted while connected
880     * Although failures should not occur while wifi is connected, race conditions are a thing, and
881     * I'd like the count to be incremented even while connected (Later test verifies that this
882     * can't cause a trigger though)
883     * Expected behavior: Failure counts increment like normal
884     */
885    @Test
886    public void testFailureCounting_wifiIsConnectedDoesNotAffectCounting() throws Exception {
887        int associationRejections = 5;
888        int authenticationFailures = 9;
889        int dhcpFailures = 11;
890
891        // Set Watchdogs internal wifi state tracking to 'connected'
892        mLastResortWatchdog.connectedStateTransition(true);
893
894        // Buffer potential candidates 1,2,3 & 4
895        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
896                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
897        mLastResortWatchdog.updateAvailableNetworks(candidates);
898
899        // Ensure new networks have zero'ed failure counts
900        for (int i = 0; i < mSsids.length; i++) {
901            assertFailureCountEquals(mBssids[i], 0, 0, 0);
902        }
903
904        //Increment failure count for each network and failure type
905        int net = 0;
906        for (int i = 0; i < associationRejections; i++) {
907            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
908                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
909            assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
910                    .get(mBssids[net]).associationRejection);
911        }
912        net = 1;
913        for (int i = 0; i < authenticationFailures; i++) {
914            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
915                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
916            assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
917                    .get(mBssids[net]).authenticationFailure);
918        }
919        net = 2;
920        for (int i = 0; i < dhcpFailures; i++) {
921            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
922                    WifiLastResortWatchdog.FAILURE_CODE_DHCP);
923            assertEquals(i + 1, mLastResortWatchdog.getRecentAvailableNetworks()
924                    .get(mBssids[net]).dhcpFailure);
925        }
926        assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
927        assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
928        assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
929        assertFailureCountEquals(mBssids[3], 0, 0, 0);
930    }
931
932    /**
933     * Case 16: Test Failure Counting, entering ConnectedState clears all failure counts
934     * 4 Networks are buffered, cause various failures to 3 of them. Transition to ConnectedState
935     * Expected behavior: After transitioning, failure counts are reset to 0
936     */
937    @Test
938    public void testFailureCounting_enteringWifiConnectedStateClearsCounts() throws Exception {
939        int associationRejections = 5;
940        int authenticationFailures = 9;
941        int dhcpFailures = 11;
942
943        // Buffer potential candidates 1,2,3 & 4
944        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
945                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
946        mLastResortWatchdog.updateAvailableNetworks(candidates);
947
948        //Increment failure count for each network and failure type
949        int net = 0;
950        for (int i = 0; i < associationRejections; i++) {
951            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
952                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
953        }
954        net = 1;
955        for (int i = 0; i < authenticationFailures; i++) {
956            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
957                    WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
958        }
959        net = 2;
960        for (int i = 0; i < dhcpFailures; i++) {
961            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(mSsids[net], mBssids[net],
962                    WifiLastResortWatchdog.FAILURE_CODE_DHCP);
963        }
964
965        // Check that we have Failures
966        assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
967        assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
968        assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
969
970        // Transition to 'ConnectedState'
971        mLastResortWatchdog.connectedStateTransition(true);
972
973        // Check that we have no failures
974        for (int i = 0; i < mSsids.length; i++) {
975            assertFailureCountEquals(mBssids[i], 0, 0, 0);
976        }
977    }
978
979    /**
980     * Case 17: Test Trigger Condition, only some networks over threshold
981     * We have 4 buffered networks, increment failure counts on 3 of them, until all 3 are over
982     * threshold.
983     * Expected Behavior: Watchdog does not trigger
984     */
985    @Test
986    public void testTriggerCondition_someNetworksOverFailureThreshold_allHaveEverConnected()
987            throws Exception {
988        int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD;
989        int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
990        int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
991        boolean[] hasEverConnected = {true, true, true, true};
992
993        // Buffer potential candidates 1,2,3 & 4
994        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
995                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, hasEverConnected);
996        mLastResortWatchdog.updateAvailableNetworks(candidates);
997
998        // Increment failure count for 3 networks and failure types, asserting each time that it
999        // does not trigger, with only 3 over threshold
1000        boolean watchdogTriggered = false;
1001        int net = 0;
1002        for (int i = 0; i < associationRejections; i++) {
1003            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1004                mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1005            assertEquals(false, watchdogTriggered);
1006        }
1007        net = 1;
1008        for (int i = 0; i < authenticationFailures; i++) {
1009            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1010                mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
1011            assertEquals(false, watchdogTriggered);
1012        }
1013        net = 2;
1014        for (int i = 0; i < dhcpFailures; i++) {
1015            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1016                mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
1017            assertEquals(false, watchdogTriggered);
1018        }
1019
1020        // Check that we have Failures
1021        assertFailureCountEquals(mBssids[0], associationRejections, 0, 0);
1022        assertFailureCountEquals(mBssids[1], 0, authenticationFailures, 0);
1023        assertFailureCountEquals(mBssids[2], 0, 0, dhcpFailures);
1024
1025        // Add one more failure to one of the already over threshold networks, assert that it
1026        // does not trigger
1027        watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1028                    mSsids[0], mBssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1029        assertEquals(false, watchdogTriggered);
1030    }
1031
1032    /**
1033     * Case 18: Test Trigger Condition, watchdog fires once, then deactivates
1034     * In this test we have 4 networks, which we have connected to in the past. Failures are
1035     * incremented until all networks but one are over failure threshold, and then a few more times.
1036     *
1037     * Expected behavior: The watchdog triggers once as soon as all failures are over threshold,
1038     * but stops triggering for subsequent failures
1039     */
1040    @Test
1041    public void testTriggerCondition_allNetworksOverFailureThreshold_allHaveEverConnected()
1042            throws Exception {
1043        int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD;
1044        int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
1045        int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
1046        boolean[] hasEverConnected = {true, true, true, true};
1047
1048        // Buffer potential candidates 1,2,3 & 4
1049        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
1050                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, hasEverConnected);
1051        mLastResortWatchdog.updateAvailableNetworks(candidates);
1052
1053        // Bring 3 of the 4 networks over failure Threshold without triggering watchdog
1054        boolean watchdogTriggered = false;
1055        int net = 0;
1056        for (int i = 0; i < associationRejections; i++) {
1057            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1058                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1059            assertEquals(false, watchdogTriggered);
1060        }
1061        net = 1;
1062        for (int i = 0; i < authenticationFailures; i++) {
1063            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1064                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
1065            assertEquals(false, watchdogTriggered);
1066        }
1067        net = 2;
1068        for (int i = 0; i < dhcpFailures; i++) {
1069            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1070                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
1071            assertEquals(false, watchdogTriggered);
1072        }
1073
1074        // Bring the remaining unfailed network upto 1 less than the failure threshold
1075        net = 3;
1076        for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD - 1; i++) {
1077            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1078                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1079            assertEquals(false, watchdogTriggered);
1080        }
1081        // Increment failure count once more, check that watchdog triggered this time
1082        watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1083                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1084        mLastResortWatchdog.updateAvailableNetworks(candidates);
1085        assertEquals(true, watchdogTriggered);
1086
1087        // Increment failure count 5 more times, watchdog should not trigger
1088        for (int i = 0; i < 5; i++) {
1089            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1090                        mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1091            assertEquals(false, watchdogTriggered);
1092        }
1093    }
1094
1095    /**
1096     * Case 19: Test Trigger Condition, all networks over failure threshold, one has ever connected
1097     * In this test we have 4 networks, only one has connected in the past. Failures are
1098     * incremented until all networks but one are over failure threshold, and then a few more times.
1099     *
1100     * Expected behavior: The watchdog triggers once as soon as all failures are over threshold,
1101     * but stops triggering for subsequent failures
1102     */
1103    @Test
1104    public void testTriggerCondition_allNetworksOverFailureThreshold_oneHaveEverConnected()
1105            throws Exception {
1106        int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD;
1107        int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
1108        int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
1109        boolean[] hasEverConnected = {false, true, false, false};
1110
1111        // Buffer potential candidates 1,2,3 & 4
1112        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
1113                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, hasEverConnected);
1114        mLastResortWatchdog.updateAvailableNetworks(candidates);
1115
1116        // Bring 3 of the 4 networks over failure Threshold without triggering watchdog
1117        boolean watchdogTriggered = false;
1118        int net = 0;
1119        for (int i = 0; i < associationRejections; i++) {
1120            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1121                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1122            assertEquals(false, watchdogTriggered);
1123        }
1124        net = 1;
1125        for (int i = 0; i < authenticationFailures; i++) {
1126            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1127                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
1128            assertEquals(false, watchdogTriggered);
1129        }
1130        net = 2;
1131        for (int i = 0; i < dhcpFailures; i++) {
1132            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1133                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
1134            assertEquals(false, watchdogTriggered);
1135        }
1136
1137        // Bring the remaining unfailed network upto 1 less than the failure threshold
1138        net = 3;
1139        for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD - 1; i++) {
1140            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1141                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1142            assertEquals(false, watchdogTriggered);
1143        }
1144        // Increment failure count once more, check that watchdog triggered this time
1145        watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1146                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1147        mLastResortWatchdog.updateAvailableNetworks(candidates);
1148        assertEquals(true, watchdogTriggered);
1149
1150        // Increment failure count 5 more times, watchdog should not trigger
1151        for (int i = 0; i < 5; i++) {
1152            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1153                        mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1154            assertEquals(false, watchdogTriggered);
1155        }
1156    }
1157
1158    /**
1159     * Case 20: Test Trigger Condition, all networks over failure threshold, 0 have ever connected
1160     * In this test we have 4 networks, none have ever connected. Failures are
1161     * incremented until all networks but one are over failure threshold, and then a few more times.
1162     *
1163     * Expected behavior: The watchdog does not trigger
1164     */
1165    @Test
1166    public void testTriggerCondition_allNetworksOverFailureThreshold_zeroHaveEverConnected()
1167            throws Exception {
1168        int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD + 1;
1169        int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
1170        int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
1171
1172        // Buffer potential candidates 1,2,3 & 4
1173        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
1174                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
1175        mLastResortWatchdog.updateAvailableNetworks(candidates);
1176
1177        // Count failures on all 4 networks until all of them are over the failure threshold
1178        boolean watchdogTriggered = false;
1179        int net = 0;
1180        for (int i = 0; i < associationRejections; i++) {
1181            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1182                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1183            assertEquals(false, watchdogTriggered);
1184        }
1185        net = 1;
1186        for (int i = 0; i < authenticationFailures; i++) {
1187            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1188                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
1189            assertEquals(false, watchdogTriggered);
1190        }
1191        net = 2;
1192        for (int i = 0; i < dhcpFailures; i++) {
1193            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1194                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
1195            assertEquals(false, watchdogTriggered);
1196        }
1197        net = 3;
1198        for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD + 1; i++) {
1199            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1200                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1201            assertEquals(false, watchdogTriggered);
1202        }
1203    }
1204
1205    /**
1206     * Case 21: Test Trigger Condition, Conditions right to trigger, but wifi is connected
1207     * In this test we have 4 networks, all have connected in the past
1208     * incremented until all networks but one are over failure threshold, and then a few more times.
1209     *
1210     * Expected behavior: The watchdog does not trigger
1211     */
1212    @Test
1213    public void testTriggerCondition_allNetworksOverFailureThreshold_isConnected()
1214        throws Exception {
1215        int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD + 1;
1216        int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
1217        int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
1218
1219        // Buffer potential candidates 1,2,3 & 4
1220        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
1221                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, mHasEverConnected);
1222        mLastResortWatchdog.updateAvailableNetworks(candidates);
1223
1224        // Set Watchdogs internal wifi state tracking to 'connected'
1225        mLastResortWatchdog.connectedStateTransition(true);
1226
1227        // Count failures on all 4 networks until all of them are over the failure threshold
1228        boolean watchdogTriggered = false;
1229        int net = 0;
1230        for (int i = 0; i < associationRejections; i++) {
1231            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1232                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1233            assertEquals(false, watchdogTriggered);
1234        }
1235        net = 1;
1236        for (int i = 0; i < authenticationFailures; i++) {
1237            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1238                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
1239            assertEquals(false, watchdogTriggered);
1240        }
1241        net = 2;
1242        for (int i = 0; i < dhcpFailures; i++) {
1243            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1244                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
1245            assertEquals(false, watchdogTriggered);
1246        }
1247        net = 3;
1248        for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD + 1; i++) {
1249            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1250                    mSsids[net], mBssids[net], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1251            assertEquals(false, watchdogTriggered);
1252        }
1253    }
1254
1255    private void incrementFailuresUntilTrigger(String[] ssids, String[] bssids) {
1256        // Bring 3 of the 4 networks over failure Threshold without triggering watchdog
1257        boolean watchdogTriggered = false;
1258        for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) {
1259            for (int j = 0; j < ssids.length - 1; j++) {
1260                watchdogTriggered = mLastResortWatchdog
1261                        .noteConnectionFailureAndTriggerIfNeeded(ssids[j], bssids[j],
1262                        WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1263                assertEquals(false, watchdogTriggered);
1264            }
1265        }
1266        for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD - 1; i++) {
1267            watchdogTriggered = mLastResortWatchdog
1268                    .noteConnectionFailureAndTriggerIfNeeded(ssids[ssids.length - 1],
1269                    bssids[ssids.length - 1], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1270            assertEquals(false, watchdogTriggered);
1271        }
1272
1273        // Increment failure count once more, check that watchdog triggered this time
1274        watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1275                    ssids[ssids.length - 1], bssids[ssids.length - 1],
1276                    WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1277        assertEquals(true, watchdogTriggered);
1278    }
1279
1280    /**
1281     * Case 22: Test enabling/disabling of Watchdog Trigger, disabled after triggering
1282     * In this test, we have 4 networks. Increment failures until Watchdog triggers. Increment some
1283     * more failures.
1284     * Expected behavior: Watchdog trigger gets deactivated after triggering, and stops triggering
1285     */
1286    @Test
1287    public void testTriggerEnabling_disabledAfterTriggering() throws Exception {
1288        int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD;
1289        int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
1290        int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
1291        boolean[] hasEverConnected = {false, true, false, false};
1292
1293        // Buffer potential candidates 1,2,3 & 4
1294        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
1295                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, hasEverConnected);
1296        mLastResortWatchdog.updateAvailableNetworks(candidates);
1297
1298        incrementFailuresUntilTrigger(mSsids, mBssids);
1299
1300        // Increment failure count 5 more times, watchdog should not trigger
1301        for (int i = 0; i < 5; i++) {
1302            boolean watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1303                        mSsids[3], mBssids[3], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1304            assertEquals(false, watchdogTriggered);
1305        }
1306    }
1307
1308    /**
1309     * Case 23: Test enabling/disabling of Watchdog Trigger, trigger re-enabled after connecting
1310     * In this test, we have 4 networks. Increment failures until Watchdog triggers and deactivates,
1311     * transition wifi to connected state, then increment failures until all networks over threshold
1312     * Expected behavior: Watchdog able to trigger again after transitioning to and from connected
1313     * state
1314     */
1315    @Test
1316    public void testTriggerEnabling_enabledAfterConnecting() throws Exception {
1317        int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD;
1318        int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
1319        int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
1320        boolean[] hasEverConnected = {false, true, false, false};
1321        boolean watchdogTriggered;
1322        // Buffer potential candidates 1,2,3 & 4
1323        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(mSsids,
1324                mBssids, mFrequencies, mCaps, mLevels, mIsEphemeral, hasEverConnected);
1325        mLastResortWatchdog.updateAvailableNetworks(candidates);
1326
1327        incrementFailuresUntilTrigger(mSsids, mBssids);
1328
1329        // Increment failure count 5 more times, ensure trigger is deactivated
1330        for (int i = 0; i < 5; i++) {
1331            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1332                        mSsids[3], mBssids[3], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1333            mLastResortWatchdog.updateAvailableNetworks(candidates);
1334            assertEquals(false, watchdogTriggered);
1335        }
1336
1337        // transition Watchdog wifi state tracking to 'connected' then back to 'disconnected'
1338        mLastResortWatchdog.connectedStateTransition(true);
1339        mLastResortWatchdog.connectedStateTransition(false);
1340
1341        // Fail 3/4 networks until they're over threshold
1342        for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD + 1; i++) {
1343            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1344                    mSsids[0], mBssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1345            assertEquals(false, watchdogTriggered);
1346            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1347                    mSsids[1], mBssids[1], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
1348            assertEquals(false, watchdogTriggered);
1349            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1350                    mSsids[2], mBssids[2], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
1351            assertEquals(false, watchdogTriggered);
1352        }
1353
1354        // Bring the remaining unfailed network upto 1 less than the failure threshold
1355        for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD - 1; i++) {
1356            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1357                    mSsids[3], mBssids[3], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1358            assertEquals(false, watchdogTriggered);
1359        }
1360        // Increment failure count once more, check that watchdog triggered this time
1361        watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1362                    mSsids[3], mBssids[3], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1363        assertEquals(true, watchdogTriggered);
1364    }
1365
1366    /**
1367     * Case 24: Test enabling/disabling of Watchdog Trigger, trigger re-enabled after new network
1368     * In this test, we have 3 networks. Increment failures until Watchdog triggers and deactivates,
1369     * we then buffer a new network (network 4), then increment failures until all networks over
1370     * threshold Expected behavior: Watchdog able to trigger again after discovering a new network
1371     */
1372    @Test
1373    public void testTriggerEnabling_enabledAfterNewNetwork() {
1374        int associationRejections = WifiLastResortWatchdog.FAILURE_THRESHOLD;
1375        int authenticationFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 2;
1376        int dhcpFailures = WifiLastResortWatchdog.FAILURE_THRESHOLD + 3;
1377        boolean[] hasEverConnected = {false, true, false, false};
1378        boolean watchdogTriggered;
1379
1380        // Buffer potential candidates 1,2,3
1381        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(
1382                Arrays.copyOfRange(mSsids, 0, 3),
1383                Arrays.copyOfRange(mBssids, 0, 3),
1384                Arrays.copyOfRange(mFrequencies, 0, 3),
1385                Arrays.copyOfRange(mCaps, 0, 3),
1386                Arrays.copyOfRange(mLevels, 0, 3),
1387                Arrays.copyOfRange(mIsEphemeral, 0, 3),
1388                Arrays.copyOfRange(hasEverConnected, 0, 3));
1389        mLastResortWatchdog.updateAvailableNetworks(candidates);
1390
1391        incrementFailuresUntilTrigger(Arrays.copyOfRange(mSsids, 0, 3),
1392                Arrays.copyOfRange(mBssids, 0, 3));
1393
1394        // Increment failure count 5 more times, ensure trigger is deactivated
1395        for (int i = 0; i < 5; i++) {
1396            watchdogTriggered = mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1397                        mSsids[2], mBssids[2], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1398            mLastResortWatchdog.updateAvailableNetworks(candidates);
1399            assertEquals(false, watchdogTriggered);
1400        }
1401
1402        candidates = createFilteredQnsCandidates(mSsids, mBssids, mFrequencies, mCaps, mLevels,
1403                mIsEphemeral, hasEverConnected);
1404        mLastResortWatchdog.updateAvailableNetworks(candidates);
1405
1406        incrementFailuresUntilTrigger(mSsids, mBssids);
1407
1408    }
1409
1410    /**
1411     * Case 26: Test Metrics collection
1412     * Setup 5 networks (unique SSIDs). Fail them until watchdog triggers, with 1 network failing
1413     * association, 1 failing authentication, 2 failing dhcp and one failing both authentication and
1414     * dhcp, (over threshold for all these failures)
1415     * Expected behavior: Metrics are updated as follows
1416     *  Triggers++
1417     *  # of Networks += 5
1418     *  Triggers with Bad association++
1419     *  Triggers with Bad authentication++
1420     *  Triggers with Bad dhcp++
1421     *  Number of networks with bad association += 1
1422     *  Number of networks with bad authentication += 2
1423     *  Number of networks with bad dhcp += 3
1424     */
1425    @Test
1426    public void testMetricsCollection() {
1427        String[] ssids = {"\"test1\"", "\"test2\"", "\"test3\"", "\"test4\"", "\"test5\""};
1428        String[] bssids = {"6c:f3:7f:ae:8c:f3", "6c:f3:7f:ae:8c:f4", "de:ad:ba:b1:e5:55",
1429                "c0:ff:ee:ee:e3:ee", "6c:f3:7f:ae:3c:f3"};
1430        int[] frequencies = {2437, 5180, 5180, 2437, 2437};
1431        String[] caps = {"[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]",
1432                "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]", "[WPA2-EAP-CCMP][ESS]"};
1433        int[] levels = {-60, -86, -50, -62, -60};
1434        boolean[] isEphemeral = {false, false, false, false, false};
1435        boolean[] hasEverConnected = {true, false, false, false, false};
1436        // Buffer potential candidates 1,2,3 & 4
1437        List<Pair<ScanDetail, WifiConfiguration>> candidates = createFilteredQnsCandidates(ssids,
1438                bssids, frequencies, caps, levels, isEphemeral, hasEverConnected);
1439        mLastResortWatchdog.updateAvailableNetworks(candidates);
1440
1441        // Ensure new networks have zero'ed failure counts
1442        for (int i = 0; i < ssids.length; i++) {
1443            assertFailureCountEquals(bssids[i], 0, 0, 0);
1444        }
1445
1446        //Increment failure count for the first test network ssid & bssid
1447        for (int i = 0; i < WifiLastResortWatchdog.FAILURE_THRESHOLD; i++) {
1448            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1449                    ssids[1], bssids[1], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
1450            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1451                    ssids[2], bssids[2], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
1452            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1453                    ssids[3], bssids[3], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
1454            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1455                    ssids[4], bssids[4], WifiLastResortWatchdog.FAILURE_CODE_DHCP);
1456            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1457                    ssids[4], bssids[4], WifiLastResortWatchdog.FAILURE_CODE_AUTHENTICATION);
1458            mLastResortWatchdog.noteConnectionFailureAndTriggerIfNeeded(
1459                    ssids[0], bssids[0], WifiLastResortWatchdog.FAILURE_CODE_ASSOCIATION);
1460        }
1461
1462        // Verify relevant WifiMetrics calls were made once with appropriate arguments
1463        verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogTriggers();
1464        verify(mWifiMetrics, times(1)).addCountToNumLastResortWatchdogAvailableNetworksTotal(5);
1465        verify(mWifiMetrics, times(1))
1466                .addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(2);
1467        verify(mWifiMetrics, times(1))
1468                .incrementNumLastResortWatchdogTriggersWithBadAuthentication();
1469        verify(mWifiMetrics, times(1))
1470                .addCountToNumLastResortWatchdogBadAssociationNetworksTotal(1);
1471        verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogTriggersWithBadAssociation();
1472        verify(mWifiMetrics, times(1)).addCountToNumLastResortWatchdogBadDhcpNetworksTotal(3);
1473        verify(mWifiMetrics, times(1)).incrementNumLastResortWatchdogTriggersWithBadDhcp();
1474    }
1475}
1476