Skip to content

Commit 55d0dae

Browse files
Build tests/apply fixtures through apply_fixture (#1941) (#1944)
* Start #1941 apply fixture consolidation Assisted-by: Claude Code:claude-opus-5-5 * Build tests/apply fixtures through apply_fixture Nine suites of the apply test binary wrote their own manifest, blob, npm package, gem and event-lookup helpers beside apply_fixture's. They now call apply_fixture (one_file/hashed_file, write_manifest, stage_blob, install_npm_pkg, install_gem, write_gem_patch, link_dir) and common::envelope::event_for. stage_blob writes through common::write_blob. The four gem runners share apply_fixture::run_gem, so gem_stale_bundler_plugin's child now gets the BUNDLE_* scrub the others had. The fallback-home human test moves next to its --json twin and reuses its fixture. apply_invariants compares .socket/ snapshots instead of a digest plus two byte checks. The explicit SOCKET_TELEMETRY_DISABLED=1 pairs, which hermetic::command forces, are gone. Assisted-by: Claude Code:claude-opus-5-5 * Apply /code-review findings on apply fixtures Gem suites that pin --cwd run their child from the runner's directory again, so a crawler reading the process cwd still fails them. apply_invariants runs apply through apply_fixture::run_apply, the --cwd remedy test stages its blob with stage_blob, and the gem --check fixture derives its specifications dir from install_gem's path. bun_global_store and lockfile_only_skip build their records through one index_js_patches helper. apply_network passes bytes to one_file instead of precomputed hashes. Stale module docs updated. Assisted-by: Claude Code:claude-opus-5-5 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7178662 commit 55d0dae

13 files changed

Lines changed: 410 additions & 1045 deletions

‎crates/socket-patch-cli/tests/apply/apply_fixture.rs‎

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
//! Fixtures and runners shared by `apply_failure_paths.rs` (the `--json`
2-
//! contracts) and `apply_render.rs` (the human output) (#1089).
1+
//! Fixtures and runners shared by every suite of the `apply` test binary.
32
//!
43
//! Binary-driven throughout (`common::run_with_env`, `SOCKET_*`-scrubbed
54
//! children), hand-written camelCase manifests, git-sha256 oracle,
@@ -10,7 +9,7 @@ use std::path::{Path, PathBuf};
109
use serde_json::{json, Value};
1110

1211
use crate::common::hermetic::{self, Extra};
13-
use crate::common::{binary, git_sha256, hermetic_command, run_with_env};
12+
use crate::common::{binary, git_sha256, hermetic_command, jvm_env, run_with_env, write_blob};
1413

1514
pub const GO_PURL: &str = "pkg:golang/example.com/mod@v1.0.0";
1615
pub const GO_COPY_DIR: &str = ".socket/go-patches/example.com/mod@v1.0.0";
@@ -46,7 +45,28 @@ pub fn patch_record(uuid: &str, files: Value) -> Value {
4645

4746
/// The `files` map of a one-file patch from `before` to `after` bytes.
4847
pub fn one_file(path: &str, before: &[u8], after: &[u8]) -> Value {
49-
json!({ path: { "beforeHash": git_sha256(before), "afterHash": git_sha256(after) } })
48+
hashed_file(path, &git_sha256(before), &git_sha256(after))
49+
}
50+
51+
/// [`one_file`] from the two hashes.
52+
pub fn hashed_file(path: &str, before_hash: &str, after_hash: &str) -> Value {
53+
json!({ path: { "beforeHash": before_hash, "afterHash": after_hash } })
54+
}
55+
56+
/// One `package/index.js` record from `before` to `after` per purl, the
57+
/// i-th with uuid `<prefix>-0000-4000-8000-<i, 12 digits>`.
58+
pub fn index_js_patches(purls: &[&str], uuid_prefix: &str, before: &[u8], after: &[u8]) -> Value {
59+
let files = one_file("package/index.js", before, after);
60+
Value::Object(
61+
purls
62+
.iter()
63+
.enumerate()
64+
.map(|(i, purl)| {
65+
let uuid = format!("{uuid_prefix}-0000-4000-8000-{i:012}");
66+
(purl.to_string(), patch_record(&uuid, files.clone()))
67+
})
68+
.collect(),
69+
)
5070
}
5171

5272
/// Write `.socket/manifest.json`, creating `.socket/blobs/` alongside as
@@ -62,9 +82,7 @@ pub fn write_manifest(root: &Path, patches: Value) {
6282
}
6383

6484
pub fn stage_blob(root: &Path, hash: &str, content: &[u8]) {
65-
let blobs = root.join(".socket").join("blobs");
66-
std::fs::create_dir_all(&blobs).expect("create blobs dir");
67-
std::fs::write(blobs.join(hash), content).expect("stage blob");
85+
write_blob(&root.join(".socket"), hash, content);
6886
}
6987

7088
/// Install a fake npm package at `<root>/node_modules/<name>` with the
@@ -85,6 +103,25 @@ pub fn install_npm_pkg(root: &Path, name: &str, version: &str, index_js: Option<
85103
index
86104
}
87105

106+
/// Link `link` to the directory `target`: a symlink on Unix, a junction
107+
/// on Windows.
108+
pub fn link_dir(target: &Path, link: &Path) {
109+
#[cfg(unix)]
110+
std::os::unix::fs::symlink(target, link).unwrap();
111+
#[cfg(windows)]
112+
{
113+
let link: PathBuf = link.components().collect();
114+
let target: PathBuf = target.components().collect();
115+
let status = std::process::Command::new("cmd")
116+
.args(["/C", "mklink", "/J"])
117+
.arg(&link)
118+
.arg(&target)
119+
.status()
120+
.unwrap();
121+
assert!(status.success(), "mklink /J failed");
122+
}
123+
}
124+
88125
pub fn write_root_package_json(root: &Path) {
89126
std::fs::write(
90127
root.join("package.json"),
@@ -232,7 +269,9 @@ pub fn write_sourceless_npm_patches(root: &Path, n: u32) {
232269
// ═══════════ gem release-variant mismatch fixtures ═══════════
233270
//
234271
// Shared by `cli_gem_variant_mismatch_policy.rs` (the `--json`
235-
// contracts) and `apply_render.rs` (the human output).
272+
// contracts) and `apply_render.rs` (the human output). `run_gem` also
273+
// runs the gem_stale_bundler_plugin, in_process_gem_config_warning and
274+
// in_process_gem_fallback_home children.
236275

237276
/// The rack singleton's on-disk bytes after a local edit: they match
238277
/// neither the record's beforeHash nor its afterHash.
@@ -242,24 +281,32 @@ pub const NOKOGIRI_DARWIN_BEFORE: &[u8] = b"# nokogiri.rb from the arm64-darwin
242281
pub const NOKOGIRI_LINUX_MARKER: &[u8] = b"\n# SOCKET-LINUX-PATCH\n";
243282
pub const NOKOGIRI_DARWIN_MARKER: &[u8] = b"\n# DARWIN-MARKER\n";
244283

245-
/// Run `socket-patch apply --offline --ecosystems gem <extra>` in `cwd`
246-
/// with the hermetic `SOCKET_*` environment (`hermetic_command`) and the
247-
/// ambient `BUNDLE_*` scrubbed, so only the argv decides behavior.
248-
pub fn run_gem_apply(cwd: &Path, extra: &[&str]) -> (i32, String, String) {
284+
/// Run `socket-patch <args>` in `cwd` like `common::run_with_env`, with
285+
/// the ambient `BUNDLE_*` also scrubbed so only the argv and `env` decide
286+
/// what Bundler state the gem crawler reads. Suites that pin `--cwd`
287+
/// pass `Path::new(".")` so the child stays in the runner's directory and
288+
/// a crawler reading the process cwd instead of `--cwd` finds nothing.
289+
pub fn run_gem(cwd: &Path, args: &[&str], env: &[(&str, &str)]) -> (i32, String, String) {
249290
let mut cmd = hermetic_command(&binary());
250-
cmd.arg("apply")
251-
.args(["--offline", "--ecosystems", "gem"])
252-
.args(extra)
253-
.current_dir(cwd);
291+
cmd.args(args).current_dir(cwd);
292+
jvm_env::isolate_cli(&mut cmd);
254293
hermetic::scrub_extra(&mut cmd, &[Extra::Bundle]);
255-
let out = cmd.output().expect("run socket-patch apply");
294+
cmd.envs(env.iter().copied());
295+
let out = cmd.output().expect("run socket-patch");
256296
(
257297
out.status.code().unwrap_or(-1),
258298
String::from_utf8_lossy(&out.stdout).to_string(),
259299
String::from_utf8_lossy(&out.stderr).to_string(),
260300
)
261301
}
262302

303+
/// [`run_gem`] of `apply --offline --ecosystems gem <extra>`.
304+
pub fn run_gem_apply(cwd: &Path, extra: &[&str]) -> (i32, String, String) {
305+
let mut argv = vec!["apply", "--offline", "--ecosystems", "gem"];
306+
argv.extend_from_slice(extra);
307+
run_gem(cwd, &argv, &[])
308+
}
309+
263310
/// `pkg:gem/nokogiri@1.16.5?platform=<platform>`.
264311
pub fn nokogiri_purl(platform: &str) -> String {
265312
format!("pkg:gem/nokogiri@1.16.5?platform={platform}")

0 commit comments

Comments
 (0)