Merge "[Thread] add the "vgh" TXT entry" into main

This commit is contained in:
Treehugger Robot 2024-06-12 18:07:55 +00:00 • committed by Gerrit Code Review
commit 7ff092e3d1
7 changed files with 80 additions and 95 deletions

View file

@ -53,4 +53,10 @@
UTF-8 bytes. UTF-8 bytes.
--> -->
<string translatable="false" name="config_thread_model_name">Thread Border Router</string> <string translatable="false" name="config_thread_model_name">Thread Border Router</string>
<!-- Whether the Thread network will be managed by the Google Home ecosystem. When this value
is set, a TXT entry "vgh=0" or "vgh=1" will be added to the "_mehscop._udp" mDNS service
respectively (The TXT value is a string).
-->
<bool name="config_thread_managed_by_google_home">false</bool>
</resources> </resources>

View file

@ -45,7 +45,6 @@ import com.android.server.thread.openthread.INsdStatusReceiver;
import java.net.Inet6Address; import java.net.Inet6Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -615,9 +614,8 @@ public final class NsdPublisher extends INsdPublisher.Stub {
} }
List<DnsTxtAttribute> txtList = new ArrayList<>(); List<DnsTxtAttribute> txtList = new ArrayList<>();
for (Map.Entry<String, byte[]> entry : serviceInfo.getAttributes().entrySet()) { for (Map.Entry<String, byte[]> entry : serviceInfo.getAttributes().entrySet()) {
DnsTxtAttribute attribute = new DnsTxtAttribute(); DnsTxtAttribute attribute =
attribute.name = entry.getKey(); new DnsTxtAttribute(entry.getKey(), entry.getValue().clone());
attribute.value = Arrays.copyOf(entry.getValue(), entry.getValue().length);
txtList.add(attribute); txtList.add(attribute);
} }
// TODO: b/329018320 - Use the serviceInfo.getExpirationTime to derive TTL. // TODO: b/329018320 - Use the serviceInfo.getExpirationTime to derive TTL.

View file

