1#!/usr/bin/env python3
2#
3#   Copyright 2018 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the 'License');
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an 'AS IS' BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16import json
17import os
18
19import acts_contrib.test_utils.power.PowerBaseTest as PBT
20import acts_contrib.test_utils.cellular.cellular_base_test as CBT
21from acts_contrib.test_utils.power import plot_utils
22from acts import context
23
24
25class PowerCellularLabBaseTest(CBT.CellularBaseTest, PBT.PowerBaseTest):
26    """ Base class for Cellular power related tests.
27
28    Inherits from both PowerBaseTest and CellularBaseTest so it has methods to
29    collect power measurements and run a cellular simulation.
30    """
31    def __init__(self, controllers):
32        """ Class initialization.
33
34        Sets class attributes to None.
35        """
36
37        super().__init__(controllers)
38        self.power_results = {}
39
40    def setup_test(self):
41        """ Turn screen on before starting a test. """
42
43        super().setup_test()
44        try:
45            # Save a json file for device info
46            path = os.path.join(self.log_path, 'device_info.json')
47
48            self.log.info('save the device info to {}'.format(path))
49            baseband = self.dut.adb.getprop('gsm.version.baseband')
50            self.dut.add_device_info('baseband', baseband)
51            with open(path, 'w') as f:
52                json.dump(
53                    self.dut.device_info,
54                    f,
55                    indent=2,
56                    sort_keys=True)
57        except Exception as e:
58            self.log.error('error in saving device_info: {}'.format(e))
59
60        # Make the device go to sleep
61        self.dut.droid.goToSleepNow()
62
63        return True
64
65    def collect_power_data(self):
66        """ Collect power data using base class method and plot result
67        histogram. """
68
69        samples = super().collect_power_data()
70        plot_title = '{}_{}_{}_histogram'.format(
71            self.test_name, self.dut.model, self.dut.build_info['build_id'])
72        plot_utils.monsoon_histogram_plot(samples, self.mon_info.data_path,
73                                          plot_title)
74        return samples
75
76    def teardown_test(self):
77        """ Executed after every test case, even if it failed or an exception
78        happened.
79
80        Save results to dictionary so they can be displayed after completing
81        the test batch.
82        """
83        super().teardown_test()
84
85        self.power_results[self.test_name] = self.power_result.metric_value
86
87    def teardown_class(self):
88        """Clean up the test class after tests finish running.
89
90        Stops the simulation and disconnects from the Anritsu Callbox. Then
91        displays the test results.
92
93        """
94        super().teardown_class()
95
96        # Log a summary of results
97        results_table_log = 'Results for cellular power tests:'
98
99        for test_name, value in self.power_results.items():
100            results_table_log += '\n{}\t{}'.format(test_name, value)
101
102        # Save this summary to a csv file in the logs directory
103        self.save_summary_to_file()
104
105        self.log.info(results_table_log)
106
107    def save_summary_to_file(self):
108        """ Creates CSV format files with a summary of results.
109
110        This CSV files can be easily imported in a spreadsheet to analyze the
111        results obtained from the tests.
112        """
113
114        # Save a csv file with the power measurements done in all the tests
115
116        path = os.path.join(self.log_path, self.RESULTS_SUMMARY_FILENAME)
117
118        # To avoid the test overwrite each other, open file with 'a' option
119        csvfile_exist = os.path.exists(path)
120
121        with open(path, 'a') as csvfile:
122            if not csvfile_exist:
123                csvfile.write('test,avg_power')
124            for test_name, value in self.power_results.items():
125                csvfile.write('\n{},{}'.format(test_name, value))
126
127        # Save a csv file with the calibration table for each simulation type
128
129        for sim_type in self.calibration_table:
130
131            path = os.path.join(
132                self.log_path, '{}_{}'.format(sim_type,
133                                              self.CALIBRATION_TABLE_FILENAME))
134
135            with open(path, 'w') as csvfile:
136                csvfile.write('band,dl_pathloss, ul_pathloss')
137                for band, pathloss in self.calibration_table[sim_type].items():
138                    csvfile.write('\n{},{},{}'.format(
139                        band, pathloss.get('dl', 'Error'),
140                        pathloss.get('ul', 'Error')))
141