//! Integration tests for the full finalize pipeline //! //! These tests verify the complete finalize workflow from YAML parsing //! through hook execution, using real files and the public `finalize()` entry point. use std::collections::HashMap; use std::time::Duration; use workshop_baker::cli::Cli; use workshop_baker::ExecutionContext; use workshop_engine::ExecutionEvent; use workshop_baker::finalize::finalize; fn create_test_context() -> ExecutionContext { ExecutionContext { task_id: "test-finalize-1".to_string(), pipeline_name: "test-pipeline".to_string(), username: "testuser".to_string(), working_dir: std::env::temp_dir(), env_vars: HashMap::new(), timeout: Some(Duration::from_secs(30)), shell: "bash".to_string(), dry_run: false, privileged: false, standalone: false, } } fn create_test_cli() -> Cli { Cli { username: "testuser".to_string(), pipeline: "test-pipeline".to_string(), build_id: "test-build-1".to_string(), dry_run: false, command: None, } } fn create_test_event_channel() -> ( Option>, tokio::sync::mpsc::Receiver, ) { let (tx, rx) = tokio::sync::mpsc::channel(64); (Some(tx), rx) } #[tokio::test] async fn test_full_finalize_with_early_late_hooks() { let temp_dir = std::env::temp_dir(); let finalize_path = temp_dir.join("test_finalize.yml"); let yaml_content = r#" version: "0.0.1" hooks: early: - name: "early-echo" command: "echo early-hook-ok" timeout: 5 late: - name: "late-echo" command: "echo late-hook-ok" timeout: 5 "#; std::fs::write(&finalize_path, yaml_content).expect("Failed to write test finalize.yml"); let cli = create_test_cli(); let mut ctx = create_test_context(); let (event_tx, mut event_rx) = create_test_event_channel(); // Spawn an event consumer so the channel does not block let consumer_handle = tokio::spawn(async move { while let Some(_event) = event_rx.recv().await { // Events are consumed but not validated in this test } }); let result = finalize(&finalize_path, &cli, &mut ctx, event_tx).await; let _ = consumer_handle.await; std::fs::remove_file(&finalize_path).ok(); assert!( result.is_ok(), "Full finalize pipeline should succeed: {:?}", result ); } #[tokio::test] async fn test_full_finalize_with_empty_hooks() { let temp_dir = std::env::temp_dir(); let finalize_path = temp_dir.join("test_finalize_empty.yml"); let yaml_content = r#" version: "0.0.1" "#; std::fs::write(&finalize_path, yaml_content).expect("Failed to write test finalize.yml"); let cli = create_test_cli(); let mut ctx = create_test_context(); let (event_tx, mut event_rx) = create_test_event_channel(); let consumer_handle = tokio::spawn(async move { while let Some(_event) = event_rx.recv().await {} }); let result = finalize(&finalize_path, &cli, &mut ctx, event_tx).await; let _ = consumer_handle.await; std::fs::remove_file(&finalize_path).ok(); assert!( result.is_ok(), "Finalize with empty hooks should succeed: {:?}", result ); } #[tokio::test] async fn test_full_finalize_with_failing_early_hook() { let temp_dir = std::env::temp_dir(); let finalize_path = temp_dir.join("test_finalize_fail.yml"); let yaml_content = r#" version: "0.0.1" hooks: early: - name: "failing-hook" command: "false" timeout: 5 late: - name: "never-reached" command: "echo should-not-run" timeout: 5 "#; std::fs::write(&finalize_path, yaml_content).expect("Failed to write test finalize.yml"); let cli = create_test_cli(); let mut ctx = create_test_context(); let (event_tx, mut event_rx) = create_test_event_channel(); let consumer_handle = tokio::spawn(async move { while let Some(_event) = event_rx.recv().await {} }); let result = finalize(&finalize_path, &cli, &mut ctx, event_tx).await; let _ = consumer_handle.await; std::fs::remove_file(&finalize_path).ok(); // With the notification subsystem, prior stage failures cause finalize to // send a failure notification and then return Ok (skipping artifacts/latehook) assert!( result.is_ok(), "Finalize with failing early hook should return Ok after sending failure notification" ); }