xref: /aosp_15_r20/external/toolchain-utils/rust_tools/rust_watch_test.py (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
1*760c253cSXin Li#!/usr/bin/env python3
2*760c253cSXin Li# -*- coding: utf-8 -*-
3*760c253cSXin Li# Copyright 2020 The ChromiumOS Authors
4*760c253cSXin Li# Use of this source code is governed by a BSD-style license that can be
5*760c253cSXin Li# found in the LICENSE file.
6*760c253cSXin Li
7*760c253cSXin Li"""Tests for rust_watch.py."""
8*760c253cSXin Li
9*760c253cSXin Liimport logging
10*760c253cSXin Liimport pathlib
11*760c253cSXin Liimport subprocess
12*760c253cSXin Liimport time
13*760c253cSXin Liimport unittest
14*760c253cSXin Liimport unittest.mock
15*760c253cSXin Li
16*760c253cSXin Lifrom cros_utils import tiny_render
17*760c253cSXin Liimport rust_watch
18*760c253cSXin Li
19*760c253cSXin Li
20*760c253cSXin Liclass Test(unittest.TestCase):
21*760c253cSXin Li    """Tests."""
22*760c253cSXin Li
23*760c253cSXin Li    def _silence_logs(self):
24*760c253cSXin Li        """Silences all log output until the end of the current test."""
25*760c253cSXin Li
26*760c253cSXin Li        def should_log(_record):
27*760c253cSXin Li            return 0
28*760c253cSXin Li
29*760c253cSXin Li        logger = logging.root
30*760c253cSXin Li        logger.addFilter(should_log)
31*760c253cSXin Li        self.addCleanup(logger.removeFilter, should_log)
32*760c253cSXin Li
33*760c253cSXin Li    def test_release_version_parsing(self):
34*760c253cSXin Li        self.assertEqual(
35*760c253cSXin Li            rust_watch.RustReleaseVersion.from_string("1.2.3"),
36*760c253cSXin Li            rust_watch.RustReleaseVersion(1, 2, 3),
37*760c253cSXin Li        )
38*760c253cSXin Li
39*760c253cSXin Li    def test_release_version_json_round_trips(self):
40*760c253cSXin Li        ver = rust_watch.RustReleaseVersion(1, 2, 3)
41*760c253cSXin Li        self.assertEqual(
42*760c253cSXin Li            rust_watch.RustReleaseVersion.from_json(ver.to_json()), ver
43*760c253cSXin Li        )
44*760c253cSXin Li
45*760c253cSXin Li    def test_state_json_round_trips(self):
46*760c253cSXin Li        state = rust_watch.State(
47*760c253cSXin Li            last_seen_release=rust_watch.RustReleaseVersion(1, 2, 3),
48*760c253cSXin Li            last_gentoo_sha="abc123",
49*760c253cSXin Li        )
50*760c253cSXin Li
51*760c253cSXin Li        self.assertEqual(rust_watch.State.from_json(state.to_json()), state)
52*760c253cSXin Li
53*760c253cSXin Li    @unittest.mock.patch.object(subprocess, "run")
54*760c253cSXin Li    @unittest.mock.patch.object(time, "sleep")
55*760c253cSXin Li    def test_update_git_repo_tries_again_on_failure(self, sleep_mock, run_mock):
56*760c253cSXin Li        self._silence_logs()
57*760c253cSXin Li
58*760c253cSXin Li        oh_no_error = ValueError("oh no")
59*760c253cSXin Li
60*760c253cSXin Li        def check_returncode():
61*760c253cSXin Li            raise oh_no_error
62*760c253cSXin Li
63*760c253cSXin Li        run_call_count = 0
64*760c253cSXin Li
65*760c253cSXin Li        def run_sideeffect(*_args, **_kwargs):
66*760c253cSXin Li            nonlocal run_call_count
67*760c253cSXin Li            run_call_count += 1
68*760c253cSXin Li            result = unittest.mock.Mock()
69*760c253cSXin Li            result.returncode = 1
70*760c253cSXin Li            result.check_returncode = check_returncode
71*760c253cSXin Li            return result
72*760c253cSXin Li
73*760c253cSXin Li        run_mock.side_effect = run_sideeffect
74*760c253cSXin Li
75*760c253cSXin Li        with self.assertRaises(ValueError) as raised:
76*760c253cSXin Li            rust_watch.update_git_repo(pathlib.Path("/does/not/exist/at/all"))
77*760c253cSXin Li
78*760c253cSXin Li        self.assertIs(raised.exception, oh_no_error)
79*760c253cSXin Li        self.assertEqual(run_call_count, 5)
80*760c253cSXin Li
81*760c253cSXin Li        sleep_timings = [unittest.mock.call(60 * i) for i in range(1, 5)]
82*760c253cSXin Li        self.assertEqual(sleep_mock.mock_calls, sleep_timings)
83*760c253cSXin Li
84*760c253cSXin Li    @unittest.mock.patch.object(subprocess, "run")
85*760c253cSXin Li    def test_get_new_gentoo_commits_functions(self, run_mock):
86*760c253cSXin Li        returned = unittest.mock.Mock()
87*760c253cSXin Li        returned.returncode = 0
88*760c253cSXin Li        returned.stdout = "\n".join(
89*760c253cSXin Li            (
90*760c253cSXin Li                "abc123 newer commit",
91*760c253cSXin Li                "abcdef and an older commit",
92*760c253cSXin Li            )
93*760c253cSXin Li        )
94*760c253cSXin Li        run_mock.return_value = returned
95*760c253cSXin Li        results = rust_watch.get_new_gentoo_commits(
96*760c253cSXin Li            pathlib.Path("/does/not/exist/at/all"), "defabc"
97*760c253cSXin Li        )
98*760c253cSXin Li        self.assertEqual(
99*760c253cSXin Li            results,
100*760c253cSXin Li            [
101*760c253cSXin Li                rust_watch.GitCommit("abcdef", "and an older commit"),
102*760c253cSXin Li                rust_watch.GitCommit("abc123", "newer commit"),
103*760c253cSXin Li            ],
104*760c253cSXin Li        )
105*760c253cSXin Li
106*760c253cSXin Li    def test_compose_email_on_a_new_gentoo_commit(self):
107*760c253cSXin Li        sha_a = "a" * 40
108*760c253cSXin Li        new_commit = rust_watch.maybe_compose_email(
109*760c253cSXin Li            new_gentoo_commits=[
110*760c253cSXin Li                rust_watch.GitCommit(
111*760c253cSXin Li                    sha=sha_a,
112*760c253cSXin Li                    subject="summary_a",
113*760c253cSXin Li                ),
114*760c253cSXin Li            ],
115*760c253cSXin Li        )
116*760c253cSXin Li
117*760c253cSXin Li        self.assertEqual(
118*760c253cSXin Li            new_commit,
119*760c253cSXin Li            (
120*760c253cSXin Li                "[rust-watch] new rust ebuild commit detected",
121*760c253cSXin Li                [
122*760c253cSXin Li                    "commit:",
123*760c253cSXin Li                    tiny_render.UnorderedList(
124*760c253cSXin Li                        [
125*760c253cSXin Li                            [
126*760c253cSXin Li                                tiny_render.Link(
127*760c253cSXin Li                                    rust_watch.gentoo_sha_to_link(sha_a),
128*760c253cSXin Li                                    sha_a[:12],
129*760c253cSXin Li                                ),
130*760c253cSXin Li                                ": summary_a",
131*760c253cSXin Li                            ],
132*760c253cSXin Li                        ]
133*760c253cSXin Li                    ),
134*760c253cSXin Li                ],
135*760c253cSXin Li            ),
136*760c253cSXin Li        )
137*760c253cSXin Li
138*760c253cSXin Li    def test_compose_email_composes_nothing_when_no_new_updates_exist(self):
139*760c253cSXin Li        self.assertIsNone(rust_watch.maybe_compose_email(new_gentoo_commits=()))
140*760c253cSXin Li
141*760c253cSXin Li    def test_compose_bug_creates_bugs_on_new_versions(self):
142*760c253cSXin Li        bug_body_start = "A new Rust stable release has been detected;"
143*760c253cSXin Li        title, body = rust_watch.maybe_compose_bug(
144*760c253cSXin Li            old_state=rust_watch.State(
145*760c253cSXin Li                last_seen_release=rust_watch.RustReleaseVersion(1, 0, 0),
146*760c253cSXin Li                last_gentoo_sha="",
147*760c253cSXin Li            ),
148*760c253cSXin Li            newest_release=rust_watch.RustReleaseVersion(1, 0, 1),
149*760c253cSXin Li        )
150*760c253cSXin Li        self.assertEqual(title, "[Rust] Update to 1.0.1")
151*760c253cSXin Li        self.assertTrue(body.startswith(bug_body_start))
152*760c253cSXin Li
153*760c253cSXin Li        title, body = rust_watch.maybe_compose_bug(
154*760c253cSXin Li            old_state=rust_watch.State(
155*760c253cSXin Li                last_seen_release=rust_watch.RustReleaseVersion(1, 0, 0),
156*760c253cSXin Li                last_gentoo_sha="",
157*760c253cSXin Li            ),
158*760c253cSXin Li            newest_release=rust_watch.RustReleaseVersion(1, 1, 0),
159*760c253cSXin Li        )
160*760c253cSXin Li        self.assertEqual(title, "[Rust] Update to 1.1.0")
161*760c253cSXin Li        self.assertTrue(body.startswith(bug_body_start))
162*760c253cSXin Li
163*760c253cSXin Li        title, body = rust_watch.maybe_compose_bug(
164*760c253cSXin Li            old_state=rust_watch.State(
165*760c253cSXin Li                last_seen_release=rust_watch.RustReleaseVersion(1, 0, 0),
166*760c253cSXin Li                last_gentoo_sha="",
167*760c253cSXin Li            ),
168*760c253cSXin Li            newest_release=rust_watch.RustReleaseVersion(2, 0, 0),
169*760c253cSXin Li        )
170*760c253cSXin Li        self.assertEqual(title, "[Rust] Update to 2.0.0")
171*760c253cSXin Li        self.assertTrue(body.startswith(bug_body_start))
172*760c253cSXin Li
173*760c253cSXin Li    def test_compose_bug_does_nothing_when_no_new_updates_exist(self):
174*760c253cSXin Li        self.assertIsNone(
175*760c253cSXin Li            rust_watch.maybe_compose_bug(
176*760c253cSXin Li                old_state=rust_watch.State(
177*760c253cSXin Li                    last_seen_release=rust_watch.RustReleaseVersion(1, 0, 0),
178*760c253cSXin Li                    last_gentoo_sha="",
179*760c253cSXin Li                ),
180*760c253cSXin Li                newest_release=rust_watch.RustReleaseVersion(1, 0, 0),
181*760c253cSXin Li            )
182*760c253cSXin Li        )
183*760c253cSXin Li
184*760c253cSXin Li
185*760c253cSXin Liif __name__ == "__main__":
186*760c253cSXin Li    unittest.main()
187