• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 com.android.server.connectivity;
18 
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertNull;
21 import static org.junit.Assert.assertTrue;
22 import static org.mockito.Mockito.any;
23 import static org.mockito.Mockito.eq;
24 import static org.mockito.Mockito.times;
25 import static org.mockito.Mockito.verify;
26 import static org.mockito.Mockito.verifyNoMoreInteractions;
27 import static org.mockito.Mockito.when;
28 
29 import android.net.ConnectivityManager;
30 import android.net.InterfaceConfiguration;
31 import android.net.LinkAddress;
32 import android.net.LinkProperties;
33 import android.net.NetworkInfo;
34 import android.os.Handler;
35 import android.os.INetworkManagementService;
36 import android.os.test.TestLooper;
37 import android.support.test.filters.SmallTest;
38 import android.support.test.runner.AndroidJUnit4;
39 
40 import com.android.server.ConnectivityService;
41 
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 import org.mockito.ArgumentCaptor;
46 import org.mockito.Mock;
47 import org.mockito.MockitoAnnotations;
48 
49 @RunWith(AndroidJUnit4.class)
50 @SmallTest
51 public class Nat464XlatTest {
52 
53     static final String BASE_IFACE = "test0";
54     static final String STACKED_IFACE = "v4-test0";
55     static final LinkAddress ADDR = new LinkAddress("192.0.2.5/29");
56 
57     @Mock ConnectivityService mConnectivity;
58     @Mock INetworkManagementService mNms;
59     @Mock InterfaceConfiguration mConfig;
60     @Mock NetworkAgentInfo mNai;
61 
62     TestLooper mLooper;
63     Handler mHandler;
64 
makeNat464Xlat()65     Nat464Xlat makeNat464Xlat() {
66         return new Nat464Xlat(mNms, mNai);
67     }
68 
69     @Before
setUp()70     public void setUp() throws Exception {
71         mLooper = new TestLooper();
72         mHandler = new Handler(mLooper.getLooper());
73 
74         MockitoAnnotations.initMocks(this);
75 
76         mNai.linkProperties = new LinkProperties();
77         mNai.linkProperties.setInterfaceName(BASE_IFACE);
78         mNai.networkInfo = new NetworkInfo(null);
79         mNai.networkInfo.setType(ConnectivityManager.TYPE_WIFI);
80         when(mNai.connService()).thenReturn(mConnectivity);
81         when(mNai.handler()).thenReturn(mHandler);
82 
83         when(mNms.getInterfaceConfig(eq(STACKED_IFACE))).thenReturn(mConfig);
84         when(mConfig.getLinkAddress()).thenReturn(ADDR);
85     }
86 
87     @Test
testRequiresClat()88     public void testRequiresClat() throws Exception {
89         final int[] supportedTypes = {
90             ConnectivityManager.TYPE_MOBILE,
91             ConnectivityManager.TYPE_WIFI,
92             ConnectivityManager.TYPE_ETHERNET,
93         };
94 
95         // NetworkInfo doesn't allow setting the State directly, but rather
96         // requires setting DetailedState in order set State as a side-effect.
97         final NetworkInfo.DetailedState[] supportedDetailedStates = {
98             NetworkInfo.DetailedState.CONNECTED,
99             NetworkInfo.DetailedState.SUSPENDED,
100         };
101 
102         for (int type : supportedTypes) {
103             mNai.networkInfo.setType(type);
104             for (NetworkInfo.DetailedState state : supportedDetailedStates) {
105                 mNai.networkInfo.setDetailedState(state, "reason", "extraInfo");
106                 assertTrue(
107                         String.format("requiresClat expected for type=%d state=%s", type, state),
108                         Nat464Xlat.requiresClat(mNai));
109             }
110         }
111     }
112 
113     @Test
testNormalStartAndStop()114     public void testNormalStartAndStop() throws Exception {
115         Nat464Xlat nat = makeNat464Xlat();
116         ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
117 
118         // ConnectivityService starts clat.
119         nat.start();
120 
121         verify(mNms).registerObserver(eq(nat));
122         verify(mNms).startClatd(eq(BASE_IFACE));
123 
124         // Stacked interface up notification arrives.
125         nat.interfaceLinkStateChanged(STACKED_IFACE, true);
126         mLooper.dispatchNext();
127 
128         verify(mNms).getInterfaceConfig(eq(STACKED_IFACE));
129         verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
130         assertFalse(c.getValue().getStackedLinks().isEmpty());
131         assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
132         assertRunning(nat);
133 
134         // ConnectivityService stops clat (Network disconnects, IPv4 addr appears, ...).
135         nat.stop();
136 
137         verify(mNms).stopClatd(eq(BASE_IFACE));
138 
139         // Stacked interface removed notification arrives.
140         nat.interfaceRemoved(STACKED_IFACE);
141         mLooper.dispatchNext();
142 
143         verify(mNms).unregisterObserver(eq(nat));
144         verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
145         assertTrue(c.getValue().getStackedLinks().isEmpty());
146         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
147         assertIdle(nat);
148 
149         verifyNoMoreInteractions(mNms, mConnectivity);
150     }
151 
152     @Test
testClatdCrashWhileRunning()153     public void testClatdCrashWhileRunning() throws Exception {
154         Nat464Xlat nat = makeNat464Xlat();
155         ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
156 
157         // ConnectivityService starts clat.
158         nat.start();
159 
160         verify(mNms).registerObserver(eq(nat));
161         verify(mNms).startClatd(eq(BASE_IFACE));
162 
163         // Stacked interface up notification arrives.
164         nat.interfaceLinkStateChanged(STACKED_IFACE, true);
165         mLooper.dispatchNext();
166 
167         verify(mNms).getInterfaceConfig(eq(STACKED_IFACE));
168         verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
169         assertFalse(c.getValue().getStackedLinks().isEmpty());
170         assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
171         assertRunning(nat);
172 
173         // Stacked interface removed notification arrives (clatd crashed, ...).
174         nat.interfaceRemoved(STACKED_IFACE);
175         mLooper.dispatchNext();
176 
177         verify(mNms).unregisterObserver(eq(nat));
178         verify(mNms).stopClatd(eq(BASE_IFACE));
179         verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
180         assertTrue(c.getValue().getStackedLinks().isEmpty());
181         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
182         assertIdle(nat);
183 
184         // ConnectivityService stops clat: no-op.
185         nat.stop();
186 
187         verifyNoMoreInteractions(mNms, mConnectivity);
188     }
189 
190     @Test
testStopBeforeClatdStarts()191     public void testStopBeforeClatdStarts() throws Exception {
192         Nat464Xlat nat = makeNat464Xlat();
193 
194         // ConnectivityService starts clat.
195         nat.start();
196 
197         verify(mNms).registerObserver(eq(nat));
198         verify(mNms).startClatd(eq(BASE_IFACE));
199 
200         // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
201         nat.stop();
202 
203         verify(mNms).unregisterObserver(eq(nat));
204         verify(mNms).stopClatd(eq(BASE_IFACE));
205         assertIdle(nat);
206 
207         // In-flight interface up notification arrives: no-op
208         nat.interfaceLinkStateChanged(STACKED_IFACE, true);
209         mLooper.dispatchNext();
210 
211 
212         // Interface removed notification arrives after stopClatd() takes effect: no-op.
213         nat.interfaceRemoved(STACKED_IFACE);
214         mLooper.dispatchNext();
215 
216         assertIdle(nat);
217 
218         verifyNoMoreInteractions(mNms, mConnectivity);
219     }
220 
221     @Test
testStopAndClatdNeverStarts()222     public void testStopAndClatdNeverStarts() throws Exception {
223         Nat464Xlat nat = makeNat464Xlat();
224 
225         // ConnectivityService starts clat.
226         nat.start();
227 
228         verify(mNms).registerObserver(eq(nat));
229         verify(mNms).startClatd(eq(BASE_IFACE));
230 
231         // ConnectivityService immediately stops clat (Network disconnects, IPv4 addr appears, ...)
232         nat.stop();
233 
234         verify(mNms).unregisterObserver(eq(nat));
235         verify(mNms).stopClatd(eq(BASE_IFACE));
236         assertIdle(nat);
237 
238         verifyNoMoreInteractions(mNms, mConnectivity);
239     }
240 
assertIdle(Nat464Xlat nat)241     static void assertIdle(Nat464Xlat nat) {
242         assertTrue("Nat464Xlat was not IDLE", !nat.isStarted());
243     }
244 
assertRunning(Nat464Xlat nat)245     static void assertRunning(Nat464Xlat nat) {
246         assertTrue("Nat464Xlat was not RUNNING", nat.isRunning());
247     }
248 }
249