Skip to content
Bitcoin Roots

v29.4-roots.4 · Commit 22: [PATCH 22/37] ci: consolidate sanitizer and apt workflows

ci/test/test_apt_refresh.py

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

File metadata
new file mode 100644
index 0000000000000000000000000000000000000000..ddf581675359c2b686f10021dc402e747cbe557b

Download original patch · Release notes

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

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.

ci/test/test_apt_refresh.py ADDED
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env python3
2
+ """Regression tests for strict, retried APT index refreshes in Linux CI."""
3
+
4
+ import os
5
+ import pathlib
6
+ import re
7
+ import subprocess
8
+ import tempfile
9
+ import unittest
10
+
11
+
12
+ CI_TEST_ROOT = pathlib.Path(__file__).resolve().parent
13
+ CI_ROOT = CI_TEST_ROOT.parent
14
+ APT_HELPER = CI_TEST_ROOT / "apt.sh"
15
+ CI_IMAGEFILE = CI_TEST_ROOT.parent / "test_imagefile"
16
+ LINT_IMAGEFILE = CI_ROOT / "lint_imagefile"
17
+ LINT_INSTALL = CI_ROOT / "lint" / "04_install.sh"
18
+ REFRESH_CALLERS = [
19
+ CI_TEST_ROOT / "01_base_install.sh",
20
+ CI_TEST_ROOT / "03_test_script.sh",
21
+ ]
22
+
23
+
24
+ class AptRefreshTest(unittest.TestCase):
25
+ def test_refresh_callers_use_the_shared_strict_helper(self):
26
+ helper = APT_HELPER.read_text(encoding="utf-8")
27
+ self.assertIn('APT::Update::Error-Mode=any update', helper)
28
+ self.assertIn('"${retry_command[@]}" apt-get', helper)
29
+ self.assertIn('./ci/test/apt.sh', CI_IMAGEFILE.read_text(encoding="utf-8"))
30
+ self.assertIn('./ci/test/apt.sh', LINT_IMAGEFILE.read_text(encoding="utf-8"))
31
+
32
+ for caller in REFRESH_CALLERS:
33
+ with self.subTest(caller=caller):
34
+ contents = caller.read_text(encoding="utf-8")
35
+ self.assertIn('source "$(dirname "${BASH_SOURCE[0]}")/apt.sh"', contents)
36
+ self.assertIn('ci_retry_apt_update', contents)
37
+ self.assertNotIn('apt-get update', contents)
38
+ self.assertNotIn('APT::Update::Error-Mode=any update', contents)
39
+
40
+ lint_install = LINT_INSTALL.read_text(encoding="utf-8")
41
+ self.assertIn('source /ci/test/apt.sh', lint_install)
42
+ self.assertIn('ci_retry_apt_update', lint_install)
43
+
44
+ refresh_pattern = re.compile(r"\bapt-get\b.*\bupdate\b")
45
+ for script in CI_ROOT.rglob("*.sh"):
46
+ matches = refresh_pattern.findall(script.read_text(encoding="utf-8"))
47
+ with self.subTest(script=script):
48
+ if script == APT_HELPER:
49
+ self.assertEqual(matches, ['apt-get -o APT::Update::Error-Mode=any update'])
50
+ else:
51
+ self.assertEqual(matches, [])
52
+
53
+ def test_invalid_repository_failure_is_retried_and_propagated(self):
54
+ with tempfile.TemporaryDirectory() as temporary_directory:
55
+ temporary_path = pathlib.Path(temporary_directory)
56
+ attempts = temporary_path / "attempts"
57
+ retry = temporary_path / "retry"
58
+ apt_get = temporary_path / "apt-get"
59
+ retry.write_text(
60
+ "#!/usr/bin/env bash\n"
61
+ "set -u\n"
62
+ "test \"$1\" = --\n"
63
+ "shift\n"
64
+ "for attempt in 1 2 3; do\n"
65
+ " \"$@\" || status=$?\n"
66
+ " test \"${status:-0}\" -eq 0 && exit 0\n"
67
+ "done\n"
68
+ "exit \"$status\"\n",
69
+ encoding="utf-8",
70
+ )
71
+ apt_get.write_text(
72
+ "#!/usr/bin/env bash\n"
73
+ "set -u\n"
74
+ "printf '%s\\n' \"$*\" >> \"$APT_ATTEMPTS\"\n"
75
+ "exit 100\n",
76
+ encoding="utf-8",
77
+ )
78
+ retry.chmod(0o755)
79
+ apt_get.chmod(0o755)
80
+
81
+ environment = os.environ | {
82
+ "APT_ATTEMPTS": str(attempts),
83
+ "CI_RETRY_EXE": f"{retry} --",
84
+ "PATH": f"{temporary_path}{os.pathsep}{os.environ['PATH']}",
85
+ }
86
+ result = subprocess.run(
87
+ ["bash", "-c", f'source "{APT_HELPER}"; ci_retry_apt_update'],
88
+ check=False,
89
+ env=environment,
90
+ )
91
+
92
+ self.assertEqual(result.returncode, 100)
93
+ self.assertEqual(
94
+ attempts.read_text(encoding="utf-8").splitlines(),
95
+ ['-o APT::Update::Error-Mode=any update'] * 3,
96
+ )
97
+
98
+
99
+ if __name__ == "__main__":
100
+ unittest.main()