-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create smoke test for CORS headers (#19)
When rolling out Fastly, rust-lang/crates.io#6164 reported an issue with missing CORS headers. A new smoke test has been implemented that checks that the correct header is set for both CloudFront and Fastly.
- Loading branch information
Showing
6 changed files
with
460 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
//! Test the CORS headers on CloudFront | ||
use async_trait::async_trait; | ||
|
||
use crate::crates::utils::crate_url; | ||
use crate::test::{Test, TestResult}; | ||
|
||
use super::config::Config; | ||
use super::request_url_and_expect_cors_header; | ||
|
||
/// The name of the test | ||
const NAME: &str = "CloudFront"; | ||
|
||
/// Test the CORS headers on CloudFront | ||
/// | ||
/// This test requests a crate from CloudFront and expects the response to have the correct CORS | ||
/// headers. | ||
pub struct CloudFront<'a> { | ||
/// Configuration for this test | ||
config: &'a Config, | ||
} | ||
|
||
impl<'a> CloudFront<'a> { | ||
/// Create a new instance of the test | ||
pub fn new(config: &'a Config) -> Self { | ||
Self { config } | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl<'a> Test for CloudFront<'a> { | ||
async fn run(&self) -> TestResult { | ||
let url = crate_url( | ||
self.config.cloudfront_url(), | ||
self.config.krate(), | ||
self.config.version(), | ||
); | ||
|
||
request_url_and_expect_cors_header(NAME, &url).await | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::crates::crates_6164::tests::setup; | ||
use crate::test_utils::*; | ||
|
||
use super::*; | ||
|
||
const KRATE: &str = "crates-6164"; | ||
const VERSION: &str = "1.0.0"; | ||
|
||
#[tokio::test] | ||
async fn succeeds_with_cors_header() { | ||
let (mut server, config) = setup(KRATE, VERSION).await; | ||
|
||
let mock = server | ||
.mock( | ||
"GET", | ||
format!("/crates/{KRATE}/{KRATE}-{VERSION}.crate").as_str(), | ||
) | ||
.with_status(200) | ||
.with_header("Access-Control-Allow-Origin", "*") | ||
.create(); | ||
|
||
let result = CloudFront::new(&config).run().await; | ||
|
||
// Assert that the mock was called | ||
mock.assert(); | ||
|
||
assert!(result.success()); | ||
} | ||
|
||
#[tokio::test] | ||
async fn fails_without_cors_header() { | ||
let (mut server, config) = setup(KRATE, VERSION).await; | ||
|
||
let mock = server | ||
.mock( | ||
"GET", | ||
format!("/crates/{KRATE}/{KRATE}-{VERSION}.crate").as_str(), | ||
) | ||
.with_status(200) | ||
.create(); | ||
|
||
let result = CloudFront::new(&config).run().await; | ||
|
||
// Assert that the mock was called | ||
mock.assert(); | ||
|
||
assert!(!result.success()); | ||
} | ||
|
||
#[test] | ||
fn trait_send() { | ||
assert_send::<CloudFront>(); | ||
} | ||
|
||
#[test] | ||
fn trait_sync() { | ||
assert_sync::<CloudFront>(); | ||
} | ||
|
||
#[test] | ||
fn trait_unpin() { | ||
assert_unpin::<CloudFront>(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
//! Configuration to test rust-lang/crates.io#6164 | ||
use getset::Getters; | ||
#[cfg(test)] | ||
use typed_builder::TypedBuilder; | ||
|
||
use crate::environment::Environment; | ||
|
||
/// Configuration to test rust-lang/crates.io#6164 | ||
/// | ||
/// The smoke tests try to download a crate from the different CDNs and check if the CORS headers | ||
/// are set correctly. This requires knowing the respective base URLs, the crate, and its version. | ||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, Getters)] | ||
#[cfg_attr(test, derive(TypedBuilder))] | ||
pub struct Config { | ||
/// The name of the crate | ||
#[getset(get = "pub")] | ||
krate: String, | ||
|
||
/// The version with the `+` character | ||
#[getset(get = "pub")] | ||
version: String, | ||
|
||
/// The URL for the CloudFront CDN | ||
#[getset(get = "pub")] | ||
cloudfront_url: String, | ||
|
||
/// The URL for the Fastly CDN | ||
#[getset(get = "pub")] | ||
fastly_url: String, | ||
} | ||
|
||
impl Config { | ||
/// Return the configuration for the given environment | ||
pub fn for_env(env: Environment) -> Self { | ||
match env { | ||
Environment::Staging => Self { | ||
krate: "crossbeam".into(), | ||
version: "0.2.10".into(), | ||
cloudfront_url: "https://cloudfront-static.staging.crates.io".into(), | ||
fastly_url: "https://fastly-static.staging.crates.io".into(), | ||
}, | ||
Environment::Production => Self { | ||
krate: "axum".into(), | ||
version: "0.6.10".into(), | ||
cloudfront_url: "https://cloudfront-static.crates.io".into(), | ||
fastly_url: "https://fastly-static.crates.io".into(), | ||
}, | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::test_utils::*; | ||
|
||
use super::*; | ||
|
||
#[test] | ||
fn trait_send() { | ||
assert_send::<Config>(); | ||
} | ||
|
||
#[test] | ||
fn trait_sync() { | ||
assert_sync::<Config>(); | ||
} | ||
|
||
#[test] | ||
fn trait_unpin() { | ||
assert_unpin::<Config>(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
//! Test the CORS headers on Fastly | ||
use async_trait::async_trait; | ||
|
||
use crate::crates::utils::crate_url; | ||
use crate::test::{Test, TestResult}; | ||
|
||
use super::config::Config; | ||
use super::request_url_and_expect_cors_header; | ||
|
||
/// The name of the test | ||
const NAME: &str = "Fastly"; | ||
|
||
/// Test the CORS headers on Fastly | ||
/// | ||
/// This test requests a crate from Fastly and expects the response to have the correct CORS | ||
/// headers. | ||
pub struct Fastly<'a> { | ||
/// Configuration for this test | ||
config: &'a Config, | ||
} | ||
|
||
impl<'a> Fastly<'a> { | ||
/// Create a new instance of the test | ||
pub fn new(config: &'a Config) -> Self { | ||
Self { config } | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl<'a> Test for Fastly<'a> { | ||
async fn run(&self) -> TestResult { | ||
let url = crate_url( | ||
self.config.fastly_url(), | ||
self.config.krate(), | ||
self.config.version(), | ||
); | ||
|
||
request_url_and_expect_cors_header(NAME, &url).await | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::crates::crates_6164::tests::setup; | ||
use crate::test_utils::*; | ||
|
||
use super::*; | ||
|
||
const KRATE: &str = "crates-6164"; | ||
const VERSION: &str = "1.0.0"; | ||
|
||
#[tokio::test] | ||
async fn succeeds_with_cors_header() { | ||
let (mut server, config) = setup(KRATE, VERSION).await; | ||
|
||
let mock = server | ||
.mock( | ||
"GET", | ||
format!("/crates/{KRATE}/{KRATE}-{VERSION}.crate").as_str(), | ||
) | ||
.with_status(200) | ||
.with_header("Access-Control-Allow-Origin", "*") | ||
.create(); | ||
|
||
let result = Fastly::new(&config).run().await; | ||
|
||
// Assert that the mock was called | ||
mock.assert(); | ||
|
||
assert!(result.success()); | ||
} | ||
|
||
#[tokio::test] | ||
async fn fails_without_cors_header() { | ||
let (mut server, config) = setup(KRATE, VERSION).await; | ||
|
||
let mock = server | ||
.mock( | ||
"GET", | ||
format!("/crates/{KRATE}/{KRATE}-{VERSION}.crate").as_str(), | ||
) | ||
.with_status(200) | ||
.create(); | ||
|
||
let result = Fastly::new(&config).run().await; | ||
|
||
// Assert that the mock was called | ||
mock.assert(); | ||
|
||
assert!(!result.success()); | ||
} | ||
|
||
#[test] | ||
fn trait_send() { | ||
assert_send::<Fastly>(); | ||
} | ||
|
||
#[test] | ||
fn trait_sync() { | ||
assert_sync::<Fastly>(); | ||
} | ||
|
||
#[test] | ||
fn trait_unpin() { | ||
assert_unpin::<Fastly>(); | ||
} | ||
} |
Oops, something went wrong.