1 /* 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 17 package android.net.shared; 18 19 import static android.net.INetd.LOCAL_NET_ID; 20 import static android.system.OsConstants.EBUSY; 21 22 import static org.junit.Assert.assertEquals; 23 import static org.junit.Assert.fail; 24 import static org.mockito.Matchers.any; 25 import static org.mockito.Matchers.anyInt; 26 import static org.mockito.Matchers.anyString; 27 import static org.mockito.Matchers.eq; 28 import static org.mockito.Mockito.doAnswer; 29 import static org.mockito.Mockito.never; 30 import static org.mockito.Mockito.reset; 31 import static org.mockito.Mockito.times; 32 import static org.mockito.Mockito.verify; 33 import static org.mockito.Mockito.verifyNoMoreInteractions; 34 35 import android.net.INetd; 36 import android.net.IpPrefix; 37 import android.os.RemoteException; 38 import android.os.ServiceSpecificException; 39 40 import androidx.test.filters.SmallTest; 41 import androidx.test.runner.AndroidJUnit4; 42 43 import org.junit.Before; 44 import org.junit.Test; 45 import org.junit.runner.RunWith; 46 import org.mockito.Mock; 47 import org.mockito.MockitoAnnotations; 48 49 @RunWith(AndroidJUnit4.class) 50 @SmallTest 51 public final class NetdUtilsTest { 52 private static final String IFACE_NAME = "testnet1"; 53 private static final IpPrefix TEST_IPPREFIX = new IpPrefix("192.168.42.1/24"); 54 55 @Mock private INetd mNetd; 56 setUp()57 @Before public void setUp() throws Exception { 58 MockitoAnnotations.initMocks(this); 59 } 60 setNetworkAddInterfaceOutcome(final Exception cause, int numLoops)61 private void setNetworkAddInterfaceOutcome(final Exception cause, int numLoops) 62 throws Exception { 63 // This cannot be an int because local variables referenced from a lambda expression must 64 // be final or effectively final. 65 final Counter myCounter = new Counter(); 66 doAnswer((invocation) -> { 67 myCounter.count(); 68 if (myCounter.isCounterReached(numLoops)) { 69 if (cause == null) return null; 70 71 throw cause; 72 } 73 74 throw new ServiceSpecificException(EBUSY); 75 }).when(mNetd).networkAddInterface(LOCAL_NET_ID, IFACE_NAME); 76 } 77 78 class Counter { 79 private int mValue = 0; 80 count()81 private void count() { 82 mValue++; 83 } 84 isCounterReached(int target)85 private boolean isCounterReached(int target) { 86 return mValue >= target; 87 } 88 } 89 verifyTetherInterfaceSucceeds(int expectedTries)90 private void verifyTetherInterfaceSucceeds(int expectedTries) throws Exception { 91 setNetworkAddInterfaceOutcome(null, expectedTries); 92 93 NetdUtils.tetherInterface(mNetd, IFACE_NAME, TEST_IPPREFIX); 94 verify(mNetd).tetherInterfaceAdd(IFACE_NAME); 95 verify(mNetd, times(expectedTries)).networkAddInterface(LOCAL_NET_ID, IFACE_NAME); 96 verify(mNetd, times(2)).networkAddRoute(eq(LOCAL_NET_ID), eq(IFACE_NAME), any(), any()); 97 verifyNoMoreInteractions(mNetd); 98 reset(mNetd); 99 } 100 101 @Test testTetherInterfaceSuccessful()102 public void testTetherInterfaceSuccessful() throws Exception { 103 // Expect #networkAddInterface successful at first tries. 104 verifyTetherInterfaceSucceeds(1); 105 106 // Expect #networkAddInterface successful after 10 tries. 107 verifyTetherInterfaceSucceeds(10); 108 } 109 runTetherInterfaceWithServiceSpecificException(int expectedTries, int expectedCode)110 private void runTetherInterfaceWithServiceSpecificException(int expectedTries, 111 int expectedCode) throws Exception { 112 setNetworkAddInterfaceOutcome(new ServiceSpecificException(expectedCode), expectedTries); 113 114 try { 115 NetdUtils.tetherInterface(mNetd, IFACE_NAME, TEST_IPPREFIX, 20, 0); 116 fail("Expect throw ServiceSpecificException"); 117 } catch (ServiceSpecificException e) { 118 assertEquals(e.errorCode, expectedCode); 119 } 120 121 verifyNetworkAddInterfaceFails(expectedTries); 122 reset(mNetd); 123 } 124 runTetherInterfaceWithRemoteException(int expectedTries)125 private void runTetherInterfaceWithRemoteException(int expectedTries) throws Exception { 126 setNetworkAddInterfaceOutcome(new RemoteException(), expectedTries); 127 128 try { 129 NetdUtils.tetherInterface(mNetd, IFACE_NAME, TEST_IPPREFIX, 20, 0); 130 fail("Expect throw RemoteException"); 131 } catch (RemoteException e) { } 132 133 verifyNetworkAddInterfaceFails(expectedTries); 134 reset(mNetd); 135 } 136 verifyNetworkAddInterfaceFails(int expectedTries)137 private void verifyNetworkAddInterfaceFails(int expectedTries) throws Exception { 138 verify(mNetd).tetherInterfaceAdd(IFACE_NAME); 139 verify(mNetd, times(expectedTries)).networkAddInterface(LOCAL_NET_ID, IFACE_NAME); 140 verify(mNetd, never()).networkAddRoute(anyInt(), anyString(), any(), any()); 141 verifyNoMoreInteractions(mNetd); 142 } 143 144 @Test testTetherInterfaceFailOnNetworkAddInterface()145 public void testTetherInterfaceFailOnNetworkAddInterface() throws Exception { 146 // Test throwing ServiceSpecificException with EBUSY failure. 147 runTetherInterfaceWithServiceSpecificException(20, EBUSY); 148 149 // Test throwing ServiceSpecificException with unexpectedError. 150 final int unexpectedError = 999; 151 runTetherInterfaceWithServiceSpecificException(1, unexpectedError); 152 153 // Test throwing ServiceSpecificException with unexpectedError after 7 tries. 154 runTetherInterfaceWithServiceSpecificException(7, unexpectedError); 155 156 // Test throwing RemoteException. 157 runTetherInterfaceWithRemoteException(1); 158 159 // Test throwing RemoteException after 3 tries. 160 runTetherInterfaceWithRemoteException(3); 161 } 162 } 163