Skip to content
Bitcoin Roots

v29.4-roots.4 · Commit 8: [PATCH 08/37] ci: restore assurance and isolate Core fixtures

ci/test/test_change_classifier.py

Before: /dev/null · After: ci/test/test_change_classifier.py

File metadata
new file mode 100755
index 0000000000000000000000000000000000000000..3d8f363de2c7be1363d42907aab7be09dbc02a29

Download original patch · Release notes

Diff rows 1–90 of 90. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.

ci/test/test_change_classifier.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Regression fixtures for ci/change-classifier.py."""
3
+
4
+ import contextlib
5
+ import importlib.util
6
+ import io
7
+ import json
8
+ import pathlib
9
+ import sys
10
+ import tempfile
11
+ import unittest
12
+ from unittest import mock
13
+
14
+
15
+ CI_ROOT = pathlib.Path(__file__).resolve().parents[1]
16
+ SCRIPT = CI_ROOT / "change-classifier.py"
17
+ POLICY = CI_ROOT / "change-classifier-policy.json"
18
+ FIXTURES = pathlib.Path(__file__).with_name("fixtures") / "change-classifier.json"
19
+ SPEC = importlib.util.spec_from_file_location("change_classifier", SCRIPT)
20
+ MODULE = importlib.util.module_from_spec(SPEC)
21
+ SPEC.loader.exec_module(MODULE)
22
+
23
+
24
+ class ChangeClassifierTest(unittest.TestCase):
25
+ @classmethod
26
+ def setUpClass(cls):
27
+ cls.policy = json.loads(POLICY.read_text(encoding="utf-8"))
28
+
29
+ def test_fixtures(self):
30
+ for fixture in json.loads(FIXTURES.read_text(encoding="utf-8")):
31
+ with self.subTest(fixture=fixture["name"]):
32
+ result = MODULE.result_for(
33
+ fixture["files"], fixture["labels"],
34
+ fixture.get("truncated", False), fixture.get("error", False),
35
+ self.policy)
36
+ self.assertEqual(fixture["expected"], {key: result[key] for key in fixture["expected"]})
37
+
38
+ def test_github_output_is_stable(self):
39
+ result = MODULE.result_for(["README.md"], ["ci:fuzz"], False, False, self.policy)
40
+ self.assertEqual(result["labels"], ["ci:fuzz"])
41
+ self.assertTrue(result["selected"]["fuzz"])
42
+ with tempfile.TemporaryDirectory() as temporary_directory:
43
+ output = pathlib.Path(temporary_directory) / "github-output"
44
+ MODULE.write_github_output(result, output)
45
+ self.assertEqual(
46
+ output.read_text(encoding="utf-8"),
47
+ "baseline=true\ncompat=false\ndocs=true\nfuzz=true\ngui=false\n"
48
+ "nightly_full=false\nnightly_fuzz=true\nnightly_platforms=false\nnightly_sanitizers=false\nplatforms=false\nsanitizers=false\nwallet=false\nbroad=false\n"
49
+ "complete=true\ncategories=[\"docs-only\"]\nlabels=[\"ci:fuzz\"]\n"
50
+ "result={\"broad\":false,\"categories\":[\"docs-only\"],\"complete\":true,"
51
+ "\"labels\":[\"ci:fuzz\"],\"selected\":{\"baseline\":true,\"compat\":false,"
52
+ "\"docs\":true,\"fuzz\":true,\"gui\":false,\"nightly_full\":false,\"nightly_fuzz\":true,\"nightly_platforms\":false,\"nightly_sanitizers\":false,\"platforms\":false,"
53
+ "\"sanitizers\":false,\"wallet\":false},\"version\":1}\n")
54
+
55
+ def test_full_label_selects_reusable_nightly_assurance(self):
56
+ result = MODULE.result_for(["README.md"], ["ci:full"], False, False, self.policy)
57
+ self.assertTrue(result["selected"]["nightly_full"])
58
+ self.assertFalse(any(result["selected"][name] for name in (
59
+ "nightly_sanitizers", "nightly_fuzz", "nightly_platforms")))
60
+
61
+ def test_individual_extended_labels_select_their_nightly_groups(self):
62
+ for label, selection in (("ci:sanitizers", "nightly_sanitizers"),
63
+ ("ci:fuzz", "nightly_fuzz"),
64
+ ("ci:platforms", "nightly_platforms")):
65
+ with self.subTest(label=label):
66
+ result = MODULE.result_for(["README.md"], [label], False, False, self.policy)
67
+ self.assertTrue(result["selected"][selection])
68
+
69
+ def test_invalid_policy_fails_open_and_restores_path(self):
70
+ original_policy_path = MODULE.POLICY_PATH
71
+ with tempfile.TemporaryDirectory() as temporary_directory:
72
+ policy_path = pathlib.Path(temporary_directory) / "invalid-policy.json"
73
+ policy_path.write_text("{}", encoding="utf-8")
74
+ output = io.StringIO()
75
+ try:
76
+ MODULE.POLICY_PATH = policy_path
77
+ with mock.patch.object(sys, "argv", [str(SCRIPT), "--files-json", '["README.md"]']):
78
+ with contextlib.redirect_stdout(output):
79
+ MODULE.main()
80
+ finally:
81
+ MODULE.POLICY_PATH = original_policy_path
82
+ result = json.loads(output.getvalue())
83
+ self.assertEqual(MODULE.POLICY_PATH, original_policy_path)
84
+ self.assertTrue(result["broad"])
85
+ self.assertFalse(result["complete"])
86
+ self.assertEqual(result["categories"], ["unknown"])
87
+
88
+
89
+ if __name__ == "__main__":
90
+ unittest.main()