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