Viewing files at commit b297e8a25d08Commit detailsView latest

Browse files
tests/test_remotes.py 168 lines · 7.2 KB · python
1
"""Tests for shared remote plumbing: resolution, skip reasons, branch names."""
2
3
from __future__ import annotations
4
5
import os
6
import subprocess
7
import sys
8
import tempfile
9
import unittest
10
from pathlib import Path
11
from unittest import mock
12
13
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
14
15
from oakbench import remotes
16
17
18
class ResolveOakRemoteTest(unittest.TestCase):
19
    def test_purpose_scoped_env_wins(self) -> None:
20
        env = {"OAK_BENCH_FLEET_REPO": "oak/bench-fleet-tmp", "OAK_BENCH_REMOTE": "oak/other"}
21
        with mock.patch.dict(os.environ, env, clear=False):
22
            res = remotes.resolve_oak_remote("fleet")
23
        self.assertTrue(res.resolved)
24
        self.assertEqual(res.repo, "oak/bench-fleet-tmp")
25
        self.assertEqual(res.env_var, "OAK_BENCH_FLEET_REPO")
26
        self.assertEqual(res.transport, remotes.TRANSPORT_NETWORK)
27
28
    def test_falls_back_to_generic_remote(self) -> None:
29
        env = {"OAK_BENCH_REMOTE": "oak/oak-benchmarks-tmp"}
30
        with mock.patch.dict(os.environ, env, clear=False):
31
            os.environ.pop("OAK_BENCH_SYNC_REPO", None)
32
            res = remotes.resolve_oak_remote("sync")
33
        self.assertTrue(res.resolved)
34
        self.assertEqual(res.repo, "oak/oak-benchmarks-tmp")
35
        self.assertEqual(res.env_var, "OAK_BENCH_REMOTE")
36
37
    def test_mirror_does_not_fall_back_to_generic_remote(self) -> None:
38
        env = {"OAK_BENCH_REMOTE": "oak/tiny-disposable"}
39
        with mock.patch.dict(os.environ, env, clear=False):
40
            os.environ.pop("OAK_BENCH_MIRROR_REPO", None)
41
            res = remotes.resolve_oak_remote("mirror")
42
        self.assertFalse(res.resolved)
43
        self.assertEqual(res.env_var, "OAK_BENCH_MIRROR_REPO")
44
        self.assertIn("OAK_BENCH_MIRROR_REPO", res.skip_reason)
45
46
    def test_mirror_scoped_env_resolves(self) -> None:
47
        env = {
48
            "OAK_BENCH_MIRROR_REPO": "oak/bench-large-mirror",
49
            "OAK_BENCH_REMOTE": "oak/tiny-disposable",
50
        }
51
        with mock.patch.dict(os.environ, env, clear=False):
52
            res = remotes.resolve_oak_remote("mirror")
53
        self.assertTrue(res.resolved)
54
        self.assertEqual(res.repo, "oak/bench-large-mirror")
55
        self.assertEqual(res.env_var, "OAK_BENCH_MIRROR_REPO")
56
57
    def test_unresolved_names_the_scoped_env_var(self) -> None:
58
        with mock.patch.dict(os.environ, {}, clear=False):
59
            for var in ("OAK_BENCH_SYNC_REPO", "OAK_BENCH_REMOTE"):
60
                os.environ.pop(var, None)
61
            res = remotes.resolve_oak_remote("sync")
62
        self.assertFalse(res.resolved)
63
        self.assertIn("OAK_BENCH_SYNC_REPO", res.skip_reason)
64
        with self.assertRaises(ValueError):
65
            res.row_fields()
66
67
    def test_row_fields_carry_transport_honesty(self) -> None:
68
        env = {"OAK_BENCH_REMOTE": "oak/bench-sync-tmp"}
69
        with mock.patch.dict(os.environ, env, clear=False):
70
            os.environ.pop("OAK_BENCH_SYNC_REPO", None)
71
            os.environ.pop("OAK_SERVER", None)
72
            fields = remotes.resolve_oak_remote("sync").row_fields()
73
        self.assertEqual(
74
            fields,
75
            {
76
                "remote_repo": "oak/bench-sync-tmp",
77
                "remote_transport": "network",
78
                "remote_server": "oak.space",
79
            },
80
        )
81
82
83
class RemotePreflightTest(unittest.TestCase):
84
    def test_reports_missing_env_vars_and_affected_operations(self) -> None:
