blob: db5373ac34b2c80051e9aae4e723f86f913116ca [file] [log] [blame]
Christopher Wiley08725a82016-05-18 16:32:44 -07001/*
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.connectivity.tethering;
18
Erik Klinedd4d5822017-06-12 18:20:08 +090019import static org.junit.Assert.assertFalse;
20import static org.junit.Assert.assertTrue;
Erik Klineab6439b2017-06-06 19:24:21 +090021import static org.mockito.Matchers.any;
Christopher Wileyf972edc2016-05-23 16:17:30 -070022import static org.mockito.Matchers.anyString;
Erik Klineab6439b2017-06-06 19:24:21 +090023import static org.mockito.Matchers.eq;
Christopher Wileyf972edc2016-05-23 16:17:30 -070024import static org.mockito.Mockito.doThrow;
Christopher Wiley279eca32016-05-20 13:23:10 -070025import static org.mockito.Mockito.inOrder;
26import static org.mockito.Mockito.reset;
27import static org.mockito.Mockito.verify;
Christopher Wiley08725a82016-05-18 16:32:44 -070028import static org.mockito.Mockito.verifyNoMoreInteractions;
Christopher Wiley279eca32016-05-20 13:23:10 -070029import static org.mockito.Mockito.when;
Christopher Wiley08725a82016-05-18 16:32:44 -070030
Christopher Wileye90e0a72016-05-31 10:44:35 -070031import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
32import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
33import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
34import static android.net.ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
Erik Klinea954be92017-02-13 17:12:02 +090035import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
36import static android.net.ConnectivityManager.TETHERING_USB;
37import static android.net.ConnectivityManager.TETHERING_WIFI;
Christopher Wileye90e0a72016-05-31 10:44:35 -070038import static com.android.server.connectivity.tethering.IControlsTethering.STATE_AVAILABLE;
39import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED;
40import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
41
Christopher Wileycd0cfbb2016-05-31 14:43:08 -070042import android.net.ConnectivityManager;
Christopher Wiley08725a82016-05-18 16:32:44 -070043import android.net.INetworkStatsService;
Christopher Wiley279eca32016-05-20 13:23:10 -070044import android.net.InterfaceConfiguration;
Erik Klinedd4d5822017-06-12 18:20:08 +090045import android.net.LinkAddress;
Erik Klineab6439b2017-06-06 19:24:21 +090046import android.net.LinkProperties;
Erik Klinedd4d5822017-06-12 18:20:08 +090047import android.net.RouteInfo;
Erik Kline7747fd42017-05-12 16:52:48 +090048import android.net.util.SharedLog;
Christopher Wiley08725a82016-05-18 16:32:44 -070049import android.os.INetworkManagementService;
Christopher Wiley279eca32016-05-20 13:23:10 -070050import android.os.RemoteException;
Christopher Wiley08725a82016-05-18 16:32:44 -070051import android.os.test.TestLooper;
Christopher Wiley9bc0df22016-05-25 13:57:27 -070052import android.support.test.filters.SmallTest;
53import android.support.test.runner.AndroidJUnit4;
Erik Klinedd4d5822017-06-12 18:20:08 +090054import android.text.TextUtils;
55
56import java.net.Inet4Address;
Christopher Wiley08725a82016-05-18 16:32:44 -070057
58import org.junit.Before;
59import org.junit.Test;
Christopher Wiley9bc0df22016-05-25 13:57:27 -070060import org.junit.runner.RunWith;
Erik Klinedd4d5822017-06-12 18:20:08 +090061import org.mockito.ArgumentCaptor;
Christopher Wiley279eca32016-05-20 13:23:10 -070062import org.mockito.InOrder;
Christopher Wiley08725a82016-05-18 16:32:44 -070063import org.mockito.Mock;
64import org.mockito.MockitoAnnotations;
65
Christopher Wiley9bc0df22016-05-25 13:57:27 -070066@RunWith(AndroidJUnit4.class)
67@SmallTest
Mitchell Wills4622c2d2016-05-23 16:40:10 -070068public class TetherInterfaceStateMachineTest {
Christopher Wiley08725a82016-05-18 16:32:44 -070069 private static final String IFACE_NAME = "testnet1";
Christopher Wiley279eca32016-05-20 13:23:10 -070070 private static final String UPSTREAM_IFACE = "upstream0";
71 private static final String UPSTREAM_IFACE2 = "upstream1";
Christopher Wiley08725a82016-05-18 16:32:44 -070072
73 @Mock private INetworkManagementService mNMService;
74 @Mock private INetworkStatsService mStatsService;
75 @Mock private IControlsTethering mTetherHelper;
Christopher Wiley279eca32016-05-20 13:23:10 -070076 @Mock private InterfaceConfiguration mInterfaceConfiguration;
Erik Kline7747fd42017-05-12 16:52:48 +090077 @Mock private SharedLog mSharedLog;
Christopher Wiley08725a82016-05-18 16:32:44 -070078
79 private final TestLooper mLooper = new TestLooper();
Erik Klinedd4d5822017-06-12 18:20:08 +090080 private final ArgumentCaptor<LinkProperties> mLinkPropertiesCaptor =
81 ArgumentCaptor.forClass(LinkProperties.class);
Mitchell Wills4622c2d2016-05-23 16:40:10 -070082 private TetherInterfaceStateMachine mTestedSm;
Christopher Wiley08725a82016-05-18 16:32:44 -070083
Christopher Wileycd0cfbb2016-05-31 14:43:08 -070084 private void initStateMachine(int interfaceType) throws Exception {
Erik Kline7747fd42017-05-12 16:52:48 +090085 mTestedSm = new TetherInterfaceStateMachine(
86 IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
Erik Kline94ae4c92017-06-13 21:32:10 +090087 mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -070088 mTestedSm.start();
89 // Starting the state machine always puts us in a consistent state and notifies
Erik Klinedd4d5822017-06-12 18:20:08 +090090 // the rest of the world that we've changed from an unknown to available state.
Christopher Wiley279eca32016-05-20 13:23:10 -070091 mLooper.dispatchAll();
92 reset(mNMService, mStatsService, mTetherHelper);
Christopher Wileyf972edc2016-05-23 16:17:30 -070093 when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
Christopher Wiley279eca32016-05-20 13:23:10 -070094 }
95
Christopher Wileycd0cfbb2016-05-31 14:43:08 -070096 private void initTetheredStateMachine(int interfaceType, String upstreamIface) throws Exception {
97 initStateMachine(interfaceType);
Erik Klineea9cc482017-03-10 19:35:34 +090098 dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
Christopher Wiley279eca32016-05-20 13:23:10 -070099 if (upstreamIface != null) {
100 dispatchTetherConnectionChanged(upstreamIface);
101 }
102 reset(mNMService, mStatsService, mTetherHelper);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700103 when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
Christopher Wiley279eca32016-05-20 13:23:10 -0700104 }
105
Christopher Wileye90e0a72016-05-31 10:44:35 -0700106 @Before public void setUp() throws Exception {
Christopher Wiley08725a82016-05-18 16:32:44 -0700107 MockitoAnnotations.initMocks(this);
Erik Kline7747fd42017-05-12 16:52:48 +0900108 when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
Christopher Wiley279eca32016-05-20 13:23:10 -0700109 }
110
111 @Test
112 public void startsOutAvailable() {
Christopher Wileycd0cfbb2016-05-31 14:43:08 -0700113 mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
Erik Kline94ae4c92017-06-13 21:32:10 +0900114 TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper);
Christopher Wiley08725a82016-05-18 16:32:44 -0700115 mTestedSm.start();
Christopher Wiley279eca32016-05-20 13:23:10 -0700116 mLooper.dispatchAll();
Erik Klineab6439b2017-06-06 19:24:21 +0900117 verify(mTetherHelper).updateInterfaceState(
118 mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
119 verify(mTetherHelper).updateLinkProperties(eq(mTestedSm), any(LinkProperties.class));
Christopher Wiley279eca32016-05-20 13:23:10 -0700120 verifyNoMoreInteractions(mTetherHelper, mNMService, mStatsService);
Christopher Wiley08725a82016-05-18 16:32:44 -0700121 }
122
123 @Test
Christopher Wileyf972edc2016-05-23 16:17:30 -0700124 public void shouldDoNothingUntilRequested() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900125 initStateMachine(TETHERING_BLUETOOTH);
Christopher Wiley08725a82016-05-18 16:32:44 -0700126 final int [] NOOP_COMMANDS = {
Mitchell Wills4622c2d2016-05-23 16:40:10 -0700127 TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED,
128 TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR,
129 TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR,
130 TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR,
131 TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR,
132 TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR,
133 TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED
Christopher Wiley08725a82016-05-18 16:32:44 -0700134 };
135 for (int command : NOOP_COMMANDS) {
Christopher Wiley279eca32016-05-20 13:23:10 -0700136 // None of these commands should trigger us to request action from
Christopher Wiley08725a82016-05-18 16:32:44 -0700137 // the rest of the system.
Christopher Wiley279eca32016-05-20 13:23:10 -0700138 dispatchCommand(command);
139 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley08725a82016-05-18 16:32:44 -0700140 }
141 }
142
Christopher Wiley279eca32016-05-20 13:23:10 -0700143 @Test
Christopher Wileyf972edc2016-05-23 16:17:30 -0700144 public void handlesImmediateInterfaceDown() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900145 initStateMachine(TETHERING_BLUETOOTH);
Christopher Wileye90e0a72016-05-31 10:44:35 -0700146
Mitchell Wills4622c2d2016-05-23 16:40:10 -0700147 dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
Erik Klineab6439b2017-06-06 19:24:21 +0900148 verify(mTetherHelper).updateInterfaceState(
149 mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
150 verify(mTetherHelper).updateLinkProperties(eq(mTestedSm), any(LinkProperties.class));
Christopher Wiley279eca32016-05-20 13:23:10 -0700151 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -0700152 }
153
154 @Test
Christopher Wileyf972edc2016-05-23 16:17:30 -0700155 public void canBeTethered() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900156 initStateMachine(TETHERING_BLUETOOTH);
Christopher Wileye90e0a72016-05-31 10:44:35 -0700157
Erik Klineea9cc482017-03-10 19:35:34 +0900158 dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
Christopher Wiley279eca32016-05-20 13:23:10 -0700159 InOrder inOrder = inOrder(mTetherHelper, mNMService);
Christopher Wiley279eca32016-05-20 13:23:10 -0700160 inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
Erik Klineab6439b2017-06-06 19:24:21 +0900161 inOrder.verify(mTetherHelper).updateInterfaceState(
162 mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
163 inOrder.verify(mTetherHelper).updateLinkProperties(
164 eq(mTestedSm), any(LinkProperties.class));
Christopher Wiley279eca32016-05-20 13:23:10 -0700165 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -0700166 }
167
168 @Test
169 public void canUnrequestTethering() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900170 initTetheredStateMachine(TETHERING_BLUETOOTH, null);
Christopher Wiley279eca32016-05-20 13:23:10 -0700171
Mitchell Wills4622c2d2016-05-23 16:40:10 -0700172 dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
Christopher Wiley279eca32016-05-20 13:23:10 -0700173 InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700174 inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
Erik Klineab6439b2017-06-06 19:24:21 +0900175 inOrder.verify(mTetherHelper).updateInterfaceState(
176 mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
177 inOrder.verify(mTetherHelper).updateLinkProperties(
178 eq(mTestedSm), any(LinkProperties.class));
Christopher Wiley279eca32016-05-20 13:23:10 -0700179 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -0700180 }
181
182 @Test
Christopher Wileyf972edc2016-05-23 16:17:30 -0700183 public void canBeTetheredAsUsb() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900184 initStateMachine(TETHERING_USB);
Christopher Wiley279eca32016-05-20 13:23:10 -0700185
Erik Klineea9cc482017-03-10 19:35:34 +0900186 dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
Christopher Wiley279eca32016-05-20 13:23:10 -0700187 InOrder inOrder = inOrder(mTetherHelper, mNMService);
Christopher Wiley279eca32016-05-20 13:23:10 -0700188 inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
189 inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
Christopher Wiley279eca32016-05-20 13:23:10 -0700190 inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
Erik Klineab6439b2017-06-06 19:24:21 +0900191 inOrder.verify(mTetherHelper).updateInterfaceState(
192 mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
193 inOrder.verify(mTetherHelper).updateLinkProperties(
Erik Klinedd4d5822017-06-12 18:20:08 +0900194 eq(mTestedSm), mLinkPropertiesCaptor.capture());
195 assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
Christopher Wiley279eca32016-05-20 13:23:10 -0700196 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -0700197 }
198
199 @Test
200 public void handlesFirstUpstreamChange() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900201 initTetheredStateMachine(TETHERING_BLUETOOTH, null);
Christopher Wiley279eca32016-05-20 13:23:10 -0700202
Erik Klineab6439b2017-06-06 19:24:21 +0900203 // Telling the state machine about its upstream interface triggers
204 // a little more configuration.
Christopher Wiley279eca32016-05-20 13:23:10 -0700205 dispatchTetherConnectionChanged(UPSTREAM_IFACE);
206 InOrder inOrder = inOrder(mNMService);
207 inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE);
208 inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
209 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -0700210 }
211
212 @Test
213 public void handlesChangingUpstream() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900214 initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
Christopher Wiley279eca32016-05-20 13:23:10 -0700215
216 dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
217 InOrder inOrder = inOrder(mNMService, mStatsService);
218 inOrder.verify(mStatsService).forceUpdate();
219 inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
220 inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
221 inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
222 inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
223 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -0700224 }
225
226 @Test
Erik Klinea954be92017-02-13 17:12:02 +0900227 public void handlesChangingUpstreamNatFailure() throws Exception {
228 initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
229
230 doThrow(RemoteException.class).when(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
231
232 dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
233 InOrder inOrder = inOrder(mNMService, mStatsService);
234 inOrder.verify(mStatsService).forceUpdate();
235 inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
236 inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
237 inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
Erik Kline8ea45482017-02-13 17:28:53 +0900238 inOrder.verify(mStatsService).forceUpdate();
239 inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
240 inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2);
Erik Klinea954be92017-02-13 17:12:02 +0900241 }
242
243 @Test
244 public void handlesChangingUpstreamInterfaceForwardingFailure() throws Exception {
245 initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
246
247 doThrow(RemoteException.class).when(mNMService).startInterfaceForwarding(
248 IFACE_NAME, UPSTREAM_IFACE2);
249
250 dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
251 InOrder inOrder = inOrder(mNMService, mStatsService);
252 inOrder.verify(mStatsService).forceUpdate();
253 inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
254 inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
255 inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
256 inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
Erik Kline8ea45482017-02-13 17:28:53 +0900257 inOrder.verify(mStatsService).forceUpdate();
258 inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
259 inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2);
Erik Klinea954be92017-02-13 17:12:02 +0900260 }
261
262 @Test
Christopher Wiley279eca32016-05-20 13:23:10 -0700263 public void canUnrequestTetheringWithUpstream() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900264 initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
Christopher Wiley279eca32016-05-20 13:23:10 -0700265
Mitchell Wills4622c2d2016-05-23 16:40:10 -0700266 dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
Christopher Wiley279eca32016-05-20 13:23:10 -0700267 InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
268 inOrder.verify(mStatsService).forceUpdate();
269 inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
270 inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
271 inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
Erik Klineab6439b2017-06-06 19:24:21 +0900272 inOrder.verify(mTetherHelper).updateInterfaceState(
273 mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
274 inOrder.verify(mTetherHelper).updateLinkProperties(
275 eq(mTestedSm), any(LinkProperties.class));
Christopher Wiley279eca32016-05-20 13:23:10 -0700276 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -0700277 }
278
Christopher Wileyf972edc2016-05-23 16:17:30 -0700279 @Test
280 public void interfaceDownLeadsToUnavailable() throws Exception {
281 for (boolean shouldThrow : new boolean[]{true, false}) {
Erik Klinea954be92017-02-13 17:12:02 +0900282 initTetheredStateMachine(TETHERING_USB, null);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700283
284 if (shouldThrow) {
285 doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME);
286 }
287 dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
Christopher Wileye90e0a72016-05-31 10:44:35 -0700288 InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700289 usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
290 usbTeardownOrder.verify(mNMService).setInterfaceConfig(
291 IFACE_NAME, mInterfaceConfiguration);
Erik Klineab6439b2017-06-06 19:24:21 +0900292 usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
293 mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
294 usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
Erik Klinedd4d5822017-06-12 18:20:08 +0900295 eq(mTestedSm), mLinkPropertiesCaptor.capture());
296 assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
Christopher Wileyf972edc2016-05-23 16:17:30 -0700297 }
298 }
299
300 @Test
301 public void usbShouldBeTornDownOnTetherError() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900302 initStateMachine(TETHERING_USB);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700303
304 doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME);
Erik Klineea9cc482017-03-10 19:35:34 +0900305 dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
Christopher Wileye90e0a72016-05-31 10:44:35 -0700306 InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700307 usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
308 usbTeardownOrder.verify(mNMService).setInterfaceConfig(
309 IFACE_NAME, mInterfaceConfiguration);
Erik Klineab6439b2017-06-06 19:24:21 +0900310 usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
311 mTestedSm, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
312 usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
Erik Klinedd4d5822017-06-12 18:20:08 +0900313 eq(mTestedSm), mLinkPropertiesCaptor.capture());
314 assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
Christopher Wileyf972edc2016-05-23 16:17:30 -0700315 }
316
317 @Test
318 public void shouldTearDownUsbOnUpstreamError() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900319 initTetheredStateMachine(TETHERING_USB, null);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700320
321 doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString());
322 dispatchTetherConnectionChanged(UPSTREAM_IFACE);
Christopher Wileye90e0a72016-05-31 10:44:35 -0700323 InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700324 usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
325 usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
Erik Klineab6439b2017-06-06 19:24:21 +0900326 usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
327 mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
328 usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
Erik Klinedd4d5822017-06-12 18:20:08 +0900329 eq(mTestedSm), mLinkPropertiesCaptor.capture());
330 assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
Christopher Wileyf972edc2016-05-23 16:17:30 -0700331 }
Christopher Wiley279eca32016-05-20 13:23:10 -0700332
Erik Kline624bf3d2017-02-14 15:55:00 +0900333 @Test
334 public void ignoresDuplicateUpstreamNotifications() throws Exception {
335 initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
336
337 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
338
339 for (int i = 0; i < 5; i++) {
340 dispatchTetherConnectionChanged(UPSTREAM_IFACE);
341 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
342 }
343 }
344
Christopher Wiley279eca32016-05-20 13:23:10 -0700345 /**
346 * Send a command to the state machine under test, and run the event loop to idle.
347 *
Mitchell Wills4622c2d2016-05-23 16:40:10 -0700348 * @param command One of the TetherInterfaceStateMachine.CMD_* constants.
Erik Klineea9cc482017-03-10 19:35:34 +0900349 * @param obj An additional argument to pass.
350 */
351 private void dispatchCommand(int command, int arg1) {
352 mTestedSm.sendMessage(command, arg1);
353 mLooper.dispatchAll();
354 }
355
356 /**
357 * Send a command to the state machine under test, and run the event loop to idle.
358 *
359 * @param command One of the TetherInterfaceStateMachine.CMD_* constants.
Christopher Wiley279eca32016-05-20 13:23:10 -0700360 */
361 private void dispatchCommand(int command) {
362 mTestedSm.sendMessage(command);
363 mLooper.dispatchAll();
364 }
365
366 /**
367 * Special override to tell the state machine that the upstream interface has changed.
368 *
369 * @see #dispatchCommand(int)
370 * @param upstreamIface String name of upstream interface (or null)
371 */
372 private void dispatchTetherConnectionChanged(String upstreamIface) {
Mitchell Wills4622c2d2016-05-23 16:40:10 -0700373 mTestedSm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
374 upstreamIface);
Christopher Wiley279eca32016-05-20 13:23:10 -0700375 mLooper.dispatchAll();
Christopher Wiley08725a82016-05-18 16:32:44 -0700376 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900377
378 private void assertIPv4AddressAndDirectlyConnectedRoute(LinkProperties lp) {
379 // Find the first IPv4 LinkAddress.
380 LinkAddress addr4 = null;
381 for (LinkAddress addr : lp.getLinkAddresses()) {
382 if (!(addr.getAddress() instanceof Inet4Address)) continue;
383 addr4 = addr;
384 break;
385 }
386 assertTrue("missing IPv4 address", addr4 != null);
387
388 // Assert the presence of the associated directly connected route.
389 final RouteInfo directlyConnected = new RouteInfo(addr4, null, lp.getInterfaceName());
390 assertTrue("missing directly connected route: '" + directlyConnected.toString() + "'",
391 lp.getRoutes().contains(directlyConnected));
392 }
393
394 private void assertNoAddressesNorRoutes(LinkProperties lp) {
395 assertTrue(lp.getLinkAddresses().isEmpty());
396 assertTrue(lp.getRoutes().isEmpty());
397 // We also check that interface name is non-empty, because we should
398 // never see an empty interface name in any LinkProperties update.
399 assertFalse(TextUtils.isEmpty(lp.getInterfaceName()));
400 }
Lorenzo Colitti5bce5a12016-10-28 17:45:55 +0900401}