Skip to content

Commit 708a6f1

Browse files
chore(uptime): Make redis use in tests safer. (#205)
This generalizes our Redis test lock so that we can easily apply it to other tests. Also flushes the redis db when we're done to avoid test pollution. --------- Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>
1 parent 35eb41f commit 708a6f1

File tree

9 files changed

+108
-17
lines changed

9 files changed

+108
-17
lines changed

Cargo.lock

+20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ tokio-rustls = "0.26.1"
4343
rustls = "0.23.21"
4444
rcgen = "0.11"
4545
time = "0.3"
46-
46+
ctor = "0.2"
4747
[patch.crates-io]
4848
rdkafka = { git = "https://github.com/fede1024/rust-rdkafka" }
4949
reqwest = { git = "https://github.com/getsentry/reqwest", branch = "restricted-connector" }
@@ -53,3 +53,6 @@ lto = true
5353
codegen-units = 1
5454
panic = 'abort'
5555
strip = "debuginfo"
56+
57+
[dev-dependencies]
58+
redis-test-macro = { path = "./redis-test-macro" }

Dockerfile

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ WORKDIR /app
1616
# Just copy the Cargo.toml files and trigger a build so that we compile our
1717
# dependencies only. This way we avoid layer cache invalidation if our
1818
# dependencies haven't changed, resulting in faster builds.
19+
COPY Cargo.toml Cargo.lock ./
20+
COPY redis-test-macro redis-test-macro/
1921

20-
COPY Cargo.toml .
21-
COPY Cargo.lock .
2222
ENV RUSTFLAGS="-Ctarget-feature=-crt-static"
2323
ENV PKG_CONFIG_ALLOW_CROSS=1
2424
RUN cargo build --release && rm -rf src/

redis-test-macro/Cargo.toml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "redis-test-macro"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
proc-macro = true
8+
9+
[dependencies]
10+
syn = { version = "2.0", features = ["full"] }
11+
quote = "1.0"

redis-test-macro/src/lib.rs

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use proc_macro::TokenStream;
2+
use quote::quote;
3+
use syn::{parse_macro_input, ItemFn, parse::Parse, parse::ParseStream, Token, LitBool, Ident};
4+
5+
struct TestArgs {
6+
start_paused: bool,
7+
}
8+
9+
impl Parse for TestArgs {
10+
fn parse(input: ParseStream) -> syn::Result<Self> {
11+
let mut start_paused = false;
12+
13+
if !input.is_empty() {
14+
let ident: Ident = input.parse()?;
15+
if ident != "start_paused" {
16+
return Err(syn::Error::new(ident.span(), "expected `start_paused`"));
17+
}
18+
input.parse::<Token![=]>()?;
19+
start_paused = input.parse::<LitBool>()?.value;
20+
}
21+
22+
Ok(TestArgs { start_paused })
23+
}
24+
}
25+
26+
#[proc_macro_attribute]
27+
pub fn redis_test(attr: TokenStream, item: TokenStream) -> TokenStream {
28+
let args = parse_macro_input!(attr as TestArgs);
29+
let input = parse_macro_input!(item as ItemFn);
30+
let fn_name = &input.sig.ident;
31+
let body = &input.block;
32+
let start_paused = args.start_paused;
33+
34+
let expanded = quote! {
35+
#[tokio::test(start_paused = #start_paused)]
36+
async fn #fn_name() {
37+
let _guard = crate::test_utils::sync::TEST_MUTEX.lock().await;
38+
#body
39+
}
40+
};
41+
42+
TokenStream::from(expanded)
43+
}

src/checker/http_checker.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -274,15 +274,15 @@ mod tests {
274274
use httpmock::Method;
275275

276276
use sentry::protocol::SpanId;
277-
use tokio::io::AsyncWriteExt;
278-
use tokio::net::TcpListener;
279277
use uuid::Uuid;
280278
#[cfg(target_os = "linux")]
281279
use {
282280
rcgen::{Certificate, CertificateParams},
283281
rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer},
284282
rustls::ServerConfig,
285283
std::sync::Arc,
284+
tokio::io::AsyncWriteExt,
285+
tokio::net::TcpListener,
286286
tokio_rustls::TlsAcceptor,
287287
};
288288

src/main.rs

+16
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod manager;
1111
mod metrics;
1212
mod producer;
1313
mod scheduler;
14+
mod test_utils;
1415
mod types;
1516

1617
use std::process;
@@ -30,3 +31,18 @@ pub fn main() {
3031
Hub::current().client().map(|x| x.close(None));
3132
process::exit(exit_code);
3233
}
34+
35+
#[cfg(test)]
36+
mod test {
37+
use crate::app::config::Config;
38+
use redis::Client;
39+
40+
#[ctor::dtor]
41+
fn cleanup() {
42+
// Flushes Redis back to the default state to avoid state crossover between runs.
43+
let config = Config::default();
44+
let client = Client::open(config.redis_host).unwrap();
45+
let mut conn = client.get_connection().unwrap();
46+
let _: () = redis::cmd("FLUSHDB").query(&mut conn).unwrap();
47+
}
48+
}

src/scheduler.rs

+4-12
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,9 @@ mod tests {
170170
use crate::app::config::Config;
171171
use chrono::{Duration, Utc};
172172
use redis::{Client, Commands};
173+
use redis_test_macro::redis_test;
173174
use similar_asserts::assert_eq;
174175
use std::sync::Arc;
175-
use tokio::sync::Mutex;
176176
use tokio::sync::{mpsc, oneshot};
177177
use tokio_util::sync::CancellationToken;
178178
use tracing_test::traced_test;
@@ -190,14 +190,10 @@ mod tests {
190190
result::{CheckResult, CheckStatus},
191191
},
192192
};
193-
static TEST_MUTEX: Mutex<()> = Mutex::const_new(());
194193

195194
#[traced_test]
196-
#[tokio::test(start_paused = true)]
195+
#[redis_test(start_paused = true)]
197196
async fn test_scheduler() {
198-
// We don't want these tests to run at the same time, since they access the external redis.
199-
let _guard = TEST_MUTEX.lock().await;
200-
201197
let config = Config::default();
202198
let partition = 0;
203199

@@ -297,10 +293,8 @@ mod tests {
297293
}
298294

299295
#[traced_test]
300-
#[tokio::test(start_paused = true)]
296+
#[redis_test(start_paused = true)]
301297
async fn test_scheduler_multi_region() {
302-
// We don't want these tests to run at the same time, since they access the external redis.
303-
let _guard = TEST_MUTEX.lock().await;
304298
let config = Config {
305299
region: "us_west".to_string(),
306300
..Default::default()
@@ -407,10 +401,8 @@ mod tests {
407401
}
408402

409403
#[traced_test]
410-
#[tokio::test(start_paused = true)]
404+
#[redis_test(start_paused = true)]
411405
async fn test_scheduler_start() {
412-
// We don't want these tests to run at the same time, since they access the external redis.
413-
let _guard = TEST_MUTEX.lock().await;
414406
// TODO: Better abstraction here
415407
let config = Config::default();
416408
let partition = 1;

src/test_utils.rs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#[cfg(test)]
2+
pub mod sync {
3+
use tokio::sync::Mutex;
4+
5+
pub static TEST_MUTEX: Mutex<()> = Mutex::const_new(());
6+
}

0 commit comments

Comments
 (0)