• 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 android.net.ip;
18 
19 import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
20 
21 import static com.android.networkstack.util.NetworkStackUtils.IPCLIENT_PARSE_NETLINK_EVENTS_VERSION;
22 
23 import static org.junit.Assert.assertArrayEquals;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertFalse;
26 import static org.junit.Assert.assertNotNull;
27 import static org.junit.Assert.assertNull;
28 import static org.junit.Assert.assertTrue;
29 import static org.junit.Assert.fail;
30 import static org.mockito.Mockito.any;
31 import static org.mockito.Mockito.anyBoolean;
32 import static org.mockito.Mockito.anyString;
33 import static org.mockito.Mockito.clearInvocations;
34 import static org.mockito.Mockito.doReturn;
35 import static org.mockito.Mockito.eq;
36 import static org.mockito.Mockito.never;
37 import static org.mockito.Mockito.reset;
38 import static org.mockito.Mockito.timeout;
39 import static org.mockito.Mockito.times;
40 import static org.mockito.Mockito.verify;
41 import static org.mockito.Mockito.verifyNoMoreInteractions;
42 import static org.mockito.Mockito.when;
43 
44 import static java.util.Collections.emptySet;
45 
46 import android.annotation.SuppressLint;
47 import android.app.AlarmManager;
48 import android.content.ContentResolver;
49 import android.content.Context;
50 import android.content.res.Resources;
51 import android.net.ConnectivityManager;
52 import android.net.INetd;
53 import android.net.InetAddresses;
54 import android.net.IpPrefix;
55 import android.net.LinkAddress;
56 import android.net.LinkProperties;
57 import android.net.MacAddress;
58 import android.net.NetworkStackIpMemoryStore;
59 import android.net.RouteInfo;
60 import android.net.apf.ApfCapabilities;
61 import android.net.apf.ApfFilter.ApfConfiguration;
62 import android.net.ipmemorystore.NetworkAttributes;
63 import android.net.metrics.IpConnectivityLog;
64 import android.net.shared.InitialConfiguration;
65 import android.net.shared.Layer2Information;
66 import android.net.shared.ProvisioningConfiguration;
67 import android.net.shared.ProvisioningConfiguration.ScanResultInfo;
68 import android.os.Build;
69 
70 import androidx.test.filters.SmallTest;
71 import androidx.test.runner.AndroidJUnit4;
72 
73 import com.android.net.module.util.InterfaceParams;
74 import com.android.networkstack.R;
75 import com.android.networkstack.ipmemorystore.IpMemoryStoreService;
76 import com.android.server.NetworkObserver;
77 import com.android.server.NetworkObserverRegistry;
78 import com.android.server.NetworkStackService;
79 import com.android.testutils.DevSdkIgnoreRule;
80 import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
81 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
82 import com.android.testutils.HandlerUtils;
83 
84 import org.junit.Before;
85 import org.junit.Rule;
86 import org.junit.Test;
87 import org.junit.runner.RunWith;
88 import org.mockito.ArgumentCaptor;
89 import org.mockito.Mock;
90 import org.mockito.MockitoAnnotations;
91 
92 import java.net.Inet4Address;
93 import java.net.Inet6Address;
94 import java.net.InetAddress;
95 import java.nio.ByteBuffer;
96 import java.util.Arrays;
97 import java.util.Collections;
98 import java.util.HashSet;
99 import java.util.List;
100 import java.util.Random;
101 import java.util.Set;
102 
103 
104 /**
105  * Tests for IpClient.
106  */
107 @RunWith(AndroidJUnit4.class)
108 @SmallTest
109 public class IpClientTest {
110     @Rule
111     public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
112 
113     private static final String VALID = "VALID";
114     private static final String INVALID = "INVALID";
115     private static final String TEST_IFNAME = "test_wlan0";
116     private static final int TEST_IFINDEX = 1001;
117     // See RFC 7042#section-2.1.2 for EUI-48 documentation values.
118     private static final MacAddress TEST_MAC = MacAddress.fromString("00:00:5E:00:53:01");
119     private static final int TEST_TIMEOUT_MS = 30_000;
120     private static final String TEST_L2KEY = "some l2key";
121     private static final String TEST_CLUSTER = "some cluster";
122     private static final String TEST_SSID = "test_ssid";
123     private static final String TEST_BSSID = "00:11:22:33:44:55";
124     private static final String TEST_BSSID2 = "00:1A:11:22:33:44";
125 
126     private static final String TEST_GLOBAL_ADDRESS = "1234:4321::548d:2db2:4fcf:ef75/64";
127     private static final String[] TEST_LOCAL_ADDRESSES = {
128             "fe80::a4be:f92:e1f7:22d1/64",
129             "fe80::f04a:8f6:6a32:d756/64",
130             "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"
131     };
132     private static final String TEST_IPV4_LINKADDRESS = "192.168.42.24/24";
133     private static final String[] TEST_PREFIXES = { "fe80::/64", "fd2c:4e57:8e3c::/64" };
134     private static final String[] TEST_DNSES = { "fd2c:4e57:8e3c::42" };
135     private static final String TEST_IPV6_GATEWAY = "fd2c:4e57:8e3c::43";
136     private static final String TEST_IPV4_GATEWAY = "192.168.42.11";
137     private static final long TEST_DNS_LIFETIME = 3600;
138 
139     @Mock private Context mContext;
140     @Mock private ConnectivityManager mCm;
141     @Mock private NetworkObserverRegistry mObserverRegistry;
142     @Mock private INetd mNetd;
143     @Mock private Resources mResources;
144     @Mock private IIpClientCallbacks mCb;
145     @Mock private AlarmManager mAlarm;
146     @Mock private IpClient.Dependencies mDependencies;
147     @Mock private ContentResolver mContentResolver;
148     @Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager;
149     @Mock private NetworkStackIpMemoryStore mIpMemoryStore;
150     @Mock private IpMemoryStoreService mIpMemoryStoreService;
151     @Mock private InterfaceParams mInterfaceParams;
152     @Mock private IpConnectivityLog mMetricsLog;
153 
154     private NetworkObserver mObserver;
155     private InterfaceParams mIfParams;
156 
157     @Before
setUp()158     public void setUp() throws Exception {
159         MockitoAnnotations.initMocks(this);
160 
161         when(mContext.getSystemService(eq(Context.ALARM_SERVICE))).thenReturn(mAlarm);
162         when(mContext.getSystemService(eq(ConnectivityManager.class))).thenReturn(mCm);
163         when(mContext.getResources()).thenReturn(mResources);
164         when(mDependencies.getNetd(any())).thenReturn(mNetd);
165         when(mCm.shouldAvoidBadWifi()).thenReturn(true);
166         when(mContext.getContentResolver()).thenReturn(mContentResolver);
167         when(mNetworkStackServiceManager.getIpMemoryStoreService())
168                 .thenReturn(mIpMemoryStoreService);
169         when(mDependencies.getInterfaceParams(any())).thenReturn(mInterfaceParams);
170         when(mDependencies.getIpMemoryStore(mContext, mNetworkStackServiceManager))
171                 .thenReturn(mIpMemoryStore);
172         when(mDependencies.getIpConnectivityLog()).thenReturn(mMetricsLog);
173         when(mDependencies.isFeatureEnabled(eq(mContext),
174                 eq(IPCLIENT_PARSE_NETLINK_EVENTS_VERSION), anyBoolean())).thenReturn(false);
175 
176         mIfParams = null;
177     }
178 
setTestInterfaceParams(String ifname)179     private void setTestInterfaceParams(String ifname) {
180         mIfParams = (ifname != null)
181                 ? new InterfaceParams(ifname, TEST_IFINDEX, TEST_MAC)
182                 : null;
183         when(mDependencies.getInterfaceParams(anyString())).thenReturn(mIfParams);
184     }
185 
makeIpClient(String ifname)186     private IpClient makeIpClient(String ifname) throws Exception {
187         setTestInterfaceParams(ifname);
188         final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry,
189                 mNetworkStackServiceManager, mDependencies);
190         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(ifname, false);
191         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(ifname);
192         ArgumentCaptor<NetworkObserver> arg = ArgumentCaptor.forClass(NetworkObserver.class);
193         verify(mObserverRegistry, times(1)).registerObserverForNonblockingCallback(arg.capture());
194         mObserver = arg.getValue();
195         reset(mObserverRegistry);
196         reset(mNetd);
197         // Verify IpClient doesn't call onLinkPropertiesChange() when it starts.
198         verify(mCb, never()).onLinkPropertiesChange(any());
199         reset(mCb);
200         return ipc;
201     }
202 
makeEmptyLinkProperties(String iface)203     private static LinkProperties makeEmptyLinkProperties(String iface) {
204         final LinkProperties empty = new LinkProperties();
205         empty.setInterfaceName(iface);
206         return empty;
207     }
208 
verifyNetworkAttributesStored(final String l2Key, final NetworkAttributes attributes)209     private void verifyNetworkAttributesStored(final String l2Key,
210             final NetworkAttributes attributes) {
211         // TODO : when storing is implemented, turn this on
212         // verify(mIpMemoryStore).storeNetworkAttributes(eq(l2Key), eq(attributes), any());
213     }
214 
215     @Test
testNullInterfaceNameMostDefinitelyThrows()216     public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
217         setTestInterfaceParams(null);
218         try {
219             final IpClient ipc = new IpClient(mContext, null, mCb, mObserverRegistry,
220                     mNetworkStackServiceManager, mDependencies);
221             ipc.shutdown();
222             fail();
223         } catch (NullPointerException npe) {
224             // Phew; null interface names not allowed.
225         }
226     }
227 
228     @Test
testNullCallbackMostDefinitelyThrows()229     public void testNullCallbackMostDefinitelyThrows() throws Exception {
230         final String ifname = "lo";
231         setTestInterfaceParams(ifname);
232         try {
233             final IpClient ipc = new IpClient(mContext, ifname, null, mObserverRegistry,
234                     mNetworkStackServiceManager, mDependencies);
235             ipc.shutdown();
236             fail();
237         } catch (NullPointerException npe) {
238             // Phew; null callbacks not allowed.
239         }
240     }
241 
242     @Test
testInvalidInterfaceDoesNotThrow()243     public void testInvalidInterfaceDoesNotThrow() throws Exception {
244         setTestInterfaceParams(TEST_IFNAME);
245         final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
246                 mNetworkStackServiceManager, mDependencies);
247         verifyNoMoreInteractions(mIpMemoryStore);
248         ipc.shutdown();
249     }
250 
251     @Test
testInterfaceNotFoundFailsImmediately()252     public void testInterfaceNotFoundFailsImmediately() throws Exception {
253         setTestInterfaceParams(null);
254         final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
255                 mNetworkStackServiceManager, mDependencies);
256         ipc.startProvisioning(new ProvisioningConfiguration());
257         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningFailure(any());
258         verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any());
259         ipc.shutdown();
260     }
261 
makeIPv6ProvisionedLinkProperties()262     private LinkProperties makeIPv6ProvisionedLinkProperties() {
263         // Add local addresses, and a global address with global scope
264         final Set<LinkAddress> addresses = links(TEST_LOCAL_ADDRESSES);
265         addresses.add(new LinkAddress(TEST_GLOBAL_ADDRESS, 0, RT_SCOPE_UNIVERSE));
266 
267         // Add a route on the interface for each prefix, and a global route
268         final Set<RouteInfo> routes = routes(TEST_PREFIXES);
269         routes.add(defaultIPV6Route(TEST_IPV6_GATEWAY));
270 
271         return linkproperties(addresses, routes, ips(TEST_DNSES));
272     }
273 
doProvisioningWithDefaultConfiguration()274     private IpClient doProvisioningWithDefaultConfiguration() throws Exception {
275         final IpClient ipc = makeIpClient(TEST_IFNAME);
276 
277         ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
278                 .withoutIPv4()
279                 // TODO: mock IpReachabilityMonitor's dependencies (NetworkInterface, PowerManager)
280                 // and enable it in this test
281                 .withoutIpReachabilityMonitor()
282                 .build();
283 
284         ipc.startProvisioning(config);
285         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setNeighborDiscoveryOffload(true);
286         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
287 
288         final LinkProperties lp = makeIPv6ProvisionedLinkProperties();
289         lp.getRoutes().forEach(mObserver::onRouteUpdated);
290         lp.getLinkAddresses().forEach(la -> mObserver.onInterfaceAddressUpdated(la, TEST_IFNAME));
291         mObserver.onInterfaceDnsServerInfo(TEST_IFNAME, TEST_DNS_LIFETIME,
292                 lp.getDnsServers().stream().map(InetAddress::getHostAddress)
293                         .toArray(String[]::new));
294 
295         HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
296         verify(mCb, never()).onProvisioningFailure(any());
297         verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any());
298 
299         verify(mCb).onProvisioningSuccess(lp);
300         return ipc;
301     }
302 
303     @SuppressLint("NewApi")
addIPv4Provisioning(LinkProperties lp)304     private void addIPv4Provisioning(LinkProperties lp) {
305         final LinkAddress la = new LinkAddress(TEST_IPV4_LINKADDRESS);
306         final RouteInfo defaultRoute = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
307                 InetAddresses.parseNumericAddress(TEST_IPV4_GATEWAY), TEST_IFNAME);
308         mObserver.onInterfaceAddressUpdated(la, TEST_IFNAME);
309         mObserver.onRouteUpdated(defaultRoute);
310 
311         lp.addLinkAddress(la);
312         lp.addRoute(defaultRoute);
313     }
314 
315     /**
316      * Simulate loss of IPv6 provisioning (default route lost).
317      *
318      * @return The expected new LinkProperties.
319      */
doIPv6ProvisioningLoss(LinkProperties lp)320     private void doIPv6ProvisioningLoss(LinkProperties lp) {
321         final RouteInfo defaultRoute = defaultIPV6Route(TEST_IPV6_GATEWAY);
322         mObserver.onRouteRemoved(defaultRoute);
323 
324         lp.removeRoute(defaultRoute);
325     }
326 
doDefaultIPv6ProvisioningConfigurationAndProvisioningLossTest(boolean avoidBadWifi)327     private void doDefaultIPv6ProvisioningConfigurationAndProvisioningLossTest(boolean avoidBadWifi)
328             throws Exception {
329         when(mCm.shouldAvoidBadWifi()).thenReturn(avoidBadWifi);
330         final IpClient ipc = doProvisioningWithDefaultConfiguration();
331         final LinkProperties lp = makeIPv6ProvisionedLinkProperties();
332 
333         reset(mCb);
334         doIPv6ProvisioningLoss(lp);
335         HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
336         verify(mCb).onProvisioningFailure(lp);
337         verify(mCb).onLinkPropertiesChange(makeEmptyLinkProperties(TEST_IFNAME));
338 
339         verifyShutdown(ipc);
340     }
341 
342     @Test
testDefaultIPv6ProvisioningConfiguration_AvoidBadWifi()343     public void testDefaultIPv6ProvisioningConfiguration_AvoidBadWifi() throws Exception {
344         doDefaultIPv6ProvisioningConfigurationAndProvisioningLossTest(true /* avoidBadWifi */);
345     }
346 
347     @Test
testDefaultIPv6ProvisioningConfiguration_StayOnBadWifi()348     public void testDefaultIPv6ProvisioningConfiguration_StayOnBadWifi() throws Exception {
349         // Even when avoidBadWifi=false, if IPv6 only, loss of all provisioning causes
350         // onProvisioningFailure to be called.
351         doDefaultIPv6ProvisioningConfigurationAndProvisioningLossTest(false /* avoidBadWifi */);
352     }
353 
doDefaultDualStackProvisioningConfigurationTest( boolean avoidBadWifi)354     private void doDefaultDualStackProvisioningConfigurationTest(
355             boolean avoidBadWifi) throws Exception {
356         when(mCm.shouldAvoidBadWifi()).thenReturn(avoidBadWifi);
357         final IpClient ipc = doProvisioningWithDefaultConfiguration();
358         final LinkProperties lp = makeIPv6ProvisionedLinkProperties();
359         addIPv4Provisioning(lp);
360         HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
361 
362         reset(mCb);
363         doIPv6ProvisioningLoss(lp);
364         HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
365         if (avoidBadWifi) { // Provisioning failure is expected only when avoidBadWifi is true
366             verify(mCb).onProvisioningFailure(lp);
367             verify(mCb).onLinkPropertiesChange(makeEmptyLinkProperties(TEST_IFNAME));
368         } else {
369             verify(mCb, never()).onProvisioningFailure(any());
370             verify(mCb).onLinkPropertiesChange(lp);
371         }
372 
373         verifyShutdown(ipc);
374     }
375 
376     @Test
testDefaultDualStackProvisioningConfiguration_AvoidBadWifi()377     public void testDefaultDualStackProvisioningConfiguration_AvoidBadWifi() throws Exception {
378         doDefaultDualStackProvisioningConfigurationTest(true /* avoidBadWifi */);
379     }
380 
381     @Test
testDefaultDualStackProvisioningConfiguration_StayOnBadWifi()382     public void testDefaultDualStackProvisioningConfiguration_StayOnBadWifi() throws Exception {
383         doDefaultDualStackProvisioningConfigurationTest(false /* avoidBadWifi */);
384     }
385 
386     @Test
testProvisioningWithInitialConfiguration()387     public void testProvisioningWithInitialConfiguration() throws Exception {
388         final String iface = TEST_IFNAME;
389         final IpClient ipc = makeIpClient(iface);
390         final String l2Key = TEST_L2KEY;
391         final String cluster = TEST_CLUSTER;
392 
393         ProvisioningConfiguration config = new ProvisioningConfiguration.Builder()
394                 .withoutIPv4()
395                 .withoutIpReachabilityMonitor()
396                 .withInitialConfiguration(
397                         conf(links(TEST_LOCAL_ADDRESSES), prefixes(TEST_PREFIXES), ips()))
398                 .build();
399 
400         ipc.startProvisioning(config);
401         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setNeighborDiscoveryOffload(true);
402         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
403         verify(mCb, never()).onProvisioningFailure(any());
404         ipc.setL2KeyAndCluster(l2Key, cluster);
405 
406         for (String addr : TEST_LOCAL_ADDRESSES) {
407             String[] parts = addr.split("/");
408             verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1))
409                     .interfaceAddAddress(iface, parts[0], Integer.parseInt(parts[1]));
410         }
411 
412         final int lastAddr = TEST_LOCAL_ADDRESSES.length - 1;
413 
414         // Add N - 1 addresses
415         for (int i = 0; i < lastAddr; i++) {
416             mObserver.onInterfaceAddressUpdated(new LinkAddress(TEST_LOCAL_ADDRESSES[i]), iface);
417             verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(any());
418             reset(mCb);
419         }
420 
421         // Add Nth address
422         mObserver.onInterfaceAddressUpdated(new LinkAddress(TEST_LOCAL_ADDRESSES[lastAddr]), iface);
423         LinkProperties want = linkproperties(links(TEST_LOCAL_ADDRESSES),
424                 routes(TEST_PREFIXES), emptySet() /* dnses */);
425         want.setInterfaceName(iface);
426         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(want);
427         verifyNetworkAttributesStored(l2Key, new NetworkAttributes.Builder()
428                 .setCluster(cluster)
429                 .build());
430     }
431 
verifyShutdown(IpClient ipc)432     private void verifyShutdown(IpClient ipc) throws Exception {
433         ipc.shutdown();
434         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(TEST_IFNAME, false);
435         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(TEST_IFNAME);
436         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
437                 .onLinkPropertiesChange(makeEmptyLinkProperties(TEST_IFNAME));
438         verifyNoMoreInteractions(mIpMemoryStore);
439     }
440 
441     @Test
testIsProvisioned()442     public void testIsProvisioned() throws Exception {
443         final IpClient ipc = makeIpClient(TEST_IFNAME);
444         InitialConfiguration empty = conf(links(), prefixes());
445         IsProvisionedTestCase[] testcases = {
446             // nothing
447             notProvisionedCase(links(), routes(), dns(), null),
448             notProvisionedCase(links(), routes(), dns(), empty),
449 
450             // IPv4
451             provisionedCase(links("192.0.2.12/24"), routes(), dns(), empty),
452 
453             // IPv6
454             notProvisionedCase(
455                     links("fe80::a4be:f92:e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
456                     routes(), dns(), empty),
457             notProvisionedCase(
458                     links("fe80::a4be:f92:e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
459                     routes("fe80::/64", "fd2c:4e57:8e3c::/64"), dns("fd00:1234:5678::1000"), empty),
460             provisionedCase(
461                     links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
462                     routes("::/0"),
463                     dns("2001:db8:dead:beef:f00::02"), empty),
464 
465             // Initial configuration
466             provisionedCase(
467                     links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
468                     routes("fe80::/64", "fd2c:4e57:8e3c::/64"),
469                     dns(),
470                     conf(links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
471                         prefixes("fe80::/64", "fd2c:4e57:8e3c::/64"), ips())),
472 
473             // Test case with excluded route
474             notProvisionedCase(
475                     links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
476                     routes(
477                             routes("fe80::/64"),
478                             excludedRoutes("fd2c:4e57:8e3c::/64")),
479                     dns(),
480                     conf(links("fe80::e1f7:22d1/64", "fd2c:4e57:8e3c:0:548d:2db2:4fcf:ef75/64"),
481                             prefixes("fe80::/64", "fd2c:4e57:8e3c::/64"), ips()))
482         };
483 
484         for (IsProvisionedTestCase testcase : testcases) {
485             if (ipc.isProvisioned(testcase.lp, testcase.config) != testcase.isProvisioned) {
486                 fail(testcase.errorMessage());
487             }
488         }
489     }
490 
491     static class IsProvisionedTestCase {
492         boolean isProvisioned;
493         LinkProperties lp;
494         InitialConfiguration config;
495 
errorMessage()496         String errorMessage() {
497             return String.format("expected %s with config %s to be %s, but was %s",
498                      lp, config, provisioned(isProvisioned), provisioned(!isProvisioned));
499         }
500 
provisioned(boolean isProvisioned)501         static String provisioned(boolean isProvisioned) {
502             return isProvisioned ? "provisioned" : "not provisioned";
503         }
504     }
505 
provisionedCase(Set<LinkAddress> lpAddrs, Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config)506     static IsProvisionedTestCase provisionedCase(Set<LinkAddress> lpAddrs, Set<RouteInfo> lpRoutes,
507             Set<InetAddress> lpDns, InitialConfiguration config) {
508         return provisioningTest(true, lpAddrs, lpRoutes, lpDns, config);
509     }
510 
notProvisionedCase(Set<LinkAddress> lpAddrs, Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config)511     static IsProvisionedTestCase notProvisionedCase(Set<LinkAddress> lpAddrs,
512             Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config) {
513         return provisioningTest(false, lpAddrs, lpRoutes, lpDns, config);
514     }
515 
provisioningTest(boolean isProvisioned, Set<LinkAddress> lpAddrs, Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config)516     static IsProvisionedTestCase provisioningTest(boolean isProvisioned, Set<LinkAddress> lpAddrs,
517             Set<RouteInfo> lpRoutes, Set<InetAddress> lpDns, InitialConfiguration config) {
518         IsProvisionedTestCase testcase = new IsProvisionedTestCase();
519         testcase.isProvisioned = isProvisioned;
520         testcase.lp = makeEmptyLinkProperties(TEST_IFNAME);
521         testcase.lp.setLinkAddresses(lpAddrs);
522         for (RouteInfo route : lpRoutes) {
523             testcase.lp.addRoute(route);
524         }
525         for (InetAddress dns : lpDns) {
526             testcase.lp.addDnsServer(dns);
527         }
528         testcase.config = config;
529         return testcase;
530     }
531 
532     @Test
testInitialConfigurations()533     public void testInitialConfigurations() throws Exception {
534         InitialConfigurationTestCase[] testcases = {
535             validConf("valid IPv4 configuration",
536                     links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("192.0.2.2")),
537             validConf("another valid IPv4 configuration",
538                     links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns()),
539             validConf("valid IPv6 configurations",
540                     links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
541                     prefixes("2001:db8:dead:beef::/64", "fe80::/64"),
542                     dns("2001:db8:dead:beef:f00::02")),
543             validConf("valid IPv6 configurations",
544                     links("fe80::1/64"), prefixes("fe80::/64"), dns()),
545             validConf("valid IPv6/v4 configuration",
546                     links("2001:db8:dead:beef:f00::a0/48", "192.0.2.12/24"),
547                     prefixes("2001:db8:dead:beef::/64", "192.0.2.0/24"),
548                     dns("192.0.2.2", "2001:db8:dead:beef:f00::02")),
549             validConf("valid IPv6 configuration without any GUA.",
550                     links("fd00:1234:5678::1/48"),
551                     prefixes("fd00:1234:5678::/48"),
552                     dns("fd00:1234:5678::1000")),
553 
554             invalidConf("empty configuration", links(), prefixes(), dns()),
555             invalidConf("v4 addr and dns not in any prefix",
556                     links("192.0.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
557             invalidConf("v4 addr not in any prefix",
558                     links("198.51.2.12/24"), prefixes("198.51.100.0/24"), dns("192.0.2.2")),
559             invalidConf("v4 dns addr not in any prefix",
560                     links("192.0.2.12/24"), prefixes("192.0.2.0/24"), dns("198.51.100.2")),
561             invalidConf("v6 addr not in any prefix",
562                     links("2001:db8:dead:beef:f00::a0/64", "fe80::1/64"),
563                     prefixes("2001:db8:dead:beef::/64"),
564                     dns("2001:db8:dead:beef:f00::02")),
565             invalidConf("v6 dns addr not in any prefix",
566                     links("fe80::1/64"), prefixes("fe80::/64"), dns("2001:db8:dead:beef:f00::02")),
567             invalidConf("default ipv6 route and no GUA",
568                     links("fd01:1111:2222:3333::a0/128"), prefixes("::/0"), dns()),
569             invalidConf("invalid v6 prefix length",
570                     links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/32"),
571                     dns()),
572             invalidConf("another invalid v6 prefix length",
573                     links("2001:db8:dead:beef:f00::a0/128"), prefixes("2001:db8:dead:beef::/72"),
574                     dns())
575         };
576 
577         for (InitialConfigurationTestCase testcase : testcases) {
578             if (testcase.config.isValid() != testcase.isValid) {
579                 fail(testcase.errorMessage());
580             }
581         }
582     }
583 
584     static class InitialConfigurationTestCase {
585         String descr;
586         boolean isValid;
587         InitialConfiguration config;
errorMessage()588         public String errorMessage() {
589             return String.format("%s: expected configuration %s to be %s, but was %s",
590                     descr, config, validString(isValid), validString(!isValid));
591         }
validString(boolean isValid)592         static String validString(boolean isValid) {
593             return isValid ? VALID : INVALID;
594         }
595     }
596 
validConf(String descr, Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns)597     static InitialConfigurationTestCase validConf(String descr, Set<LinkAddress> links,
598             Set<IpPrefix> prefixes, Set<InetAddress> dns) {
599         return confTestCase(descr, true, conf(links, prefixes, dns));
600     }
601 
invalidConf(String descr, Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns)602     static InitialConfigurationTestCase invalidConf(String descr, Set<LinkAddress> links,
603             Set<IpPrefix> prefixes, Set<InetAddress> dns) {
604         return confTestCase(descr, false, conf(links, prefixes, dns));
605     }
606 
confTestCase( String descr, boolean isValid, InitialConfiguration config)607     static InitialConfigurationTestCase confTestCase(
608             String descr, boolean isValid, InitialConfiguration config) {
609         InitialConfigurationTestCase testcase = new InitialConfigurationTestCase();
610         testcase.descr = descr;
611         testcase.isValid = isValid;
612         testcase.config = config;
613         return testcase;
614     }
615 
linkproperties(Set<LinkAddress> addresses, Set<RouteInfo> routes, Set<InetAddress> dnses)616     static LinkProperties linkproperties(Set<LinkAddress> addresses,
617             Set<RouteInfo> routes, Set<InetAddress> dnses) {
618         LinkProperties lp = makeEmptyLinkProperties(TEST_IFNAME);
619         lp.setLinkAddresses(addresses);
620         routes.forEach(lp::addRoute);
621         dnses.forEach(lp::addDnsServer);
622         return lp;
623     }
624 
conf(Set<LinkAddress> links, Set<IpPrefix> prefixes)625     static InitialConfiguration conf(Set<LinkAddress> links, Set<IpPrefix> prefixes) {
626         return conf(links, prefixes, new HashSet<>());
627     }
628 
conf( Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns)629     static InitialConfiguration conf(
630             Set<LinkAddress> links, Set<IpPrefix> prefixes, Set<InetAddress> dns) {
631         InitialConfiguration conf = new InitialConfiguration();
632         conf.ipAddresses.addAll(links);
633         conf.directlyConnectedRoutes.addAll(prefixes);
634         conf.dnsServers.addAll(dns);
635         return conf;
636     }
637 
routes(String... routes)638     static Set<RouteInfo> routes(String... routes) {
639         return mapIntoSet(routes, (r) -> new RouteInfo(new IpPrefix(r), null /* gateway */,
640                 TEST_IFNAME));
641     }
642 
excludedRoutes(String... excludedRoutes)643     static Set<RouteInfo> excludedRoutes(String... excludedRoutes) {
644         return mapIntoSet(excludedRoutes, (r) -> new RouteInfo(new IpPrefix(r), null /* gateway */,
645                 TEST_IFNAME, RouteInfo.RTN_THROW));
646     }
647 
routes(Set<RouteInfo> includedRoutes, Set<RouteInfo> excludedRoutes)648     static Set<RouteInfo> routes(Set<RouteInfo> includedRoutes, Set<RouteInfo> excludedRoutes) {
649         Set<RouteInfo> result = new HashSet<>(includedRoutes.size() + excludedRoutes.size());
650 
651         result.addAll(includedRoutes);
652         result.addAll(excludedRoutes);
653 
654         return result;
655     }
656 
657     @SuppressLint("NewApi")
defaultIPV6Route(String gateway)658     static RouteInfo defaultIPV6Route(String gateway) {
659         return new RouteInfo(new IpPrefix(Inet6Address.ANY, 0),
660                 InetAddresses.parseNumericAddress(gateway), TEST_IFNAME);
661     }
662 
prefixes(String... prefixes)663     static Set<IpPrefix> prefixes(String... prefixes) {
664         return mapIntoSet(prefixes, IpPrefix::new);
665     }
666 
links(String... addresses)667     static Set<LinkAddress> links(String... addresses) {
668         return mapIntoSet(addresses, LinkAddress::new);
669     }
670 
ips(String... addresses)671     static Set<InetAddress> ips(String... addresses) {
672         return mapIntoSet(addresses, InetAddress::getByName);
673     }
674 
dns(String... addresses)675     static Set<InetAddress> dns(String... addresses) {
676         return ips(addresses);
677     }
678 
mapIntoSet(A[] in, Fn<A, B> fn)679     static <A, B> Set<B> mapIntoSet(A[] in, Fn<A, B> fn) {
680         Set<B> out = new HashSet<>(in.length);
681         for (A item : in) {
682             try {
683                 out.add(fn.call(item));
684             } catch (Exception e) {
685                 throw new RuntimeException(e);
686             }
687         }
688         return out;
689     }
690 
verifyApfFilterCreatedOnStart(IpClient ipc, boolean isApfSupported)691     private ApfConfiguration verifyApfFilterCreatedOnStart(IpClient ipc, boolean isApfSupported) {
692         ProvisioningConfiguration.Builder config = new ProvisioningConfiguration.Builder()
693                 .withoutIPv4()
694                 .withoutIpReachabilityMonitor()
695                 .withInitialConfiguration(
696                         conf(links(TEST_LOCAL_ADDRESSES), prefixes(TEST_PREFIXES), ips()));
697         if (isApfSupported) {
698             config.withApfCapabilities(new ApfCapabilities(4 /* version */,
699                     4096 /* maxProgramSize */, 4 /* format */));
700         }
701 
702         ipc.startProvisioning(config.build());
703         final ArgumentCaptor<ApfConfiguration> configCaptor = ArgumentCaptor.forClass(
704                 ApfConfiguration.class);
705         verify(mDependencies, timeout(TEST_TIMEOUT_MS)).maybeCreateApfFilter(
706                 any(), configCaptor.capture(), any(), any());
707 
708         return configCaptor.getValue();
709     }
710 
711     @Test @IgnoreAfter(Build.VERSION_CODES.R)
testApfConfiguration_R()712     public void testApfConfiguration_R() throws Exception {
713         final IpClient ipc = makeIpClient(TEST_IFNAME);
714         final ApfConfiguration config = verifyApfFilterCreatedOnStart(ipc,
715                 true /* isApfSupported */);
716 
717         assertEquals(ApfCapabilities.getApfDrop8023Frames(), config.ieee802_3Filter);
718         assertArrayEquals(ApfCapabilities.getApfEtherTypeBlackList(), config.ethTypeBlackList);
719 
720         verify(mResources, never()).getBoolean(R.bool.config_apfDrop802_3Frames);
721         verify(mResources, never()).getIntArray(R.array.config_apfEthTypeDenyList);
722 
723         verifyShutdown(ipc);
724     }
725 
726     @Test @IgnoreUpTo(Build.VERSION_CODES.R)
testApfConfiguration()727     public void testApfConfiguration() throws Exception {
728         doReturn(true).when(mResources).getBoolean(R.bool.config_apfDrop802_3Frames);
729         final int[] ethTypeDenyList = new int[] { 0x88A2, 0x88A4 };
730         doReturn(ethTypeDenyList).when(mResources).getIntArray(
731                 R.array.config_apfEthTypeDenyList);
732 
733         final IpClient ipc = makeIpClient(TEST_IFNAME);
734         final ApfConfiguration config = verifyApfFilterCreatedOnStart(ipc,
735                 true /* isApfSupported */);
736 
737         assertTrue(config.ieee802_3Filter);
738         assertArrayEquals(ethTypeDenyList, config.ethTypeBlackList);
739 
740         verifyShutdown(ipc);
741     }
742 
743     @Test @IgnoreUpTo(Build.VERSION_CODES.R)
testApfConfiguration_NoApfDrop8023Frames()744     public void testApfConfiguration_NoApfDrop8023Frames() throws Exception {
745         doReturn(false).when(mResources).getBoolean(R.bool.config_apfDrop802_3Frames);
746         final int[] ethTypeDenyList = new int[] { 0x88A3, 0x88A5 };
747         doReturn(ethTypeDenyList).when(mResources).getIntArray(
748                 R.array.config_apfEthTypeDenyList);
749 
750         final IpClient ipc = makeIpClient(TEST_IFNAME);
751         final ApfConfiguration config = verifyApfFilterCreatedOnStart(ipc,
752                 true /* isApfSupported */);
753 
754         assertFalse(config.ieee802_3Filter);
755         assertArrayEquals(ethTypeDenyList, config.ethTypeBlackList);
756 
757         verifyShutdown(ipc);
758     }
759 
760     @Test
testApfUpdateCapabilities()761     public void testApfUpdateCapabilities() throws Exception {
762         final IpClient ipc = makeIpClient(TEST_IFNAME);
763         final ApfConfiguration config = verifyApfFilterCreatedOnStart(ipc,
764                 false /* isApfSupported */);
765         assertNull(config.apfCapabilities);
766         clearInvocations(mDependencies);
767 
768         ipc.updateApfCapabilities(new ApfCapabilities(4 /* version */, 4096 /* maxProgramSize */,
769                 4 /* format */));
770         HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
771 
772         final ArgumentCaptor<ApfConfiguration> configCaptor = ArgumentCaptor.forClass(
773                 ApfConfiguration.class);
774         verify(mDependencies, timeout(TEST_TIMEOUT_MS)).maybeCreateApfFilter(
775                 any(), configCaptor.capture(), any(), any());
776         final ApfConfiguration actual = configCaptor.getValue();
777         assertNotNull(actual);
778         assertEquals(4, actual.apfCapabilities.apfVersionSupported);
779         assertEquals(4096, actual.apfCapabilities.maximumApfProgramSize);
780         assertEquals(4, actual.apfCapabilities.apfPacketFormat);
781 
782         verifyShutdown(ipc);
783     }
784 
785     @Test
testApfUpdateCapabilities_nonNullInitialApfCapabilities()786     public void testApfUpdateCapabilities_nonNullInitialApfCapabilities() throws Exception {
787         final IpClient ipc = makeIpClient(TEST_IFNAME);
788         final ApfConfiguration config = verifyApfFilterCreatedOnStart(ipc,
789                 true /* isApfSupported */);
790         assertNotNull(config.apfCapabilities);
791         clearInvocations(mDependencies);
792 
793         final ApfCapabilities newApfCapabilities = new ApfCapabilities(4 /* version */,
794                 8192 /* maxProgramSize */, 4 /* format */);
795         ipc.updateApfCapabilities(newApfCapabilities);
796         HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
797         verify(mDependencies, never()).maybeCreateApfFilter(any(), any(), any(), any());
798         verifyShutdown(ipc);
799     }
800 
801     @Test
testApfUpdateCapabilities_nullNewApfCapabilities()802     public void testApfUpdateCapabilities_nullNewApfCapabilities() throws Exception {
803         final IpClient ipc = makeIpClient(TEST_IFNAME);
804         final ApfConfiguration config = verifyApfFilterCreatedOnStart(ipc,
805                 true /* isApfSupported */);
806         assertNotNull(config.apfCapabilities);
807         clearInvocations(mDependencies);
808 
809         ipc.updateApfCapabilities(null /* apfCapabilities */);
810         HandlerUtils.waitForIdle(ipc.getHandler(), TEST_TIMEOUT_MS);
811         verify(mDependencies, never()).maybeCreateApfFilter(any(), any(), any(), any());
812         verifyShutdown(ipc);
813     }
814 
makeScanResultInfo(final String ssid, final String bssid)815     private ScanResultInfo makeScanResultInfo(final String ssid, final String bssid) {
816         final ByteBuffer payload = ByteBuffer.allocate(14 /* oui + type + data */);
817         final byte[] data = new byte[10];
818         new Random().nextBytes(data);
819         payload.put(new byte[] { 0x00, 0x1A, 0x11 });
820         payload.put((byte) 0x06);
821         payload.put(data);
822 
823         final ScanResultInfo.InformationElement ie =
824                 new ScanResultInfo.InformationElement(0xdd /* IE id */, payload);
825         return new ScanResultInfo(ssid, bssid, Collections.singletonList(ie));
826     }
827 
828     @Test
testGetInitialBssidOnSOrAbove()829     public void testGetInitialBssidOnSOrAbove() throws Exception {
830         final IpClient ipc = makeIpClient(TEST_IFNAME);
831         final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
832                 MacAddress.fromString(TEST_BSSID));
833         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, TEST_BSSID2);
834         final MacAddress bssid = ipc.getInitialBssid(layer2Info, scanResultInfo,
835                 true /* isAtLeastS */);
836         assertEquals(bssid, MacAddress.fromString(TEST_BSSID));
837     }
838 
839     @Test
testGetInitialBssidOnSOrAbove_NullScanReqsultInfo()840     public void testGetInitialBssidOnSOrAbove_NullScanReqsultInfo() throws Exception {
841         final IpClient ipc = makeIpClient(TEST_IFNAME);
842         final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
843                 MacAddress.fromString(TEST_BSSID));
844         final MacAddress bssid = ipc.getInitialBssid(layer2Info, null /* ScanResultInfo */,
845                 true /* isAtLeastS */);
846         assertEquals(bssid, MacAddress.fromString(TEST_BSSID));
847     }
848 
849     @Test
testGetInitialBssidOnSOrAbove_NullBssid()850     public void testGetInitialBssidOnSOrAbove_NullBssid() throws Exception {
851         final IpClient ipc = makeIpClient(TEST_IFNAME);
852         final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
853                 null /* bssid */);
854         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, TEST_BSSID);
855         final MacAddress bssid = ipc.getInitialBssid(layer2Info, scanResultInfo,
856                 true /* isAtLeastS */);
857         assertNull(bssid);
858     }
859 
860     @Test
testGetInitialBssidOnSOrAbove_NullLayer2Info()861     public void testGetInitialBssidOnSOrAbove_NullLayer2Info() throws Exception {
862         final IpClient ipc = makeIpClient(TEST_IFNAME);
863         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, TEST_BSSID);
864         final MacAddress bssid = ipc.getInitialBssid(null /* layer2Info */, scanResultInfo,
865                 true /* isAtLeastS */);
866         assertNull(bssid);
867     }
868 
869     @Test
testGetInitialBssidBeforeS()870     public void testGetInitialBssidBeforeS() throws Exception {
871         final IpClient ipc = makeIpClient(TEST_IFNAME);
872         final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
873                 MacAddress.fromString(TEST_BSSID2));
874         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, TEST_BSSID);
875         final MacAddress bssid = ipc.getInitialBssid(layer2Info, scanResultInfo,
876                 false /* isAtLeastS */);
877         assertEquals(bssid, MacAddress.fromString(TEST_BSSID));
878     }
879 
880     @Test
testGetInitialBssidBeforeS_NullLayer2Info()881     public void testGetInitialBssidBeforeS_NullLayer2Info() throws Exception {
882         final IpClient ipc = makeIpClient(TEST_IFNAME);
883         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, TEST_BSSID);
884         final MacAddress bssid = ipc.getInitialBssid(null /* layer2Info */, scanResultInfo,
885                 false /* isAtLeastS */);
886         assertEquals(bssid, MacAddress.fromString(TEST_BSSID));
887     }
888 
889     @Test
testGetInitialBssidBeforeS_BrokenInitialBssid()890     public void testGetInitialBssidBeforeS_BrokenInitialBssid() throws Exception {
891         final IpClient ipc = makeIpClient(TEST_IFNAME);
892         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, "00:11:22:33:44:");
893         final MacAddress bssid = ipc.getInitialBssid(null /* layer2Info */, scanResultInfo,
894                 false /* isAtLeastS */);
895         assertNull(bssid);
896     }
897 
898     @Test
testGetInitialBssidBeforeS_BrokenInitialBssidFallback()899     public void testGetInitialBssidBeforeS_BrokenInitialBssidFallback() throws Exception {
900         final IpClient ipc = makeIpClient(TEST_IFNAME);
901         final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
902                 MacAddress.fromString(TEST_BSSID));
903         final ScanResultInfo scanResultInfo = makeScanResultInfo(TEST_SSID, "00:11:22:33:44:");
904         final MacAddress bssid = ipc.getInitialBssid(layer2Info, scanResultInfo,
905                 false /* isAtLeastS */);
906         assertEquals(bssid, MacAddress.fromString(TEST_BSSID));
907     }
908 
909     @Test
testGetInitialBssidBeforeS_NullScanResultInfoFallback()910     public void testGetInitialBssidBeforeS_NullScanResultInfoFallback() throws Exception {
911         final IpClient ipc = makeIpClient(TEST_IFNAME);
912         final Layer2Information layer2Info = new Layer2Information(TEST_L2KEY, TEST_CLUSTER,
913                 MacAddress.fromString(TEST_BSSID));
914         final MacAddress bssid = ipc.getInitialBssid(layer2Info, null /* scanResultInfo */,
915                 false /* isAtLeastS */);
916         assertEquals(bssid, MacAddress.fromString(TEST_BSSID));
917     }
918 
919     @Test
testGetInitialBssidBeforeS_NullScanResultInfoAndLayer2Info()920     public void testGetInitialBssidBeforeS_NullScanResultInfoAndLayer2Info() throws Exception {
921         final IpClient ipc = makeIpClient(TEST_IFNAME);
922         final MacAddress bssid = ipc.getInitialBssid(null /* layer2Info */,
923                 null /* scanResultInfo */, false /* isAtLeastS */);
924         assertNull(bssid);
925     }
926 
927     interface Fn<A,B> {
call(A a)928         B call(A a) throws Exception;
929     }
930 
931     @Test
testAll()932     public void testAll() {
933         List<String> list1 = Arrays.asList();
934         List<String> list2 = Arrays.asList("foo");
935         List<String> list3 = Arrays.asList("bar", "baz");
936         List<String> list4 = Arrays.asList("foo", "bar", "baz");
937 
938         assertTrue(InitialConfiguration.all(list1, (x) -> false));
939         assertFalse(InitialConfiguration.all(list2, (x) -> false));
940         assertTrue(InitialConfiguration.all(list3, (x) -> true));
941         assertTrue(InitialConfiguration.all(list2, (x) -> x.charAt(0) == 'f'));
942         assertFalse(InitialConfiguration.all(list4, (x) -> x.charAt(0) == 'f'));
943     }
944 
945     @Test
testAny()946     public void testAny() {
947         List<String> list1 = Arrays.asList();
948         List<String> list2 = Arrays.asList("foo");
949         List<String> list3 = Arrays.asList("bar", "baz");
950         List<String> list4 = Arrays.asList("foo", "bar", "baz");
951 
952         assertFalse(InitialConfiguration.any(list1, (x) -> true));
953         assertTrue(InitialConfiguration.any(list2, (x) -> true));
954         assertTrue(InitialConfiguration.any(list2, (x) -> x.charAt(0) == 'f'));
955         assertFalse(InitialConfiguration.any(list3, (x) -> x.charAt(0) == 'f'));
956         assertTrue(InitialConfiguration.any(list4, (x) -> x.charAt(0) == 'f'));
957     }
958 
959     @Test
testFindAll()960     public void testFindAll() {
961         List<String> list1 = Arrays.asList();
962         List<String> list2 = Arrays.asList("foo");
963         List<String> list3 = Arrays.asList("foo", "bar", "baz");
964 
965         assertEquals(list1, IpClient.findAll(list1, (x) -> true));
966         assertEquals(list1, IpClient.findAll(list3, (x) -> false));
967         assertEquals(list3, IpClient.findAll(list3, (x) -> true));
968         assertEquals(list2, IpClient.findAll(list3, (x) -> x.charAt(0) == 'f'));
969     }
970 }
971