196a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius/*
296a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius * Copyright (C) 2017 The Android Open Source Project
396a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius *
496a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius * Licensed under the Apache License, Version 2.0 (the "License");
596a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius * you may not use this file except in compliance with the License.
696a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius * You may obtain a copy of the License at
796a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius *
896a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius *      http://www.apache.org/licenses/LICENSE-2.0
996a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius *
1096a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius * Unless required by applicable law or agreed to in writing, software
1196a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius * distributed under the License is distributed on an "AS IS" BASIS,
1296a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1396a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius * See the License for the specific language governing permissions and
1496a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius * limitations under the License.
1596a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius */
1696a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius
1796a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Piuspackage com.android.server.wifi;
1896a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius
1996a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Piusimport static org.mockito.Mockito.*;
2096a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Piusimport static org.mockito.MockitoAnnotations.*;
2196a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius
2296a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Piusimport android.test.suitebuilder.annotation.SmallTest;
2396a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius
2496a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Piusimport org.junit.Before;
2596a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Piusimport org.junit.Test;
2696a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Piusimport org.mockito.Mock;
2796a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius
2896a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius/**
2996a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius * Unit tests for {@link com.android.server.wifi.SelfRecovery}.
3096a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius */
3196a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius@SmallTest
3296a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Piuspublic class SelfRecoveryTest {
3396a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius    SelfRecovery mSelfRecovery;
3496a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius    @Mock WifiController mWifiController;
35e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne    @Mock Clock mClock;
3696a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius
3796a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius    @Before
3896a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius    public void setUp() throws Exception {
3996a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius        initMocks(this);
40e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        mSelfRecovery = new SelfRecovery(mWifiController, mClock);
4196a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius    }
4296a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius
4396a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius    /**
4496a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius     * Verifies that invocations of {@link SelfRecovery#trigger(int)} with valid reasons will send
4596a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius     * the restart message to {@link WifiController}.
4696a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius     */
4796a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius    @Test
4896a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius    public void testValidTriggerReasonsSendMessageToWifiController() {
4996a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius        mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
5096a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius        verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
5196a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius        reset(mWifiController);
5296a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius
53e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        when(mClock.getElapsedSinceBootMillis())
54e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne                .thenReturn(SelfRecovery.MAX_RESTARTS_TIME_WINDOW_MILLIS + 1);
5596a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius        mSelfRecovery.trigger(SelfRecovery.REASON_HAL_CRASH);
5696a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius        verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
5796a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius        reset(mWifiController);
5896a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius
59e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        when(mClock.getElapsedSinceBootMillis())
60e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne                .thenReturn(2 * (SelfRecovery.MAX_RESTARTS_TIME_WINDOW_MILLIS + 1));
6196a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius        mSelfRecovery.trigger(SelfRecovery.REASON_WIFICOND_CRASH);
6296a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius        verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
6396a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius        reset(mWifiController);
6496a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius
6596a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius    }
6696a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius
6796a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius    /**
6896a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius     * Verifies that invocations of {@link SelfRecovery#trigger(int)} with invalid reasons will not
6996a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius     * send the restart message to {@link WifiController}.
7096a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius     */
7196a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius    @Test
7296a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius    public void testInvalidTriggerReasonsDoesNotSendMessageToWifiController() {
7396a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius        mSelfRecovery.trigger(-1);
7496a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius        verify(mWifiController, never()).sendMessage(anyInt());
7596a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius
7696a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius        mSelfRecovery.trigger(8);
7796a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius        verify(mWifiController, never()).sendMessage(anyInt());
7896a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius    }
79e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne
80e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne    /**
81e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne     * Verifies that invocations of {@link SelfRecovery#trigger(int)} for REASON_HAL_CRASH &
82e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne     * REASON_WIFICOND_CRASH are limited to {@link SelfRecovery#MAX_RESTARTS_IN_TIME_WINDOW} in a
83e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne     * {@link SelfRecovery#MAX_RESTARTS_TIME_WINDOW_MILLIS} millisecond time window.
84e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne     */
85e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne    @Test
86e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne    public void testTimeWindowLimiting_typicalUse() {
87e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        when(mClock.getElapsedSinceBootMillis()).thenReturn(0L);
88e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        // Fill up the SelfRecovery's restart time window buffer, ensure all the restart triggers
89e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        // aren't ignored
90e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        for (int i = 0; i < SelfRecovery.MAX_RESTARTS_IN_TIME_WINDOW / 2; i++) {
91e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne            mSelfRecovery.trigger(SelfRecovery.REASON_HAL_CRASH);
92e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne            verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
93e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne            reset(mWifiController);
94e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne
95e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne            mSelfRecovery.trigger(SelfRecovery.REASON_WIFICOND_CRASH);
96e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne            verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
97e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne            reset(mWifiController);
98e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        }
99e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        if ((SelfRecovery.MAX_RESTARTS_IN_TIME_WINDOW % 2) == 1) {
100e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne            mSelfRecovery.trigger(SelfRecovery.REASON_WIFICOND_CRASH);
101e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne            verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
102e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne            reset(mWifiController);
103e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        }
104e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne
105e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        // Verify that further attempts to trigger restarts for are ignored
106e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        mSelfRecovery.trigger(SelfRecovery.REASON_HAL_CRASH);
107e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        verify(mWifiController, never()).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
108e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        reset(mWifiController);
109e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne
110e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        mSelfRecovery.trigger(SelfRecovery.REASON_WIFICOND_CRASH);
111e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        verify(mWifiController, never()).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
112e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        reset(mWifiController);
113e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne
114e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        // Verify L.R.Watchdog can still restart things (It has its own complex limiter)
115e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
116e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
117e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        reset(mWifiController);
118e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne
119e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        // now TRAVEL FORWARDS IN TIME and ensure that more restarts can occur
120e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        when(mClock.getElapsedSinceBootMillis())
121e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne                .thenReturn(SelfRecovery.MAX_RESTARTS_TIME_WINDOW_MILLIS + 1);
122e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
123e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
124e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        reset(mWifiController);
125e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne
126e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        when(mClock.getElapsedSinceBootMillis())
127e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne                .thenReturn(SelfRecovery.MAX_RESTARTS_TIME_WINDOW_MILLIS + 1);
128e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        mSelfRecovery.trigger(SelfRecovery.REASON_HAL_CRASH);
129e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
130e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        reset(mWifiController);
131e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne    }
132e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne
133e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne    /**
134e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne     * Verifies that invocations of {@link SelfRecovery#trigger(int)} for
135e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne     * REASON_LAST_RESORT_WATCHDOG are NOT limited to
136e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne     * {@link SelfRecovery#MAX_RESTARTS_IN_TIME_WINDOW} in a
137e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne     * {@link SelfRecovery#MAX_RESTARTS_TIME_WINDOW_MILLIS} millisecond time window.
138e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne     */
139e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne    @Test
140e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne    public void testTimeWindowLimiting_lastResortWatchdog_noEffect() {
141e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        for (int i = 0; i < SelfRecovery.MAX_RESTARTS_IN_TIME_WINDOW * 2; i++) {
142e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne            // Verify L.R.Watchdog can still restart things (It has it's own complex limiter)
143e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne            mSelfRecovery.trigger(SelfRecovery.REASON_LAST_RESORT_WATCHDOG);
144e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne            verify(mWifiController).sendMessage(eq(WifiController.CMD_RESTART_WIFI));
145e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne            reset(mWifiController);
146e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne        }
147e8cf3b95869b71ff4719b037f79d74b74d2a2fc3Glen Kuhne    }
14896a9dbeb3a622e44c13ff7be8decf36d06ff7dbbRoshan Pius}
149