Move utils to staticlib

This is a no-op refactoring.

Test: m connectivity_multi_devices_snippet && \
      atest CtsConnectivityMultiDevicesTestCases
Bug: 335368434
Change-Id: I415cc22f49c437be6fe8e8ae8822af22ebefe8d1
diff --git a/staticlibs/testutils/Android.bp b/staticlibs/testutils/Android.bp
index 3843b90..8c71a91 100644
--- a/staticlibs/testutils/Android.bp
+++ b/staticlibs/testutils/Android.bp
@@ -86,8 +86,8 @@
 java_test_host {
     name: "net-tests-utils-host-common",
     srcs: [
-        "host/**/*.java",
-        "host/**/*.kt",
+        "host/java/**/*.java",
+        "host/java/**/*.kt",
     ],
     libs: ["tradefed"],
     test_suites: [
@@ -104,3 +104,11 @@
     ],
     data: [":ConnectivityTestPreparer"],
 }
+
+python_library_host {
+    name: "net-tests-utils-host-python-common",
+    srcs: [
+        "host/python/*.py",
+    ],
+    pkg_path: "net_tests_utils",
+}
diff --git a/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt b/staticlibs/testutils/host/java/com/android/testutils/ConnectivityTestTargetPreparer.kt
similarity index 100%
rename from staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt
rename to staticlibs/testutils/host/java/com/android/testutils/ConnectivityTestTargetPreparer.kt
diff --git a/staticlibs/testutils/host/com/android/testutils/DisableConfigSyncTargetPreparer.kt b/staticlibs/testutils/host/java/com/android/testutils/DisableConfigSyncTargetPreparer.kt
similarity index 100%
rename from staticlibs/testutils/host/com/android/testutils/DisableConfigSyncTargetPreparer.kt
rename to staticlibs/testutils/host/java/com/android/testutils/DisableConfigSyncTargetPreparer.kt
diff --git a/staticlibs/testutils/host/python/mdns_utils.py b/staticlibs/testutils/host/python/mdns_utils.py
new file mode 100644
index 0000000..ec1fea0
--- /dev/null
+++ b/staticlibs/testutils/host/python/mdns_utils.py
@@ -0,0 +1,42 @@
+#  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.
+
+from mobly.controllers import android_device
+
+
+def register_mdns_service_and_discover_resolve(
+    advertising_device: android_device, discovery_device: android_device
+) -> None:
+  """Test mdns advertising, discovery and resolution
+
+  One device registers an mDNS service, and another device discovers and
+  resolves that service.
+  """
+  advertising = advertising_device.connectivity_multi_devices_snippet
+  discovery = discovery_device.connectivity_multi_devices_snippet
+
+  # Register a mDns service
+  advertising.registerMDnsService()
+
+  # Ensure the discovery and resolution of the mDNS service
+  discovery.ensureMDnsServiceDiscoveryAndResolution()
+
+
+def cleanup_mdns_service(
+    advertising_device: android_device, discovery_device: android_device
+) -> None:
+  # Unregister the mDns service
+  advertising_device.connectivity_multi_devices_snippet.unregisterMDnsService()
+  # Stop discovery
+  discovery_device.connectivity_multi_devices_snippet.stopMDnsServiceDiscovery()
diff --git a/staticlibs/testutils/host/python/tether_utils.py b/staticlibs/testutils/host/python/tether_utils.py
new file mode 100644
index 0000000..702b596
--- /dev/null
+++ b/staticlibs/testutils/host/python/tether_utils.py
@@ -0,0 +1,110 @@
+#  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.
+
+import base64
+import uuid
+
+from mobly import asserts
+from mobly.controllers import android_device
+
+
+class UpstreamType:
+  NONE = 0
+  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 assume_hotspot_test_preconditions(
+    server_device: android_device,
+    client_device: android_device,
+    upstream_type: UpstreamType,
+) -> None:
+  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"
+    )
+  elif upstream_type == UpstreamType.WIFI:
+    asserts.skip_if(
+        not server.isStaApConcurrencySupported(),
+        "Server requires Wifi AP + STA concurrency",
+    )
+  elif upstream_type == UpstreamType.NONE:
+    pass
+  else:
+    raise ValueError(f"Invalid upstream type: {upstream_type}")
+
+
+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
+
+  if upstream_type == UpstreamType.CELLULAR:
+    server.requestCellularAndEnsureDefault()
+  elif upstream_type == UpstreamType.WIFI:
+    server.ensureWifiIsDefault()
+  elif upstream_type == UpstreamType.NONE:
+    pass
+  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.unregisterAll()
+  # Teardown the hotspot.
+  server.stopAllTethering()