Skip to content

Commit 75aeef5

Browse files
authored
Merge pull request #399 from ahrav/feature/dedupe-git-test-helpers
Feature/dedupe git test helpers
2 parents db35448 + e893e9a commit 75aeef5

35 files changed

Lines changed: 506 additions & 714 deletions

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/gossip-orchestrator/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ scanner-git.workspace = true
1515
thiserror = { workspace = true }
1616

1717
[dev-dependencies]
18+
gossip-stdx = { workspace = true, features = ["git-test-support"] }
1819
tempfile = "3"

crates/gossip-orchestrator/src/git_payload.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,7 +1227,7 @@ mod tests {
12271227

12281228
use super::*;
12291229
use crate::git_request::{GitRequest, GitRequestSelection, GitRequestTarget};
1230-
use crate::test_support::{init_git_repo, run_config, run_git_in};
1230+
use crate::test_support::{init_git_repo, run_config, run_git};
12311231

12321232
fn tenant(byte: u8) -> TenantId {
12331233
TenantId::from_bytes([byte; 32])
@@ -1470,8 +1470,8 @@ mod tests {
14701470
let dir = tempdir().expect("tempdir");
14711471
init_repo(dir.path());
14721472
fs::write(dir.path().join("tracked.txt"), "v1\n").expect("write tracked file");
1473-
run_git_in(dir.path(), &["add", "."]);
1474-
run_git_in(dir.path(), &["commit", "-m", "first"]);
1473+
run_git(dir.path(), &["add", "."]);
1474+
run_git(dir.path(), &["commit", "-m", "first"]);
14751475
let commit = current_commit_oid(dir.path());
14761476

14771477
let (_, payload) = payload_from_request(
@@ -1508,8 +1508,8 @@ mod tests {
15081508
let dir = tempdir().expect("tempdir");
15091509
init_repo(dir.path());
15101510
fs::write(dir.path().join("tracked.txt"), "v1\n").expect("write tracked file");
1511-
run_git_in(dir.path(), &["add", "."]);
1512-
run_git_in(dir.path(), &["commit", "-m", "first"]);
1511+
run_git(dir.path(), &["add", "."]);
1512+
run_git(dir.path(), &["commit", "-m", "first"]);
15131513
let commit = current_commit_oid(dir.path());
15141514

15151515
let (_, payload) = payload_from_request(
@@ -1552,7 +1552,7 @@ mod tests {
15521552
fn lowering_explicit_commit_rejects_missing_commit() {
15531553
let dir = tempdir().expect("tempdir");
15541554
init_repo(dir.path());
1555-
run_git_in(dir.path(), &["commit", "--allow-empty", "-m", "first"]);
1555+
run_git(dir.path(), &["commit", "--allow-empty", "-m", "first"]);
15561556

15571557
let (_, payload) = payload_from_request(
15581558
GitRequest::repo_with_explicit_commit(

crates/gossip-orchestrator/src/git_request.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,7 @@ mod tests {
782782
use tempfile::tempdir;
783783

784784
use super::*;
785-
use crate::test_support::{init_git_repo, run_config, run_git_in};
785+
use crate::test_support::{init_committed_repo, init_git_repo, run_config};
786786

787787
fn tenant(byte: u8) -> TenantId {
788788
TenantId::from_bytes([byte; 32])
@@ -792,11 +792,8 @@ mod tests {
792792
init_git_repo(dir, "git-request-tests@example.com", "Git Request Tests");
793793
}
794794

795-
fn init_committed_repo(dir: &Path) {
796-
init_repo(dir);
797-
fs::write(dir.join("fixture.txt"), "fixture").expect("write fixture");
798-
run_git_in(dir, &["add", "."]);
799-
run_git_in(dir, &["commit", "-q", "-m", "fixture"]);
795+
fn init_committed(dir: &Path) {
796+
init_committed_repo(dir, "git-request-tests@example.com", "Git Request Tests");
800797
}
801798

802799
fn default_scan_mode() -> GitScanMode {
@@ -1060,7 +1057,7 @@ mod tests {
10601057
#[test]
10611058
fn request_debug_redacts_repo_path_refs_commit_and_display_name() {
10621059
let dir = tempdir().expect("tempdir");
1063-
init_committed_repo(dir.path());
1060+
init_committed(dir.path());
10641061

10651062
let refs_request = GitRequest::new(
10661063
tenant(0x90),
@@ -1096,7 +1093,7 @@ mod tests {
10961093
#[test]
10971094
fn normalized_debug_redacts_repo_path_refs_commit_and_display_name() {
10981095
let dir = tempdir().expect("tempdir");
1099-
init_committed_repo(dir.path());
1096+
init_committed(dir.path());
11001097

11011098
let refs_request = GitRequest::new(
11021099
tenant(0x91),
Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,11 @@
11
//! Shared test fixtures for the orchestrator crate.
22
3-
use std::path::Path;
4-
use std::process::Command;
5-
63
use gossip_coordination::{CursorSemantics, RunConfig};
74

5+
pub(crate) use gossip_stdx::git_test_support::{init_committed_repo, init_git_repo, run_git};
6+
87
/// Default run configuration for orchestrator unit tests.
98
pub(crate) fn run_config() -> RunConfig {
109
RunConfig::try_new(CursorSemantics::Completed, 30_000, Some(5))
1110
.expect("run config should be valid")
1211
}
13-
14-
pub(crate) fn run_git_in(dir: &Path, args: &[&str]) {
15-
let output = Command::new("git")
16-
.arg("-C")
17-
.arg(dir)
18-
.args(args)
19-
.output()
20-
.expect("run git command");
21-
assert!(
22-
output.status.success(),
23-
"git command failed: git -C {} {}\nstdout:{}\nstderr:{}",
24-
dir.display(),
25-
args.join(" "),
26-
String::from_utf8_lossy(&output.stdout),
27-
String::from_utf8_lossy(&output.stderr),
28-
);
29-
}
30-
31-
pub(crate) fn init_git_repo(dir: &Path, email: &str, name: &str) {
32-
run_git_in(dir, &["init", "-q", "-b", "main"]);
33-
run_git_in(dir, &["config", "user.email", email]);
34-
run_git_in(dir, &["config", "user.name", name]);
35-
}

crates/gossip-scanner-runtime/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ description = "Runtime orchestration APIs for scanner-rs direct and connector ex
99

1010
[features]
1111
default = []
12-
test-support = []
12+
test-support = ["gossip-stdx/git-test-support"]
1313
aegis-pure-rust = [
1414
"scanner-engine/aegis-pure-rust",
1515
"scanner-scheduler/aegis-pure-rust",
@@ -36,6 +36,7 @@ tracing.workspace = true
3636

3737
[dev-dependencies]
3838
gossip-persistence-inmemory.workspace = true
39+
gossip-stdx = { workspace = true, features = ["git-test-support"] }
3940
proptest.workspace = true
4041
rstest.workspace = true
4142
tempfile = "3"

crates/gossip-scanner-runtime/src/distributed/test_support.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ use crate::{
8080
git_persistence::{GitPersistenceBackend, GitPersistenceOp},
8181
join_scoped,
8282
ordered_content::OrderedContentSkipReason,
83-
test_fixtures::{init_git_repo, run_git_in},
83+
test_fixtures::{init_git_repo, run_git},
8484
};
8585

8686
// ============================================================================
@@ -459,9 +459,9 @@ pub(super) fn create_git_repo_fixture_with_secret_history(
459459
let filename = format!("secret-{commit}.txt");
460460
let contents = format!("{}\ncommit-{commit}\n", secret_fixture());
461461
fs::write(dir.path().join(&filename), contents).expect("write fixture");
462-
run_git_in(dir.path(), &["add", "."]);
462+
run_git(dir.path(), &["add", "."]);
463463
let message = format!("fixture-{commit}");
464-
run_git_in(dir.path(), &["commit", "-q", "-m", message.as_str()]);
464+
run_git(dir.path(), &["commit", "-q", "-m", message.as_str()]);
465465
}
466466

467467
dir
@@ -476,8 +476,8 @@ pub(super) fn create_clean_git_repo_fixture() -> tempfile::TempDir {
476476
"Distributed Runtime Tests",
477477
);
478478
fs::write(dir.path().join("readme.txt"), "hello world\n").expect("write fixture");
479-
run_git_in(dir.path(), &["add", "."]);
480-
run_git_in(dir.path(), &["commit", "-q", "-m", "fixture"]);
479+
run_git(dir.path(), &["add", "."]);
480+
run_git(dir.path(), &["commit", "-q", "-m", "fixture"]);
481481
dir
482482
}
483483

@@ -898,8 +898,8 @@ pub(super) fn create_git_repo_fixture_with_corrupt_blob() -> tempfile::TempDir {
898898
"Distributed Runtime Tests",
899899
);
900900
fs::write(dir.path().join("secret.txt"), secret_fixture()).expect("write fixture");
901-
run_git_in(dir.path(), &["add", "."]);
902-
run_git_in(dir.path(), &["commit", "-q", "-m", "fixture"]);
901+
run_git(dir.path(), &["add", "."]);
902+
run_git(dir.path(), &["commit", "-q", "-m", "fixture"]);
903903

904904
// Locate and corrupt the blob loose object. Walk .git/objects
905905
// fan-out directories looking for loose files, then use `git

crates/gossip-scanner-runtime/src/git_mirror.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ fn classify_io_git_run_error(op: &str, path: &Path, err: &io::Error) -> GitRunEr
561561
#[cfg(test)]
562562
mod tests {
563563
use super::*;
564-
use crate::test_fixtures::{init_git_repo, run_git_in};
564+
use crate::test_fixtures::{init_git_repo, run_git};
565565

566566
use tempfile::tempdir;
567567

@@ -642,12 +642,12 @@ mod tests {
642642
// Create a commit so `git gc` has objects to pack.
643643
let sentinel = repo_dir.path().join("sentinel.txt");
644644
fs::write(&sentinel, b"data").expect("write sentinel");
645-
run_git_in(repo_dir.path(), &["add", "sentinel.txt"]);
646-
run_git_in(
645+
run_git(repo_dir.path(), &["add", "sentinel.txt"]);
646+
run_git(
647647
repo_dir.path(),
648648
&["-c", "gc.auto=0", "commit", "-m", "seed"],
649649
);
650-
run_git_in(repo_dir.path(), &["-c", "gc.auto=0", "repack", "-a", "-d"]);
650+
run_git(repo_dir.path(), &["-c", "gc.auto=0", "repack", "-a", "-d"]);
651651

652652
// Remove the commit-graph (if created) so preflight reports
653653
// `missing_commit_graph = true`.

crates/gossip-scanner-runtime/src/lib_tests.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::{
2929
CommitProgressRecord, CoordinationEventRecorder, StageSignal, StoredGitEvent,
3030
},
3131
distributed::{DistributedPersistence, DistributedRuntimeConfig, WorkerIdentity, run_worker},
32-
test_fixtures::{init_git_repo, run_git_in},
32+
test_fixtures::{init_git_repo, run_git},
3333
};
3434

3535
fn create_test_repo(files: &[(&str, &[u8])]) -> tempfile::TempDir {
@@ -49,8 +49,8 @@ fn create_test_repo(files: &[(&str, &[u8])]) -> tempfile::TempDir {
4949
}
5050

5151
if !files.is_empty() {
52-
run_git_in(dir.path(), &["add", "."]);
53-
run_git_in(dir.path(), &["commit", "-q", "-m", "fixture"]);
52+
run_git(dir.path(), &["add", "."]);
53+
run_git(dir.path(), &["commit", "-q", "-m", "fixture"]);
5454
}
5555

5656
dir
@@ -1344,7 +1344,7 @@ fn scan_git_with_perf_debug_handles_empty_pack_exec_reports() {
13441344
// empty-vector path in format_git_debug_output's Perf branch.
13451345
let repo = create_test_repo(&[]);
13461346
// Create an empty commit so the repo has at least one ref.
1347-
run_git_in(
1347+
run_git(
13481348
repo.path(),
13491349
&["commit", "-q", "--allow-empty", "-m", "empty"],
13501350
);

crates/gossip-scanner-runtime/src/test_fixtures.rs

Lines changed: 2 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
//! This module centralizes reusable test data builders and git repository
44
//! setup helpers so runtime test modules share one command/assertion path.
55
6-
use std::path::Path;
7-
use std::process::Command;
8-
96
#[cfg(test)]
107
use gossip_contracts::{
118
connector::{Cursor, ItemKey, ItemRef, Location, ScanItem, VersionId},
@@ -24,6 +21,8 @@ use crate::{
2421
result_translation::{ItemResult, PersistenceTranslation, ScanTiming, translate_item_result},
2522
};
2623

24+
pub use gossip_stdx::git_test_support::{git_stdout, init_git_repo, run_git};
25+
2726
#[cfg(test)]
2827
pub(crate) fn test_rule_fingerprint(rule_id: u32) -> RuleFingerprint {
2928
let name = format!("test-rule-{rule_id}");
@@ -51,63 +50,6 @@ pub(crate) fn write_context_with_epoch(fence_epoch_raw: u64) -> WriteContext {
5150
)
5251
}
5352

54-
/// Run `git` inside `dir`, assert the command succeeds, and return the raw
55-
/// process output. Both [`run_git_in`] and [`run_git_in_stdout`] delegate here.
56-
fn assert_git_output(dir: &Path, args: &[&str]) -> std::process::Output {
57-
let output = Command::new("git")
58-
.arg("-C")
59-
.arg(dir)
60-
.args(args)
61-
.output()
62-
.unwrap_or_else(|e| {
63-
panic!(
64-
"failed to spawn git -C {} {}: {e}",
65-
dir.display(),
66-
args.join(" "),
67-
)
68-
});
69-
assert!(
70-
output.status.success(),
71-
"git command failed: git -C {} {}\nstdout:{}\nstderr:{}",
72-
dir.display(),
73-
args.join(" "),
74-
String::from_utf8_lossy(&output.stdout),
75-
String::from_utf8_lossy(&output.stderr),
76-
);
77-
output
78-
}
79-
80-
/// Run `git` inside `dir` and assert the command succeeds.
81-
pub fn run_git_in(dir: &Path, args: &[&str]) {
82-
assert_git_output(dir, args);
83-
}
84-
85-
/// Run `git` inside `dir`, assert success, and return trimmed stdout.
86-
pub fn run_git_in_stdout(dir: &Path, args: &[&str]) -> String {
87-
let output = assert_git_output(dir, args);
88-
String::from_utf8(output.stdout)
89-
.unwrap_or_else(|e| {
90-
panic!(
91-
"git -C {} {} produced non-UTF-8 stdout: {e}",
92-
dir.display(),
93-
args.join(" "),
94-
)
95-
})
96-
.trim()
97-
.to_owned()
98-
}
99-
100-
/// Initialize a git repository with the configured author identity.
101-
///
102-
/// The `-b main` flag ensures the initial branch is always `main` regardless
103-
/// of the host's `init.defaultBranch` setting, making callers portable across
104-
/// git configurations.
105-
pub fn init_git_repo(dir: &Path, email: &str, name: &str) {
106-
run_git_in(dir, &["init", "-q", "-b", "main"]);
107-
run_git_in(dir, &["config", "user.email", email]);
108-
run_git_in(dir, &["config", "user.name", name]);
109-
}
110-
11153
#[cfg(test)]
11254
pub(crate) fn timing() -> ScanTiming {
11355
timing_with_offset(0)

0 commit comments

Comments
 (0)