Skip to content

Commit 6e9935a

Browse files
authored
Merge pull request #111 from Kobzol/fix-refresh-tests
Fix refresh tests
2 parents 69984e4 + 4625e9d commit 6e9935a

File tree

4 files changed

+162
-140
lines changed

4 files changed

+162
-140
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ base64 = "0.22.1"
6161
tracing-test = "0.2.4"
6262
regex = "1.10.4"
6363
parking_lot = "0.12.3"
64-
once_cell = "1.19.0"
64+
thread_local = "1.1.8"
6565

6666
[profile.release]
6767
debug = 1

src/bors/handlers/refresh.rs

Lines changed: 127 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -105,132 +105,130 @@ fn elapsed_time(date: DateTime<Utc>) -> Duration {
105105
(time - date).to_std().unwrap_or(Duration::ZERO)
106106
}
107107

108-
// TODO: we need a way to get MOCK_TIME working with a multi-threaded tokio runtime
109-
// #[cfg(test)]
110-
// mod tests {
111-
// use crate::bors::handlers::refresh::MOCK_TIME;
112-
// use crate::bors::handlers::WAIT_FOR_WORKFLOW_STARTED;
113-
// use crate::database::DbClient;
114-
// use crate::tests::mocks::{default_repo_name, run_test, BorsBuilder, WorkflowEvent, World};
115-
// use chrono::Utc;
116-
// use std::future::Future;
117-
// use std::time::Duration;
118-
// use tokio::runtime::RuntimeFlavor;
119-
//
120-
// #[sqlx::test]
121-
// async fn refresh_no_builds(pool: sqlx::PgPool) {
122-
// run_test(pool, |tester| async move {
123-
// tester.refresh().await;
124-
// Ok(tester)
125-
// })
126-
// .await;
127-
// }
128-
//
129-
// #[sqlx::test]
130-
// async fn refresh_do_nothing_before_timeout(pool: sqlx::PgPool) {
131-
// let world = World::default();
132-
// world.default_repo().lock().set_config(
133-
// r#"
134-
// timeout = 3600
135-
// "#,
136-
// );
137-
// BorsBuilder::new(pool)
138-
// .world(world)
139-
// .run_test(|mut tester| async move {
140-
// tester.post_comment("@bors try").await?;
141-
// tester.expect_comments(1).await;
142-
// with_mocked_time(Duration::from_secs(10), async {
143-
// tester.refresh().await;
144-
// })
145-
// .await;
146-
// Ok(tester)
147-
// })
148-
// .await;
149-
// }
150-
//
151-
// #[sqlx::test]
152-
// async fn refresh_cancel_build_after_timeout(pool: sqlx::PgPool) {
153-
// let world = World::default();
154-
// world.default_repo().lock().set_config(
155-
// r#"
156-
// timeout = 3600
157-
// "#,
158-
// );
159-
// BorsBuilder::new(pool)
160-
// .world(world)
161-
// .run_test(|mut tester| async move {
162-
// tester.post_comment("@bors try").await?;
163-
// tester.expect_comments(1).await;
164-
// with_mocked_time(Duration::from_secs(4000), async {
165-
// assert_eq!(
166-
// tester
167-
// .db()
168-
// .get_running_builds(&default_repo_name())
169-
// .await
170-
// .unwrap()
171-
// .len(),
172-
// 1
173-
// );
174-
// tester.refresh().await;
175-
// })
176-
// .await;
177-
// insta::assert_snapshot!(tester.get_comment().await?, @":boom: Test timed out");
178-
// assert_eq!(
179-
// tester
180-
// .db()
181-
// .get_running_builds(&default_repo_name())
182-
// .await
183-
// .unwrap()
184-
// .len(),
185-
// 0
186-
// );
187-
// Ok(tester)
188-
// })
189-
// .await;
190-
// }
191-
//
192-
// #[sqlx::test]
193-
// async fn refresh_cancel_workflow_after_timeout(pool: sqlx::PgPool) {
194-
// let world = World::default();
195-
// world.default_repo().lock().set_config(
196-
// r#"
197-
// timeout = 3600
198-
// "#,
199-
// );
200-
// let world = BorsBuilder::new(pool)
201-
// .world(world)
202-
// .run_test(|mut tester| async move {
203-
// tester.post_comment("@bors try").await?;
204-
// tester.expect_comments(1).await;
205-
// tester
206-
// .workflow_event(WorkflowEvent::started(tester.try_branch()))
207-
// .await?;
208-
// WAIT_FOR_WORKFLOW_STARTED.sync().await;
209-
//
210-
// with_mocked_time(Duration::from_secs(4000), async {
211-
// tester.refresh().await;
212-
// })
213-
// .await;
214-
// tester.expect_comments(1).await;
215-
// Ok(tester)
216-
// })
217-
// .await;
218-
// world.check_cancelled_workflows(default_repo_name(), &[1]);
219-
// }
220-
//
221-
// async fn with_mocked_time<Fut: Future<Output = ()>>(in_future: Duration, future: Fut) {
222-
// // It is important to use this function only with a single threaded runtime,
223-
// // otherwise the `MOCK_TIME` variable might get mixed up between different threads.
224-
// assert_eq!(
225-
// tokio::runtime::Handle::current().runtime_flavor(),
226-
// RuntimeFlavor::CurrentThread
227-
// );
228-
// MOCK_TIME.with(|time| {
229-
// *time.borrow_mut() = Some(Utc::now() + chrono::Duration::from_std(in_future).unwrap());
230-
// });
231-
// future.await;
232-
// MOCK_TIME.with(|time| {
233-
// *time.borrow_mut() = None;
234-
// });
235-
// }
236-
// }
108+
#[cfg(test)]
109+
mod tests {
110+
use crate::bors::handlers::refresh::MOCK_TIME;
111+
use crate::bors::handlers::WAIT_FOR_WORKFLOW_STARTED;
112+
use crate::tests::mocks::{default_repo_name, run_test, BorsBuilder, WorkflowEvent, World};
113+
use chrono::Utc;
114+
use std::future::Future;
115+
use std::time::Duration;
116+
use tokio::runtime::RuntimeFlavor;
117+
118+
#[sqlx::test]
119+
async fn refresh_no_builds(pool: sqlx::PgPool) {
120+
run_test(pool, |tester| async move {
121+
tester.refresh().await;
122+
Ok(tester)
123+
})
124+
.await;
125+
}
126+
127+
#[sqlx::test]
128+
async fn refresh_do_nothing_before_timeout(pool: sqlx::PgPool) {
129+
let world = World::default();
130+
world.default_repo().lock().set_config(
131+
r#"
132+
timeout = 3600
133+
"#,
134+
);
135+
BorsBuilder::new(pool)
136+
.world(world)
137+
.run_test(|mut tester| async move {
138+
tester.post_comment("@bors try").await?;
139+
tester.expect_comments(1).await;
140+
with_mocked_time(Duration::from_secs(10), async {
141+
tester.refresh().await;
142+
})
143+
.await;
144+
Ok(tester)
145+
})
146+
.await;
147+
}
148+
149+
#[sqlx::test]
150+
async fn refresh_cancel_build_after_timeout(pool: sqlx::PgPool) {
151+
let world = World::default();
152+
world.default_repo().lock().set_config(
153+
r#"
154+
timeout = 3600
155+
"#,
156+
);
157+
BorsBuilder::new(pool)
158+
.world(world)
159+
.run_test(|mut tester| async move {
160+
tester.post_comment("@bors try").await?;
161+
tester.expect_comments(1).await;
162+
with_mocked_time(Duration::from_secs(4000), async {
163+
assert_eq!(
164+
tester
165+
.db()
166+
.get_running_builds(&default_repo_name())
167+
.await
168+
.unwrap()
169+
.len(),
170+
1
171+
);
172+
tester.refresh().await;
173+
})
174+
.await;
175+
insta::assert_snapshot!(tester.get_comment().await?, @":boom: Test timed out");
176+
assert_eq!(
177+
tester
178+
.db()
179+
.get_running_builds(&default_repo_name())
180+
.await
181+
.unwrap()
182+
.len(),
183+
0
184+
);
185+
Ok(tester)
186+
})
187+
.await;
188+
}
189+
190+
#[sqlx::test]
191+
async fn refresh_cancel_workflow_after_timeout(pool: sqlx::PgPool) {
192+
let world = World::default();
193+
world.default_repo().lock().set_config(
194+
r#"
195+
timeout = 3600
196+
"#,
197+
);
198+
let world = BorsBuilder::new(pool)
199+
.world(world)
200+
.run_test(|mut tester| async move {
201+
tester.post_comment("@bors try").await?;
202+
tester.expect_comments(1).await;
203+
tester
204+
.workflow_event(WorkflowEvent::started(tester.try_branch()))
205+
.await?;
206+
WAIT_FOR_WORKFLOW_STARTED.sync().await;
207+
208+
with_mocked_time(Duration::from_secs(4000), async {
209+
tester.refresh().await;
210+
})
211+
.await;
212+
tester.expect_comments(1).await;
213+
Ok(tester)
214+
})
215+
.await;
216+
world.check_cancelled_workflows(default_repo_name(), &[1]);
217+
}
218+
219+
async fn with_mocked_time<Fut: Future<Output = ()>>(in_future: Duration, future: Fut) {
220+
// It is important to use this function only with a single threaded runtime,
221+
// otherwise the `MOCK_TIME` variable might get mixed up between different threads.
222+
assert_eq!(
223+
tokio::runtime::Handle::current().runtime_flavor(),
224+
RuntimeFlavor::CurrentThread
225+
);
226+
MOCK_TIME.with(|time| {
227+
*time.borrow_mut() = Some(Utc::now() + chrono::Duration::from_std(in_future).unwrap());
228+
});
229+
future.await;
230+
MOCK_TIME.with(|time| {
231+
*time.borrow_mut() = None;
232+
});
233+
}
234+
}

