From 10eed05d8730f2193a4afc2cff02d6c45f45ae9e Mon Sep 17 00:00:00 2001 From: Wyatt Verchere Date: Fri, 5 Jan 2024 08:20:56 -0800 Subject: [PATCH] Fixes failing tests (#813) * fixes failing tests * fmt clippy * updated dockerfile * fixes failing tests; adds important fix from extracts_versions PR * assert_eq -> assert_status, giving better error messages * fixed random failure bug * fmt, clippy, etc --- Dockerfile | 2 +- src/file_hosting/mock.rs | 5 +- src/lib.rs | 6 +- src/main.rs | 4 +- src/models/v3/organizations.rs | 2 +- src/routes/mod.rs | 2 +- src/routes/v3/users.rs | 21 +-- src/search/indexing/mod.rs | 23 +-- src/search/mod.rs | 40 ++++-- tests/common/api_v2/project.rs | 11 +- tests/common/api_v2/tags.rs | 17 +-- tests/common/api_v2/team.rs | 12 +- tests/common/api_v2/version.rs | 22 +-- tests/common/api_v3/collections.rs | 12 +- tests/common/api_v3/organization.rs | 12 +- tests/common/api_v3/project.rs | 18 +-- tests/common/api_v3/tags.rs | 12 +- tests/common/api_v3/team.rs | 12 +- tests/common/api_v3/version.rs | 16 +-- tests/common/database.rs | 10 +- tests/common/dummy_data.rs | 11 +- tests/common/mod.rs | 2 + tests/common/permissions.rs | 20 +-- tests/common/search.rs | 7 +- tests/error.rs | 5 +- tests/loader_fields.rs | 26 ++-- tests/organizations.rs | 136 +++++++++++------- tests/pats.rs | 29 ++-- tests/project.rs | 214 +++++++++++++++++++++++----- tests/scopes.rs | 10 +- tests/teams.rs | 77 +++++----- tests/v2/error.rs | 4 +- tests/v2/project.rs | 25 ++-- tests/v2/search.rs | 6 +- tests/v2/teams.rs | 18 +-- tests/v2/version.rs | 16 ++- tests/version.rs | 20 +-- 37 files changed, 555 insertions(+), 330 deletions(-) diff --git a/Dockerfile b/Dockerfile index c0a65d8e5..011ddbeb9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.68.0 as build +FROM rust:1.75.0 as build ENV PKG_CONFIG_ALLOW_CROSS=1 WORKDIR /usr/src/labrinth diff --git a/src/file_hosting/mock.rs b/src/file_hosting/mock.rs index c1b62c4c9..625795435 100644 --- a/src/file_hosting/mock.rs +++ b/src/file_hosting/mock.rs @@ -47,8 +47,9 @@ impl FileHost for MockHost { ) -> Result { let path = std::path::Path::new(&dotenvy::var("MOCK_FILE_PATH").unwrap()) .join(file_name.replace("../", "")); - std::fs::remove_file(path)?; - + if path.exists() { + std::fs::remove_file(path)?; + } Ok(DeleteFileData { file_id: file_id.to_string(), file_name: file_name.to_string(), diff --git a/src/lib.rs b/src/lib.rs index a01112605..cac75903f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,6 +57,7 @@ pub struct LabrinthConfig { pub fn app_setup( pool: sqlx::Pool, redis_pool: RedisPool, + search_config: search::SearchConfig, clickhouse: &mut Client, file_host: Arc, maxmind: Arc, @@ -66,11 +67,6 @@ pub fn app_setup( dotenvy::var("BIND_ADDR").unwrap() ); - let search_config = search::SearchConfig { - address: dotenvy::var("MEILISEARCH_ADDR").unwrap(), - key: dotenvy::var("MEILISEARCH_KEY").unwrap(), - }; - let mut scheduler = scheduler::Scheduler::new(); // The interval in seconds at which the local database is indexed diff --git a/src/main.rs b/src/main.rs index 7aff4d601..e242509f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,10 +6,10 @@ use labrinth::file_hosting::S3Host; use labrinth::ratelimit::errors::ARError; use labrinth::ratelimit::memory::{MemoryStore, MemoryStoreActor}; use labrinth::ratelimit::middleware::RateLimiter; +use labrinth::search; use labrinth::util::env::parse_var; use labrinth::{check_env_vars, clickhouse, database, file_hosting, queue}; use log::{error, info}; - use std::sync::Arc; #[derive(Clone)] @@ -93,11 +93,13 @@ async fn main() -> std::io::Result<()> { .build() .expect("Failed to create prometheus metrics middleware"); + let search_config = search::SearchConfig::new(None); info!("Starting Actix HTTP server!"); let labrinth_config = labrinth::app_setup( pool.clone(), redis_pool.clone(), + search_config.clone(), &mut clickhouse, file_host.clone(), maxmind_reader.clone(), diff --git a/src/models/v3/organizations.rs b/src/models/v3/organizations.rs index 47e541f47..11a0f72d8 100644 --- a/src/models/v3/organizations.rs +++ b/src/models/v3/organizations.rs @@ -17,7 +17,7 @@ pub struct Organization { pub id: OrganizationId, /// The slug of the organization pub slug: String, - /// The title (and slug) of the organization + /// The title of the organization pub name: String, /// The associated team of the organization pub team_id: TeamId, diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 917e015ac..18581eaaa 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -81,7 +81,7 @@ pub fn root_config(cfg: &mut web::ServiceConfig) { pub enum ApiError { #[error("Environment Error")] Env(#[from] dotenvy::Error), - #[error("Error while uploading file")] + #[error("Error while uploading file: {0}")] FileHosting(#[from] FileHostingError), #[error("Database Error: {0}")] Database(#[from] crate::database::models::DatabaseError), diff --git a/src/routes/v3/users.rs b/src/routes/v3/users.rs index f997dd709..455e6fb0a 100644 --- a/src/routes/v3/users.rs +++ b/src/routes/v3/users.rs @@ -8,7 +8,7 @@ use sqlx::PgPool; use validator::Validate; use crate::{ - auth::get_user_from_headers, + auth::{filter_visible_projects, get_user_from_headers}, database::{models::User, redis::RedisPool}, file_hosting::FileHost, models::{ @@ -65,23 +65,12 @@ pub async fn projects_list( let id_option = User::get(&info.into_inner().0, &**pool, &redis).await?; if let Some(id) = id_option.map(|x| x.id) { - let user_id: UserId = id.into(); - - let can_view_private = user - .map(|y| y.role.is_mod() || y.id == user_id) - .unwrap_or(false); - let project_data = User::get_projects(id, &**pool, &redis).await?; - let response: Vec<_> = - crate::database::Project::get_many_ids(&project_data, &**pool, &redis) - .await? - .into_iter() - .filter(|x| can_view_private || x.inner.status.is_searchable()) - .map(Project::from) - .collect(); - - Ok(HttpResponse::Ok().json(response)) + let projects: Vec<_> = + crate::database::Project::get_many_ids(&project_data, &**pool, &redis).await?; + let projects = filter_visible_projects(projects, &user, &pool).await?; + Ok(HttpResponse::Ok().json(projects)) } else { Err(ApiError::NotFound) } diff --git a/src/search/indexing/mod.rs b/src/search/indexing/mod.rs index c77903018..b669837a9 100644 --- a/src/search/indexing/mod.rs +++ b/src/search/indexing/mod.rs @@ -107,11 +107,12 @@ pub async fn get_indexes( config: &SearchConfig, ) -> Result, meilisearch_sdk::errors::Error> { let client = config.make_client(); - - let projects_index = create_or_update_index(&client, "projects", None).await?; + let project_name = config.get_index_name("projects"); + let project_filtered_name = config.get_index_name("projects_filtered"); + let projects_index = create_or_update_index(&client, &project_name, None).await?; let projects_filtered_index = create_or_update_index( &client, - "projects_filtered", + &project_filtered_name, Some(&[ "sort", "words", @@ -128,7 +129,7 @@ pub async fn get_indexes( async fn create_or_update_index( client: &Client, - name: &'static str, + name: &str, custom_rules: Option<&'static [&'static str]>, ) -> Result { info!("Updating/creating index."); @@ -207,7 +208,6 @@ async fn create_or_update_index( typo_tolerance: None, // We don't use typo tolerance right now dictionary: None, // We don't use dictionary right now }; - if old_settings.synonyms != settings.synonyms || old_settings.stop_words != settings.stop_words || old_settings.ranking_rules != settings.ranking_rules @@ -294,16 +294,23 @@ async fn update_and_add_to_index( new_filterable_attributes.extend(additional_fields.iter().map(|s| s.to_string())); new_displayed_attributes.extend(additional_fields.iter().map(|s| s.to_string())); info!("add attributes."); - index + let filterable_task = index .set_filterable_attributes(new_filterable_attributes) .await?; - index + let displayable_task = index .set_displayed_attributes(new_displayed_attributes) .await?; + filterable_task + .wait_for_completion(client, None, Some(TIMEOUT)) + .await?; + displayable_task + .wait_for_completion(client, None, Some(TIMEOUT)) + .await?; info!("Adding to index."); add_to_index(client, index, projects).await?; + Ok(()) } @@ -315,7 +322,6 @@ pub async fn add_projects( ) -> Result<(), IndexingError> { let client = config.make_client(); for index in indices { - info!("adding projects part1 or 2."); update_and_add_to_index(&client, index, &projects, &additional_fields).await?; } @@ -329,7 +335,6 @@ fn default_settings() -> Settings { sorted_sortable.sort(); let mut sorted_attrs = DEFAULT_ATTRIBUTES_FOR_FACETING.to_vec(); sorted_attrs.sort(); - Settings::new() .with_distinct_attribute("project_id") .with_displayed_attributes(sorted_display) diff --git a/src/search/mod.rs b/src/search/mod.rs index 6b9e160c7..fc01b70f5 100644 --- a/src/search/mod.rs +++ b/src/search/mod.rs @@ -59,16 +59,34 @@ impl actix_web::ResponseError for SearchError { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct SearchConfig { pub address: String, pub key: String, + pub meta_namespace: String, } impl SearchConfig { + // Panics if the environment variables are not set, + // but these are already checked for on startup. + pub fn new(meta_namespace: Option) -> Self { + let address = dotenvy::var("MEILISEARCH_ADDR").expect("MEILISEARCH_ADDR not set"); + let key = dotenvy::var("MEILISEARCH_KEY").expect("MEILISEARCH_KEY not set"); + + Self { + address, + key, + meta_namespace: meta_namespace.unwrap_or_default(), + } + } + pub fn make_client(&self) -> Client { Client::new(self.address.as_str(), Some(self.key.as_str())) } + + pub fn get_index_name(&self, index: &str) -> String { + format!("{}_{}", self.meta_namespace, index) + } } /// A project document used for uploading projects to MeiliSearch's indices. @@ -172,13 +190,18 @@ pub struct ResultSearchProject { pub loader_fields: HashMap>, } -pub fn get_sort_index(index: &str) -> Result<(&str, [&str; 1]), SearchError> { +pub fn get_sort_index( + config: &SearchConfig, + index: &str, +) -> Result<(String, [&'static str; 1]), SearchError> { + let projects_name = config.get_index_name("projects"); + let projects_filtered_name = config.get_index_name("projects_filtered"); Ok(match index { - "relevance" => ("projects", ["downloads:desc"]), - "downloads" => ("projects_filtered", ["downloads:desc"]), - "follows" => ("projects", ["follows:desc"]), - "updated" => ("projects", ["date_modified:desc"]), - "newest" => ("projects", ["date_created:desc"]), + "relevance" => (projects_name, ["downloads:desc"]), + "downloads" => (projects_filtered_name, ["downloads:desc"]), + "follows" => (projects_name, ["follows:desc"]), + "updated" => (projects_name, ["date_modified:desc"]), + "newest" => (projects_name, ["date_created:desc"]), i => return Err(SearchError::InvalidIndex(i.to_string())), }) } @@ -193,8 +216,7 @@ pub async fn search_for_project( let index = info.index.as_deref().unwrap_or("relevance"); let limit = info.limit.as_deref().unwrap_or("10").parse()?; - let sort = get_sort_index(index)?; - + let sort = get_sort_index(config, index)?; let meilisearch_index = client.get_index(sort.0).await?; let mut filter_string = String::new(); diff --git a/tests/common/api_v2/project.rs b/tests/common/api_v2/project.rs index 7a42d506a..23e1f0332 100644 --- a/tests/common/api_v2/project.rs +++ b/tests/common/api_v2/project.rs @@ -35,7 +35,7 @@ impl ApiV2 { pat: Option<&str>, ) -> LegacyProject { let resp = self.get_project(id_or_slug, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -45,7 +45,7 @@ impl ApiV2 { pat: Option<&str>, ) -> Vec { let resp = self.get_user_projects(user_id_or_username, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -72,8 +72,7 @@ impl ApiV2 { .append_pat(pat) .to_request(); let resp = self.call(req).await; - let status = resp.status(); - assert_eq!(status, 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } } @@ -164,7 +163,7 @@ impl ApiProject for ApiV2 { pat: Option<&str>, ) -> CommonProject { let resp = self.get_project(id_or_slug, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let project: LegacyProject = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -214,7 +213,7 @@ impl ApiProject for ApiV2 { pat: Option<&str>, ) -> Vec { let resp = self.get_user_projects(user_id_or_username, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let projects: Vec = test::read_body_json(resp).await; // Then, deserialize to the common format diff --git a/tests/common/api_v2/tags.rs b/tests/common/api_v2/tags.rs index 08fb4b886..93fb0ae23 100644 --- a/tests/common/api_v2/tags.rs +++ b/tests/common/api_v2/tags.rs @@ -1,3 +1,4 @@ +use actix_http::StatusCode; use actix_web::{ dev::ServiceResponse, test::{self, TestRequest}, @@ -12,6 +13,7 @@ use crate::common::{ models::{CommonCategoryData, CommonLoaderData}, Api, ApiTags, AppendsOptionalPat, }, + asserts::assert_status, database::ADMIN_USER_PAT, }; @@ -30,7 +32,7 @@ impl ApiV2 { pub async fn get_side_types_deserialized(&self) -> Vec { let resp = self.get_side_types().await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -44,19 +46,19 @@ impl ApiV2 { pub async fn get_game_versions_deserialized(&self) -> Vec { let resp = self.get_game_versions().await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } pub async fn get_loaders_deserialized(&self) -> Vec { let resp = self.get_loaders().await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } pub async fn get_categories_deserialized(&self) -> Vec { let resp = self.get_categories().await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -70,8 +72,7 @@ impl ApiV2 { pub async fn get_donation_platforms_deserialized(&self) -> Vec { let resp = self.get_donation_platforms().await; - println!("Response: {:?}", resp.response().body()); - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } } @@ -88,7 +89,7 @@ impl ApiTags for ApiV2 { async fn get_loaders_deserialized_common(&self) -> Vec { let resp = self.get_loaders().await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: Vec = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -106,7 +107,7 @@ impl ApiTags for ApiV2 { async fn get_categories_deserialized_common(&self) -> Vec { let resp = self.get_categories().await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: Vec = test::read_body_json(resp).await; // Then, deserialize to the common format diff --git a/tests/common/api_v2/team.rs b/tests/common/api_v2/team.rs index a7de717dd..c232358dd 100644 --- a/tests/common/api_v2/team.rs +++ b/tests/common/api_v2/team.rs @@ -24,7 +24,7 @@ impl ApiV2 { pat: Option<&str>, ) -> Vec { let resp = self.get_organization_members(id_or_title, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -34,7 +34,7 @@ impl ApiV2 { pat: Option<&str>, ) -> Vec { let resp = self.get_team_members(team_id, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -44,7 +44,7 @@ impl ApiV2 { pat: Option<&str>, ) -> Vec { let resp = self.get_user_notifications(user_id, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } } @@ -65,7 +65,7 @@ impl ApiTeams for ApiV2 { pat: Option<&str>, ) -> Vec { let resp = self.get_team_members(id_or_title, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // TODO: Note, this does NOT deserialize to any other struct first, as currently TeamMember is the same in v2 and v3. // CommonTeamMember = TeamMember (v3) // This may yet change, so we should keep common struct. @@ -102,7 +102,7 @@ impl ApiTeams for ApiV2 { pat: Option<&str>, ) -> Vec { let resp = self.get_project_members(id_or_title, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // TODO: Note, this does NOT deserialize to any other struct first, as currently TeamMember is the same in v2 and v3. // CommonTeamMember = TeamMember (v3) // This may yet change, so we should keep common struct. @@ -127,7 +127,7 @@ impl ApiTeams for ApiV2 { pat: Option<&str>, ) -> Vec { let resp = self.get_organization_members(id_or_title, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // TODO: Note, this does NOT deserialize to any other struct first, as currently TeamMember is the same in v2 and v3. // CommonTeamMember = TeamMember (v3) // This may yet change, so we should keep common struct. diff --git a/tests/common/api_v2/version.rs b/tests/common/api_v2/version.rs index 1a8b2d193..db4913291 100644 --- a/tests/common/api_v2/version.rs +++ b/tests/common/api_v2/version.rs @@ -33,7 +33,7 @@ pub fn url_encode_json_serialized_vec(elements: &[String]) -> String { impl ApiV2 { pub async fn get_version_deserialized(&self, id: &str, pat: Option<&str>) -> LegacyVersion { let resp = self.get_version(id, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -44,7 +44,7 @@ impl ApiV2 { pat: Option<&str>, ) -> LegacyVersion { let resp = self.get_version_from_hash(hash, algorithm, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -55,7 +55,7 @@ impl ApiV2 { pat: Option<&str>, ) -> HashMap { let resp = self.get_versions_from_hashes(hashes, algorithm, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -83,7 +83,7 @@ impl ApiV2 { pat: Option<&str>, ) -> HashMap { let resp = self.update_individual_files(algorithm, hashes, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } } @@ -135,7 +135,7 @@ impl ApiVersion for ApiV2 { pat, ) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: LegacyVersion = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -153,7 +153,7 @@ impl ApiVersion for ApiV2 { async fn get_version_deserialized_common(&self, id: &str, pat: Option<&str>) -> CommonVersion { let resp = self.get_version(id, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: LegacyVersion = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -212,7 +212,7 @@ impl ApiVersion for ApiV2 { pat: Option<&str>, ) -> CommonVersion { let resp = self.get_version_from_hash(hash, algorithm, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: LegacyVersion = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -244,7 +244,7 @@ impl ApiVersion for ApiV2 { pat: Option<&str>, ) -> HashMap { let resp = self.get_versions_from_hashes(hashes, algorithm, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: HashMap = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -287,7 +287,7 @@ impl ApiVersion for ApiV2 { let resp = self .get_update_from_hash(hash, algorithm, loaders, game_versions, version_types, pat) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: LegacyVersion = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -337,7 +337,7 @@ impl ApiVersion for ApiV2 { pat, ) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: HashMap = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -420,7 +420,7 @@ impl ApiVersion for ApiV2 { pat, ) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: Vec = test::read_body_json(resp).await; // Then, deserialize to the common format diff --git a/tests/common/api_v3/collections.rs b/tests/common/api_v3/collections.rs index eea4b14cc..d49a68c9a 100644 --- a/tests/common/api_v3/collections.rs +++ b/tests/common/api_v3/collections.rs @@ -1,3 +1,4 @@ +use actix_http::StatusCode; use actix_web::{ dev::ServiceResponse, test::{self, TestRequest}, @@ -6,7 +7,10 @@ use bytes::Bytes; use labrinth::models::{collections::Collection, v3::projects::Project}; use serde_json::json; -use crate::common::api_common::{request_data::ImageData, Api, AppendsOptionalPat}; +use crate::common::{ + api_common::{request_data::ImageData, Api, AppendsOptionalPat}, + asserts::assert_status, +}; use super::ApiV3; @@ -40,7 +44,7 @@ impl ApiV3 { pub async fn get_collection_deserialized(&self, id: &str, pat: Option<&str>) -> Collection { let resp = self.get_collection(id, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -70,7 +74,7 @@ impl ApiV3 { pat: Option<&str>, ) -> Vec { let resp = self.get_collection_projects(id, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -145,7 +149,7 @@ impl ApiV3 { pat: Option<&str>, ) -> Vec { let resp = self.get_user_collections(user_id_or_username, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let projects: Vec = test::read_body_json(resp).await; // Then, deserialize to the common format diff --git a/tests/common/api_v3/organization.rs b/tests/common/api_v3/organization.rs index 94956afff..a8c9732f9 100644 --- a/tests/common/api_v3/organization.rs +++ b/tests/common/api_v3/organization.rs @@ -1,3 +1,4 @@ +use actix_http::StatusCode; use actix_web::{ dev::ServiceResponse, test::{self, TestRequest}, @@ -6,7 +7,10 @@ use bytes::Bytes; use labrinth::models::{organizations::Organization, users::UserId, v3::projects::Project}; use serde_json::json; -use crate::common::api_common::{request_data::ImageData, Api, AppendsOptionalPat}; +use crate::common::{ + api_common::{request_data::ImageData, Api, AppendsOptionalPat}, + asserts::assert_status, +}; use super::ApiV3; @@ -14,6 +18,7 @@ impl ApiV3 { pub async fn create_organization( &self, organization_title: &str, + organization_slug: &str, description: &str, pat: Option<&str>, ) -> ServiceResponse { @@ -22,6 +27,7 @@ impl ApiV3 { .append_pat(pat) .set_json(json!({ "name": organization_title, + "slug": organization_slug, "description": description, })) .to_request(); @@ -42,7 +48,7 @@ impl ApiV3 { pat: Option<&str>, ) -> Organization { let resp = self.get_organization(id_or_title, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -80,7 +86,7 @@ impl ApiV3 { pat: Option<&str>, ) -> Vec { let resp = self.get_organization_projects(id_or_title, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } diff --git a/tests/common/api_v3/project.rs b/tests/common/api_v3/project.rs index 8aa095707..38db0eb51 100644 --- a/tests/common/api_v3/project.rs +++ b/tests/common/api_v3/project.rs @@ -119,7 +119,7 @@ impl ApiProject for ApiV3 { pat: Option<&str>, ) -> CommonProject { let resp = self.get_project(id_or_slug, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let project: Project = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -169,7 +169,7 @@ impl ApiProject for ApiV3 { pat: Option<&str>, ) -> Vec { let resp = self.get_user_projects(user_id_or_username, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let projects: Vec = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -383,10 +383,7 @@ impl ApiProject for ApiV3 { .append_pat(pat) .to_request(); - let t = self.call(req).await; - println!("Status: {}", t.status()); - println!("respone Body: {:?}", t.response().body()); - t + self.call(req).await } async fn remove_gallery_item( @@ -480,7 +477,7 @@ impl ApiProject for ApiV3 { impl ApiV3 { pub async fn get_project_deserialized(&self, id_or_slug: &str, pat: Option<&str>) -> Project { let resp = self.get_project(id_or_slug, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -503,7 +500,7 @@ impl ApiV3 { pat: Option<&str>, ) -> Organization { let resp = self.get_project_organization(id_or_slug, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -530,8 +527,7 @@ impl ApiV3 { .append_pat(pat) .to_request(); let resp = self.call(req).await; - let status = resp.status(); - assert_eq!(status, 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -598,7 +594,7 @@ impl ApiV3 { pat, ) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } } diff --git a/tests/common/api_v3/tags.rs b/tests/common/api_v3/tags.rs index 9539dab23..2ebbc1ebc 100644 --- a/tests/common/api_v3/tags.rs +++ b/tests/common/api_v3/tags.rs @@ -1,3 +1,4 @@ +use actix_http::StatusCode; use actix_web::{ dev::ServiceResponse, test::{self, TestRequest}, @@ -13,6 +14,7 @@ use crate::common::{ models::{CommonCategoryData, CommonLoaderData}, Api, ApiTags, AppendsOptionalPat, }, + asserts::assert_status, database::ADMIN_USER_PAT, }; @@ -30,7 +32,7 @@ impl ApiTags for ApiV3 { async fn get_loaders_deserialized_common(&self) -> Vec { let resp = self.get_loaders().await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: Vec = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -48,7 +50,7 @@ impl ApiTags for ApiV3 { async fn get_categories_deserialized_common(&self) -> Vec { let resp = self.get_categories().await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: Vec = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -60,7 +62,7 @@ impl ApiTags for ApiV3 { impl ApiV3 { pub async fn get_loaders_deserialized(&self) -> Vec { let resp = self.get_loaders().await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -77,7 +79,7 @@ impl ApiV3 { loader_field: &str, ) -> Vec { let resp = self.get_loader_field_variants(loader_field).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -92,7 +94,7 @@ impl ApiV3 { pub async fn get_games_deserialized(&self) -> Vec { let resp = self.get_games().await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } } diff --git a/tests/common/api_v3/team.rs b/tests/common/api_v3/team.rs index ca2d1dffc..e2b6f2661 100644 --- a/tests/common/api_v3/team.rs +++ b/tests/common/api_v3/team.rs @@ -24,7 +24,7 @@ impl ApiV3 { pat: Option<&str>, ) -> Vec { let resp = self.get_organization_members(id_or_title, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -34,7 +34,7 @@ impl ApiV3 { pat: Option<&str>, ) -> Vec { let resp = self.get_team_members(team_id, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -44,7 +44,7 @@ impl ApiV3 { pat: Option<&str>, ) -> Vec { let resp = self.get_project_members(project_id, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } } @@ -65,7 +65,7 @@ impl ApiTeams for ApiV3 { pat: Option<&str>, ) -> Vec { let resp = self.get_team_members(id_or_title, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: Vec = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -103,7 +103,7 @@ impl ApiTeams for ApiV3 { pat: Option<&str>, ) -> Vec { let resp = self.get_project_members(id_or_title, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: Vec = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -129,7 +129,7 @@ impl ApiTeams for ApiV3 { pat: Option<&str>, ) -> Vec { let resp = self.get_organization_members(id_or_title, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: Vec = test::read_body_json(resp).await; // Then, deserialize to the common format diff --git a/tests/common/api_v3/version.rs b/tests/common/api_v3/version.rs index 1c2a230c4..f18e67884 100644 --- a/tests/common/api_v3/version.rs +++ b/tests/common/api_v3/version.rs @@ -60,7 +60,7 @@ impl ApiV3 { pub async fn get_version_deserialized(&self, id: &str, pat: Option<&str>) -> Version { let resp = self.get_version(id, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } @@ -88,7 +88,7 @@ impl ApiV3 { pat: Option<&str>, ) -> HashMap { let resp = self.update_individual_files(algorithm, hashes, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); test::read_body_json(resp).await } } @@ -158,7 +158,7 @@ impl ApiVersion for ApiV3 { async fn get_version_deserialized_common(&self, id: &str, pat: Option<&str>) -> CommonVersion { let resp = self.get_version(id, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: Version = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -217,7 +217,7 @@ impl ApiVersion for ApiV3 { pat: Option<&str>, ) -> CommonVersion { let resp = self.get_version_from_hash(hash, algorithm, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: Version = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -249,7 +249,7 @@ impl ApiVersion for ApiV3 { pat: Option<&str>, ) -> HashMap { let resp = self.get_versions_from_hashes(hashes, algorithm, pat).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: HashMap = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -301,7 +301,7 @@ impl ApiVersion for ApiV3 { let resp = self .get_update_from_hash(hash, algorithm, loaders, game_versions, version_types, pat) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: Version = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -361,7 +361,7 @@ impl ApiVersion for ApiV3 { pat, ) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: HashMap = test::read_body_json(resp).await; // Then, deserialize to the common format @@ -444,7 +444,7 @@ impl ApiVersion for ApiV3 { pat, ) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // First, deserialize to the non-common format (to test the response is valid for this api version) let v: Vec = test::read_body_json(resp).await; // Then, deserialize to the common format diff --git a/tests/common/database.rs b/tests/common/database.rs index ba6e9cae9..cc56f0259 100644 --- a/tests/common/database.rs +++ b/tests/common/database.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -use labrinth::database::redis::RedisPool; +use labrinth::{database::redis::RedisPool, search}; use sqlx::{postgres::PgPoolOptions, PgPool}; use std::time::Duration; use url::Url; @@ -39,6 +39,7 @@ const TEMPLATE_DATABASE_NAME: &str = "labrinth_tests_template"; pub struct TemporaryDatabase { pub pool: PgPool, pub redis_pool: RedisPool, + pub search_config: labrinth::search::SearchConfig, pub database_name: String, } @@ -84,10 +85,13 @@ impl TemporaryDatabase { // Gets new Redis pool let redis_pool = RedisPool::new(Some(temp_database_name.clone())); + // Create new meilisearch config + let search_config = search::SearchConfig::new(Some(temp_database_name.clone())); Self { pool, database_name: temp_database_name, redis_pool, + search_config, } } @@ -168,10 +172,12 @@ impl TemporaryDatabase { if !dummy_data_exists { // Add dummy data + let name = generate_random_name("test_template_"); let db = TemporaryDatabase { pool: pool.clone(), database_name: TEMPLATE_DATABASE_NAME.to_string(), - redis_pool: RedisPool::new(Some(generate_random_name("test_template_"))), + redis_pool: RedisPool::new(Some(name.clone())), + search_config: search::SearchConfig::new(Some(name)), }; let setup_api = TestEnvironment::::build_setup_api(&db).await; dummy_data::add_dummy_data(&setup_api, db.clone()).await; diff --git a/tests/common/dummy_data.rs b/tests/common/dummy_data.rs index 394df3692..16ad72dce 100644 --- a/tests/common/dummy_data.rs +++ b/tests/common/dummy_data.rs @@ -207,7 +207,7 @@ impl DummyData { organization_zeta: DummyOrganizationZeta { organization_id: organization_zeta.id.to_string(), team_id: organization_zeta.team_id.to_string(), - organization_name: organization_zeta.name, + organization_slug: organization_zeta.slug, }, oauth_client_alpha: DummyOAuthClientAlpha { @@ -249,7 +249,7 @@ pub struct DummyProjectBeta { #[derive(Clone)] pub struct DummyOrganizationZeta { pub organization_id: String, - pub organization_name: String, + pub organization_slug: String, pub team_id: String, } @@ -390,7 +390,7 @@ pub async fn add_project_beta(api: &ApiV3) -> (Project, Version) { .set_multipart(vec![json_segment.clone(), file_segment.clone()]) .to_request(); let resp = api.call(req).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); get_project_beta(api).await } @@ -401,13 +401,14 @@ pub async fn add_organization_zeta(api: &ApiV3) -> Organization { .uri("/v3/organization") .append_pat(USER_USER_PAT) .set_json(json!({ - "name": "zeta", + "name": "Zeta", + "slug": "zeta", "description": "A dummy organization for testing with." })) .to_request(); let resp = api.call(req).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); get_organization_zeta(api).await } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 27c2f475c..43490cfba 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -27,6 +27,7 @@ pub async fn setup(db: &database::TemporaryDatabase) -> LabrinthConfig { let pool = db.pool.clone(); let redis_pool = db.redis_pool.clone(); + let search_config = db.search_config.clone(); let file_host: Arc = Arc::new(file_hosting::MockHost::new()); let mut clickhouse = clickhouse::init_client().await.unwrap(); @@ -36,6 +37,7 @@ pub async fn setup(db: &database::TemporaryDatabase) -> LabrinthConfig { labrinth::app_setup( pool.clone(), redis_pool.clone(), + search_config, &mut clickhouse, file_host.clone(), maxmind_reader, diff --git a/tests/common/permissions.rs b/tests/common/permissions.rs index 2a645557d..a368d5ab5 100644 --- a/tests/common/permissions.rs +++ b/tests/common/permissions.rs @@ -356,12 +356,13 @@ impl<'a, A: Api> PermissionsTest<'a, A> { .await; if !self.allowed_failure_codes.contains(&resp.status().as_u16()) { return Err(format!( - "Failure permissions test failed. Expected failure codes {} got {}", + "Failure permissions test failed. Expected failure codes {} got {}. Body: {:#?}", self.allowed_failure_codes .iter() .map(|code| code.to_string()) .join(","), - resp.status().as_u16() + resp.status().as_u16(), + resp.response().body() )); } @@ -385,8 +386,9 @@ impl<'a, A: Api> PermissionsTest<'a, A> { .await; if !resp.status().is_success() { return Err(format!( - "Success permissions test failed. Expected success, got {}", - resp.status().as_u16() + "Success permissions test failed. Expected success, got {}. Body: {:#?}", + resp.status().as_u16(), + resp.response().body() )); } @@ -1007,15 +1009,15 @@ async fn create_dummy_project(setup_api: &ApiV3) -> (String, String) { async fn create_dummy_org(setup_api: &ApiV3) -> (String, String) { // Create a very simple organization - let name = generate_random_name("test_org"); + let slug = generate_random_name("test_org"); let resp = setup_api - .create_organization(&name, "Example description.", ADMIN_USER_PAT) + .create_organization("Example org", &slug, "Example description.", ADMIN_USER_PAT) .await; assert!(resp.status().is_success()); let organization = setup_api - .get_organization_deserialized(&name, ADMIN_USER_PAT) + .get_organization_deserialized(&slug, ADMIN_USER_PAT) .await; let organizaion_id = organization.id.to_string(); let team_id = organization.team_id.to_string(); @@ -1109,7 +1111,7 @@ async fn get_project_permissions( .await; let permissions = members .iter() - .find(|member| &member.user.id.to_string() == user_id) + .find(|member| member.user.id.to_string() == user_id) .and_then(|member| member.permissions); let organization_members = match organization { @@ -1123,7 +1125,7 @@ async fn get_project_permissions( let organization_default_project_permissions = match organization_members { Some(members) => members .iter() - .find(|member| &member.user.id.to_string() == user_id) + .find(|member| member.user.id.to_string() == user_id) .and_then(|member| member.permissions), None => None, }; diff --git a/tests/common/search.rs b/tests/common/search.rs index 51058d191..d975e2bd2 100644 --- a/tests/common/search.rs +++ b/tests/common/search.rs @@ -2,6 +2,7 @@ use std::{collections::HashMap, sync::Arc}; +use actix_http::StatusCode; use serde_json::json; use crate::common::{ @@ -10,7 +11,7 @@ use crate::common::{ dummy_data::{TestFile, DUMMY_CATEGORIES}, }; -use super::{api_v3::ApiV3, environment::TestEnvironment}; +use super::{api_v3::ApiV3, asserts::assert_status, environment::TestEnvironment}; pub async fn setup_search_projects(test_env: &TestEnvironment) -> Arc> { // Test setup and dummy data @@ -47,7 +48,7 @@ pub async fn setup_search_projects(test_env: &TestEnvironment) -> Arc) -> Arc| async move { + with_test_environment(Some(10), |test_env: TestEnvironment| async move { let api = &test_env.api; let zeta_organization_id = &test_env.dummy.organization_zeta.organization_id; @@ -205,7 +241,7 @@ async fn add_remove_icon() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Get project let zeta_org = api @@ -218,7 +254,7 @@ async fn add_remove_icon() { let resp = api .edit_organization_icon(zeta_organization_id, None, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Get project let zeta_org = api @@ -239,13 +275,13 @@ async fn delete_org() { let resp = api .delete_organization(zeta_organization_id, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Get organization, which should no longer exist let resp = api .get_organization(zeta_organization_id, USER_USER_PAT) .await; - assert_eq!(resp.status(), 404); + assert_status(&resp, StatusCode::NOT_FOUND); }) .await; } @@ -264,7 +300,7 @@ async fn add_remove_organization_projects() { .api .organization_add_project(zeta_organization_id, alpha, USER_USER_PAT) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // Get organization projects let projects = test_env @@ -284,7 +320,7 @@ async fn add_remove_organization_projects() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // Get organization projects let projects = test_env @@ -338,11 +374,11 @@ async fn add_remove_organization_project_ownership_to_user() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Accept invites let resp = test_env.api.join_team(team, FRIEND_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); } // For each team, confirm there are two members, but only one owner of the project, and it is USER_USER_ID @@ -362,7 +398,7 @@ async fn add_remove_organization_project_ownership_to_user() { .api .transfer_team_ownership(beta_team_id, FRIEND_USER_ID, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Confirm there are still two users, but now FRIEND_USER_ID is the owner let members = test_env @@ -383,7 +419,7 @@ async fn add_remove_organization_project_ownership_to_user() { .api .organization_add_project(zeta_organization_id, project_id, pat) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // Get and confirm it has been added let project = test_env.api.get_project_deserialized(project_id, pat).await; @@ -416,7 +452,7 @@ async fn add_remove_organization_project_ownership_to_user() { .api .transfer_team_ownership(zeta_team_id, FRIEND_USER_ID, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Confirm there are no members of the alpha project OR the beta project // - Friend was removed as a member of these projects when ownership was transferred to them @@ -433,14 +469,14 @@ async fn add_remove_organization_project_ownership_to_user() { .api .add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // As friend, can add user to alpha project, as they are not the org owner let resp = test_env .api .add_user_to_team(alpha_team_id, USER_USER_ID, None, None, FRIEND_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // At this point, friend owns the org // Alpha member has user as a member, but not as an owner @@ -457,7 +493,7 @@ async fn add_remove_organization_project_ownership_to_user() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Set user's permissions within the project that it is a member of to none (for a later test) let resp = test_env @@ -471,7 +507,7 @@ async fn add_remove_organization_project_ownership_to_user() { FRIEND_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Remove project from organization with a user that is an organization member, and a project member // This should succeed @@ -484,7 +520,7 @@ async fn add_remove_organization_project_ownership_to_user() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // Remove project from organization with a user that is an organization member, but not a project member // This should succeed @@ -497,7 +533,7 @@ async fn add_remove_organization_project_ownership_to_user() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // For each of alpha and beta, confirm: // - There is one member of each project, the owner, USER_USER_ID @@ -559,11 +595,11 @@ async fn delete_organization_means_all_projects_to_org_owner() { .api .add_user_to_team(zeta_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Accept invite let resp = test_env.api.join_team(zeta_team_id, FRIEND_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Confirm there is only one owner of the project, and it is USER_USER_ID let members = test_env @@ -579,7 +615,7 @@ async fn delete_organization_means_all_projects_to_org_owner() { .api .organization_add_project(zeta_organization_id, alpha_project_id, USER_USER_PAT) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // Add beta to zeta organization test_env @@ -592,13 +628,13 @@ async fn delete_organization_means_all_projects_to_org_owner() { .api .add_user_to_team(beta_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Try to accept invite // This returns a failure, because since beta and FRIEND are in the organizations, // they can be added to the project without an invite let resp = test_env.api.join_team(beta_team_id, FRIEND_USER_PAT).await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Confirm there is NO owner of the project, as it is owned by the organization let members = test_env @@ -613,7 +649,7 @@ async fn delete_organization_means_all_projects_to_org_owner() { .api .transfer_team_ownership(zeta_team_id, FRIEND_USER_ID, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Confirm there is NO owner of the project, as it is owned by the organization let members = test_env @@ -628,7 +664,7 @@ async fn delete_organization_means_all_projects_to_org_owner() { .api .delete_organization(zeta_organization_id, FRIEND_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Confirm there is only one owner of the alpha project, and it is now FRIEND_USER_ID let members = test_env @@ -708,7 +744,7 @@ async fn permissions_patch_organization() { // Not covered by PATCH /organization #[actix_rt::test] async fn permissions_edit_details() { - with_test_environment(None, |test_env: TestEnvironment| async move { + with_test_environment(Some(12), |test_env: TestEnvironment| async move { let zeta_organization_id = &test_env.dummy.organization_zeta.organization_id; let zeta_team_id = &test_env.dummy.organization_zeta.team_id; @@ -814,9 +850,9 @@ async fn permissions_manage_invites() { let resp = api .add_user_to_team(zeta_team_id, MOD_USER_ID, None, None, ADMIN_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let resp = api.join_team(zeta_team_id, MOD_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // remove existing member (requires remove_member) let remove_member = OrganizationPermissions::REMOVE_MEMBER; @@ -852,13 +888,13 @@ async fn permissions_add_remove_project() { let resp = api .add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let resp = api.join_team(alpha_team_id, FRIEND_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let resp = api .transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Now, FRIEND_USER_ID owns the alpha project // Add alpha project to zeta organization diff --git a/tests/pats.rs b/tests/pats.rs index 832f4d3d5..337a5f402 100644 --- a/tests/pats.rs +++ b/tests/pats.rs @@ -1,3 +1,4 @@ +use actix_http::StatusCode; use actix_web::test; use chrono::{Duration, Utc}; use common::{database::*, environment::with_test_environment_all}; @@ -5,7 +6,7 @@ use common::{database::*, environment::with_test_environment_all}; use labrinth::models::pats::Scopes; use serde_json::json; -use crate::common::api_common::AppendsOptionalPat; +use crate::common::{api_common::AppendsOptionalPat, asserts::assert_status}; mod common; @@ -30,7 +31,7 @@ pub async fn pat_full_test() { })) .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status().as_u16(), 200); + assert_status(&resp, StatusCode::OK); let success: serde_json::Value = test::read_body_json(resp).await; let id = success["id"].as_str().unwrap(); @@ -48,7 +49,7 @@ pub async fn pat_full_test() { .uri("/_internal/pat") .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status().as_u16(), 200); + assert_status(&resp, StatusCode::OK); let success: serde_json::Value = test::read_body_json(resp).await; // Ensure access token is NOT returned for any PATs @@ -87,7 +88,7 @@ pub async fn pat_full_test() { })) .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status().as_u16(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); assert_eq!(mock_pat_test(access_token).await, 401); // No longer works // Change scopes back, and set expiry to the past, and test again @@ -100,7 +101,7 @@ pub async fn pat_full_test() { })) .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status().as_u16(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Wait 1 second before testing again for expiry tokio::time::sleep(Duration::seconds(1).to_std().unwrap()).await; @@ -115,7 +116,7 @@ pub async fn pat_full_test() { })) .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status().as_u16(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); assert_eq!(mock_pat_test(access_token).await, 200); // Works again // Patching to a bad expiry should fail @@ -127,7 +128,7 @@ pub async fn pat_full_test() { })) .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status().as_u16(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Similar to above with PAT creation, patching to a bad scope should fail for i in 0..64 { @@ -156,7 +157,7 @@ pub async fn pat_full_test() { .uri(&format!("/_internal/pat/{}", id)) .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status().as_u16(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); }) .await; } @@ -175,7 +176,7 @@ pub async fn bad_pats() { })) .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status().as_u16(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Name too short or too long should fail for name in ["n", "this_name_is_too_long".repeat(16).as_str()] { @@ -189,7 +190,7 @@ pub async fn bad_pats() { })) .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status().as_u16(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); } // Creating a PAT with an expiry in the past should fail @@ -203,7 +204,7 @@ pub async fn bad_pats() { })) .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status().as_u16(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Make a PAT with each scope, with the result varying by whether that scope is restricted for i in 0..64 { @@ -238,7 +239,7 @@ pub async fn bad_pats() { })) .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status().as_u16(), 200); + assert_status(&resp, StatusCode::OK); let success: serde_json::Value = test::read_body_json(resp).await; let id = success["id"].as_str().unwrap(); @@ -252,7 +253,7 @@ pub async fn bad_pats() { })) .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status().as_u16(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); } // Patching to a bad expiry should fail @@ -264,7 +265,7 @@ pub async fn bad_pats() { })) .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status().as_u16(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Similar to above with PAT creation, patching to a bad scope should fail for i in 0..64 { diff --git a/tests/project.rs b/tests/project.rs index 2eb9755f7..0ceb9b194 100644 --- a/tests/project.rs +++ b/tests/project.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use actix_http::StatusCode; use actix_web::test; use common::api_v3::ApiV3; +use common::asserts::assert_status; use common::database::*; use common::dummy_data::DUMMY_CATEGORIES; @@ -20,7 +21,9 @@ use serde_json::json; use crate::common::api_common::models::CommonItemType; use crate::common::api_common::request_data::ProjectCreationRequestData; use crate::common::api_common::{ApiProject, ApiTeams, ApiVersion}; -use crate::common::dummy_data::{DummyImage, DummyProjectAlpha, DummyProjectBeta, TestFile}; +use crate::common::dummy_data::{ + DummyImage, DummyOrganizationZeta, DummyProjectAlpha, DummyProjectBeta, TestFile, +}; mod common; #[actix_rt::test] @@ -42,10 +45,9 @@ async fn test_get_project() { // Perform request on dummy data let resp = api.get_project(alpha_project_id, USER_USER_PAT).await; - let status = resp.status(); + assert_status(&resp, StatusCode::OK); let body: serde_json::Value = test::read_body_json(resp).await; - assert_eq!(status, 200); assert_eq!(body["id"], json!(alpha_project_id)); assert_eq!(body["slug"], json!(alpha_project_slug)); let versions = body["versions"].as_array().unwrap(); @@ -75,8 +77,7 @@ async fn test_get_project() { // Make the request again, this time it should be cached let resp = api.get_project(alpha_project_id, USER_USER_PAT).await; - let status = resp.status(); - assert_eq!(status, 200); + assert_status(&resp, StatusCode::OK); let body: serde_json::Value = test::read_body_json(resp).await; assert_eq!(body["id"], json!(alpha_project_id)); @@ -84,11 +85,11 @@ async fn test_get_project() { // Request should fail on non-existent project let resp = api.get_project("nonexistent", USER_USER_PAT).await; - assert_eq!(resp.status(), 404); + assert_status(&resp, StatusCode::NOT_FOUND); // Similarly, request should fail on non-authorized user, on a yet-to-be-approved or hidden project, with a 404 (hiding the existence of the project) let resp = api.get_project(beta_project_id, ENEMY_USER_PAT).await; - assert_eq!(resp.status(), 404); + assert_status(&resp, StatusCode::NOT_FOUND); }) .await; } @@ -170,8 +171,7 @@ async fn test_add_remove_project() { ) .await; - let status = resp.status(); - assert_eq!(status, 200); + assert_status(&resp, StatusCode::OK); // Get the project we just made, and confirm that it's correct let project = api @@ -204,7 +204,7 @@ async fn test_add_remove_project() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Reusing with the same slug and a different file should fail let resp = api @@ -220,7 +220,7 @@ async fn test_add_remove_project() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Different slug, different file should succeed let resp = api @@ -236,7 +236,7 @@ async fn test_add_remove_project() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // Get let project = api @@ -246,7 +246,7 @@ async fn test_add_remove_project() { // Remove the project let resp = test_env.api.remove_project("demo", USER_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Confirm that the project is gone from the cache let mut redis_pool = test_env.db.redis_pool.connect().await.unwrap(); @@ -269,7 +269,7 @@ async fn test_add_remove_project() { // Old slug no longer works let resp = api.get_project("demo", USER_USER_PAT).await; - assert_eq!(resp.status(), 404); + assert_status(&resp, StatusCode::NOT_FOUND); }) .await; } @@ -293,7 +293,7 @@ pub async fn test_patch_project() { ENEMY_USER_PAT, ) .await; - assert_eq!(resp.status(), 401); + assert_status(&resp, StatusCode::UNAUTHORIZED); // Failure because we are setting URL fields to invalid urls. for url_type in ["issues", "source", "wiki", "discord"] { @@ -308,7 +308,7 @@ pub async fn test_patch_project() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); } // Failure because these are illegal requested statuses for a normal user. @@ -322,7 +322,7 @@ pub async fn test_patch_project() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); } // Failure because these should not be able to be set by a non-mod @@ -336,7 +336,7 @@ pub async fn test_patch_project() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 401); + assert_status(&resp, StatusCode::UNAUTHORIZED); // (should work for a mod, though) let resp = api @@ -348,7 +348,7 @@ pub async fn test_patch_project() { MOD_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); } // Failed patch to alpha slug: @@ -372,7 +372,7 @@ pub async fn test_patch_project() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); } // Not allowed to directly set status, as 'beta_project_slug' (the other project) is "processing" and cannot have its status changed like this. @@ -385,7 +385,7 @@ pub async fn test_patch_project() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 401); + assert_status(&resp, StatusCode::UNAUTHORIZED); // Sucessful request to patch many fields. let resp = api @@ -406,11 +406,11 @@ pub async fn test_patch_project() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Old slug no longer works let resp = api.get_project(alpha_project_slug, USER_USER_PAT).await; - assert_eq!(resp.status(), 404); + assert_status(&resp, StatusCode::NOT_FOUND); // New slug does work let project = api.get_project_deserialized("newslug", USER_USER_PAT).await; @@ -447,7 +447,7 @@ pub async fn test_patch_project() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let project = api.get_project_deserialized("newslug", USER_USER_PAT).await; assert_eq!(project.link_urls.len(), 3); assert!(!project.link_urls.contains_key("issues")); @@ -475,7 +475,7 @@ pub async fn test_patch_v3() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let project = api .get_project_deserialized(alpha_project_slug, USER_USER_PAT) @@ -509,7 +509,7 @@ pub async fn test_bulk_edit_categories() { ADMIN_USER_PAT, ) .await; - assert_eq!(resp.status(), StatusCode::NO_CONTENT); + assert_status(&resp, StatusCode::NO_CONTENT); let alpha_body = api .get_project_deserialized_common(alpha_project_id, ADMIN_USER_PAT) @@ -552,7 +552,7 @@ pub async fn test_bulk_edit_links() { ADMIN_USER_PAT, ) .await; - assert_eq!(resp.status(), StatusCode::NO_CONTENT); + assert_status(&resp, StatusCode::NO_CONTENT); let alpha_body = api .get_project_deserialized(alpha_project_id, ADMIN_USER_PAT) @@ -597,7 +597,7 @@ async fn delete_project_with_report() { ENEMY_USER_PAT, // Enemy makes a report ) .await; - assert_eq!(resp.status(), StatusCode::OK); + assert_status(&resp, StatusCode::OK); let value = test::read_body_json::(resp).await; let alpha_report_id = value["id"].as_str().unwrap(); @@ -608,7 +608,7 @@ async fn delete_project_with_report() { ENEMY_USER_PAT, // Enemy makes a report ) .await; - assert_eq!(resp.status(), StatusCode::OK); + assert_status(&resp, StatusCode::OK); // Do the same for beta let resp = api @@ -620,13 +620,13 @@ async fn delete_project_with_report() { ENEMY_USER_PAT, // Enemy makes a report ) .await; - assert_eq!(resp.status(), StatusCode::OK); + assert_status(&resp, StatusCode::OK); let value = test::read_body_json::(resp).await; let beta_report_id = value["id"].as_str().unwrap(); // Delete the project let resp = api.remove_project(alpha_project_id, USER_USER_PAT).await; - assert_eq!(resp.status(), StatusCode::NO_CONTENT); + assert_status(&resp, StatusCode::NO_CONTENT); // Confirm that the project is gone from the cache let mut redis_pool = test_env.db.redis_pool.connect().await.unwrap(); @@ -654,7 +654,7 @@ async fn delete_project_with_report() { ENEMY_USER_PAT, // Enemy makes a report ) .await; - assert_eq!(resp.status(), StatusCode::NOT_FOUND); + assert_status(&resp, StatusCode::NOT_FOUND); // Confirm that report for beta still exists let resp = api @@ -663,7 +663,7 @@ async fn delete_project_with_report() { ENEMY_USER_PAT, // Enemy makes a report ) .await; - assert_eq!(resp.status(), StatusCode::OK); + assert_status(&resp, StatusCode::OK); }) .await; } @@ -815,7 +815,7 @@ async fn permissions_patch_project_v3() { // MOD_USER_PAT, // ) // .await; -// assert_eq!(resp.status(), 204); +// assert_status(&resp, StatusCode::NO_CONTENT); // // Schedule version // let req_gen = |ctx: PermissionsTestContext| async move { @@ -839,7 +839,7 @@ async fn permissions_patch_project_v3() { // Not covered by PATCH /project #[actix_rt::test] async fn permissions_edit_details() { - with_test_environment_all(None, |test_env| async move { + with_test_environment_all(Some(10), |test_env| async move { let DummyProjectAlpha { project_id: alpha_project_id, team_id: alpha_team_id, @@ -1112,11 +1112,11 @@ async fn permissions_manage_invites() { ADMIN_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Accept invite let resp = api.join_team(alpha_team_id, MOD_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // remove existing member (requires remove_member) let remove_member = ProjectPermissions::REMOVE_MEMBER; @@ -1223,7 +1223,7 @@ async fn align_search_projects() { let project_model = api .get_project(&project.id.to_string(), USER_USER_PAT) .await; - assert_eq!(project_model.status(), 200); + assert_status(&project_model, StatusCode::OK); let mut project_model: Project = test::read_body_json(project_model).await; // Body/description is huge- don't store it in search, so it's OK if they differ here @@ -1233,9 +1233,24 @@ async fn align_search_projects() { // Aggregate project loader fields will not match exactly, // because the search will only return the matching version, whereas the project returns the aggregate. // So, we remove them from both. + let project_model_mrpack_loaders: Vec<_> = project_model + .fields + .remove("mrpack_loaders") + .unwrap_or_default() + .into_iter() + .filter_map(|v| v.as_str().map(|v| v.to_string())) + .collect(); project_model.fields = HashMap::new(); project.fields = HashMap::new(); + // For a similar reason we also remove the mrpack loaders from the additional categories of the search model + // (Becasue they are not returned by the search) + // TODO: get models to match *exactly* without an additional project fetch, + // including these fields removed here + project + .additional_categories + .retain(|x| !project_model_mrpack_loaders.contains(x)); + let project_model = serde_json::to_value(project_model).unwrap(); let searched_project_serialized = serde_json::to_value(project).unwrap(); assert_eq!(project_model, searched_project_serialized); @@ -1244,6 +1259,129 @@ async fn align_search_projects() { .await } +#[actix_rt::test] +async fn projects_various_visibility() { + // For testing the filter_visible_projects and is_visible_project + with_test_environment( + None, + |env: common::environment::TestEnvironment| async move { + let DummyProjectAlpha { + project_id: alpha_project_id, + project_id_parsed: alpha_project_id_parsed, + .. + } = &env.dummy.project_alpha; + let DummyProjectBeta { + project_id: beta_project_id, + project_id_parsed: beta_project_id_parsed, + .. + } = &env.dummy.project_beta; + let DummyOrganizationZeta { + organization_id: zeta_organization_id, + team_id: zeta_team_id, + .. + } = &env.dummy.organization_zeta; + + // Invite friend to org zeta and accept it + let resp = env + .api + .add_user_to_team( + zeta_team_id, + FRIEND_USER_ID, + Some(ProjectPermissions::empty()), + None, + USER_USER_PAT, + ) + .await; + assert_status(&resp, StatusCode::NO_CONTENT); + let resp = env.api.join_team(zeta_team_id, FRIEND_USER_PAT).await; + assert_status(&resp, StatusCode::NO_CONTENT); + + let visible_pat_pairs = vec![ + (&alpha_project_id_parsed, USER_USER_PAT, StatusCode::OK), + (&alpha_project_id_parsed, FRIEND_USER_PAT, StatusCode::OK), + (&alpha_project_id_parsed, ENEMY_USER_PAT, StatusCode::OK), + (&beta_project_id_parsed, USER_USER_PAT, StatusCode::OK), + ( + &beta_project_id_parsed, + FRIEND_USER_PAT, + StatusCode::NOT_FOUND, + ), + ( + &beta_project_id_parsed, + ENEMY_USER_PAT, + StatusCode::NOT_FOUND, + ), + ]; + + // Tests get_project, a route that uses is_visible_project + for (project_id, pat, expected_status) in visible_pat_pairs { + let resp = env.api.get_project(&project_id.to_string(), pat).await; + assert_status(&resp, expected_status); + } + + // Test get_user_projects, a route that uses filter_visible_projects + let visible_pat_pairs = vec![ + (USER_USER_PAT, 2), + (FRIEND_USER_PAT, 1), + (ENEMY_USER_PAT, 1), + ]; + for (pat, expected_count) in visible_pat_pairs { + let projects = env + .api + .get_user_projects_deserialized_common(USER_USER_ID, pat) + .await; + assert_eq!(projects.len(), expected_count); + } + + // Add projects to org zeta + let resp = env + .api + .organization_add_project(zeta_organization_id, alpha_project_id, USER_USER_PAT) + .await; + assert_status(&resp, StatusCode::OK); + let resp = env + .api + .organization_add_project(zeta_organization_id, beta_project_id, USER_USER_PAT) + .await; + assert_status(&resp, StatusCode::OK); + + // Test get_project, a route that uses is_visible_project + let visible_pat_pairs = vec![ + (&alpha_project_id_parsed, USER_USER_PAT, StatusCode::OK), + (&alpha_project_id_parsed, FRIEND_USER_PAT, StatusCode::OK), + (&alpha_project_id_parsed, ENEMY_USER_PAT, StatusCode::OK), + (&beta_project_id_parsed, USER_USER_PAT, StatusCode::OK), + (&beta_project_id_parsed, FRIEND_USER_PAT, StatusCode::OK), + ( + &beta_project_id_parsed, + ENEMY_USER_PAT, + StatusCode::NOT_FOUND, + ), + ]; + + for (project_id, pat, expected_status) in visible_pat_pairs { + let resp = env.api.get_project(&project_id.to_string(), pat).await; + assert_status(&resp, expected_status); + } + + // Test get_user_projects, a route that uses filter_visible_projects + let visible_pat_pairs = vec![ + (USER_USER_PAT, 2), + (FRIEND_USER_PAT, 2), + (ENEMY_USER_PAT, 1), + ]; + for (pat, expected_count) in visible_pat_pairs { + let projects = env + .api + .get_user_projects_deserialized_common(USER_USER_ID, pat) + .await; + assert_eq!(projects.len(), expected_count); + } + }, + ) + .await; +} + // Route tests: // TODO: Missing routes on projects // TODO: using permissions/scopes, can we SEE projects existence that we are not allowed to? (ie 401 instead of 404) diff --git a/tests/scopes.rs b/tests/scopes.rs index 2b9b36134..8e2e24395 100644 --- a/tests/scopes.rs +++ b/tests/scopes.rs @@ -2,12 +2,14 @@ use std::collections::HashMap; use crate::common::api_common::{ApiProject, ApiTeams, ApiUser, ApiVersion, AppendsOptionalPat}; use crate::common::dummy_data::{DummyImage, DummyProjectAlpha, DummyProjectBeta}; +use actix_http::StatusCode; use actix_web::test; use chrono::{Duration, Utc}; use common::api_common::models::CommonItemType; use common::api_common::Api; use common::api_v3::request_data::get_public_project_creation_data; use common::api_v3::ApiV3; +use common::asserts::assert_status; use common::dummy_data::TestFile; use common::environment::{with_test_environment, with_test_environment_all, TestEnvironment}; use common::{database::*, scopes::ScopeTest}; @@ -114,7 +116,7 @@ pub async fn notifications_scopes() { .api .add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Notification get let read_notifications = Scopes::NOTIFICATION_READ; @@ -187,7 +189,7 @@ pub async fn notifications_scopes() { .api .add_user_to_team(alpha_team_id, MOD_USER_ID, None, None, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let read_notifications = Scopes::NOTIFICATION_READ; let req_gen = |pat: Option| async move { api.get_user_notifications(MOD_USER_ID, pat.as_deref()) @@ -386,7 +388,7 @@ pub async fn project_version_reads_scopes() { .api .edit_version(beta_version_id, json!({ "status": "draft" }), USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let req_gen = |pat: Option| async move { api.get_version_from_hash(beta_file_hash, "sha1", pat.as_deref()) @@ -1084,7 +1086,7 @@ pub async fn organization_scopes() { // Create organization let organization_create = Scopes::ORGANIZATION_CREATE; let req_gen = |pat: Option| async move { - api.create_organization("TestOrg", "TestOrg Description", pat.as_deref()) + api.create_organization("Test Org", "TestOrg", "TestOrg Description", pat.as_deref()) .await }; let (_, success) = ScopeTest::new(&test_env) diff --git a/tests/teams.rs b/tests/teams.rs index b3e267d82..2a5629ebc 100644 --- a/tests/teams.rs +++ b/tests/teams.rs @@ -1,4 +1,5 @@ -use crate::common::{api_common::ApiTeams, database::*}; +use crate::common::{api_common::ApiTeams, asserts::assert_status, database::*}; +use actix_http::StatusCode; use common::{ api_v3::ApiV3, environment::{with_test_environment, with_test_environment_all, TestEnvironment}, @@ -39,7 +40,7 @@ async fn test_get_team() { let resp = api .add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Team check directly let members = api @@ -92,7 +93,7 @@ async fn test_get_team() { // An accepted member of the team should appear in the team members list // and should be able to see private data about the team let resp = api.join_team(alpha_team_id, FRIEND_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Team check directly let members = api @@ -163,7 +164,7 @@ async fn test_get_team_organization() { let resp = api .add_user_to_team(zeta_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Team check directly let members = api @@ -217,7 +218,7 @@ async fn test_get_team_organization() { // An accepted member of the team should appear in the team members list // and should be able to see private data about the team let resp = api.join_team(zeta_team_id, FRIEND_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Team check directly let members = api @@ -272,17 +273,17 @@ async fn test_get_team_project_orgs() { .api .organization_add_project(zeta_organization_id, alpha_project_id, USER_USER_PAT) .await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // Invite and add friend to zeta let resp = test_env .api .add_user_to_team(zeta_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let resp = test_env.api.join_team(zeta_team_id, FRIEND_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // The team members route from teams (on a project's team): // - the members of the project team specifically @@ -315,19 +316,19 @@ async fn test_patch_project_team_member() { // Edit team as admin/mod but not a part of the team should be OK let resp = api.edit_team_member(alpha_team_id, USER_USER_ID, json!({}), ADMIN_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // As a non-owner with full permissions, attempt to edit the owner's permissions let resp = api.edit_team_member(alpha_team_id, USER_USER_ID, json!({ "permissions": 0 }), ADMIN_USER_PAT).await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Should not be able to edit organization permissions of a project team let resp = api.edit_team_member(alpha_team_id, USER_USER_ID, json!({ "organization_permissions": 0 }), USER_USER_PAT).await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Should not be able to add permissions to a user that the adding-user does not have // (true for both project and org) @@ -336,24 +337,24 @@ async fn test_patch_project_team_member() { let resp = api.add_user_to_team(alpha_team_id, FRIEND_USER_ID, Some(ProjectPermissions::EDIT_MEMBER | ProjectPermissions::EDIT_BODY), None, USER_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // accept let resp = api.join_team(alpha_team_id, FRIEND_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // try to add permissions let resp = api.edit_team_member(alpha_team_id, FRIEND_USER_ID, json!({ "permissions": (ProjectPermissions::EDIT_MEMBER | ProjectPermissions::EDIT_DETAILS).bits() }), FRIEND_USER_PAT).await; // should this be friend_user_pat - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Cannot set payouts outside of 0 and 5000 for payout in [-1, 5001] { let resp = api.edit_team_member(alpha_team_id, FRIEND_USER_ID, json!({ "payouts_split": payout }), USER_USER_PAT).await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); } // Successful patch @@ -363,7 +364,7 @@ async fn test_patch_project_team_member() { "role": "membe2r", "ordering": 5 }), FRIEND_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Check results let members = api.get_team_members_deserialized_common(alpha_team_id, FRIEND_USER_PAT).await; @@ -387,14 +388,14 @@ async fn test_patch_organization_team_member() { .api .edit_team_member(zeta_team_id, USER_USER_ID, json!({}), ADMIN_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // As a non-owner with full permissions, attempt to edit the owner's permissions let resp = test_env .api .edit_team_member(zeta_team_id, USER_USER_ID, json!({ "permissions": 0 }), ADMIN_USER_PAT) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Should not be able to add permissions to a user that the adding-user does not have // (true for both project and org) @@ -404,18 +405,18 @@ async fn test_patch_organization_team_member() { .api .add_user_to_team(zeta_team_id, FRIEND_USER_ID, None, Some(OrganizationPermissions::EDIT_MEMBER | OrganizationPermissions::EDIT_MEMBER_DEFAULT_PERMISSIONS), USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // accept let resp = test_env.api.join_team(zeta_team_id, FRIEND_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // try to add permissions- fails, as we do not have EDIT_DETAILS let resp = test_env .api .edit_team_member(zeta_team_id, FRIEND_USER_ID, json!({ "organization_permissions": (OrganizationPermissions::EDIT_MEMBER | OrganizationPermissions::EDIT_DETAILS).bits() }), FRIEND_USER_PAT) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Cannot set payouts outside of 0 and 5000 for payout in [-1, 5001] { @@ -423,7 +424,7 @@ async fn test_patch_organization_team_member() { .api .edit_team_member(zeta_team_id, FRIEND_USER_ID, json!({ "payouts_split": payout }), USER_USER_PAT) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); } // Successful patch @@ -442,7 +443,7 @@ async fn test_patch_organization_team_member() { FRIEND_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Check results let members = test_env @@ -481,39 +482,39 @@ async fn transfer_ownership_v3() { let resp = api .transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); let resp = api .transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, FRIEND_USER_PAT) .await; - assert_eq!(resp.status(), 401); + assert_status(&resp, StatusCode::UNAUTHORIZED); // first, invite friend let resp = api .add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // still cannot set friend as owner (not accepted) let resp = api .transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // accept let resp = api.join_team(alpha_team_id, FRIEND_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Cannot set ourselves as owner if we are not owner let resp = api .transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, FRIEND_USER_PAT) .await; - assert_eq!(resp.status(), 401); + assert_status(&resp, StatusCode::UNAUTHORIZED); // Can set friend as owner let resp = api .transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Check let members = api @@ -542,7 +543,7 @@ async fn transfer_ownership_v3() { let resp = api .remove_from_team(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT) .await; - assert_eq!(resp.status(), 401); + assert_status(&resp, StatusCode::UNAUTHORIZED); // V3 only- confirm the owner can change their role without losing ownership let resp = api @@ -555,7 +556,7 @@ async fn transfer_ownership_v3() { FRIEND_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let members = api .get_team_members_deserialized(alpha_team_id, USER_USER_PAT) @@ -588,25 +589,25 @@ async fn transfer_ownership_v3() { // // Link alpha team to zeta org // let resp = api.organization_add_project(zeta_organization_id, alpha_project_id, USER_USER_PAT).await; -// assert_eq!(resp.status(), 200); +// assert_status(&resp, StatusCode::OK); // // Invite friend to zeta team with all project default permissions // let resp = api.add_user_to_team(&zeta_team_id, FRIEND_USER_ID, Some(ProjectPermissions::all()), Some(OrganizationPermissions::all()), USER_USER_PAT).await; -// assert_eq!(resp.status(), 204); +// assert_status(&resp, StatusCode::NO_CONTENT); // // Accept invite to zeta team // let resp = api.join_team(&zeta_team_id, FRIEND_USER_PAT).await; -// assert_eq!(resp.status(), 204); +// assert_status(&resp, StatusCode::NO_CONTENT); // // Attempt, as friend, to edit details of alpha project (should succeed, org invite accepted) // let resp = api.edit_project(alpha_project_id, json!({ // "title": "new name" // }), FRIEND_USER_PAT).await; -// assert_eq!(resp.status(), 204); +// assert_status(&resp, StatusCode::NO_CONTENT); // // Invite friend to alpha team with *no* project permissions // let resp = api.add_user_to_team(&alpha_team_id, FRIEND_USER_ID, Some(ProjectPermissions::empty()), None, USER_USER_PAT).await; -// assert_eq!(resp.status(), 204); +// assert_status(&resp, StatusCode::NO_CONTENT); // // Do not accept invite to alpha team @@ -614,7 +615,7 @@ async fn transfer_ownership_v3() { // let resp = api.edit_project(alpha_project_id, json!({ // "title": "new name" // }), FRIEND_USER_PAT).await; -// assert_eq!(resp.status(), 401); +// assert_status(&resp, StatusCode::UNAUTHORIZED); // test_env.cleanup().await; // } diff --git a/tests/v2/error.rs b/tests/v2/error.rs index e87d08878..0460d9445 100644 --- a/tests/v2/error.rs +++ b/tests/v2/error.rs @@ -1,4 +1,6 @@ use crate::common::api_common::ApiProject; +use crate::common::asserts::assert_status; +use actix_http::StatusCode; use actix_web::test; use bytes::Bytes; @@ -13,7 +15,7 @@ pub async fn error_404_empty() { // V2 errors should have 404 as blank body, for missing resources let api = &test_env.api; let resp = api.get_project("does-not-exist", USER_USER_PAT).await; - assert_eq!(resp.status(), 404); + assert_status(&resp, StatusCode::NOT_FOUND); let body = test::read_body(resp).await; let empty_bytes = Bytes::from_static(b""); assert_eq!(body, empty_bytes); diff --git a/tests/v2/project.rs b/tests/v2/project.rs index 67f9386dd..3e79aa0ac 100644 --- a/tests/v2/project.rs +++ b/tests/v2/project.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use crate::common::{ api_common::{ApiProject, ApiVersion, AppendsOptionalPat}, api_v2::{request_data::get_public_project_creation_data_json, ApiV2}, + asserts::assert_status, database::{ generate_random_name, ADMIN_USER_PAT, FRIEND_USER_ID, FRIEND_USER_PAT, USER_USER_PAT, }, @@ -132,10 +133,8 @@ async fn test_add_remove_project() { .append_pat(USER_USER_PAT) .set_multipart(vec![json_segment.clone(), file_segment.clone()]) .to_request(); - let resp = test_env.call(req).await; - - let status = resp.status(); - assert_eq!(status, 200); + let resp: actix_web::dev::ServiceResponse = test_env.call(req).await; + assert_status(&resp, StatusCode::OK); // Get the project we just made, and confirm that it's correct let project = api.get_project_deserialized("demo", USER_USER_PAT).await; @@ -163,7 +162,7 @@ async fn test_add_remove_project() { .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Reusing with the same slug and a different file should fail let req = test::TestRequest::post() @@ -176,7 +175,7 @@ async fn test_add_remove_project() { .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // Different slug, different file should succeed let req = test::TestRequest::post() @@ -189,7 +188,7 @@ async fn test_add_remove_project() { .to_request(); let resp = test_env.call(req).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); // Get let project = api.get_project_deserialized("demo", USER_USER_PAT).await; @@ -197,7 +196,7 @@ async fn test_add_remove_project() { // Remove the project let resp = test_env.api.remove_project("demo", USER_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Confirm that the project is gone from the cache let mut redis_conn = test_env.db.redis_pool.connect().await.unwrap(); @@ -220,7 +219,7 @@ async fn test_add_remove_project() { // Old slug no longer works let resp = api.get_project("demo", USER_USER_PAT).await; - assert_eq!(resp.status(), 404); + assert_status(&resp, StatusCode::NOT_FOUND); }) .await; } @@ -344,7 +343,7 @@ pub async fn test_patch_v2() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let project = api .get_project_deserialized(alpha_project_slug, USER_USER_PAT) @@ -456,7 +455,7 @@ pub async fn test_bulk_edit_links() { ADMIN_USER_PAT, ) .await; - assert_eq!(resp.status(), StatusCode::NO_CONTENT); + assert_status(&resp, StatusCode::NO_CONTENT); let alpha_body = api .get_project_deserialized(alpha_project_id, ADMIN_USER_PAT) @@ -496,7 +495,7 @@ pub async fn test_bulk_edit_links() { ADMIN_USER_PAT, ) .await; - assert_eq!(resp.status(), StatusCode::NO_CONTENT); + assert_status(&resp, StatusCode::NO_CONTENT); let alpha_body = api .get_project_deserialized(alpha_project_id, ADMIN_USER_PAT) @@ -568,7 +567,7 @@ pub async fn test_bulk_edit_links() { ADMIN_USER_PAT, ) .await; - assert_eq!(resp.status(), StatusCode::NO_CONTENT); + assert_status(&resp, StatusCode::NO_CONTENT); let alpha_body = api .get_project_deserialized(alpha_project_id, ADMIN_USER_PAT) diff --git a/tests/v2/search.rs b/tests/v2/search.rs index df77de9c4..cc5d104e2 100644 --- a/tests/v2/search.rs +++ b/tests/v2/search.rs @@ -2,11 +2,13 @@ use crate::common::api_common::Api; use crate::common::api_common::ApiProject; use crate::common::api_common::ApiVersion; use crate::common::api_v2::ApiV2; +use crate::common::asserts::assert_status; use crate::common::database::*; use crate::common::dummy_data::TestFile; use crate::common::dummy_data::DUMMY_CATEGORIES; use crate::common::environment::with_test_environment; use crate::common::environment::TestEnvironment; +use actix_http::StatusCode; use futures::stream::StreamExt; use labrinth::models::ids::base62_impl::parse_base62; use serde_json::json; @@ -53,7 +55,7 @@ async fn search_projects() { MOD_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); (project.id.0, id) } }; @@ -282,7 +284,7 @@ async fn search_projects() { // Forcibly reset the search index let resp = api.reset_search_index().await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Test searches let stream = futures::stream::iter(pairs); diff --git a/tests/v2/teams.rs b/tests/v2/teams.rs index 7caf9b728..12cc6260d 100644 --- a/tests/v2/teams.rs +++ b/tests/v2/teams.rs @@ -1,9 +1,11 @@ +use actix_http::StatusCode; use labrinth::models::teams::ProjectPermissions; use serde_json::json; use crate::common::{ api_common::ApiTeams, api_v2::ApiV2, + asserts::assert_status, database::{ FRIEND_USER_ID, FRIEND_USER_ID_PARSED, FRIEND_USER_PAT, USER_USER_ID_PARSED, USER_USER_PAT, }, @@ -23,35 +25,35 @@ async fn transfer_ownership_v2() { let resp = api .transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // first, invite friend let resp = api .add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // still cannot set friend as owner (not accepted) let resp = api .transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); // accept let resp = api.join_team(alpha_team_id, FRIEND_USER_PAT).await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Cannot set ourselves as owner if we are not owner let resp = api .transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, FRIEND_USER_PAT) .await; - assert_eq!(resp.status(), 401); + assert_status(&resp, StatusCode::UNAUTHORIZED); // Can set friend as owner let resp = api .transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); // Check let members = api @@ -78,7 +80,7 @@ async fn transfer_ownership_v2() { let resp = api .remove_from_team(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT) .await; - assert_eq!(resp.status(), 401); + assert_status(&resp, StatusCode::UNAUTHORIZED); // V2 only- confirm the owner changing the role to member does nothing let resp = api @@ -91,7 +93,7 @@ async fn transfer_ownership_v2() { FRIEND_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let members = api .get_team_members_deserialized(alpha_team_id, USER_USER_PAT) .await; diff --git a/tests/v2/version.rs b/tests/v2/version.rs index bc719f68b..ea982a16f 100644 --- a/tests/v2/version.rs +++ b/tests/v2/version.rs @@ -1,3 +1,4 @@ +use actix_http::StatusCode; use actix_web::test; use futures::StreamExt; use labrinth::models::projects::VersionId; @@ -9,6 +10,7 @@ use serde_json::json; use crate::common::api_common::{ApiProject, ApiVersion}; use crate::common::api_v2::ApiV2; +use crate::common::asserts::assert_status; use crate::common::dummy_data::{DummyProjectAlpha, DummyProjectBeta}; use crate::common::environment::{with_test_environment, TestEnvironment}; use crate::common::{ @@ -34,7 +36,7 @@ pub async fn test_patch_version() { ENEMY_USER_PAT, ) .await; - assert_eq!(resp.status(), 401); + assert_status(&resp, StatusCode::UNAUTHORIZED); // Failure because these are illegal requested statuses for a normal user. for req in ["unknown", "scheduled"] { @@ -48,7 +50,7 @@ pub async fn test_patch_version() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); } // Sucessful request to patch many fields. @@ -72,7 +74,7 @@ pub async fn test_patch_version() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let version = api .get_version_deserialized(alpha_version_id, USER_USER_PAT) @@ -100,7 +102,7 @@ pub async fn test_patch_version() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let version = api .get_version_deserialized(alpha_version_id, USER_USER_PAT) @@ -117,7 +119,7 @@ pub async fn test_patch_version() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let version = api .get_version_deserialized(alpha_version_id, USER_USER_PAT) @@ -260,12 +262,12 @@ async fn version_updates() { ) .await; if success { - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); let body: serde_json::Value = test::read_body_json(resp).await; let id = body["id"].as_str().unwrap(); assert_eq!(id, &result_id.to_string()); } else { - assert_eq!(resp.status(), 404); + assert_status(&resp, StatusCode::NOT_FOUND); } // update_files diff --git a/tests/version.rs b/tests/version.rs index 5d762f8cd..5912b46fa 100644 --- a/tests/version.rs +++ b/tests/version.rs @@ -61,7 +61,7 @@ async fn test_get_version() { // Request should fail on non-existent version let resp = api.get_version("false", USER_USER_PAT).await; - assert_eq!(resp.status(), 404); + assert_status(&resp, StatusCode::NOT_FOUND); // Similarly, request should fail on non-authorized user, on a yet-to-be-approved or hidden project, with a 404 (hiding the existence of the project) // TODO: beta version should already be draft in dummy data, but theres a bug in finding it that @@ -74,9 +74,9 @@ async fn test_get_version() { ) .await; let resp = api.get_version(beta_version_id, USER_USER_PAT).await; - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); let resp = api.get_version(beta_version_id, ENEMY_USER_PAT).await; - assert_eq!(resp.status(), 404); + assert_status(&resp, StatusCode::NOT_FOUND); }) .await; } @@ -219,12 +219,12 @@ async fn version_updates() { ) .await; if success { - assert_eq!(resp.status(), 200); + assert_status(&resp, StatusCode::OK); let body: serde_json::Value = test::read_body_json(resp).await; let id = body["id"].as_str().unwrap(); assert_eq!(id, &result_id.to_string()); } else { - assert_eq!(resp.status(), 404); + assert_status(&resp, StatusCode::NOT_FOUND); } // update_files @@ -405,7 +405,7 @@ pub async fn test_patch_version() { ENEMY_USER_PAT, ) .await; - assert_eq!(resp.status(), 401); + assert_status(&resp, StatusCode::UNAUTHORIZED); // Failure because these are illegal requested statuses for a normal user. for req in ["unknown", "scheduled"] { @@ -419,7 +419,7 @@ pub async fn test_patch_version() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 400); + assert_status(&resp, StatusCode::BAD_REQUEST); } // Sucessful request to patch many fields. @@ -447,7 +447,7 @@ pub async fn test_patch_version() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let version = api .get_version_deserialized_common(alpha_version_id, USER_USER_PAT) @@ -483,7 +483,7 @@ pub async fn test_patch_version() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let version = api .get_version_deserialized_common(alpha_version_id, USER_USER_PAT) @@ -499,7 +499,7 @@ pub async fn test_patch_version() { USER_USER_PAT, ) .await; - assert_eq!(resp.status(), 204); + assert_status(&resp, StatusCode::NO_CONTENT); let version = api .get_version_deserialized_common(alpha_version_id, USER_USER_PAT)