• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#   Copyright 2022 - The Android Open Source Project
2#
3#   Licensed under the Apache License, Version 2.0 (the 'License');
4#   you may not use this file except in compliance with the License.
5#   You may obtain a copy of the License at
6#
7#       http://www.apache.org/licenses/LICENSE-2.0
8#
9#   Unless required by applicable law or agreed to in writing, software
10#   distributed under the License is distributed on an 'AS IS' BASIS,
11#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12#   See the License for the specific language governing permissions and
13#   limitations under the License.
14import os
15import time
16
17from acts import asserts
18import acts_contrib.test_utils.power.cellular.cellular_power_preset_base_test as PB
19
20class PowerTelTrafficPresetTest(PB.PowerCellularPresetLabBaseTest):
21    # command to enable mobile data
22    ADB_CMD_ENABLE_MOBILE_DATA = 'svc data enable'
23
24    # command to start iperf server on UE
25    START_IPERF_SV_UE_CMD = 'nohup > /dev/null 2>&1 sh -c "iperf3 -s -i1 -p5201 > /dev/null  &"'
26
27    # command to start iperf server on UE
28    # (require: 1.path to iperf exe 2.hostname/hostIP)
29    START_IPERF_CLIENT_UE_CMD = 'nohup > /dev/null 2>&1 sh -c "iperf3 -c {iperf_host_ip} -i1 -p5202 -w8m -t2000 -O{second} > /dev/null &"'
30
31    # command to start iperf server on host()
32    START_IPERF_SV_HOST_CMD = '{exe_path}\\iperf3 -s -p5202'
33
34    # command to start iperf client on host
35    # (require: 1.path to iperf exe 2.UE IP)
36    START_IPERF_CLIENT_HOST_CMD = (
37        '{exe_path}\\iperf3 -c {ue_ip} -w16M -t1000 -p5201 -O{second}')
38
39    START_IPERF_CLIENT_HOST_CMD_FR2 = (
40        '{exe_path}\\iperf3 -c {ue_ip} -w16M -t1000 -p5201 -O{second}')
41
42    def __init__(self, controllers):
43        super().__init__(controllers)
44        self.ssh_iperf_client = None
45        self.ssh_iperf_server = None
46        self.iperf_out_err = {}
47
48    def setup_class(self):
49        super().setup_class()
50
51        # Unpack test parameters used in this class
52        self.unpack_userparams(iperf_exe_path=None,
53                               ue_ip=None,
54                               iperf_host_ip=None)
55
56        # Verify required config
57        for param in ('iperf_exe_path', 'ue_ip', 'iperf_host_ip'):
58            if getattr(self, param) is None:
59                raise RuntimeError(
60                    f'Parameter "{param}" is required to run this type of test')
61
62    def setup_test(self):
63        # Call parent method first to setup simulation
64        super().setup_test()
65
66        # get tput configs
67        self.unpack_userparams(abnormal_bandwidth_tolerance=0.1,
68                               bandwidth_tolerance=0.1,
69                               n_second_to_omitted=45)
70        self.expected_downlink_bandwidth = float(self.test_configs[self.test_name]['tput']['downlink'].split()[0])
71        self.expected_uplink_bandwidth = float(self.test_configs[self.test_name]['tput']['uplink'].split()[0])
72
73        # setup ssh client
74        self.ssh_iperf_client = self.cellular_simulator.create_ssh_client()
75        self.ssh_iperf_server = self.cellular_simulator.create_ssh_client()
76
77        self.turn_on_mobile_data()
78
79    def power_tel_traffic_test(self):
80        """Measure power while data is transferring."""
81        # Start data traffic
82        self.start_uplink_process()
83        self.start_downlink_process()
84
85        # Measure power and check against threshold
86        self.collect_power_data_and_validate()
87
88    def _end_iperfs(self):
89        err_message = []
90        # Write iperf log
91        self.ssh_iperf_server.close()
92        uplink_log_name = self.test_name + '_uplink.txt'
93        out, err = self.iperf_out_err[self.ssh_iperf_server]
94        output_content = ''.join(out.readlines())
95        err_content = ''.join(err.readlines())
96        self._write_iperf_log(uplink_log_name, output_content + err_content)
97        if err_content.strip():
98            err_message.append(f'Uplink process fail due to error: {err_content}\n')
99        else:
100            if not self._iperf_log_check(output_content, self.expected_uplink_bandwidth):
101                err_message.append('Bandwidth of uplink process is unstable.')
102
103        self.ssh_iperf_client.close()
104        downlink_log_name = self.test_name + '_downlink.txt'
105        out, err = self.iperf_out_err[self.ssh_iperf_client]
106        output_content = ''.join(out.readlines())
107        err_content = ''.join(err.readlines())
108        self._write_iperf_log(downlink_log_name, output_content + err_content)
109        if err_content.strip():
110            err_message.append(f'Downlink process fail due to error: {err_content}\n')
111        else:
112            if not self._iperf_log_check(output_content, self.expected_downlink_bandwidth):
113                err_message.append('Bandwidth of downlink process is unstable.')
114
115        if err_message:
116            raise RuntimeError('\n'.join(err_message))
117
118    def teardown_test(self):
119        try:
120            self._end_iperfs()
121        except RuntimeError as re:
122            raise re
123        finally:
124            super().teardown_test()
125
126    def _iperf_log_check(self, file, expected_bandwidth):
127        """Check iperf log and abnormal bandwidth instances.
128
129        Args:
130            file: file object of iperf log to be checked.
131            expected_bandwidth: integer value for expected bandwidth.
132        Returns:
133            True if log is normal, False otherwise.
134        """
135        # example of record line
136        #[  4]   0.00-1.00   sec  20.2 MBytes   169 Mbits/sec
137        total_abnormal_entries = 0
138        total_record_entries = 0
139        bandwidth_val_idx = 6
140        record_entry_total_cols = 8
141        lines = file.split('\n')
142        acceptable_difference = self.bandwidth_tolerance * expected_bandwidth
143        self.log.debug('Expected bandwidth: %f', expected_bandwidth)
144        self.log.debug('Acceptance difference: %f', acceptable_difference)
145        for line in lines:
146            cols = line.split()
147            self.log.debug(cols)
148            if len(cols) == record_entry_total_cols:
149                total_record_entries += 1
150                bandwidth = float(cols[bandwidth_val_idx])
151                self.log.debug('bandwidth: %f', bandwidth)
152                if abs(bandwidth - expected_bandwidth) > acceptable_difference:
153                    total_abnormal_entries += 1
154        if not total_record_entries:
155            raise RuntimeError('No tput data record found.')
156        self.log.debug('Total abnormal entries: %d - Total record: %d', total_abnormal_entries, total_record_entries)
157        return (total_abnormal_entries/total_record_entries) <= self.abnormal_bandwidth_tolerance
158
159    def _exec_ssh_cmd(self, ssh_client, cmd):
160        """Execute command on given ssh client.
161
162        Args:
163            ssh_client: parmiko ssh client object.
164            cmd: command to execute via ssh.
165        """
166        self.log.info('Sending cmd to ssh host: ' + cmd)
167        stdin, stdout, stderr = ssh_client.exec_command(cmd, get_pty=True)
168        stdin.close()
169        self.iperf_out_err[ssh_client] = (stdout, stderr)
170
171    def start_downlink_process(self):
172        """UE transfer data to host."""
173        self.log.info('Start downlink process')
174        # start UE iperf server
175        self.cellular_dut.ad.adb.shell(self.START_IPERF_SV_UE_CMD)
176        self.log.info('cmd sent to UE: ' + self.START_IPERF_SV_UE_CMD)
177        self.log.info('UE iperf server started')
178        time.sleep(5)
179        # start host iperf client
180        cmd = None
181        if 'fr2' in self.test_name:
182            cmd = self.START_IPERF_CLIENT_HOST_CMD_FR2.format(
183                exe_path=self.iperf_exe_path,
184                ue_ip=self.ue_ip,
185                second=self.n_second_to_omitted)
186        else:
187            cmd = self.START_IPERF_CLIENT_HOST_CMD.format(
188                exe_path=self.iperf_exe_path,
189                ue_ip=self.ue_ip,
190                second=self.n_second_to_omitted)
191
192        if not cmd:
193            raise RuntimeError('Cannot format command to start iperf client.')
194        self._exec_ssh_cmd(self.ssh_iperf_client, cmd)
195        self.log.info('Host iperf client started')
196        time.sleep(5)
197
198    def start_uplink_process(self):
199        """Host transfer data to UE."""
200        self.log.info('Start uplink process')
201        # start host iperf server
202        cmd = self.START_IPERF_SV_HOST_CMD.format(exe_path=self.iperf_exe_path)
203        self._exec_ssh_cmd(self.ssh_iperf_server, cmd)
204        self.log.info('Host iperf server started')
205        time.sleep(5)
206        # start UE iperf
207        adb_cmd = self.START_IPERF_CLIENT_UE_CMD.format(
208            iperf_host_ip=self.iperf_host_ip,
209            second=self.n_second_to_omitted)
210        self.cellular_dut.ad.adb.shell(adb_cmd)
211        self.log.info('cmd sent to UE: ' + adb_cmd)
212        self.log.info('UE iperf client started')
213        time.sleep(5)
214
215    def _write_iperf_log(self, file_name, content):
216        """ Writing ssh stdout and stdin to log file.
217
218        Args:
219            file_name: Log file name to write log to.
220            content: Content to write to file.
221        """
222        iperf_log_dir = os.path.join(self.root_output_path, 'iperf')
223        os.makedirs(iperf_log_dir, exist_ok=True)
224        iperf_log_file_path = os.path.join(iperf_log_dir, file_name)
225        with open(iperf_log_file_path, 'w') as f:
226            f.write(content)
227
228    def turn_on_mobile_data(self):
229        self.dut.adb.shell(self.ADB_CMD_ENABLE_MOBILE_DATA)
230
231
232class PowerTelTraffic_Preset_Test(PowerTelTrafficPresetTest):
233    def test_preset_LTE_traffic(self):
234        self.power_tel_traffic_test()
235
236    def test_preset_nsa_traffic_fr1(self):
237        self.power_tel_traffic_test()
238
239    def test_preset_sa_traffic_fr1(self):
240        self.power_tel_traffic_test()
241
242
243class PowerTelTrafficFr2_Preset_Test(PowerTelTrafficPresetTest):
244    def test_preset_nsa_traffic_fr2(self):
245        self.power_tel_traffic_test()
246