diff options
Diffstat (limited to '')
-rw-r--r-- | testing/mozbase/mozpower/tests/test_mozpower.py | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/testing/mozbase/mozpower/tests/test_mozpower.py b/testing/mozbase/mozpower/tests/test_mozpower.py new file mode 100644 index 0000000000..1ad6194c0a --- /dev/null +++ b/testing/mozbase/mozpower/tests/test_mozpower.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python + +import subprocess +import sys +from unittest import mock + +import mozunit +import pytest +from mozpower import MozPower +from mozpower.mozpower import MissingProcessorInfoError, OsCpuComboMissingError + + +def test_mozpower_android_init_failure(): + """Tests that the MozPower object fails when the android + flag is set. Remove this test once android is implemented. + """ + with pytest.raises(NotImplementedError): + MozPower(android=True) + + +def test_mozpower_oscpu_combo_missing_error(): + """Tests that the error OsCpuComboMissingError is raised + when we can't find a OS, and CPU combination (and, therefore, cannot + find a power measurer). + """ + with mock.patch.object( + MozPower, "_get_os", return_value="Not-An-OS" + ) as _, mock.patch.object( + MozPower, "_get_processor_info", return_value="Not-A-Processor" + ) as _: + with pytest.raises(OsCpuComboMissingError): + MozPower() + + +def test_mozpower_processor_info_missing_error(): + """Tests that the error MissingProcessorInfoError is raised + when failures occur during processor information parsing. + """ + # The builtins module name differs between python 2 and 3 + builtins_name = "__builtin__" + if sys.version_info[0] == 3: + builtins_name = "builtins" + + def os_side_effect_true(*args, **kwargs): + """Used as a passing side effect for os.path.exists calls.""" + return True + + def os_side_effect_false(*args, **kwargs): + """Used as a failing side effect for os.path.exists calls.""" + return False + + def subprocess_side_effect_fail(*args, **kwargs): + """Used to mock a failure in subprocess.check_output calls.""" + raise subprocess.CalledProcessError(1, "Testing failure") + + # Test failures in macos processor information parsing + with mock.patch.object(MozPower, "_get_os", return_value="Darwin") as _: + with mock.patch("os.path.exists") as os_mock: + os_mock.side_effect = os_side_effect_false + + # Check that we fail properly if the processor + # information file doesn't exist. + with pytest.raises(MissingProcessorInfoError): + MozPower() + + # Check that we fail properly when an error occurs + # in the subprocess call. + os_mock.side_effect = os_side_effect_true + with mock.patch("subprocess.check_output") as subprocess_mock: + subprocess_mock.side_effect = subprocess_side_effect_fail + with pytest.raises(MissingProcessorInfoError): + MozPower() + + # Test failures in linux processor information parsing + with mock.patch.object(MozPower, "_get_os", return_value="Linux") as _: + with mock.patch("os.path.exists") as os_mock: + os_mock.side_effect = os_side_effect_false + + # Check that we fail properly if the processor + # information file doesn't exist. + with pytest.raises(MissingProcessorInfoError): + MozPower() + + # Check that we fail properly when the model cannot be found + # with by searching for 'model name'. + os_mock.side_effect = os_side_effect_true + with mock.patch( + "%s.open" % builtins_name, mock.mock_open(read_data="") + ) as _: + with pytest.raises(MissingProcessorInfoError): + MozPower() + + +def test_mozpower_oscpu_combo(mozpower_obj): + """Tests that the correct class is instantiated for a given + OS and CPU combination (MacIntelPower in this case). + """ + assert mozpower_obj.measurer.__class__.__name__ == "MacIntelPower" + assert ( + mozpower_obj.measurer._os == "darwin" and mozpower_obj.measurer._cpu == "intel" + ) + + +def test_mozpower_measuring(mozpower_obj): + """Tests that measurers are properly called with each method.""" + with mock.patch( + "mozpower.macintelpower.MacIntelPower.initialize_power_measurements" + ) as _, mock.patch( + "mozpower.macintelpower.MacIntelPower.finalize_power_measurements" + ) as _, mock.patch( + "mozpower.macintelpower.MacIntelPower.get_perfherder_data" + ) as _: + mozpower_obj.initialize_power_measurements() + mozpower_obj.measurer.initialize_power_measurements.assert_called() + + mozpower_obj.finalize_power_measurements() + mozpower_obj.measurer.finalize_power_measurements.assert_called() + + mozpower_obj.get_perfherder_data() + mozpower_obj.measurer.get_perfherder_data.assert_called() + + +def test_mozpower_measuring_with_no_measurer(mozpower_obj): + """Tests that no errors occur when the measurer is None, and the + initialize, finalize, and get_perfherder_data functions are called. + """ + with mock.patch( + "mozpower.macintelpower.MacIntelPower.initialize_power_measurements" + ) as _, mock.patch( + "mozpower.macintelpower.MacIntelPower.finalize_power_measurements" + ) as _, mock.patch( + "mozpower.macintelpower.MacIntelPower.get_perfherder_data" + ) as _: + measurer = mozpower_obj.measurer + mozpower_obj.measurer = None + + mozpower_obj.initialize_power_measurements() + assert not measurer.initialize_power_measurements.called + + mozpower_obj.finalize_power_measurements() + assert not measurer.finalize_power_measurements.called + + mozpower_obj.get_perfherder_data() + assert not measurer.get_perfherder_data.called + + mozpower_obj.get_full_perfherder_data("mozpower") + assert not measurer.get_perfherder_data.called + + +def test_mozpower_get_full_perfherder_data(mozpower_obj): + """Tests that the full perfherder data blob is properly + produced given a partial perfherder data blob with correct + entries. + """ + partial_perfherder = { + "utilization": { + "type": "power", + "test": "mozpower", + "unit": "%", + "values": {"cpu": 50, "gpu": 0}, + }, + "power-usage": { + "type": "power", + "test": "mozpower", + "unit": "mWh", + "values": {"cpu": 2.0, "dram": 0.1, "gpu": 4.0}, + }, + "frequency-cpu": { + "type": "power", + "test": "mozpower", + "unit": "MHz", + "values": { + "cpu-favg": 2.0, + "cpu-fmax": 5.0, + "cpu-fmin": 0.0, + }, + }, + "frequency-gpu": { + "type": "power", + "test": "mozpower", + "unit": "MHz", + "values": {"gpu-favg": 3.0, "gpu-fmax": 6.0, "gpu-fmin": 0.0}, + }, + } + utilization_vals = [0, 50] + power_usage_vals = [2.0, 0.1, 4.0] + frequency_cpu_vals = [2.0, 5.0, 0.0] + frequency_gpu_vals = [3.0, 6.0, 0.0] + + with mock.patch("mozpower.macintelpower.MacIntelPower.get_perfherder_data") as gpd: + gpd.return_value = partial_perfherder + + full_perfherder = mozpower_obj.get_full_perfherder_data("mozpower") + assert full_perfherder["framework"]["name"] == "mozpower" + assert len(full_perfherder["suites"]) == 4 + + # Check that each of the two suites were created correctly. + suites = full_perfherder["suites"] + for suite in suites: + assert "subtests" in suite + + assert suite["type"] == "power" + assert suite["alertThreshold"] == 2.0 + assert suite["lowerIsBetter"] + + all_vals = [] + for subtest in suite["subtests"]: + assert "value" in subtest + + # Check that the subtest names were created correctly + if "utilization" in suite["name"]: + assert "utilization" in subtest["name"] + elif "power-usage" in suite["name"]: + assert "power-usage" in subtest["name"] + elif "frequency-cpu" in suite["name"]: + assert "frequency-cpu" in subtest["name"] + elif "frequency-gpu" in suite["name"]: + assert "frequency-gpu" in subtest["name"] + else: + assert False, "Unknown subtest name %s" % subtest["name"] + + all_vals.append(subtest["value"]) + + if "utilization" in suite["name"]: + assert len(all_vals) == 2 + assert suite["unit"] == "%" + assert suite["name"] == "mozpower-utilization" + assert not list(set(all_vals) - set(utilization_vals)) + assert suite["value"] == float(25) + elif "power-usage" in suite["name"]: + assert len(all_vals) == 3 + assert suite["unit"] == "mWh" + assert suite["name"] == "mozpower-power-usage" + assert not list(set(all_vals) - set(power_usage_vals)) + assert suite["value"] == float(6.1) + elif "frequency-cpu" in suite["name"]: + assert len(all_vals) == 3 + assert suite["unit"] == "MHz" + assert suite["name"] == "mozpower-frequency-cpu" + assert not list(set(all_vals) - set(frequency_cpu_vals)) + assert suite["value"] == float(2.0) + elif "frequency-gpu" in suite["name"]: + assert len(all_vals) == 3 + assert suite["unit"] == "MHz" + assert suite["name"] == "mozpower-frequency-gpu" + assert not list(set(all_vals) - set(frequency_gpu_vals)) + assert suite["value"] == float(3.0) + else: + assert False, "Unknown suite name %s" % suite["name"] + + +if __name__ == "__main__": + mozunit.main() |