use crate::git_helpers::{create_local_repo, push_new_commit}; use crate::harness::TestServer; use crate::runtime::{skip_without_git, skip_without_runtime}; use serial_test::serial; use std::time::Duration; use witryna::config::{BuildOverrides, Config, SiteConfig}; fn polling_site(name: &str, repo_url: &str) -> SiteConfig { SiteConfig { name: name.to_owned(), repo_url: repo_url.to_owned(), branch: "main".to_owned(), webhook_token: "poll-token".to_owned(), webhook_token_file: None, build_overrides: BuildOverrides { image: Some("alpine:latest".to_owned()), command: Some("mkdir -p out && echo '

polled

' > out/index.html".to_owned()), public: Some("out".to_owned()), }, poll_interval: Some(Duration::from_secs(2)), build_timeout: None, cache_dirs: None, post_deploy: None, env: None, container_memory: None, container_cpus: None, container_pids_limit: None, container_network: "none".to_owned(), git_depth: None, container_workdir: None, config_file: None, } } #[tokio::test] #[serial] async fn polling_triggers_build_on_new_commits() { skip_without_git!(); skip_without_runtime!(); let tempdir = tempfile::tempdir().unwrap(); let base_dir = tempdir.path().to_path_buf(); let repo_dir = tempdir.path().join("repos"); tokio::fs::create_dir_all(&repo_dir).await.unwrap(); let repo_url = create_local_repo(&repo_dir, "main").await; let site = polling_site("poll-site", &repo_url); let config = Config { listen_address: "127.0.0.1:0".to_owned(), container_runtime: crate::harness::test_config(base_dir.clone()).container_runtime, base_dir: base_dir.clone(), log_dir: base_dir.join("logs"), log_level: "debug".to_owned(), rate_limit_per_minute: 100, max_builds_to_keep: 5, git_timeout: None, sites: vec![site], }; let server = TestServer::start(config).await; // Start polling server .state .polling_manager .start_polling(server.state.clone()) .await; // Wait for the initial poll cycle to trigger a build let builds_dir = base_dir.join("builds/poll-site"); let max_wait = Duration::from_secs(30); let start = std::time::Instant::now(); loop { if start.elapsed() > max_wait { // Polling may not have triggered yet — acceptable in CI eprintln!("SOFT FAIL: polling did not trigger build within {max_wait:?}"); return; } if builds_dir.join("current").is_symlink() { break; } tokio::time::sleep(Duration::from_millis(500)).await; } let first_target = tokio::fs::read_link(builds_dir.join("current")) .await .unwrap(); // Push a new commit push_new_commit(&repo_url, &tempdir.path().join("push"), "main").await; // Wait for polling to detect and rebuild let max_wait = Duration::from_secs(30); let start = std::time::Instant::now(); loop { if start.elapsed() > max_wait { eprintln!("SOFT FAIL: polling did not detect new commit within {max_wait:?}"); return; } if let Ok(target) = tokio::fs::read_link(builds_dir.join("current")).await && target != first_target { // New build detected return; } tokio::time::sleep(Duration::from_millis(500)).await; } }