Viewing files at commit bd39a563b7f5Commit detailsView latest

Browse files
tests/test_gitserver.py 128 lines · 5.0 KB · python
1
"""REAL tests for the stdlib smart-HTTP git server: serve a temp repo, clone
2
it with the actual git CLI, push a commit back, and observe protocol v2
3
passing through. This is the piece of the netshape slice the macOS dev host
4
can exercise for real."""
5
6
from __future__ import annotations
7
8
import os
9
import shutil
10
import subprocess
11
import sys
12
import tempfile
13
import unittest
14
from pathlib import Path
15
16
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
17
18
from oakbench.environment import base_env
19
from oakbench.gitserver import GitHTTPServer
20
21
GIT = shutil.which("git")
22
23
24
def run_git(args: list[str], cwd: Path | None = None) -> subprocess.CompletedProcess:
25
    return subprocess.run(
26
        [GIT, *args],
27
        cwd=cwd,
28
        env=base_env(),
29
        stdout=subprocess.PIPE,
30
        stderr=subprocess.PIPE,
31
        text=True,
32
        timeout=120,
33
        check=False,
34
    )
35
36
37
@unittest.skipIf(GIT is None, "git binary not installed")
38
class GitHTTPServerTest(unittest.TestCase):
39
    def setUp(self) -> None:
40
        self.tmp = Path(tempfile.mkdtemp(prefix="oak-gitserver-test-"))
41
        self.addCleanup(shutil.rmtree, self.tmp, True)
42
43
        src = self.tmp / "src"
44
        run_git(["-c", "init.defaultBranch=main", "init", str(src)])
45
        (src / "README.md").write_text("# gitserver fixture\n")
46
        run_git(["add", "-A"], cwd=src)
47
        commit = run_git(["commit", "-m", "fixture commit"], cwd=src)
48
        self.assertEqual(commit.returncode, 0, commit.stderr)
49
50
        self.served_root = self.tmp / "served"
51
        self.served_root.mkdir()
52
        self.bare = self.served_root / "repo.git"
53
        run_git(["clone", "--bare", str(src), str(self.bare)])
54
        # Push over http works only when the served repo opts in.
55
        run_git(["-C", str(self.bare), "config", "http.receivepack", "true"])
56
57
        self.server = GitHTTPServer(self.served_root).start()
58
        self.addCleanup(self.server.stop)
59
        self.repo_url = f"{self.server.url}/repo.git"
60
61
    def test_clone_succeeds_and_logs_smart_paths(self) -> None:
62
        dest = self.tmp / "clone"
63
        result = run_git(["clone", self.repo_url, str(dest)])
64
        self.assertEqual(result.returncode, 0, result.stderr)
65
        self.assertEqual((dest / "README.md").read_text(), "# gitserver fixture\n")
66
        self.assertTrue(
67
            any(
68
                "/repo.git/info/refs" in entry and "service=git-upload-pack" in entry
69
                for entry in self.server.request_log
70
            ),
71
            self.server.request_log,
72
        )
73
74
    def test_push_over_http_succeeds(self) -> None:
75
        dest = self.tmp / "pusher"
76
        clone = run_git(["clone", self.repo_url, str(dest)])
77
        self.assertEqual(clone.returncode, 0, clone.stderr)
78
        (dest / "delta.txt").write_text("pushed over http\n")
79
        run_git(["add", "-A"], cwd=dest)
80
        commit = run_git(["commit", "-m", "small delta"], cwd=dest)
81
        self.assertEqual(commit.returncode, 0, commit.stderr)
82
        local_head = run_git(["rev-parse", "HEAD"], cwd=dest).stdout.strip()
83
84
        push = run_git(["push", "origin", "main"], cwd=dest)
85
        self.assertEqual(push.returncode, 0, push.stderr)
86
        served_head = run_git(["-C", str(self.bare), "rev-parse", "main"]).stdout.strip()
87
        self.assertEqual(served_head, local_head)
88
        self.assertTrue(
89
            any("git-receive-pack" in entry for entry in self.server.request_log),
90
            self.server.request_log,
91
        )
92
93
    def test_push_refused_without_receivepack_optin(self) -> None:
94
        run_git(["-C", str(self.bare), "config", "--unset", "http.receivepack"])
95
        dest = self.tmp / "refused"
96
        clone = run_git(["clone", self.repo_url, str(dest)])
97
        self.assertEqual(clone.returncode, 0, clone.stderr)
98
        (dest / "delta.txt").write_text("should be refused\n")
99
        run_git(["add", "-A"], cwd=dest)
100
        run_git(["commit", "-m", "refused delta"], cwd=dest)
101
        push = run_git(["push", "origin", "main"], cwd=dest)
102
        self.assertNotEqual(push.returncode, 0)
103
104
    def test_protocol_v2_header_passes_through(self) -> None:
105
        dest = self.tmp / "clone-v2"
106
        result = run_git(["-c", "protocol.version=2", "clone", self.repo_url, str(dest)])
107
        self.assertEqual(result.returncode, 0, result.stderr)
108
        self.assertTrue(
109
            any("version=2" in value for value in self.server.git_protocol_headers),
110
            self.server.git_protocol_headers,
111
        )
112
113
    def test_url_requires_started_server(self) -> None:
114
        stopped = GitHTTPServer(self.served_root)
115
        with self.assertRaises(RuntimeError):
116
            _ = stopped.url
117
118
    def test_missing_repo_is_a_client_error_not_a_crash(self) -> None:
119
        dest = self.tmp / "missing"
120
        result = run_git(["clone", f"{self.server.url}/nope.git", str(dest)])
121
        self.assertNotEqual(result.returncode, 0)
122
        # Server is still healthy afterwards.
123
        ok = run_git(["clone", self.repo_url, str(self.tmp / "still-works")])
124
        self.assertEqual(ok.returncode, 0, ok.stderr)
125
126
127
if __name__ == "__main__":
128
    unittest.main()