xref: /aosp_15_r20/external/toolchain-utils/crosperf/suite_runner_unittest.py (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
1*760c253cSXin Li#!/usr/bin/env python3
2*760c253cSXin Li# -*- coding: utf-8 -*-
3*760c253cSXin Li#
4*760c253cSXin Li# Copyright 2014 The ChromiumOS Authors
5*760c253cSXin Li# Use of this source code is governed by a BSD-style license that can be
6*760c253cSXin Li# found in the LICENSE file.
7*760c253cSXin Li
8*760c253cSXin Li"""Unittest for suite_runner."""
9*760c253cSXin Li
10*760c253cSXin Li
11*760c253cSXin Liimport contextlib
12*760c253cSXin Liimport json
13*760c253cSXin Liimport unittest
14*760c253cSXin Liimport unittest.mock as mock
15*760c253cSXin Li
16*760c253cSXin Lifrom benchmark import Benchmark
17*760c253cSXin Lifrom cros_utils import command_executer
18*760c253cSXin Lifrom cros_utils import logger
19*760c253cSXin Liimport label
20*760c253cSXin Lifrom machine_manager import MockCrosMachine
21*760c253cSXin Liimport suite_runner
22*760c253cSXin Li
23*760c253cSXin Li
24*760c253cSXin Liclass SuiteRunnerTest(unittest.TestCase):
25*760c253cSXin Li    """Class of SuiteRunner test."""
26*760c253cSXin Li
27*760c253cSXin Li    mock_json = mock.Mock(spec=json)
28*760c253cSXin Li    mock_cmd_exec = mock.Mock(spec=command_executer.CommandExecuter)
29*760c253cSXin Li    mock_cmd_term = mock.Mock(spec=command_executer.CommandTerminator)
30*760c253cSXin Li    mock_logger = mock.Mock(spec=logger.Logger)
31*760c253cSXin Li    mock_label = label.MockLabel(
32*760c253cSXin Li        "lumpy",
33*760c253cSXin Li        "build",
34*760c253cSXin Li        "lumpy_chromeos_image",
35*760c253cSXin Li        "",
36*760c253cSXin Li        "",
37*760c253cSXin Li        "/tmp/chromeos",
38*760c253cSXin Li        "lumpy",
39*760c253cSXin Li        ["lumpy1.cros", "lumpy.cros2"],
40*760c253cSXin Li        "",
41*760c253cSXin Li        "",
42*760c253cSXin Li        False,
43*760c253cSXin Li        "average",
44*760c253cSXin Li        "gcc",
45*760c253cSXin Li        False,
46*760c253cSXin Li        "",
47*760c253cSXin Li    )
48*760c253cSXin Li    telemetry_crosperf_bench = Benchmark(
49*760c253cSXin Li        "b1_test",  # name
50*760c253cSXin Li        "octane",  # test_name
51*760c253cSXin Li        "",  # test_args
52*760c253cSXin Li        3,  # iterations
53*760c253cSXin Li        False,  # rm_chroot_tmp
54*760c253cSXin Li        "record -e cycles",  # perf_args
55*760c253cSXin Li        "telemetry_Crosperf",  # suite
56*760c253cSXin Li        True,
57*760c253cSXin Li    )  # show_all_results
58*760c253cSXin Li
59*760c253cSXin Li    crosperf_wrapper_bench = Benchmark(
60*760c253cSXin Li        "b2_test",  # name
61*760c253cSXin Li        "webgl",  # test_name
62*760c253cSXin Li        "",  # test_args
63*760c253cSXin Li        3,  # iterations
64*760c253cSXin Li        False,  # rm_chroot_tmp
65*760c253cSXin Li        "",  # perf_args
66*760c253cSXin Li        "crosperf_Wrapper",
67*760c253cSXin Li    )  # suite
68*760c253cSXin Li
69*760c253cSXin Li    tast_bench = Benchmark(
70*760c253cSXin Li        "b3_test",  # name
71*760c253cSXin Li        "platform.ReportDiskUsage",  # test_name
72*760c253cSXin Li        "",  # test_args
73*760c253cSXin Li        1,  # iterations
74*760c253cSXin Li        False,  # rm_chroot_tmp
75*760c253cSXin Li        "",  # perf_args
76*760c253cSXin Li        "tast",
77*760c253cSXin Li    )  # suite
78*760c253cSXin Li
79*760c253cSXin Li    def __init__(self, *args, **kwargs):
80*760c253cSXin Li        super(SuiteRunnerTest, self).__init__(*args, **kwargs)
81*760c253cSXin Li        self.crosfleet_run_args = []
82*760c253cSXin Li        self.test_that_args = []
83*760c253cSXin Li        self.tast_args = []
84*760c253cSXin Li        self.call_crosfleet_run = False
85*760c253cSXin Li        self.call_test_that_run = False
86*760c253cSXin Li        self.call_tast_run = False
87*760c253cSXin Li
88*760c253cSXin Li    def setUp(self):
89*760c253cSXin Li        self.runner = suite_runner.SuiteRunner(
90*760c253cSXin Li            {},
91*760c253cSXin Li            self.mock_logger,
92*760c253cSXin Li            "verbose",
93*760c253cSXin Li            self.mock_cmd_exec,
94*760c253cSXin Li            self.mock_cmd_term,
95*760c253cSXin Li        )
96*760c253cSXin Li
97*760c253cSXin Li    def test_get_profiler_args(self):
98*760c253cSXin Li        input_str = (
99*760c253cSXin Li            "--profiler=custom_perf --profiler_args='perf_options"
100*760c253cSXin Li            '="record -a -e cycles,instructions"\''
101*760c253cSXin Li        )
102*760c253cSXin Li        output_str = (
103*760c253cSXin Li            "profiler=custom_perf profiler_args='record -a -e "
104*760c253cSXin Li            "cycles,instructions'"
105*760c253cSXin Li        )
106*760c253cSXin Li        res = suite_runner.GetProfilerArgs(input_str)
107*760c253cSXin Li        self.assertEqual(res, output_str)
108*760c253cSXin Li
109*760c253cSXin Li    def test_get_dut_config_args(self):
110*760c253cSXin Li        dut_config = {"enable_aslr": False, "top_interval": 1.0}
111*760c253cSXin Li        output_str = (
112*760c253cSXin Li            "dut_config="
113*760c253cSXin Li            "'"
114*760c253cSXin Li            '{"enable_aslr": '
115*760c253cSXin Li            'false, "top_interval": 1.0}'
116*760c253cSXin Li            "'"
117*760c253cSXin Li            ""
118*760c253cSXin Li        )
119*760c253cSXin Li        res = suite_runner.GetDutConfigArgs(dut_config)
120*760c253cSXin Li        self.assertEqual(res, output_str)
121*760c253cSXin Li
122*760c253cSXin Li    @mock.patch("suite_runner.ssh_tunnel")
123*760c253cSXin Li    def test_run(self, ssh_tunnel):
124*760c253cSXin Li        @contextlib.contextmanager
125*760c253cSXin Li        def mock_ssh_tunnel(_watcher, _host):
126*760c253cSXin Li            yield "fakelocalhost:1234"
127*760c253cSXin Li
128*760c253cSXin Li        ssh_tunnel.side_effect = mock_ssh_tunnel
129*760c253cSXin Li
130*760c253cSXin Li        def reset():
131*760c253cSXin Li            self.test_that_args = []
132*760c253cSXin Li            self.crosfleet_run_args = []
133*760c253cSXin Li            self.tast_args = []
134*760c253cSXin Li            self.call_test_that_run = False
135*760c253cSXin Li            self.call_crosfleet_run = False
136*760c253cSXin Li            self.call_tast_run = False
137*760c253cSXin Li
138*760c253cSXin Li        def FakeCrosfleetRun(test_label, benchmark, test_args, profiler_args):
139*760c253cSXin Li            self.crosfleet_run_args = [
140*760c253cSXin Li                test_label,
141*760c253cSXin Li                benchmark,
142*760c253cSXin Li                test_args,
143*760c253cSXin Li                profiler_args,
144*760c253cSXin Li            ]
145*760c253cSXin Li            self.call_crosfleet_run = True
146*760c253cSXin Li            return "Ran FakeCrosfleetRun"
147*760c253cSXin Li
148*760c253cSXin Li        def FakeTestThatRun(
149*760c253cSXin Li            machine, test_label, benchmark, test_args, profiler_args
150*760c253cSXin Li        ):
151*760c253cSXin Li            self.test_that_args = [
152*760c253cSXin Li                machine,
153*760c253cSXin Li                test_label,
154*760c253cSXin Li                benchmark,
155*760c253cSXin Li                test_args,
156*760c253cSXin Li                profiler_args,
157*760c253cSXin Li            ]
158*760c253cSXin Li            self.call_test_that_run = True
159*760c253cSXin Li            return "Ran FakeTestThatRun"
160*760c253cSXin Li
161*760c253cSXin Li        def FakeTastRun(machine, test_label, benchmark):
162*760c253cSXin Li            self.tast_args = [machine, test_label, benchmark]
163*760c253cSXin Li            self.call_tast_run = True
164*760c253cSXin Li            return "Ran FakeTastRun"
165*760c253cSXin Li
166*760c253cSXin Li        self.runner.Crosfleet_Run = FakeCrosfleetRun
167*760c253cSXin Li        self.runner.Test_That_Run = FakeTestThatRun
168*760c253cSXin Li        self.runner.Tast_Run = FakeTastRun
169*760c253cSXin Li
170*760c253cSXin Li        self.runner.dut_config["enable_aslr"] = False
171*760c253cSXin Li        self.runner.dut_config["cooldown_time"] = 0
172*760c253cSXin Li        self.runner.dut_config["governor"] = "fake_governor"
173*760c253cSXin Li        self.runner.dut_config["cpu_freq_pct"] = 65
174*760c253cSXin Li        self.runner.dut_config["intel_pstate"] = "no_hwp"
175*760c253cSXin Li        machine = "fake_machine"
176*760c253cSXin Li        cros_machine = MockCrosMachine(
177*760c253cSXin Li            machine, self.mock_label.chromeos_root, self.mock_logger
178*760c253cSXin Li        )
179*760c253cSXin Li        test_args = ""
180*760c253cSXin Li        profiler_args = ""
181*760c253cSXin Li
182*760c253cSXin Li        # Test crosfleet run for telemetry_Crosperf and crosperf_Wrapper benchmarks.
183*760c253cSXin Li        self.mock_label.crosfleet = True
184*760c253cSXin Li        reset()
185*760c253cSXin Li        self.runner.Run(
186*760c253cSXin Li            cros_machine,
187*760c253cSXin Li            self.mock_label,
188*760c253cSXin Li            self.crosperf_wrapper_bench,
189*760c253cSXin Li            test_args,
190*760c253cSXin Li            profiler_args,
191*760c253cSXin Li        )
192*760c253cSXin Li        self.assertTrue(self.call_crosfleet_run)
193*760c253cSXin Li        self.assertFalse(self.call_test_that_run)
194*760c253cSXin Li        self.assertEqual(
195*760c253cSXin Li            self.crosfleet_run_args,
196*760c253cSXin Li            [self.mock_label, self.crosperf_wrapper_bench, "", ""],
197*760c253cSXin Li        )
198*760c253cSXin Li
199*760c253cSXin Li        reset()
200*760c253cSXin Li        self.runner.Run(
201*760c253cSXin Li            cros_machine,
202*760c253cSXin Li            self.mock_label,
203*760c253cSXin Li            self.telemetry_crosperf_bench,
204*760c253cSXin Li            test_args,
205*760c253cSXin Li            profiler_args,
206*760c253cSXin Li        )
207*760c253cSXin Li        self.assertTrue(self.call_crosfleet_run)
208*760c253cSXin Li        self.assertFalse(self.call_test_that_run)
209*760c253cSXin Li        self.assertEqual(
210*760c253cSXin Li            self.crosfleet_run_args,
211*760c253cSXin Li            [self.mock_label, self.telemetry_crosperf_bench, "", ""],
212*760c253cSXin Li        )
213*760c253cSXin Li
214*760c253cSXin Li        # Test test_that run for telemetry_Crosperf and crosperf_Wrapper benchmarks.
215*760c253cSXin Li        self.mock_label.crosfleet = False
216*760c253cSXin Li        reset()
217*760c253cSXin Li        self.runner.Run(
218*760c253cSXin Li            cros_machine,
219*760c253cSXin Li            self.mock_label,
220*760c253cSXin Li            self.crosperf_wrapper_bench,
221*760c253cSXin Li            test_args,
222*760c253cSXin Li            profiler_args,
223*760c253cSXin Li        )
224*760c253cSXin Li        self.assertTrue(self.call_test_that_run)
225*760c253cSXin Li        self.assertFalse(self.call_crosfleet_run)
226*760c253cSXin Li        self.assertEqual(
227*760c253cSXin Li            self.test_that_args,
228*760c253cSXin Li            [
229*760c253cSXin Li                "fake_machine",
230*760c253cSXin Li                self.mock_label,
231*760c253cSXin Li                self.crosperf_wrapper_bench,
232*760c253cSXin Li                "",
233*760c253cSXin Li                "",
234*760c253cSXin Li            ],
235*760c253cSXin Li        )
236*760c253cSXin Li
237*760c253cSXin Li        reset()
238*760c253cSXin Li        self.runner.Run(
239*760c253cSXin Li            cros_machine,
240*760c253cSXin Li            self.mock_label,
241*760c253cSXin Li            self.telemetry_crosperf_bench,
242*760c253cSXin Li            test_args,
243*760c253cSXin Li            profiler_args,
244*760c253cSXin Li        )
245*760c253cSXin Li        self.assertTrue(self.call_test_that_run)
246*760c253cSXin Li        self.assertFalse(self.call_crosfleet_run)
247*760c253cSXin Li        self.assertEqual(
248*760c253cSXin Li            self.test_that_args,
249*760c253cSXin Li            [
250*760c253cSXin Li                "fake_machine",
251*760c253cSXin Li                self.mock_label,
252*760c253cSXin Li                self.telemetry_crosperf_bench,
253*760c253cSXin Li                "",
254*760c253cSXin Li                "",
255*760c253cSXin Li            ],
256*760c253cSXin Li        )
257*760c253cSXin Li
258*760c253cSXin Li        # Test tast run for tast benchmarks.
259*760c253cSXin Li        reset()
260*760c253cSXin Li        self.runner.Run(cros_machine, self.mock_label, self.tast_bench, "", "")
261*760c253cSXin Li        self.assertTrue(self.call_tast_run)
262*760c253cSXin Li        self.assertFalse(self.call_test_that_run)
263*760c253cSXin Li        self.assertFalse(self.call_crosfleet_run)
264*760c253cSXin Li        self.assertEqual(
265*760c253cSXin Li            self.tast_args,
266*760c253cSXin Li            ["fakelocalhost:1234", self.mock_label, self.tast_bench],
267*760c253cSXin Li        )
268*760c253cSXin Li
269*760c253cSXin Li    def test_gen_test_args(self):
270*760c253cSXin Li        test_args = "--iterations=2"
271*760c253cSXin Li        perf_args = "record -a -e cycles"
272*760c253cSXin Li
273*760c253cSXin Li        # Test crosperf_Wrapper benchmarks arg list generation
274*760c253cSXin Li        args_list = [
275*760c253cSXin Li            "test_args='--iterations=2'",
276*760c253cSXin Li            "dut_config='{}'",
277*760c253cSXin Li            "test=webgl",
278*760c253cSXin Li        ]
279*760c253cSXin Li        res = self.runner.GenTestArgs(
280*760c253cSXin Li            self.crosperf_wrapper_bench, test_args, ""
281*760c253cSXin Li        )
282*760c253cSXin Li        self.assertCountEqual(res, args_list)
283*760c253cSXin Li
284*760c253cSXin Li        # Test telemetry_Crosperf benchmarks arg list generation
285*760c253cSXin Li        args_list = [
286*760c253cSXin Li            "test_args='--iterations=2'",
287*760c253cSXin Li            "dut_config='{}'",
288*760c253cSXin Li            "test=octane",
289*760c253cSXin Li            "run_local=False",
290*760c253cSXin Li        ]
291*760c253cSXin Li        args_list.append(suite_runner.GetProfilerArgs(perf_args))
292*760c253cSXin Li        res = self.runner.GenTestArgs(
293*760c253cSXin Li            self.telemetry_crosperf_bench, test_args, perf_args
294*760c253cSXin Li        )
295*760c253cSXin Li        self.assertCountEqual(res, args_list)
296*760c253cSXin Li
297*760c253cSXin Li    @mock.patch.object(command_executer.CommandExecuter, "CrosRunCommand")
298*760c253cSXin Li    @mock.patch.object(
299*760c253cSXin Li        command_executer.CommandExecuter, "ChrootRunCommandWOutput"
300*760c253cSXin Li    )
301*760c253cSXin Li    def test_tast_run(self, mock_chroot_runcmd, mock_cros_runcmd):
302*760c253cSXin Li        mock_chroot_runcmd.return_value = 0
303*760c253cSXin Li        self.mock_cmd_exec.ChrootRunCommandWOutput = mock_chroot_runcmd
304*760c253cSXin Li        self.mock_cmd_exec.CrosRunCommand = mock_cros_runcmd
305*760c253cSXin Li        res = self.runner.Tast_Run(
306*760c253cSXin Li            "lumpy1.cros", self.mock_label, self.tast_bench
307*760c253cSXin Li        )
308*760c253cSXin Li        self.assertEqual(mock_cros_runcmd.call_count, 1)
309*760c253cSXin Li        self.assertEqual(mock_chroot_runcmd.call_count, 1)
310*760c253cSXin Li        self.assertEqual(res, 0)
311*760c253cSXin Li        self.assertEqual(
312*760c253cSXin Li            mock_cros_runcmd.call_args_list[0][0],
313*760c253cSXin Li            ("rm -rf /usr/local/autotest/results/*",),
314*760c253cSXin Li        )
315*760c253cSXin Li        args_list = mock_chroot_runcmd.call_args_list[0][0]
316*760c253cSXin Li        args_dict = mock_chroot_runcmd.call_args_list[0][1]
317*760c253cSXin Li        self.assertEqual(len(args_list), 2)
318*760c253cSXin Li        self.assertEqual(args_dict["command_terminator"], self.mock_cmd_term)
319*760c253cSXin Li
320*760c253cSXin Li    @mock.patch.object(command_executer.CommandExecuter, "CrosRunCommand")
321*760c253cSXin Li    @mock.patch.object(
322*760c253cSXin Li        command_executer.CommandExecuter, "ChrootRunCommandWOutput"
323*760c253cSXin Li    )
324*760c253cSXin Li    @mock.patch.object(logger.Logger, "LogFatal")
325*760c253cSXin Li    def test_test_that_run(
326*760c253cSXin Li        self, mock_log_fatal, mock_chroot_runcmd, mock_cros_runcmd
327*760c253cSXin Li    ):
328*760c253cSXin Li        mock_log_fatal.side_effect = SystemExit()
329*760c253cSXin Li        self.runner.logger.LogFatal = mock_log_fatal
330*760c253cSXin Li        # Test crosperf_Wrapper benchmarks cannot take perf_args
331*760c253cSXin Li        raised_exception = False
332*760c253cSXin Li        try:
333*760c253cSXin Li            self.runner.Test_That_Run(
334*760c253cSXin Li                "lumpy1.cros",
335*760c253cSXin Li                self.mock_label,
336*760c253cSXin Li                self.crosperf_wrapper_bench,
337*760c253cSXin Li                "",
338*760c253cSXin Li                "record -a -e cycles",
339*760c253cSXin Li            )
340*760c253cSXin Li        except SystemExit:
341*760c253cSXin Li            raised_exception = True
342*760c253cSXin Li        self.assertTrue(raised_exception)
343*760c253cSXin Li
344*760c253cSXin Li        mock_chroot_runcmd.return_value = 0
345*760c253cSXin Li        self.mock_cmd_exec.ChrootRunCommandWOutput = mock_chroot_runcmd
346*760c253cSXin Li        self.mock_cmd_exec.CrosRunCommand = mock_cros_runcmd
347*760c253cSXin Li        res = self.runner.Test_That_Run(
348*760c253cSXin Li            "lumpy1.cros",
349*760c253cSXin Li            self.mock_label,
350*760c253cSXin Li            self.crosperf_wrapper_bench,
351*760c253cSXin Li            "--iterations=2",
352*760c253cSXin Li            "",
353*760c253cSXin Li        )
354*760c253cSXin Li        self.assertEqual(mock_cros_runcmd.call_count, 1)
355*760c253cSXin Li        self.assertEqual(mock_chroot_runcmd.call_count, 1)
356*760c253cSXin Li        self.assertEqual(res, 0)
357*760c253cSXin Li        self.assertEqual(
358*760c253cSXin Li            mock_cros_runcmd.call_args_list[0][0],
359*760c253cSXin Li            ("rm -rf /usr/local/autotest/results/*",),
360*760c253cSXin Li        )
361*760c253cSXin Li        args_list = mock_chroot_runcmd.call_args_list[0][0]
362*760c253cSXin Li        args_dict = mock_chroot_runcmd.call_args_list[0][1]
363*760c253cSXin Li        self.assertEqual(len(args_list), 2)
364*760c253cSXin Li        self.assertEqual(args_dict["command_terminator"], self.mock_cmd_term)
365*760c253cSXin Li
366*760c253cSXin Li    @mock.patch.object(command_executer.CommandExecuter, "RunCommandWOutput")
367*760c253cSXin Li    @mock.patch.object(json, "loads")
368*760c253cSXin Li    def test_crosfleet_run_client(self, mock_json_loads, mock_runcmd):
369*760c253cSXin Li        def FakeDownloadResult(l, task_id):
370*760c253cSXin Li            if l and task_id:
371*760c253cSXin Li                self.assertEqual(task_id, "12345")
372*760c253cSXin Li                return 0
373*760c253cSXin Li
374*760c253cSXin Li        mock_runcmd.return_value = (
375*760c253cSXin Li            0,
376*760c253cSXin Li            "Created Swarming task https://swarming/task/b12345",
377*760c253cSXin Li            "",
378*760c253cSXin Li        )
379*760c253cSXin Li        self.mock_cmd_exec.RunCommandWOutput = mock_runcmd
380*760c253cSXin Li
381*760c253cSXin Li        mock_json_loads.return_value = {
382*760c253cSXin Li            "child-results": [
383*760c253cSXin Li                {
384*760c253cSXin Li                    "success": True,
385*760c253cSXin Li                    "task-run-url": "https://swarming/task?id=12345",
386*760c253cSXin Li                }
387*760c253cSXin Li            ]
388*760c253cSXin Li        }
389*760c253cSXin Li        self.mock_json.loads = mock_json_loads
390*760c253cSXin Li
391*760c253cSXin Li        self.mock_label.crosfleet = True
392*760c253cSXin Li        self.runner.DownloadResult = FakeDownloadResult
393*760c253cSXin Li        res = self.runner.Crosfleet_Run(
394*760c253cSXin Li            self.mock_label, self.crosperf_wrapper_bench, "", ""
395*760c253cSXin Li        )
396*760c253cSXin Li        ret_tup = (0, "\nResults placed in tmp/swarming-12345\n", "")
397*760c253cSXin Li        self.assertEqual(res, ret_tup)
398*760c253cSXin Li        self.assertEqual(mock_runcmd.call_count, 2)
399*760c253cSXin Li
400*760c253cSXin Li        args_list = mock_runcmd.call_args_list[0][0]
401*760c253cSXin Li        args_dict = mock_runcmd.call_args_list[0][1]
402*760c253cSXin Li        self.assertEqual(len(args_list), 1)
403*760c253cSXin Li        self.assertEqual(args_dict["command_terminator"], self.mock_cmd_term)
404*760c253cSXin Li
405*760c253cSXin Li        args_list = mock_runcmd.call_args_list[1][0]
406*760c253cSXin Li        self.assertEqual(args_list[0], ("crosfleet wait-task 12345"))
407*760c253cSXin Li        self.assertEqual(args_dict["command_terminator"], self.mock_cmd_term)
408*760c253cSXin Li
409*760c253cSXin Li
410*760c253cSXin Liif __name__ == "__main__":
411*760c253cSXin Li    unittest.main()
412