prodigy 0.4.4

Turn ad-hoc Claude sessions into reproducible development pipelines with parallel AI agents
Documentation
//! Baseline tests for workflow execution behavior
//!
//! This test suite documents the current behavior of all workflow execution paths
//! before migration to the unified execution model. These tests capture both
//! correct behavior and existing bugs to ensure the migration preserves or fixes
//! the current state appropriately.

use prodigy::config::{WorkflowCommand, WorkflowConfig};
use prodigy::cook::command::CookCommand;
use prodigy::cook::orchestrator::CookConfig;
use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;

/// Helper to create a basic cook config for testing
fn create_test_config(workflow: WorkflowConfig) -> CookConfig {
    CookConfig {
        command: CookCommand {
            playbook: PathBuf::from("test.yaml"),
            path: None,
            max_iterations: 1,
            map: vec![],
            args: vec![],
            fail_fast: false,
            auto_accept: false,
            resume: None,
            verbosity: 0,
            quiet: false,
            dry_run: false,
            params: HashMap::new(),
        },
        project_path: Arc::new(PathBuf::from("/tmp/test")),
        workflow: Arc::new(workflow),
        mapreduce_config: None,
    }
}

mod standard_workflow {
    use super::*;

    #[test]
    fn test_standard_workflow_with_validation() {
        // Document that validation works in standard workflows
        let workflow = WorkflowConfig {
            name: None,
            env: None,
            secrets: None,
            env_files: None,
            profiles: None,
            merge: None,
            commands: vec![WorkflowCommand::Simple("test-command".to_string())],
        };

        let config = create_test_config(workflow);

        // This test documents that standard workflows SHOULD have validation
        // In real code, validation would be specified elsewhere
        assert_eq!(config.workflow.commands.len(), 1);
    }

    #[test]
    fn test_standard_workflow_with_handlers() {
        // Document that handlers work in standard workflows
        let workflow = WorkflowConfig {
            name: None,
            env: None,
            secrets: None,
            env_files: None,
            profiles: None,
            merge: None,
            commands: vec![WorkflowCommand::Simple("test-command".to_string())],
        };

        let config = create_test_config(workflow);

        // This test documents that standard workflows SHOULD support handlers
        // Handlers would be specified in the actual workflow YAML
        assert_eq!(config.workflow.commands.len(), 1);
    }

    #[test]
    fn test_standard_workflow_with_timeouts() {
        // Document that timeouts work in standard workflows
        let workflow = WorkflowConfig {
            name: None,
            env: None,
            secrets: None,
            env_files: None,
            profiles: None,
            merge: None,
            commands: vec![WorkflowCommand::Simple("test-command".to_string())],
        };

        let config = create_test_config(workflow);

        // This test documents that standard workflows SHOULD support timeouts
        // Timeouts would be specified in the actual workflow YAML
        assert_eq!(config.workflow.commands.len(), 1);
    }
}

mod structured_workflow {
    use super::*;

    #[test]
    fn test_structured_workflow_type_classification() {
        // Document that structured workflows are those with outputs
        let workflow = WorkflowConfig {
            name: None,
            env: None,
            secrets: None,
            env_files: None,
            profiles: None,
            merge: None,
            commands: vec![
                // WorkflowCommand doesn't have WithOutput variant in actual code
                WorkflowCommand::Simple("test-command".to_string()),
            ],
        };

        let config = create_test_config(workflow);

        // This test documents the existence of structured workflow type
        assert_eq!(config.workflow.commands.len(), 1);
    }
}

mod args_workflow {
    use super::*;

    #[test]
    fn test_args_workflow_type_classification() {
        // Document that args workflows use the args field
        let workflow = WorkflowConfig {
            name: None,
            env: None,
            secrets: None,
            env_files: None,
            profiles: None,
            merge: None,
            commands: vec![WorkflowCommand::Simple("test-command".to_string())],
        };

        let mut config = create_test_config(workflow);
        config.command.args = vec!["arg1".to_string(), "arg2".to_string()];

        // This test documents the args workflow type
        assert_eq!(config.command.args.len(), 2);
    }
}

mod mapreduce_workflow {
    use super::*;

    #[test]
    fn test_mapreduce_workflow_type_exists() {
        // Document that MapReduce workflows exist
        let workflow = WorkflowConfig {
            name: None,
            commands: vec![],
            env: None,
            secrets: None,
            env_files: None,
            profiles: None,
            merge: None,
        };

        // MapReduceWorkflowConfig would be in a separate field
        let config = CookConfig {
            command: CookCommand {
                playbook: PathBuf::from("test.yaml"),
                path: None,
                max_iterations: 1,
                map: vec![],
                args: vec![],
                fail_fast: false,
                auto_accept: false,
                resume: None,
                verbosity: 0,
                quiet: false,
                dry_run: false,
                params: HashMap::new(),
            },
            project_path: Arc::new(PathBuf::from("/tmp/test")),
            workflow: Arc::new(workflow),
            mapreduce_config: None,
        };

        // This test documents the MapReduce workflow type
        assert!(config.mapreduce_config.is_none());
    }
}

mod feature_matrix {
    use super::*;

    #[test]
    fn document_feature_matrix() {
        // This test documents the feature matrix from the spec

        // Feature availability by workflow type:
        // | Feature | Standard | Structured | Args/Map | MapReduce |
        // |---------|----------|------------|----------|-----------|
        // | Validation | ✅ | ❌ | ❌ | ❌ |
        // | Handlers | ✅ | ❌ | ❌ | ❌ |
        // | Timeouts | ✅ | ✅ | ✅ | ✅ |
        // | Outputs | ❌ | ✅ | ❌ | ❌ |
        // | Variables | ✅ | ✅ | ✅ | ✅ |

        // Feature matrix documented in comments above
    }

    #[test]
    fn test_workflow_type_classification() {
        // Test that we can correctly classify workflow types

        // Standard workflow
        let standard = WorkflowConfig {
            name: None,
            env: None,
            secrets: None,
            env_files: None,
            profiles: None,
            merge: None,
            commands: vec![WorkflowCommand::Simple("test".to_string())],
        };

        // These classifications should be preserved during migration
        assert_eq!(standard.commands.len(), 1);
    }
}

#[cfg(test)]
mod migration_tests {
    use super::*;

    #[test]
    fn test_backward_compatibility_requirement() {
        // This test ensures we maintain backward compatibility
        // during the incremental migration

        // All existing workflow configs must continue to work
        let workflow = WorkflowConfig {
            name: None,
            commands: vec![],
            env: None,
            secrets: None,
            env_files: None,
            profiles: None,
            merge: None,
        };
        let config = create_test_config(workflow);

        // The config structure should remain unchanged
        assert!(config.workflow.commands.is_empty());
    }

    // Note: test_feature_flag_controls was removed as it only tested that
    // std::env::set_var and std::env::var work, not any actual feature flag behavior.
}