test_mozpower.py (9505B)
1 #!/usr/bin/env python 2 3 import subprocess 4 from unittest import mock 5 6 import mozunit 7 import pytest 8 from mozpower import MozPower 9 from mozpower.mozpower import MissingProcessorInfoError, OsCpuComboMissingError 10 11 12 def test_mozpower_android_init_failure(): 13 """Tests that the MozPower object fails when the android 14 flag is set. Remove this test once android is implemented. 15 """ 16 with pytest.raises(NotImplementedError): 17 MozPower(android=True) 18 19 20 def test_mozpower_oscpu_combo_missing_error(): 21 """Tests that the error OsCpuComboMissingError is raised 22 when we can't find a OS, and CPU combination (and, therefore, cannot 23 find a power measurer). 24 """ 25 with mock.patch.object( 26 MozPower, "_get_os", return_value="Not-An-OS" 27 ) as _, mock.patch.object( 28 MozPower, "_get_processor_info", return_value="Not-A-Processor" 29 ) as _: 30 with pytest.raises(OsCpuComboMissingError): 31 MozPower() 32 33 34 def test_mozpower_processor_info_missing_error(): 35 """Tests that the error MissingProcessorInfoError is raised 36 when failures occur during processor information parsing. 37 """ 38 builtins_name = "builtins" 39 40 def os_side_effect_true(*args, **kwargs): 41 """Used as a passing side effect for os.path.exists calls.""" 42 return True 43 44 def os_side_effect_false(*args, **kwargs): 45 """Used as a failing side effect for os.path.exists calls.""" 46 return False 47 48 def subprocess_side_effect_fail(*args, **kwargs): 49 """Used to mock a failure in subprocess.check_output calls.""" 50 raise subprocess.CalledProcessError(1, "Testing failure") 51 52 # Test failures in macos processor information parsing 53 with mock.patch.object(MozPower, "_get_os", return_value="Darwin") as _: 54 with mock.patch("os.path.exists") as os_mock: 55 os_mock.side_effect = os_side_effect_false 56 57 # Check that we fail properly if the processor 58 # information file doesn't exist. 59 with pytest.raises(MissingProcessorInfoError): 60 MozPower() 61 62 # Check that we fail properly when an error occurs 63 # in the subprocess call. 64 os_mock.side_effect = os_side_effect_true 65 with mock.patch("subprocess.check_output") as subprocess_mock: 66 subprocess_mock.side_effect = subprocess_side_effect_fail 67 with pytest.raises(MissingProcessorInfoError): 68 MozPower() 69 70 # Test failures in linux processor information parsing 71 with mock.patch.object(MozPower, "_get_os", return_value="Linux") as _: 72 with mock.patch("os.path.exists") as os_mock: 73 os_mock.side_effect = os_side_effect_false 74 75 # Check that we fail properly if the processor 76 # information file doesn't exist. 77 with pytest.raises(MissingProcessorInfoError): 78 MozPower() 79 80 # Check that we fail properly when the model cannot be found 81 # with by searching for 'model name'. 82 os_mock.side_effect = os_side_effect_true 83 with mock.patch( 84 "%s.open" % builtins_name, mock.mock_open(read_data="") 85 ) as _: 86 with pytest.raises(MissingProcessorInfoError): 87 MozPower() 88 89 90 def test_mozpower_oscpu_combo(mozpower_obj): 91 """Tests that the correct class is instantiated for a given 92 OS and CPU combination (MacIntelPower in this case). 93 """ 94 assert mozpower_obj.measurer.__class__.__name__ == "MacIntelPower" 95 assert ( 96 mozpower_obj.measurer._os == "darwin" and mozpower_obj.measurer._cpu == "intel" 97 ) 98 99 100 def test_mozpower_measuring(mozpower_obj): 101 """Tests that measurers are properly called with each method.""" 102 with mock.patch( 103 "mozpower.macintelpower.MacIntelPower.initialize_power_measurements" 104 ) as _, mock.patch( 105 "mozpower.macintelpower.MacIntelPower.finalize_power_measurements" 106 ) as _, mock.patch("mozpower.macintelpower.MacIntelPower.get_perfherder_data") as _: 107 mozpower_obj.initialize_power_measurements() 108 mozpower_obj.measurer.initialize_power_measurements.assert_called() 109 110 mozpower_obj.finalize_power_measurements() 111 mozpower_obj.measurer.finalize_power_measurements.assert_called() 112 113 mozpower_obj.get_perfherder_data() 114 mozpower_obj.measurer.get_perfherder_data.assert_called() 115 116 117 def test_mozpower_measuring_with_no_measurer(mozpower_obj): 118 """Tests that no errors occur when the measurer is None, and the 119 initialize, finalize, and get_perfherder_data functions are called. 120 """ 121 with mock.patch( 122 "mozpower.macintelpower.MacIntelPower.initialize_power_measurements" 123 ) as _, mock.patch( 124 "mozpower.macintelpower.MacIntelPower.finalize_power_measurements" 125 ) as _, mock.patch("mozpower.macintelpower.MacIntelPower.get_perfherder_data") as _: 126 measurer = mozpower_obj.measurer 127 mozpower_obj.measurer = None 128 129 mozpower_obj.initialize_power_measurements() 130 assert not measurer.initialize_power_measurements.called 131 132 mozpower_obj.finalize_power_measurements() 133 assert not measurer.finalize_power_measurements.called 134 135 mozpower_obj.get_perfherder_data() 136 assert not measurer.get_perfherder_data.called 137 138 mozpower_obj.get_full_perfherder_data("mozpower") 139 assert not measurer.get_perfherder_data.called 140 141 142 def test_mozpower_get_full_perfherder_data(mozpower_obj): 143 """Tests that the full perfherder data blob is properly 144 produced given a partial perfherder data blob with correct 145 entries. 146 """ 147 partial_perfherder = { 148 "utilization": { 149 "type": "power", 150 "test": "mozpower", 151 "unit": "%", 152 "values": {"cpu": 50, "gpu": 0}, 153 }, 154 "power-usage": { 155 "type": "power", 156 "test": "mozpower", 157 "unit": "mWh", 158 "values": {"cpu": 2.0, "dram": 0.1, "gpu": 4.0}, 159 }, 160 "frequency-cpu": { 161 "type": "power", 162 "test": "mozpower", 163 "unit": "MHz", 164 "values": { 165 "cpu-favg": 2.0, 166 "cpu-fmax": 5.0, 167 "cpu-fmin": 0.0, 168 }, 169 }, 170 "frequency-gpu": { 171 "type": "power", 172 "test": "mozpower", 173 "unit": "MHz", 174 "values": {"gpu-favg": 3.0, "gpu-fmax": 6.0, "gpu-fmin": 0.0}, 175 }, 176 } 177 utilization_vals = [0, 50] 178 power_usage_vals = [2.0, 0.1, 4.0] 179 frequency_cpu_vals = [2.0, 5.0, 0.0] 180 frequency_gpu_vals = [3.0, 6.0, 0.0] 181 182 with mock.patch("mozpower.macintelpower.MacIntelPower.get_perfherder_data") as gpd: 183 gpd.return_value = partial_perfherder 184 185 full_perfherder = mozpower_obj.get_full_perfherder_data("mozpower") 186 assert full_perfherder["framework"]["name"] == "mozpower" 187 assert len(full_perfherder["suites"]) == 4 188 189 # Check that each of the two suites were created correctly. 190 suites = full_perfherder["suites"] 191 for suite in suites: 192 assert "subtests" in suite 193 194 assert suite["type"] == "power" 195 assert suite["alertThreshold"] == 2.0 196 assert suite["lowerIsBetter"] 197 198 all_vals = [] 199 for subtest in suite["subtests"]: 200 assert "value" in subtest 201 202 # Check that the subtest names were created correctly 203 if "utilization" in suite["name"]: 204 assert "utilization" in subtest["name"] 205 elif "power-usage" in suite["name"]: 206 assert "power-usage" in subtest["name"] 207 elif "frequency-cpu" in suite["name"]: 208 assert "frequency-cpu" in subtest["name"] 209 elif "frequency-gpu" in suite["name"]: 210 assert "frequency-gpu" in subtest["name"] 211 else: 212 assert False, "Unknown subtest name %s" % subtest["name"] 213 214 all_vals.append(subtest["value"]) 215 216 if "utilization" in suite["name"]: 217 assert len(all_vals) == 2 218 assert suite["unit"] == "%" 219 assert suite["name"] == "mozpower-utilization" 220 assert not list(set(all_vals) - set(utilization_vals)) 221 assert suite["value"] == float(25) 222 elif "power-usage" in suite["name"]: 223 assert len(all_vals) == 3 224 assert suite["unit"] == "mWh" 225 assert suite["name"] == "mozpower-power-usage" 226 assert not list(set(all_vals) - set(power_usage_vals)) 227 assert suite["value"] == 6.1 228 elif "frequency-cpu" in suite["name"]: 229 assert len(all_vals) == 3 230 assert suite["unit"] == "MHz" 231 assert suite["name"] == "mozpower-frequency-cpu" 232 assert not list(set(all_vals) - set(frequency_cpu_vals)) 233 assert suite["value"] == 2.0 234 elif "frequency-gpu" in suite["name"]: 235 assert len(all_vals) == 3 236 assert suite["unit"] == "MHz" 237 assert suite["name"] == "mozpower-frequency-gpu" 238 assert not list(set(all_vals) - set(frequency_gpu_vals)) 239 assert suite["value"] == 3.0 240 else: 241 assert False, "Unknown suite name %s" % suite["name"] 242 243 244 if __name__ == "__main__": 245 mozunit.main()