forge
ExploreLog in

Tahinli/forge

public
0 watching
★ 0
4.7 KiB
1use std::path::{Path, PathBuf};
2use std::process::Command;
3
4use forge_git::command::{GitCommand, GitEnv};
5use forge_git::pktline::{FLUSH_PKT, pkt_line, service_advertisement_header};
6use forge_git::repo::{init_bare, list_branches, repo_path};
7use forge_git::service::{GitService, service_command};
8use forge_git::setup::{write_hook_shims, write_managed_gitconfig};
9use forge_git::version::parse_git_version;
10
11fn env_for(data_dir: &Path) -> GitEnv {
12 GitEnv {
13 git_bin: PathBuf::from("/usr/bin/git"),
14 data_dir: data_dir.to_path_buf(),
15 }
16}
17
18const ULID: &str = "01arz3ndektsv4rrffq69g5fav";
19
20#[test]
21fn version_parse() {
22 assert_eq!(parse_git_version("git version 2.56.0\n"), Some((2, 56, 0)));
23 assert_eq!(
24 parse_git_version("git version 2.39.2.windows.1"),
25 Some((2, 39, 2))
26 );
27 assert_eq!(parse_git_version("git version 2.46"), Some((2, 46, 0)));
28 assert_eq!(
29 parse_git_version("git version 2.46.0-rc1"),
30 Some((2, 46, 0))
31 );
32 assert_eq!(parse_git_version("garbage"), None);
33}
34
35#[test]
36fn pkt_line_encoding() {
37 assert_eq!(pkt_line("a\n"), b"0006a\n".to_vec());
38 assert_eq!(pkt_line(""), b"0004".to_vec());
39 assert_eq!(FLUSH_PKT, b"0000");
40 let header = service_advertisement_header(GitService::UploadPack);
41 assert_eq!(header, b"001e# service=git-upload-pack\n0000".to_vec());
42}
43
44#[test]
45fn repo_path_layout() {
46 let p = repo_path(Path::new("/data"), &ULID.to_uppercase()).unwrap();
47 assert_eq!(p, PathBuf::from(format!("/data/repos/01/ar/{ULID}.git")));
48 assert!(repo_path(Path::new("/data"), "not-a-ulid").is_err());
49 assert!(repo_path(Path::new("/data"), "01arz3ndektsv4rrffq69g5fa").is_err());
50 assert!(repo_path(Path::new("/data"), "01arz3ndektsv4rrffq69g5fau").is_err());
51}
52
53#[tokio::test]
54async fn init_bare_and_list_branches_empty() {
55 let dir = tempfile::tempdir().unwrap();
56 let env = env_for(dir.path());
57 let repo = repo_path(dir.path(), ULID).unwrap();
58 init_bare(&env, &repo, "trunk").await.unwrap();
59 assert!(repo.join("HEAD").exists());
60 let branches = list_branches(&env, &repo).await.unwrap();
61 assert!(branches.is_empty());
62}
63
64#[tokio::test]
65async fn init_bare_rejects_bad_branch() {
66 let dir = tempfile::tempdir().unwrap();
67 let env = env_for(dir.path());
68 let repo = dir.path().join("x.git");
69 assert!(init_bare(&env, &repo, "-x").await.is_err());
70 assert!(init_bare(&env, &repo, "a..b").await.is_err());
71 assert!(!repo.exists());
72}
73
74#[test]
75fn user_revs_rejects_option_like_values() {
76 let dir = tempfile::tempdir().unwrap();
77 let env = env_for(dir.path());
78 assert!(GitCommand::new(&env, "log").user_revs(&["-x"]).is_err());
79 assert!(GitCommand::new(&env, "log").user_revs(&[""]).is_err());
80 assert!(GitCommand::new(&env, "log").user_revs(&["main"]).is_ok());
81}
82
83#[test]
84fn gitconfig_is_written() {
85 let dir = tempfile::tempdir().unwrap();
86 write_managed_gitconfig(dir.path()).unwrap();
87 let cfg = dir.path().join("gitconfig");
88 let out = Command::new("/usr/bin/git")
89 .args(["config", "--file"])
90 .arg(&cfg)
91 .args(["--get", "core.hooksPath"])
92 .output()
93 .unwrap();
94 assert!(out.status.success());
95 let hooks = String::from_utf8_lossy(&out.stdout);
96 assert_eq!(hooks.trim(), dir.path().join("hooks").to_str().unwrap());
97
98 let out = Command::new("/usr/bin/git")
99 .args(["config", "--file"])
100 .arg(&cfg)
101 .args(["--get", "receive.denyNonFastForwards"])
102 .output()
103 .unwrap();
104 assert_eq!(String::from_utf8_lossy(&out.stdout).trim(), "false");
105}
106
107#[test]
108fn hook_shims_are_executable() {
109 use std::os::unix::fs::PermissionsExt;
110 let dir = tempfile::tempdir().unwrap();
111 write_hook_shims(dir.path(), Path::new("/usr/local/bin/forge")).unwrap();
112 for name in ["pre-receive", "post-receive"] {
113 let p = dir.path().join("hooks").join(name);
114 let mode = std::fs::metadata(&p).unwrap().permissions().mode();
115 assert_eq!(mode & 0o777, 0o755, "{name}");
116 let body = std::fs::read_to_string(&p).unwrap();
117 assert_eq!(
118 body,
119 format!("#!/bin/sh\nexec '/usr/local/bin/forge' hook {name}\n")
120 );
121 }
122 assert!(write_hook_shims(dir.path(), Path::new("/tmp/it's")).is_err());
123 assert!(write_hook_shims(dir.path(), Path::new("/tmp/a\nb")).is_err());
124}
125
126#[tokio::test]
127async fn upload_pack_advertise_exits_zero() {
128 let dir = tempfile::tempdir().unwrap();
129 let env = env_for(dir.path());
130 let repo = repo_path(dir.path(), ULID).unwrap();
131 init_bare(&env, &repo, "main").await.unwrap();
132 service_command(&env, GitService::UploadPack, &repo, true, true, None)
133 .status()
134 .await
135 .unwrap();
136}