From 9c7b2b7a861f4b51f77c49efec83bfd921c67e23 Mon Sep 17 00:00:00 2001 From: _ <> Date: Sun, 13 Dec 2020 04:44:37 +0000 Subject: [PATCH] :white_check_mark: test: add tests for scraper API test endpoint --- crates/ptth_relay/src/scraper_api.rs | 155 ++++++++++++++++++++++----- src/tests.rs | 22 +++- 2 files changed, 150 insertions(+), 27 deletions(-) diff --git a/crates/ptth_relay/src/scraper_api.rs b/crates/ptth_relay/src/scraper_api.rs index ff58a32..d642cbb 100644 --- a/crates/ptth_relay/src/scraper_api.rs +++ b/crates/ptth_relay/src/scraper_api.rs @@ -102,7 +102,7 @@ pub async fn handle_scraper_api ( #[cfg (test)] mod tests { use std::{ - convert::TryFrom, + convert::{TryFrom, TryInto}, }; use tokio::runtime::Runtime; @@ -112,35 +112,140 @@ mod tests { }; use super::*; + #[derive (Clone)] + struct TestCase { + // Inputs + path_rest: &'static str, + valid_key: Option <&'static str>, + input_key: Option <&'static str>, + + // Expected + expected_status: StatusCode, + expected_headers: Vec <(&'static str, &'static str)>, + expected_body: &'static str, + } + + impl TestCase { + fn path_rest (&self, v: &'static str) -> Self { + let mut x = self.clone (); + x.path_rest = v; + x + } + + fn valid_key (&self, v: Option <&'static str>) -> Self { + let mut x = self.clone (); + x.valid_key = v; + x + } + + fn input_key (&self, v: Option <&'static str>) -> Self { + let mut x = self.clone (); + x.input_key = v; + x + } + + fn expected_status (&self, v: StatusCode) -> Self { + let mut x = self.clone (); + x.expected_status = v; + x + } + + fn expected_headers (&self, v: Vec <(&'static str, &'static str)>) -> Self { + let mut x = self.clone (); + x.expected_headers = v; + x + } + + fn expected_body (&self, v: &'static str) -> Self { + let mut x = self.clone (); + x.expected_body = v; + x + } + + fn expected (&self, sc: StatusCode, body: &'static str) -> Self { + self + .expected_status (sc) + .expected_body (body) + } + + async fn test (&self) { + let mut input = Request::builder () + .method ("GET") + .uri (format! ("http://127.0.0.1:4000/scraper/{}", self.path_rest)); + + if let Some (input_key) = self.input_key { + input = input.header ("X-ApiKey", input_key); + } + let input = input.body (Body::empty ()).unwrap (); + + let config_file = config::file::Config { + port: Some (4000), + servers: vec! [], + iso: config::file::Isomorphic { + enable_scraper_auth: true, + dev_mode: self.valid_key.map (|key| config::file::DevMode { + scraper_key: Some (key_validity::ScraperKey::new (key.as_bytes ())), + }), + }, + }; + + let config = config::Config::try_from (config_file).expect ("Can't load config"); + + let relay_state = Arc::new (RelayState::try_from (config).expect ("Can't create relay state")); + + let actual = handle_scraper_api (input, relay_state, self.path_rest).await; + let actual = actual.expect ("Relay didn't respond"); + let (actual_head, actual_body) = actual.into_parts (); + + let mut expected_headers = hyper::header::HeaderMap::new (); + + for (key, value) in &self.expected_headers { + expected_headers.insert (*key, (*value).try_into ().expect ("Couldn't convert header value")); + } + + assert_eq! (actual_head.status, self.expected_status); + assert_eq! (actual_head.headers, expected_headers); + + let actual_body = hyper::body::to_bytes (actual_body).await; + let actual_body = actual_body.expect ("Body should be convertible to bytes"); + let actual_body = actual_body.to_vec (); + let actual_body = String::from_utf8 (actual_body).expect ("Body should be UTF-8"); + + assert_eq! (&actual_body, self.expected_body); + } + } + #[test] fn auth () { - let input = Request::builder () - .method ("GET") - .uri ("http://127.0.0.1:4000/scraper/v1/test") - .header ("X-ApiKey", "bogus") - .body (Body::empty ()) - .unwrap (); - - let config_file = config::file::Config { - port: Some (4000), - servers: vec! [], - iso: config::file::Isomorphic { - enable_scraper_auth: true, - dev_mode: Some (config::file::DevMode { - scraper_key: Some (key_validity::ScraperKey::new (b"bogus")), - }), - }, - }; - - let config = config::Config::try_from (config_file).expect ("Can't load config"); - - let relay_state = Arc::new (RelayState::try_from (config).expect ("Can't create relay state")); - let mut rt = Runtime::new ().expect ("Can't create runtime for testing"); rt.block_on (async move { - let actual = handle_scraper_api (input, relay_state, "").await; - let actual = actual.expect ("Relay didn't respond"); + let base_case = TestCase { + path_rest: "v1/test", + valid_key: Some ("bogus"), + input_key: Some ("bogus"), + expected_status: StatusCode::OK, + expected_headers: vec! [ + ("content-type", "text/plain"), + ], + expected_body: "You're valid!\n", + }; + + for case in &[ + base_case.clone (), + base_case.path_rest ("v9999/test") + .expected (StatusCode::NOT_FOUND, "Unknown scraper API version\n"), + base_case.valid_key (None) + .expected (StatusCode::FORBIDDEN, "403 Forbidden\n"), + base_case.input_key (Some ("borgus")) + .expected (StatusCode::FORBIDDEN, "403 Forbidden\n"), + base_case.path_rest ("v1/toast") + .expected (StatusCode::NOT_FOUND, "Unknown API endpoint\n"), + base_case.input_key (None) + .expected (StatusCode::FORBIDDEN, "Can't run scraper without an API key\n"), + ] { + case.test ().await; + } }); } } diff --git a/src/tests.rs b/src/tests.rs index 6a4c28f..ad5a9be 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -179,8 +179,26 @@ fn scraper_endpoints () { .timeout (Duration::from_secs (2)) .build ().expect ("Couldn't build HTTP client"); - let resp = client.get (&format! ("{}/scraper/api/test", relay_url)) - .send ().await.expect ("Couldn't check if relay is up").bytes ().await.expect ("Couldn't check if relay is up"); + let mut resp = None; + for _ in 0usize..5 { + let x = client.get (&format! ("{}/scraper/api/test", relay_url)) + .send ().await; + match x { + Err (_) => { + // Probably a reqwest error cause the port is in + // use or something. Try again. + () + }, + Ok (x) => { + resp = Some (x); + break; + }, + }; + + delay_for (Duration::from_millis (200)).await; + } + let resp = resp.expect ("Reqwest repeatedly failed to connect to the relay"); + let resp = resp.bytes ().await.expect ("Couldn't check if relay is up"); assert_eq! (resp, "You're valid!\n");