Merge "[Thread] add integration tests for aosp/3334156" into main
This commit is contained in:
commit
2ec7bbc491
4 changed files with 128 additions and 1 deletions
|
|
@ -18,8 +18,8 @@ package android.net.thread;
|
|||
|
||||
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
|
||||
import static android.net.InetAddresses.parseNumericAddress;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.buildIcmpv4EchoReply;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.DEFAULT_DATASET;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.buildIcmpv4EchoReply;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.enableThreadAndJoinNetwork;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.getIpv6LinkAddresses;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.isExpectedIcmpv4Packet;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import static android.net.thread.utils.IntegrationTestUtils.getPrefixesFromNetDa
|
|||
import static android.net.thread.utils.IntegrationTestUtils.getThreadNetwork;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.isInMulticastGroup;
|
||||
import static android.net.thread.utils.IntegrationTestUtils.waitFor;
|
||||
import static android.net.thread.utils.ThreadNetworkControllerWrapper.JOIN_TIMEOUT;
|
||||
|
||||
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
|
||||
import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
|
||||
|
|
@ -55,6 +56,7 @@ import android.net.thread.utils.OtDaemonController;
|
|||
import android.net.thread.utils.ThreadFeatureCheckerRule;
|
||||
import android.net.thread.utils.ThreadFeatureCheckerRule.RequiresThreadFeature;
|
||||
import android.net.thread.utils.ThreadNetworkControllerWrapper;
|
||||
import android.net.thread.utils.ThreadStateListener;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
|
@ -138,6 +140,8 @@ public class ThreadIntegrationTest {
|
|||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
ThreadStateListener.stopAllListeners();
|
||||
|
||||
mController.setTestNetworkAsUpstreamAndWait(null);
|
||||
mController.leaveAndWait();
|
||||
mController.setConfigurationAndWait(DEFAULT_CONFIG);
|
||||
|
|
@ -267,6 +271,20 @@ public class ThreadIntegrationTest {
|
|||
assertTunInterfaceMemberOfGroup(GROUP_ADDR_ALL_ROUTERS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void joinNetwork_joinTheSameNetworkTwice_neverDetached() throws Exception {
|
||||
mController.joinAndWait(DEFAULT_DATASET);
|
||||
mController.waitForRole(DEVICE_ROLE_LEADER, JOIN_TIMEOUT);
|
||||
|
||||
var listener = ThreadStateListener.startListener(mController.get());
|
||||
mController.joinAndWait(DEFAULT_DATASET);
|
||||
|
||||
assertThat(
|
||||
listener.pollForAnyRoleOf(
|
||||
List.of(DEVICE_ROLE_DETACHED, DEVICE_ROLE_STOPPED), JOIN_TIMEOUT))
|
||||
.isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void edPingsMeshLocalAddresses_oneReplyPerRequest() throws Exception {
|
||||
mController.joinAndWait(DEFAULT_DATASET);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import android.net.thread.ThreadNetworkManager;
|
|||
import android.os.OutcomeReceiver;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
|
@ -53,6 +54,9 @@ public final class ThreadNetworkControllerWrapper {
|
|||
|
||||
private final ThreadNetworkController mController;
|
||||
|
||||
private final List<Integer> mDeviceRoleUpdates = new ArrayList<>();
|
||||
@Nullable private StateCallback mStateCallback;
|
||||
|
||||
/**
|
||||
* Returns a new {@link ThreadNetworkControllerWrapper} instance or {@code null} if Thread
|
||||
* feature is not supported on this device.
|
||||
|
|
@ -70,6 +74,15 @@ public final class ThreadNetworkControllerWrapper {
|
|||
mController = controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link ThreadNetworkController} object or {@code null} if the current
|
||||
* platform doesn't support it.
|
||||
*/
|
||||
@Nullable
|
||||
public ThreadNetworkController get() {
|
||||
return mController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Thread enabled state.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (C) 2024 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 android.net.thread.utils;
|
||||
|
||||
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
|
||||
|
||||
import static com.android.testutils.TestPermissionUtil.runAsShell;
|
||||
|
||||
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.net.thread.ThreadNetworkController;
|
||||
import android.net.thread.ThreadNetworkController.StateCallback;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.net.module.util.ArrayTrackRecord;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A listener for sequential Thread state updates.
|
||||
*
|
||||
* <p>This is a wrapper around {@link ThreadNetworkController#registerStateCallback} to make
|
||||
* synchronized access to Thread state updates easier.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public final class ThreadStateListener {
|
||||
private static final List<ThreadStateListener> sListeners = new ArrayList<>();
|
||||
private final ArrayTrackRecord<Integer> mDeviceRoleUpdates = new ArrayTrackRecord<>();
|
||||
private final ArrayTrackRecord<Integer>.ReadHead mReadHead = mDeviceRoleUpdates.newReadHead();
|
||||
private final ThreadNetworkController mController;
|
||||
private final StateCallback mCallback =
|
||||
new ThreadNetworkController.StateCallback() {
|
||||
@Override
|
||||
public void onDeviceRoleChanged(int newRole) {
|
||||
mDeviceRoleUpdates.add(newRole);
|
||||
}
|
||||
// Add more state update trackers here
|
||||
};
|
||||
|
||||
/** Creates a new {@link ThreadStateListener} object and starts listening for state updates. */
|
||||
public static ThreadStateListener startListener(ThreadNetworkController controller) {
|
||||
var listener = new ThreadStateListener(controller);
|
||||
sListeners.add(listener);
|
||||
listener.start();
|
||||
return listener;
|
||||
}
|
||||
|
||||
/** Stops all listeners created by {@link #startListener}. */
|
||||
public static void stopAllListeners() {
|
||||
for (var listener : sListeners) {
|
||||
listener.stop();
|
||||
}
|
||||
sListeners.clear();
|
||||
}
|
||||
|
||||
private ThreadStateListener(ThreadNetworkController controller) {
|
||||
mController = controller;
|
||||
}
|
||||
|
||||
private void start() {
|
||||
runAsShell(
|
||||
ACCESS_NETWORK_STATE,
|
||||
() -> mController.registerStateCallback(directExecutor(), mCallback));
|
||||
}
|
||||
|
||||
private void stop() {
|
||||
runAsShell(ACCESS_NETWORK_STATE, () -> mController.unregisterStateCallback(mCallback));
|
||||
}
|
||||
|
||||
/**
|
||||
* Polls for any role in {@code roles} starting after call to {@link #startListener}.
|
||||
*
|
||||
* <p>Returns the matched device role or {@code null} if timeout.
|
||||
*/
|
||||
@Nullable
|
||||
public Integer pollForAnyRoleOf(List<Integer> roles, Duration timeout) {
|
||||
return mReadHead.poll(timeout.toMillis(), newRole -> (roles.contains(newRole)));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue