| #!/usr/bin/env python3 |
| # |
| # Copyright 2019 - 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 time |
| |
| from acts import base_test |
| from acts import asserts |
| from acts.controllers.rohdeschwarz_lib import contest |
| from acts_contrib.test_utils.tel import tel_test_utils |
| from acts.metrics.loggers import blackbox |
| |
| import json |
| |
| |
| class AGNSSPerformanceTest(base_test.BaseTestClass): |
| |
| # User parameters defined in the ACTS config file |
| |
| TESTPLAN_KEY = '{}_testplan' |
| CONTEST_IP_KEY = 'contest_ip' |
| REMOTE_SERVER_PORT_KEY = 'remote_server_port' |
| AUTOMATION_PORT_KEY = 'automation_port' |
| CUSTOM_FILES_KEY = 'custom_files' |
| AUTOMATION_LISTEN_IP = 'automation_listen_ip' |
| FTP_USER_KEY = 'ftp_user' |
| FTP_PASSWORD_KEY = 'ftp_password' |
| |
| def __init__(self, controllers): |
| """ Initializes class attributes. """ |
| |
| super().__init__(controllers) |
| |
| self.dut = None |
| self.contest = None |
| self.testplan = None |
| self.thresholds_file = None |
| |
| self.ttf_metric = blackbox.BlackboxMetricLogger.for_test_case( |
| metric_name='ttf') |
| self.pos_error_metric = blackbox.BlackboxMetricLogger.for_test_case( |
| metric_name='pos_error') |
| self.sensitivity_metric = blackbox.BlackboxMetricLogger.for_test_case( |
| metric_name='sensitivity') |
| |
| def setup_class(self): |
| """ Executed before any test case is started. Initializes the Contest |
| controller and prepares the DUT for testing. """ |
| |
| req_params = [ |
| self.CONTEST_IP_KEY, self.REMOTE_SERVER_PORT_KEY, |
| self.AUTOMATION_PORT_KEY, self.AUTOMATION_LISTEN_IP, |
| self.FTP_USER_KEY, self.FTP_PASSWORD_KEY |
| ] |
| |
| for param in req_params: |
| if param not in self.user_params: |
| self.log.error('Required parameter {} is missing in config ' |
| 'file.'.format(param)) |
| return False |
| |
| contest_ip = self.user_params[self.CONTEST_IP_KEY] |
| remote_port = self.user_params[self.REMOTE_SERVER_PORT_KEY] |
| automation_port = self.user_params[self.AUTOMATION_PORT_KEY] |
| listen_ip = self.user_params[self.AUTOMATION_LISTEN_IP] |
| ftp_user = self.user_params[self.FTP_USER_KEY] |
| ftp_password = self.user_params[self.FTP_PASSWORD_KEY] |
| custom_files = self.user_params.get(self.CUSTOM_FILES_KEY, []) |
| |
| self.dut = self.android_devices[0] |
| |
| self.contest = contest.Contest(logger=self.log, |
| remote_ip=contest_ip, |
| remote_port=remote_port, |
| automation_listen_ip=listen_ip, |
| automation_port=automation_port, |
| dut_on_func=self.set_apm_off, |
| dut_off_func=self.set_apm_on, |
| ftp_usr=ftp_user, |
| ftp_pwd=ftp_password) |
| |
| # Look for the threshold files |
| for file in custom_files: |
| if 'pass_fail_threshold_' + self.dut.model in file: |
| self.thresholds_file = file |
| self.log.debug('Threshold file loaded: ' + file) |
| break |
| else: |
| self.log.warning('No threshold files found in custom files.') |
| |
| def teardown_class(self): |
| """ Executed after completing all selected test cases.""" |
| if self.contest: |
| self.contest.destroy() |
| |
| def setup_test(self): |
| """ Executed before every test case. |
| |
| Returns: |
| False if the setup failed. |
| """ |
| |
| testplan_formatted_key = self.TESTPLAN_KEY.format(self.test_name) |
| |
| if testplan_formatted_key not in self.user_params: |
| self.log.error('Test plan not indicated in the config file. Use ' |
| 'the {} key to set the testplan filename.'.format( |
| testplan_formatted_key)) |
| return False |
| |
| self.testplan = self.user_params[testplan_formatted_key] |
| |
| def agnss_performance_test(self): |
| """ Executes the aGNSS performance test and verifies that the results |
| are within the expected values if a thresholds file is available. |
| |
| The thresholds file is in json format and contains the metrics keys |
| defined in the Contest object with 'min' and 'max' values. """ |
| |
| results = self.contest.execute_testplan(self.testplan) |
| |
| asserts.assert_true( |
| results, 'No results were obtained from the test execution.') |
| |
| if not self.thresholds_file: |
| self.log.info('Skipping pass / fail check because no thresholds ' |
| 'file was provided.') |
| return |
| |
| passed = True |
| |
| with open(self.thresholds_file, 'r') as file: |
| |
| thresholds = json.load(file) |
| |
| for key, val in results.items(): |
| |
| asserts.assert_true( |
| key in thresholds, 'Key {} is missing in ' |
| 'the thresholds file.'.format(key)) |
| |
| # If the result is provided as a dictionary, obtain the value |
| # from the 'avg' key. |
| if isinstance(val, dict): |
| metric = val['avg'] |
| else: |
| metric = val |
| |
| if thresholds[key]['min'] < metric < thresholds[key]['max']: |
| self.log.info('Metric {} = {} is within the expected ' |
| 'values.'.format(key, metric)) |
| else: |
| self.log.error('Metric {} = {} is not within ({}, ' |
| '{}).'.format(key, metric, |
| thresholds[key]['min'], |
| thresholds[key]['max'])) |
| passed = False |
| |
| # Save metric to Blackbox logger |
| if key == contest.Contest.TTFF_KEY: |
| self.ttf_metric.metric_value = metric |
| elif key == contest.Contest.POS_ERROR_KEY: |
| self.pos_error_metric.metric_value = metric |
| elif key == contest.Contest.SENSITIVITY_KEY: |
| self.sensitivity_metric.metric_value = metric |
| |
| asserts.assert_true( |
| passed, 'At least one of the metrics was not ' |
| 'within the expected values.') |
| |
| def set_apm_on(self): |
| """ Wrapper method to turn airplane mode on. |
| |
| This is passed to the Contest object so it can be executed when the |
| automation system requires the DUT to be set to 'off' state. |
| """ |
| |
| tel_test_utils.toggle_airplane_mode(self.log, self.dut, True) |
| |
| def set_apm_off(self): |
| """ Wrapper method to turn airplane mode off. |
| |
| This is passed to the Contest object so it can be executed when the |
| automation system requires the DUT to be set to 'on' state. |
| """ |
| # Wait for the Contest system to initialize the base stations before |
| # actually setting APM off. |
| time.sleep(5) |
| |
| tel_test_utils.toggle_airplane_mode(self.log, self.dut, False) |
| |
| def test_agnss_performance(self): |
| self.agnss_performance_test() |