1/*
2 * Copyright (C) 2017 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.mockito.Mockito.*;
20import static org.mockito.MockitoAnnotations.*;
21
22import android.test.suitebuilder.annotation.SmallTest;
23
24import org.junit.Before;
25import org.junit.Test;
26import org.mockito.Mock;
27
28/**
29 * Unit tests for {@link com.android.server.wifi.SelfRecovery}.
30 */
31@SmallTest
32public class SelfRecoveryTest {
33    SelfRecovery mSelfRecovery;
34    @Mock WifiController mWifiController;
35    @Mock Clock mClock;
36
37    @Before
38    public void setUp() throws Exception {
39        initMocks(this);
40        mSelfRecovery = new SelfRecovery(mWifiController, mClock);
41    }
42
43    /**
44     * Verifies that invocations of {@link SelfRecovery#trigger(int)} with valid reasons will send
45     * the restart message to {@link WifiController}.
46     */
47    @Test
48    public void testValidTriggerReasonsSendMessageToWifiController() {
49        mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
50        verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
51        reset(mWifiController);
52
53        when(mClock.getElapsedSinceBootMillis())
54                .thenReturn(SelfRecovery.MAX_RESTARTS_TIME_WINDOW_MILLIS + 1);
55        mSelfRecovery.trigger(SelfRecovery.REASON_HAL_CRASH);
56        verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
57        reset(mWifiController);
58
59        when(mClock.getElapsedSinceBootMillis())
60                .thenReturn(2 * (SelfRecovery.MAX_RESTARTS_TIME_WINDOW_MILLIS + 1));
61        mSelfRecovery.trigger(SelfRecovery.REASON_WIFICOND_CRASH);
62        verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
63        reset(mWifiController);
64
65    }
66
67    /**
68     * Verifies that invocations of {@link SelfRecovery#trigger(int)} with invalid reasons will not
69     * send the restart message to {@link WifiController}.
70     */
71    @Test
72    public void testInvalidTriggerReasonsDoesNotSendMessageToWifiController() {
73        mSelfRecovery.trigger(-1);
74        verify(mWifiController, never()).sendMessage(anyInt());
75
76        mSelfRecovery.trigger(8);
77        verify(mWifiController, never()).sendMessage(anyInt());
78    }
79
80    /**
81     * Verifies that invocations of {@link SelfRecovery#trigger(int)} for REASON_HAL_CRASH &
82     * REASON_WIFICOND_CRASH are limited to {@link SelfRecovery#MAX_RESTARTS_IN_TIME_WINDOW} in a
83     * {@link SelfRecovery#MAX_RESTARTS_TIME_WINDOW_MILLIS} millisecond time window.
84     */
85    @Test
86    public void testTimeWindowLimiting_typicalUse() {
87        when(mClock.getElapsedSinceBootMillis()).thenReturn(0L);
88        // Fill up the SelfRecovery's restart time window buffer, ensure all the restart triggers
89        // aren't ignored
90        for (int i = 0; i < SelfRecovery.MAX_RESTARTS_IN_TIME_WINDOW / 2; i++) {
91            mSelfRecovery.trigger(SelfRecovery.REASON_HAL_CRASH);
92            verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
93            reset(mWifiController);
94
95            mSelfRecovery.trigger(SelfRecovery.REASON_WIFICOND_CRASH);
96            verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
97            reset(mWifiController);
98        }
99        if ((SelfRecovery.MAX_RESTARTS_IN_TIME_WINDOW % 2) == 1) {
100            mSelfRecovery.trigger(SelfRecovery.REASON_WIFICOND_CRASH);
101            verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
102            reset(mWifiController);
103        }
104
105        // Verify that further attempts to trigger restarts for are ignored
106        mSelfRecovery.trigger(SelfRecovery.REASON_HAL_CRASH);
107        verify(mWifiController, never()).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
108        reset(mWifiController);
109
110        mSelfRecovery.trigger(SelfRecovery.REASON_WIFICOND_CRASH);
111        verify(mWifiController, never()).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
112        reset(mWifiController);
113
114        // Verify L.R.Watchdog can still restart things (It has its own complex limiter)
115        mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
116        verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
117        reset(mWifiController);
118
119        // now TRAVEL FORWARDS IN TIME and ensure that more restarts can occur
120        when(mClock.getElapsedSinceBootMillis())
121                .thenReturn(SelfRecovery.MAX_RESTARTS_TIME_WINDOW_MILLIS + 1);
122        mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
123        verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
124        reset(mWifiController);
125
126        when(mClock.getElapsedSinceBootMillis())
127                .thenReturn(SelfRecovery.MAX_RESTARTS_TIME_WINDOW_MILLIS + 1);
128        mSelfRecovery.trigger(SelfRecovery.REASON_HAL_CRASH);
129        verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
130        reset(mWifiController);
131    }
132
133    /**
134     * Verifies that invocations of {@link SelfRecovery#trigger(int)} for
135     * REASON_LAST_RESORT_WATCHDOG are NOT limited to
136     * {@link SelfRecovery#MAX_RESTARTS_IN_TIME_WINDOW} in a
137     * {@link SelfRecovery#MAX_RESTARTS_TIME_WINDOW_MILLIS} millisecond time window.
138     */
139    @Test
140    public void testTimeWindowLimiting_lastResortWatchdog_noEffect() {
141        for (int i = 0; i < SelfRecovery.MAX_RESTARTS_IN_TIME_WINDOW * 2; i++) {
142            // Verify L.R.Watchdog can still restart things (It has it's own complex limiter)
143            mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
144            verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
145            reset(mWifiController);
146        }
147    }
148}
149