85
        requirements = [
86
            remotes.RemoteRequirement("sync", "workflow", ("sync_push_divergence/workflow.skipped",)),
87
            remotes.RemoteRequirement("fleet", "contention", ("contention_workspace_per_task_w8/parallel.total",)),
88
        ]
89
90
        warnings = remotes.oak_remote_preflight_warnings(requirements, env={})
91
        by_env = {warning.env_var: warning for warning in warnings}
92
93
        self.assertIn("OAK_BENCH_SYNC_REPO", by_env)
94
        self.assertIn("OAK_BENCH_FLEET_REPO", by_env)
95
        self.assertIn("sync_push_divergence", by_env["OAK_BENCH_SYNC_REPO"].operations[0])
96
        lines = remotes.format_remote_preflight_warnings(warnings)
97
        self.assertTrue(any("OAK_BENCH_FLEET_REPO" in line for line in lines))
98
99
    def test_generic_oak_remote_satisfies_sync_and_fleet_preflight(self) -> None:
100
        requirements = [
101
            remotes.RemoteRequirement("sync", "workflow", ("sync_pull_upstream/workflow.skipped",)),
102
            remotes.RemoteRequirement("fleet", "contention", ("contention_workspace_per_task_w2/parallel.total",)),
103
        ]
104
        warnings = remotes.oak_remote_preflight_warnings(
105
            requirements,
106
            env={"OAK_BENCH_REMOTE": "oak/bench-disposable"},
107
        )
108
        self.assertEqual(warnings, [])
109
110
111
class ResolveGitGithubRemoteTest(unittest.TestCase):
112
    def test_unset_yields_skip_reason(self) -> None:
113
        with mock.patch.dict(os.environ, {}, clear=False):
114
            os.environ.pop("GIT_BENCH_REMOTE", None)
115
            res = remotes.resolve_git_github_remote()
116
        self.assertFalse(res.resolved)
117
        self.assertIn("GIT_BENCH_REMOTE", res.skip_reason)
118
119
    def test_https_url_server_parsed(self) -> None:
120
        env = {"GIT_BENCH_REMOTE": "https://github.com/oakdotspace/bench-task-loop-tmp.git"}
121
        with mock.patch.dict(os.environ, env, clear=False):
122
            res = remotes.resolve_git_github_remote()
123
        self.assertEqual(res.server, "github.com")
124
        self.assertEqual(res.transport, remotes.TRANSPORT_NETWORK)
125
126
    def test_ssh_url_server_parsed(self) -> None:
127
        env = {"GIT_BENCH_REMOTE": "[email protected]:oakdotspace/bench-task-loop-tmp.git"}
128
        with mock.patch.dict(os.environ, env, clear=False):
129
            res = remotes.resolve_git_github_remote()
130
        self.assertEqual(res.server, "github.com")
131
132
133
class GitBareRemoteTest(unittest.TestCase):
134
    def test_creates_bare_repo_with_local_file_transport(self) -> None:
135
        with tempfile.TemporaryDirectory() as tmp:
136
            res = remotes.make_git_bare_remote("git", Path(tmp))
137
            self.assertTrue(res.resolved)
138
            self.assertEqual(res.transport, remotes.TRANSPORT_LOCAL_FILE)
139
            self.assertEqual(res.server, "local")
140
            probe = subprocess.run(
141
                ["git", "rev-parse", "--is-bare-repository"],
142
                cwd=res.repo,
143
                capture_output=True,
144
                text=True,
145
            )
146
            self.assertEqual(probe.stdout.strip(), "true")
147
148
149
class DisposableBranchTest(unittest.TestCase):
150
    def test_deterministic_with_explicit_uniquifiers(self) -> None:
151
        name = remotes.disposable_branch("b1", "scn", "oak", 3, pid=0xAB, token="ffff")
152
        self.assertEqual(name, "bench-b1-scn-oak-r3-ab-ffff")
153
154
    def test_collision_safe_across_calls(self) -> None:
155
        names = {remotes.disposable_branch("b1", "scn", "oak", 1) for _ in range(50)}
156
        self.assertEqual(len(names), 50)
157
158
    def test_matches_bench_py_legacy_shape(self) -> None:
159
        # ADR-0005: the lift must be name-identical to bench.py's scheme.
160
        import bench
161
162
        legacy = bench.oak_network_branch_name("id", "core", "oak_installed", 2, pid=0x10, token="dead")
163
        shared = remotes.disposable_branch("id", "core", "oak_installed", 2, pid=0x10, token="dead")
164
        self.assertEqual(legacy, shared)
165
166
167
if __name__ == "__main__":
168
    unittest.main()