diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8eb2be917..45b4d4ed8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,9 +60,19 @@ jobs: - name: Build run: cargo build --workspace --locked - - name: Test + - name: fast tests run: cargo test --workspace --locked + - name: create small build-environment + run: | + docker build -t buildenv - < dockerfiles/Dockerfile-small-build-env + + - name: slow tests + env: + DOCSRS_INCLUDE_DEFAULT_TARGETS: true + DOCS_RS_LOCAL_DOCKER_IMAGE: buildenv + run: cargo test --workspace --locked -- --ignored + - name: Clean up the database run: docker-compose down --volumes diff --git a/dockerfiles/Dockerfile-small-build-env b/dockerfiles/Dockerfile-small-build-env new file mode 100644 index 000000000..118b375fc --- /dev/null +++ b/dockerfiles/Dockerfile-small-build-env @@ -0,0 +1,6 @@ +FROM ubuntu:focal + +RUN apt-get update +RUN apt-get install -y --no-install-recommends apt-utils build-essential sudo git + +CMD ["bash"] diff --git a/src/docbuilder/rustwide_builder.rs b/src/docbuilder/rustwide_builder.rs index 1f2402d13..b62e75536 100644 --- a/src/docbuilder/rustwide_builder.rs +++ b/src/docbuilder/rustwide_builder.rs @@ -87,6 +87,9 @@ impl RustwideBuilder { if let Some(custom_image) = &config.local_docker_image { builder = builder.sandbox_image(SandboxImage::local(&custom_image)?); } + if cfg!(test) { + builder = builder.fast_init(true); + } let workspace = builder.init()?; workspace.purge_all_build_dirs()?; @@ -753,3 +756,102 @@ pub(crate) struct BuildResult { pub(crate) docsrs_version: String, pub(crate) successful: bool, } + +#[cfg(test)] +mod tests { + use super::*; + use crate::test::{assert_redirect, assert_success, wrapper}; + + #[test] + #[ignore] + fn test_build_crate() { + wrapper(|env| { + let crate_ = DUMMY_CRATE_NAME; + let crate_path = crate_.replace("-", "_"); + let version = DUMMY_CRATE_VERSION; + let default_target = "x86_64-unknown-linux-gnu"; + + assert_eq!(env.config().include_default_targets, true); + + let mut builder = RustwideBuilder::init(env).unwrap(); + builder + .build_package(crate_, version, PackageKind::CratesIo) + .map(|_| ())?; + + // check release record in the db (default and other targets) + let mut conn = env.db().conn(); + let rows = conn + .query( + "SELECT + r.rustdoc_status, + r.default_target, + r.doc_targets + FROM + crates as c + INNER JOIN releases AS r ON c.id = r.crate_id + WHERE + c.name = $1 AND + r.version = $2", + &[&crate_, &version], + ) + .unwrap(); + let row = rows.get(0).unwrap(); + + assert_eq!(row.get::<_, bool>("rustdoc_status"), true); + assert_eq!(row.get::<_, String>("default_target"), default_target); + + let mut targets: Vec = row + .get::<_, Value>("doc_targets") + .as_array() + .unwrap() + .iter() + .map(|v| v.as_str().unwrap().to_owned()) + .collect(); + targets.sort(); + assert_eq!( + targets, + vec![ + "i686-pc-windows-msvc", + "i686-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", + ] + ); + + let storage = env.storage(); + let web = env.frontend(); + + let base = format!("rustdoc/{}/{}", crate_, version); + + // default target was built and is accessible + assert!(storage.exists(&format!("{}/{}/index.html", base, crate_path))?); + assert_success(&format!("/{}/{}/{}", crate_, version, crate_path), web)?; + + // other targets too + for target in DEFAULT_TARGETS { + let target_docs_present = + storage.exists(&format!("{}/{}/{}/index.html", base, target, crate_path))?; + + let target_url = format!( + "/{}/{}/{}/{}/index.html", + crate_, version, target, crate_path + ); + + if target == &default_target { + assert!(!target_docs_present); + assert_redirect( + &target_url, + &format!("/{}/{}/{}/index.html", crate_, version, crate_path), + web, + )?; + } else { + assert!(target_docs_present); + assert_success(&target_url, web)?; + } + } + + Ok(()) + }) + } +} diff --git a/src/test/mod.rs b/src/test/mod.rs index 5e839ecc4..6bc3a6e82 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -13,6 +13,7 @@ use reqwest::{ blocking::{Client, RequestBuilder}, Method, }; +use std::fs; use std::{panic, sync::Arc}; pub(crate) fn wrapper(f: impl FnOnce(&TestEnvironment) -> Result<(), Error>) { @@ -103,10 +104,12 @@ pub(crate) struct TestEnvironment { } pub(crate) fn init_logger() { - // If this fails it's probably already initialized - let _ = env_logger::from_env(env_logger::Env::default().filter("DOCSRS_LOG")) - .is_test(true) - .try_init(); + // initializing rustwide logging also sets the global logger + rustwide::logging::init_with( + env_logger::from_env(env_logger::Env::default().filter("DOCSRS_LOG")) + .is_test(true) + .build(), + ); } impl TestEnvironment { @@ -137,8 +140,11 @@ impl TestEnvironment { fn base_config(&self) -> Config { let mut config = Config::from_env().expect("failed to get base config"); + // create index directory + fs::create_dir_all(config.registry_index_path.clone()).unwrap(); + // Use less connections for each test compared to production. - config.max_pool_size = 2; + config.max_pool_size = 4; config.min_pool_idle = 0; // Use the database for storage, as it's faster than S3.