Merge changes If71fadd2,I42047185
am: 022daeb874
Change-Id: Ie15258f09adb7f1cc53c558e1d3d5fdaf8d93476
This commit is contained in:
@@ -25,6 +25,6 @@ oneway interface IOnNetworkAttributesRetrieved {
|
||||
* Network attributes were fetched for the specified L2 key. While the L2 key will never
|
||||
* be null, the attributes may be if no data is stored about this L2 key.
|
||||
*/
|
||||
void onL2KeyResponse(in StatusParcelable status, in String l2Key,
|
||||
void onNetworkAttributesRetrieved(in StatusParcelable status, in String l2Key,
|
||||
in NetworkAttributesParcelable attributes);
|
||||
}
|
||||
|
||||
@@ -37,27 +37,57 @@ import java.util.StringJoiner;
|
||||
public class NetworkAttributes {
|
||||
private static final boolean DBG = true;
|
||||
|
||||
// Weight cutoff for grouping. To group, a similarity score is computed with the following
|
||||
// algorithm : if both fields are non-null and equals() then add their assigned weight, else if
|
||||
// both are null then add a portion of their assigned weight (see NULL_MATCH_WEIGHT),
|
||||
// otherwise add nothing.
|
||||
// As a guideline, this should be something like 60~75% of the total weights in this class. The
|
||||
// design states "in essence a reader should imagine that if two important columns don't match,
|
||||
// or one important and several unimportant columns don't match then the two records are
|
||||
// considered a different group".
|
||||
private static final float TOTAL_WEIGHT_CUTOFF = 520.0f;
|
||||
// The portion of the weight that is earned when scoring group-sameness by having both columns
|
||||
// being null. This is because some networks rightfully don't have some attributes (e.g. a
|
||||
// V6-only network won't have an assigned V4 address) and both being null should count for
|
||||
// something, but attributes may also be null just because data is unavailable.
|
||||
private static final float NULL_MATCH_WEIGHT = 0.25f;
|
||||
|
||||
// The v4 address that was assigned to this device the last time it joined this network.
|
||||
// This typically comes from DHCP but could be something else like static configuration.
|
||||
// This does not apply to IPv6.
|
||||
// TODO : add a list of v6 prefixes for the v6 case.
|
||||
@Nullable
|
||||
public final Inet4Address assignedV4Address;
|
||||
private static final float WEIGHT_ASSIGNEDV4ADDR = 300.0f;
|
||||
|
||||
// Optionally supplied by the client if it has an opinion on L3 network. For example, this
|
||||
// could be a hash of the SSID + security type on WiFi.
|
||||
@Nullable
|
||||
public final String groupHint;
|
||||
private static final float WEIGHT_GROUPHINT = 300.0f;
|
||||
|
||||
// The list of DNS server addresses.
|
||||
@Nullable
|
||||
public final List<InetAddress> dnsAddresses;
|
||||
private static final float WEIGHT_DNSADDRESSES = 200.0f;
|
||||
|
||||
// The mtu on this network.
|
||||
@Nullable
|
||||
public final Integer mtu;
|
||||
private static final float WEIGHT_MTU = 50.0f;
|
||||
|
||||
NetworkAttributes(
|
||||
// The sum of all weights in this class. Tests ensure that this stays equal to the total of
|
||||
// all weights.
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public static final float TOTAL_WEIGHT = WEIGHT_ASSIGNEDV4ADDR
|
||||
+ WEIGHT_GROUPHINT
|
||||
+ WEIGHT_DNSADDRESSES
|
||||
+ WEIGHT_MTU;
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public NetworkAttributes(
|
||||
@Nullable final Inet4Address assignedV4Address,
|
||||
@Nullable final String groupHint,
|
||||
@Nullable final List<InetAddress> dnsAddresses,
|
||||
@@ -126,6 +156,34 @@ public class NetworkAttributes {
|
||||
return parcelable;
|
||||
}
|
||||
|
||||
private float samenessContribution(final float weight,
|
||||
@Nullable final Object o1, @Nullable final Object o2) {
|
||||
if (null == o1) {
|
||||
return (null == o2) ? weight * NULL_MATCH_WEIGHT : 0f;
|
||||
}
|
||||
return Objects.equals(o1, o2) ? weight : 0f;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public float getNetworkGroupSamenessConfidence(@NonNull final NetworkAttributes o) {
|
||||
final float samenessScore =
|
||||
samenessContribution(WEIGHT_ASSIGNEDV4ADDR, assignedV4Address, o.assignedV4Address)
|
||||
+ samenessContribution(WEIGHT_GROUPHINT, groupHint, o.groupHint)
|
||||
+ samenessContribution(WEIGHT_DNSADDRESSES, dnsAddresses, o.dnsAddresses)
|
||||
+ samenessContribution(WEIGHT_MTU, mtu, o.mtu);
|
||||
// The minimum is 0, the max is TOTAL_WEIGHT and should be represented by 1.0, and
|
||||
// TOTAL_WEIGHT_CUTOFF should represent 0.5, but there is no requirement that
|
||||
// TOTAL_WEIGHT_CUTOFF would be half of TOTAL_WEIGHT (indeed, it should not be).
|
||||
// So scale scores under the cutoff between 0 and 0.5, and the scores over the cutoff
|
||||
// between 0.5 and 1.0.
|
||||
if (samenessScore < TOTAL_WEIGHT_CUTOFF) {
|
||||
return samenessScore / (TOTAL_WEIGHT_CUTOFF * 2);
|
||||
} else {
|
||||
return (samenessScore - TOTAL_WEIGHT_CUTOFF) / (TOTAL_WEIGHT - TOTAL_WEIGHT_CUTOFF) / 2
|
||||
+ 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static class Builder {
|
||||
@Nullable
|
||||
|
||||
@@ -91,7 +91,8 @@ public class SameL3NetworkResponse {
|
||||
return confidence > 0.5 ? NETWORK_SAME : NETWORK_DIFFERENT;
|
||||
}
|
||||
|
||||
SameL3NetworkResponse(@NonNull final String l2Key1, @NonNull final String l2Key2,
|
||||
/** @hide */
|
||||
public SameL3NetworkResponse(@NonNull final String l2Key1, @NonNull final String l2Key2,
|
||||
final float confidence) {
|
||||
this.l2Key1 = l2Key1;
|
||||
this.l2Key2 = l2Key2;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -134,12 +134,14 @@ public class IpMemoryStoreDatabase {
|
||||
}
|
||||
|
||||
/** Called when the database is created */
|
||||
@Override
|
||||
public void onCreate(@NonNull final SQLiteDatabase db) {
|
||||
db.execSQL(NetworkAttributesContract.CREATE_TABLE);
|
||||
db.execSQL(PrivateDataContract.CREATE_TABLE);
|
||||
}
|
||||
|
||||
/** Called when the database is upgraded */
|
||||
@Override
|
||||
public void onUpgrade(@NonNull final SQLiteDatabase db, final int oldVersion,
|
||||
final int newVersion) {
|
||||
// No upgrade supported yet.
|
||||
@@ -149,6 +151,7 @@ public class IpMemoryStoreDatabase {
|
||||
}
|
||||
|
||||
/** Called when the database is downgraded */
|
||||
@Override
|
||||
public void onDowngrade(@NonNull final SQLiteDatabase db, final int oldVersion,
|
||||
final int newVersion) {
|
||||
// Downgrades always nuke all data and recreate an empty table.
|
||||
@@ -247,7 +250,9 @@ public class IpMemoryStoreDatabase {
|
||||
// result here. 0 results means the key was not found.
|
||||
if (cursor.getCount() != 1) return EXPIRY_ERROR;
|
||||
cursor.moveToFirst();
|
||||
return cursor.getLong(0); // index in the EXPIRY_COLUMN array
|
||||
final long result = cursor.getLong(0); // index in the EXPIRY_COLUMN array
|
||||
cursor.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
static final int RELEVANCE_ERROR = -1; // Legal values for relevance are positive
|
||||
@@ -321,6 +326,8 @@ public class IpMemoryStoreDatabase {
|
||||
final byte[] dnsAddressesBlob =
|
||||
getBlob(cursor, NetworkAttributesContract.COLNAME_DNSADDRESSES);
|
||||
final int mtu = getInt(cursor, NetworkAttributesContract.COLNAME_MTU, -1);
|
||||
cursor.close();
|
||||
|
||||
if (0 != assignedV4AddressInt) {
|
||||
builder.setAssignedV4Address(NetworkUtils.intToInet4AddressHTH(assignedV4AddressInt));
|
||||
}
|
||||
@@ -353,7 +360,9 @@ public class IpMemoryStoreDatabase {
|
||||
// get more than one result here. 0 results means the key was not found.
|
||||
if (cursor.getCount() != 1) return null;
|
||||
cursor.moveToFirst();
|
||||
return cursor.getBlob(0); // index in the DATA_COLUMN array
|
||||
final byte[] result = cursor.getBlob(0); // index in the DATA_COLUMN array
|
||||
cursor.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
|
||||
@@ -37,6 +37,7 @@ import android.net.ipmemorystore.IOnSameNetworkResponseListener;
|
||||
import android.net.ipmemorystore.IOnStatusListener;
|
||||
import android.net.ipmemorystore.NetworkAttributes;
|
||||
import android.net.ipmemorystore.NetworkAttributesParcelable;
|
||||
import android.net.ipmemorystore.SameL3NetworkResponse;
|
||||
import android.net.ipmemorystore.Status;
|
||||
import android.net.ipmemorystore.StatusParcelable;
|
||||
import android.net.ipmemorystore.Utils;
|
||||
@@ -264,9 +265,40 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub {
|
||||
* Through the listener, a SameL3NetworkResponse containing the answer and confidence.
|
||||
*/
|
||||
@Override
|
||||
public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2,
|
||||
@NonNull final IOnSameNetworkResponseListener listener) {
|
||||
// TODO : implement this.
|
||||
public void isSameNetwork(@Nullable final String l2Key1, @Nullable final String l2Key2,
|
||||
@Nullable final IOnSameNetworkResponseListener listener) {
|
||||
if (null == listener) return;
|
||||
mExecutor.execute(() -> {
|
||||
try {
|
||||
if (null == l2Key1 || null == l2Key2) {
|
||||
listener.onSameNetworkResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
|
||||
return;
|
||||
}
|
||||
if (null == mDb) {
|
||||
listener.onSameNetworkResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final NetworkAttributes attr1 =
|
||||
IpMemoryStoreDatabase.retrieveNetworkAttributes(mDb, l2Key1);
|
||||
final NetworkAttributes attr2 =
|
||||
IpMemoryStoreDatabase.retrieveNetworkAttributes(mDb, l2Key2);
|
||||
if (null == attr1 || null == attr2) {
|
||||
listener.onSameNetworkResponse(makeStatus(SUCCESS),
|
||||
new SameL3NetworkResponse(l2Key1, l2Key2,
|
||||
-1f /* never connected */).toParcelable());
|
||||
return;
|
||||
}
|
||||
final float confidence = attr1.getNetworkGroupSamenessConfidence(attr2);
|
||||
listener.onSameNetworkResponse(makeStatus(SUCCESS),
|
||||
new SameL3NetworkResponse(l2Key1, l2Key2, confidence).toParcelable());
|
||||
} catch (Exception e) {
|
||||
listener.onSameNetworkResponse(makeStatus(ERROR_GENERIC), null);
|
||||
}
|
||||
} catch (final RemoteException e) {
|
||||
// Client at the other end died
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,21 +317,22 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub {
|
||||
mExecutor.execute(() -> {
|
||||
try {
|
||||
if (null == l2Key) {
|
||||
listener.onL2KeyResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), l2Key, null);
|
||||
listener.onNetworkAttributesRetrieved(
|
||||
makeStatus(ERROR_ILLEGAL_ARGUMENT), l2Key, null);
|
||||
return;
|
||||
}
|
||||
if (null == mDb) {
|
||||
listener.onL2KeyResponse(makeStatus(ERROR_DATABASE_CANNOT_BE_OPENED), l2Key,
|
||||
null);
|
||||
listener.onNetworkAttributesRetrieved(
|
||||
makeStatus(ERROR_DATABASE_CANNOT_BE_OPENED), l2Key, null);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final NetworkAttributes attributes =
|
||||
IpMemoryStoreDatabase.retrieveNetworkAttributes(mDb, l2Key);
|
||||
listener.onL2KeyResponse(makeStatus(SUCCESS), l2Key,
|
||||
listener.onNetworkAttributesRetrieved(makeStatus(SUCCESS), l2Key,
|
||||
null == attributes ? null : attributes.toParcelable());
|
||||
} catch (final Exception e) {
|
||||
listener.onL2KeyResponse(makeStatus(ERROR_GENERIC), l2Key, null);
|
||||
listener.onNetworkAttributesRetrieved(makeStatus(ERROR_GENERIC), l2Key, null);
|
||||
}
|
||||
} catch (final RemoteException e) {
|
||||
// Client at the other end died
|
||||
|
||||
@@ -28,9 +28,12 @@ import android.content.Context;
|
||||
import android.net.ipmemorystore.Blob;
|
||||
import android.net.ipmemorystore.IOnBlobRetrievedListener;
|
||||
import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
|
||||
import android.net.ipmemorystore.IOnSameNetworkResponseListener;
|
||||
import android.net.ipmemorystore.IOnStatusListener;
|
||||
import android.net.ipmemorystore.NetworkAttributes;
|
||||
import android.net.ipmemorystore.NetworkAttributesParcelable;
|
||||
import android.net.ipmemorystore.SameL3NetworkResponse;
|
||||
import android.net.ipmemorystore.SameL3NetworkResponseParcelable;
|
||||
import android.net.ipmemorystore.Status;
|
||||
import android.net.ipmemorystore.StatusParcelable;
|
||||
import android.os.IBinder;
|
||||
@@ -53,7 +56,6 @@ import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
@@ -65,6 +67,8 @@ public class IpMemoryStoreServiceTest {
|
||||
private static final String TEST_CLIENT_ID = "testClientId";
|
||||
private static final String TEST_DATA_NAME = "testData";
|
||||
|
||||
private static final String[] FAKE_KEYS = { "fakeKey1", "fakeKey2", "fakeKey3", "fakeKey4" };
|
||||
|
||||
@Mock
|
||||
private Context mMockContext;
|
||||
private File mDbFile;
|
||||
@@ -130,8 +134,8 @@ public class IpMemoryStoreServiceTest {
|
||||
final OnNetworkAttributesRetrievedListener functor) {
|
||||
return new IOnNetworkAttributesRetrieved() {
|
||||
@Override
|
||||
public void onL2KeyResponse(final StatusParcelable status, final String l2Key,
|
||||
final NetworkAttributesParcelable attributes)
|
||||
public void onNetworkAttributesRetrieved(final StatusParcelable status,
|
||||
final String l2Key, final NetworkAttributesParcelable attributes)
|
||||
throws RemoteException {
|
||||
functor.onNetworkAttributesRetrieved(new Status(status), l2Key,
|
||||
null == attributes ? null : new NetworkAttributes(attributes));
|
||||
@@ -144,6 +148,28 @@ public class IpMemoryStoreServiceTest {
|
||||
};
|
||||
}
|
||||
|
||||
/** Helper method to make an IOnSameNetworkResponseListener */
|
||||
private interface OnSameNetworkResponseListener {
|
||||
void onSameNetworkResponse(Status status, SameL3NetworkResponse answer);
|
||||
}
|
||||
private IOnSameNetworkResponseListener onSameResponse(
|
||||
final OnSameNetworkResponseListener functor) {
|
||||
return new IOnSameNetworkResponseListener() {
|
||||
@Override
|
||||
public void onSameNetworkResponse(final StatusParcelable status,
|
||||
final SameL3NetworkResponseParcelable sameL3Network)
|
||||
throws RemoteException {
|
||||
functor.onSameNetworkResponse(new Status(status),
|
||||
null == sameL3Network ? null : new SameL3NetworkResponse(sameL3Network));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder asBinder() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Helper method to factorize some boilerplate
|
||||
private void doLatched(final String timeoutMessage, final Consumer<CountDownLatch> functor) {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
@@ -155,6 +181,19 @@ public class IpMemoryStoreServiceTest {
|
||||
}
|
||||
}
|
||||
|
||||
// Helper methods to factorize more boilerplate
|
||||
private void storeAttributes(final String l2Key, final NetworkAttributes na) {
|
||||
storeAttributes("Did not complete storing attributes", l2Key, na);
|
||||
}
|
||||
private void storeAttributes(final String timeoutMessage, final String l2Key,
|
||||
final NetworkAttributes na) {
|
||||
doLatched(timeoutMessage, latch -> mService.storeNetworkAttributes(l2Key, na.toParcelable(),
|
||||
onStatus(status -> {
|
||||
assertTrue("Store not successful : " + status.resultCode, status.isSuccess());
|
||||
latch.countDown();
|
||||
})));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNetworkAttributes() {
|
||||
final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
|
||||
@@ -164,15 +203,9 @@ public class IpMemoryStoreServiceTest {
|
||||
} catch (UnknownHostException e) { /* Can't happen */ }
|
||||
na.setGroupHint("hint1");
|
||||
na.setMtu(219);
|
||||
final String l2Key = UUID.randomUUID().toString();
|
||||
final String l2Key = FAKE_KEYS[0];
|
||||
NetworkAttributes attributes = na.build();
|
||||
doLatched("Did not complete storing attributes", latch ->
|
||||
mService.storeNetworkAttributes(l2Key, attributes.toParcelable(),
|
||||
onStatus(status -> {
|
||||
assertTrue("Store status not successful : " + status.resultCode,
|
||||
status.isSuccess());
|
||||
latch.countDown();
|
||||
})));
|
||||
storeAttributes(l2Key, attributes);
|
||||
|
||||
doLatched("Did not complete retrieving attributes", latch ->
|
||||
mService.retrieveNetworkAttributes(l2Key, onNetworkAttributesRetrieved(
|
||||
@@ -190,9 +223,7 @@ public class IpMemoryStoreServiceTest {
|
||||
new InetAddress[] {Inet6Address.getByName("0A1C:2E40:480A::1CA6")}));
|
||||
} catch (UnknownHostException e) { /* Still can't happen */ }
|
||||
final NetworkAttributes attributes2 = na2.build();
|
||||
doLatched("Did not complete storing attributes 2", latch ->
|
||||
mService.storeNetworkAttributes(l2Key, attributes2.toParcelable(),
|
||||
onStatus(status -> latch.countDown())));
|
||||
storeAttributes("Did not complete storing attributes 2", l2Key, attributes2);
|
||||
|
||||
doLatched("Did not complete retrieving attributes 2", latch ->
|
||||
mService.retrieveNetworkAttributes(l2Key, onNetworkAttributesRetrieved(
|
||||
@@ -268,7 +299,7 @@ public class IpMemoryStoreServiceTest {
|
||||
public void testPrivateData() {
|
||||
final Blob b = new Blob();
|
||||
b.data = new byte[] { -3, 6, 8, -9, 12, -128, 0, 89, 112, 91, -34 };
|
||||
final String l2Key = UUID.randomUUID().toString();
|
||||
final String l2Key = FAKE_KEYS[0];
|
||||
doLatched("Did not complete storing private data", latch ->
|
||||
mService.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
|
||||
onStatus(status -> {
|
||||
@@ -306,8 +337,50 @@ public class IpMemoryStoreServiceTest {
|
||||
// TODO : implement this
|
||||
}
|
||||
|
||||
private void assertNetworksSameness(final String key1, final String key2, final int sameness) {
|
||||
doLatched("Did not finish evaluating sameness", latch ->
|
||||
mService.isSameNetwork(key1, key2, onSameResponse((status, answer) -> {
|
||||
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
|
||||
status.isSuccess());
|
||||
assertEquals(sameness, answer.getNetworkSameness());
|
||||
})));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsSameNetwork() {
|
||||
// TODO : implement this
|
||||
public void testIsSameNetwork() throws UnknownHostException {
|
||||
final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
|
||||
na.setAssignedV4Address((Inet4Address) Inet4Address.getByAddress(new byte[]{1, 2, 3, 4}));
|
||||
na.setGroupHint("hint1");
|
||||
na.setMtu(219);
|
||||
na.setDnsAddresses(Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")));
|
||||
|
||||
storeAttributes(FAKE_KEYS[0], na.build());
|
||||
// 0 and 1 have identical attributes
|
||||
storeAttributes(FAKE_KEYS[1], na.build());
|
||||
|
||||
// Hopefully only the MTU being different still means it's the same network
|
||||
na.setMtu(200);
|
||||
storeAttributes(FAKE_KEYS[2], na.build());
|
||||
|
||||
// Hopefully different MTU, assigned V4 address and grouphint make a different network,
|
||||
// even with identical DNS addresses
|
||||
na.setAssignedV4Address(null);
|
||||
na.setGroupHint("hint2");
|
||||
storeAttributes(FAKE_KEYS[3], na.build());
|
||||
|
||||
assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[1], SameL3NetworkResponse.NETWORK_SAME);
|
||||
assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[2], SameL3NetworkResponse.NETWORK_SAME);
|
||||
assertNetworksSameness(FAKE_KEYS[1], FAKE_KEYS[2], SameL3NetworkResponse.NETWORK_SAME);
|
||||
assertNetworksSameness(FAKE_KEYS[0], FAKE_KEYS[3], SameL3NetworkResponse.NETWORK_DIFFERENT);
|
||||
assertNetworksSameness(FAKE_KEYS[0], "neverInsertedKey",
|
||||
SameL3NetworkResponse.NETWORK_NEVER_CONNECTED);
|
||||
|
||||
doLatched("Did not finish evaluating sameness", latch ->
|
||||
mService.isSameNetwork(null, null, onSameResponse((status, answer) -> {
|
||||
assertFalse("Retrieve network sameness suspiciously successful : "
|
||||
+ status.resultCode, status.isSuccess());
|
||||
assertEquals(Status.ERROR_ILLEGAL_ARGUMENT, status.resultCode);
|
||||
assertNull(answer);
|
||||
})));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.net.ipmemorystore;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.net.ipmemorystore.NetworkAttributes;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/** Unit tests for {@link NetworkAttributes}. */
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class NetworkAttributesTest {
|
||||
private static final String WEIGHT_FIELD_NAME_PREFIX = "WEIGHT_";
|
||||
private static final float EPSILON = 0.0001f;
|
||||
|
||||
// This is running two tests to make sure the total weight is the sum of all weights. To be
|
||||
// sure this is not fireproof, but you'd kind of need to do it on purpose to pass.
|
||||
@Test
|
||||
public void testTotalWeight() throws IllegalAccessException, UnknownHostException {
|
||||
// Make sure that TOTAL_WEIGHT is equal to the sum of the fields starting with WEIGHT_
|
||||
float sum = 0f;
|
||||
final Field[] fieldList = NetworkAttributes.class.getDeclaredFields();
|
||||
for (final Field field : fieldList) {
|
||||
if (!field.getName().startsWith(WEIGHT_FIELD_NAME_PREFIX)) continue;
|
||||
field.setAccessible(true);
|
||||
sum += (float) field.get(null);
|
||||
}
|
||||
assertEquals(sum, NetworkAttributes.TOTAL_WEIGHT, EPSILON);
|
||||
|
||||
// Use directly the constructor with all attributes, and make sure that when compared
|
||||
// to itself the score is a clean 1.0f.
|
||||
final NetworkAttributes na =
|
||||
new NetworkAttributes(
|
||||
(Inet4Address) Inet4Address.getByAddress(new byte[] {1, 2, 3, 4}),
|
||||
"some hint",
|
||||
Arrays.asList(Inet4Address.getByAddress(new byte[] {5, 6, 7, 8}),
|
||||
Inet4Address.getByAddress(new byte[] {9, 0, 1, 2})),
|
||||
98);
|
||||
assertEquals(1.0f, na.getNetworkGroupSamenessConfidence(na), EPSILON);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user