Refactor tethering utility methods
This is no-op refactoring to extract tethering utility methods
to a standalone file, and split setup and clean up process
to allow new test cases can perform custom verifications.
Also, this CL makes connectToWifi returns NetworkHandle for later use.
Test: m connectivity_multi_devices_snippet && \
atest CtsConnectivityMultiDevicesTestCases:ConnectivityMultiDevicesTest
Bug: 335368434
Change-Id: Ib0df28107fd09b573db1e51ff624d0f027bda23d
diff --git a/tests/cts/multidevices/tether_utils.py b/tests/cts/multidevices/tether_utils.py
new file mode 100644
index 0000000..a2d703c
--- /dev/null
+++ b/tests/cts/multidevices/tether_utils.py
@@ -0,0 +1,103 @@
+# 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.
+#
+# 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.
+
+import base64
+import uuid
+
+from mobly import asserts
+from mobly.controllers import android_device
+
+
+class UpstreamType:
+ CELLULAR = 1
+ WIFI = 2
+
+
+def generate_uuid32_base64() -> str:
+ """Generates a UUID32 and encodes it in Base64.
+
+ Returns:
+ str: The Base64-encoded UUID32 string. Which is 22 characters.
+ """
+ # Strip padding characters to make it safer for hotspot name length limit.
+ return base64.b64encode(uuid.uuid1().bytes).decode("utf-8").strip("=")
+
+
+def setup_hotspot_and_client_for_upstream_type(
+ server_device: android_device,
+ client_device: android_device,
+ upstream_type: UpstreamType,
+) -> (str, int):
+ """Setup the hotspot with a connected client with the specified upstream type.
+
+ This creates a hotspot, make the client connect
+ to it, and verify the packet is forwarded by the hotspot.
+ And returns interface name of both if successful.
+ """
+ server = server_device.connectivity_multi_devices_snippet
+ client = client_device.connectivity_multi_devices_snippet
+
+ # Assert pre-conditions specific to each upstream type.
+ asserts.skip_if(not client.hasWifiFeature(), "Client requires Wifi feature")
+ asserts.skip_if(
+ not server.hasHotspotFeature(), "Server requires hotspot feature"
+ )
+ if upstream_type == UpstreamType.CELLULAR:
+ asserts.skip_if(
+ not server.hasTelephonyFeature(), "Server requires Telephony feature"
+ )
+ server.requestCellularAndEnsureDefault()
+ elif upstream_type == UpstreamType.WIFI:
+ asserts.skip_if(
+ not server.isStaApConcurrencySupported(),
+ "Server requires Wifi AP + STA concurrency",
+ )
+ server.ensureWifiIsDefault()
+ else:
+ raise ValueError(f"Invalid upstream type: {upstream_type}")
+
+ # Generate ssid/passphrase with random characters to make sure nearby devices won't
+ # connect unexpectedly. Note that total length of ssid cannot go over 32.
+ test_ssid = "HOTSPOT-" + generate_uuid32_base64()
+ test_passphrase = generate_uuid32_base64()
+
+ # Create a hotspot with fixed SSID and password.
+ hotspot_interface = server.startHotspot(test_ssid, test_passphrase)
+
+ # Make the client connects to the hotspot.
+ client_network = client.connectToWifi(test_ssid, test_passphrase)
+
+ return hotspot_interface, client_network
+
+
+def cleanup_tethering_for_upstream_type(
+ server_device: android_device, upstream_type: UpstreamType
+) -> None:
+ server = server_device.connectivity_multi_devices_snippet
+ if upstream_type == UpstreamType.CELLULAR:
+ server.unrequestCellular()
+ # Teardown the hotspot.
+ server.stopAllTethering()