//! Integration tests for Worker repository //! //! Tests cover CRUD operations, specialized queries, constraints, //! enum handling, timestamps, heartbeat updates, and edge cases. use attune_common::models::enums::{WorkerStatus, WorkerType}; use attune_common::repositories::runtime::{ CreateRuntimeInput, CreateWorkerInput, RuntimeRepository, UpdateWorkerInput, WorkerRepository, }; use attune_common::repositories::{Create, Delete, FindById, List, Update}; use serde_json::json; use sqlx::PgPool; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; use std::sync::atomic::{AtomicU64, Ordering}; mod helpers; use helpers::create_test_pool; // Global counter for unique IDs across all tests static GLOBAL_COUNTER: AtomicU64 = AtomicU64::new(0); /// Test fixture for creating unique worker data struct WorkerFixture { sequence: AtomicU64, test_id: String, } impl WorkerFixture { fn new(test_name: &str) -> Self { let global_count = GLOBAL_COUNTER.fetch_add(1, Ordering::SeqCst); let timestamp = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_nanos(); // Create unique test ID from test name, timestamp, and global counter let mut hasher = DefaultHasher::new(); test_name.hash(&mut hasher); timestamp.hash(&mut hasher); global_count.hash(&mut hasher); let hash = hasher.finish(); let test_id = format!("test_{}_{:x}", global_count, hash); Self { sequence: AtomicU64::new(0), test_id, } } fn unique_name(&self, prefix: &str) -> String { let seq = self.sequence.fetch_add(1, Ordering::SeqCst); format!("{}_{}_worker_{}", prefix, self.test_id, seq) } fn create_input(&self, name_suffix: &str, worker_type: WorkerType) -> CreateWorkerInput { CreateWorkerInput { name: self.unique_name(name_suffix), worker_type, runtime: None, host: Some("localhost".to_string()), port: Some(8080), status: Some(WorkerStatus::Active), capabilities: Some(json!({ "cpu": "x86_64", "memory": "8GB", "python": ["3.9", "3.10", "3.11"], "node": ["16", "18", "20"] })), meta: Some(json!({ "region": "us-west-2", "environment": "test" })), } } fn create_minimal_input(&self, name_suffix: &str) -> CreateWorkerInput { CreateWorkerInput { name: self.unique_name(name_suffix), worker_type: WorkerType::Local, runtime: None, host: None, port: None, status: None, capabilities: None, meta: None, } } } async fn setup_db() -> PgPool { create_test_pool() .await .expect("Failed to create test pool") } // ============================================================================ // Basic CRUD Tests // ============================================================================ #[tokio::test] async fn test_create_worker() { let pool = setup_db().await; let fixture = WorkerFixture::new("create_worker"); let input = fixture.create_input("basic", WorkerType::Local); let worker = WorkerRepository::create(&pool, input.clone()) .await .expect("Failed to create worker"); assert!(worker.id > 0); assert_eq!(worker.name, input.name); assert_eq!(worker.worker_type, input.worker_type); assert_eq!(worker.runtime, input.runtime); assert_eq!(worker.host, input.host); assert_eq!(worker.port, input.port); assert_eq!(worker.status, input.status); assert_eq!(worker.capabilities, input.capabilities); assert_eq!(worker.meta, input.meta); assert_eq!(worker.last_heartbeat, None); assert!(worker.created > chrono::Utc::now() - chrono::Duration::seconds(5)); assert!(worker.updated > chrono::Utc::now() - chrono::Duration::seconds(5)); } #[tokio::test] async fn test_create_worker_minimal() { let pool = setup_db().await; let fixture = WorkerFixture::new("create_worker_minimal"); let input = fixture.create_minimal_input("minimal"); let worker = WorkerRepository::create(&pool, input.clone()) .await .expect("Failed to create minimal worker"); assert!(worker.id > 0); assert_eq!(worker.name, input.name); assert_eq!(worker.worker_type, WorkerType::Local); assert_eq!(worker.host, None); assert_eq!(worker.port, None); assert_eq!(worker.status, None); assert_eq!(worker.capabilities, None); assert_eq!(worker.meta, None); } #[tokio::test] async fn test_find_worker_by_id() { let pool = setup_db().await; let fixture = WorkerFixture::new("find_by_id"); let input = fixture.create_input("findable", WorkerType::Remote); let created = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); let found = WorkerRepository::find_by_id(&pool, created.id) .await .expect("Failed to find worker") .expect("Worker not found"); assert_eq!(found.id, created.id); assert_eq!(found.name, created.name); assert_eq!(found.worker_type, created.worker_type); } #[tokio::test] async fn test_find_worker_by_id_not_found() { let pool = setup_db().await; let result = WorkerRepository::find_by_id(&pool, 999999999) .await .expect("Query should succeed"); assert!(result.is_none()); } #[tokio::test] async fn test_find_worker_by_name() { let pool = setup_db().await; let fixture = WorkerFixture::new("find_by_name"); let input = fixture.create_input("nametest", WorkerType::Container); let created = WorkerRepository::create(&pool, input.clone()) .await .expect("Failed to create worker"); let found = WorkerRepository::find_by_name(&pool, &input.name) .await .expect("Failed to find worker") .expect("Worker not found"); assert_eq!(found.id, created.id); assert_eq!(found.name, created.name); } #[tokio::test] async fn test_find_worker_by_name_not_found() { let pool = setup_db().await; let result = WorkerRepository::find_by_name(&pool, "nonexistent_worker_999999") .await .expect("Query should succeed"); assert!(result.is_none()); } #[tokio::test] async fn test_list_workers() { let pool = setup_db().await; let fixture = WorkerFixture::new("list_workers"); let input1 = fixture.create_input("list1", WorkerType::Local); let input2 = fixture.create_input("list2", WorkerType::Remote); let created1 = WorkerRepository::create(&pool, input1) .await .expect("Failed to create worker 1"); let created2 = WorkerRepository::create(&pool, input2) .await .expect("Failed to create worker 2"); let list = WorkerRepository::list(&pool) .await .expect("Failed to list workers"); assert!(list.len() >= 2); assert!(list.iter().any(|w| w.id == created1.id)); assert!(list.iter().any(|w| w.id == created2.id)); } #[tokio::test] async fn test_update_worker() { let pool = setup_db().await; let fixture = WorkerFixture::new("update_worker"); let input = fixture.create_input("update", WorkerType::Local); let created = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); let update_input = UpdateWorkerInput { name: Some("updated_worker_name".to_string()), status: Some(WorkerStatus::Busy), capabilities: Some(json!({ "updated": true })), meta: Some(json!({ "version": "2.0" })), host: Some("updated-host".to_string()), port: Some(9090), }; let updated = WorkerRepository::update(&pool, created.id, update_input.clone()) .await .expect("Failed to update worker"); assert_eq!(updated.id, created.id); assert_eq!(updated.name, update_input.name.unwrap()); assert_eq!(updated.status, update_input.status); assert_eq!(updated.capabilities, update_input.capabilities); assert_eq!(updated.meta, update_input.meta); assert_eq!(updated.host, update_input.host); assert_eq!(updated.port, update_input.port); assert!(updated.updated > created.updated); } #[tokio::test] async fn test_update_worker_partial() { let pool = setup_db().await; let fixture = WorkerFixture::new("update_partial"); let input = fixture.create_input("partial", WorkerType::Remote); let created = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); let update_input = UpdateWorkerInput { status: Some(WorkerStatus::Inactive), name: None, capabilities: None, meta: None, host: None, port: None, }; let updated = WorkerRepository::update(&pool, created.id, update_input.clone()) .await .expect("Failed to update worker"); assert_eq!(updated.status, update_input.status); assert_eq!(updated.name, created.name); assert_eq!(updated.capabilities, created.capabilities); assert_eq!(updated.meta, created.meta); assert_eq!(updated.host, created.host); assert_eq!(updated.port, created.port); } #[tokio::test] async fn test_update_worker_empty() { let pool = setup_db().await; let fixture = WorkerFixture::new("update_empty"); let input = fixture.create_input("empty", WorkerType::Container); let created = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); let update_input = UpdateWorkerInput::default(); let result = WorkerRepository::update(&pool, created.id, update_input) .await .expect("Failed to update worker"); // Should return existing entity unchanged assert_eq!(result.id, created.id); assert_eq!(result.name, created.name); assert_eq!(result.status, created.status); } #[tokio::test] async fn test_delete_worker() { let pool = setup_db().await; let fixture = WorkerFixture::new("delete_worker"); let input = fixture.create_input("delete", WorkerType::Local); let created = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); let deleted = WorkerRepository::delete(&pool, created.id) .await .expect("Failed to delete worker"); assert!(deleted); let found = WorkerRepository::find_by_id(&pool, created.id) .await .expect("Query should succeed"); assert!(found.is_none()); } #[tokio::test] async fn test_delete_worker_not_found() { let pool = setup_db().await; let deleted = WorkerRepository::delete(&pool, 999999999) .await .expect("Delete should succeed"); assert!(!deleted); } // ============================================================================ // Specialized Query Tests // ============================================================================ #[tokio::test] async fn test_find_by_status_active() { let pool = setup_db().await; let fixture = WorkerFixture::new("find_by_status_active"); let mut input1 = fixture.create_input("active1", WorkerType::Local); input1.status = Some(WorkerStatus::Active); let mut input2 = fixture.create_input("active2", WorkerType::Remote); input2.status = Some(WorkerStatus::Active); let mut input3 = fixture.create_input("busy", WorkerType::Container); input3.status = Some(WorkerStatus::Busy); let created1 = WorkerRepository::create(&pool, input1) .await .expect("Failed to create active worker 1"); let created2 = WorkerRepository::create(&pool, input2) .await .expect("Failed to create active worker 2"); let _created3 = WorkerRepository::create(&pool, input3) .await .expect("Failed to create busy worker"); let active_workers = WorkerRepository::find_by_status(&pool, WorkerStatus::Active) .await .expect("Failed to find by status"); assert!(active_workers.iter().any(|w| w.id == created1.id)); assert!(active_workers.iter().any(|w| w.id == created2.id)); assert!(active_workers .iter() .all(|w| w.status == Some(WorkerStatus::Active))); } #[tokio::test] async fn test_find_by_status_all_statuses() { let pool = setup_db().await; let fixture = WorkerFixture::new("find_by_status_all"); let statuses = vec![ WorkerStatus::Active, WorkerStatus::Inactive, WorkerStatus::Busy, WorkerStatus::Error, ]; for status in &statuses { let mut input = fixture.create_input(&format!("{:?}", status), WorkerType::Local); input.status = Some(*status); let created = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); let found = WorkerRepository::find_by_status(&pool, *status) .await .expect("Failed to find by status"); assert!(found.iter().any(|w| w.id == created.id)); } } #[tokio::test] async fn test_find_by_type_local() { let pool = setup_db().await; let fixture = WorkerFixture::new("find_by_type_local"); let input1 = fixture.create_input("local1", WorkerType::Local); let input2 = fixture.create_input("local2", WorkerType::Local); let input3 = fixture.create_input("remote", WorkerType::Remote); let created1 = WorkerRepository::create(&pool, input1) .await .expect("Failed to create local worker 1"); let created2 = WorkerRepository::create(&pool, input2) .await .expect("Failed to create local worker 2"); let _created3 = WorkerRepository::create(&pool, input3) .await .expect("Failed to create remote worker"); let local_workers = WorkerRepository::find_by_type(&pool, WorkerType::Local) .await .expect("Failed to find by type"); assert!(local_workers.iter().any(|w| w.id == created1.id)); assert!(local_workers.iter().any(|w| w.id == created2.id)); assert!(local_workers .iter() .all(|w| w.worker_type == WorkerType::Local)); } #[tokio::test] async fn test_find_by_type_all_types() { let pool = setup_db().await; let fixture = WorkerFixture::new("find_by_type_all"); let types = vec![WorkerType::Local, WorkerType::Remote, WorkerType::Container]; for worker_type in &types { let input = fixture.create_input(&format!("{:?}", worker_type), *worker_type); let created = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); let found = WorkerRepository::find_by_type(&pool, *worker_type) .await .expect("Failed to find by type"); assert!(found.iter().any(|w| w.id == created.id)); assert!(found.iter().all(|w| w.worker_type == *worker_type)); } } #[tokio::test] async fn test_update_heartbeat() { let pool = setup_db().await; let fixture = WorkerFixture::new("update_heartbeat"); let input = fixture.create_input("heartbeat", WorkerType::Local); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); assert_eq!(worker.last_heartbeat, None); let before = chrono::Utc::now(); WorkerRepository::update_heartbeat(&pool, worker.id) .await .expect("Failed to update heartbeat"); let after = chrono::Utc::now(); let updated = WorkerRepository::find_by_id(&pool, worker.id) .await .expect("Failed to find worker") .expect("Worker not found"); assert!(updated.last_heartbeat.is_some()); let heartbeat = updated.last_heartbeat.unwrap(); assert!(heartbeat >= before); assert!(heartbeat <= after); } #[tokio::test] async fn test_update_heartbeat_multiple_times() { let pool = setup_db().await; let fixture = WorkerFixture::new("heartbeat_multiple"); let input = fixture.create_input("multi", WorkerType::Remote); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); WorkerRepository::update_heartbeat(&pool, worker.id) .await .expect("Failed to update heartbeat 1"); let first = WorkerRepository::find_by_id(&pool, worker.id) .await .expect("Failed to find worker") .expect("Worker not found") .last_heartbeat .unwrap(); tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; WorkerRepository::update_heartbeat(&pool, worker.id) .await .expect("Failed to update heartbeat 2"); let second = WorkerRepository::find_by_id(&pool, worker.id) .await .expect("Failed to find worker") .expect("Worker not found") .last_heartbeat .unwrap(); assert!(second > first); } // ============================================================================ // Runtime Association Tests // ============================================================================ #[tokio::test] async fn test_worker_with_runtime() { let pool = setup_db().await; let fixture = WorkerFixture::new("with_runtime"); // Create a runtime first let runtime_input = CreateRuntimeInput { r#ref: format!("{}.action.test_runtime", fixture.test_id), pack: None, pack_ref: None, description: Some("Test runtime".to_string()), name: "test_runtime".to_string(), distributions: json!({}), installation: None, }; let runtime = RuntimeRepository::create(&pool, runtime_input) .await .expect("Failed to create runtime"); // Create worker with runtime association let mut input = fixture.create_input("with_rt", WorkerType::Local); input.runtime = Some(runtime.id); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); assert_eq!(worker.runtime, Some(runtime.id)); let found = WorkerRepository::find_by_id(&pool, worker.id) .await .expect("Failed to find worker") .expect("Worker not found"); assert_eq!(found.runtime, Some(runtime.id)); } // ============================================================================ // Enum Tests // ============================================================================ #[tokio::test] async fn test_worker_type_local() { let pool = setup_db().await; let fixture = WorkerFixture::new("type_local"); let input = fixture.create_input("local", WorkerType::Local); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); assert_eq!(worker.worker_type, WorkerType::Local); } #[tokio::test] async fn test_worker_type_remote() { let pool = setup_db().await; let fixture = WorkerFixture::new("type_remote"); let input = fixture.create_input("remote", WorkerType::Remote); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); assert_eq!(worker.worker_type, WorkerType::Remote); } #[tokio::test] async fn test_worker_type_container() { let pool = setup_db().await; let fixture = WorkerFixture::new("type_container"); let input = fixture.create_input("container", WorkerType::Container); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); assert_eq!(worker.worker_type, WorkerType::Container); } #[tokio::test] async fn test_worker_status_active() { let pool = setup_db().await; let fixture = WorkerFixture::new("status_active"); let mut input = fixture.create_input("active", WorkerType::Local); input.status = Some(WorkerStatus::Active); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); assert_eq!(worker.status, Some(WorkerStatus::Active)); } #[tokio::test] async fn test_worker_status_inactive() { let pool = setup_db().await; let fixture = WorkerFixture::new("status_inactive"); let mut input = fixture.create_input("inactive", WorkerType::Local); input.status = Some(WorkerStatus::Inactive); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); assert_eq!(worker.status, Some(WorkerStatus::Inactive)); } #[tokio::test] async fn test_worker_status_busy() { let pool = setup_db().await; let fixture = WorkerFixture::new("status_busy"); let mut input = fixture.create_input("busy", WorkerType::Local); input.status = Some(WorkerStatus::Busy); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); assert_eq!(worker.status, Some(WorkerStatus::Busy)); } #[tokio::test] async fn test_worker_status_error() { let pool = setup_db().await; let fixture = WorkerFixture::new("status_error"); let mut input = fixture.create_input("error", WorkerType::Local); input.status = Some(WorkerStatus::Error); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); assert_eq!(worker.status, Some(WorkerStatus::Error)); } // ============================================================================ // Edge Cases and Constraints // ============================================================================ #[tokio::test] async fn test_duplicate_name_allowed() { let pool = setup_db().await; let fixture = WorkerFixture::new("duplicate_name"); // Use a fixed name for both workers let name = format!("{}_duplicate", fixture.test_id); let mut input1 = fixture.create_input("dup1", WorkerType::Local); input1.name = name.clone(); let mut input2 = fixture.create_input("dup2", WorkerType::Remote); input2.name = name.clone(); let worker1 = WorkerRepository::create(&pool, input1) .await .expect("Failed to create first worker"); let worker2 = WorkerRepository::create(&pool, input2) .await .expect("Failed to create second worker with same name"); assert_eq!(worker1.name, worker2.name); assert_ne!(worker1.id, worker2.id); } #[tokio::test] async fn test_json_fields() { let pool = setup_db().await; let fixture = WorkerFixture::new("json_fields"); let input = fixture.create_input("json", WorkerType::Container); let worker = WorkerRepository::create(&pool, input.clone()) .await .expect("Failed to create worker"); assert_eq!(worker.capabilities, input.capabilities); assert_eq!(worker.meta, input.meta); // Verify JSON structure let caps = worker.capabilities.unwrap(); assert_eq!(caps["cpu"], json!("x86_64")); assert_eq!(caps["memory"], json!("8GB")); } #[tokio::test] async fn test_null_json_fields() { let pool = setup_db().await; let fixture = WorkerFixture::new("null_json"); let input = fixture.create_minimal_input("nulljson"); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); assert_eq!(worker.capabilities, None); assert_eq!(worker.meta, None); } #[tokio::test] async fn test_null_status() { let pool = setup_db().await; let fixture = WorkerFixture::new("null_status"); let mut input = fixture.create_input("nostatus", WorkerType::Local); input.status = None; let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); assert_eq!(worker.status, None); } #[tokio::test] async fn test_list_ordering() { let pool = setup_db().await; let fixture = WorkerFixture::new("list_ordering"); let mut input1 = fixture.create_input("z", WorkerType::Local); input1.name = format!("{}_zzz_worker", fixture.test_id); let mut input2 = fixture.create_input("a", WorkerType::Remote); input2.name = format!("{}_aaa_worker", fixture.test_id); let mut input3 = fixture.create_input("m", WorkerType::Container); input3.name = format!("{}_mmm_worker", fixture.test_id); WorkerRepository::create(&pool, input1) .await .expect("Failed to create worker 1"); WorkerRepository::create(&pool, input2) .await .expect("Failed to create worker 2"); WorkerRepository::create(&pool, input3) .await .expect("Failed to create worker 3"); let list = WorkerRepository::list(&pool) .await .expect("Failed to list workers"); // Find our test workers in the list let test_workers: Vec<_> = list .iter() .filter(|w| w.name.contains(&fixture.test_id)) .collect(); assert_eq!(test_workers.len(), 3); // Verify they are sorted by name for i in 0..test_workers.len() - 1 { assert!(test_workers[i].name <= test_workers[i + 1].name); } } #[tokio::test] async fn test_timestamps() { let pool = setup_db().await; let fixture = WorkerFixture::new("timestamps"); let input = fixture.create_input("time", WorkerType::Local); let before = chrono::Utc::now(); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); let after = chrono::Utc::now(); assert!(worker.created >= before); assert!(worker.created <= after); assert!(worker.updated >= before); assert!(worker.updated <= after); assert_eq!(worker.created, worker.updated); } #[tokio::test] async fn test_update_changes_timestamp() { let pool = setup_db().await; let fixture = WorkerFixture::new("timestamp_update"); let input = fixture.create_input("ts", WorkerType::Remote); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; let update_input = UpdateWorkerInput { status: Some(WorkerStatus::Busy), ..Default::default() }; let updated = WorkerRepository::update(&pool, worker.id, update_input) .await .expect("Failed to update worker"); assert_eq!(updated.created, worker.created); assert!(updated.updated > worker.updated); } #[tokio::test] async fn test_heartbeat_updates_timestamp() { let pool = setup_db().await; let fixture = WorkerFixture::new("heartbeat_updates"); let input = fixture.create_input("hb", WorkerType::Container); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); let original_updated = worker.updated; tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; WorkerRepository::update_heartbeat(&pool, worker.id) .await .expect("Failed to update heartbeat"); let after_heartbeat = WorkerRepository::find_by_id(&pool, worker.id) .await .expect("Failed to find worker") .expect("Worker not found"); // Heartbeat should update both last_heartbeat and updated timestamp (due to trigger) assert!(after_heartbeat.last_heartbeat.is_some()); assert!(after_heartbeat.updated > original_updated); } #[tokio::test] async fn test_port_range() { let pool = setup_db().await; let fixture = WorkerFixture::new("port_range"); // Test various port numbers let ports = vec![1, 80, 443, 8080, 65535]; for port in ports { let mut input = fixture.create_input(&format!("port{}", port), WorkerType::Local); input.port = Some(port); let worker = WorkerRepository::create(&pool, input) .await .expect(&format!("Failed to create worker with port {}", port)); assert_eq!(worker.port, Some(port)); } } #[tokio::test] async fn test_update_status_lifecycle() { let pool = setup_db().await; let fixture = WorkerFixture::new("status_lifecycle"); let mut input = fixture.create_input("lifecycle", WorkerType::Local); input.status = Some(WorkerStatus::Inactive); let worker = WorkerRepository::create(&pool, input) .await .expect("Failed to create worker"); assert_eq!(worker.status, Some(WorkerStatus::Inactive)); // Transition to Active let update1 = UpdateWorkerInput { status: Some(WorkerStatus::Active), ..Default::default() }; let worker = WorkerRepository::update(&pool, worker.id, update1) .await .expect("Failed to update to Active"); assert_eq!(worker.status, Some(WorkerStatus::Active)); // Transition to Busy let update2 = UpdateWorkerInput { status: Some(WorkerStatus::Busy), ..Default::default() }; let worker = WorkerRepository::update(&pool, worker.id, update2) .await .expect("Failed to update to Busy"); assert_eq!(worker.status, Some(WorkerStatus::Busy)); // Transition to Error let update3 = UpdateWorkerInput { status: Some(WorkerStatus::Error), ..Default::default() }; let worker = WorkerRepository::update(&pool, worker.id, update3) .await .expect("Failed to update to Error"); assert_eq!(worker.status, Some(WorkerStatus::Error)); // Back to Inactive let update4 = UpdateWorkerInput { status: Some(WorkerStatus::Inactive), ..Default::default() }; let worker = WorkerRepository::update(&pool, worker.id, update4) .await .expect("Failed to update back to Inactive"); assert_eq!(worker.status, Some(WorkerStatus::Inactive)); }