Skip to content

Commit 827ded4

Browse files
committed
Test Hatch takeover through the real hosted unwind
Covers #674 through the hosted rewrite, discovery and the takeover's per-pin restore_upstream, rather than a simulated unwind, and checks both revert orders come back to the pre-hosted pyproject bytes. Assisted-by: Claude Code:claude-opus-5-5
1 parent e5076f0 commit 827ded4

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

‎crates/socket-patch-core/src/vendor/pypi_hatch.rs‎

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,91 @@ mod tests {
607607
}
608608
}
609609

610+
/// #674 end to end through the real lanes: the hosted rewrite, then the
611+
/// takeover's per-pin `restore_upstream` and vendored wiring for each
612+
/// package in turn, then a revert in either order.
613+
#[tokio::test]
614+
async fn takeover_through_hosted_unwind_reverts_byte_exact() {
615+
use crate::patch::redirect::upstream::{restore_upstream, HostedPin, RestoreOptions};
616+
let original = "[build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"app\"\nversion = \"0.1.0\"\ndependencies = [\"six==1.16.0\", \"toml==0.10.2\"]\n";
617+
let packages = [
618+
("six", "1.16.0", UUID),
619+
("toml", "0.10.2", "a0f74f9a-ce65-4451-ab60-025159b4d410"),
620+
];
621+
let deps: Vec<crate::patch::redirect::DepOverride> = packages
622+
.iter()
623+
.map(|(name, version, uuid)| {
624+
serde_json::from_value(json!({
625+
"ecosystem": "pypi", "name": name, "version": version,
626+
"token": "11111111-1111-1111-1111-111111111111",
627+
"patchUuid": uuid,
628+
"artifactUrl": format!(
629+
"https://patch.socket.dev/patch/pypi/{name}/{version}/11111111-1111-1111-1111-111111111111/{uuid}/{name}-{version}-py3-none-any.whl"
630+
),
631+
"integrity": { "sha256": "d".repeat(64) }
632+
}))
633+
.unwrap()
634+
})
635+
.collect();
636+
let input = BTreeMap::from([("pyproject.toml".to_owned(), original.to_owned())]);
637+
let hosted = crate::patch::redirect::rewrite_registry_redirect_with_pipenv_version(
638+
&input,
639+
&deps,
640+
&BTreeMap::new(),
641+
None,
642+
false,
643+
);
644+
let hosted = &hosted.files["pyproject.toml"];
645+
assert!(
646+
hosted.contains("allow-direct-references = true"),
647+
"{hosted}"
648+
);
649+
for order in [[0, 1], [1, 0]] {
650+
let temp = tempfile::tempdir().unwrap();
651+
let root = temp.path();
652+
tokio::fs::write(root.join("pyproject.toml"), hosted)
653+
.await
654+
.unwrap();
655+
let pins = HostedPin::all(&crate::vex::discover_patched_refs(root).await);
656+
assert_eq!(pins.len(), 2, "{pins:?}");
657+
let mut state = VendorState::default();
658+
let mut entries = Vec::new();
659+
for (name, version, uuid) in packages {
660+
let pin = pins.iter().find(|pin| pin.uuid == uuid).unwrap();
661+
let restore = restore_upstream(
662+
root,
663+
std::slice::from_ref(pin),
664+
&RestoreOptions {
665+
offline: true,
666+
..RestoreOptions::default()
667+
},
668+
)
669+
.await;
670+
assert_eq!(restore.refused().count(), 0, "{name}");
671+
let project = load(root, name, version, uuid).await.unwrap();
672+
let wheel = format!(".socket/vendor/pypi/{uuid}/{name}-{version}-py3-none-any.whl");
673+
let wiring = wire(&project, root, name, version, &wheel, &"0".repeat(64))
674+
.await
675+
.unwrap();
676+
let entry = entry(uuid, name, &wheel, &"0".repeat(64), wiring);
677+
state.entries.insert(name.into(), entry.clone());
678+
entries.push(entry);
679+
save_state(root, &state).await.unwrap();
680+
}
681+
for index in order {
682+
let outcome = revert(&entries[index], root, false).await;
683+
assert!(outcome.success, "{:?}", outcome.error);
684+
}
685+
assert_eq!(
686+
tokio::fs::read_to_string(root.join("pyproject.toml"))
687+
.await
688+
.unwrap(),
689+
original,
690+
"order {order:?}"
691+
);
692+
}
693+
}
694+
610695
/// The #674 drop only applies to a permission recorded while
611696
/// non-vendored direct references were live. A permission the user set
612697
/// is restored verbatim after two vendored packages are reverted, inline

0 commit comments

Comments
 (0)