280 lines
8.1 KiB
Rust
280 lines
8.1 KiB
Rust
//! 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);
|
|
}
|