Allow multiple reviewers for a CL per project

* For a List of reviewers, one will be randomly selected.
* For a Set of reviewers, all will be selected.
* Add some unit tests for reviewers and fix some gpylint warnings.

Bug: 162988933
Test: out/.../bin/external_updater update --branch_and_commit --push_change <some_project>
Test: out/host/linux-x86/testcases/external_updater_test/x86_64/external_updater_test
Change-Id: I4fc226ed4a9fde59371f217a4f32545a9f694616
diff --git a/external_updater_test.py b/external_updater_test.py
index b834fed..32e2918 100644
--- a/external_updater_test.py
+++ b/external_updater_test.py
@@ -13,13 +13,16 @@
 # limitations under the License.
 """Unit tests for external updater."""
 
+from typing import List, Mapping, Set
 import unittest
 
 import github_archive_updater
+import reviewers
 
 
 class ExternalUpdaterTest(unittest.TestCase):
     """Unit tests for external updater."""
+
     def test_url_selection(self):
         """Tests that GithubArchiveUpdater can choose the right url."""
         prefix = "https://github.com/author/project/"
@@ -42,6 +45,63 @@
         expected_url = prefix + "archive/ver-1.0.zip"
         self.assertEqual(url, expected_url)
 
+    def collect_reviewers(self, num_runs, proj_path):
+        counters = {}
+        for _ in range(num_runs):
+            name = reviewers.find_reviewers(proj_path)
+            if name in counters:
+                counters[name] += 1
+            else:
+                counters[name] = 1
+        return counters
 
-if __name__ == '__main__':
+    def test_reviewers(self):
+        # There should be enough people in the reviewers pool.
+        self.assertGreaterEqual(len(reviewers.RUST_REVIEWERS), 3)
+        # Check element types of the reviewers list and map.
+        self.assertIsInstance(reviewers.RUST_REVIEWERS, List)
+        for x in reviewers.RUST_REVIEWERS:
+            self.assertIsInstance(x, str)
+        self.assertIsInstance(reviewers.PROJ_REVIEWERS, Mapping)
+        for key, value in reviewers.PROJ_REVIEWERS.items():
+            self.assertIsInstance(key, str)
+            if isinstance(value, Set) or isinstance(value, List):
+                for x in value:
+                    self.assertIsInstance(x, str)
+            else:
+                self.assertIsInstance(value, str)
+        # Check random selection of reviewers.
+        # This might fail when the random.choice function is extremely unfair.
+        # With N * 20 tries, each reviewer should be picked at least twice.
+        counters = self.collect_reviewers(len(reviewers.RUST_REVIEWERS) * 20,
+                                          "rust/crates/no_such_project")
+        self.assertEqual(len(counters), len(reviewers.RUST_REVIEWERS))
+        for key, value in counters.items():
+            self.assertGreaterEqual(value, 2)
+        # For specific projects, select only the specified reviewers.
+        saved_reviewers = reviewers.PROJ_REVIEWERS
+        reviewers.PROJ_REVIEWERS = {
+            "rust/crates/p1": "[email protected]",
+            "rust/crates/p_any": ["[email protected]", "[email protected]"],
+            "rust/crates/p_all": {"[email protected]", "[email protected]"},
+        }
+        counters = self.collect_reviewers(20, "external/rust/crates/p1")
+        self.assertEqual(len(counters), 1)
+        self.assertTrue(counters["[email protected]"], 20)
+        counters = self.collect_reviewers(20, "external/rust/crates/p_any")
+        self.assertEqual(len(counters), 2)
+        self.assertGreater(counters["[email protected]"], 2)
+        self.assertGreater(counters["[email protected]"], 2)
+        self.assertTrue(counters["[email protected]"] + counters["[email protected]"], 20)
+        counters = self.collect_reviewers(20, "external/rust/crates/p_all")
+        counted = 0
+        if "[email protected],[email protected]" in counters:
+            counted += counters["[email protected],[email protected]"]
+        if "[email protected],[email protected]" in counters:
+            counted += counters["[email protected],[email protected]"]
+        self.assertEqual(counted, 20)
+        reviewers.PROJ_REVIEWERS = saved_reviewers
+
+
+if __name__ == "__main__":
     unittest.main()