@ -61,6 +61,8 @@ import static com.android.server.thread.openthread.IOtDaemon.OT_STATE_DISABLING;
import static com.android.server.thread.openthread.IOtDaemon.OT_STATE_ENABLED; import static com.android.server.thread.openthread.IOtDaemon.OT_STATE_ENABLED;
import static com.android.server.thread.openthread.IOtDaemon.TUN_IF_NAME; import static com.android.server.thread.openthread.IOtDaemon.TUN_IF_NAME;
import static java.nio.charset.StandardCharsets.UTF_8;
import android.Manifest.permission; import android.Manifest.permission;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
@ -117,6 +119,7 @@ import com.android.server.ServiceManagerWrapper;
import com.android.server.connectivity.ConnectivityResources; import com.android.server.connectivity.ConnectivityResources;
import com.android.server.thread.openthread.BackboneRouterState; import com.android.server.thread.openthread.BackboneRouterState;
import com.android.server.thread.openthread.BorderRouterConfigurationParcel; import com.android.server.thread.openthread.BorderRouterConfigurationParcel;
import com.android.server.thread.openthread.DnsTxtAttribute;
import com.android.server.thread.openthread.IChannelMasksReceiver; import com.android.server.thread.openthread.IChannelMasksReceiver;
import com.android.server.thread.openthread.IOtDaemon; import com.android.server.thread.openthread.IOtDaemon;
import com.android.server.thread.openthread.IOtDaemonCallback; import com.android.server.thread.openthread.IOtDaemonCallback;
@ -130,7 +133,6 @@ import libcore.util.HexEncoding;
import java.io.IOException; import java.io.IOException;
import java.net.Inet6Address; import java.net.Inet6Address;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.time.Clock; import java.time.Clock;
import java.time.DateTimeException; import java.time.DateTimeException;
@ -338,9 +340,11 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub
final String modelName = resources.getString(R.string.config_thread_model_name); final String modelName = resources.getString(R.string.config_thread_model_name);
final String vendorName = resources.getString(R.string.config_thread_vendor_name); final String vendorName = resources.getString(R.string.config_thread_vendor_name);
final String vendorOui = resources.getString(R.string.config_thread_vendor_oui); final String vendorOui = resources.getString(R.string.config_thread_vendor_oui);
final boolean managedByGoogle =
resources.getBoolean(R.bool.config_thread_managed_by_google_home);
if (!modelName.isEmpty()) { if (!modelName.isEmpty()) {
if (modelName.getBytes(StandardCharsets.UTF_8).length > MAX_MODEL_NAME_UTF8_BYTES) { if (modelName.getBytes(UTF_8).length > MAX_MODEL_NAME_UTF8_BYTES) {
throw new IllegalStateException( throw new IllegalStateException(
"Model name is longer than " "Model name is longer than "
+ MAX_MODEL_NAME_UTF8_BYTES + MAX_MODEL_NAME_UTF8_BYTES
@ -350,7 +354,7 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub
} }
if (!vendorName.isEmpty()) { if (!vendorName.isEmpty()) {
if (vendorName.getBytes(StandardCharsets.UTF_8).length > MAX_VENDOR_NAME_UTF8_BYTES) { if (vendorName.getBytes(UTF_8).length > MAX_VENDOR_NAME_UTF8_BYTES) {
throw new IllegalStateException( throw new IllegalStateException(
"Vendor name is longer than " "Vendor name is longer than "
+ MAX_VENDOR_NAME_UTF8_BYTES + MAX_VENDOR_NAME_UTF8_BYTES
@ -367,9 +371,21 @@ final class ThreadNetworkControllerService extends IThreadNetworkController.Stub
meshcopTxts.modelName = modelName; meshcopTxts.modelName = modelName;
meshcopTxts.vendorName = vendorName; meshcopTxts.vendorName = vendorName;
meshcopTxts.vendorOui = HexEncoding.decode(vendorOui.replace("-", "").replace(":", "")); meshcopTxts.vendorOui = HexEncoding.decode(vendorOui.replace("-", "").replace(":", ""));
meshcopTxts.nonStandardTxtEntries = List.of(makeManagedByGoogleTxtAttr(managedByGoogle));
return meshcopTxts; return meshcopTxts;
} }
/**
* Creates a DNS-SD TXT entry for indicating whether Thread on this device is managed by Google.
*
* @return TXT entry "vgh=1" if {@code managedByGoogle} is {@code true}; otherwise, "vgh=0"
*/
private static DnsTxtAttribute makeManagedByGoogleTxtAttr(boolean managedByGoogle) {
final byte[] value = (managedByGoogle ? "1" : "0").getBytes(UTF_8);
return new DnsTxtAttribute("vgh", value);
}
private void onOtDaemonDied() { private void onOtDaemonDied() {
checkOnHandlerThread(); checkOnHandlerThread();
Log.w(TAG, "OT daemon is dead, clean up..."); Log.w(TAG, "OT daemon is dead, clean up...");

View file

@ -45,7 +45,6 @@ import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS;
import android.content.Context; import android.content.Context;
@ -859,6 +858,7 @@ public class ThreadNetworkControllerTest {
assertThat(txtMap.get("rv")).isNotNull(); assertThat(txtMap.get("rv")).isNotNull();
assertThat(txtMap.get("tv")).isNotNull(); assertThat(txtMap.get("tv")).isNotNull();
assertThat(txtMap.get("sb")).isNotNull(); assertThat(txtMap.get("sb")).isNotNull();
assertThat(new String(txtMap.get("vgh"))).isIn(List.of("0", "1"));
} }
@Test @Test
@ -885,6 +885,7 @@ public class ThreadNetworkControllerTest {
assertThat(txtMap.get("tv")).isNotNull(); assertThat(txtMap.get("tv")).isNotNull();
assertThat(txtMap.get("sb")).isNotNull(); assertThat(txtMap.get("sb")).isNotNull();
assertThat(txtMap.get("id").length).isEqualTo(16); assertThat(txtMap.get("id").length).isEqualTo(16);
assertThat(new String(txtMap.get("vgh"))).isIn(List.of("0", "1"));
} }
@Test @Test

View file

@ -17,7 +17,9 @@ package android.net.thread.utils;
import static android.net.thread.utils.IntegrationTestUtils.SERVICE_DISCOVERY_TIMEOUT; import static android.net.thread.utils.IntegrationTestUtils.SERVICE_DISCOVERY_TIMEOUT;
import static android.net.thread.utils.IntegrationTestUtils.waitFor; import static android.net.thread.utils.IntegrationTestUtils.waitFor;
import static com.google.common.io.BaseEncoding.base16; import static com.google.common.io.BaseEncoding.base16;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
import android.net.InetAddresses; import android.net.InetAddresses;
@ -26,7 +28,9 @@ import android.net.nsd.NsdServiceInfo;
import android.net.thread.ActiveOperationalDataset; import android.net.thread.ActiveOperationalDataset;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import com.google.errorprone.annotations.FormatMethod; import com.google.errorprone.annotations.FormatMethod;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;

View file

@ -22,14 +22,15 @@ import static android.net.nsd.NsdManager.PROTOCOL_DNS_SD;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.hamcrest.MockitoHamcrest.argThat;
import android.net.DnsResolver; import android.net.DnsResolver;
import android.net.InetAddresses; import android.net.InetAddresses;
@ -50,21 +51,23 @@ import com.android.server.thread.openthread.INsdStatusReceiver;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
/** Unit tests for {@link NsdPublisher}. */ /** Unit tests for {@link NsdPublisher}. */
public final class NsdPublisherTest { public final class NsdPublisherTest {
private static final DnsTxtAttribute TEST_TXT_ENTRY_1 =
new DnsTxtAttribute("key1", new byte[] {0x01, 0x02});
private static final DnsTxtAttribute TEST_TXT_ENTRY_2 =
new DnsTxtAttribute("key2", new byte[] {0x03});
@Mock private NsdManager mMockNsdManager; @Mock private NsdManager mMockNsdManager;
@Mock private DnsResolver mMockDnsResolver; @Mock private DnsResolver mMockDnsResolver;
@ -87,19 +90,15 @@ public final class NsdPublisherTest {
public void registerService_nsdManagerSucceeds_serviceRegistrationSucceeds() throws Exception { public void registerService_nsdManagerSucceeds_serviceRegistrationSucceeds() throws Exception {
prepareTest(); prepareTest();
DnsTxtAttribute txt1 = makeTxtAttribute("key1", List.of(0x01, 0x02));
DnsTxtAttribute txt2 = makeTxtAttribute("key2", List.of(0x03));
mNsdPublisher.registerService( mNsdPublisher.registerService(
null, null,
"MyService", "MyService",
"_test._tcp", "_test._tcp",
List.of("_subtype1", "_subtype2"), List.of("_subtype1", "_subtype2"),
12345, 12345,
List.of(txt1, txt2), List.of(TEST_TXT_ENTRY_1, TEST_TXT_ENTRY_2),
mRegistrationReceiver, mRegistrationReceiver,
16 /* listenerId */); 16 /* listenerId */);
mTestLooper.dispatchAll(); mTestLooper.dispatchAll();
ArgumentCaptor<NsdServiceInfo> actualServiceInfoCaptor = ArgumentCaptor<NsdServiceInfo> actualServiceInfoCaptor =
@ -126,11 +125,10 @@ public final class NsdPublisherTest {
assertThat(actualServiceInfo.getSubtypes()).isEqualTo(Set.of("_subtype1", "_subtype2")); assertThat(actualServiceInfo.getSubtypes()).isEqualTo(Set.of("_subtype1", "_subtype2"));
assertThat(actualServiceInfo.getPort()).isEqualTo(12345); assertThat(actualServiceInfo.getPort()).isEqualTo(12345);
assertThat(actualServiceInfo.getAttributes().size()).isEqualTo(2); assertThat(actualServiceInfo.getAttributes().size()).isEqualTo(2);
assertThat(actualServiceInfo.getAttributes().get("key1")) assertThat(actualServiceInfo.getAttributes().get(TEST_TXT_ENTRY_1.name))
.isEqualTo(new byte[] {(byte) 0x01, (byte) 0x02}); .isEqualTo(TEST_TXT_ENTRY_1.value);
assertThat(actualServiceInfo.getAttributes().get("key2")) assertThat(actualServiceInfo.getAttributes().get(TEST_TXT_ENTRY_2.name))
.isEqualTo(new byte[] {(byte) 0x03}); .isEqualTo(TEST_TXT_ENTRY_2.value);
verify(mRegistrationReceiver, times(1)).onSuccess(); verify(mRegistrationReceiver, times(1)).onSuccess();
} }
@ -138,19 +136,15 @@ public final class NsdPublisherTest {
public void registerService_nsdManagerFails_serviceRegistrationFails() throws Exception { public void registerService_nsdManagerFails_serviceRegistrationFails() throws Exception {
prepareTest(); prepareTest();
DnsTxtAttribute txt1 = makeTxtAttribute("key1", List.of(0x01, 0x02));
DnsTxtAttribute txt2 = makeTxtAttribute("key2", List.of(0x03));
mNsdPublisher.registerService( mNsdPublisher.registerService(
null, null,
"MyService", "MyService",
"_test._tcp", "_test._tcp",
List.of("_subtype1", "_subtype2"), List.of("_subtype1", "_subtype2"),
12345, 12345,
List.of(txt1, txt2), List.of(TEST_TXT_ENTRY_1, TEST_TXT_ENTRY_2),
mRegistrationReceiver, mRegistrationReceiver,
16 /* listenerId */); 16 /* listenerId */);
mTestLooper.dispatchAll(); mTestLooper.dispatchAll();
ArgumentCaptor<NsdServiceInfo> actualServiceInfoCaptor = ArgumentCaptor<NsdServiceInfo> actualServiceInfoCaptor =
@ -177,21 +171,16 @@ public final class NsdPublisherTest {
assertThat(actualServiceInfo.getSubtypes()).isEqualTo(Set.of("_subtype1", "_subtype2")); assertThat(actualServiceInfo.getSubtypes()).isEqualTo(Set.of("_subtype1", "_subtype2"));
assertThat(actualServiceInfo.getPort()).isEqualTo(12345); assertThat(actualServiceInfo.getPort()).isEqualTo(12345);
assertThat(actualServiceInfo.getAttributes().size()).isEqualTo(2); assertThat(actualServiceInfo.getAttributes().size()).isEqualTo(2);
assertThat(actualServiceInfo.getAttributes().get("key1")) assertThat(actualServiceInfo.getAttributes().get(TEST_TXT_ENTRY_1.name))
.isEqualTo(new byte[] {(byte) 0x01, (byte) 0x02}); .isEqualTo(TEST_TXT_ENTRY_1.value);
assertThat(actualServiceInfo.getAttributes().get("key2")) assertThat(actualServiceInfo.getAttributes().get(TEST_TXT_ENTRY_2.name))
.isEqualTo(new byte[] {(byte) 0x03}); .isEqualTo(TEST_TXT_ENTRY_2.value);
verify(mRegistrationReceiver, times(1)).onError(FAILURE_INTERNAL_ERROR); verify(mRegistrationReceiver, times(1)).onError(FAILURE_INTERNAL_ERROR);
} }
@Test @Test
public void registerService_nsdManagerThrows_serviceRegistrationFails() throws Exception { public void registerService_nsdManagerThrows_serviceRegistrationFails() throws Exception {
prepareTest(); prepareTest();
DnsTxtAttribute txt1 = makeTxtAttribute("key1", List.of(0x01, 0x02));
DnsTxtAttribute txt2 = makeTxtAttribute("key2", List.of(0x03));
doThrow(new IllegalArgumentException("NsdManager fails")) doThrow(new IllegalArgumentException("NsdManager fails"))
.when(mMockNsdManager) .when(mMockNsdManager)
.registerService(any(), anyInt(), any(Executor.class), any()); .registerService(any(), anyInt(), any(Executor.class), any());
@ -202,7 +191,7 @@ public final class NsdPublisherTest {
"_test._tcp", "_test._tcp",
List.of("_subtype1", "_subtype2"), List.of("_subtype1", "_subtype2"),
12345, 12345,
List.of(txt1, txt2), List.of(TEST_TXT_ENTRY_1, TEST_TXT_ENTRY_2),
mRegistrationReceiver, mRegistrationReceiver,
16 /* listenerId */); 16 /* listenerId */);
mTestLooper.dispatchAll(); mTestLooper.dispatchAll();
@ -215,16 +204,13 @@ public final class NsdPublisherTest {
throws Exception { throws Exception {
prepareTest(); prepareTest();
DnsTxtAttribute txt1 = makeTxtAttribute("key1", List.of(0x01, 0x02));
DnsTxtAttribute txt2 = makeTxtAttribute("key2", List.of(0x03));
mNsdPublisher.registerService( mNsdPublisher.registerService(
null, null,
"MyService", "MyService",
"_test._tcp", "_test._tcp",
List.of("_subtype1", "_subtype2"), List.of("_subtype1", "_subtype2"),
12345, 12345,
List.of(txt1, txt2), List.of(TEST_TXT_ENTRY_1, TEST_TXT_ENTRY_2),
mRegistrationReceiver, mRegistrationReceiver,
16 /* listenerId */); 16 /* listenerId */);
@ -260,16 +246,13 @@ public final class NsdPublisherTest {
public void unregisterService_nsdManagerFails_serviceUnregistrationFails() throws Exception { public void unregisterService_nsdManagerFails_serviceUnregistrationFails() throws Exception {
prepareTest(); prepareTest();
DnsTxtAttribute txt1 = makeTxtAttribute("key1", List.of(0x01, 0x02));
DnsTxtAttribute txt2 = makeTxtAttribute("key2", List.of(0x03));
mNsdPublisher.registerService( mNsdPublisher.registerService(
null, null,
"MyService", "MyService",
"_test._tcp", "_test._tcp",
List.of("_subtype1", "_subtype2"), List.of("_subtype1", "_subtype2"),
12345, 12345,
List.of(txt1, txt2), List.of(TEST_TXT_ENTRY_1, TEST_TXT_ENTRY_2),
mRegistrationReceiver, mRegistrationReceiver,
16 /* listenerId */); 16 /* listenerId */);
@ -587,8 +570,8 @@ public final class NsdPublisherTest {
List.of( List.of(
InetAddress.parseNumericAddress("2001::1"), InetAddress.parseNumericAddress("2001::1"),
InetAddress.parseNumericAddress("2001::2"))); InetAddress.parseNumericAddress("2001::2")));
serviceInfo.setAttribute("key1", new byte[] {(byte) 0x01, (byte) 0x02}); serviceInfo.setAttribute(TEST_TXT_ENTRY_1.name, TEST_TXT_ENTRY_1.value);
serviceInfo.setAttribute("key2", new byte[] {(byte) 0x03}); serviceInfo.setAttribute(TEST_TXT_ENTRY_2.name, TEST_TXT_ENTRY_2.value);
serviceInfoCallbackArgumentCaptor.getValue().onServiceUpdated(serviceInfo); serviceInfoCallbackArgumentCaptor.getValue().onServiceUpdated(serviceInfo);
mTestLooper.dispatchAll(); mTestLooper.dispatchAll();
@ -599,11 +582,8 @@ public final class NsdPublisherTest {
eq("_test._tcp"), eq("_test._tcp"),
eq(12345), eq(12345),
eq(List.of("2001::1", "2001::2")), eq(List.of("2001::1", "2001::2")),
argThat( (List<DnsTxtAttribute>)
new TxtMatcher( argThat(containsInAnyOrder(TEST_TXT_ENTRY_1, TEST_TXT_ENTRY_2)),
List.of(
makeTxtAttribute("key1", List.of(0x01, 0x02)),
makeTxtAttribute("key2", List.of(0x03))))),
anyInt()); anyInt());
} }
@ -725,10 +705,6 @@ public final class NsdPublisherTest {
@Test @Test
public void reset_unregisterAll() { public void reset_unregisterAll() {
prepareTest(); prepareTest();
DnsTxtAttribute txt1 = makeTxtAttribute("key1", List.of(0x01, 0x02));
DnsTxtAttribute txt2 = makeTxtAttribute("key2", List.of(0x03));
ArgumentCaptor<NsdServiceInfo> actualServiceInfoCaptor = ArgumentCaptor<NsdServiceInfo> actualServiceInfoCaptor =
ArgumentCaptor.forClass(NsdServiceInfo.class); ArgumentCaptor.forClass(NsdServiceInfo.class);
ArgumentCaptor<NsdManager.RegistrationListener> actualRegistrationListenerCaptor = ArgumentCaptor<NsdManager.RegistrationListener> actualRegistrationListenerCaptor =
@ -740,7 +716,7 @@ public final class NsdPublisherTest {
"_test._tcp", "_test._tcp",
List.of("_subtype1", "_subtype2"), List.of("_subtype1", "_subtype2"),
12345, 12345,
List.of(txt1, txt2), List.of(TEST_TXT_ENTRY_1, TEST_TXT_ENTRY_2),
mRegistrationReceiver, mRegistrationReceiver,
16 /* listenerId */); 16 /* listenerId */);
mTestLooper.dispatchAll(); mTestLooper.dispatchAll();
@ -814,19 +790,6 @@ public final class NsdPublisherTest {
verify(spyNsdPublisher, times(1)).reset(); verify(spyNsdPublisher, times(1)).reset();
} }
private static DnsTxtAttribute makeTxtAttribute(String name, List<Integer> value) {
DnsTxtAttribute txtAttribute = new DnsTxtAttribute();
txtAttribute.name = name;
txtAttribute.value = new byte[value.size()];
for (int i = 0; i < value.size(); ++i) {
txtAttribute.value[i] = value.get(i).byteValue();
}
return txtAttribute;
}
private static List<InetAddress> makeAddresses(String... addressStrings) { private static List<InetAddress> makeAddresses(String... addressStrings) {
List<InetAddress> addresses = new ArrayList<>(); List<InetAddress> addresses = new ArrayList<>();
@ -836,30 +799,6 @@ public final class NsdPublisherTest {
return addresses; return addresses;
} }
private static class TxtMatcher implements ArgumentMatcher<List<DnsTxtAttribute>> {
private final List<DnsTxtAttribute> mAttributes;
TxtMatcher(List<DnsTxtAttribute> attributes) {
mAttributes = attributes;
}
@Override
public boolean matches(List<DnsTxtAttribute> argument) {
if (argument.size() != mAttributes.size()) {
return false;
}
for (int i = 0; i < argument.size(); ++i) {
if (!Objects.equals(argument.get(i).name, mAttributes.get(i).name)) {
return false;
}
if (!Arrays.equals(argument.get(i).value, mAttributes.get(i).value)) {
return false;
}
}
return true;
}
}
// @Before and @Test run in different threads. NsdPublisher requires the jobs are run on the // @Before and @Test run in different threads. NsdPublisher requires the jobs are run on the
// thread looper, so TestLooper needs to be created inside each test case to install the // thread looper, so TestLooper needs to be created inside each test case to install the
// correct looper. // correct looper.

View file

@ -78,6 +78,7 @@ import androidx.test.filters.SmallTest;
import com.android.connectivity.resources.R; import com.android.connectivity.resources.R;
import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.dx.mockito.inline.extended.ExtendedMockito;
import com.android.server.connectivity.ConnectivityResources; import com.android.server.connectivity.ConnectivityResources;
import com.android.server.thread.openthread.DnsTxtAttribute;
import com.android.server.thread.openthread.MeshcopTxtAttributes; import com.android.server.thread.openthread.MeshcopTxtAttributes;
import com.android.server.thread.openthread.testing.FakeOtDaemon; import com.android.server.thread.openthread.testing.FakeOtDaemon;
@ -94,6 +95,7 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession; import org.mockito.MockitoSession;
import java.nio.charset.StandardCharsets;
import java.time.Clock; import java.time.Clock;
import java.time.DateTimeException; import java.time.DateTimeException;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@ -145,6 +147,7 @@ public final class ThreadNetworkControllerServiceTest {
private static final byte[] TEST_VENDOR_OUI_BYTES = new byte[] {(byte) 0xAC, (byte) 0xDE, 0x48}; private static final byte[] TEST_VENDOR_OUI_BYTES = new byte[] {(byte) 0xAC, (byte) 0xDE, 0x48};
private static final String TEST_VENDOR_NAME = "test vendor"; private static final String TEST_VENDOR_NAME = "test vendor";
private static final String TEST_MODEL_NAME = "test model"; private static final String TEST_MODEL_NAME = "test model";
private static final boolean TEST_VGH_VALUE = false;
@Mock private ConnectivityManager mMockConnectivityManager; @Mock private ConnectivityManager mMockConnectivityManager;
@Mock private NetworkAgent mMockNetworkAgent; @Mock private NetworkAgent mMockNetworkAgent;
@ -197,6 +200,8 @@ public final class ThreadNetworkControllerServiceTest {
.thenReturn(TEST_VENDOR_OUI); .thenReturn(TEST_VENDOR_OUI);
when(mResources.getString(eq(R.string.config_thread_model_name))) when(mResources.getString(eq(R.string.config_thread_model_name)))
.thenReturn(TEST_MODEL_NAME); .thenReturn(TEST_MODEL_NAME);
when(mResources.getBoolean(eq(R.bool.config_thread_managed_by_google_home)))
.thenReturn(TEST_VGH_VALUE);
final AtomicFile storageFile = new AtomicFile(tempFolder.newFile("thread_settings.xml")); final AtomicFile storageFile = new AtomicFile(tempFolder.newFile("thread_settings.xml"));
mPersistentSettings = new ThreadPersistentSettings(storageFile, mConnectivityResources); mPersistentSettings = new ThreadPersistentSettings(storageFile, mConnectivityResources);
@ -232,13 +237,15 @@ public final class ThreadNetworkControllerServiceTest {
} }
@Test @Test
public void initialize_vendorAndModelNameInResourcesAreSetToOtDaemon() throws Exception { public void initialize_resourceOverlayValuesAreSetToOtDaemon() throws Exception {
when(mResources.getString(eq(R.string.config_thread_vendor_name))) when(mResources.getString(eq(R.string.config_thread_vendor_name)))
.thenReturn(TEST_VENDOR_NAME); .thenReturn(TEST_VENDOR_NAME);
when(mResources.getString(eq(R.string.config_thread_vendor_oui))) when(mResources.getString(eq(R.string.config_thread_vendor_oui)))
.thenReturn(TEST_VENDOR_OUI); .thenReturn(TEST_VENDOR_OUI);
when(mResources.getString(eq(R.string.config_thread_model_name))) when(mResources.getString(eq(R.string.config_thread_model_name)))
.thenReturn(TEST_MODEL_NAME); .thenReturn(TEST_MODEL_NAME);
when(mResources.getBoolean(eq(R.bool.config_thread_managed_by_google_home)))
.thenReturn(true);
mService.initialize(); mService.initialize();
mTestLooper.dispatchAll(); mTestLooper.dispatchAll();
@ -247,6 +254,20 @@ public final class ThreadNetworkControllerServiceTest {
assertThat(meshcopTxts.vendorName).isEqualTo(TEST_VENDOR_NAME); assertThat(meshcopTxts.vendorName).isEqualTo(TEST_VENDOR_NAME);
assertThat(meshcopTxts.vendorOui).isEqualTo(TEST_VENDOR_OUI_BYTES); assertThat(meshcopTxts.vendorOui).isEqualTo(TEST_VENDOR_OUI_BYTES);
assertThat(meshcopTxts.modelName).isEqualTo(TEST_MODEL_NAME); assertThat(meshcopTxts.modelName).isEqualTo(TEST_MODEL_NAME);
assertThat(meshcopTxts.nonStandardTxtEntries)
.containsExactly(new DnsTxtAttribute("vgh", "1".getBytes(StandardCharsets.UTF_8)));
}
@Test
public void getMeshcopTxtAttributes_managedByGoogleIsFalse_vghIsZero() {
when(mResources.getBoolean(eq(R.bool.config_thread_managed_by_google_home)))
.thenReturn(false);
MeshcopTxtAttributes meshcopTxts =
ThreadNetworkControllerService.getMeshcopTxtAttributes(mResources);
assertThat(meshcopTxts.nonStandardTxtEntries)
.containsExactly(new DnsTxtAttribute("vgh", "0".getBytes(StandardCharsets.UTF_8)));
} }
@Test @Test