108725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley/* 208725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley * Copyright (C) 2016 The Android Open Source Project 308725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley * 408725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley * Licensed under the Apache License, Version 2.0 (the "License"); 508725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley * you may not use this file except in compliance with the License. 608725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley * You may obtain a copy of the License at 708725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley * 808725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley * http://www.apache.org/licenses/LICENSE-2.0 908725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley * 1008725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley * Unless required by applicable law or agreed to in writing, software 1108725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley * distributed under the License is distributed on an "AS IS" BASIS, 1208725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1308725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley * See the License for the specific language governing permissions and 1408725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley * limitations under the License. 1508725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley */ 1608725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley 1708725a8c4042aee177774f6275811aa88f26ef30Christopher Wileypackage com.android.server.connectivity.tethering; 1808725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley 19f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wileyimport static org.mockito.Matchers.anyString; 20f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wileyimport static org.mockito.Mockito.doThrow; 21279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wileyimport static org.mockito.Mockito.inOrder; 22279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wileyimport static org.mockito.Mockito.reset; 23279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wileyimport static org.mockito.Mockito.verify; 2408725a8c4042aee177774f6275811aa88f26ef30Christopher Wileyimport static org.mockito.Mockito.verifyNoMoreInteractions; 25279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wileyimport static org.mockito.Mockito.when; 2608725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley 27e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wileyimport static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR; 28e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wileyimport static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; 29e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wileyimport static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR; 30e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wileyimport static android.net.ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; 31a954be956315e6d25a63e961fc9befe9916e1cbdErik Klineimport static android.net.ConnectivityManager.TETHERING_BLUETOOTH; 32a954be956315e6d25a63e961fc9befe9916e1cbdErik Klineimport static android.net.ConnectivityManager.TETHERING_USB; 33a954be956315e6d25a63e961fc9befe9916e1cbdErik Klineimport static android.net.ConnectivityManager.TETHERING_WIFI; 34e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wileyimport static com.android.server.connectivity.tethering.IControlsTethering.STATE_AVAILABLE; 35e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wileyimport static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED; 36e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wileyimport static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE; 37e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley 38cd0cfbbc61168b61360a6247b4a826494deb3912Christopher Wileyimport android.net.ConnectivityManager; 3908725a8c4042aee177774f6275811aa88f26ef30Christopher Wileyimport android.net.INetworkStatsService; 40279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wileyimport android.net.InterfaceConfiguration; 41292b65a6f11a37b5cbb354fab5587484c2ef4d2eErik Klineimport android.net.util.SharedLog; 4208725a8c4042aee177774f6275811aa88f26ef30Christopher Wileyimport android.os.INetworkManagementService; 43279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wileyimport android.os.RemoteException; 4408725a8c4042aee177774f6275811aa88f26ef30Christopher Wileyimport android.os.test.TestLooper; 459bc0df24827336889d3100542536595c2809c3ceChristopher Wileyimport android.support.test.filters.SmallTest; 469bc0df24827336889d3100542536595c2809c3ceChristopher Wileyimport android.support.test.runner.AndroidJUnit4; 4708725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley 4808725a8c4042aee177774f6275811aa88f26ef30Christopher Wileyimport org.junit.Before; 4908725a8c4042aee177774f6275811aa88f26ef30Christopher Wileyimport org.junit.Test; 509bc0df24827336889d3100542536595c2809c3ceChristopher Wileyimport org.junit.runner.RunWith; 51279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wileyimport org.mockito.InOrder; 5208725a8c4042aee177774f6275811aa88f26ef30Christopher Wileyimport org.mockito.Mock; 5308725a8c4042aee177774f6275811aa88f26ef30Christopher Wileyimport org.mockito.MockitoAnnotations; 5408725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley 559bc0df24827336889d3100542536595c2809c3ceChristopher Wiley@RunWith(AndroidJUnit4.class) 569bc0df24827336889d3100542536595c2809c3ceChristopher Wiley@SmallTest 574622c2d8b65e267ede15bffd903faaf917642d7eMitchell Willspublic class TetherInterfaceStateMachineTest { 5808725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley private static final String IFACE_NAME = "testnet1"; 59279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley private static final String UPSTREAM_IFACE = "upstream0"; 60279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley private static final String UPSTREAM_IFACE2 = "upstream1"; 6108725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley 6208725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley @Mock private INetworkManagementService mNMService; 6308725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley @Mock private INetworkStatsService mStatsService; 6408725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley @Mock private IControlsTethering mTetherHelper; 65279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley @Mock private InterfaceConfiguration mInterfaceConfiguration; 665bce5a16b17498981253d7a2d1a490667cd71798Lorenzo Colitti @Mock private IPv6TetheringInterfaceServices mIPv6TetheringInterfaceServices; 67292b65a6f11a37b5cbb354fab5587484c2ef4d2eErik Kline @Mock private SharedLog mSharedLog; 6808725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley 6908725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley private final TestLooper mLooper = new TestLooper(); 704622c2d8b65e267ede15bffd903faaf917642d7eMitchell Wills private TetherInterfaceStateMachine mTestedSm; 7108725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley 72cd0cfbbc61168b61360a6247b4a826494deb3912Christopher Wiley private void initStateMachine(int interfaceType) throws Exception { 73292b65a6f11a37b5cbb354fab5587484c2ef4d2eErik Kline mTestedSm = new TetherInterfaceStateMachine( 74292b65a6f11a37b5cbb354fab5587484c2ef4d2eErik Kline IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, 755bce5a16b17498981253d7a2d1a490667cd71798Lorenzo Colitti mNMService, mStatsService, mTetherHelper, mIPv6TetheringInterfaceServices); 76279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley mTestedSm.start(); 77279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley // Starting the state machine always puts us in a consistent state and notifies 78279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley // the test of the world that we've changed from an unknown to available state. 79279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley mLooper.dispatchAll(); 80279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley reset(mNMService, mStatsService, mTetherHelper); 81f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration); 82279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley } 83279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 84cd0cfbbc61168b61360a6247b4a826494deb3912Christopher Wiley private void initTetheredStateMachine(int interfaceType, String upstreamIface) throws Exception { 85cd0cfbbc61168b61360a6247b4a826494deb3912Christopher Wiley initStateMachine(interfaceType); 865f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED); 87279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley if (upstreamIface != null) { 88279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley dispatchTetherConnectionChanged(upstreamIface); 89279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley } 90279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley reset(mNMService, mStatsService, mTetherHelper); 91f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration); 92279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley } 93279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 94e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley @Before public void setUp() throws Exception { 9508725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley MockitoAnnotations.initMocks(this); 96292b65a6f11a37b5cbb354fab5587484c2ef4d2eErik Kline when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); 97279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley } 98279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 99279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley @Test 100279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley public void startsOutAvailable() { 101cd0cfbbc61168b61360a6247b4a826494deb3912Christopher Wiley mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), 102292b65a6f11a37b5cbb354fab5587484c2ef4d2eErik Kline TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper, 1035bce5a16b17498981253d7a2d1a490667cd71798Lorenzo Colitti mIPv6TetheringInterfaceServices); 10408725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley mTestedSm.start(); 105279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley mLooper.dispatchAll(); 106e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley verify(mTetherHelper).notifyInterfaceStateChange( 107e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); 108279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley verifyNoMoreInteractions(mTetherHelper, mNMService, mStatsService); 10908725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley } 11008725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley 11108725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley @Test 112f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley public void shouldDoNothingUntilRequested() throws Exception { 113a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline initStateMachine(TETHERING_BLUETOOTH); 11408725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley final int [] NOOP_COMMANDS = { 1154622c2d8b65e267ede15bffd903faaf917642d7eMitchell Wills TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED, 1164622c2d8b65e267ede15bffd903faaf917642d7eMitchell Wills TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR, 1174622c2d8b65e267ede15bffd903faaf917642d7eMitchell Wills TetherInterfaceStateMachine.CMD_IP_FORWARDING_DISABLE_ERROR, 1184622c2d8b65e267ede15bffd903faaf917642d7eMitchell Wills TetherInterfaceStateMachine.CMD_START_TETHERING_ERROR, 1194622c2d8b65e267ede15bffd903faaf917642d7eMitchell Wills TetherInterfaceStateMachine.CMD_STOP_TETHERING_ERROR, 1204622c2d8b65e267ede15bffd903faaf917642d7eMitchell Wills TetherInterfaceStateMachine.CMD_SET_DNS_FORWARDERS_ERROR, 1214622c2d8b65e267ede15bffd903faaf917642d7eMitchell Wills TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED 12208725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley }; 12308725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley for (int command : NOOP_COMMANDS) { 124279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley // None of these commands should trigger us to request action from 12508725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley // the rest of the system. 126279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley dispatchCommand(command); 127279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); 12808725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley } 12908725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley } 13008725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley 131279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley @Test 132f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley public void handlesImmediateInterfaceDown() throws Exception { 133a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline initStateMachine(TETHERING_BLUETOOTH); 134e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley 1354622c2d8b65e267ede15bffd903faaf917642d7eMitchell Wills dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN); 136e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley verify(mTetherHelper).notifyInterfaceStateChange( 137e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley IFACE_NAME, mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR); 138279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); 139279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley } 140279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 141279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley @Test 142f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley public void canBeTethered() throws Exception { 143a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline initStateMachine(TETHERING_BLUETOOTH); 144e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley 1455f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED); 146279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley InOrder inOrder = inOrder(mTetherHelper, mNMService); 147279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mNMService).tetherInterface(IFACE_NAME); 148e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley inOrder.verify(mTetherHelper).notifyInterfaceStateChange( 149e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley IFACE_NAME, mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR); 150279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); 151279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley } 152279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 153279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley @Test 154279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley public void canUnrequestTethering() throws Exception { 155a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline initTetheredStateMachine(TETHERING_BLUETOOTH, null); 156279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 1574622c2d8b65e267ede15bffd903faaf917642d7eMitchell Wills dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED); 158279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper); 159f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley inOrder.verify(mNMService).untetherInterface(IFACE_NAME); 160e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley inOrder.verify(mTetherHelper).notifyInterfaceStateChange( 161e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); 162279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); 163279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley } 164279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 165279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley @Test 166f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley public void canBeTetheredAsUsb() throws Exception { 167a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline initStateMachine(TETHERING_USB); 168279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 1695f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED); 170279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley InOrder inOrder = inOrder(mTetherHelper, mNMService); 171279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME); 172279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration); 173279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mNMService).tetherInterface(IFACE_NAME); 174e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley inOrder.verify(mTetherHelper).notifyInterfaceStateChange( 175e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley IFACE_NAME, mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR); 176279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); 177279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley } 178279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 179279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley @Test 180279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley public void handlesFirstUpstreamChange() throws Exception { 181a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline initTetheredStateMachine(TETHERING_BLUETOOTH, null); 182279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 183279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley // Telling the state machine about its upstream interface triggers a little more configuration. 184279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley dispatchTetherConnectionChanged(UPSTREAM_IFACE); 185279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley InOrder inOrder = inOrder(mNMService); 186279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE); 187279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); 188279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); 189279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley } 190279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 191279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley @Test 192279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley public void handlesChangingUpstream() throws Exception { 193a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE); 194279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 195279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley dispatchTetherConnectionChanged(UPSTREAM_IFACE2); 196279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley InOrder inOrder = inOrder(mNMService, mStatsService); 197279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mStatsService).forceUpdate(); 198279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); 199279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE); 200279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2); 201279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2); 202279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); 203279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley } 204279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 205279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley @Test 206a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline public void handlesChangingUpstreamNatFailure() throws Exception { 207a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); 208a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline 209a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline doThrow(RemoteException.class).when(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2); 210a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline 211a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline dispatchTetherConnectionChanged(UPSTREAM_IFACE2); 212a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline InOrder inOrder = inOrder(mNMService, mStatsService); 213a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline inOrder.verify(mStatsService).forceUpdate(); 214a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); 215a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE); 216a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2); 2178ea45483fc59ef63851a64640ed1bb18c09f7ea9Erik Kline inOrder.verify(mStatsService).forceUpdate(); 2188ea45483fc59ef63851a64640ed1bb18c09f7ea9Erik Kline inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2); 2198ea45483fc59ef63851a64640ed1bb18c09f7ea9Erik Kline inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2); 220a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline } 221a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline 222a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline @Test 223a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline public void handlesChangingUpstreamInterfaceForwardingFailure() throws Exception { 224a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); 225a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline 226a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline doThrow(RemoteException.class).when(mNMService).startInterfaceForwarding( 227a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline IFACE_NAME, UPSTREAM_IFACE2); 228a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline 229a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline dispatchTetherConnectionChanged(UPSTREAM_IFACE2); 230a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline InOrder inOrder = inOrder(mNMService, mStatsService); 231a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline inOrder.verify(mStatsService).forceUpdate(); 232a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); 233a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE); 234a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2); 235a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2); 2368ea45483fc59ef63851a64640ed1bb18c09f7ea9Erik Kline inOrder.verify(mStatsService).forceUpdate(); 2378ea45483fc59ef63851a64640ed1bb18c09f7ea9Erik Kline inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2); 2388ea45483fc59ef63851a64640ed1bb18c09f7ea9Erik Kline inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2); 239a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline } 240a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline 241a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline @Test 242279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley public void canUnrequestTetheringWithUpstream() throws Exception { 243a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE); 244279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 2454622c2d8b65e267ede15bffd903faaf917642d7eMitchell Wills dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED); 246279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper); 247279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mStatsService).forceUpdate(); 248279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE); 249279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE); 250279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley inOrder.verify(mNMService).untetherInterface(IFACE_NAME); 251e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley inOrder.verify(mTetherHelper).notifyInterfaceStateChange( 252e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); 253279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); 254279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley } 255279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 256f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley @Test 257f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley public void interfaceDownLeadsToUnavailable() throws Exception { 258f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley for (boolean shouldThrow : new boolean[]{true, false}) { 259a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline initTetheredStateMachine(TETHERING_USB, null); 260f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley 261f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley if (shouldThrow) { 262f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME); 263f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley } 264f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN); 265e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper); 266f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown(); 267f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley usbTeardownOrder.verify(mNMService).setInterfaceConfig( 268f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley IFACE_NAME, mInterfaceConfiguration); 269e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley usbTeardownOrder.verify(mTetherHelper).notifyInterfaceStateChange( 270e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley IFACE_NAME, mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR); 271f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley } 272f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley } 273f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley 274f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley @Test 275f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley public void usbShouldBeTornDownOnTetherError() throws Exception { 276a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline initStateMachine(TETHERING_USB); 277f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley 278f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME); 2795f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, STATE_TETHERED); 280e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper); 281f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown(); 282f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley usbTeardownOrder.verify(mNMService).setInterfaceConfig( 283f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley IFACE_NAME, mInterfaceConfiguration); 284e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley usbTeardownOrder.verify(mTetherHelper).notifyInterfaceStateChange( 285e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR); 286f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley } 287f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley 288f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley @Test 289f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley public void shouldTearDownUsbOnUpstreamError() throws Exception { 290a954be956315e6d25a63e961fc9befe9916e1cbdErik Kline initTetheredStateMachine(TETHERING_USB, null); 291f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley 292f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString()); 293f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley dispatchTetherConnectionChanged(UPSTREAM_IFACE); 294e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper); 295f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown(); 296f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration); 297e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley usbTeardownOrder.verify(mTetherHelper).notifyInterfaceStateChange( 298e90e0a74adf33f3d0ed0f2617520ab72b3b5d624Christopher Wiley IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR); 299f972edcae7386d0dfc596aaa01e97d039dd1e0e2Christopher Wiley } 300279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 301624bf3d7f66e496952c5ae8917dc785676921c99Erik Kline @Test 302624bf3d7f66e496952c5ae8917dc785676921c99Erik Kline public void ignoresDuplicateUpstreamNotifications() throws Exception { 303624bf3d7f66e496952c5ae8917dc785676921c99Erik Kline initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); 304624bf3d7f66e496952c5ae8917dc785676921c99Erik Kline 305624bf3d7f66e496952c5ae8917dc785676921c99Erik Kline verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); 306624bf3d7f66e496952c5ae8917dc785676921c99Erik Kline 307624bf3d7f66e496952c5ae8917dc785676921c99Erik Kline for (int i = 0; i < 5; i++) { 308624bf3d7f66e496952c5ae8917dc785676921c99Erik Kline dispatchTetherConnectionChanged(UPSTREAM_IFACE); 309624bf3d7f66e496952c5ae8917dc785676921c99Erik Kline verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper); 310624bf3d7f66e496952c5ae8917dc785676921c99Erik Kline } 311624bf3d7f66e496952c5ae8917dc785676921c99Erik Kline } 312624bf3d7f66e496952c5ae8917dc785676921c99Erik Kline 313279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley /** 314279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley * Send a command to the state machine under test, and run the event loop to idle. 315279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley * 3164622c2d8b65e267ede15bffd903faaf917642d7eMitchell Wills * @param command One of the TetherInterfaceStateMachine.CMD_* constants. 3175f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline * @param obj An additional argument to pass. 3185f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline */ 3195f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline private void dispatchCommand(int command, int arg1) { 3205f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline mTestedSm.sendMessage(command, arg1); 3215f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline mLooper.dispatchAll(); 3225f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline } 3235f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline 3245f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline /** 3255f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline * Send a command to the state machine under test, and run the event loop to idle. 3265f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline * 3275f2b7992cfe1149de115c6f7056d0da128b8afbaErik Kline * @param command One of the TetherInterfaceStateMachine.CMD_* constants. 328279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley */ 329279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley private void dispatchCommand(int command) { 330279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley mTestedSm.sendMessage(command); 331279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley mLooper.dispatchAll(); 332279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley } 333279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley 334279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley /** 335279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley * Special override to tell the state machine that the upstream interface has changed. 336279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley * 337279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley * @see #dispatchCommand(int) 338279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley * @param upstreamIface String name of upstream interface (or null) 339279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley */ 340279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley private void dispatchTetherConnectionChanged(String upstreamIface) { 3414622c2d8b65e267ede15bffd903faaf917642d7eMitchell Wills mTestedSm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED, 3424622c2d8b65e267ede15bffd903faaf917642d7eMitchell Wills upstreamIface); 343279eca3de6f0eb3cd9a947991fe9d1d5d2cd13c1Christopher Wiley mLooper.dispatchAll(); 34408725a8c4042aee177774f6275811aa88f26ef30Christopher Wiley } 3455bce5a16b17498981253d7a2d1a490667cd71798Lorenzo Colitti} 346