Skip to content

Commit 9dbc7f5

Browse files
committed
add integration test crate & static file integration test
1 parent dbeb791 commit 9dbc7f5

File tree

8 files changed

+122
-18
lines changed

8 files changed

+122
-18
lines changed

Cargo.lock

Lines changed: 13 additions & 0 deletions
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
@@ -1,7 +1,7 @@
11
[workspace]
22
resolver = "2"
33

4-
members = ["crates/bin/*", "crates/lib/*"]
4+
members = ["crates/bin/*", "crates/lib/*", "integration_tests"]
55

66
default-members = [
77
"crates/bin/docs_rs_admin",
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use anyhow::Result;
2+
use docs_rs_context::Context;
3+
use std::sync::Arc;
4+
5+
pub async fn build_context() -> Result<Arc<Context>> {
6+
Ok(Arc::new(
7+
Context::builder()
8+
.with_runtime()
9+
.await?
10+
.with_meter_provider()?
11+
.with_pool()
12+
.await?
13+
.with_build_queue()?
14+
.with_storage()
15+
.await?
16+
.with_registry_api()?
17+
.with_build_limits()?
18+
.build()?,
19+
))
20+
}

crates/bin/docs_rs_web/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
mod cache;
88
mod config;
9+
mod context;
910
mod error;
1011
mod extractors;
1112
mod file;
@@ -21,6 +22,7 @@ pub(crate) mod testing;
2122
mod utils;
2223

2324
pub use config::Config;
25+
pub use context::build_context;
2426
pub use docs_rs_build_limits::DEFAULT_MAX_TARGETS;
2527
pub use docs_rs_utils::{APP_USER_AGENT, BUILD_VERSION, RUSTDOC_STATIC_STORAGE_PREFIX};
2628
pub use font_awesome_as_a_crate::icons;

crates/bin/docs_rs_web/src/main.rs

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use anyhow::Context as _;
22
use clap::Parser;
33
use docs_rs_config::AppConfig as _;
4-
use docs_rs_web::{Config, run_web_server};
4+
use docs_rs_web::{Config, build_context, run_web_server};
55
use std::{net::SocketAddr, sync::Arc};
66

77
#[derive(Parser)]
@@ -20,22 +20,7 @@ async fn main() -> anyhow::Result<()> {
2020
let _guard = docs_rs_logging::init().context("error initializing logging")?;
2121

2222
let args = Cli::parse();
23-
24-
let context = Arc::new(
25-
docs_rs_context::Context::builder()
26-
.with_runtime()
27-
.await?
28-
.with_meter_provider()?
29-
.with_pool()
30-
.await?
31-
.with_build_queue()?
32-
.with_storage()
33-
.await?
34-
.with_registry_api()?
35-
.with_build_limits()?
36-
.build()?,
37-
);
38-
23+
let context = build_context().await?;
3924
let config = Arc::new(Config::from_environment()?);
4025

4126
run_web_server(Some(args.socket_addr), config, context).await?;

integration_tests/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "docs_rs_integration_tests"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dev-dependencies]
7+
anyhow = { workspace = true }
8+
docs_rs_config = { path = "../crates/lib/docs_rs_config", features = ["testing"] }
9+
docs_rs_context = { path = "../crates/lib/docs_rs_context", features = ["testing"] }
10+
docs_rs_web = { path = "../crates/bin/docs_rs_web" }
11+
reqwest = { workspace = true }
12+
tokio = { workspace = true }
13+
tracing = { workspace = true }

integration_tests/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// Integration tests live in `integration_tests/tests`.

integration_tests/tests/web.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use anyhow::{Context as _, Result, bail};
2+
use docs_rs_config::AppConfig;
3+
use docs_rs_context::Context;
4+
use docs_rs_web::{Config, build_context, run_web_server};
5+
use reqwest::Url;
6+
use std::{sync::Arc, time::Duration};
7+
use tokio::{
8+
net::{TcpListener, TcpStream},
9+
time,
10+
};
11+
use tracing::debug;
12+
13+
fn web_config() -> Result<Arc<Config>> {
14+
Ok(Arc::new(Config::test_config()?))
15+
}
16+
17+
/// starts a test webserver.
18+
///
19+
/// Graceful shutdown is not needed, the test runtime will clean up after
20+
/// the test is finished.
21+
async fn start_web_server(config: Arc<Config>, context: Arc<Context>) -> Result<Url> {
22+
let socket_addr = {
23+
// find free local random port.
24+
let listener = TcpListener::bind("127.0.0.1:0")
25+
.await
26+
.context("error binding socket for web server")?;
27+
28+
listener.local_addr()?
29+
};
30+
31+
tokio::spawn(async move {
32+
run_web_server(Some(socket_addr), config, context)
33+
.await
34+
.expect("error starting web server")
35+
});
36+
37+
const WAIT_DURATION: Duration = Duration::from_millis(10);
38+
const WAIT_ATTEMPTS: usize = 20;
39+
40+
for _attempt in 0..WAIT_ATTEMPTS {
41+
if TcpStream::connect(socket_addr).await.is_ok() {
42+
return Ok(Url::parse(&format!("http://{}/", socket_addr))?);
43+
}
44+
debug!("waiting for webserver to start...");
45+
time::sleep(WAIT_DURATION).await;
46+
}
47+
48+
bail!(
49+
"test web server failed to start after {}s",
50+
(WAIT_DURATION * WAIT_ATTEMPTS as u32).as_secs()
51+
);
52+
}
53+
54+
#[tokio::test(flavor = "multi_thread")]
55+
async fn test_static_files_from_repo_root() -> Result<()> {
56+
let config = web_config()?;
57+
let context = build_context().await?;
58+
let base_url = start_web_server(config, context).await?;
59+
60+
assert!(
61+
reqwest::get(base_url.join("/-/static/menu.js")?)
62+
.await?
63+
.error_for_status()?
64+
.text()
65+
.await?
66+
.contains("updateMenuPositionForSubMenu")
67+
);
68+
69+
Ok(())
70+
}

0 commit comments

Comments
 (0)