1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
use crate::harness::{SiteBuilder, TestServer, test_config_with_site};
#[tokio::test]
async fn concurrent_build_gets_queued() {
let dir = tempfile::tempdir().unwrap().keep();
let site = SiteBuilder::new("my-site", "https://example.com/repo.git", "secret-token").build();
let server = TestServer::start(test_config_with_site(dir, site)).await;
// Pre-inject a build in progress via AppState
server
.state
.build_scheduler
.in_progress
.lock()
.unwrap()
.insert("my-site".to_owned());
let resp = TestServer::client()
.post(server.url("/my-site"))
.header("Authorization", "Bearer secret-token")
.send()
.await
.unwrap();
assert_eq!(resp.status().as_u16(), 202);
let body = resp.text().await.unwrap();
let json: serde_json::Value = serde_json::from_str(&body).unwrap();
assert_eq!(json["status"], "queued");
}
#[tokio::test]
async fn concurrent_build_queue_collapse() {
let dir = tempfile::tempdir().unwrap().keep();
let site = SiteBuilder::new("my-site", "https://example.com/repo.git", "secret-token").build();
let server = TestServer::start(test_config_with_site(dir, site)).await;
// Pre-inject a build in progress and a queued rebuild
server
.state
.build_scheduler
.in_progress
.lock()
.unwrap()
.insert("my-site".to_owned());
server
.state
.build_scheduler
.queued
.lock()
.unwrap()
.insert("my-site".to_owned());
// Third request should collapse (202, no body)
let resp = TestServer::client()
.post(server.url("/my-site"))
.header("Authorization", "Bearer secret-token")
.send()
.await
.unwrap();
assert_eq!(resp.status().as_u16(), 202);
let body = resp.text().await.unwrap();
assert!(body.is_empty());
}
#[tokio::test]
async fn concurrent_different_sites_both_accepted() {
let dir = tempfile::tempdir().unwrap().keep();
let sites = vec![
SiteBuilder::new("site-one", "https://example.com/one.git", "token-one").build(),
SiteBuilder::new("site-two", "https://example.com/two.git", "token-two").build(),
];
let config = crate::harness::test_config_with_sites(dir, sites);
let server = TestServer::start(config).await;
// First site — accepted
let resp1 = TestServer::client()
.post(server.url("/site-one"))
.header("Authorization", "Bearer token-one")
.send()
.await
.unwrap();
assert_eq!(resp1.status().as_u16(), 202);
// Second site — also accepted (different build lock)
let resp2 = TestServer::client()
.post(server.url("/site-two"))
.header("Authorization", "Bearer token-two")
.send()
.await
.unwrap();
assert_eq!(resp2.status().as_u16(), 202);
}
#[tokio::test]
async fn build_in_progress_checked_after_auth() {
let dir = tempfile::tempdir().unwrap().keep();
let site = SiteBuilder::new("my-site", "https://example.com/repo.git", "secret-token").build();
let server = TestServer::start(test_config_with_site(dir, site)).await;
// Pre-mark site as building
server
.state
.build_scheduler
.in_progress
.lock()
.unwrap()
.insert("my-site".to_owned());
// Request with wrong token should return 401 (auth checked before build status)
let resp = TestServer::client()
.post(server.url("/my-site"))
.header("Authorization", "Bearer wrong-token")
.send()
.await
.unwrap();
assert_eq!(resp.status().as_u16(), 401);
}
|