* chore(clippy): enable and fix many stricter lints These ensure that the codebase uses more idiomatic, performant, and concise language constructions. * chore: make non-Clippy compiler warnings also deny by default
126 lines
4.9 KiB
Rust
126 lines
4.9 KiB
Rust
use actix_web::{dev::ServiceResponse, test};
|
|
use futures::Future;
|
|
use labrinth::models::pats::Scopes;
|
|
|
|
use super::{
|
|
api_common::Api, database::USER_USER_ID_PARSED,
|
|
environment::TestEnvironment, pats::create_test_pat,
|
|
};
|
|
|
|
// A reusable test type that works for any scope test testing an endpoint that:
|
|
// - returns a known 'expected_failure_code' if the scope is not present (defaults to 401)
|
|
// - returns a 200-299 if the scope is present
|
|
// - returns failure and success JSON bodies for requests that are 200 (for performing non-simple follow-up tests on)
|
|
// This uses a builder format, so you can chain methods to set the parameters to non-defaults (most will probably be not need to be set).
|
|
pub struct ScopeTest<'a, A> {
|
|
test_env: &'a TestEnvironment<A>,
|
|
// Scopes expected to fail on this test. By default, this is all scopes except the success scopes.
|
|
// (To ensure we have isolated the scope we are testing)
|
|
failure_scopes: Option<Scopes>,
|
|
// User ID to use for the PATs. By default, this is the USER_USER_ID_PARSED constant.
|
|
user_id: i64,
|
|
// The code that is expected to be returned if the scope is not present. By default, this is 401 (Unauthorized)
|
|
expected_failure_code: u16,
|
|
}
|
|
|
|
impl<'a, A: Api> ScopeTest<'a, A> {
|
|
pub fn new(test_env: &'a TestEnvironment<A>) -> Self {
|
|
Self {
|
|
test_env,
|
|
failure_scopes: None,
|
|
user_id: USER_USER_ID_PARSED,
|
|
expected_failure_code: 401,
|
|
}
|
|
}
|
|
|
|
// Set non-standard failure scopes
|
|
// If not set, it will be set to all scopes except the success scopes
|
|
// (eg: if a combination of scopes is needed, but you want to make sure that the endpoint does not work with all-but-one of them)
|
|
pub fn with_failure_scopes(mut self, scopes: Scopes) -> Self {
|
|
self.failure_scopes = Some(scopes);
|
|
self
|
|
}
|
|
|
|
// Set the user ID to use
|
|
// (eg: a moderator, or friend)
|
|
pub fn with_user_id(mut self, user_id: i64) -> Self {
|
|
self.user_id = user_id;
|
|
self
|
|
}
|
|
|
|
// If a non-401 code is expected.
|
|
// (eg: a 404 for a hidden resource, or 200 for a resource with hidden values deeper in)
|
|
pub fn with_failure_code(mut self, code: u16) -> Self {
|
|
self.expected_failure_code = code;
|
|
self
|
|
}
|
|
|
|
// Call the endpoint generated by req_gen twice, once with a PAT with the failure scopes, and once with the success scopes.
|
|
// success_scopes : the scopes that we are testing that should succeed
|
|
// returns a tuple of (failure_body, success_body)
|
|
// Should return a String error if on unexpected status code, allowing unwrapping in tests.
|
|
pub async fn test<T, Fut>(
|
|
&self,
|
|
req_gen: T,
|
|
success_scopes: Scopes,
|
|
) -> Result<(serde_json::Value, serde_json::Value), String>
|
|
where
|
|
T: Fn(Option<String>) -> Fut,
|
|
Fut: Future<Output = ServiceResponse>, // Ensure Fut is Send and 'static
|
|
{
|
|
// First, create a PAT with failure scopes
|
|
let failure_scopes = self
|
|
.failure_scopes
|
|
.unwrap_or(Scopes::all() ^ success_scopes);
|
|
let access_token_all_others =
|
|
create_test_pat(failure_scopes, self.user_id, &self.test_env.db)
|
|
.await;
|
|
|
|
// Create a PAT with the success scopes
|
|
let access_token =
|
|
create_test_pat(success_scopes, self.user_id, &self.test_env.db)
|
|
.await;
|
|
|
|
// Perform test twice, once with each PAT
|
|
// the first time, we expect a 401 (or known failure code)
|
|
let resp = req_gen(Some(access_token_all_others.clone())).await;
|
|
if resp.status().as_u16() != self.expected_failure_code {
|
|
return Err(format!(
|
|
"Expected failure code {}, got {} ({:#?})",
|
|
self.expected_failure_code,
|
|
resp.status().as_u16(),
|
|
resp.response()
|
|
));
|
|
}
|
|
|
|
let failure_body = if resp.status() == 200
|
|
&& resp.headers().contains_key("Content-Type")
|
|
&& resp.headers().get("Content-Type").unwrap() == "application/json"
|
|
{
|
|
test::read_body_json(resp).await
|
|
} else {
|
|
serde_json::Value::Null
|
|
};
|
|
|
|
// The second time, we expect a success code
|
|
let resp = req_gen(Some(access_token.clone())).await;
|
|
if !(resp.status().is_success() || resp.status().is_redirection()) {
|
|
return Err(format!(
|
|
"Expected success code, got {} ({:#?})",
|
|
resp.status().as_u16(),
|
|
resp.response()
|
|
));
|
|
}
|
|
|
|
let success_body = if resp.status() == 200
|
|
&& resp.headers().contains_key("Content-Type")
|
|
&& resp.headers().get("Content-Type").unwrap() == "application/json"
|
|
{
|
|
test::read_body_json(resp).await
|
|
} else {
|
|
serde_json::Value::Null
|
|
};
|
|
Ok((failure_body, success_body))
|
|
}
|
|
}
|