src/tests/util.rs

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,39 @@
1-
use once_cell::sync::Lazy;
1+
use std::sync::atomic::{AtomicUsize, Ordering};
2+
use thread_local::ThreadLocal;
23
use tokio::sync;
34

45
pub struct TestSyncMarker {
5-
state: Lazy<TestSyncMarkerInner>,
6+
inner: ThreadLocal<TestSyncMarkerInner>,
67
}
78

89
impl TestSyncMarker {
910
pub const fn new() -> Self {
1011
Self {
11-
state: Lazy::new(TestSyncMarkerInner::new),
12+
inner: ThreadLocal::new(),
1213
}
1314
}
1415

15-
/// Mark that code has encountered this location.
1616
pub fn mark(&self) {
17-
// If we cannot send, don't block the program.
18-
let _ = self.state.tx.try_send(());
17+
self.get().mark();
1918
}
20-
21-
/// Wait until code has encountered this location.
2219
pub async fn sync(&self) {
23-
self.state.rx.lock().await.recv().await.unwrap();
20+
self.get().sync().await;
21+
}
22+
pub fn hits(&self) -> usize {
23+
self.get().hits()
24+
}
25+
26+
fn get(&self) -> &TestSyncMarkerInner {
27+
self.inner
28+
.get_or_try(|| Ok::<TestSyncMarkerInner, ()>(TestSyncMarkerInner::new()))
29+
.unwrap()
2430
}
2531
}
2632

2733
struct TestSyncMarkerInner {
2834
rx: sync::Mutex<sync::mpsc::Receiver<()>>,
2935
tx: sync::mpsc::Sender<()>,
36+
hits: AtomicUsize,
3037
}
3138

3239
impl TestSyncMarkerInner {
@@ -35,6 +42,23 @@ impl TestSyncMarkerInner {
3542
Self {
3643
tx,
3744
rx: sync::Mutex::new(rx),
45+
hits: AtomicUsize::new(0),
3846
}
3947
}
48+
49+
/// Mark that code has encountered this location.
50+
pub fn mark(&self) {
51+
// If we cannot send, don't block the program.
52+
let _ = self.tx.try_send(());
53+
self.hits.fetch_add(1, Ordering::SeqCst);
54+
}
55+
56+
/// Wait until code has encountered this location.
57+
pub async fn sync(&self) {
58+
self.rx.lock().await.recv().await.unwrap();
59+
}
60+
61+
pub fn hits(&self) -> usize {
62+
self.hits.load(Ordering::SeqCst)
63+
}
4064
}

0 commit comments

Comments
 (0)