|
| 1 | +//! End-to-End Provisioning Tests for Torrust Tracker Deploy |
| 2 | +//! |
| 3 | +//! This binary focuses exclusively on testing infrastructure provisioning. |
| 4 | +//! It creates VMs/containers using `OpenTofu` and validates that the infrastructure |
| 5 | +//! is properly provisioned and ready for configuration, but does NOT attempt |
| 6 | +//! to configure or install software. |
| 7 | +//! |
| 8 | +//! ## Test Workflow |
| 9 | +//! |
| 10 | +//! 1. **Preflight cleanup** - Remove any lingering test resources |
| 11 | +//! 2. **Infrastructure provisioning** - Create VMs/containers using `OpenTofu` |
| 12 | +//! 3. **Basic validation** - Verify VM is created and cloud-init completed |
| 13 | +//! 4. **Cleanup** - Remove test resources |
| 14 | +//! |
| 15 | +//! This split allows provisioning tests to run reliably on GitHub Actions |
| 16 | +//! while configuration tests can be handled separately with different infrastructure. |
| 17 | +
|
| 18 | +use anyhow::Result; |
| 19 | +use clap::Parser; |
| 20 | +use std::net::IpAddr; |
| 21 | +use std::time::Instant; |
| 22 | +use tracing::{error, info}; |
| 23 | + |
| 24 | +// Import E2E testing infrastructure |
| 25 | +use torrust_tracker_deploy::config::InstanceName; |
| 26 | +use torrust_tracker_deploy::e2e::environment::TestEnvironment; |
| 27 | +use torrust_tracker_deploy::e2e::tasks::{ |
| 28 | + cleanup_infrastructure::cleanup_infrastructure, preflight_cleanup::cleanup_lingering_resources, |
| 29 | + provision_infrastructure::provision_infrastructure, |
| 30 | +}; |
| 31 | +use torrust_tracker_deploy::logging::{self, LogFormat}; |
| 32 | + |
| 33 | +#[derive(Parser)] |
| 34 | +#[command(name = "e2e-provision-tests")] |
| 35 | +#[command(about = "E2E provisioning tests for Torrust Tracker Deploy")] |
| 36 | +struct Cli { |
| 37 | + /// Keep the test environment after completion |
| 38 | + #[arg(long)] |
| 39 | + keep: bool, |
| 40 | + |
| 41 | + /// Templates directory path (default: ./data/templates) |
| 42 | + #[arg(long, default_value = "./data/templates")] |
| 43 | + templates_dir: String, |
| 44 | + |
| 45 | + /// Logging format to use |
| 46 | + #[arg( |
| 47 | + long, |
| 48 | + default_value = "pretty", |
| 49 | + help = "Logging format: pretty, json, or compact" |
| 50 | + )] |
| 51 | + log_format: LogFormat, |
| 52 | +} |
| 53 | + |
| 54 | +/// Main entry point for the E2E provisioning test suite |
| 55 | +/// |
| 56 | +/// This function orchestrates the complete provisioning test workflow: |
| 57 | +/// 1. Initializes logging and test environment |
| 58 | +/// 2. Performs pre-flight cleanup |
| 59 | +/// 3. Runs provisioning tests (infrastructure creation only) |
| 60 | +/// 4. Performs cleanup |
| 61 | +/// 5. Reports results |
| 62 | +/// |
| 63 | +/// Returns `Ok(())` if all tests pass, `Err` otherwise. |
| 64 | +/// |
| 65 | +/// # Errors |
| 66 | +/// |
| 67 | +/// This function may return errors in the following cases: |
| 68 | +/// - Test environment setup fails |
| 69 | +/// - Pre-flight cleanup encounters issues |
| 70 | +/// - Infrastructure provisioning fails |
| 71 | +/// - Cleanup operations fail |
| 72 | +/// |
| 73 | +/// # Panics |
| 74 | +/// |
| 75 | +/// May panic if the hardcoded instance name "torrust-tracker-vm" is invalid, |
| 76 | +/// which should never happen in normal operation. |
| 77 | +/// |
| 78 | +/// May panic during the match statement if unexpected error combinations occur |
| 79 | +/// that are not handled by the current error handling logic. |
| 80 | +#[tokio::main] |
| 81 | +pub async fn main() -> Result<()> { |
| 82 | + let cli = Cli::parse(); |
| 83 | + |
| 84 | + // Initialize logging based on the chosen format |
| 85 | + logging::init_with_format(&cli.log_format); |
| 86 | + |
| 87 | + info!( |
| 88 | + application = "torrust_tracker_deploy", |
| 89 | + test_suite = "e2e_provision_tests", |
| 90 | + log_format = ?cli.log_format, |
| 91 | + "Starting E2E provisioning tests" |
| 92 | + ); |
| 93 | + |
| 94 | + // Instance name for the test environment - not user configurable for now |
| 95 | + let instance_name = |
| 96 | + InstanceName::new("torrust-tracker-vm".to_string()).expect("Valid hardcoded instance name"); |
| 97 | + |
| 98 | + let env = TestEnvironment::new(cli.keep, cli.templates_dir, instance_name)?; |
| 99 | + |
| 100 | + // Perform pre-flight cleanup to remove any lingering resources from interrupted tests |
| 101 | + cleanup_lingering_resources(&env)?; |
| 102 | + |
| 103 | + let test_start = Instant::now(); |
| 104 | + |
| 105 | + let provision_result = run_provisioning_test(&env).await; |
| 106 | + |
| 107 | + cleanup_infrastructure(&env); |
| 108 | + |
| 109 | + let test_duration = test_start.elapsed(); |
| 110 | + |
| 111 | + info!( |
| 112 | + performance = "test_execution", |
| 113 | + duration_secs = test_duration.as_secs_f64(), |
| 114 | + duration = ?test_duration, |
| 115 | + "Provisioning test execution completed" |
| 116 | + ); |
| 117 | + |
| 118 | + // Handle provisioning test results |
| 119 | + match provision_result { |
| 120 | + Ok(_) => { |
| 121 | + info!( |
| 122 | + test_suite = "e2e_provision_tests", |
| 123 | + status = "success", |
| 124 | + "All provisioning tests passed and cleanup completed successfully" |
| 125 | + ); |
| 126 | + Ok(()) |
| 127 | + } |
| 128 | + Err(provision_err) => { |
| 129 | + error!( |
| 130 | + test_suite = "e2e_provision_tests", |
| 131 | + status = "failed", |
| 132 | + error = %provision_err, |
| 133 | + "Infrastructure provisioning failed" |
| 134 | + ); |
| 135 | + Err(provision_err) |
| 136 | + } |
| 137 | + } |
| 138 | +} |
| 139 | + |
| 140 | +/// Runs the provisioning test workflow |
| 141 | +/// |
| 142 | +/// This function focuses exclusively on infrastructure provisioning and validation. |
| 143 | +/// It does NOT attempt to configure software or install applications. |
| 144 | +/// |
| 145 | +/// # Test Phases |
| 146 | +/// |
| 147 | +/// 1. **Provision Infrastructure**: Creates VMs/containers using `OpenTofu` |
| 148 | +/// 2. **Basic Validation**: Verifies infrastructure is ready (cloud-init completed) |
| 149 | +/// |
| 150 | +/// Returns the provisioned instance IP address on success. |
| 151 | +async fn run_provisioning_test(env: &TestEnvironment) -> Result<IpAddr> { |
| 152 | + info!( |
| 153 | + test_type = "provision_only", |
| 154 | + workflow = "infrastructure_provisioning", |
| 155 | + "Starting infrastructure provisioning E2E test" |
| 156 | + ); |
| 157 | + |
| 158 | + let instance_ip = provision_infrastructure(env).await?; |
| 159 | + |
| 160 | + info!( |
| 161 | + status = "success", |
| 162 | + instance_ip = %instance_ip, |
| 163 | + "Infrastructure provisioning completed successfully" |
| 164 | + ); |
| 165 | + |
| 166 | + info!( |
| 167 | + test_type = "provision_only", |
| 168 | + status = "success", |
| 169 | + note = "VM/container created and cloud-init completed - ready for configuration", |
| 170 | + "Provisioning E2E test completed successfully" |
| 171 | + ); |
| 172 | + |
| 173 | + // Return the instance IP for potential future validation |
| 174 | + Ok(instance_ip) |
| 175 | +} |
0 commit comments