summaryrefslogtreecommitdiff
path: root/tests/integration/harness.rs
diff options
context:
space:
mode:
authorDawid Rycerz <dawid@rycerz.xyz>2026-02-15 21:27:00 +0100
committerDawid Rycerz <dawid@rycerz.xyz>2026-02-15 21:27:00 +0100
commitce0dbf6b249956700c6a1705bf4ad85a09d53e8c (patch)
treed7c3236807cfbf75d7f3a355eb5df5a5e2cc4ad7 /tests/integration/harness.rs
parent064a1d01c5c14f5ecc032fa9b8346a4a88b893f6 (diff)
feat: witryna 0.2.0HEADv0.2.0main
Switch, cleanup, and status CLI commands. Persistent build state via state.json. Post-deploy hooks on success and failure with WITRYNA_BUILD_STATUS. Dependency diet (axum→tiny_http, clap→argh, tracing→log). Drop built-in rate limiting. Nix flake with NixOS module. Arch Linux PKGBUILD. Centralized version management. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'tests/integration/harness.rs')
-rw-r--r--tests/integration/harness.rs77
1 files changed, 40 insertions, 37 deletions
diff --git a/tests/integration/harness.rs b/tests/integration/harness.rs
index c015fa8..b985971 100644
--- a/tests/integration/harness.rs
+++ b/tests/integration/harness.rs
@@ -1,11 +1,8 @@
-use governor::{Quota, RateLimiter};
use std::collections::HashMap;
-use std::num::NonZeroU32;
use std::path::PathBuf;
-use std::sync::Arc;
+use std::sync::{Arc, RwLock};
use tempfile::TempDir;
-use tokio::net::TcpListener;
-use tokio::sync::{RwLock, oneshot};
+use tiny_http::Server;
use witryna::build_guard::BuildScheduler;
use witryna::config::{BuildOverrides, Config, SiteConfig};
use witryna::polling::PollingManager;
@@ -18,18 +15,14 @@ pub struct TestServer {
/// Kept alive for RAII cleanup of the config file written during startup.
#[allow(dead_code)]
pub tempdir: TempDir,
- shutdown_tx: Option<oneshot::Sender<()>>,
+ server: Arc<Server>,
+ server_thread: Option<std::thread::JoinHandle<()>>,
}
impl TestServer {
/// Start a new test server with the given config.
/// Binds to `127.0.0.1:0` (OS-assigned port).
- pub async fn start(config: Config) -> Self {
- Self::start_with_rate_limit(config, 1000).await
- }
-
- /// Start a new test server with a specific rate limit.
- pub async fn start_with_rate_limit(mut config: Config, rate_limit: u32) -> Self {
+ pub async fn start(mut config: Config) -> Self {
let tempdir = TempDir::new().expect("failed to create temp dir");
let config_path = tempdir.path().join("witryna.toml");
@@ -44,38 +37,50 @@ impl TestServer {
.await
.expect("failed to resolve secrets");
- let quota = Quota::per_minute(NonZeroU32::new(rate_limit).expect("rate limit must be > 0"));
-
let state = AppState {
config: Arc::new(RwLock::new(config)),
config_path: Arc::new(config_path),
build_scheduler: Arc::new(BuildScheduler::new()),
- rate_limiter: Arc::new(RateLimiter::dashmap(quota)),
polling_manager: Arc::new(PollingManager::new()),
};
- let listener = TcpListener::bind("127.0.0.1:0")
- .await
- .expect("failed to bind to random port");
- let port = listener.local_addr().unwrap().port();
+ let server = Arc::new(Server::http("127.0.0.1:0").expect("failed to bind"));
+ let port = match server.server_addr() {
+ tiny_http::ListenAddr::IP(addr) => addr.port(),
+ _ => unreachable!("expected IP address"),
+ };
let base_url = format!("http://127.0.0.1:{port}");
- let (shutdown_tx, shutdown_rx) = oneshot::channel::<()>();
-
- let server_state = state.clone();
- tokio::spawn(async move {
- witryna::test_support::run_server(server_state, listener, async {
- let _ = shutdown_rx.await;
- })
- .await
- .expect("server failed");
- });
+ // Shutdown uses server.unblock() directly — no oneshot needed.
+ // We pass a future that never resolves; shutdown is triggered
+ // by calling server.unblock() from TestServer::shutdown().
+ let server_thread = witryna::test_support::run_server(
+ state.clone(),
+ server.clone(),
+ std::future::pending(),
+ );
+
+ // Readiness probe: wait for server to accept connections
+ let client = reqwest::Client::new();
+ for _ in 0..50 {
+ if client
+ .get(format!("{base_url}/health"))
+ .send()
+ .await
+ .map(|r| r.status().as_u16() == 200)
+ .unwrap_or(false)
+ {
+ break;
+ }
+ tokio::time::sleep(std::time::Duration::from_millis(10)).await;
+ }
Self {
base_url,
state,
tempdir,
- shutdown_tx: Some(shutdown_tx),
+ server,
+ server_thread: Some(server_thread),
}
}
@@ -91,8 +96,11 @@ impl TestServer {
/// Shut down the server gracefully.
pub fn shutdown(&mut self) {
- if let Some(tx) = self.shutdown_tx.take() {
- let _ = tx.send(());
+ // Unblock the HTTP request loop directly — no async channel needed
+ self.server.unblock();
+ // Join the HTTP thread to ensure clean teardown
+ if let Some(handle) = self.server_thread.take() {
+ let _ = handle.join();
}
}
}
@@ -112,7 +120,6 @@ pub fn test_config(base_dir: PathBuf) -> Config {
base_dir,
log_dir,
log_level: "debug".to_owned(),
- rate_limit_per_minute: 10,
max_builds_to_keep: 5,
git_timeout: None,
sites: vec![],
@@ -128,7 +135,6 @@ pub fn test_config_with_site(base_dir: PathBuf, site: SiteConfig) -> Config {
base_dir,
log_dir,
log_level: "debug".to_owned(),
- rate_limit_per_minute: 10,
max_builds_to_keep: 5,
git_timeout: None,
sites: vec![site],
@@ -144,7 +150,6 @@ pub fn test_config_with_sites(base_dir: PathBuf, sites: Vec<SiteConfig>) -> Conf
base_dir,
log_dir,
log_level: "debug".to_owned(),
- rate_limit_per_minute: 10,
max_builds_to_keep: 5,
git_timeout: None,
sites,
@@ -286,7 +291,6 @@ fn build_config_toml(config: &Config) -> String {
{}base_dir = "{}"
log_dir = "{}"
log_level = "{}"
-rate_limit_per_minute = {}
max_builds_to_keep = {}
"#,
config.listen_address,
@@ -294,7 +298,6 @@ max_builds_to_keep = {}
config.base_dir.display(),
config.log_dir.display(),
config.log_level,
- config.rate_limit_per_minute,
config.max_builds_to_keep,
);