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