summaryrefslogtreecommitdiff
path: root/tests/integration/sighup.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/integration/sighup.rs')
-rw-r--r--tests/integration/sighup.rs149
1 files changed, 149 insertions, 0 deletions
diff --git a/tests/integration/sighup.rs b/tests/integration/sighup.rs
new file mode 100644
index 0000000..23c0dfd
--- /dev/null
+++ b/tests/integration/sighup.rs
@@ -0,0 +1,149 @@
+use crate::harness::{SiteBuilder, TestServer, test_config_with_site};
+use serial_test::serial;
+use std::time::Duration;
+
+/// Send SIGHUP to the current process.
+fn send_sighup_to_self() {
+ use nix::sys::signal::{Signal, kill};
+ use nix::unistd::Pid;
+
+ kill(Pid::this(), Signal::SIGHUP).expect("failed to send SIGHUP");
+}
+
+/// Install the SIGHUP handler and wait for it to be registered.
+async fn install_sighup_handler(server: &TestServer) {
+ witryna::test_support::setup_sighup_handler(&server.state);
+ // Yield to allow the spawned handler task to register the signal listener
+ tokio::task::yield_now().await;
+ tokio::time::sleep(std::time::Duration::from_millis(50)).await;
+}
+
+#[tokio::test]
+#[serial]
+async fn sighup_reload_keeps_server_healthy() {
+ let dir = tempfile::tempdir().unwrap().keep();
+ let site = SiteBuilder::new("my-site", "https://example.com/repo.git", "test-token").build();
+ let server = TestServer::start(test_config_with_site(dir, site)).await;
+
+ install_sighup_handler(&server).await;
+
+ // Verify server is healthy before SIGHUP
+ let resp = TestServer::client()
+ .get(server.url("/health"))
+ .send()
+ .await
+ .unwrap();
+ assert_eq!(resp.status().as_u16(), 200);
+
+ // Send SIGHUP (reload config)
+ send_sighup_to_self();
+
+ // Give the handler time to process
+ tokio::time::sleep(std::time::Duration::from_millis(500)).await;
+
+ // Server should still be healthy
+ let resp = TestServer::client()
+ .get(server.url("/health"))
+ .send()
+ .await
+ .unwrap();
+ assert_eq!(resp.status().as_u16(), 200);
+}
+
+#[tokio::test]
+#[serial]
+async fn rapid_sighup_does_not_crash() {
+ let dir = tempfile::tempdir().unwrap().keep();
+ let site = SiteBuilder::new("my-site", "https://example.com/repo.git", "test-token").build();
+ let server = TestServer::start(test_config_with_site(dir, site)).await;
+
+ install_sighup_handler(&server).await;
+
+ // Send multiple SIGHUPs in quick succession
+ for _ in 0..3 {
+ send_sighup_to_self();
+ tokio::time::sleep(std::time::Duration::from_millis(50)).await;
+ }
+
+ // Wait for stabilization
+ tokio::time::sleep(std::time::Duration::from_millis(500)).await;
+
+ // Server should survive
+ let resp = TestServer::client()
+ .get(server.url("/health"))
+ .send()
+ .await
+ .unwrap();
+ assert_eq!(resp.status().as_u16(), 200);
+}
+
+#[tokio::test]
+#[serial]
+async fn sighup_preserves_listen_address() {
+ let dir = tempfile::tempdir().unwrap().keep();
+ let site = SiteBuilder::new("my-site", "https://example.com/repo.git", "test-token").build();
+ let server = TestServer::start(test_config_with_site(dir, site)).await;
+
+ install_sighup_handler(&server).await;
+
+ // Verify server is healthy before SIGHUP
+ let resp = TestServer::client()
+ .get(server.url("/health"))
+ .send()
+ .await
+ .unwrap();
+ assert_eq!(resp.status().as_u16(), 200);
+
+ // Rewrite the on-disk config with a different listen_address (unreachable port)
+ // and an additional site to verify reloadable fields are updated
+ let config_path = server.state.config_path.as_ref();
+ let new_toml = format!(
+ r#"listen_address = "127.0.0.1:19999"
+container_runtime = "podman"
+base_dir = "{}"
+log_dir = "{}"
+log_level = "debug"
+
+[[sites]]
+name = "my-site"
+repo_url = "https://example.com/repo.git"
+branch = "main"
+webhook_token = "test-token"
+
+[[sites]]
+name = "new-site"
+repo_url = "https://example.com/new.git"
+branch = "main"
+webhook_token = "new-token"
+"#,
+ server.state.config.read().await.base_dir.display(),
+ server.state.config.read().await.log_dir.display(),
+ );
+ tokio::fs::write(config_path, &new_toml).await.unwrap();
+
+ // Send SIGHUP to reload
+ send_sighup_to_self();
+ tokio::time::sleep(Duration::from_millis(500)).await;
+
+ // Server should still respond on the original port (listen_address preserved)
+ let resp = TestServer::client()
+ .get(server.url("/health"))
+ .send()
+ .await
+ .unwrap();
+ assert_eq!(resp.status().as_u16(), 200);
+
+ // Verify the reloadable field (sites) was updated
+ let config = server.state.config.read().await;
+ assert_eq!(config.sites.len(), 2, "sites should have been reloaded");
+ assert!(
+ config.find_site("new-site").is_some(),
+ "new-site should exist after reload"
+ );
+
+ // Verify non-reloadable field was preserved (not overwritten with "127.0.0.1:19999")
+ assert_ne!(
+ config.listen_address, "127.0.0.1:19999",
+ "listen_address should be preserved from original config"
+ );
+}