[OTA tests] Add OTA tests for wifi hotspot and core networking features

CHERRY PICKED FROM AOSP

Bug: 109876567
Test: Verified
Change-Id: I6618ea8a734d64feb1128784f70e0a68394dacec
Merged-In: Idb1435b9b62dad16356e2e8bb108e38ab6506cd0
diff --git a/acts/framework/acts/test_utils/net/net_test_utils.py b/acts/framework/acts/test_utils/net/net_test_utils.py
new file mode 100644
index 0000000..c7e55d3
--- /dev/null
+++ b/acts/framework/acts/test_utils/net/net_test_utils.py
@@ -0,0 +1,211 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 Google, Inc.
+#
+#   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 acts import asserts
+from acts.test_utils.net import connectivity_const as cconst
+from acts.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
+from acts.test_utils.tel.tel_test_utils import verify_http_connection
+from acts.test_utils.wifi import wifi_test_utils as wutils
+
+import os
+import re
+import time
+import urllib.request
+
+VPN_CONST = cconst.VpnProfile
+VPN_TYPE = cconst.VpnProfileType
+VPN_PARAMS = cconst.VpnReqParams
+VPN_PING_ADDR = "10.10.10.1"
+
+def verify_lte_data_and_tethering_supported(ad):
+    """Verify if LTE data is enabled and tethering supported"""
+    wutils.wifi_toggle_state(ad, False)
+    ad.droid.telephonyToggleDataConnection(True)
+    wait_for_cell_data_connection(ad.log, ad, True)
+    asserts.assert_true(
+        verify_http_connection(ad.log, ad),
+        "HTTP verification failed on cell data connection")
+    asserts.assert_true(
+        ad.droid.connectivityIsTetheringSupported(),
+        "Tethering is not supported for the provider")
+    wutils.wifi_toggle_state(ad, True)
+
+def set_chrome_browser_permissions(ad):
+    """Set chrome browser start with no-first-run verification.
+    Give permission to read from and write to storage
+    """
+    commands = ["pm grant com.android.chrome "
+                "android.permission.READ_EXTERNAL_STORAGE",
+                "pm grant com.android.chrome "
+                "android.permission.WRITE_EXTERNAL_STORAGE",
+                "rm /data/local/chrome-command-line",
+                "am set-debug-app --persistent com.android.chrome",
+                'echo "chrome --no-default-browser-check --no-first-run '
+                '--disable-fre" > /data/local/tmp/chrome-command-line']
+    for cmd in commands:
+        try:
+            ad.adb.shell(cmd)
+        except adb.AdbError:
+            self.log.warn("adb command %s failed on %s" % (cmd, ad.serial))
+
+def verify_ping_to_vpn_ip(ad):
+    """ Verify if IP behind VPN server is pingable.
+    Ping should pass, if VPN is connected.
+    Ping should fail, if VPN is disconnected.
+
+    Args:
+      ad: android device object
+    """
+    ping_result = None
+    pkt_loss = "100% packet loss"
+    try:
+        ping_result = ad.adb.shell("ping -c 3 -W 2 %s" % VPN_PING_ADDR)
+    except adb.AdbError:
+        pass
+    return ping_result and pkt_loss not in ping_result
+
+def legacy_vpn_connection_test_logic(ad, vpn_profile):
+    """ Test logic for each legacy VPN connection
+
+    Steps:
+      1. Generate profile for the VPN type
+      2. Establish connection to the server
+      3. Verify that connection is established using LegacyVpnInfo
+      4. Verify the connection by pinging the IP behind VPN
+      5. Stop the VPN connection
+      6. Check the connection status
+      7. Verify that ping to IP behind VPN fails
+
+    Args:
+      1. ad: Android device object
+      2. VpnProfileType (1 of the 6 types supported by Android)
+    """
+    # Wait for sometime so that VPN server flushes all interfaces and
+    # connections after graceful termination
+    time.sleep(10)
+
+    ad.adb.shell("ip xfrm state flush")
+    ad.log.info("Connecting to: %s", vpn_profile)
+    ad.droid.vpnStartLegacyVpn(vpn_profile)
+    time.sleep(cconst.VPN_TIMEOUT)
+
+    connected_vpn_info = ad.droid.vpnGetLegacyVpnInfo()
+    asserts.assert_equal(connected_vpn_info["state"],
+                         cconst.VPN_STATE_CONNECTED,
+                         "Unable to establish VPN connection for %s"
+                         % vpn_profile)
+
+    ping_result = verify_ping_to_vpn_ip(ad)
+    ip_xfrm_state = ad.adb.shell("ip xfrm state")
+    match_obj = re.search(r'hmac(.*)', "%s" % ip_xfrm_state)
+    if match_obj:
+        ip_xfrm_state = format(match_obj.group(0)).split()
+        ad.log.info("HMAC for ESP is %s " % ip_xfrm_state[0])
+
+    ad.droid.vpnStopLegacyVpn()
+    asserts.assert_true(ping_result,
+                        "Ping to the internal IP failed. "
+                        "Expected to pass as VPN is connected")
+
+    connected_vpn_info = ad.droid.vpnGetLegacyVpnInfo()
+    asserts.assert_true(not connected_vpn_info,
+                        "Unable to terminate VPN connection for %s"
+                        % vpn_profile)
+
+def download_load_certs(ad, vpn_params, vpn_type, vpn_server_addr,
+                        ipsec_server_type, log_path):
+    """ Download the certificates from VPN server and push to sdcard of DUT
+
+    Args:
+      ad: android device object
+      vpn_params: vpn params from config file
+      vpn_type: 1 of the 6 VPN types
+      vpn_server_addr: server addr to connect to
+      ipsec_server_type: ipsec version - strongswan or openswan
+      log_path: log path to download cert
+
+    Returns:
+      Client cert file name on DUT's sdcard
+    """
+    url = "http://%s%s%s" % (vpn_server_addr,
+                             vpn_params['cert_path_vpnserver'],
+                             vpn_params['client_pkcs_file_name'])
+    local_cert_name = "%s_%s_%s" % (vpn_type.name,
+                                    ipsec_server_type,
+                                    vpn_params['client_pkcs_file_name'])
+    ad.adb.push("%s sdcard/" % local_cert_name)
+    return local_cert_name
+
+    local_file_path = os.path.join(log_path, local_cert_name)
+    try:
+        ret = urllib.request.urlopen(url)
+        with open(local_file_path, "wb") as f:
+            f.write(ret.read())
+    except:
+        asserts.fail("Unable to download certificate from the server")
+
+    f.close()
+    ad.adb.push("%s sdcard/" % local_file_path)
+    return local_cert_name
+
+def generate_legacy_vpn_profile(ad,
+                                vpn_params,
+                                vpn_type,
+                                vpn_server_addr,
+                                ipsec_server_type,
+                                log_path):
+    """ Generate legacy VPN profile for a VPN
+
+    Args:
+      ad: android device object
+      vpn_params: vpn params from config file
+      vpn_type: 1 of the 6 VPN types
+      vpn_server_addr: server addr to connect to
+      ipsec_server_type: ipsec version - strongswan or openswan
+      log_path: log path to download cert
+
+    Returns:
+      Vpn profile
+    """
+    vpn_profile = {VPN_CONST.USER: vpn_params['vpn_username'],
+                   VPN_CONST.PWD: vpn_params['vpn_password'],
+                   VPN_CONST.TYPE: vpn_type.value,
+                   VPN_CONST.SERVER: vpn_server_addr,}
+    vpn_profile[VPN_CONST.NAME] = "test_%s_%s" % (vpn_type.name,
+                                                  ipsec_server_type)
+    if vpn_type.name == "PPTP":
+        vpn_profile[VPN_CONST.NAME] = "test_%s" % vpn_type.name
+
+    psk_set = set(["L2TP_IPSEC_PSK", "IPSEC_XAUTH_PSK"])
+    rsa_set = set(["L2TP_IPSEC_RSA", "IPSEC_XAUTH_RSA", "IPSEC_HYBRID_RSA"])
+
+    if vpn_type.name in psk_set:
+        vpn_profile[VPN_CONST.IPSEC_SECRET] = vpn_params['psk_secret']
+    elif vpn_type.name in rsa_set:
+        cert_name = download_load_certs(ad,
+                                        vpn_params,
+                                        vpn_type,
+                                        vpn_server_addr,
+                                        ipsec_server_type,
+                                        log_path)
+        vpn_profile[VPN_CONST.IPSEC_USER_CERT] = cert_name.split('.')[0]
+        vpn_profile[VPN_CONST.IPSEC_CA_CERT] = cert_name.split('.')[0]
+        ad.droid.installCertificate(vpn_profile, cert_name,
+                                    vpn_params['cert_password'])
+    else:
+        vpn_profile[VPN_CONST.MPPE] = "mppe"
+
+    return vpn_profile
diff --git a/acts/framework/acts/test_utils/wifi/wifi_test_utils.py b/acts/framework/acts/test_utils/wifi/wifi_test_utils.py
index e5e9e5a..fca5085 100755
--- a/acts/framework/acts/test_utils/wifi/wifi_test_utils.py
+++ b/acts/framework/acts/test_utils/wifi/wifi_test_utils.py
@@ -745,6 +745,32 @@
     finally:
         ad.droid.wifiStopTrackingTetherStateChange()
 
