summaryrefslogtreecommitdiffstats
path: root/testing/mozbase/mozpower/tests/test_mozpower.py
blob: fd513e836bb60098553ae069bf703c0a9605ac36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
#!/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()