update api, fix tests and examples
This commit is contained in:
		
							
								
								
									
										279
									
								
								tests/job_api_integration_tests.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								tests/job_api_integration_tests.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,279 @@
 | 
			
		||||
//! Integration tests for the job API
 | 
			
		||||
//! 
 | 
			
		||||
//! These tests validate the complete job lifecycle using a real supervisor instance.
 | 
			
		||||
//! They require Redis and a running supervisor to execute properly.
 | 
			
		||||
 | 
			
		||||
use hero_supervisor_openrpc_client::{SupervisorClient, JobBuilder, JobResult};
 | 
			
		||||
use std::time::Duration;
 | 
			
		||||
use tokio::time::sleep;
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
/// Test helper to create a unique job for testing
 | 
			
		||||
fn create_test_job(context: &str) -> Result<hero_supervisor_openrpc_client::Job, Box<dyn std::error::Error>> {
 | 
			
		||||
    JobBuilder::new()
 | 
			
		||||
        .caller_id("integration_test")
 | 
			
		||||
        .context_id(context)
 | 
			
		||||
        .payload("echo 'Test job output'")
 | 
			
		||||
        .executor("osis")
 | 
			
		||||
        .runner("osis_runner_1")
 | 
			
		||||
        .timeout(30)
 | 
			
		||||
        .env_var("TEST_VAR", "test_value")
 | 
			
		||||
        .build()
 | 
			
		||||
        .map_err(|e| e.into())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Test helper to check if supervisor is available
 | 
			
		||||
async fn is_supervisor_available() -> bool {
 | 
			
		||||
    match SupervisorClient::new("http://localhost:3030") {
 | 
			
		||||
        Ok(client) => client.discover().await.is_ok(),
 | 
			
		||||
        Err(_) => false,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test]
 | 
			
		||||
async fn test_jobs_create_and_start() {
 | 
			
		||||
    if !is_supervisor_available().await {
 | 
			
		||||
        println!("Skipping test - supervisor not available");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let client = SupervisorClient::new("http://localhost:3030").unwrap();
 | 
			
		||||
    let secret = "user-secret-456";
 | 
			
		||||
    let job = create_test_job("create_and_start").unwrap();
 | 
			
		||||
 | 
			
		||||
    // Test jobs.create
 | 
			
		||||
    let job_id = client.jobs_create(secret, job).await.unwrap();
 | 
			
		||||
    assert!(!job_id.is_empty());
 | 
			
		||||
 | 
			
		||||
    // Test job.start
 | 
			
		||||
    let result = client.job_start(secret, &job_id).await;
 | 
			
		||||
    assert!(result.is_ok());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test]
 | 
			
		||||
async fn test_job_status_monitoring() {
 | 
			
		||||
    if !is_supervisor_available().await {
 | 
			
		||||
        println!("Skipping test - supervisor not available");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let client = SupervisorClient::new("http://localhost:3030").unwrap();
 | 
			
		||||
    let secret = "user-secret-456";
 | 
			
		||||
    let job = create_test_job("status_monitoring").unwrap();
 | 
			
		||||
 | 
			
		||||
    let job_id = client.jobs_create(secret, job).await.unwrap();
 | 
			
		||||
    client.job_start(secret, &job_id).await.unwrap();
 | 
			
		||||
 | 
			
		||||
    // Test job.status
 | 
			
		||||
    let mut attempts = 0;
 | 
			
		||||
    let max_attempts = 10;
 | 
			
		||||
 | 
			
		||||
    while attempts < max_attempts {
 | 
			
		||||
        let status = client.job_status(&job_id).await.unwrap();
 | 
			
		||||
        assert!(!status.job_id.is_empty());
 | 
			
		||||
        assert!(!status.status.is_empty());
 | 
			
		||||
        assert!(!status.created_at.is_empty());
 | 
			
		||||
 | 
			
		||||
        if status.status == "completed" || status.status == "failed" {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        attempts += 1;
 | 
			
		||||
        sleep(Duration::from_secs(1)).await;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test]
 | 
			
		||||
async fn test_job_result_retrieval() {
 | 
			
		||||
    if !is_supervisor_available().await {
 | 
			
		||||
        println!("Skipping test - supervisor not available");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let client = SupervisorClient::new("http://localhost:3030").unwrap();
 | 
			
		||||
    let secret = "user-secret-456";
 | 
			
		||||
    let job = create_test_job("result_retrieval").unwrap();
 | 
			
		||||
 | 
			
		||||
    let job_id = client.jobs_create(secret, job).await.unwrap();
 | 
			
		||||
    client.job_start(secret, &job_id).await.unwrap();
 | 
			
		||||
 | 
			
		||||
    // Wait a bit for job to complete
 | 
			
		||||
    sleep(Duration::from_secs(3)).await;
 | 
			
		||||
 | 
			
		||||
    // Test job.result
 | 
			
		||||
    let result = client.job_result(&job_id).await.unwrap();
 | 
			
		||||
    match result {
 | 
			
		||||
        JobResult::Success { success } => {
 | 
			
		||||
            assert!(!success.is_empty());
 | 
			
		||||
        },
 | 
			
		||||
        JobResult::Error { error } => {
 | 
			
		||||
            assert!(!error.is_empty());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test]
 | 
			
		||||
async fn test_job_run_immediate() {
 | 
			
		||||
    if !is_supervisor_available().await {
 | 
			
		||||
        println!("Skipping test - supervisor not available");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let client = SupervisorClient::new("http://localhost:3030").unwrap();
 | 
			
		||||
    let secret = "user-secret-456";
 | 
			
		||||
    let job = create_test_job("immediate_run").unwrap();
 | 
			
		||||
 | 
			
		||||
    // Test job.run (immediate execution)
 | 
			
		||||
    let result = client.job_run(secret, job).await.unwrap();
 | 
			
		||||
    match result {
 | 
			
		||||
        JobResult::Success { success } => {
 | 
			
		||||
            assert!(!success.is_empty());
 | 
			
		||||
        },
 | 
			
		||||
        JobResult::Error { error } => {
 | 
			
		||||
            assert!(!error.is_empty());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test]
 | 
			
		||||
async fn test_jobs_list() {
 | 
			
		||||
    if !is_supervisor_available().await {
 | 
			
		||||
        println!("Skipping test - supervisor not available");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let client = SupervisorClient::new("http://localhost:3030").unwrap();
 | 
			
		||||
 | 
			
		||||
    // Test jobs.list
 | 
			
		||||
    let job_ids = client.jobs_list().await.unwrap();
 | 
			
		||||
    // Should return a vector (might be empty)
 | 
			
		||||
    assert!(job_ids.len() >= 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test]
 | 
			
		||||
async fn test_authentication_failures() {
 | 
			
		||||
    if !is_supervisor_available().await {
 | 
			
		||||
        println!("Skipping test - supervisor not available");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let client = SupervisorClient::new("http://localhost:3030").unwrap();
 | 
			
		||||
    let invalid_secret = "invalid-secret-123";
 | 
			
		||||
    let job = create_test_job("auth_failure").unwrap();
 | 
			
		||||
 | 
			
		||||
    // Test that invalid secrets fail
 | 
			
		||||
    let result = client.jobs_create(invalid_secret, job.clone()).await;
 | 
			
		||||
    assert!(result.is_err());
 | 
			
		||||
 | 
			
		||||
    let result = client.job_run(invalid_secret, job.clone()).await;
 | 
			
		||||
    assert!(result.is_err());
 | 
			
		||||
 | 
			
		||||
    let result = client.job_start(invalid_secret, "fake-job-id").await;
 | 
			
		||||
    assert!(result.is_err());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test]
 | 
			
		||||
async fn test_nonexistent_job_operations() {
 | 
			
		||||
    if !is_supervisor_available().await {
 | 
			
		||||
        println!("Skipping test - supervisor not available");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let client = SupervisorClient::new("http://localhost:3030").unwrap();
 | 
			
		||||
    let fake_job_id = format!("nonexistent-{}", Uuid::new_v4());
 | 
			
		||||
 | 
			
		||||
    // Test operations on nonexistent job should fail
 | 
			
		||||
    let result = client.job_status(&fake_job_id).await;
 | 
			
		||||
    assert!(result.is_err());
 | 
			
		||||
 | 
			
		||||
    let result = client.job_result(&fake_job_id).await;
 | 
			
		||||
    assert!(result.is_err());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test]
 | 
			
		||||
async fn test_complete_workflow() {
 | 
			
		||||
    if !is_supervisor_available().await {
 | 
			
		||||
        println!("Skipping test - supervisor not available");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let client = SupervisorClient::new("http://localhost:3030").unwrap();
 | 
			
		||||
    let secret = "user-secret-456";
 | 
			
		||||
    let job = create_test_job("complete_workflow").unwrap();
 | 
			
		||||
 | 
			
		||||
    // Complete workflow test
 | 
			
		||||
    let job_id = client.jobs_create(secret, job).await.unwrap();
 | 
			
		||||
    client.job_start(secret, &job_id).await.unwrap();
 | 
			
		||||
 | 
			
		||||
    // Monitor until completion
 | 
			
		||||
    let mut final_status = String::new();
 | 
			
		||||
    for _ in 0..15 {
 | 
			
		||||
        let status = client.job_status(&job_id).await.unwrap();
 | 
			
		||||
        final_status = status.status.clone();
 | 
			
		||||
        
 | 
			
		||||
        if final_status == "completed" || final_status == "failed" || final_status == "timeout" {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        sleep(Duration::from_secs(1)).await;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Get final result
 | 
			
		||||
    let result = client.job_result(&job_id).await.unwrap();
 | 
			
		||||
    match result {
 | 
			
		||||
        JobResult::Success { .. } => {
 | 
			
		||||
            assert_eq!(final_status, "completed");
 | 
			
		||||
        },
 | 
			
		||||
        JobResult::Error { .. } => {
 | 
			
		||||
            assert!(final_status == "failed" || final_status == "timeout");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[tokio::test]
 | 
			
		||||
async fn test_batch_job_processing() {
 | 
			
		||||
    if !is_supervisor_available().await {
 | 
			
		||||
        println!("Skipping test - supervisor not available");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let client = SupervisorClient::new("http://localhost:3030").unwrap();
 | 
			
		||||
    let secret = "user-secret-456";
 | 
			
		||||
    
 | 
			
		||||
    let job_count = 3;
 | 
			
		||||
    let mut job_ids = Vec::new();
 | 
			
		||||
 | 
			
		||||
    // Create multiple jobs
 | 
			
		||||
    for i in 0..job_count {
 | 
			
		||||
        let job = JobBuilder::new()
 | 
			
		||||
            .caller_id("integration_test")
 | 
			
		||||
            .context_id(&format!("batch_job_{}", i))
 | 
			
		||||
            .payload(&format!("echo 'Batch job {}'", i))
 | 
			
		||||
            .executor("osis")
 | 
			
		||||
            .runner("osis_runner_1")
 | 
			
		||||
            .timeout(30)
 | 
			
		||||
            .build()
 | 
			
		||||
            .unwrap();
 | 
			
		||||
 | 
			
		||||
        let job_id = client.jobs_create(secret, job).await.unwrap();
 | 
			
		||||
        job_ids.push(job_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Start all jobs
 | 
			
		||||
    for job_id in &job_ids {
 | 
			
		||||
        client.job_start(secret, job_id).await.unwrap();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Wait for all jobs to complete
 | 
			
		||||
    sleep(Duration::from_secs(5)).await;
 | 
			
		||||
 | 
			
		||||
    // Collect all results
 | 
			
		||||
    let mut results = Vec::new();
 | 
			
		||||
    for job_id in &job_ids {
 | 
			
		||||
        let result = client.job_result(job_id).await.unwrap();
 | 
			
		||||
        results.push(result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Verify we got results for all jobs
 | 
			
		||||
    assert_eq!(results.len(), job_count);
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user