Merge "[MS11] Implement findL2Key"
This commit is contained in:
@@ -252,6 +252,12 @@ public class NetworkAttributes {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public boolean isEmpty() {
|
||||
return (null == assignedV4Address) && (null == groupHint)
|
||||
&& (null == dnsAddresses) && (null == mtu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable final Object o) {
|
||||
if (!(o instanceof NetworkAttributes)) return false;
|
||||
|
||||
@@ -21,9 +21,12 @@ import android.annotation.Nullable;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteCursor;
|
||||
import android.database.sqlite.SQLiteCursorDriver;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.database.sqlite.SQLiteQuery;
|
||||
import android.net.NetworkUtils;
|
||||
import android.net.ipmemorystore.NetworkAttributes;
|
||||
import android.net.ipmemorystore.Status;
|
||||
@@ -35,6 +38,7 @@ import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* Encapsulating class for using the SQLite database backing the memory store.
|
||||
@@ -46,6 +50,9 @@ import java.util.List;
|
||||
*/
|
||||
public class IpMemoryStoreDatabase {
|
||||
private static final String TAG = IpMemoryStoreDatabase.class.getSimpleName();
|
||||
// A pair of NetworkAttributes objects is group-close if the confidence that they are
|
||||
// the same is above this cutoff. See NetworkAttributes and SameL3NetworkResponse.
|
||||
private static final float GROUPCLOSE_CONFIDENCE = 0.5f;
|
||||
|
||||
/**
|
||||
* Contract class for the Network Attributes table.
|
||||
@@ -187,30 +194,35 @@ public class IpMemoryStoreDatabase {
|
||||
return addresses;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static ContentValues toContentValues(@Nullable final NetworkAttributes attributes) {
|
||||
final ContentValues values = new ContentValues();
|
||||
if (null == attributes) return values;
|
||||
if (null != attributes.assignedV4Address) {
|
||||
values.put(NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS,
|
||||
NetworkUtils.inet4AddressToIntHTH(attributes.assignedV4Address));
|
||||
}
|
||||
if (null != attributes.groupHint) {
|
||||
values.put(NetworkAttributesContract.COLNAME_GROUPHINT, attributes.groupHint);
|
||||
}
|
||||
if (null != attributes.dnsAddresses) {
|
||||
values.put(NetworkAttributesContract.COLNAME_DNSADDRESSES,
|
||||
encodeAddressList(attributes.dnsAddresses));
|
||||
}
|
||||
if (null != attributes.mtu) {
|
||||
values.put(NetworkAttributesContract.COLNAME_MTU, attributes.mtu);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
// Convert a NetworkAttributes object to content values to store them in a table compliant
|
||||
// with the contract defined in NetworkAttributesContract.
|
||||
@NonNull
|
||||
private static ContentValues toContentValues(@NonNull final String key,
|
||||
@Nullable final NetworkAttributes attributes, final long expiry) {
|
||||
final ContentValues values = new ContentValues();
|
||||
final ContentValues values = toContentValues(attributes);
|
||||
values.put(NetworkAttributesContract.COLNAME_L2KEY, key);
|
||||
values.put(NetworkAttributesContract.COLNAME_EXPIRYDATE, expiry);
|
||||
if (null != attributes) {
|
||||
if (null != attributes.assignedV4Address) {
|
||||
values.put(NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS,
|
||||
NetworkUtils.inet4AddressToIntHTH(attributes.assignedV4Address));
|
||||
}
|
||||
if (null != attributes.groupHint) {
|
||||
values.put(NetworkAttributesContract.COLNAME_GROUPHINT, attributes.groupHint);
|
||||
}
|
||||
if (null != attributes.dnsAddresses) {
|
||||
values.put(NetworkAttributesContract.COLNAME_DNSADDRESSES,
|
||||
encodeAddressList(attributes.dnsAddresses));
|
||||
}
|
||||
if (null != attributes.mtu) {
|
||||
values.put(NetworkAttributesContract.COLNAME_MTU, attributes.mtu);
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
@@ -228,6 +240,32 @@ public class IpMemoryStoreDatabase {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static NetworkAttributes readNetworkAttributesLine(@NonNull final Cursor cursor) {
|
||||
// Make sure the data hasn't expired
|
||||
final long expiry = getLong(cursor, NetworkAttributesContract.COLNAME_EXPIRYDATE, -1L);
|
||||
if (expiry < System.currentTimeMillis()) return null;
|
||||
|
||||
final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
|
||||
final int assignedV4AddressInt = getInt(cursor,
|
||||
NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS, 0);
|
||||
final String groupHint = getString(cursor, NetworkAttributesContract.COLNAME_GROUPHINT);
|
||||
final byte[] dnsAddressesBlob =
|
||||
getBlob(cursor, NetworkAttributesContract.COLNAME_DNSADDRESSES);
|
||||
final int mtu = getInt(cursor, NetworkAttributesContract.COLNAME_MTU, -1);
|
||||
if (0 != assignedV4AddressInt) {
|
||||
builder.setAssignedV4Address(NetworkUtils.intToInet4AddressHTH(assignedV4AddressInt));
|
||||
}
|
||||
builder.setGroupHint(groupHint);
|
||||
if (null != dnsAddressesBlob) {
|
||||
builder.setDnsAddresses(decodeAddressList(dnsAddressesBlob));
|
||||
}
|
||||
if (mtu >= 0) {
|
||||
builder.setMtu(mtu);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static final String[] EXPIRY_COLUMN = new String[] {
|
||||
NetworkAttributesContract.COLNAME_EXPIRYDATE
|
||||
};
|
||||
@@ -313,32 +351,9 @@ public class IpMemoryStoreDatabase {
|
||||
// result here. 0 results means the key was not found.
|
||||
if (cursor.getCount() != 1) return null;
|
||||
cursor.moveToFirst();
|
||||
|
||||
// Make sure the data hasn't expired
|
||||
final long expiry = cursor.getLong(
|
||||
cursor.getColumnIndexOrThrow(NetworkAttributesContract.COLNAME_EXPIRYDATE));
|
||||
if (expiry < System.currentTimeMillis()) return null;
|
||||
|
||||
final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
|
||||
final int assignedV4AddressInt = getInt(cursor,
|
||||
NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS, 0);
|
||||
final String groupHint = getString(cursor, NetworkAttributesContract.COLNAME_GROUPHINT);
|
||||
final byte[] dnsAddressesBlob =
|
||||
getBlob(cursor, NetworkAttributesContract.COLNAME_DNSADDRESSES);
|
||||
final int mtu = getInt(cursor, NetworkAttributesContract.COLNAME_MTU, -1);
|
||||
final NetworkAttributes attributes = readNetworkAttributesLine(cursor);
|
||||
cursor.close();
|
||||
|
||||
if (0 != assignedV4AddressInt) {
|
||||
builder.setAssignedV4Address(NetworkUtils.intToInet4AddressHTH(assignedV4AddressInt));
|
||||
}
|
||||
builder.setGroupHint(groupHint);
|
||||
if (null != dnsAddressesBlob) {
|
||||
builder.setDnsAddresses(decodeAddressList(dnsAddressesBlob));
|
||||
}
|
||||
if (mtu >= 0) {
|
||||
builder.setMtu(mtu);
|
||||
}
|
||||
return builder.build();
|
||||
return attributes;
|
||||
}
|
||||
|
||||
private static final String[] DATA_COLUMN = new String[] {
|
||||
@@ -365,17 +380,134 @@ public class IpMemoryStoreDatabase {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The following is a horrible hack that is necessary because the Android SQLite API does not
|
||||
* have a way to query a binary blob. This, almost certainly, is an overlook.
|
||||
*
|
||||
* The Android SQLite API has two family of methods : one for query that returns data, and
|
||||
* one for more general SQL statements that can execute any statement but may not return
|
||||
* anything. All the query methods, however, take only String[] for the arguments.
|
||||
*
|
||||
* In principle it is simple to write a function that will encode the binary blob in the
|
||||
* way SQLite expects it. However, because the API forces the argument to be coerced into a
|
||||
* String, the SQLiteQuery object generated by the default query methods will bind all
|
||||
* arguments as Strings and SQL will *sanitize* them. This works okay for numeric types,
|
||||
* but the format for blobs is x'<hex string>'. Note the presence of quotes, which will
|
||||
* be sanitized, changing the contents of the field, and the query will fail to match the
|
||||
* blob.
|
||||
*
|
||||
* As far as I can tell, there are two possible ways around this problem. The first one
|
||||
* is to put the data in the query string and eschew it being an argument. This would
|
||||
* require doing the sanitizing by hand. The other is to call bindBlob directly on the
|
||||
* generated SQLiteQuery object, which not only is a lot less dangerous than rolling out
|
||||
* sanitizing, but also will do the right thing if the underlying format ever changes.
|
||||
*
|
||||
* But none of the methods that take an SQLiteQuery object can return data ; this *must*
|
||||
* be called with SQLiteDatabase#query. This object is not accessible from outside.
|
||||
* However, there is a #query version that accepts a CursorFactory and this is pretty
|
||||
* straightforward to implement as all the arguments are coming in and the SQLiteCursor
|
||||
* class is public API.
|
||||
* With this, it's possible to intercept the SQLiteQuery object, and assuming the args
|
||||
* are available, to bind them directly and work around the API's oblivious coercion into
|
||||
* Strings.
|
||||
*
|
||||
* This is really sad, but I don't see another way of having this work than this or the
|
||||
* hand-rolled sanitizing, and this is the lesser evil.
|
||||
*/
|
||||
private static class CustomCursorFactory implements SQLiteDatabase.CursorFactory {
|
||||
@NonNull
|
||||
private final ArrayList<Object> mArgs;
|
||||
CustomCursorFactory(@NonNull final ArrayList<Object> args) {
|
||||
mArgs = args;
|
||||
}
|
||||
@Override
|
||||
public Cursor newCursor(final SQLiteDatabase db, final SQLiteCursorDriver masterQuery,
|
||||
final String editTable,
|
||||
final SQLiteQuery query) {
|
||||
int index = 1; // bind is 1-indexed
|
||||
for (final Object arg : mArgs) {
|
||||
if (arg instanceof String) {
|
||||
query.bindString(index++, (String) arg);
|
||||
} else if (arg instanceof Long) {
|
||||
query.bindLong(index++, (Long) arg);
|
||||
} else if (arg instanceof Integer) {
|
||||
query.bindLong(index++, Long.valueOf((Integer) arg));
|
||||
} else if (arg instanceof byte[]) {
|
||||
query.bindBlob(index++, (byte[]) arg);
|
||||
} else {
|
||||
throw new IllegalStateException("Unsupported type CustomCursorFactory "
|
||||
+ arg.getClass().toString());
|
||||
}
|
||||
}
|
||||
return new SQLiteCursor(masterQuery, editTable, query);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the l2key of the closest match, if and only if it matches
|
||||
// closely enough (as determined by group-closeness).
|
||||
@Nullable
|
||||
static String findClosestAttributes(@NonNull final SQLiteDatabase db,
|
||||
@NonNull final NetworkAttributes attr) {
|
||||
if (attr.isEmpty()) return null;
|
||||
final ContentValues values = toContentValues(attr);
|
||||
|
||||
// Build the selection and args. To cut down on the number of lines to search, limit
|
||||
// the search to those with at least one argument equals to the requested attributes.
|
||||
// This works only because null attributes match only will not result in group-closeness.
|
||||
final StringJoiner sj = new StringJoiner(" OR ");
|
||||
final ArrayList<Object> args = new ArrayList<>();
|
||||
args.add(System.currentTimeMillis());
|
||||
for (final String field : values.keySet()) {
|
||||
sj.add(field + " = ?");
|
||||
args.add(values.get(field));
|
||||
}
|
||||
|
||||
final String selection = NetworkAttributesContract.COLNAME_EXPIRYDATE + " > ? AND ("
|
||||
+ sj.toString() + ")";
|
||||
final Cursor cursor = db.queryWithFactory(new CustomCursorFactory(args),
|
||||
false, // distinct
|
||||
NetworkAttributesContract.TABLENAME,
|
||||
null, // columns, null means everything
|
||||
selection, // selection
|
||||
null, // selectionArgs, horrendously passed to the cursor factory instead
|
||||
null, // groupBy
|
||||
null, // having
|
||||
null, // orderBy
|
||||
null); // limit
|
||||
if (cursor.getCount() <= 0) return null;
|
||||
cursor.moveToFirst();
|
||||
String bestKey = null;
|
||||
float bestMatchConfidence = GROUPCLOSE_CONFIDENCE; // Never return a match worse than this.
|
||||
while (!cursor.isAfterLast()) {
|
||||
final NetworkAttributes read = readNetworkAttributesLine(cursor);
|
||||
final float confidence = read.getNetworkGroupSamenessConfidence(attr);
|
||||
if (confidence > bestMatchConfidence) {
|
||||
bestKey = getString(cursor, NetworkAttributesContract.COLNAME_L2KEY);
|
||||
bestMatchConfidence = confidence;
|
||||
}
|
||||
cursor.moveToNext();
|
||||
}
|
||||
cursor.close();
|
||||
return bestKey;
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
static String getString(final Cursor cursor, final String columnName) {
|
||||
private static String getString(final Cursor cursor, final String columnName) {
|
||||
final int columnIndex = cursor.getColumnIndex(columnName);
|
||||
return (columnIndex >= 0) ? cursor.getString(columnIndex) : null;
|
||||
}
|
||||
static byte[] getBlob(final Cursor cursor, final String columnName) {
|
||||
private static byte[] getBlob(final Cursor cursor, final String columnName) {
|
||||
final int columnIndex = cursor.getColumnIndex(columnName);
|
||||
return (columnIndex >= 0) ? cursor.getBlob(columnIndex) : null;
|
||||
}
|
||||
static int getInt(final Cursor cursor, final String columnName, final int defaultValue) {
|
||||
private static int getInt(final Cursor cursor, final String columnName,
|
||||
final int defaultValue) {
|
||||
final int columnIndex = cursor.getColumnIndex(columnName);
|
||||
return (columnIndex >= 0) ? cursor.getInt(columnIndex) : defaultValue;
|
||||
}
|
||||
private static long getLong(final Cursor cursor, final String columnName,
|
||||
final long defaultValue) {
|
||||
final int columnIndex = cursor.getColumnIndex(columnName);
|
||||
return (columnIndex >= 0) ? cursor.getLong(columnIndex) : defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,9 +250,26 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub {
|
||||
* Through the listener, returns the L2 key if one matched, or null.
|
||||
*/
|
||||
@Override
|
||||
public void findL2Key(@NonNull final NetworkAttributesParcelable attributes,
|
||||
@NonNull final IOnL2KeyResponseListener listener) {
|
||||
// TODO : implement this.
|
||||
public void findL2Key(@Nullable final NetworkAttributesParcelable attributes,
|
||||
@Nullable final IOnL2KeyResponseListener listener) {
|
||||
if (null == listener) return;
|
||||
mExecutor.execute(() -> {
|
||||
try {
|
||||
if (null == attributes) {
|
||||
listener.onL2KeyResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
|
||||
return;
|
||||
}
|
||||
if (null == mDb) {
|
||||
listener.onL2KeyResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
|
||||
return;
|
||||
}
|
||||
final String key = IpMemoryStoreDatabase.findClosestAttributes(mDb,
|
||||
new NetworkAttributes(attributes));
|
||||
listener.onL2KeyResponse(makeStatus(SUCCESS), key);
|
||||
} catch (final RemoteException e) {
|
||||
// Client at the other end died
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.doReturn;
|
||||
import android.content.Context;
|
||||
import android.net.ipmemorystore.Blob;
|
||||
import android.net.ipmemorystore.IOnBlobRetrievedListener;
|
||||
import android.net.ipmemorystore.IOnL2KeyResponseListener;
|
||||
import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
|
||||
import android.net.ipmemorystore.IOnSameNetworkResponseListener;
|
||||
import android.net.ipmemorystore.IOnStatusListener;
|
||||
@@ -67,7 +68,14 @@ 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" };
|
||||
private static final int FAKE_KEY_COUNT = 20;
|
||||
private static final String[] FAKE_KEYS;
|
||||
static {
|
||||
FAKE_KEYS = new String[FAKE_KEY_COUNT];
|
||||
for (int i = 0; i < FAKE_KEYS.length; ++i) {
|
||||
FAKE_KEYS[i] = "fakeKey" + i;
|
||||
}
|
||||
}
|
||||
|
||||
@Mock
|
||||
private Context mMockContext;
|
||||
@@ -170,6 +178,25 @@ public class IpMemoryStoreServiceTest {
|
||||
};
|
||||
}
|
||||
|
||||
/** Helper method to make an IOnL2KeyResponseListener */
|
||||
private interface OnL2KeyResponseListener {
|
||||
void onL2KeyResponse(Status status, String key);
|
||||
}
|
||||
private IOnL2KeyResponseListener onL2KeyResponse(final OnL2KeyResponseListener functor) {
|
||||
return new IOnL2KeyResponseListener() {
|
||||
@Override
|
||||
public void onL2KeyResponse(final StatusParcelable status, final String key)
|
||||
throws RemoteException {
|
||||
functor.onL2KeyResponse(new Status(status), key);
|
||||
}
|
||||
|
||||
@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);
|
||||
@@ -195,12 +222,9 @@ public class IpMemoryStoreServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNetworkAttributes() {
|
||||
public void testNetworkAttributes() throws UnknownHostException {
|
||||
final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
|
||||
try {
|
||||
na.setAssignedV4Address(
|
||||
(Inet4Address) Inet4Address.getByAddress(new byte[]{1, 2, 3, 4}));
|
||||
} catch (UnknownHostException e) { /* Can't happen */ }
|
||||
na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
|
||||
na.setGroupHint("hint1");
|
||||
na.setMtu(219);
|
||||
final String l2Key = FAKE_KEYS[0];
|
||||
@@ -218,10 +242,8 @@ public class IpMemoryStoreServiceTest {
|
||||
})));
|
||||
|
||||
final NetworkAttributes.Builder na2 = new NetworkAttributes.Builder();
|
||||
try {
|
||||
na.setDnsAddresses(Arrays.asList(
|
||||
new InetAddress[] {Inet6Address.getByName("0A1C:2E40:480A::1CA6")}));
|
||||
} catch (UnknownHostException e) { /* Still can't happen */ }
|
||||
na.setDnsAddresses(Arrays.asList(
|
||||
new InetAddress[] {Inet6Address.getByName("0A1C:2E40:480A::1CA6")}));
|
||||
final NetworkAttributes attributes2 = na2.build();
|
||||
storeAttributes("Did not complete storing attributes 2", l2Key, attributes2);
|
||||
|
||||
@@ -333,8 +355,93 @@ public class IpMemoryStoreServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindL2Key() {
|
||||
// TODO : implement this
|
||||
public void testFindL2Key() throws UnknownHostException {
|
||||
final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
|
||||
na.setGroupHint("hint0");
|
||||
storeAttributes(FAKE_KEYS[0], na.build());
|
||||
|
||||
na.setDnsAddresses(Arrays.asList(
|
||||
new InetAddress[] {Inet6Address.getByName("8D56:9AF1::08EE:20F1")}));
|
||||
na.setMtu(219);
|
||||
storeAttributes(FAKE_KEYS[1], na.build());
|
||||
na.setMtu(null);
|
||||
na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
|
||||
na.setDnsAddresses(Arrays.asList(
|
||||
new InetAddress[] {Inet6Address.getByName("0A1C:2E40:480A::1CA6")}));
|
||||
na.setGroupHint("hint1");
|
||||
storeAttributes(FAKE_KEYS[2], na.build());
|
||||
na.setMtu(219);
|
||||
storeAttributes(FAKE_KEYS[3], na.build());
|
||||
na.setMtu(240);
|
||||
storeAttributes(FAKE_KEYS[4], na.build());
|
||||
na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("5.6.7.8"));
|
||||
storeAttributes(FAKE_KEYS[5], na.build());
|
||||
|
||||
// Matches key 5 exactly
|
||||
doLatched("Did not finish finding L2Key", latch ->
|
||||
mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
|
||||
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
|
||||
status.isSuccess());
|
||||
assertEquals(FAKE_KEYS[5], key);
|
||||
})));
|
||||
|
||||
// MTU matches key 4 but v4 address matches key 5. The latter is stronger.
|
||||
na.setMtu(240);
|
||||
doLatched("Did not finish finding L2Key", latch ->
|
||||
mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
|
||||
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
|
||||
status.isSuccess());
|
||||
assertEquals(FAKE_KEYS[5], key);
|
||||
})));
|
||||
|
||||
// Closest to key 3 (indeed, identical)
|
||||
na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
|
||||
na.setMtu(219);
|
||||
doLatched("Did not finish finding L2Key", latch ->
|
||||
mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
|
||||
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
|
||||
status.isSuccess());
|
||||
assertEquals(FAKE_KEYS[3], key);
|
||||
})));
|
||||
|
||||
// Group hint alone must not be strong enough to override the rest
|
||||
na.setGroupHint("hint0");
|
||||
doLatched("Did not finish finding L2Key", latch ->
|
||||
mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
|
||||
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
|
||||
status.isSuccess());
|
||||
assertEquals(FAKE_KEYS[3], key);
|
||||
})));
|
||||
|
||||
// Still closest to key 3, though confidence is lower
|
||||
na.setGroupHint("hint1");
|
||||
na.setDnsAddresses(null);
|
||||
doLatched("Did not finish finding L2Key", latch ->
|
||||
mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
|
||||
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
|
||||
status.isSuccess());
|
||||
assertEquals(FAKE_KEYS[3], key);
|
||||
})));
|
||||
|
||||
// But changing the MTU makes this closer to key 4
|
||||
na.setMtu(240);
|
||||
doLatched("Did not finish finding L2Key", latch ->
|
||||
mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
|
||||
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
|
||||
status.isSuccess());
|
||||
assertEquals(FAKE_KEYS[4], key);
|
||||
})));
|
||||
|
||||
// MTU alone not strong enough to make this group-close
|
||||
na.setGroupHint(null);
|
||||
na.setDnsAddresses(null);
|
||||
na.setAssignedV4Address(null);
|
||||
doLatched("Did not finish finding L2Key", latch ->
|
||||
mService.findL2Key(na.build().toParcelable(), onL2KeyResponse((status, key) -> {
|
||||
assertTrue("Retrieve network sameness not successful : " + status.resultCode,
|
||||
status.isSuccess());
|
||||
assertNull(key);
|
||||
})));
|
||||
}
|
||||
|
||||
private void assertNetworksSameness(final String key1, final String key2, final int sameness) {
|
||||
@@ -349,7 +456,7 @@ public class IpMemoryStoreServiceTest {
|
||||
@Test
|
||||
public void testIsSameNetwork() throws UnknownHostException {
|
||||
final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
|
||||
na.setAssignedV4Address((Inet4Address) Inet4Address.getByAddress(new byte[]{1, 2, 3, 4}));
|
||||
na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
|
||||
na.setGroupHint("hint1");
|
||||
na.setMtu(219);
|
||||
na.setDnsAddresses(Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")));
|
||||
|
||||
Reference in New Issue
Block a user