blob: 94cc5891945908de5c2358322dc2c777c168e5da [file] [log] [blame]
Chalard Jean8c141bd2018-12-04 20:20:56 +09001/*
2 * Copyright (C) 2018 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
Chalard Jean95213512019-01-30 21:04:58 +090017package com.android.server.connectivity.ipmemorystore;
Chalard Jean8c141bd2018-12-04 20:20:56 +090018
paulhu028d7a52019-03-26 01:39:10 +080019import static com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService.InterruptMaintenance;
20
Chalard Jeanbf73e662018-12-27 20:59:41 +090021import static org.junit.Assert.assertEquals;
22import static org.junit.Assert.assertFalse;
23import static org.junit.Assert.assertNull;
Chalard Jean91549b62018-12-18 22:05:19 +090024import static org.junit.Assert.assertTrue;
25import static org.junit.Assert.fail;
Chalard Jean61e27ab2018-12-12 17:56:37 +090026import static org.mockito.ArgumentMatchers.anyString;
27import static org.mockito.Mockito.doReturn;
28
paulhu028d7a52019-03-26 01:39:10 +080029import android.app.job.JobScheduler;
Chalard Jean8c141bd2018-12-04 20:20:56 +090030import android.content.Context;
Chalard Jean91549b62018-12-18 22:05:19 +090031import android.net.ipmemorystore.Blob;
Chalard Jeanbf73e662018-12-27 20:59:41 +090032import android.net.ipmemorystore.IOnBlobRetrievedListener;
Chalard Jean8d1a8902019-01-18 20:21:26 +090033import android.net.ipmemorystore.IOnL2KeyResponseListener;
Chalard Jeanbf73e662018-12-27 20:59:41 +090034import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
Chalard Jeana39756a2019-01-16 18:18:44 +090035import android.net.ipmemorystore.IOnSameNetworkResponseListener;
Chalard Jean91549b62018-12-18 22:05:19 +090036import android.net.ipmemorystore.IOnStatusListener;
37import android.net.ipmemorystore.NetworkAttributes;
Chalard Jeanbf73e662018-12-27 20:59:41 +090038import android.net.ipmemorystore.NetworkAttributesParcelable;
Chalard Jeana39756a2019-01-16 18:18:44 +090039import android.net.ipmemorystore.SameL3NetworkResponse;
40import android.net.ipmemorystore.SameL3NetworkResponseParcelable;
Chalard Jean91549b62018-12-18 22:05:19 +090041import android.net.ipmemorystore.Status;
42import android.net.ipmemorystore.StatusParcelable;
paulhu028d7a52019-03-26 01:39:10 +080043import android.os.ConditionVariable;
Chalard Jean91549b62018-12-18 22:05:19 +090044import android.os.IBinder;
45import android.os.RemoteException;
Brett Chabot1ae2aa62019-03-04 14:14:56 -080046
47import androidx.test.InstrumentationRegistry;
48import androidx.test.filters.SmallTest;
49import androidx.test.runner.AndroidJUnit4;
Chalard Jean8c141bd2018-12-04 20:20:56 +090050
Chalard Jean91549b62018-12-18 22:05:19 +090051import org.junit.After;
Chalard Jean8c141bd2018-12-04 20:20:56 +090052import org.junit.Before;
53import org.junit.Test;
54import org.junit.runner.RunWith;
55import org.mockito.Mock;
56import org.mockito.MockitoAnnotations;
57
Chalard Jean61e27ab2018-12-12 17:56:37 +090058import java.io.File;
Chalard Jeanbf73e662018-12-27 20:59:41 +090059import java.lang.reflect.Modifier;
Chalard Jean91549b62018-12-18 22:05:19 +090060import java.net.Inet4Address;
Chalard Jeanbf73e662018-12-27 20:59:41 +090061import java.net.Inet6Address;
62import java.net.InetAddress;
Chalard Jean91549b62018-12-18 22:05:19 +090063import java.net.UnknownHostException;
Chalard Jeanbf73e662018-12-27 20:59:41 +090064import java.util.Arrays;
Chalard Jean91549b62018-12-18 22:05:19 +090065import java.util.concurrent.CountDownLatch;
66import java.util.concurrent.TimeUnit;
67import java.util.function.Consumer;
Chalard Jean61e27ab2018-12-12 17:56:37 +090068
Chalard Jean91549b62018-12-18 22:05:19 +090069/** Unit tests for {@link IpMemoryStoreService}. */
Chalard Jean8c141bd2018-12-04 20:20:56 +090070@SmallTest
71@RunWith(AndroidJUnit4.class)
72public class IpMemoryStoreServiceTest {
Chalard Jean91549b62018-12-18 22:05:19 +090073 private static final String TEST_CLIENT_ID = "testClientId";
74 private static final String TEST_DATA_NAME = "testData";
75
paulhu028d7a52019-03-26 01:39:10 +080076 private static final int TEST_DATABASE_SIZE_THRESHOLD = 100 * 1024; //100KB
77 private static final int DEFAULT_TIMEOUT_MS = 5000;
78 private static final int LONG_TIMEOUT_MS = 30000;
Chalard Jean8d1a8902019-01-18 20:21:26 +090079 private static final int FAKE_KEY_COUNT = 20;
80 private static final String[] FAKE_KEYS;
81 static {
82 FAKE_KEYS = new String[FAKE_KEY_COUNT];
83 for (int i = 0; i < FAKE_KEYS.length; ++i) {
84 FAKE_KEYS[i] = "fakeKey" + i;
85 }
86 }
Chalard Jeanb67e4932019-01-16 23:05:10 +090087
Chalard Jean8c141bd2018-12-04 20:20:56 +090088 @Mock
Chalard Jean91549b62018-12-18 22:05:19 +090089 private Context mMockContext;
paulhu028d7a52019-03-26 01:39:10 +080090 @Mock
91 private JobScheduler mMockJobScheduler;
Chalard Jean91549b62018-12-18 22:05:19 +090092 private File mDbFile;
93
94 private IpMemoryStoreService mService;
Chalard Jean8c141bd2018-12-04 20:20:56 +090095
96 @Before
97 public void setUp() {
98 MockitoAnnotations.initMocks(this);
Chalard Jean91549b62018-12-18 22:05:19 +090099 final Context context = InstrumentationRegistry.getContext();
100 final File dir = context.getFilesDir();
101 mDbFile = new File(dir, "test.db");
102 doReturn(mDbFile).when(mMockContext).getDatabasePath(anyString());
paulhu028d7a52019-03-26 01:39:10 +0800103 doReturn(mMockJobScheduler).when(mMockContext)
104 .getSystemService(Context.JOB_SCHEDULER_SERVICE);
105 mService = new IpMemoryStoreService(mMockContext) {
106 @Override
107 protected int getDbSizeThreshold() {
108 return TEST_DATABASE_SIZE_THRESHOLD;
109 }
110
111 @Override
112 boolean isDbSizeOverThreshold() {
113 // Add a 100ms delay here for pausing maintenance job a while. Interrupted flag can
114 // be set at this time.
115 waitForMs(100);
116 return super.isDbSizeOverThreshold();
117 }
118 };
Chalard Jean91549b62018-12-18 22:05:19 +0900119 }
120
121 @After
122 public void tearDown() {
123 mService.shutdown();
124 mDbFile.delete();
125 }
126
127 /** Helper method to make a vanilla IOnStatusListener */
128 private IOnStatusListener onStatus(Consumer<Status> functor) {
129 return new IOnStatusListener() {
130 @Override
131 public void onComplete(final StatusParcelable statusParcelable) throws RemoteException {
132 functor.accept(new Status(statusParcelable));
133 }
134
135 @Override
136 public IBinder asBinder() {
137 return null;
138 }
139 };
Chalard Jean8c141bd2018-12-04 20:20:56 +0900140 }
141
Chalard Jeanbf73e662018-12-27 20:59:41 +0900142 /** Helper method to make an IOnBlobRetrievedListener */
143 private interface OnBlobRetrievedListener {
144 void onBlobRetrieved(Status status, String l2Key, String name, byte[] data);
145 }
146 private IOnBlobRetrievedListener onBlobRetrieved(final OnBlobRetrievedListener functor) {
147 return new IOnBlobRetrievedListener() {
148 @Override
149 public void onBlobRetrieved(final StatusParcelable statusParcelable,
150 final String l2Key, final String name, final Blob blob) throws RemoteException {
151 functor.onBlobRetrieved(new Status(statusParcelable), l2Key, name,
152 null == blob ? null : blob.data);
153 }
154
155 @Override
156 public IBinder asBinder() {
157 return null;
158 }
159 };
160 }
161
162 /** Helper method to make an IOnNetworkAttributesRetrievedListener */
163 private interface OnNetworkAttributesRetrievedListener {
164 void onNetworkAttributesRetrieved(Status status, String l2Key, NetworkAttributes attr);
165 }
166 private IOnNetworkAttributesRetrieved onNetworkAttributesRetrieved(
167 final OnNetworkAttributesRetrievedListener functor) {
168 return new IOnNetworkAttributesRetrieved() {
169 @Override
Chalard Jeanb67e4932019-01-16 23:05:10 +0900170 public void onNetworkAttributesRetrieved(final StatusParcelable status,
171 final String l2Key, final NetworkAttributesParcelable attributes)
Chalard Jeanbf73e662018-12-27 20:59:41 +0900172 throws RemoteException {
173 functor.onNetworkAttributesRetrieved(new Status(status), l2Key,
174 null == attributes ? null : new NetworkAttributes(attributes));
175 }
176
177 @Override
178 public IBinder asBinder() {
179 return null;
180 }
181 };
182 }
183
Chalard Jeana39756a2019-01-16 18:18:44 +0900184 /** Helper method to make an IOnSameNetworkResponseListener */
185 private interface OnSameNetworkResponseListener {
186 void onSameNetworkResponse(Status status, SameL3NetworkResponse answer);
187 }
188 private IOnSameNetworkResponseListener onSameResponse(
189 final OnSameNetworkResponseListener functor) {
190 return new IOnSameNetworkResponseListener() {
191 @Override
192 public void onSameNetworkResponse(final StatusParcelable status,
193 final SameL3NetworkResponseParcelable sameL3Network)
194 throws RemoteException {
195 functor.onSameNetworkResponse(new Status(status),
196 null == sameL3Network ? null : new SameL3NetworkResponse(sameL3Network));
197 }
198
199 @Override
200 public IBinder asBinder() {
201 return null;
202 }
203 };
204 }
205
Chalard Jean8d1a8902019-01-18 20:21:26 +0900206 /** Helper method to make an IOnL2KeyResponseListener */
207 private interface OnL2KeyResponseListener {
208 void onL2KeyResponse(Status status, String key);
209 }
210 private IOnL2KeyResponseListener onL2KeyResponse(final OnL2KeyResponseListener functor) {
211 return new IOnL2KeyResponseListener() {
212 @Override
213 public void onL2KeyResponse(final StatusParcelable status, final String key)
214 throws RemoteException {
215 functor.onL2KeyResponse(new Status(status), key);
216 }
217
218 @Override
219 public IBinder asBinder() {
220 return null;
221 }
222 };
223 }
224
Chalard Jeanbf73e662018-12-27 20:59:41 +0900225 // Helper method to factorize some boilerplate
226 private void doLatched(final String timeoutMessage, final Consumer<CountDownLatch> functor) {
paulhu028d7a52019-03-26 01:39:10 +0800227 doLatched(timeoutMessage, functor, DEFAULT_TIMEOUT_MS);
228 }
229
230 private void doLatched(final String timeoutMessage, final Consumer<CountDownLatch> functor,
231 final int timeout) {
Chalard Jeanbf73e662018-12-27 20:59:41 +0900232 final CountDownLatch latch = new CountDownLatch(1);
233 functor.accept(latch);
234 try {
paulhu028d7a52019-03-26 01:39:10 +0800235 if (!latch.await(timeout, TimeUnit.MILLISECONDS)) {
Chalard Jeanf735efc2019-01-24 19:34:39 +0900236 fail(timeoutMessage);
237 }
Chalard Jeanbf73e662018-12-27 20:59:41 +0900238 } catch (InterruptedException e) {
Chalard Jeanf735efc2019-01-24 19:34:39 +0900239 fail("Thread was interrupted");
Chalard Jeanbf73e662018-12-27 20:59:41 +0900240 }
241 }
242
Chalard Jeana39756a2019-01-16 18:18:44 +0900243 // Helper methods to factorize more boilerplate
244 private void storeAttributes(final String l2Key, final NetworkAttributes na) {
245 storeAttributes("Did not complete storing attributes", l2Key, na);
246 }
247 private void storeAttributes(final String timeoutMessage, final String l2Key,
248 final NetworkAttributes na) {
249 doLatched(timeoutMessage, latch -> mService.storeNetworkAttributes(l2Key, na.toParcelable(),
250 onStatus(status -> {
251 assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
252 latch.countDown();
253 })));
254 }
255
paulhu028d7a52019-03-26 01:39:10 +0800256 /** Insert large data that db size will be over threshold for maintenance test usage. */
257 private void insertFakeDataAndOverThreshold() {
258 try {
259 final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
260 na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
261 na.setGroupHint("hint1");
262 na.setMtu(219);
263 na.setDnsAddresses(Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")));
264 final byte[] data = new byte[]{-3, 6, 8, -9, 12, -128, 0, 89, 112, 91, -34};
265 final long time = System.currentTimeMillis() - 1;
266 for (int i = 0; i < 1000; i++) {
267 int errorCode = IpMemoryStoreDatabase.storeNetworkAttributes(
268 mService.mDb,
269 "fakeKey" + i,
270 // Let first 100 records get expiry.
271 i < 100 ? time : time + TimeUnit.HOURS.toMillis(i),
272 na.build());
273 assertEquals(errorCode, Status.SUCCESS);
274
275 errorCode = IpMemoryStoreDatabase.storeBlob(
276 mService.mDb, "fakeKey" + i, TEST_CLIENT_ID, TEST_DATA_NAME, data);
277 assertEquals(errorCode, Status.SUCCESS);
278 }
279
280 // After added 5000 records, db size is larger than fake threshold(100KB).
281 assertTrue(mService.isDbSizeOverThreshold());
282 } catch (final UnknownHostException e) {
283 fail("Insert fake data fail");
284 }
285 }
286
287 /** Wait for assigned time. */
288 private void waitForMs(long ms) {
289 try {
290 Thread.sleep(ms);
291 } catch (final InterruptedException e) {
292 fail("Thread was interrupted");
293 }
294 }
295
Chalard Jean8c141bd2018-12-04 20:20:56 +0900296 @Test
Chalard Jean8d1a8902019-01-18 20:21:26 +0900297 public void testNetworkAttributes() throws UnknownHostException {
Chalard Jean91549b62018-12-18 22:05:19 +0900298 final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
Chalard Jean8d1a8902019-01-18 20:21:26 +0900299 na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
Xiao Ma385ccb02019-03-01 12:25:36 +0900300 na.setAssignedV4AddressExpiry(System.currentTimeMillis() + 7_200_000);
Chalard Jean91549b62018-12-18 22:05:19 +0900301 na.setGroupHint("hint1");
302 na.setMtu(219);
Chalard Jeanb67e4932019-01-16 23:05:10 +0900303 final String l2Key = FAKE_KEYS[0];
Chalard Jeanbf73e662018-12-27 20:59:41 +0900304 NetworkAttributes attributes = na.build();
Chalard Jeana39756a2019-01-16 18:18:44 +0900305 storeAttributes(l2Key, attributes);
Chalard Jeanbf73e662018-12-27 20:59:41 +0900306
307 doLatched("Did not complete retrieving attributes", latch ->
308 mService.retrieveNetworkAttributes(l2Key, onNetworkAttributesRetrieved(
309 (status, key, attr) -> {
310 assertTrue("Retrieve network attributes not successful : "
311 + status.resultCode, status.isSuccess());
312 assertEquals(l2Key, key);
313 assertEquals(attributes, attr);
314 latch.countDown();
315 })));
316
317 final NetworkAttributes.Builder na2 = new NetworkAttributes.Builder();
Chalard Jean8d1a8902019-01-18 20:21:26 +0900318 na.setDnsAddresses(Arrays.asList(
319 new InetAddress[] {Inet6Address.getByName("0A1C:2E40:480A::1CA6")}));
Chalard Jeanbf73e662018-12-27 20:59:41 +0900320 final NetworkAttributes attributes2 = na2.build();
Chalard Jeana39756a2019-01-16 18:18:44 +0900321 storeAttributes("Did not complete storing attributes 2", l2Key, attributes2);
Chalard Jeanbf73e662018-12-27 20:59:41 +0900322
323 doLatched("Did not complete retrieving attributes 2", latch ->
324 mService.retrieveNetworkAttributes(l2Key, onNetworkAttributesRetrieved(
325 (status, key, attr) -> {
326 assertTrue("Retrieve network attributes not successful : "
327 + status.resultCode, status.isSuccess());
328 assertEquals(l2Key, key);
329 assertEquals(attributes.assignedV4Address, attr.assignedV4Address);
Xiao Ma385ccb02019-03-01 12:25:36 +0900330 assertEquals(attributes.assignedV4AddressExpiry,
331 attr.assignedV4AddressExpiry);
Chalard Jeanbf73e662018-12-27 20:59:41 +0900332 assertEquals(attributes.groupHint, attr.groupHint);
333 assertEquals(attributes.mtu, attr.mtu);
334 assertEquals(attributes2.dnsAddresses, attr.dnsAddresses);
335 latch.countDown();
336 })));
337
338 doLatched("Did not complete retrieving attributes 3", latch ->
339 mService.retrieveNetworkAttributes(l2Key + "nonexistent",
340 onNetworkAttributesRetrieved(
341 (status, key, attr) -> {
342 assertTrue("Retrieve network attributes not successful : "
343 + status.resultCode, status.isSuccess());
344 assertEquals(l2Key + "nonexistent", key);
345 assertNull("Retrieved data not stored", attr);
346 latch.countDown();
347 }
348 )));
349
350 // Verify that this test does not miss any new field added later.
351 // If any field is added to NetworkAttributes it must be tested here for storing
352 // and retrieving.
Xiao Ma385ccb02019-03-01 12:25:36 +0900353 assertEquals(5, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
Chalard Jeanbf73e662018-12-27 20:59:41 +0900354 .filter(f -> !Modifier.isStatic(f.getModifiers())).count());
355 }
356
357 @Test
358 public void testInvalidAttributes() {
359 doLatched("Did not complete storing bad attributes", latch ->
360 mService.storeNetworkAttributes("key", null, onStatus(status -> {
361 assertFalse("Success storing on a null key",
362 status.isSuccess());
363 assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
364 latch.countDown();
365 })));
366
367 final NetworkAttributes na = new NetworkAttributes.Builder().setMtu(2).build();
368 doLatched("Did not complete storing bad attributes", latch ->
369 mService.storeNetworkAttributes(null, na.toParcelable(), onStatus(status -> {
370 assertFalse("Success storing null attributes on a null key",
371 status.isSuccess());
372 assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
373 latch.countDown();
374 })));
375
376 doLatched("Did not complete storing bad attributes", latch ->
377 mService.storeNetworkAttributes(null, null, onStatus(status -> {
378 assertFalse("Success storing null attributes on a null key",
379 status.isSuccess());
380 assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
381 latch.countDown();
382 })));
383
384 doLatched("Did not complete retrieving bad attributes", latch ->
385 mService.retrieveNetworkAttributes(null, onNetworkAttributesRetrieved(
386 (status, key, attr) -> {
387 assertFalse("Success retrieving attributes for a null key",
388 status.isSuccess());
389 assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
390 assertNull(key);
391 assertNull(attr);
Chalard Jeanf735efc2019-01-24 19:34:39 +0900392 latch.countDown();
Chalard Jeanbf73e662018-12-27 20:59:41 +0900393 })));
Chalard Jeanf89d7be2018-12-07 23:09:02 +0900394 }
395
396 @Test
397 public void testPrivateData() {
Chalard Jean91549b62018-12-18 22:05:19 +0900398 final Blob b = new Blob();
399 b.data = new byte[] { -3, 6, 8, -9, 12, -128, 0, 89, 112, 91, -34 };
Chalard Jeanb67e4932019-01-16 23:05:10 +0900400 final String l2Key = FAKE_KEYS[0];
Chalard Jeanbf73e662018-12-27 20:59:41 +0900401 doLatched("Did not complete storing private data", latch ->
402 mService.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
403 onStatus(status -> {
404 assertTrue("Store status not successful : " + status.resultCode,
405 status.isSuccess());
406 latch.countDown();
407 })));
408
409 doLatched("Did not complete retrieving private data", latch ->
410 mService.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, onBlobRetrieved(
411 (status, key, name, data) -> {
412 assertTrue("Retrieve blob status not successful : " + status.resultCode,
413 status.isSuccess());
414 assertEquals(l2Key, key);
415 assertEquals(name, TEST_DATA_NAME);
paulhu028d7a52019-03-26 01:39:10 +0800416 assertTrue(Arrays.equals(b.data, data));
Chalard Jeanbf73e662018-12-27 20:59:41 +0900417 latch.countDown();
418 })));
419
420 // Most puzzling error message ever
421 doLatched("Did not complete retrieving nothing", latch ->
422 mService.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME + "2", onBlobRetrieved(
423 (status, key, name, data) -> {
424 assertTrue("Retrieve blob status not successful : " + status.resultCode,
425 status.isSuccess());
426 assertEquals(l2Key, key);
427 assertEquals(name, TEST_DATA_NAME + "2");
428 assertNull(data);
429 latch.countDown();
430 })));
Chalard Jeanf89d7be2018-12-07 23:09:02 +0900431 }
432
433 @Test
Chalard Jean8d1a8902019-01-18 20:21:26 +0900434 public void testFindL2Key() throws UnknownHostException {
435 final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
436 na.setGroupHint("hint0");
437 storeAttributes(FAKE_KEYS[0], na.build());
438
439 na.setDnsAddresses(Arrays.asList(
440 new InetAddress[] {Inet6Address.getByName("8D56:9AF1::08EE:20F1")}));
441 na.setMtu(219);
442 storeAttributes(FAKE_KEYS[1], na.build());
443 na.setMtu(null);
444 na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
445 na.setDnsAddresses(Arrays.asList(
446 new InetAddress[] {Inet6Address.getByName("0A1C:2E40:480A::1CA6")}));
447 na.setGroupHint("hint1");
448 storeAttributes(FAKE_KEYS[2], na.build());
449 na.setMtu(219);
450 storeAttributes(FAKE_KEYS[3], na.build());
451 na.setMtu(240);
452 storeAttributes(FAKE_KEYS[4], na.build());
453 na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("5.6.7.8"));
454 storeAttributes(FAKE_KEYS[5], na.build());
455
456 // Matches key 5 exactly
457 doLatched("Did not finish finding L2Key", latch ->
458 mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
459 assertTrue("Retrieve network sameness not successful : " + status.resultCode,
460 status.isSuccess());
461 assertEquals(FAKE_KEYS[5], key);
Chalard Jeanf735efc2019-01-24 19:34:39 +0900462 latch.countDown();
Chalard Jean8d1a8902019-01-18 20:21:26 +0900463 })));
464
465 // MTU matches key 4 but v4 address matches key 5. The latter is stronger.
466 na.setMtu(240);
467 doLatched("Did not finish finding L2Key", latch ->
468 mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
469 assertTrue("Retrieve network sameness not successful : " + status.resultCode,
470 status.isSuccess());
471 assertEquals(FAKE_KEYS[5], key);
Chalard Jeanf735efc2019-01-24 19:34:39 +0900472 latch.countDown();
Chalard Jean8d1a8902019-01-18 20:21:26 +0900473 })));
474
475 // Closest to key 3 (indeed, identical)
476 na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
477 na.setMtu(219);
478 doLatched("Did not finish finding L2Key", latch ->
479 mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
480 assertTrue("Retrieve network sameness not successful : " + status.resultCode,
481 status.isSuccess());
482 assertEquals(FAKE_KEYS[3], key);
Chalard Jeanf735efc2019-01-24 19:34:39 +0900483 latch.countDown();
Chalard Jean8d1a8902019-01-18 20:21:26 +0900484 })));
485
486 // Group hint alone must not be strong enough to override the rest
487 na.setGroupHint("hint0");
488 doLatched("Did not finish finding L2Key", latch ->
489 mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
490 assertTrue("Retrieve network sameness not successful : " + status.resultCode,
491 status.isSuccess());
492 assertEquals(FAKE_KEYS[3], key);
Chalard Jeanf735efc2019-01-24 19:34:39 +0900493 latch.countDown();
Chalard Jean8d1a8902019-01-18 20:21:26 +0900494 })));
495
496 // Still closest to key 3, though confidence is lower
497 na.setGroupHint("hint1");
498 na.setDnsAddresses(null);
499 doLatched("Did not finish finding L2Key", latch ->
500 mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
501 assertTrue("Retrieve network sameness not successful : " + status.resultCode,
502 status.isSuccess());
503 assertEquals(FAKE_KEYS[3], key);
Chalard Jeanf735efc2019-01-24 19:34:39 +0900504 latch.countDown();
Chalard Jean8d1a8902019-01-18 20:21:26 +0900505 })));
506
507 // But changing the MTU makes this closer to key 4
508 na.setMtu(240);
509 doLatched("Did not finish finding L2Key", latch ->
510 mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
511 assertTrue("Retrieve network sameness not successful : " + status.resultCode,
512 status.isSuccess());
513 assertEquals(FAKE_KEYS[4], key);
Chalard Jeanf735efc2019-01-24 19:34:39 +0900514 latch.countDown();
Chalard Jean8d1a8902019-01-18 20:21:26 +0900515 })));
516
517 // MTU alone not strong enough to make this group-close
518 na.setGroupHint(null);
519 na.setDnsAddresses(null);
520 na.setAssignedV4Address(null);
521 doLatched("Did not finish finding L2Key", latch ->
522 mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
523 assertTrue("Retrieve network sameness not successful : " + status.resultCode,
524 status.isSuccess());
525 assertNull(key);
Chalard Jeanf735efc2019-01-24 19:34:39 +0900526 latch.countDown();
Chalard Jean8d1a8902019-01-18 20:21:26 +0900527 })));
Chalard Jeanf89d7be2018-12-07 23:09:02 +0900528 }
529
Chalard Jeana39756a2019-01-16 18:18:44 +0900530 private void assertNetworksSameness(final String key1, final String key2, final int sameness) {
531 doLatched("Did not finish evaluating sameness", latch ->
532 mService.isSameNetwork(key1, key2, onSameResponse((status, answer) -> {
533 assertTrue("Retrieve network sameness not successful : " + status.resultCode,
534 status.isSuccess());
535 assertEquals(sameness, answer.getNetworkSameness());
Chalard Jeanf735efc2019-01-24 19:34:39 +0900536 latch.countDown();
Chalard Jeana39756a2019-01-16 18:18:44 +0900537 })));
538 }
539
Chalard Jeanf89d7be2018-12-07 23:09:02 +0900540 @Test
Chalard Jeana39756a2019-01-16 18:18:44 +0900541 public void testIsSameNetwork() throws UnknownHostException {
542 final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
Chalard Jean8d1a8902019-01-18 20:21:26 +0900543 na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
Chalard Jeana39756a2019-01-16 18:18:44 +0900544 na.setGroupHint("hint1");
545 na.setMtu(219);
546 na.setDnsAddresses(Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")));
547
Chalard Jeanb67e4932019-01-16 23:05:10 +0900548 storeAttributes(FAKE_KEYS[0], na.build());
Chalard Jeana39756a2019-01-16 18:18:44 +0900549 // 0 and 1 have identical attributes
Chalard Jeanb67e4932019-01-16 23:05:10 +0900550 storeAttributes(FAKE_KEYS[1], na.build());
Chalard Jeana39756a2019-01-16 18:18:44 +0900551
552 // Hopefully only the MTU being different still means it's the same network
553 na.setMtu(200);
Chalard Jeanb67e4932019-01-16 23:05:10 +0900554 storeAttributes(FAKE_KEYS[2], na.build());
Chalard Jeana39756a2019-01-16 18:18:44 +0900555
556 // Hopefully different MTU, assigned V4 address and grouphint make a different network,
557 // even with identical DNS addresses
558 na.setAssignedV4Address(null);
559 na.setGroupHint("hint2");
Chalard Jeanb67e4932019-01-16 23:05:10 +0900560 storeAttributes(FAKE_KEYS[3], na.build());
Chalard Jeana39756a2019-01-16 18:18:44 +0900561
Chalard Jeanb67e4932019-01-16 23:05:10 +0900562 assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[1], SameL3NetworkResponse.NETWORK_SAME);
563 assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[2], SameL3NetworkResponse.NETWORK_SAME);
564 assertNetworksSameness(FAKE_KEYS[1], FAKE_KEYS[2], SameL3NetworkResponse.NETWORK_SAME);
565 assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[3], SameL3NetworkResponse.NETWORK_DIFFERENT);
566 assertNetworksSameness(FAKE_KEYS[0], "neverInsertedKey",
Chalard Jeana39756a2019-01-16 18:18:44 +0900567 SameL3NetworkResponse.NETWORK_NEVER_CONNECTED);
568
569 doLatched("Did not finish evaluating sameness", latch ->
570 mService.isSameNetwork(null, null, onSameResponse((status, answer) -> {
571 assertFalse("Retrieve network sameness suspiciously successful : "
572 + status.resultCode, status.isSuccess());
573 assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
574 assertNull(answer);
Chalard Jeanf735efc2019-01-24 19:34:39 +0900575 latch.countDown();
Chalard Jeana39756a2019-01-16 18:18:44 +0900576 })));
Chalard Jean8c141bd2018-12-04 20:20:56 +0900577 }
paulhu028d7a52019-03-26 01:39:10 +0800578
579
580 @Test
581 public void testFullMaintenance() {
582 insertFakeDataAndOverThreshold();
583
584 final InterruptMaintenance im = new InterruptMaintenance(0/* Fake JobId */);
585 // Do full maintenance and then db size should go down and meet the threshold.
586 doLatched("Maintenance unexpectedly completed successfully", latch ->
587 mService.fullMaintenance(onStatus((status) -> {
588 assertTrue("Execute full maintenance failed: "
589 + status.resultCode, status.isSuccess());
590 latch.countDown();
591 }), im), LONG_TIMEOUT_MS);
592
593 // Assume that maintenance is successful, db size shall meet the threshold.
594 assertFalse(mService.isDbSizeOverThreshold());
595 }
596
597 @Test
598 public void testInterruptMaintenance() {
599 insertFakeDataAndOverThreshold();
600
601 final InterruptMaintenance im = new InterruptMaintenance(0/* Fake JobId */);
602
603 // Test interruption immediately.
604 im.setInterrupted(true);
605 // Do full maintenance and the expectation is not completed by interruption.
606 doLatched("Maintenance unexpectedly completed successfully", latch ->
607 mService.fullMaintenance(onStatus((status) -> {
608 assertFalse(status.isSuccess());
609 latch.countDown();
610 }), im), LONG_TIMEOUT_MS);
611
612 // Assume that no data are removed, db size shall be over the threshold.
613 assertTrue(mService.isDbSizeOverThreshold());
614
615 // Reset the flag and test interruption during maintenance.
616 im.setInterrupted(false);
617
618 final ConditionVariable latch = new ConditionVariable();
619 // Do full maintenance and the expectation is not completed by interruption.
620 mService.fullMaintenance(onStatus((status) -> {
621 assertFalse(status.isSuccess());
622 latch.open();
623 }), im);
624
625 // Give a little bit of time for maintenance to start up for realism
626 waitForMs(50);
627 // Interrupt maintenance job.
628 im.setInterrupted(true);
629
630 if (!latch.block(LONG_TIMEOUT_MS)) {
631 fail("Maintenance unexpectedly completed successfully");
632 }
633
634 // Assume that only do dropAllExpiredRecords method in previous maintenance, db size shall
635 // still be over the threshold.
636 assertTrue(mService.isDbSizeOverThreshold());
637 }
Chalard Jean8c141bd2018-12-04 20:20:56 +0900638}