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