blob: bd488ea4145fa0db87d75e52d0fb837879c1d662 [file] [log] [blame]
Erik Klineaa95ae52017-03-14 10:01:58 +09001/*
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
17package android.net.ip;
18
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +090019import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
20
Hugo Benichifd31b9d2017-06-23 10:07:08 +090021import static org.junit.Assert.assertEquals;
Hugo Benichid00ddf52017-08-08 13:08:06 +090022import static org.junit.Assert.assertFalse;
23import static org.junit.Assert.assertTrue;
Hugo Benichifd31b9d2017-06-23 10:07:08 +090024import static org.junit.Assert.fail;
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +090025import static org.mockito.ArgumentMatchers.argThat;
Hugo Benichifd31b9d2017-06-23 10:07:08 +090026import static org.mockito.Mockito.any;
Erik Klineb152cd02018-03-02 16:51:13 +090027import static org.mockito.Mockito.anyString;
Hugo Benichifd31b9d2017-06-23 10:07:08 +090028import static org.mockito.Mockito.eq;
Hugo Benichifd31b9d2017-06-23 10:07:08 +090029import static org.mockito.Mockito.never;
Hugo Benichie9bdc192017-07-21 14:12:26 +090030import static org.mockito.Mockito.reset;
Hugo Benichifd31b9d2017-06-23 10:07:08 +090031import static org.mockito.Mockito.timeout;
32import static org.mockito.Mockito.times;
33import static org.mockito.Mockito.verify;
Erik Klineaa95ae52017-03-14 10:01:58 +090034import static org.mockito.Mockito.when;
35
Hugo Benichifd31b9d2017-06-23 10:07:08 +090036import android.app.AlarmManager;
Remi NGUYEN VAN22cd6852019-03-08 18:03:07 +090037import android.content.ContentResolver;
Erik Klineaa95ae52017-03-14 10:01:58 +090038import android.content.Context;
39import android.content.res.Resources;
Remi NGUYEN VAN97f69c22019-01-20 20:35:06 +090040import android.net.ConnectivityManager;
Hugo Benichid00ddf52017-08-08 13:08:06 +090041import android.net.INetd;
Hugo Benichifd31b9d2017-06-23 10:07:08 +090042import android.net.IpPrefix;
43import android.net.LinkAddress;
Hugo Benichid00ddf52017-08-08 13:08:06 +090044import android.net.LinkProperties;
Erik Klineb152cd02018-03-02 16:51:13 +090045import android.net.MacAddress;
Hugo Benichid00ddf52017-08-08 13:08:06 +090046import android.net.RouteInfo;
Remi NGUYEN VANa5d31f52019-01-12 15:36:47 +090047import android.net.shared.InitialConfiguration;
48import android.net.shared.ProvisioningConfiguration;
Erik Klineb152cd02018-03-02 16:51:13 +090049import android.net.util.InterfaceParams;
Erik Klineaa95ae52017-03-14 10:01:58 +090050
Brett Chabot8091d9e2019-02-26 14:52:33 -080051import androidx.test.filters.SmallTest;
52import androidx.test.runner.AndroidJUnit4;
53
Erik Klineaa95ae52017-03-14 10:01:58 +090054import com.android.internal.R;
Remi NGUYEN VAN31d74472019-01-28 15:15:59 +090055import com.android.server.NetworkObserver;
56import com.android.server.NetworkObserverRegistry;
Erik Klineaa95ae52017-03-14 10:01:58 +090057
58import org.junit.Before;
Erik Klineaa95ae52017-03-14 10:01:58 +090059import org.junit.Test;
Hugo Benichifd31b9d2017-06-23 10:07:08 +090060import org.junit.runner.RunWith;
Hugo Benichid00ddf52017-08-08 13:08:06 +090061import org.mockito.ArgumentCaptor;
Erik Klineaa95ae52017-03-14 10:01:58 +090062import org.mockito.Mock;
63import org.mockito.MockitoAnnotations;
64
Hugo Benichifd31b9d2017-06-23 10:07:08 +090065import java.net.InetAddress;
Hugo Benichid00ddf52017-08-08 13:08:06 +090066import java.util.Arrays;
Hugo Benichifd31b9d2017-06-23 10:07:08 +090067import java.util.HashSet;
Remi NGUYEN VANa5d31f52019-01-12 15:36:47 +090068import java.util.List;
Hugo Benichifd31b9d2017-06-23 10:07:08 +090069import java.util.Set;
70
Erik Klineaa95ae52017-03-14 10:01:58 +090071/**
Erik Klineb152cd02018-03-02 16:51:13 +090072 * Tests for IpClient.
Erik Klineaa95ae52017-03-14 10:01:58 +090073 */
74@RunWith(AndroidJUnit4.class)
75@SmallTest
Erik Klineb152cd02018-03-02 16:51:13 +090076public class IpClientTest {
Erik Kline246bc1f2017-03-14 13:00:27 +090077 private static final int DEFAULT_AVOIDBADWIFI_CONFIG_VALUE = 1;
78
Hugo Benichifd31b9d2017-06-23 10:07:08 +090079 private static final String VALID = "VALID";
80 private static final String INVALID = "INVALID";
Erik Klineb152cd02018-03-02 16:51:13 +090081 private static final String TEST_IFNAME = "test_wlan0";
82 private static final int TEST_IFINDEX = 1001;
83 // See RFC 7042#section-2.1.2 for EUI-48 documentation values.
84 private static final MacAddress TEST_MAC = MacAddress.fromString("00:00:5E:00:53:01");
Lorenzo Colitti87c7dff2018-12-07 18:59:38 +090085 private static final int TEST_TIMEOUT_MS = 400;
Hugo Benichifd31b9d2017-06-23 10:07:08 +090086
Erik Klineaa95ae52017-03-14 10:01:58 +090087 @Mock private Context mContext;
Remi NGUYEN VAN97f69c22019-01-20 20:35:06 +090088 @Mock private ConnectivityManager mCm;
Remi NGUYEN VAN31d74472019-01-28 15:15:59 +090089 @Mock private NetworkObserverRegistry mObserverRegistry;
Hugo Benichid00ddf52017-08-08 13:08:06 +090090 @Mock private INetd mNetd;
Erik Klineaa95ae52017-03-14 10:01:58 +090091 @Mock private Resources mResources;
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +090092 @Mock private IIpClientCallbacks mCb;
Hugo Benichifd31b9d2017-06-23 10:07:08 +090093 @Mock private AlarmManager mAlarm;
Remi NGUYEN VAN31d74472019-01-28 15:15:59 +090094 @Mock private IpClient.Dependencies mDependencies;
Remi NGUYEN VAN22cd6852019-03-08 18:03:07 +090095 @Mock private ContentResolver mContentResolver;
Erik Klineaa95ae52017-03-14 10:01:58 +090096
Remi NGUYEN VAN31d74472019-01-28 15:15:59 +090097 private NetworkObserver mObserver;
Erik Klineb152cd02018-03-02 16:51:13 +090098 private InterfaceParams mIfParams;
Hugo Benichid00ddf52017-08-08 13:08:06 +090099
Hugo Benichic10fe5f2017-07-18 16:17:49 +0900100 @Before
101 public void setUp() throws Exception {
Erik Klineaa95ae52017-03-14 10:01:58 +0900102 MockitoAnnotations.initMocks(this);
103
Hugo Benichifd31b9d2017-06-23 10:07:08 +0900104 when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
Remi NGUYEN VAN89485142019-01-24 20:13:09 +0900105 when(mContext.getSystemService(eq(ConnectivityManager.class))).thenReturn(mCm);
Erik Klineaa95ae52017-03-14 10:01:58 +0900106 when(mContext.getResources()).thenReturn(mResources);
Remi NGUYEN VANdacee142019-02-13 18:28:35 +0900107 when(mDependencies.getNetd(any())).thenReturn(mNetd);
Erik Klineaa95ae52017-03-14 10:01:58 +0900108 when(mResources.getInteger(R.integer.config_networkAvoidBadWifi))
Erik Kline246bc1f2017-03-14 13:00:27 +0900109 .thenReturn(DEFAULT_AVOIDBADWIFI_CONFIG_VALUE);
Erik Klineaa95ae52017-03-14 10:01:58 +0900110 when(mContext.getContentResolver()).thenReturn(mContentResolver);
Erik Klineb152cd02018-03-02 16:51:13 +0900111
112 mIfParams = null;
Erik Klineaa95ae52017-03-14 10:01:58 +0900113 }
114
Erik Klineb152cd02018-03-02 16:51:13 +0900115 private void setTestInterfaceParams(String ifname) {
116 mIfParams = (ifname != null)
117 ? new InterfaceParams(ifname, TEST_IFINDEX, TEST_MAC)
118 : null;
Remi NGUYEN VAN31d74472019-01-28 15:15:59 +0900119 when(mDependencies.getInterfaceParams(anyString())).thenReturn(mIfParams);
Erik Klineb152cd02018-03-02 16:51:13 +0900120 }
121
122 private IpClient makeIpClient(String ifname) throws Exception {
123 setTestInterfaceParams(ifname);
Remi NGUYEN VAN31d74472019-01-28 15:15:59 +0900124 final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry, mDependencies);
Remi NGUYEN VANd1b51a32019-01-22 16:13:57 +0900125 verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(ifname, false);
126 verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(ifname);
Remi NGUYEN VAN31d74472019-01-28 15:15:59 +0900127 ArgumentCaptor<NetworkObserver> arg = ArgumentCaptor.forClass(NetworkObserver.class);
Remi NGUYEN VAN1bbed8a2019-01-29 16:46:48 +0900128 verify(mObserverRegistry, times(1)).registerObserverForNonblockingCallback(arg.capture());
Hugo Benichid00ddf52017-08-08 13:08:06 +0900129 mObserver = arg.getValue();
Remi NGUYEN VAN31d74472019-01-28 15:15:59 +0900130 reset(mObserverRegistry);
Remi NGUYEN VANd1b51a32019-01-22 16:13:57 +0900131 reset(mNetd);
Erik Klinec8cb0f72017-12-11 14:24:08 +0900132 // Verify IpClient doesn't call onLinkPropertiesChange() when it starts.
133 verify(mCb, never()).onLinkPropertiesChange(any());
134 reset(mCb);
Erik Klineb152cd02018-03-02 16:51:13 +0900135 return ipc;
Hugo Benichic10fe5f2017-07-18 16:17:49 +0900136 }
137
Erik Klinec8cb0f72017-12-11 14:24:08 +0900138 private static LinkProperties makeEmptyLinkProperties(String iface) {
139 final LinkProperties empty = new LinkProperties();
140 empty.setInterfaceName(iface);
141 return empty;
142 }
143
Erik Klineaa95ae52017-03-14 10:01:58 +0900144 @Test
Erik Klineb152cd02018-03-02 16:51:13 +0900145 public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
146 setTestInterfaceParams(null);
147 try {
Remi NGUYEN VAN31d74472019-01-28 15:15:59 +0900148 final IpClient ipc = new IpClient(
149 mContext, null, mCb, mObserverRegistry, mDependencies);
Erik Klineb152cd02018-03-02 16:51:13 +0900150 ipc.shutdown();
151 fail();
152 } catch (NullPointerException npe) {
153 // Phew; null interface names not allowed.
154 }
155 }
156
157 @Test
158 public void testNullCallbackMostDefinitelyThrows() throws Exception {
159 final String ifname = "lo";
160 setTestInterfaceParams(ifname);
161 try {
Remi NGUYEN VAN31d74472019-01-28 15:15:59 +0900162 final IpClient ipc = new IpClient(
163 mContext, ifname, null, mObserverRegistry, mDependencies);
Erik Klineb152cd02018-03-02 16:51:13 +0900164 ipc.shutdown();
165 fail();
166 } catch (NullPointerException npe) {
167 // Phew; null callbacks not allowed.
168 }
Erik Klineaa95ae52017-03-14 10:01:58 +0900169 }
170
171 @Test
172 public void testInvalidInterfaceDoesNotThrow() throws Exception {
Erik Klineb152cd02018-03-02 16:51:13 +0900173 setTestInterfaceParams(TEST_IFNAME);
Remi NGUYEN VAN31d74472019-01-28 15:15:59 +0900174 final IpClient ipc = new IpClient(
175 mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies);
Erik Klineb152cd02018-03-02 16:51:13 +0900176 ipc.shutdown();
177 }
178
179 @Test
180 public void testInterfaceNotFoundFailsImmediately() throws Exception {
181 setTestInterfaceParams(null);
Remi NGUYEN VAN31d74472019-01-28 15:15:59 +0900182 final IpClient ipc = new IpClient(
183 mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies);
Remi NGUYEN VANa5d31f52019-01-12 15:36:47 +0900184 ipc.startProvisioning(new ProvisioningConfiguration());
Erik Klineb152cd02018-03-02 16:51:13 +0900185 verify(mCb, times(1)).onProvisioningFailure(any());
186 ipc.shutdown();
Hugo Benichifd31b9d2017-06-23 10:07:08 +0900187 }
188
189 @Test
190 public void testDefaultProvisioningConfiguration() throws Exception {
Erik Klineb152cd02018-03-02 16:51:13 +0900191 final String iface = TEST_IFNAME;
192 final IpClient ipc = makeIpClient(iface);
Hugo Benichic10fe5f2017-07-18 16:17:49 +0900193
Hugo Benichifd31b9d2017-06-23 10:07:08 +0900194 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
195 .withoutIPv4()
196 // TODO: mock IpReachabilityMonitor's dependencies (NetworkInterface, PowerManager)
197 // and enable it in this test
198 .withoutIpReachabilityMonitor()
199 .build();
200
Erik Klineb152cd02018-03-02 16:51:13 +0900201 ipc.startProvisioning(config);
Hugo Benichifd31b9d2017-06-23 10:07:08 +0900202 verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
Remi NGUYEN VAN01a34ac2018-07-27 12:48:54 +0900203 verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
Hugo Benichifd31b9d2017-06-23 10:07:08 +0900204 verify(mCb, never()).onProvisioningFailure(any());
205
Erik Klineb152cd02018-03-02 16:51:13 +0900206 ipc.shutdown();
Remi NGUYEN VANd1b51a32019-01-22 16:13:57 +0900207 verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
208 verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(iface);
Remi NGUYEN VAN01a34ac2018-07-27 12:48:54 +0900209 verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +0900210 .onLinkPropertiesChange(argThat(
211 lp -> fromStableParcelable(lp).equals(makeEmptyLinkProperties(iface))));
Hugo Benichifd31b9d2017-06-23 10:07:08 +0900212 }
213
214 @Test
Hugo Benichid00ddf52017-08-08 13:08:06 +0900215 public void testProvisioningWithInitialConfiguration() throws Exception {
Erik Klineb152cd02018-03-02 16:51:13 +0900216 final String iface = TEST_IFNAME;
217 final IpClient ipc = makeIpClient(iface);
Hugo Benichid00ddf52017-08-08 13:08:06 +0900218
219 String[] addresses = {
220 "fe80::a4be:f92:e1f7:22d1/64",
221 "fe80::f04a:8f6:6a32:d756/64",
222 "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"
223 };
224 String[] prefixes = { "fe80::/64", "fd2c:4e57:8e3c::/64" };
225
226 ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
227 .withoutIPv4()
228 .withoutIpReachabilityMonitor()
229 .withInitialConfiguration(conf(links(addresses), prefixes(prefixes), ips()))
230 .build();
231
Erik Klineb152cd02018-03-02 16:51:13 +0900232 ipc.startProvisioning(config);
Hugo Benichid00ddf52017-08-08 13:08:06 +0900233 verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
Remi NGUYEN VAN01a34ac2018-07-27 12:48:54 +0900234 verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
Hugo Benichid00ddf52017-08-08 13:08:06 +0900235 verify(mCb, never()).onProvisioningFailure(any());
236
237 for (String addr : addresses) {
238 String[] parts = addr.split("/");
Remi NGUYEN VAN01a34ac2018-07-27 12:48:54 +0900239 verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1))
Hugo Benichid00ddf52017-08-08 13:08:06 +0900240 .interfaceAddAddress(iface, parts[0], Integer.parseInt(parts[1]));
241 }
242
243 final int lastAddr = addresses.length - 1;
244
245 // Add N - 1 addresses
246 for (int i = 0; i < lastAddr; i++) {
Remi NGUYEN VAN31d74472019-01-28 15:15:59 +0900247 mObserver.onInterfaceAddressUpdated(new LinkAddress(addresses[i]), iface);
Remi NGUYEN VAN01a34ac2018-07-27 12:48:54 +0900248 verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(any());
Hugo Benichi25c7f492017-09-07 14:18:33 +0900249 reset(mCb);
Hugo Benichid00ddf52017-08-08 13:08:06 +0900250 }
251
252 // Add Nth address
Remi NGUYEN VAN31d74472019-01-28 15:15:59 +0900253 mObserver.onInterfaceAddressUpdated(new LinkAddress(addresses[lastAddr]), iface);
Hugo Benichid00ddf52017-08-08 13:08:06 +0900254 LinkProperties want = linkproperties(links(addresses), routes(prefixes));
255 want.setInterfaceName(iface);
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +0900256 verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(argThat(
257 lp -> fromStableParcelable(lp).equals(want)));
Hugo Benichid00ddf52017-08-08 13:08:06 +0900258
Erik Klineb152cd02018-03-02 16:51:13 +0900259 ipc.shutdown();
Remi NGUYEN VANd1b51a32019-01-22 16:13:57 +0900260 verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
261 verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(iface);
Remi NGUYEN VAN01a34ac2018-07-27 12:48:54 +0900262 verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +0900263 .onLinkPropertiesChange(argThat(
264 lp -> fromStableParcelable(lp).equals(makeEmptyLinkProperties(iface))));
Hugo Benichid00ddf52017-08-08 13:08:06 +0900265 }
266
267 @Test
268 public void testIsProvisioned() throws Exception {
269 InitialConfiguration empty = conf(links(), prefixes());
270 IsProvisionedTestCase[] testcases = {
271 // nothing
272 notProvisionedCase(links(), routes(), dns(), null),
273 notProvisionedCase(links(), routes(), dns(), empty),
274
275 // IPv4
276 provisionedCase(links("192.0.2.12/24"), routes(), dns(), empty),
277
278 // IPv6
279 notProvisionedCase(
280 links("fe80::a4be:f92:e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
281 routes(), dns(), empty),
282 notProvisionedCase(
283 links("fe80::a4be:f92:e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
284 routes("fe80::/64", "fd2c:4e57:8e3c::/64"), dns("fd00:1234:5678::1000"), empty),
285 provisionedCase(
286 links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
287 routes("::/0"),
288 dns("2001:db8:dead:beef:f00::02"), empty),
289
290 // Initial configuration
291 provisionedCase(
292 links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
293 routes("fe80::/64", "fd2c:4e57:8e3c::/64"),
294 dns(),
295 conf(links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
296 prefixes( "fe80::/64", "fd2c:4e57:8e3c::/64"), ips()))
297 };
298
299 for (IsProvisionedTestCase testcase : testcases) {
Erik Klineb152cd02018-03-02 16:51:13 +0900300 if (IpClient.isProvisioned(testcase.lp, testcase.config) != testcase.isProvisioned) {
Hugo Benichid00ddf52017-08-08 13:08:06 +0900301 fail(testcase.errorMessage());
302 }
303 }
304 }
305
306 static class IsProvisionedTestCase {
307 boolean isProvisioned;
308 LinkProperties lp;
309 InitialConfiguration config;
310
311 String errorMessage() {
312 return String.format("expected %s with config %s to be %s, but was %s",
313 lp, config, provisioned(isProvisioned), provisioned(!isProvisioned));
314 }
315
316 static String provisioned(boolean isProvisioned) {
317 return isProvisioned ? "provisioned" : "not provisioned";
318 }
319 }
320
321 static IsProvisionedTestCase provisionedCase(Set<LinkAddress> lpAddrs, Set<RouteInfo> lpRoutes,
322 Set<InetAddress> lpDns, InitialConfiguration config) {
323 return provisioningTest(true, lpAddrs, lpRoutes, lpDns, config);
324 }
325
326 static IsProvisionedTestCase notProvisionedCase(Set<LinkAddress> lpAddrs,
327 Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config) {
328 return provisioningTest(false, lpAddrs, lpRoutes, lpDns, config);
329 }
330
331 static IsProvisionedTestCase provisioningTest(boolean isProvisioned, Set<LinkAddress> lpAddrs,
332 Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config) {
333 IsProvisionedTestCase testcase = new IsProvisionedTestCase();
334 testcase.isProvisioned = isProvisioned;
335 testcase.lp = new LinkProperties();
336 testcase.lp.setLinkAddresses(lpAddrs);
337 for (RouteInfo route : lpRoutes) {
338 testcase.lp.addRoute(route);
339 }
340 for (InetAddress dns : lpDns) {
341 testcase.lp.addDnsServer(dns);
342 }
343 testcase.config = config;
344 return testcase;
345 }
346
347 @Test
Hugo Benichifd31b9d2017-06-23 10:07:08 +0900348 public void testInitialConfigurations() throws Exception {
349 InitialConfigurationTestCase[] testcases = {
350 validConf("valid IPv4 configuration",
351 links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("192.0.2.2")),
352 validConf("another valid IPv4 configuration",
353 links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns()),
354 validConf("valid IPv6 configurations",
355 links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
356 prefixes("2001:db8:dead:beef::/64", "fe80::/64"),
357 dns("2001:db8:dead:beef:f00::02")),
358 validConf("valid IPv6 configurations",
359 links("fe80::1/64"), prefixes("fe80::/64"), dns()),
360 validConf("valid IPv6/v4 configuration",
361 links("2001:db8:dead:beef:f00::a0/48", "192.0.2.12/24"),
362 prefixes("2001:db8:dead:beef::/64", "192.0.2.0/24"),
363 dns("192.0.2.2", "2001:db8:dead:beef:f00::02")),
364 validConf("valid IPv6 configuration without any GUA.",
365 links("fd00:1234:5678::1/48"),
366 prefixes("fd00:1234:5678::/48"),
367 dns("fd00:1234:5678::1000")),
368
Hugo Benichid00ddf52017-08-08 13:08:06 +0900369 invalidConf("empty configuration", links(), prefixes(), dns()),
Hugo Benichifd31b9d2017-06-23 10:07:08 +0900370 invalidConf("v4 addr and dns not in any prefix",
371 links("192.0.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
372 invalidConf("v4 addr not in any prefix",
373 links("198.51.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
374 invalidConf("v4 dns addr not in any prefix",
375 links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("198.51.100.2")),
376 invalidConf("v6 addr not in any prefix",
377 links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
378 prefixes("2001:db8:dead:beef::/64"),
379 dns("2001:db8:dead:beef:f00::02")),
380 invalidConf("v6 dns addr not in any prefix",
381 links("fe80::1/64"), prefixes("fe80::/64"), dns("2001:db8:dead:beef:f00::02")),
382 invalidConf("default ipv6 route and no GUA",
383 links("fd01:1111:2222:3333::a0/128"), prefixes("::/0"), dns()),
384 invalidConf("invalid v6 prefix length",
385 links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/32"),
386 dns()),
387 invalidConf("another invalid v6 prefix length",
388 links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/72"),
389 dns())
390 };
391
392 for (InitialConfigurationTestCase testcase : testcases) {
393 if (testcase.config.isValid() != testcase.isValid) {
394 fail(testcase.errorMessage());
395 }
396 }
397 }
398
399 static class InitialConfigurationTestCase {
400 String descr;
401 boolean isValid;
402 InitialConfiguration config;
403 public String errorMessage() {
404 return String.format("%s: expected configuration %s to be %s, but was %s",
405 descr, config, validString(isValid), validString(!isValid));
406 }
Hugo Benichid00ddf52017-08-08 13:08:06 +0900407 static String validString(boolean isValid) {
408 return isValid ? VALID : INVALID;
409 }
Hugo Benichifd31b9d2017-06-23 10:07:08 +0900410 }
411
412 static InitialConfigurationTestCase validConf(String descr, Set<LinkAddress> links,
413 Set<IpPrefix> prefixes, Set<InetAddress> dns) {
414 return confTestCase(descr, true, conf(links, prefixes, dns));
415 }
416
417 static InitialConfigurationTestCase invalidConf(String descr, Set<LinkAddress> links,
418 Set<IpPrefix> prefixes, Set<InetAddress> dns) {
419 return confTestCase(descr, false, conf(links, prefixes, dns));
420 }
421
422 static InitialConfigurationTestCase confTestCase(
423 String descr, boolean isValid, InitialConfiguration config) {
424 InitialConfigurationTestCase testcase = new InitialConfigurationTestCase();
425 testcase.descr = descr;
426 testcase.isValid = isValid;
427 testcase.config = config;
428 return testcase;
429 }
430
Hugo Benichid00ddf52017-08-08 13:08:06 +0900431 static LinkProperties linkproperties(Set<LinkAddress> addresses, Set<RouteInfo> routes) {
432 LinkProperties lp = new LinkProperties();
433 lp.setLinkAddresses(addresses);
434 for (RouteInfo route : routes) {
435 lp.addRoute(route);
436 }
437 return lp;
438 }
439
440 static InitialConfiguration conf(Set<LinkAddress> links, Set<IpPrefix> prefixes) {
441 return conf(links, prefixes, new HashSet<>());
442 }
443
Hugo Benichifd31b9d2017-06-23 10:07:08 +0900444 static InitialConfiguration conf(
445 Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns) {
446 InitialConfiguration conf = new InitialConfiguration();
447 conf.ipAddresses.addAll(links);
448 conf.directlyConnectedRoutes.addAll(prefixes);
449 conf.dnsServers.addAll(dns);
450 return conf;
451 }
452
Hugo Benichid00ddf52017-08-08 13:08:06 +0900453 static Set<RouteInfo> routes(String... routes) {
454 return mapIntoSet(routes, (r) -> new RouteInfo(new IpPrefix(r)));
455 }
456
Hugo Benichifd31b9d2017-06-23 10:07:08 +0900457 static Set<IpPrefix> prefixes(String... prefixes) {
458 return mapIntoSet(prefixes, IpPrefix::new);
459 }
460
461 static Set<LinkAddress> links(String... addresses) {
462 return mapIntoSet(addresses, LinkAddress::new);
463 }
464
465 static Set<InetAddress> ips(String... addresses) {
466 return mapIntoSet(addresses, InetAddress::getByName);
467 }
468
469 static Set<InetAddress> dns(String... addresses) {
470 return ips(addresses);
471 }
472
473 static <A, B> Set<B> mapIntoSet(A[] in, Fn<A, B> fn) {
474 Set<B> out = new HashSet<>(in.length);
475 for (A item : in) {
476 try {
477 out.add(fn.call(item));
478 } catch (Exception e) {
479 throw new RuntimeException(e);
480 }
481 }
482 return out;
483 }
484
485 interface Fn<A,B> {
486 B call(A a) throws Exception;
Erik Klineaa95ae52017-03-14 10:01:58 +0900487 }
Hugo Benichid00ddf52017-08-08 13:08:06 +0900488
489 @Test
490 public void testAll() {
491 List<String> list1 = Arrays.asList();
492 List<String> list2 = Arrays.asList("foo");
493 List<String> list3 = Arrays.asList("bar", "baz");
494 List<String> list4 = Arrays.asList("foo", "bar", "baz");
495
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +0900496 assertTrue(InitialConfiguration.all(list1, (x) -> false));
497 assertFalse(InitialConfiguration.all(list2, (x) -> false));
498 assertTrue(InitialConfiguration.all(list3, (x) -> true));
499 assertTrue(InitialConfiguration.all(list2, (x) -> x.charAt(0) == 'f'));
500 assertFalse(InitialConfiguration.all(list4, (x) -> x.charAt(0) == 'f'));
Hugo Benichid00ddf52017-08-08 13:08:06 +0900501 }
502
503 @Test
504 public void testAny() {
505 List<String> list1 = Arrays.asList();
506 List<String> list2 = Arrays.asList("foo");
507 List<String> list3 = Arrays.asList("bar", "baz");
508 List<String> list4 = Arrays.asList("foo", "bar", "baz");
509
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +0900510 assertFalse(InitialConfiguration.any(list1, (x) -> true));
511 assertTrue(InitialConfiguration.any(list2, (x) -> true));
512 assertTrue(InitialConfiguration.any(list2, (x) -> x.charAt(0) == 'f'));
513 assertFalse(InitialConfiguration.any(list3, (x) -> x.charAt(0) == 'f'));
514 assertTrue(InitialConfiguration.any(list4, (x) -> x.charAt(0) == 'f'));
Hugo Benichid00ddf52017-08-08 13:08:06 +0900515 }
516
517 @Test
518 public void testFindAll() {
519 List<String> list1 = Arrays.asList();
520 List<String> list2 = Arrays.asList("foo");
521 List<String> list3 = Arrays.asList("foo", "bar", "baz");
522
Erik Klineb152cd02018-03-02 16:51:13 +0900523 assertEquals(list1, IpClient.findAll(list1, (x) -> true));
524 assertEquals(list1, IpClient.findAll(list3, (x) -> false));
525 assertEquals(list3, IpClient.findAll(list3, (x) -> true));
526 assertEquals(list2, IpClient.findAll(list3, (x) -> x.charAt(0) == 'f'));
Hugo Benichid00ddf52017-08-08 13:08:06 +0900527 }
Erik Klineaa95ae52017-03-14 10:01:58 +0900528}