commit cd707bd59c2874add5e27788b1ec954969cd4462
parent c4956a526a6bec1b4766ca3d8f6ba28284ec749f
Author: triesap <tyson@radroots.org>
Date: Tue, 21 Apr 2026 21:08:03 +0000
app: prove pack day artifact action planning
Diffstat:
2 files changed, 152 insertions(+), 29 deletions(-)
diff --git a/crates/launchers/desktop/src/pack_day_host_handoff.rs b/crates/launchers/desktop/src/pack_day_host_handoff.rs
@@ -366,6 +366,12 @@ mod tests {
}
}
+ fn write_artifact(bundle_directory: &PathBuf, file_name: &str) -> PathBuf {
+ let path = bundle_directory.join(file_name);
+ fs::write(&path, file_name).expect("artifact should write");
+ path
+ }
+
#[test]
fn reveal_bundle_plan_uses_open_reveal_for_the_bundle_directory() {
let temp_dir = TestDirectory::new();
@@ -389,8 +395,7 @@ mod tests {
#[test]
fn open_pack_sheet_plan_targets_the_exported_pack_sheet() {
let temp_dir = TestDirectory::new();
- let pack_sheet_path = temp_dir.path().join("pack_sheet.txt");
- fs::write(&pack_sheet_path, "pack day").expect("pack sheet should write");
+ let pack_sheet_path = write_artifact(temp_dir.path(), "pack_sheet.txt");
let bundle = sample_bundle(temp_dir.path());
let plan = plan_pack_day_host_handoff(&bundle, PackDayHostHandoffKind::OpenPackSheet)
@@ -406,6 +411,42 @@ mod tests {
}
#[test]
+ fn open_pickup_roster_plan_targets_the_exported_pickup_roster() {
+ let temp_dir = TestDirectory::new();
+ let pickup_roster_path = write_artifact(temp_dir.path(), "pickup_roster.txt");
+ let bundle = sample_bundle(temp_dir.path());
+
+ let plan = plan_pack_day_host_handoff(&bundle, PackDayHostHandoffKind::OpenPickupRoster)
+ .expect("open pickup roster plan should build");
+
+ assert_eq!(plan.kind, PackDayHostHandoffKind::OpenPickupRoster);
+ assert_eq!(plan.target_path, pickup_roster_path.clone());
+ assert_eq!(plan.command_program, "open");
+ assert_eq!(
+ plan.command_args,
+ vec![pickup_roster_path.to_string_lossy().into_owned()]
+ );
+ }
+
+ #[test]
+ fn open_customer_labels_plan_targets_the_exported_customer_labels() {
+ let temp_dir = TestDirectory::new();
+ let customer_labels_path = write_artifact(temp_dir.path(), "customer_labels.txt");
+ let bundle = sample_bundle(temp_dir.path());
+
+ let plan = plan_pack_day_host_handoff(&bundle, PackDayHostHandoffKind::OpenCustomerLabels)
+ .expect("open customer labels plan should build");
+
+ assert_eq!(plan.kind, PackDayHostHandoffKind::OpenCustomerLabels);
+ assert_eq!(plan.target_path, customer_labels_path.clone());
+ assert_eq!(plan.command_program, "open");
+ assert_eq!(
+ plan.command_args,
+ vec![customer_labels_path.to_string_lossy().into_owned()]
+ );
+ }
+
+ #[test]
fn planning_fails_when_the_bundle_directory_is_missing() {
let bundle_directory = std::env::temp_dir().join(format!(
"radroots_app_pack_day_host_handoff_missing_{}",
@@ -445,6 +486,26 @@ mod tests {
}
#[test]
+ fn planning_fails_when_pickup_roster_reference_is_missing() {
+ let temp_dir = TestDirectory::new();
+ let mut bundle = sample_bundle(temp_dir.path());
+ bundle
+ .artifacts
+ .retain(|artifact| artifact.kind != PackDayExportArtifactKind::PickupRoster);
+
+ let error = plan_pack_day_host_handoff(&bundle, PackDayHostHandoffKind::OpenPickupRoster)
+ .expect_err("missing pickup roster artifact should fail");
+
+ assert_eq!(
+ error,
+ PackDayHostHandoffError::MissingArtifactReference {
+ kind: PackDayHostHandoffKind::OpenPickupRoster,
+ artifact_kind: PackDayExportArtifactKind::PickupRoster,
+ }
+ );
+ }
+
+ #[test]
fn planning_fails_when_pack_sheet_relative_path_is_invalid() {
let temp_dir = TestDirectory::new();
let mut bundle = sample_bundle(temp_dir.path());
@@ -463,6 +524,23 @@ mod tests {
}
#[test]
+ fn planning_fails_when_customer_labels_target_is_missing_on_disk() {
+ let temp_dir = TestDirectory::new();
+ let bundle = sample_bundle(temp_dir.path());
+
+ let error = plan_pack_day_host_handoff(&bundle, PackDayHostHandoffKind::OpenCustomerLabels)
+ .expect_err("missing customer labels file should fail");
+
+ assert_eq!(
+ error,
+ PackDayHostHandoffError::MissingTargetPath {
+ kind: PackDayHostHandoffKind::OpenCustomerLabels,
+ path: temp_dir.path().join("customer_labels.txt"),
+ }
+ );
+ }
+
+ #[test]
fn execution_classifies_command_launch_failures() {
let temp_dir = TestDirectory::new();
let bundle = sample_bundle(temp_dir.path());
@@ -510,6 +588,33 @@ mod tests {
}
#[test]
+ fn execution_classifies_nonzero_exit_failures_for_customer_labels() {
+ let temp_dir = TestDirectory::new();
+ write_artifact(temp_dir.path(), "customer_labels.txt");
+ let bundle = sample_bundle(temp_dir.path());
+ let plan = plan_pack_day_host_handoff(&bundle, PackDayHostHandoffKind::OpenCustomerLabels)
+ .expect("customer labels plan should build");
+
+ let error = execute_pack_day_host_handoff_plan_with(&plan, |_| {
+ Ok(PackDayHostHandoffCommandResult::failed(
+ Some(1),
+ "labels unavailable",
+ ))
+ })
+ .expect_err("nonzero exit should classify");
+
+ assert_eq!(
+ error,
+ PackDayHostHandoffError::CommandFailed {
+ kind: PackDayHostHandoffKind::OpenCustomerLabels,
+ program: "open".to_owned(),
+ exit_code: Some(1),
+ stderr: "labels unavailable".to_owned(),
+ }
+ );
+ }
+
+ #[test]
fn execution_accepts_successful_runs() {
let temp_dir = TestDirectory::new();
let bundle = sample_bundle(temp_dir.path());
diff --git a/crates/launchers/desktop/src/runtime.rs b/crates/launchers/desktop/src/runtime.rs
@@ -7247,7 +7247,7 @@ mod tests {
}
#[test]
- fn runtime_prepare_pack_day_host_handoff_uses_the_current_export_bundle() {
+ fn runtime_prepare_pack_day_host_handoff_uses_the_current_export_bundle_for_file_actions() {
let (runtime, paths) = bootstrapped_runtime("pack_day_host_handoff_prepare");
let (_, farm_id) = provision_ready_farmer_account(&runtime);
@@ -7259,33 +7259,51 @@ mod tests {
.expect("pack day export should succeed")
);
- let prepared = runtime
- .prepare_pack_day_host_handoff(PackDayHostHandoffKind::OpenPackSheet)
- .expect("host handoff should prepare")
- .expect("host handoff should produce a plan");
+ for (kind, suffix) in [
+ (PackDayHostHandoffKind::OpenPackSheet, "pack_sheet.txt"),
+ (
+ PackDayHostHandoffKind::OpenPickupRoster,
+ "pickup_roster.txt",
+ ),
+ (
+ PackDayHostHandoffKind::OpenCustomerLabels,
+ "customer_labels.txt",
+ ),
+ ] {
+ let prepared = runtime
+ .prepare_pack_day_host_handoff(kind)
+ .expect("host handoff should prepare")
+ .expect("host handoff should produce a plan");
+
+ let summary = runtime.summary();
+ assert_eq!(
+ summary.pack_day_projection.host_handoff.status,
+ PackDayHostHandoffStatus::Running
+ );
+ assert_eq!(
+ summary.pack_day_projection.host_handoff.request,
+ Some(prepared.0.clone())
+ );
+ assert_eq!(prepared.0.kind, kind);
+ assert_eq!(
+ prepared.0.bundle_directory,
+ summary
+ .pack_day_projection
+ .export
+ .bundle
+ .as_ref()
+ .expect("pack day export bundle")
+ .bundle_directory
+ );
+ assert_eq!(prepared.1.kind, kind);
+ assert!(prepared.1.target_path.ends_with(suffix));
- let summary = runtime.summary();
- assert_eq!(
- summary.pack_day_projection.host_handoff.status,
- PackDayHostHandoffStatus::Running
- );
- assert_eq!(
- summary.pack_day_projection.host_handoff.request,
- Some(prepared.0.clone())
- );
- assert_eq!(prepared.0.kind, PackDayHostHandoffKind::OpenPackSheet);
- assert_eq!(
- prepared.0.bundle_directory,
- summary
- .pack_day_projection
- .export
- .bundle
- .as_ref()
- .expect("pack day export bundle")
- .bundle_directory
- );
- assert_eq!(prepared.1.kind, PackDayHostHandoffKind::OpenPackSheet);
- assert!(prepared.1.target_path.ends_with("pack_sheet.txt"));
+ assert!(
+ runtime
+ .finish_pack_day_host_handoff(prepared.0, Ok(()))
+ .expect("host handoff success should apply")
+ );
+ }
cleanup_bootstrapped_runtime_paths(&paths);
}