xref: /aosp_15_r20/external/toolchain-utils/pgo_tools/generate_pgo_profile_test.py (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
1#!/usr/bin/env python3
2# Copyright 2023 The ChromiumOS Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Tests for generate_pgo_profile."""
7
8from pathlib import Path
9import shutil
10import tempfile
11import unittest
12from unittest import mock
13
14import generate_pgo_profile
15import pgo_tools
16
17
18class Test(unittest.TestCase):
19    """Tests for generate_pgo_profile."""
20
21    @mock.patch.object(pgo_tools, "run")
22    def test_find_missing_cross_libs_works_for_empty_results(self, mock_run):
23        mock_run.return_value.returncode = 3
24        mock_run.return_value.stdout = ""
25        self.assertEqual(
26            generate_pgo_profile.find_missing_cross_libs(),
27            generate_pgo_profile.ALL_NEEDED_CROSS_LIBS,
28        )
29
30        mock_run.return_value.returncode = 0
31        self.assertEqual(
32            generate_pgo_profile.find_missing_cross_libs(),
33            generate_pgo_profile.ALL_NEEDED_CROSS_LIBS,
34        )
35
36    @mock.patch.object(pgo_tools, "run")
37    def test_find_missing_cross_libs_filters_results_properly(self, mock_run):
38        mock_run.return_value.returncode = 0
39        mock_run.return_value.stdout = "\n".join(
40            generate_pgo_profile.ALL_NEEDED_CROSS_LIBS
41        )
42        self.assertEqual(generate_pgo_profile.find_missing_cross_libs(), set())
43
44        some_cross_libs = sorted(generate_pgo_profile.ALL_NEEDED_CROSS_LIBS)
45        del some_cross_libs[len(some_cross_libs) // 3 :]
46        mock_run.return_value.stdout = "\n".join(
47            some_cross_libs + ["cross-foo/bar"]
48        )
49
50        expected_result = generate_pgo_profile.ALL_NEEDED_CROSS_LIBS - set(
51            some_cross_libs
52        )
53        self.assertEqual(
54            generate_pgo_profile.find_missing_cross_libs(), expected_result
55        )
56
57    def make_tempdir(self) -> Path:
58        tempdir = Path(tempfile.mkdtemp(prefix="generate_pgo_profile_test_"))
59        self.addCleanup(lambda: shutil.rmtree(tempdir))
60        return tempdir
61
62    def test_read_exactly_one_dirent_works(self):
63        tempdir = self.make_tempdir()
64        ent = tempdir / "one-ent"
65        ent.touch()
66
67        self.assertEqual(
68            generate_pgo_profile.read_exactly_one_dirent(tempdir), ent
69        )
70
71    def test_read_exactly_one_dirent_fails_when_no_ents(self):
72        tempdir = self.make_tempdir()
73        with self.assertRaisesRegex(ValueError, "^Expected exactly one"):
74            generate_pgo_profile.read_exactly_one_dirent(tempdir)
75
76    def test_read_exactly_one_dirent_fails_when_multiple_ents(self):
77        tempdir = self.make_tempdir()
78        (tempdir / "a").touch()
79        (tempdir / "b").touch()
80        with self.assertRaisesRegex(ValueError, "^Expected exactly one"):
81            generate_pgo_profile.read_exactly_one_dirent(tempdir)
82
83    @mock.patch.object(pgo_tools, "run")
84    def test_profraw_conversion_works(self, mock_run):
85        tempdir = self.make_tempdir()
86        profiles = [
87            tempdir / "profile-foo.profraw",
88            tempdir / "profile-bar.profraw",
89        ]
90        not_a_profile = tempdir / "not-a-profile.profraw"
91        for f in profiles + [not_a_profile]:
92            f.touch()
93
94        result = generate_pgo_profile.convert_profraw_to_pgo_profile(tempdir)
95        self.assertNotEqual(result.stem, ".profraw")
96        try:
97            # is_relative_to was added in Py3.9; until the chroot has that,
98            # this code needs to use `relative_to` & check for exceptions.
99            result.relative_to(tempdir)
100        except ValueError:
101            self.fail(f"{result} should be relative to {tempdir}")
102
103        mock_run.assert_called_once()
104        run_cmd = mock_run.call_args[0][0]
105        for p in profiles:
106            self.assertIn(p, run_cmd)
107        self.assertNotIn(not_a_profile, run_cmd)
108        self.assertIn(f"--output={result}", run_cmd)
109
110
111if __name__ == "__main__":
112    unittest.main()
113