blob: d6e4b71687094837e9674887c854b044f795a567 [file] [log] [blame]
Chih-Hung Hsiehaa485552020-08-20 15:45:09 -07001# Copyright (C) 2020 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Unit tests for external updater reviewers."""
15
16from typing import List, Mapping, Set
17import unittest
18
19import reviewers
20
21
22class ExternalUpdaterReviewersTest(unittest.TestCase):
23 """Unit tests for external updater reviewers."""
24
25 def setUp(self):
26 super().setUp()
27 # save constants in reviewers
28 self.saved_proj_reviewers = reviewers.PROJ_REVIEWERS
29 self.saved_rust_reviewers = reviewers.RUST_REVIEWERS
30 self.saved_rust_reviewer_list = reviewers.RUST_REVIEWER_LIST
31 self.saved_num_rust_projects = reviewers.NUM_RUST_PROJECTS
32 self.saved_rust_crate_owners = reviewers.RUST_CRATE_OWNERS
33
34 def tearDown(self):
35 super().tearDown()
36 # restore constants in reviewers
37 reviewers.PROJ_REVIEWERS = self.saved_proj_reviewers
38 reviewers.RUST_REVIEWERS = self.saved_rust_reviewers
39 reviewers.RUST_REVIEWER_LIST = self.saved_rust_reviewer_list
40 reviewers.NUM_RUST_PROJECTS = self.saved_num_rust_projects
41 reviewers.RUST_CRATE_OWNERS = self.saved_rust_crate_owners
42
Thiébaud Weksteen4ac289b2020-09-28 15:23:29 +020043 # pylint: disable=no-self-use
Chih-Hung Hsiehaa485552020-08-20 15:45:09 -070044 def _collect_reviewers(self, num_runs, proj_path):
45 counters = {}
46 for _ in range(num_runs):
47 name = reviewers.find_reviewers(proj_path)
48 if name in counters:
49 counters[name] += 1
50 else:
51 counters[name] = 1
52 return counters
53
54 def test_reviewers_types(self):
Thiébaud Weksteen4ac289b2020-09-28 15:23:29 +020055 """Check the types of PROJ_REVIEWERS and RUST_REVIEWERS."""
Chih-Hung Hsiehaa485552020-08-20 15:45:09 -070056 # Check type of PROJ_REVIEWERS
57 self.assertIsInstance(reviewers.PROJ_REVIEWERS, Mapping)
58 for key, value in reviewers.PROJ_REVIEWERS.items():
59 self.assertIsInstance(key, str)
Thiébaud Weksteen4ac289b2020-09-28 15:23:29 +020060 # pylint: disable=isinstance-second-argument-not-valid-type
61 # https://github.com/PyCQA/pylint/issues/3507
62 if isinstance(value, (List, Set)):
63 for x in value:
64 self.assertIsInstance(x, str)
Chih-Hung Hsiehaa485552020-08-20 15:45:09 -070065 else:
66 self.assertIsInstance(value, str)
67 # Check element types of the reviewers list and map.
68 self.assertIsInstance(reviewers.RUST_REVIEWERS, Mapping)
Thiébaud Weksteen4ac289b2020-09-28 15:23:29 +020069 for (name, quota) in reviewers.RUST_REVIEWERS.items():
70 self.assertIsInstance(name, str)
71 self.assertIsInstance(quota, int)
Chih-Hung Hsiehaa485552020-08-20 15:45:09 -070072
73 def test_reviewers_constants(self):
Thiébaud Weksteen4ac289b2020-09-28 15:23:29 +020074 """Check the constants associated to the reviewers."""
Chih-Hung Hsiehaa485552020-08-20 15:45:09 -070075 # There should be enough people in the reviewers pool.
76 self.assertGreaterEqual(len(reviewers.RUST_REVIEWERS), 3)
77 # The NUM_RUST_PROJECTS should not be too small.
78 self.assertGreaterEqual(reviewers.NUM_RUST_PROJECTS, 50)
79 self.assertGreaterEqual(reviewers.NUM_RUST_PROJECTS,
80 len(reviewers.RUST_CRATE_OWNERS))
Chih-Hung Hsiehaa485552020-08-20 15:45:09 -070081 # Assume no project reviewers and recreate RUST_REVIEWER_LIST
82 reviewers.PROJ_REVIEWERS = {}
83 reviewers.RUST_REVIEWER_LIST = reviewers.create_rust_reviewer_list()
84 sum_projects = sum(reviewers.RUST_REVIEWERS.values())
85 self.assertEqual(sum_projects, len(reviewers.RUST_REVIEWER_LIST))
86 self.assertGreaterEqual(sum_projects, reviewers.NUM_RUST_PROJECTS)
87
88 def test_reviewers_randomness(self):
Thiébaud Weksteen4ac289b2020-09-28 15:23:29 +020089 """Check random selection of reviewers."""
Chih-Hung Hsiehaa485552020-08-20 15:45:09 -070090 # This might fail when the random.choice function is extremely unfair.
91 # With N * 20 tries, each reviewer should be picked at least twice.
92 # Assume no project reviewers and recreate RUST_REVIEWER_LIST
93 reviewers.PROJ_REVIEWERS = {}
94 reviewers.RUST_REVIEWER_LIST = reviewers.create_rust_reviewer_list()
95 num_tries = len(reviewers.RUST_REVIEWERS) * 20
96 counters = self._collect_reviewers(num_tries, "rust/crates/libc")
97 self.assertEqual(len(counters), len(reviewers.RUST_REVIEWERS))
Thiébaud Weksteen4ac289b2020-09-28 15:23:29 +020098 for n in counters.values():
Joel Galensondf540652021-05-05 10:16:45 -070099 self.assertGreaterEqual(n, 5)
Chih-Hung Hsiehaa485552020-08-20 15:45:09 -0700100 self.assertEqual(sum(counters.values()), num_tries)
101
102 def test_project_reviewers(self):
Thiébaud Weksteen4ac289b2020-09-28 15:23:29 +0200103 """For specific projects, select only the specified reviewers."""
Chih-Hung Hsiehaa485552020-08-20 15:45:09 -0700104 reviewers.PROJ_REVIEWERS = {
105 "rust/crates/p1": "x@g.com",
106 "rust/crates/p_any": ["x@g.com", "y@g.com"],
107 "rust/crates/p_all": {"z@g", "x@g.com", "y@g.com"},
108 }
109 counters = self._collect_reviewers(20, "external/rust/crates/p1")
110 self.assertEqual(len(counters), 1)
111 self.assertTrue(counters["r=x@g.com"], 20)
112 counters = self._collect_reviewers(20, "external/rust/crates/p_any")
113 self.assertEqual(len(counters), 2)
114 self.assertGreater(counters["r=x@g.com"], 2)
115 self.assertGreater(counters["r=y@g.com"], 2)
116 self.assertTrue(counters["r=x@g.com"] + counters["r=y@g.com"], 20)
117 counters = self._collect_reviewers(20, "external/rust/crates/p_all")
118 # {x, y, z} reviewers should be sorted
119 self.assertEqual(counters["r=x@g.com,r=y@g.com,r=z@g"], 20)
120
121 def test_weighted_reviewers(self):
Thiébaud Weksteen4ac289b2020-09-28 15:23:29 +0200122 """Test create_rust_reviewer_list."""
Chih-Hung Hsiehaa485552020-08-20 15:45:09 -0700123 reviewers.PROJ_REVIEWERS = {
124 "any_p1": "x@g", # 1 for x@g
125 "any_p2": {"xyz", "x@g"}, # 1 for x@g, xyz is not a rust reviewer
126 "any_p3": {"abc", "x@g"}, # 0.5 for "abc" and "x@g"
127 }
128 reviewers.RUST_REVIEWERS = {
129 "x@g": 5, # ceil(5 - 2.5) = 3
130 "abc": 2, # ceil(2 - 0.5) = 2
131 }
132 reviewer_list = reviewers.create_rust_reviewer_list()
133 self.assertEqual(reviewer_list, ["x@g", "x@g", "x@g", "abc", "abc"])
134 # Error case: if nobody has project quota, reset everyone to 1.
135 reviewers.RUST_REVIEWERS = {
136 "x@g": 1, # ceil(1 - 2.5) = -1
137 "abc": 0, # ceil(0 - 0.5) = 0
138 }
139 reviewer_list = reviewers.create_rust_reviewer_list()
140 self.assertEqual(reviewer_list, ["x@g", "abc"]) # everyone got 1
141
142
143if __name__ == "__main__":
144 unittest.main(verbosity=2)