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