#!/usr/bin/env python3 # # Copyright 2020 - 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 time import glob import errno from acts import utils from acts import asserts from acts import signals from acts import base_test from pandas import DataFrame from collections import namedtuple from acts.controllers.spectracom_lib import gsg6 from acts.test_utils.gnss import dut_log_test_utils as diaglog from acts_contrib.test_utils.gnss import gnss_test_utils as gutils from acts_contrib.test_utils.gnss import gnss_testlog_utils as glogutils DEVICE_GPSLOG_FOLDER = '/sdcard/Android/data/com.android.gpstool/files/' GPS_PKG_NAME = 'com.android.gpstool' class LabTtffTest(base_test.BaseTestClass): """ LAB TTFF Tests""" GTW_GPSTOOL_APP = 'gtw_gpstool_apk' SPECTRACOM_IP_KEY = 'spectracom_ip' SPECTRACOM_PORT_KEY = 'spectracom_port' SPECTRACOM_FILES_KEY = 'spectracom_files' SPECTRACOM_POWER_KEY = 'spectracom_power_level' SPIRENT_IP_KEY = 'spirent_ip' SPIRENT_SCENARIO = 'sprient_scenario' CUSTOM_FILES_KEY = 'custom_files' CSTTFF_CRITERIA = 'cs_criteria' HSTTFF_CRITERIA = 'hs_criteria' WSTTFF_CRITERIA = 'ws_criteria' CSTTFF_PECRITERIA = 'cs_ttff_pecriteria' HSTTFF_PECRITERIA = 'hs_ttff_pecriteria' WSTTFF_PECRITERIA = 'ws_ttff_pecriteria' TTFF_ITERATION = 'ttff_iteration' SIMULATOR_LOCATION = 'simulator_location' DIAG_OPTION = 'diag_option' def __init__(self, controllers): """ Initializes class attributes. """ super().__init__(controllers) self.dut = None self.spectracom = None def setup_class(self): super().setup_class() req_params = [ self.SPECTRACOM_IP_KEY, self.SPECTRACOM_PORT_KEY, self.SPECTRACOM_FILES_KEY, self.SPECTRACOM_POWER_KEY, self.CSTTFF_CRITERIA, self.HSTTFF_CRITERIA, self.WSTTFF_CRITERIA, self.TTFF_ITERATION, self.SIMULATOR_LOCATION, self.DIAG_OPTION ] for param in req_params: if param not in self.user_params: self.log.error('Required parameter {} is missing in config ' 'file.'.format(param)) raise signals.TestAbortClass( 'Required parameter {} is missing in config ' 'file.'.format(param)) self.dut = self.android_devices[0] self.spectracom_ip = self.user_params[self.SPECTRACOM_IP_KEY] self.spectracom_port = self.user_params[self.SPECTRACOM_PORT_KEY] self.spectracom_file = self.user_params[self.SPECTRACOM_FILES_KEY] self.spectracom_power = self.user_params[self.SPECTRACOM_POWER_KEY] self.gtw_gpstool_app = self.user_params[self.GTW_GPSTOOL_APP] custom_files = self.user_params.get(self.CUSTOM_FILES_KEY, []) self.cs_ttff_criteria = self.user_params.get(self.CSTTFF_CRITERIA, []) self.hs_ttff_criteria = self.user_params.get(self.HSTTFF_CRITERIA, []) self.ws_ttff_criteria = self.user_params.get(self.WSTTFF_CRITERIA, []) self.cs_ttff_pecriteria = self.user_params.get( self.CSTTFF_PECRITERIA, []) self.hs_ttff_pecriteria = self.user_params.get( self.HSTTFF_PECRITERIA, []) self.ws_ttff_pecriteria = self.user_params.get( self.WSTTFF_PECRITERIA, []) self.ttff_iteration = self.user_params.get(self.TTFF_ITERATION, []) self.simulator_location = self.user_params.get( self.SIMULATOR_LOCATION, []) self.diag_option = self.user_params.get(self.DIAG_OPTION, []) test_type = namedtuple('Type', ['command', 'criteria']) self.test_types = { 'cs': test_type('Cold Start', self.cs_ttff_criteria), 'ws': test_type('Warm Start', self.ws_ttff_criteria), 'hs': test_type('Hot Start', self.hs_ttff_criteria) } # Unpack the rockbottom script or fail class setup if it can't be found for file in custom_files: if 'rockbottom_' + self.dut.model in file: self.rockbottom_script = file break else: raise signals.TestAbortClass( 'Required rockbottom script is missing.') def setup_test(self): self.clear_gps_log() self.spectracom = gsg6.GSG6(self.spectracom_ip, self.spectracom_port) self.spectracom.stop_scenario() time.sleep(10) self.spectracom.close() self.dut_rockbottom() utils.set_location_service(self.dut, True) gutils.reinstall_package_apk(self.dut, GPS_PKG_NAME, self.gtw_gpstool_app) self.spectracom = gsg6.GSG6(self.spectracom_ip, self.spectracom_port) self.spectracom.connect() def dut_rockbottom(self): """ Set the dut to rockbottom state """ # The rockbottom script might include a device reboot, so it is # necessary to stop SL4A during its execution. self.dut.stop_services() self.log.info('Executing rockbottom script for ' + self.dut.model) os.chmod(self.rockbottom_script, 0o777) os.system('{} {}'.format(self.rockbottom_script, self.dut.serial)) # Make sure the DUT is in root mode after coming back self.dut.root_adb() # Restart SL4A self.dut.start_services() def teardown_class(self): """ Executed after completing all selected test cases.""" self.clear_gps_log() if self.spectracom: self.spectracom.stop_scenario() time.sleep(10) self.spectracom.close() def start_and_set_spectracom_power(self): """ Start spectracom secnario and set power level. """ self.spectracom.start_scenario(self.spectracom_file) time.sleep(25) self.spectracom.set_power(self.spectracom_power) def get_and_verify_ttff(self, mode): """Retrieve ttff with designate mode. Args: mode: A string for identify gnss test mode. """ if mode not in self.test_types: raise signals.TestError('Unrecognized mode %s' % mode) test_type = self.test_types.get(mode) gutils.process_gnss_by_gtw_gpstool(self.dut, self.test_types['cs'].criteria) begin_time = gutils.get_current_epoch_time() gutils.start_ttff_by_gtw_gpstool( self.dut, ttff_mode=mode, iteration=self.ttff_iteration, aid_data=True) ttff_data = gutils.process_ttff_by_gtw_gpstool(self.dut, begin_time, self.simulator_location) gps_log_path = os.path.join(self.log_path, 'GPSLogs') self.dut.adb.pull("{} {}".format(DEVICE_GPSLOG_FOLDER, gps_log_path)) gps_api_log = glob.glob(gps_log_path + '/GPS_API_*.txt') ttff_loop_log = glob.glob(gps_log_path + '/GPS_{}_*.txt'. format(mode.upper())) if not gps_api_log and ttff_loop_log: raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), gps_log_path) df = DataFrame(glogutils.parse_gpstool_ttfflog_to_df(gps_api_log[0])) ttff_dict = {} for i in ttff_data: d = ttff_data[i]._asdict() ttff_dict[i] = dict(d) ttff_time =[] ttff_pe = [] for i, k in ttff_dict.items(): ttff_time.append(ttff_dict[i]['ttff_time']) ttff_pe.append(ttff_dict[i]['ttff_pe']) df['ttff_time'] = ttff_time df['ttff_pe'] = ttff_pe df.to_json(gps_log_path + '/gps_log.json', orient='table') result = gutils.check_ttff_data( self.dut, ttff_data, ttff_mode=test_type.command, criteria=test_type.criteria) if not result: raise signals.TestFailure('%s TTFF fails to reach ' 'designated criteria' % test_type.command) return ttff_data def verify_pe(self, mode): """ Verify ttff Position Error with designate mode. Args: mode: A string for identify gnss test mode. """ ffpe_type = namedtuple('Type', ['command', 'pecriteria']) ffpe_types = { 'cs': ffpe_type('Cold Start', self.cs_ttff_pecriteria), 'ws': ffpe_type('Warm Start', self.ws_ttff_pecriteria), 'hs': ffpe_type('Hot Start', self.hs_ttff_pecriteria) } if mode not in self.test_types: raise signals.TestError('Unrecognized mode %s' % mode) test_type = self.test_types.get(mode) ttff_data = self.get_and_verify_ttff(mode) result = gutils.check_ttff_pe( self.dut, ttff_data, ttff_mode=test_type.command, pecriteria=test_type.pecriteria ) if not result: raise signals.TestFailure('%s TTFF fails to reach ' 'designated criteria' % test_type.command) return ttff_data def clear_gps_log(self): """ Delete the existing GPS GTW Log from DUT. """ self.dut.adb.shell("rm -rf {}".format(DEVICE_GPSLOG_FOLDER)) def test_gnss_cold_ttff_ffpe(self): self.start_and_set_spectracom_power() if self.diag_option is "QCOM": diaglog.start_diagmdlog_background(self.dut, maskfile=self.maskfile) else: #start_tbdlog() yet to add for Broadcom pass self.verify_pe('cs') diaglog.stop_background_diagmdlog(self.dut, self.qxdm_log_path, keep_logs=False) def test_gnss_warm_ttff_ffpe(self): self.start_and_set_spectracom_power() if self.diag_option is "QCOM": diaglog.start_diagmdlog_background(self.dut, maskfile=self.maskfile) else: #start_tbdlog() yet to add for Broadcom pass self.verify_pe('ws') diaglog.stop_background_diagmdlog(self.dut, self.qxdm_log_path, keep_logs=False) def test_gnss_hot_ttff_ffpe(self): self.start_and_set_spectracom_power() if self.diag_option is "QCOM": diaglog.start_diagmdlog_background(self.dut, maskfile=self.maskfile) else: #start_tbdlog() yet to add for Broadcom pass self.verify_pe('hs') diaglog.stop_background_diagmdlog(self.dut, self.qxdm_log_path, keep_logs=False)