Modrinth/tests/common/scopes.rs
Wyatt Verchere 172b93d07f
Tests v2 recreate (#760)
* added common project information; setup for v2 test change

* all tests now use with_test_environment

* progress, failing

* finished re-adding tests

* prepare

* cargo sqlx prepare -- --tests

* fmt; clippy; prepare

* sqlx prepare

* adds version_create fix and corresponding test

* merge fixes; rev

* fmt, clippy, prepare

* test cargo sqlx prepare
2023-11-25 14:42:39 -07:00

130 lines
4.9 KiB
Rust

#![allow(dead_code)]
use actix_web::test::{self, TestRequest};
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>(
&self,
req_gen: T,
success_scopes: Scopes,
) -> Result<(serde_json::Value, serde_json::Value), String>
where
T: Fn() -> TestRequest,
{
// 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 req = req_gen()
.append_header(("Authorization", access_token_all_others.as_str()))
.to_request();
let resp = self.test_env.call(req).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 req = req_gen()
.append_header(("Authorization", access_token.as_str()))
.to_request();
let resp = self.test_env.call(req).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))
}
}