Merge "Add a test case that a Border Router sends a UDP message to Thread device" into main
This commit is contained in:
commit
b206809a64
3 changed files with 109 additions and 0 deletions
|
|
@ -21,10 +21,12 @@ import static android.Manifest.permission.NETWORK_SETTINGS;
|
|||
import static android.net.thread.ThreadNetworkController.DEVICE_ROLE_LEADER;
|
||||
import static android.net.thread.ThreadNetworkManager.PERMISSION_THREAD_NETWORK_PRIVILEGED;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.JOIN_TIMEOUT;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.RESTART_JOIN_TIMEOUT;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.isExpectedIcmpv6Packet;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.isSimulatedThreadRadioSupported;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.newPacketReader;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.readPacketFrom;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.sendUdpMessage;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.waitFor;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.waitForStateAnyOf;
|
||||
|
||||
|
|
@ -35,10 +37,13 @@ import static com.android.testutils.TestPermissionUtil.runAsShell;
|
|||
import static com.google.common.io.BaseEncoding.base16;
|
||||
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assume.assumeNotNull;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.MacAddress;
|
||||
|
|
@ -62,6 +67,7 @@ import org.junit.runner.RunWith;
|
|||
import java.net.Inet6Address;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
|
@ -187,4 +193,44 @@ public class BorderRoutingTest {
|
|||
infraNetworkReader,
|
||||
p -> isExpectedIcmpv6Packet(p, ICMPV6_ECHO_REPLY_TYPE)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unicastRouting_borderRouterSendsUdpToThreadDevice_datagramReceived()
|
||||
throws Exception {
|
||||
assumeTrue(isSimulatedThreadRadioSupported());
|
||||
|
||||
/*
|
||||
* <pre>
|
||||
* Topology:
|
||||
* Thread
|
||||
* Border Router -------------- Full Thread device
|
||||
* (Cuttlefish)
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
// BR forms a network.
|
||||
CompletableFuture<Void> joinFuture = new CompletableFuture<>();
|
||||
runAsShell(
|
||||
PERMISSION_THREAD_NETWORK_PRIVILEGED,
|
||||
() -> mController.join(DEFAULT_DATASET, directExecutor(), joinFuture::complete));
|
||||
joinFuture.get(RESTART_JOIN_TIMEOUT.toMillis(), MILLISECONDS);
|
||||
|
||||
// Creates a Full Thread Device (FTD) and lets it join the network.
|
||||
FullThreadDevice ftd = new FullThreadDevice(6 /* node ID */);
|
||||
ftd.joinNetwork(DEFAULT_DATASET);
|
||||
ftd.waitForStateAnyOf(List.of("router", "child"), JOIN_TIMEOUT);
|
||||
waitFor(() -> ftd.getOmrAddress() != null, Duration.ofSeconds(60));
|
||||
Inet6Address ftdOmr = ftd.getOmrAddress();
|
||||
assertNotNull(ftdOmr);
|
||||
Inet6Address ftdMlEid = ftd.getMlEid();
|
||||
assertNotNull(ftdMlEid);
|
||||
|
||||
ftd.udpBind(ftdOmr, 12345);
|
||||
sendUdpMessage(ftdOmr, 12345, "aaaaaaaa");
|
||||
assertEquals("aaaaaaaa", ftd.udpReceive());
|
||||
|
||||
ftd.udpBind(ftdMlEid, 12345);
|
||||
sendUdpMessage(ftdMlEid, 12345, "bbbbbbbb");
|
||||
assertEquals("bbbbbbbb", ftd.udpReceive());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ import java.time.Duration;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A class that launches and controls a simulation Full Thread Device (FTD).
|
||||
|
|
@ -94,6 +96,12 @@ public final class FullThreadDevice {
|
|||
return null;
|
||||
}
|
||||
|
||||
/** Returns the Mesh-local EID address on this device if any. */
|
||||
public Inet6Address getMlEid() {
|
||||
List<String> addresses = executeCommand("ipaddr mleid");
|
||||
return (Inet6Address) InetAddresses.parseNumericAddress(addresses.get(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins the Thread network using the given {@link ActiveOperationalDataset}.
|
||||
*
|
||||
|
|
@ -132,6 +140,33 @@ public final class FullThreadDevice {
|
|||
return executeCommand("state").get(0);
|
||||
}
|
||||
|
||||
/** Closes the UDP socket. */
|
||||
public void udpClose() {
|
||||
executeCommand("udp close");
|
||||
}
|
||||
|
||||
/** Opens the UDP socket. */
|
||||
public void udpOpen() {
|
||||
executeCommand("udp open");
|
||||
}
|
||||
|
||||
/** Opens the UDP socket and binds it to a specific address and port. */
|
||||
public void udpBind(Inet6Address address, int port) {
|
||||
udpClose();
|
||||
udpOpen();
|
||||
executeCommand(String.format("udp bind %s %d", address.getHostAddress(), port));
|
||||
}
|
||||
|
||||
/** Returns the message received on the UDP socket. */
|
||||
public String udpReceive() throws IOException {
|
||||
Pattern pattern =
|
||||
Pattern.compile("> (\\d+) bytes from ([\\da-f:]+) (\\d+) ([\\x00-\\x7F]+)");
|
||||
Matcher matcher = pattern.matcher(mReader.readLine());
|
||||
matcher.matches();
|
||||
|
||||
return matcher.group(4);
|
||||
}
|
||||
|
||||
/** Runs the "factoryreset" command on the device. */
|
||||
public void factoryReset() {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@ import com.android.testutils.TapPacketReader;
|
|||
import com.google.common.util.concurrent.SettableFuture;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -219,4 +225,26 @@ public final class IntegrationTestUtils {
|
|||
}
|
||||
return pioList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a UDP message to a destination.
|
||||
*
|
||||
* @param dstAddress the IP address of the destination
|
||||
* @param dstPort the port of the destination
|
||||
* @param message the message in UDP payload
|
||||
* @throws IOException if failed to send the message
|
||||
*/
|
||||
public static void sendUdpMessage(InetAddress dstAddress, int dstPort, String message)
|
||||
throws IOException {
|
||||
SocketAddress dstSockAddr = new InetSocketAddress(dstAddress, dstPort);
|
||||
|
||||
try (DatagramSocket socket = new DatagramSocket()) {
|
||||
socket.connect(dstSockAddr);
|
||||
|
||||
byte[] msgBytes = message.getBytes();
|
||||
DatagramPacket packet = new DatagramPacket(msgBytes, msgBytes.length);
|
||||
|
||||
socket.send(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue