261 lines
7.9 KiB
Rust
261 lines
7.9 KiB
Rust
//! Service discovery integration tests
|
|
//!
|
|
//! Tests for service discovery shim functionality for dynamic worker registration.
|
|
|
|
use axum::{
|
|
body::Body,
|
|
extract::Request,
|
|
http::{header::CONTENT_TYPE, StatusCode},
|
|
};
|
|
use serde_json::json;
|
|
use smg::config::RouterConfig;
|
|
use tower::ServiceExt;
|
|
|
|
use crate::common::{
|
|
mock_worker::{HealthStatus, MockWorkerConfig, WorkerType},
|
|
AppTestContext,
|
|
};
|
|
|
|
#[cfg(test)]
|
|
mod service_discovery_tests {
|
|
use super::*;
|
|
|
|
/// Test service discovery endpoint responds correctly
|
|
#[tokio::test]
|
|
async fn test_service_discovery_endpoint() {
|
|
let config = RouterConfig::builder()
|
|
.regular_mode(vec![])
|
|
.round_robin_policy()
|
|
.host("127.0.0.1")
|
|
.port(4000)
|
|
.max_payload_size(256 * 1024 * 1024)
|
|
.request_timeout_secs(600)
|
|
.worker_startup_timeout_secs(5)
|
|
.worker_startup_check_interval_secs(1)
|
|
.max_concurrent_requests(64)
|
|
.queue_timeout_secs(60)
|
|
.build_unchecked();
|
|
|
|
let ctx = AppTestContext::new_with_config(
|
|
config,
|
|
vec![MockWorkerConfig {
|
|
port: 20000,
|
|
worker_type: WorkerType::Regular,
|
|
health_status: HealthStatus::Healthy,
|
|
response_delay_ms: 0,
|
|
fail_rate: 0.0,
|
|
}],
|
|
)
|
|
.await;
|
|
|
|
let app = ctx.create_app().await;
|
|
|
|
// Check if service discovery endpoint exists
|
|
let req = Request::builder()
|
|
.method("GET")
|
|
.uri("/v1/workers")
|
|
.body(Body::empty())
|
|
.unwrap();
|
|
|
|
let resp = app.clone().oneshot(req).await.unwrap();
|
|
// Endpoint might return OK with worker list or 404 if not implemented
|
|
assert!(
|
|
resp.status() == StatusCode::OK || resp.status() == StatusCode::NOT_FOUND,
|
|
"Workers endpoint should respond, got {}",
|
|
resp.status()
|
|
);
|
|
|
|
ctx.shutdown().await;
|
|
}
|
|
|
|
/// Test worker registration via discovery shim
|
|
#[tokio::test]
|
|
async fn test_worker_registration() {
|
|
let config = RouterConfig::builder()
|
|
.regular_mode(vec![])
|
|
.round_robin_policy()
|
|
.host("127.0.0.1")
|
|
.port(4001)
|
|
.max_payload_size(256 * 1024 * 1024)
|
|
.request_timeout_secs(600)
|
|
.worker_startup_timeout_secs(5)
|
|
.worker_startup_check_interval_secs(1)
|
|
.max_concurrent_requests(64)
|
|
.queue_timeout_secs(60)
|
|
.build_unchecked();
|
|
|
|
let ctx = AppTestContext::new_with_config(
|
|
config,
|
|
vec![MockWorkerConfig {
|
|
port: 20001,
|
|
worker_type: WorkerType::Regular,
|
|
health_status: HealthStatus::Healthy,
|
|
response_delay_ms: 0,
|
|
fail_rate: 0.0,
|
|
}],
|
|
)
|
|
.await;
|
|
|
|
let app = ctx.create_app().await;
|
|
|
|
// Register a new worker via discovery endpoint
|
|
let register_payload = json!({
|
|
"url": "http://127.0.0.1:20002",
|
|
"weight": 1.0
|
|
});
|
|
|
|
let req = Request::builder()
|
|
.method("POST")
|
|
.uri("/register_worker")
|
|
.header(CONTENT_TYPE, "application/json")
|
|
.body(Body::from(
|
|
serde_json::to_string(®ister_payload).unwrap(),
|
|
))
|
|
.unwrap();
|
|
|
|
let resp = app.clone().oneshot(req).await.unwrap();
|
|
// Registration might succeed or endpoint might not exist
|
|
assert!(
|
|
resp.status() == StatusCode::OK
|
|
|| resp.status() == StatusCode::ACCEPTED
|
|
|| resp.status() == StatusCode::NOT_FOUND,
|
|
"Registration should respond appropriately, got {}",
|
|
resp.status()
|
|
);
|
|
|
|
ctx.shutdown().await;
|
|
}
|
|
|
|
/// Test worker deregistration via discovery shim
|
|
#[tokio::test]
|
|
async fn test_worker_deregistration() {
|
|
let config = RouterConfig::builder()
|
|
.regular_mode(vec![])
|
|
.round_robin_policy()
|
|
.host("127.0.0.1")
|
|
.port(4002)
|
|
.max_payload_size(256 * 1024 * 1024)
|
|
.request_timeout_secs(600)
|
|
.worker_startup_timeout_secs(5)
|
|
.worker_startup_check_interval_secs(1)
|
|
.max_concurrent_requests(64)
|
|
.queue_timeout_secs(60)
|
|
.build_unchecked();
|
|
|
|
let ctx = AppTestContext::new_with_config(
|
|
config,
|
|
vec![
|
|
MockWorkerConfig {
|
|
port: 20003,
|
|
worker_type: WorkerType::Regular,
|
|
health_status: HealthStatus::Healthy,
|
|
response_delay_ms: 0,
|
|
fail_rate: 0.0,
|
|
},
|
|
MockWorkerConfig {
|
|
port: 20004,
|
|
worker_type: WorkerType::Regular,
|
|
health_status: HealthStatus::Healthy,
|
|
response_delay_ms: 0,
|
|
fail_rate: 0.0,
|
|
},
|
|
],
|
|
)
|
|
.await;
|
|
|
|
let app = ctx.create_app().await;
|
|
|
|
// Deregister a worker via discovery endpoint
|
|
let deregister_payload = json!({
|
|
"url": "http://127.0.0.1:20003"
|
|
});
|
|
|
|
let req = Request::builder()
|
|
.method("POST")
|
|
.uri("/deregister_worker")
|
|
.header(CONTENT_TYPE, "application/json")
|
|
.body(Body::from(
|
|
serde_json::to_string(&deregister_payload).unwrap(),
|
|
))
|
|
.unwrap();
|
|
|
|
let resp = app.clone().oneshot(req).await.unwrap();
|
|
assert!(
|
|
resp.status() == StatusCode::OK
|
|
|| resp.status() == StatusCode::ACCEPTED
|
|
|| resp.status() == StatusCode::NOT_FOUND,
|
|
"Deregistration should respond appropriately, got {}",
|
|
resp.status()
|
|
);
|
|
|
|
// Requests should still work with remaining worker
|
|
let payload = json!({
|
|
"text": "Test after deregistration",
|
|
"stream": false
|
|
});
|
|
|
|
let req = Request::builder()
|
|
.method("POST")
|
|
.uri("/generate")
|
|
.header(CONTENT_TYPE, "application/json")
|
|
.body(Body::from(serde_json::to_string(&payload).unwrap()))
|
|
.unwrap();
|
|
|
|
let resp = app.oneshot(req).await.unwrap();
|
|
assert_eq!(
|
|
resp.status(),
|
|
StatusCode::OK,
|
|
"Request should succeed with remaining worker"
|
|
);
|
|
|
|
ctx.shutdown().await;
|
|
}
|
|
|
|
/// Test health status reporting for discovery
|
|
#[tokio::test]
|
|
async fn test_health_status_endpoint() {
|
|
let config = RouterConfig::builder()
|
|
.regular_mode(vec![])
|
|
.round_robin_policy()
|
|
.host("127.0.0.1")
|
|
.port(4003)
|
|
.max_payload_size(256 * 1024 * 1024)
|
|
.request_timeout_secs(600)
|
|
.worker_startup_timeout_secs(5)
|
|
.worker_startup_check_interval_secs(1)
|
|
.max_concurrent_requests(64)
|
|
.queue_timeout_secs(60)
|
|
.build_unchecked();
|
|
|
|
let ctx = AppTestContext::new_with_config(
|
|
config,
|
|
vec![MockWorkerConfig {
|
|
port: 20005,
|
|
worker_type: WorkerType::Regular,
|
|
health_status: HealthStatus::Healthy,
|
|
response_delay_ms: 0,
|
|
fail_rate: 0.0,
|
|
}],
|
|
)
|
|
.await;
|
|
|
|
let app = ctx.create_app().await;
|
|
|
|
// Check health endpoint
|
|
let req = Request::builder()
|
|
.method("GET")
|
|
.uri("/health")
|
|
.body(Body::empty())
|
|
.unwrap();
|
|
|
|
let resp = app.oneshot(req).await.unwrap();
|
|
assert_eq!(
|
|
resp.status(),
|
|
StatusCode::OK,
|
|
"Health endpoint should return OK when workers are healthy"
|
|
);
|
|
|
|
ctx.shutdown().await;
|
|
}
|
|
}
|