+def save_wifi_soft_ap_config(ad, wifi_config, band=None, hidden=None):
+    """ Save a soft ap configuration """
+    if band:
+        wifi_config[WifiEnums.APBAND_KEY] = band
+    if hidden:
+        wifi_config[WifiEnums.HIDDEN_KEY] = hidden
+    asserts.assert_true(ad.droid.wifiSetWifiApConfiguration(wifi_config),
+                        "Failed to set WifiAp Configuration")
+
+    wifi_ap = ad.droid.wifiGetApConfiguration()
+    asserts.assert_true(
+        wifi_ap[WifiEnums.SSID_KEY] == wifi_config[WifiEnums.SSID_KEY],
+        "Hotspot SSID doesn't match with expected SSID")
+
+def start_wifi_tethering_saved_config(ad):
+    """ Turn on wifi hotspot with a config that is already saved """
+    ad.droid.wifiStartTrackingTetherStateChange()
+    ad.droid.connectivityStartTethering(tel_defines.TETHERING_WIFI, False)
+    try:
+        ad.ed.pop_event("ConnectivityManagerOnTetheringStarted")
+        ad.ed.wait_for_event("TetherStateChanged",
+                             lambda x: x["data"]["ACTIVE_TETHER"], 30)
+    except:
+        asserts.fail("Didn't receive wifi tethering starting confirmation")
+    finally:
+        ad.droid.wifiStopTrackingTetherStateChange()
 
 def stop_wifi_tethering(ad):
     """Stops wifi tethering on an android_device.
diff --git a/acts/tests/google/net/CoreNetworkingOTATest.py b/acts/tests/google/net/CoreNetworkingOTATest.py
new file mode 100755
index 0000000..2444971
--- /dev/null
+++ b/acts/tests/google/net/CoreNetworkingOTATest.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 os
+import re
+import time
+import urllib.request
+
+import acts.base_test
+import acts.signals as signals
+
+from acts import asserts
+from acts.base_test import BaseTestClass
+from acts.libs.ota import ota_updater
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.net import connectivity_const as cconst
+
+import acts.test_utils.net.net_test_utils as nutils
+import acts.test_utils.wifi.wifi_test_utils as wutils
+
+VPN_CONST = cconst.VpnProfile
+VPN_TYPE = cconst.VpnProfileType
+VPN_PARAMS = cconst.VpnReqParams
+
+
+class CoreNetworkingOTATest(BaseTestClass):
+    """Core networking auto update tests"""
+
+    def setup_class(self):
+        super(CoreNetworkingOTATest, self).setup_class()
+        ota_updater.initialize(self.user_params, self.android_devices)
+
+        self.dut = self.android_devices[0]
+        req_params = dir(VPN_PARAMS)
+        req_params = [x for x in req_params if not x.startswith('__')]
+        req_params.extend(["download_file", "file_size"])
+        self.unpack_userparams(req_params)
+
+        vpn_params = {'vpn_username': self.vpn_username,
+                      'vpn_password': self.vpn_password,
+                      'psk_secret': self.psk_secret,
+                      'client_pkcs_file_name': self.client_pkcs_file_name,
+                      'cert_path_vpnserver': self.cert_path_vpnserver,
+                      'cert_password': self.cert_password}
+
+        # generate legacy vpn profiles
+        wutils.wifi_connect(self.dut, self.wifi_network)
+        self.xauth_rsa = nutils.generate_legacy_vpn_profile(
+            self.dut, vpn_params,
+            VPN_TYPE.IPSEC_XAUTH_RSA,
+            self.vpn_server_addresses[VPN_TYPE.IPSEC_XAUTH_RSA.name][0],
+            self.ipsec_server_type[0], self.log_path)
+        self.l2tp_rsa = nutils.generate_legacy_vpn_profile(
+            self.dut, vpn_params,
+            VPN_TYPE.L2TP_IPSEC_RSA,
+            self.vpn_server_addresses[VPN_TYPE.L2TP_IPSEC_RSA.name][0],
+            self.ipsec_server_type[0], self.log_path)
+        self.hybrid_rsa = nutils.generate_legacy_vpn_profile(
+            self.dut, vpn_params,
+            VPN_TYPE.IPSEC_HYBRID_RSA,
+            self.vpn_server_addresses[VPN_TYPE.IPSEC_HYBRID_RSA.name][0],
+            self.ipsec_server_type[0], self.log_path)
+        self.vpn_profiles = [self.l2tp_rsa, self.hybrid_rsa, self.xauth_rsa]
+
+        # verify legacy vpn
+        for prof in self.vpn_profiles:
+            nutils.legacy_vpn_connection_test_logic(self.dut, prof)
+
+        # Run OTA below, if ota fails then abort all tests.
+        try:
+          for ad in self.android_devices:
+              ota_updater.update(ad)
+        except Exception as err:
+            raise signals.TestSkipClass(
+                "Failed up apply OTA update. Aborting tests")
+
+    def on_fail(self, test_name, begin_time):
+        self.dut.take_bug_report(test_name, begin_time)
+
+    """Tests"""
+
+    def test_legacy_vpn_ota_xauth_rsa(self):
+        nutils.legacy_vpn_connection_test_logic(self.dut, self.xauth_rsa)
+
+    def test_legacy_vpn_ota_l2tp_rsa(self):
+        nutils.legacy_vpn_connection_test_logic(self.dut, self.l2tp_rsa)
+
+    def test_legacy_vpn_ota_hybrid_rsa(self):
+        nutils.legacy_vpn_connection_test_logic(self.dut, self.hybrid_rsa)
diff --git a/acts/tests/google/wifi/WifiTethering2GOpenOTATest.py b/acts/tests/google/wifi/WifiTethering2GOpenOTATest.py
new file mode 100755
index 0000000..68f0399
--- /dev/null
+++ b/acts/tests/google/wifi/WifiTethering2GOpenOTATest.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 acts.signals as signals
+
+from acts import asserts
+from acts.base_test import BaseTestClass
+from acts.libs.ota import ota_updater
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
+
+import acts.test_utils.net.net_test_utils as nutils
+import acts.test_utils.wifi.wifi_test_utils as wutils
+
+
+class WifiTethering2GOpenOTATest(BaseTestClass):
+    """Wifi Tethering 2G Open OTA tests"""
+
+    def setup_class(self):
+
+        super(WifiTethering2GOpenOTATest, self).setup_class()
+        ota_updater.initialize(self.user_params, self.android_devices)
+
+        self.hotspot_device = self.android_devices[0]
+        self.tethered_device = self.android_devices[1]
+        req_params = ("wifi_hotspot_open", )
+        self.unpack_userparams(req_params)
+
+        # verify hotspot device has lte data and supports tethering
+        nutils.verify_lte_data_and_tethering_supported(self.hotspot_device)
+
+        # Save a wifi soft ap configuration and verify that it works
+        wutils.save_wifi_soft_ap_config(self.hotspot_device,
+                                        self.wifi_hotspot_open,
+                                        WIFI_CONFIG_APBAND_2G)
+        self._verify_wifi_tethering()
+
+        # Run OTA below, if ota fails then abort all tests.
+        try:
+          ota_updater.update(self.hotspot_device)
+        except Exception as err:
+            raise signals.TestSkipClass(
+                "Failed up apply OTA update. Aborting tests")
+
+    def on_fail(self, test_name, begin_time):
+        for ad in self.android_devices:
+            ad.take_bug_report(test_name, begin_time)
+
+    def teardown_class(self):
+        wutils.wifi_toggle_state(self.hotspot_device, True)
+
+    """Helper Functions"""
+
+    def _verify_wifi_tethering(self):
+        """Verify wifi tethering"""
+        wutils.start_wifi_tethering_saved_config(self.hotspot_device)
+        wutils.wifi_connect(self.tethered_device, self.wifi_hotspot_open)
+        # (TODO: @gmoturu) Change to stop_wifi_tethering. See b/109876061
+        wutils.wifi_toggle_state(self.hotspot_device, True)
+
+    """Tests"""
+
+    def test_wifi_tethering_ota_2g_open(self):
+        self._verify_wifi_tethering()
diff --git a/acts/tests/google/wifi/WifiTethering2GPskOTATest.py b/acts/tests/google/wifi/WifiTethering2GPskOTATest.py
new file mode 100755
index 0000000..e1904e7
--- /dev/null
+++ b/acts/tests/google/wifi/WifiTethering2GPskOTATest.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 acts.signals as signals
+
+from acts import asserts
+from acts.base_test import BaseTestClass
+from acts.libs.ota import ota_updater
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
+
+import acts.test_utils.net.net_test_utils as nutils
+import acts.test_utils.wifi.wifi_test_utils as wutils
+
+
+class WifiTethering2GPskOTATest(BaseTestClass):
+    """Wifi Tethering 2G Psk OTA tests"""
+
+    def setup_class(self):
+
+        super(WifiTethering2GPskOTATest, self).setup_class()
+        ota_updater.initialize(self.user_params, self.android_devices)
+
+        self.hotspot_device = self.android_devices[0]
+        self.tethered_device = self.android_devices[1]
+        req_params = ("wifi_hotspot_psk", )
+        self.unpack_userparams(req_params)
+
+        # verify hotspot device has lte data and supports tethering
+        nutils.verify_lte_data_and_tethering_supported(self.hotspot_device)
+
+        # Save a wifi soft ap configuration and verify that it works
+        wutils.save_wifi_soft_ap_config(self.hotspot_device,
+                                        self.wifi_hotspot_psk,
+                                        WIFI_CONFIG_APBAND_2G)
+        self._verify_wifi_tethering()
+
+        # Run OTA below, if ota fails then abort all tests.
+        try:
+          ota_updater.update(self.hotspot_device)
+        except Exception as err:
+            raise signals.TestSkipClass(
+                "Failed up apply OTA update. Aborting tests")
+
+    def on_fail(self, test_name, begin_time):
+        for ad in self.android_devices:
+            ad.take_bug_report(test_name, begin_time)
+
+    def teardown_class(self):
+        wutils.wifi_toggle_state(self.hotspot_device, True)
+
+    """Helper Functions"""
+
+    def _verify_wifi_tethering(self):
+        """Verify wifi tethering"""
+        wutils.start_wifi_tethering_saved_config(self.hotspot_device)
+        wutils.wifi_connect(self.tethered_device, self.wifi_hotspot_psk)
+        # (TODO: @gmoturu) Change to stop_wifi_tethering. See b/109876061
+        wutils.wifi_toggle_state(self.hotspot_device, True)
+
+    """Tests"""
+
+    def test_wifi_tethering_ota_2g_psk(self):
+        self._verify_wifi_tethering()
diff --git a/acts/tests/google/wifi/WifiTethering5GOpenOTATest.py b/acts/tests/google/wifi/WifiTethering5GOpenOTATest.py
new file mode 100755
index 0000000..6084500
--- /dev/null
+++ b/acts/tests/google/wifi/WifiTethering5GOpenOTATest.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 acts.signals as signals
+
+from acts import asserts
+from acts.base_test import BaseTestClass
+from acts.libs.ota import ota_updater
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+
+import acts.test_utils.net.net_test_utils as nutils
+import acts.test_utils.wifi.wifi_test_utils as wutils
+
+
+class WifiTethering5GOpenOTATest(BaseTestClass):
+    """Wifi Tethering 5G Open OTA tests"""
+
+    def setup_class(self):
+
+        super(WifiTethering5GOpenOTATest, self).setup_class()
+        ota_updater.initialize(self.user_params, self.android_devices)
+
+        self.hotspot_device = self.android_devices[0]
+        self.tethered_device = self.android_devices[1]
+        req_params = ("wifi_hotspot_open", )
+        self.unpack_userparams(req_params)
+
+        # verify hotspot device has lte data and supports tethering
+        nutils.verify_lte_data_and_tethering_supported(self.hotspot_device)
+
+        # Save a wifi soft ap configuration and verify that it works
+        wutils.save_wifi_soft_ap_config(self.hotspot_device,
+                                        self.wifi_hotspot_open,
+                                        WIFI_CONFIG_APBAND_5G)
+        self._verify_wifi_tethering()
+
+        # Run OTA below, if ota fails then abort all tests.
+        try:
+          ota_updater.update(self.hotspot_device)
+        except Exception as err:
+            raise signals.TestSkipClass(
+                "Failed up apply OTA update. Aborting tests")
+
+    def on_fail(self, test_name, begin_time):
+        for ad in self.android_devices:
+            ad.take_bug_report(test_name, begin_time)
+
+    def teardown_class(self):
+        wutils.wifi_toggle_state(self.hotspot_device, True)
+
+    """Helper Functions"""
+
+    def _verify_wifi_tethering(self):
+        """Verify wifi tethering"""
+        wutils.start_wifi_tethering_saved_config(self.hotspot_device)
+        wutils.wifi_connect(self.tethered_device, self.wifi_hotspot_open)
+        # (TODO: @gmoturu) Change to stop_wifi_tethering. See b/109876061
+        wutils.wifi_toggle_state(self.hotspot_device, True)
+
+    """Tests"""
+
+    def test_wifi_tethering_ota_5g_open(self):
+        self._verify_wifi_tethering()
diff --git a/acts/tests/google/wifi/WifiTethering5GPskOTATest.py b/acts/tests/google/wifi/WifiTethering5GPskOTATest.py
new file mode 100755
index 0000000..5cb532a
--- /dev/null
+++ b/acts/tests/google/wifi/WifiTethering5GPskOTATest.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 acts.signals as signals
+
+from acts import asserts
+from acts.base_test import BaseTestClass
+from acts.libs.ota import ota_updater
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+
+import acts.test_utils.net.net_test_utils as nutils
+import acts.test_utils.wifi.wifi_test_utils as wutils
+
+
+class WifiTethering5GPskOTATest(BaseTestClass):
+    """Wifi Tethering 5G Psk OTA tests"""
+
+    def setup_class(self):
+
+        super(WifiTethering5GPskOTATest, self).setup_class()
+        ota_updater.initialize(self.user_params, self.android_devices)
+
+        self.hotspot_device = self.android_devices[0]
+        self.tethered_device = self.android_devices[1]
+        req_params = ("wifi_hotspot_psk", )
+        self.unpack_userparams(req_params)
+
+        # verify hotspot device has lte data and supports tethering
+        nutils.verify_lte_data_and_tethering_supported(self.hotspot_device)
+
+        # Save a wifi soft ap configuration and verify that it works
+        wutils.save_wifi_soft_ap_config(self.hotspot_device,
+                                        self.wifi_hotspot_psk,
+                                        WIFI_CONFIG_APBAND_5G)
+        self._verify_wifi_tethering()
+
+        # Run OTA below, if ota fails then abort all tests.
+        try:
+          ota_updater.update(self.hotspot_device)
+        except Exception as err:
+            raise signals.TestSkipClass(
+                "Failed up apply OTA update. Aborting tests")
+
+    def on_fail(self, test_name, begin_time):
+        for ad in self.android_devices:
+            ad.take_bug_report(test_name, begin_time)
+
+    def teardown_class(self):
+        wutils.wifi_toggle_state(self.hotspot_device, True)
+
+    """Helper Functions"""
+
+    def _verify_wifi_tethering(self):
+        """Verify wifi tethering"""
+        wutils.start_wifi_tethering_saved_config(self.hotspot_device)
+        wutils.wifi_connect(self.tethered_device, self.wifi_hotspot_psk)
+        # (TODO: @gmoturu) Change to stop_wifi_tethering. See b/109876061
+        wutils.wifi_toggle_state(self.hotspot_device, True)
+
+    """Tests"""
+
+    def test_wifi_tethering_ota_5g_psk(self):
+        self._verify_wifi_tethering()