blob: 7c77cf59524d9a0d6572a8ae4fe0f9eeb663dae1 [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;
Erik Klinea954be92017-02-13 17:12:02 +090034import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
35import static android.net.ConnectivityManager.TETHERING_USB;
36import static android.net.ConnectivityManager.TETHERING_WIFI;
Christopher Wileye90e0a72016-05-31 10:44:35 -070037import static com.android.server.connectivity.tethering.IControlsTethering.STATE_AVAILABLE;
38import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED;
39import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
40
Christopher Wiley08725a82016-05-18 16:32:44 -070041import android.net.INetworkStatsService;
Christopher Wiley279eca32016-05-20 13:23:10 -070042import android.net.InterfaceConfiguration;
Erik Klinedd4d5822017-06-12 18:20:08 +090043import android.net.LinkAddress;
Erik Klineab6439b2017-06-06 19:24:21 +090044import android.net.LinkProperties;
Erik Klinedd4d5822017-06-12 18:20:08 +090045import android.net.RouteInfo;
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +090046import android.net.util.InterfaceSet;
Erik Kline7747fd42017-05-12 16:52:48 +090047import android.net.util.SharedLog;
Christopher Wiley08725a82016-05-18 16:32:44 -070048import android.os.INetworkManagementService;
Christopher Wiley279eca32016-05-20 13:23:10 -070049import android.os.RemoteException;
Christopher Wiley08725a82016-05-18 16:32:44 -070050import android.os.test.TestLooper;
Christopher Wiley9bc0df22016-05-25 13:57:27 -070051import android.support.test.filters.SmallTest;
52import android.support.test.runner.AndroidJUnit4;
Erik Klinedd4d5822017-06-12 18:20:08 +090053import android.text.TextUtils;
54
55import java.net.Inet4Address;
Christopher Wiley08725a82016-05-18 16:32:44 -070056
57import org.junit.Before;
58import org.junit.Test;
Christopher Wiley9bc0df22016-05-25 13:57:27 -070059import org.junit.runner.RunWith;
Erik Klinedd4d5822017-06-12 18:20:08 +090060import org.mockito.ArgumentCaptor;
Christopher Wiley279eca32016-05-20 13:23:10 -070061import org.mockito.InOrder;
Christopher Wiley08725a82016-05-18 16:32:44 -070062import org.mockito.Mock;
63import org.mockito.MockitoAnnotations;
64
Christopher Wiley9bc0df22016-05-25 13:57:27 -070065@RunWith(AndroidJUnit4.class)
66@SmallTest
Mitchell Wills4622c2d2016-05-23 16:40:10 -070067public class TetherInterfaceStateMachineTest {
Christopher Wiley08725a82016-05-18 16:32:44 -070068 private static final String IFACE_NAME = "testnet1";
Christopher Wiley279eca32016-05-20 13:23:10 -070069 private static final String UPSTREAM_IFACE = "upstream0";
70 private static final String UPSTREAM_IFACE2 = "upstream1";
Christopher Wiley08725a82016-05-18 16:32:44 -070071
72 @Mock private INetworkManagementService mNMService;
73 @Mock private INetworkStatsService mStatsService;
74 @Mock private IControlsTethering mTetherHelper;
Christopher Wiley279eca32016-05-20 13:23:10 -070075 @Mock private InterfaceConfiguration mInterfaceConfiguration;
Erik Kline7747fd42017-05-12 16:52:48 +090076 @Mock private SharedLog mSharedLog;
Remi NGUYEN VANa911e842018-03-15 11:57:14 +090077 @Mock private TetheringDependencies mTetheringDependencies;
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,
Remi NGUYEN VANa911e842018-03-15 11:57:14 +090087 mNMService, mStatsService, mTetherHelper, mTetheringDependencies);
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(),
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900114 TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper,
115 mTetheringDependencies);
Christopher Wiley08725a82016-05-18 16:32:44 -0700116 mTestedSm.start();
Christopher Wiley279eca32016-05-20 13:23:10 -0700117 mLooper.dispatchAll();
Erik Klineab6439b2017-06-06 19:24:21 +0900118 verify(mTetherHelper).updateInterfaceState(
119 mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
120 verify(mTetherHelper).updateLinkProperties(eq(mTestedSm), any(LinkProperties.class));
Christopher Wiley279eca32016-05-20 13:23:10 -0700121 verifyNoMoreInteractions(mTetherHelper, mNMService, mStatsService);
Christopher Wiley08725a82016-05-18 16:32:44 -0700122 }
123
124 @Test
Christopher Wileyf972edc2016-05-23 16:17:30 -0700125 public void shouldDoNothingUntilRequested() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900126 initStateMachine(TETHERING_BLUETOOTH);
Christopher Wiley08725a82016-05-18 16:32:44 -0700127 final int [] NOOP_COMMANDS = {
Mitchell Wills4622c2d2016-05-23 16:40:10 -0700128 TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED,
129 TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR,
130 TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR,
131 TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR,
132 TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR,
133 TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR,
134 TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED
Christopher Wiley08725a82016-05-18 16:32:44 -0700135 };
136 for (int command : NOOP_COMMANDS) {
Christopher Wiley279eca32016-05-20 13:23:10 -0700137 // None of these commands should trigger us to request action from
Christopher Wiley08725a82016-05-18 16:32:44 -0700138 // the rest of the system.
Christopher Wiley279eca32016-05-20 13:23:10 -0700139 dispatchCommand(command);
140 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley08725a82016-05-18 16:32:44 -0700141 }
142 }
143
Christopher Wiley279eca32016-05-20 13:23:10 -0700144 @Test
Christopher Wileyf972edc2016-05-23 16:17:30 -0700145 public void handlesImmediateInterfaceDown() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900146 initStateMachine(TETHERING_BLUETOOTH);
Christopher Wileye90e0a72016-05-31 10:44:35 -0700147
Mitchell Wills4622c2d2016-05-23 16:40:10 -0700148 dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
Erik Klineab6439b2017-06-06 19:24:21 +0900149 verify(mTetherHelper).updateInterfaceState(
150 mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
151 verify(mTetherHelper).updateLinkProperties(eq(mTestedSm), any(LinkProperties.class));
Christopher Wiley279eca32016-05-20 13:23:10 -0700152 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -0700153 }
154
155 @Test
Christopher Wileyf972edc2016-05-23 16:17:30 -0700156 public void canBeTethered() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900157 initStateMachine(TETHERING_BLUETOOTH);
Christopher Wileye90e0a72016-05-31 10:44:35 -0700158
Erik Klineea9cc482017-03-10 19:35:34 +0900159 dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
Christopher Wiley279eca32016-05-20 13:23:10 -0700160 InOrder inOrder = inOrder(mTetherHelper, mNMService);
Christopher Wiley279eca32016-05-20 13:23:10 -0700161 inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
Erik Klineab6439b2017-06-06 19:24:21 +0900162 inOrder.verify(mTetherHelper).updateInterfaceState(
163 mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
164 inOrder.verify(mTetherHelper).updateLinkProperties(
165 eq(mTestedSm), any(LinkProperties.class));
Christopher Wiley279eca32016-05-20 13:23:10 -0700166 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -0700167 }
168
169 @Test
170 public void canUnrequestTethering() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900171 initTetheredStateMachine(TETHERING_BLUETOOTH, null);
Christopher Wiley279eca32016-05-20 13:23:10 -0700172
Mitchell Wills4622c2d2016-05-23 16:40:10 -0700173 dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
Christopher Wiley279eca32016-05-20 13:23:10 -0700174 InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700175 inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
Erik Klineab6439b2017-06-06 19:24:21 +0900176 inOrder.verify(mTetherHelper).updateInterfaceState(
177 mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
178 inOrder.verify(mTetherHelper).updateLinkProperties(
179 eq(mTestedSm), any(LinkProperties.class));
Christopher Wiley279eca32016-05-20 13:23:10 -0700180 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -0700181 }
182
183 @Test
Christopher Wileyf972edc2016-05-23 16:17:30 -0700184 public void canBeTetheredAsUsb() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900185 initStateMachine(TETHERING_USB);
Christopher Wiley279eca32016-05-20 13:23:10 -0700186
Erik Klineea9cc482017-03-10 19:35:34 +0900187 dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
Christopher Wiley279eca32016-05-20 13:23:10 -0700188 InOrder inOrder = inOrder(mTetherHelper, mNMService);
Christopher Wiley279eca32016-05-20 13:23:10 -0700189 inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
190 inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
Christopher Wiley279eca32016-05-20 13:23:10 -0700191 inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
Erik Klineab6439b2017-06-06 19:24:21 +0900192 inOrder.verify(mTetherHelper).updateInterfaceState(
193 mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
194 inOrder.verify(mTetherHelper).updateLinkProperties(
Erik Klinedd4d5822017-06-12 18:20:08 +0900195 eq(mTestedSm), mLinkPropertiesCaptor.capture());
196 assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue());
Christopher Wiley279eca32016-05-20 13:23:10 -0700197 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -0700198 }
199
200 @Test
201 public void handlesFirstUpstreamChange() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900202 initTetheredStateMachine(TETHERING_BLUETOOTH, null);
Christopher Wiley279eca32016-05-20 13:23:10 -0700203
Erik Klineab6439b2017-06-06 19:24:21 +0900204 // Telling the state machine about its upstream interface triggers
205 // a little more configuration.
Christopher Wiley279eca32016-05-20 13:23:10 -0700206 dispatchTetherConnectionChanged(UPSTREAM_IFACE);
207 InOrder inOrder = inOrder(mNMService);
208 inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE);
209 inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
210 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -0700211 }
212
213 @Test
214 public void handlesChangingUpstream() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900215 initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
Christopher Wiley279eca32016-05-20 13:23:10 -0700216
217 dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
218 InOrder inOrder = inOrder(mNMService, mStatsService);
219 inOrder.verify(mStatsService).forceUpdate();
220 inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
221 inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
222 inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
223 inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
224 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -0700225 }
226
227 @Test
Erik Klinea954be92017-02-13 17:12:02 +0900228 public void handlesChangingUpstreamNatFailure() throws Exception {
229 initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
230
231 doThrow(RemoteException.class).when(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
232
233 dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
234 InOrder inOrder = inOrder(mNMService, mStatsService);
235 inOrder.verify(mStatsService).forceUpdate();
236 inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
237 inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
238 inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
Erik Kline8ea45482017-02-13 17:28:53 +0900239 inOrder.verify(mStatsService).forceUpdate();
240 inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
241 inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2);
Erik Klinea954be92017-02-13 17:12:02 +0900242 }
243
244 @Test
245 public void handlesChangingUpstreamInterfaceForwardingFailure() throws Exception {
246 initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
247
248 doThrow(RemoteException.class).when(mNMService).startInterfaceForwarding(
249 IFACE_NAME, UPSTREAM_IFACE2);
250
251 dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
252 InOrder inOrder = inOrder(mNMService, mStatsService);
253 inOrder.verify(mStatsService).forceUpdate();
254 inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
255 inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
256 inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
257 inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
Erik Kline8ea45482017-02-13 17:28:53 +0900258 inOrder.verify(mStatsService).forceUpdate();
259 inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
260 inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2);
Erik Klinea954be92017-02-13 17:12:02 +0900261 }
262
263 @Test
Christopher Wiley279eca32016-05-20 13:23:10 -0700264 public void canUnrequestTetheringWithUpstream() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900265 initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
Christopher Wiley279eca32016-05-20 13:23:10 -0700266
Mitchell Wills4622c2d2016-05-23 16:40:10 -0700267 dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
Christopher Wiley279eca32016-05-20 13:23:10 -0700268 InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
269 inOrder.verify(mStatsService).forceUpdate();
270 inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
271 inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
272 inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
Erik Klineab6439b2017-06-06 19:24:21 +0900273 inOrder.verify(mTetherHelper).updateInterfaceState(
274 mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
275 inOrder.verify(mTetherHelper).updateLinkProperties(
276 eq(mTestedSm), any(LinkProperties.class));
Christopher Wiley279eca32016-05-20 13:23:10 -0700277 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
Christopher Wiley279eca32016-05-20 13:23:10 -0700278 }
279
Christopher Wileyf972edc2016-05-23 16:17:30 -0700280 @Test
281 public void interfaceDownLeadsToUnavailable() throws Exception {
282 for (boolean shouldThrow : new boolean[]{true, false}) {
Erik Klinea954be92017-02-13 17:12:02 +0900283 initTetheredStateMachine(TETHERING_USB, null);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700284
285 if (shouldThrow) {
286 doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME);
287 }
288 dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
Christopher Wileye90e0a72016-05-31 10:44:35 -0700289 InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700290 usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
291 usbTeardownOrder.verify(mNMService).setInterfaceConfig(
292 IFACE_NAME, mInterfaceConfiguration);
Erik Klineab6439b2017-06-06 19:24:21 +0900293 usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
294 mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
295 usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
Erik Klinedd4d5822017-06-12 18:20:08 +0900296 eq(mTestedSm), mLinkPropertiesCaptor.capture());
297 assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
Christopher Wileyf972edc2016-05-23 16:17:30 -0700298 }
299 }
300
301 @Test
302 public void usbShouldBeTornDownOnTetherError() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900303 initStateMachine(TETHERING_USB);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700304
305 doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME);
Erik Klineea9cc482017-03-10 19:35:34 +0900306 dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED);
Christopher Wileye90e0a72016-05-31 10:44:35 -0700307 InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700308 usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
309 usbTeardownOrder.verify(mNMService).setInterfaceConfig(
310 IFACE_NAME, mInterfaceConfiguration);
Erik Klineab6439b2017-06-06 19:24:21 +0900311 usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
312 mTestedSm, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
313 usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
Erik Klinedd4d5822017-06-12 18:20:08 +0900314 eq(mTestedSm), mLinkPropertiesCaptor.capture());
315 assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
Christopher Wileyf972edc2016-05-23 16:17:30 -0700316 }
317
318 @Test
319 public void shouldTearDownUsbOnUpstreamError() throws Exception {
Erik Klinea954be92017-02-13 17:12:02 +0900320 initTetheredStateMachine(TETHERING_USB, null);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700321
322 doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString());
323 dispatchTetherConnectionChanged(UPSTREAM_IFACE);
Christopher Wileye90e0a72016-05-31 10:44:35 -0700324 InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
Christopher Wileyf972edc2016-05-23 16:17:30 -0700325 usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
326 usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
Erik Klineab6439b2017-06-06 19:24:21 +0900327 usbTeardownOrder.verify(mTetherHelper).updateInterfaceState(
328 mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
329 usbTeardownOrder.verify(mTetherHelper).updateLinkProperties(
Erik Klinedd4d5822017-06-12 18:20:08 +0900330 eq(mTestedSm), mLinkPropertiesCaptor.capture());
331 assertNoAddressesNorRoutes(mLinkPropertiesCaptor.getValue());
Christopher Wileyf972edc2016-05-23 16:17:30 -0700332 }
Christopher Wiley279eca32016-05-20 13:23:10 -0700333
Erik Kline624bf3d2017-02-14 15:55:00 +0900334 @Test
335 public void ignoresDuplicateUpstreamNotifications() throws Exception {
336 initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
337
338 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
339
340 for (int i = 0; i < 5; i++) {
341 dispatchTetherConnectionChanged(UPSTREAM_IFACE);
342 verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
343 }
344 }
345
Christopher Wiley279eca32016-05-20 13:23:10 -0700346 /**
347 * Send a command to the state machine under test, and run the event loop to idle.
348 *
Mitchell Wills4622c2d2016-05-23 16:40:10 -0700349 * @param command One of the TetherInterfaceStateMachine.CMD_* constants.
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900350 * @param arg1 An additional argument to pass.
Erik Klineea9cc482017-03-10 19:35:34 +0900351 */
352 private void dispatchCommand(int command, int arg1) {
353 mTestedSm.sendMessage(command, arg1);
354 mLooper.dispatchAll();
355 }
356
357 /**
358 * Send a command to the state machine under test, and run the event loop to idle.
359 *
360 * @param command One of the TetherInterfaceStateMachine.CMD_* constants.
Christopher Wiley279eca32016-05-20 13:23:10 -0700361 */
362 private void dispatchCommand(int command) {
363 mTestedSm.sendMessage(command);
364 mLooper.dispatchAll();
365 }
366
367 /**
368 * Special override to tell the state machine that the upstream interface has changed.
369 *
370 * @see #dispatchCommand(int)
371 * @param upstreamIface String name of upstream interface (or null)
372 */
373 private void dispatchTetherConnectionChanged(String upstreamIface) {
Mitchell Wills4622c2d2016-05-23 16:40:10 -0700374 mTestedSm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900375 new InterfaceSet(upstreamIface));
Christopher Wiley279eca32016-05-20 13:23:10 -0700376 mLooper.dispatchAll();
Christopher Wiley08725a82016-05-18 16:32:44 -0700377 }
Erik Klinedd4d5822017-06-12 18:20:08 +0900378
379 private void assertIPv4AddressAndDirectlyConnectedRoute(LinkProperties lp) {
380 // Find the first IPv4 LinkAddress.
381 LinkAddress addr4 = null;
382 for (LinkAddress addr : lp.getLinkAddresses()) {
383 if (!(addr.getAddress() instanceof Inet4Address)) continue;
384 addr4 = addr;
385 break;
386 }
387 assertTrue("missing IPv4 address", addr4 != null);
388
389 // Assert the presence of the associated directly connected route.
390 final RouteInfo directlyConnected = new RouteInfo(addr4, null, lp.getInterfaceName());
391 assertTrue("missing directly connected route: '" + directlyConnected.toString() + "'",
392 lp.getRoutes().contains(directlyConnected));
393 }
394
395 private void assertNoAddressesNorRoutes(LinkProperties lp) {
396 assertTrue(lp.getLinkAddresses().isEmpty());
397 assertTrue(lp.getRoutes().isEmpty());
398 // We also check that interface name is non-empty, because we should
399 // never see an empty interface name in any LinkProperties update.
400 assertFalse(TextUtils.isEmpty(lp.getInterfaceName()));
401 }
Lorenzo Colitti5bce5a12016-10-28 17:45:55 +0900402}