From ea95f7e6243c7ede2a7fa285e32c2196efa46cde Mon Sep 17 00:00:00 2001 From: Wyatt Verchere Date: Wed, 8 Nov 2023 15:12:09 -0800 Subject: [PATCH] loaders to loader_fields, added tests --- migrations/20231005230721_dynamic-fields.sql | 78 +++++++++++--------- src/database/models/loader_fields.rs | 10 +-- src/models/v2/projects.rs | 49 +++++++++--- src/routes/v2/project_creation.rs | 20 +---- src/routes/v2/version_creation.rs | 2 +- src/routes/v2_reroute.rs | 2 +- src/routes/v3/analytics_get.rs | 2 +- src/routes/v3/organizations.rs | 3 - src/routes/v3/projects.rs | 5 -- src/routes/v3/users.rs | 4 - src/search/indexing/local_import.rs | 11 ++- tests/common/api_v2/project.rs | 2 - tests/files/dummy_data.sql | 6 +- tests/project.rs | 55 +++++++++++++- tests/search.rs | 20 +++-- tests/tags.rs | 4 +- 16 files changed, 174 insertions(+), 99 deletions(-) diff --git a/migrations/20231005230721_dynamic-fields.sql b/migrations/20231005230721_dynamic-fields.sql index 42977690..7bf0052f 100644 --- a/migrations/20231005230721_dynamic-fields.sql +++ b/migrations/20231005230721_dynamic-fields.sql @@ -6,41 +6,6 @@ CREATE TABLE games ( INSERT INTO games(id, name) VALUES (1, 'minecraft-java'); INSERT INTO games(id, name) VALUES (2, 'minecraft-bedrock'); --- we are creating a new loader type- 'mrpack'- for minecraft modpacks -INSERT INTO loaders (loader) VALUES ('mrpack'); -INSERT INTO loaders_project_types (joining_loader_id, joining_project_type_id) SELECT DISTINCT l.id, pt.id FROM loaders l CROSS JOIN project_types pt WHERE pt.name = 'modpack' AND l.loader = 'mrpack'; - --- We create 'modpack' categories for every loader --- That way we keep information like "this modpack is a fabric modpack" -INSERT INTO categories (category, project_type) -SELECT DISTINCT l.loader, pt.id FROM loaders l CROSS JOIN project_types pt WHERE pt.name = 'modpack' AND l.loader != 'mrpack'; - --- insert the loader of every modpack mod as a category -INSERT INTO mods_categories (joining_mod_id, joining_category_id) -SELECT DISTINCT m.id, c.id -FROM mods m -LEFT JOIN versions v ON m.id = v.mod_id -LEFT JOIN loaders_versions lv ON v.id = lv.version_id -LEFT JOIN loaders l ON lv.loader_id = l.id -CROSS JOIN categories c -WHERE m.project_type = (SELECT id FROM project_types WHERE name = 'modpack') AND c.category = l.loader; - --- Non mrpack loaders no longer support modpacks -DELETE FROM loaders_project_types WHERE joining_loader_id != (SELECT id FROM loaders WHERE loader = 'mrpack') AND joining_project_type_id = (SELECT id FROM project_types WHERE name = 'modpack'); - -CREATE TABLE loaders_project_types_games ( - loader_id integer REFERENCES loaders NOT NULL, - project_type_id integer REFERENCES project_types NOT NULL, - game_id integer REFERENCES games NOT NULL, - PRIMARY KEY (loader_id, project_type_id, game_id) -); - --- all past loader_project_types are minecraft-java as the only game before this migration is minecraft-java -INSERT INTO loaders_project_types_games (loader_id, project_type_id, game_id) SELECT joining_loader_id, joining_project_type_id, 1 FROM loaders_project_types; - --- Now that loaders are inferred, we can drop the project_type column from mods -ALTER TABLE mods DROP COLUMN project_type; - ALTER TABLE loaders ADD CONSTRAINT unique_loader_name UNIQUE (loader); CREATE TABLE loader_field_enums ( @@ -129,7 +94,7 @@ INSERT INTO loader_field_enums (id, enum_name, hidable) VALUES (2, 'game_version INSERT INTO loader_field_enum_values (original_id, enum_id, value, created, metadata) SELECT id, 2, version, created, json_build_object('type', type, 'major', major) FROM game_versions; -INSERT INTO loader_fields (field, field_type, enum_type, optional, min_val) VALUES('game_versions', 'array_enum', 2, false, 1); +INSERT INTO loader_fields (field, field_type, enum_type, optional, min_val) VALUES('game_versions', 'array_enum', 2, false, 0); INSERT INTO version_fields(version_id, field_id, enum_value) SELECT gvv.joining_version_id, 2, lfev.id @@ -141,5 +106,46 @@ ALTER TABLE mods DROP COLUMN game_versions; DROP TABLE game_versions_versions; DROP TABLE game_versions; +-- Convert project types +-- we are creating a new loader type- 'mrpack'- for minecraft modpacks +INSERT INTO loaders (loader) VALUES ('mrpack'); + +-- For the loader 'mrpack', we create loader fields for every loader +-- That way we keep information like "this modpack is a fabric modpack" +INSERT INTO loader_field_enums (id, enum_name, hidable) VALUES (3, 'mrpack_loaders', true); +INSERT INTO loader_field_enum_values (original_id, enum_id, value) SELECT id, 2, loader FROM loaders WHERE loader != 'mrpack'; +INSERT INTO loader_fields (field, field_type, enum_type, optional, min_val) VALUES('mrpack_loaders', 'array_enum', 3, false, 0); +INSERT INTO loader_fields_loaders (loader_id, loader_field_id) +SELECT l.id, lf.id FROM loaders l CROSS JOIN loader_fields lf WHERE lf.field = 'mrpack_loaders' AND l.loader = 'mrpack'; + +INSERT INTO version_fields(version_id, field_id, enum_value) +SELECT v.id, lf.id, lfev.id +FROM versions v +INNER JOIN mods m ON v.mod_id = m.id +INNER JOIN loaders_versions lv ON v.id = lv.version_id +INNER JOIN loaders l ON lv.loader_id = l.id +CROSS JOIN loader_fields lf +LEFT JOIN loader_field_enum_values lfev ON lf.enum_type = lfev.enum_id +WHERE m.project_type = (SELECT id FROM project_types WHERE name = 'modpack') AND lf.field = 'mrpack_loaders'; + +INSERT INTO loaders_project_types (joining_loader_id, joining_project_type_id) SELECT DISTINCT l.id, pt.id FROM loaders l CROSS JOIN project_types pt WHERE pt.name = 'modpack' AND l.loader = 'mrpack'; + +--- Non-mrpack loaders no longer support modpacks +DELETE FROM loaders_project_types WHERE joining_loader_id != (SELECT id FROM loaders WHERE loader = 'mrpack') AND joining_project_type_id = (SELECT id FROM project_types WHERE name = 'modpack'); + +CREATE TABLE loaders_project_types_games ( + loader_id integer REFERENCES loaders NOT NULL, + project_type_id integer REFERENCES project_types NOT NULL, + game_id integer REFERENCES games NOT NULL, + PRIMARY KEY (loader_id, project_type_id, game_id) +); + +-- all past loader_project_types are minecraft-java as the only game before this migration is minecraft-java +INSERT INTO loaders_project_types_games (loader_id, project_type_id, game_id) SELECT joining_loader_id, joining_project_type_id, 1 FROM loaders_project_types; + +-- Now that loaders are inferred, we can drop the project_type column from mods +ALTER TABLE mods DROP COLUMN project_type; + + -- Drop original_id columns ALTER TABLE loader_field_enum_values DROP COLUMN original_id; \ No newline at end of file diff --git a/src/database/models/loader_fields.rs b/src/database/models/loader_fields.rs index c755d1c1..308ae691 100644 --- a/src/database/models/loader_fields.rs +++ b/src/database/models/loader_fields.rs @@ -650,14 +650,14 @@ impl VersionField { } let query_loader_fields: Vec = loader_fields - .and_then(|x| serde_json::from_value(x).unwrap()) + .and_then(|x| serde_json::from_value(x).ok()) .unwrap_or_default(); let query_version_field_combined: Vec = version_fields - .and_then(|x| serde_json::from_value(x).unwrap()) + .and_then(|x| serde_json::from_value(x).ok()) .unwrap_or_default(); let query_loader_field_enum_values: Vec = loader_field_enum_values - .and_then(|x| serde_json::from_value(x).unwrap()) + .and_then(|x| serde_json::from_value(x).ok()) .unwrap_or_default(); let version_id = VersionId(version_id); query_loader_fields @@ -918,9 +918,9 @@ impl VersionFieldValue { } } - // For conversion to an interanl string, such as for search facets or filtering + // For conversion to an interanl string(s), such as for search facets, filtering, or direct hardcoding // No matter the type, it will be converted to a Vec, whre the non-array types will have a single element - pub fn as_search_strings(&self) -> Vec { + pub fn as_strings(&self) -> Vec { match self { VersionFieldValue::Integer(i) => vec![i.to_string()], VersionFieldValue::Text(s) => vec![s.clone()], diff --git a/src/models/v2/projects.rs b/src/models/v2/projects.rs index cb8d436e..b5d9f967 100644 --- a/src/models/v2/projects.rs +++ b/src/models/v2/projects.rs @@ -66,15 +66,19 @@ pub struct LegacyProject { impl LegacyProject { // Convert from a standard V3 project to a V2 project // Requires any queried versions to be passed in, to get access to certain version fields contained within. - // It's safe to use a db version_item for this as the only info is side types and game versions, which used to be public on project anyway. + // - This can be any version, because the fields are ones that used to be on the project itself. + // - Its conceivable that certain V3 projects that have many different ones may not have the same fields on all of them. + // TODO: Should this return an error instead for v2 users? + // It's safe to use a db version_item for this as the only info is side types, game versions, and loader fields (for loaders), which used to be public on project anyway. pub fn from(data: Project, versions_item: Option) -> Self { let mut client_side = LegacySideType::Unknown; let mut server_side = LegacySideType::Unknown; let mut game_versions = Vec::new(); - // TODO: extract modpack changes - // - if loader is mrpack, this is a modpack - // the loaders are whatever the corresponding cateogires are + // V2 versions only have one project type- v3 versions can rarely have multiple. + // We'll just use the first one. + let mut project_type = data.project_types.get(0).cloned().unwrap_or_default(); + let mut loaders = data.loaders; if let Some(versions_item) = versions_item { client_side = versions_item @@ -104,11 +108,20 @@ impl LegacyProject { .and_then(|f| MinecraftGameVersion::try_from_version_field(f).ok()) .map(|v| v.into_iter().map(|v| v.version).collect()) .unwrap_or(Vec::new()); - } - // V2 projects only have one project type- v3 ones can rarely have multiple. - // We'll just use the first one. - let project_type = data.project_types.get(0).cloned().unwrap_or_default(); + // - if loader is mrpack, this is a modpack + // the loaders are whatever the corresponding loader fields are + if versions_item.loaders == vec!["mrpack".to_string()] { + project_type = "modpack".to_string(); + if let Some(mrpack_loaders) = versions_item + .version_fields + .iter() + .find(|f| f.field_name == "mrpack_loaders") + { + loaders = mrpack_loaders.value.as_strings(); + } + } + } Self { id: data.id, @@ -132,7 +145,7 @@ impl LegacyProject { followers: data.followers, categories: data.categories, additional_categories: data.additional_categories, - loaders: data.loaders, + loaders, versions: data.versions, icon_url: data.icon_url, issues_url: data.issues_url, @@ -251,6 +264,22 @@ impl From for LegacyVersion { } } + // - if loader is mrpack, this is a modpack + // the v2 loaders are whatever the corresponding loader fields are + let mut loaders = data.loaders.into_iter().map(|l| l.0).collect::>(); + if loaders == vec!["mrpack".to_string()] { + if let Some((_, mrpack_loaders)) = data + .fields + .into_iter() + .find(|(key, _)| key == "mrpack_loaders") + { + if let Ok(mrpack_loaders) = serde_json::from_value(mrpack_loaders) { + loaders = mrpack_loaders; + } + } + } + let loaders = loaders.into_iter().map(Loader).collect::>(); + Self { id: data.id, project_id: data.project_id, @@ -268,7 +297,7 @@ impl From for LegacyVersion { files: data.files, dependencies: data.dependencies, game_versions, - loaders: data.loaders, + loaders, } } } diff --git a/src/routes/v2/project_creation.rs b/src/routes/v2/project_creation.rs index 1d628eee..d60921b0 100644 --- a/src/routes/v2/project_creation.rs +++ b/src/routes/v2/project_creation.rs @@ -12,7 +12,6 @@ use crate::routes::{v2_reroute, v3}; use actix_multipart::Multipart; use actix_web::web::Data; use actix_web::{post, HttpRequest, HttpResponse}; -use itertools::Itertools; use serde::{Deserialize, Serialize}; use serde_json::json; use sqlx::postgres::PgPool; @@ -153,9 +152,6 @@ pub async fn project_create( let server_side = legacy_create.server_side; let project_type = legacy_create.project_type; - // Modpacks now use the "mrpack" loader, and loaders are converted to categories. - // Setting of 'project_type' directly is removed, it's loader-based now. - let mut additional_categories = legacy_create.additional_categories; let initial_versions = legacy_create .initial_versions @@ -166,8 +162,10 @@ pub async fn project_create( fields.insert("server_side".to_string(), json!(server_side)); fields.insert("game_versions".to_string(), json!(v.game_versions)); + // Modpacks now use the "mrpack" loader, and loaders are converted to loader fields. + // Setting of 'project_type' directly is removed, it's loader-based now. if project_type == "modpack" { - additional_categories.extend(v.loaders.iter().map(|l| l.0.clone())); + fields.insert("mrpack_loaders".to_string(), json!(v.loaders.clone())); } let loaders = if project_type == "modpack" { @@ -195,11 +193,6 @@ pub async fn project_create( }) .collect(); - let additional_categories = additional_categories - .into_iter() - .unique() - .collect::>(); - println!("additional_categories: {:?}", additional_categories); Ok(v3::project_creation::ProjectCreateData { title: legacy_create.title, slug: legacy_create.slug, @@ -207,7 +200,7 @@ pub async fn project_create( body: legacy_create.body, initial_versions, categories: legacy_create.categories, - additional_categories, + additional_categories: legacy_create.additional_categories, issues_url: legacy_create.issues_url, source_url: legacy_create.source_url, wiki_url: legacy_create.wiki_url, @@ -236,14 +229,9 @@ pub async fn project_create( ) .await?; - println!("did a little test <3"); // Convert response to V2 format match v2_reroute::extract_ok_json::(response).await { Ok(project) => { - println!( - "Just finished doing a project create, looking at repsonse: {:?}", - serde_json::to_string(&project).unwrap() - ); let version_item = match project.versions.first() { Some(vid) => version_item::Version::get((*vid).into(), &**client, &redis).await?, None => None, diff --git a/src/routes/v2/version_creation.rs b/src/routes/v2/version_creation.rs index 1323ccb2..117fe6d0 100644 --- a/src/routes/v2/version_creation.rs +++ b/src/routes/v2/version_creation.rs @@ -99,7 +99,7 @@ pub async fn version_create( // Ideally this would, if the project 'should' be a modpack: // - change the loaders to mrpack only - // - add categories to the project for the corresponding loaders + // - add loader fields to the project for the corresponding loaders Ok(v3::version_creation::InitialVersionData { project_id: legacy_create.project_id, diff --git a/src/routes/v2_reroute.rs b/src/routes/v2_reroute.rs index 48ef7aee..7e2c16cf 100644 --- a/src/routes/v2_reroute.rs +++ b/src/routes/v2_reroute.rs @@ -102,7 +102,7 @@ where headers.insert(key, value); } Err(err) => { - panic!("Error inserting test header: {:?}.", err); + CreateError::InvalidInput(format!("Error inserting test header: {:?}.", err)); } }; diff --git a/src/routes/v3/analytics_get.rs b/src/routes/v3/analytics_get.rs index 5b971318..cc0529c5 100644 --- a/src/routes/v3/analytics_get.rs +++ b/src/routes/v3/analytics_get.rs @@ -340,7 +340,7 @@ pub async fn revenue_get( let duration: PgInterval = Duration::minutes(resolution_minutes as i64) .try_into() - .unwrap(); + .map_err(|_| ApiError::InvalidInput("Invalid resolution_minutes".to_string()))?; // Get the revenue data let payouts_values = sqlx::query!( " diff --git a/src/routes/v3/organizations.rs b/src/routes/v3/organizations.rs index 64eb1f74..a61e33b4 100644 --- a/src/routes/v3/organizations.rs +++ b/src/routes/v3/organizations.rs @@ -479,7 +479,6 @@ pub async fn organization_delete( redis: web::Data, session_queue: web::Data, ) -> Result { - println!("DELETE ORGANIZATION"); let user = get_user_from_headers( &req, &**pool, @@ -490,7 +489,6 @@ pub async fn organization_delete( .await? .1; let string = info.into_inner().0; - println!("string: {}", string); let organization = database::models::Organization::get(&string, &**pool, &redis) .await? @@ -498,7 +496,6 @@ pub async fn organization_delete( ApiError::InvalidInput("The specified organization does not exist!".to_string()) })?; - println!("organization: {:?}", organization); if !user.role.is_admin() { let team_member = database::models::TeamMember::get_from_user_id_organization( organization.id, diff --git a/src/routes/v3/projects.rs b/src/routes/v3/projects.rs index 1cc40a19..d35182aa 100644 --- a/src/routes/v3/projects.rs +++ b/src/routes/v3/projects.rs @@ -274,7 +274,6 @@ pub async fn project_edit( redis: web::Data, session_queue: web::Data, ) -> Result { - println!("project_edit"); let user = get_user_from_headers( &req, &**pool, @@ -284,17 +283,13 @@ pub async fn project_edit( ) .await? .1; - println!("serde user {}", serde_json::to_string(&user)?); new_project .validate() .map_err(|err| ApiError::Validation(validation_errors_to_string(err, None)))?; - println!("new project {}", serde_json::to_string(&new_project)?); let string = info.into_inner().0; - println!("string {}", string); let result = db_models::Project::get(&string, &**pool, &redis).await?; - println!("result {}", serde_json::to_string(&result)?); if let Some(project_item) = result { let id = project_item.inner.id; diff --git a/src/routes/v3/users.rs b/src/routes/v3/users.rs index 7e9f3a32..96b666dd 100644 --- a/src/routes/v3/users.rs +++ b/src/routes/v3/users.rs @@ -676,10 +676,6 @@ pub async fn user_notifications( .collect(); notifications.sort_by(|a, b| b.created.cmp(&a.created)); - println!( - "notifications: {:?}", - serde_json::to_string(¬ifications).unwrap() - ); Ok(HttpResponse::Ok().json(notifications)) } else { Ok(HttpResponse::NotFound().body("")) diff --git a/src/search/indexing/local_import.rs b/src/search/indexing/local_import.rs index 49089848..3b3c80f8 100644 --- a/src/search/indexing/local_import.rs +++ b/src/search/indexing/local_import.rs @@ -101,7 +101,7 @@ pub async fn index_local( let version_fields = VersionField::from_query_json(m.id, m.loader_fields, m.version_fields, m.loader_field_enum_values); let loader_fields : HashMap> = version_fields.into_iter().map(|vf| { - (vf.field_name, vf.value.as_search_strings()) + (vf.field_name, vf.value.as_strings()) }).collect(); for v in loader_fields.keys().cloned() { @@ -121,6 +121,15 @@ pub async fn index_local( _ => false, }; + // SPECIAL BEHAVIOUR + // Todo: revisit. + // For consistency with v2 searching, we consider the loader field 'mrpack_loaders' to be a category. + // These were previously considered the loader, and in v2, the loader is a category for searching. + // So to avoid breakage or awkward conversions, we just consider those loader_fields to be categories. + // The loaders are kept in loader_fields as well, so that no information is lost on retrieval. + let mrpack_loaders = loader_fields.get("mrpack_loaders").cloned().unwrap_or_default(); + categories.extend(mrpack_loaders); + UploadSearchProject { version_id: version_id.to_string(), project_id: project_id.to_string(), diff --git a/tests/common/api_v2/project.rs b/tests/common/api_v2/project.rs index acec20fd..0ac2c420 100644 --- a/tests/common/api_v2/project.rs +++ b/tests/common/api_v2/project.rs @@ -34,8 +34,6 @@ impl ApiV2 { let resp = self.call(req).await; assert_status(&resp, StatusCode::OK); - println!("Added body: {:?}", resp.response().body()); - // Approve as a moderator. let req = TestRequest::patch() .uri(&format!("/v2/project/{}", creation_data.slug)) diff --git a/tests/files/dummy_data.sql b/tests/files/dummy_data.sql index 6ab48457..1a26659e 100644 --- a/tests/files/dummy_data.sql +++ b/tests/files/dummy_data.sql @@ -25,8 +25,9 @@ INSERT INTO loaders_project_types (joining_loader_id, joining_project_type_id) V INSERT INTO loaders (id, loader) VALUES (6, 'forge'); INSERT INTO loaders_project_types (joining_loader_id, joining_project_type_id) VALUES (6,1); -INSERT INTO categories (category, project_type) SELECT 'forge', id FROM project_types WHERE name = 'modpack'; -INSERT INTO categories (category, project_type) SELECT 'fabric', id FROM project_types WHERE name = 'modpack'; +-- Adds dummies to mrpack_loaders +INSERT INTO loader_field_enum_values (enum_id, value) SELECT id, 'fabric' FROM loader_field_enums WHERE enum_name = 'mrpack_loaders'; +INSERT INTO loader_field_enum_values (enum_id, value) SELECT id, 'forge' FROM loader_field_enums WHERE enum_name = 'mrpack_loaders'; INSERT INTO loaders_project_types_games (loader_id, project_type_id, game_id) SELECT joining_loader_id, joining_project_type_id, 1 FROM loaders_project_types WHERE joining_loader_id = 5; INSERT INTO loaders_project_types_games (loader_id, project_type_id, game_id) SELECT joining_loader_id, joining_project_type_id, 1 FROM loaders_project_types WHERE joining_loader_id = 6; @@ -47,7 +48,6 @@ VALUES (2, '1.20.5', '{"type":"release","major":true}'); INSERT INTO loader_fields_loaders(loader_id, loader_field_id) SELECT l.id, lf.id FROM loaders l CROSS JOIN loader_fields lf WHERE lf.field = 'game_versions' OR lf.field = 'client_side' OR lf.field = 'server_side'; - INSERT INTO categories (id, category, project_type) VALUES (51, 'combat', 1), (52, 'decoration', 1), diff --git a/tests/project.rs b/tests/project.rs index b0982504..5bdf5890 100644 --- a/tests/project.rs +++ b/tests/project.rs @@ -5,15 +5,16 @@ use chrono::{Duration, Utc}; use common::environment::{with_test_environment, TestEnvironment}; use common::permissions::{PermissionsTest, PermissionsTestContext}; use futures::StreamExt; +use itertools::Itertools; use labrinth::database::models::project_item::{PROJECTS_NAMESPACE, PROJECTS_SLUGS_NAMESPACE}; use labrinth::models::ids::base62_impl::parse_base62; use labrinth::models::teams::ProjectPermissions; use labrinth::util::actix::{AppendsMultipart, MultipartSegment, MultipartSegmentData}; use serde_json::json; -use crate::common::database::*; +use crate::common::{database::*, request_data}; -use crate::common::dummy_data::DUMMY_CATEGORIES; +use crate::common::dummy_data::{TestFile, DUMMY_CATEGORIES}; // importing common module. mod common; @@ -278,6 +279,55 @@ async fn test_add_remove_project() { test_env.cleanup().await; } +#[actix_rt::test] +async fn test_project_type_sanity() { + let test_env = TestEnvironment::build(None).await; + let api = &test_env.v2; + + // Perform all other patch tests on both 'mod' and 'modpack' + let test_creation_mod = request_data::get_public_project_creation_data( + "test-mod", + Some(TestFile::build_random_jar()), + ); + let test_creation_modpack = request_data::get_public_project_creation_data( + "test-modpack", + Some(TestFile::build_random_mrpack()), + ); + for (mod_or_modpack, test_creation_data) in [ + ("mod", test_creation_mod), + ("modpack", test_creation_modpack), + ] { + let (test_project, test_version) = api + .add_public_project(test_creation_data, USER_USER_PAT) + .await; + let test_project_slug = test_project.slug.as_ref().unwrap(); + + assert_eq!(test_project.project_type, mod_or_modpack); + assert_eq!(test_project.loaders, vec!["fabric"]); + assert_eq!( + test_version[0].loaders.iter().map(|x| &x.0).collect_vec(), + vec!["fabric"] + ); + + let project = api + .get_project_deserialized(test_project_slug, USER_USER_PAT) + .await; + assert_eq!(test_project.loaders, vec!["fabric"]); + assert_eq!(project.project_type, mod_or_modpack); + + let version = api + .get_version_deserialized(&test_version[0].id.to_string(), USER_USER_PAT) + .await; + assert_eq!( + version.loaders.iter().map(|x| &x.0).collect_vec(), + vec!["fabric"] + ); + } + + // TODO: as we get more complicated strucures with v3 testing, and alpha/beta get more complicated, we should add more tests here, + // to ensure that projects created with v3 routes are still valid and work with v2 routes. +} + #[actix_rt::test] pub async fn test_patch_project() { let test_env = TestEnvironment::build(None).await; @@ -958,7 +1008,6 @@ async fn permissions_manage_invites() { #[actix_rt::test] async fn permissions_delete_project() { - println!("doing:"); // Add member, remove member, edit member let test_env = TestEnvironment::build(None).await; diff --git a/tests/search.rs b/tests/search.rs index 61d6bb5b..9e87ee18 100644 --- a/tests/search.rs +++ b/tests/search.rs @@ -234,7 +234,6 @@ async fn search_projects() { (json!([[r#"title:'Mysterious Project'"#]]), vec![2, 3]), (json!([["author:user"]]), vec![0, 1, 2, 4, 5, 7]), (json!([["versions:1.20.5"]]), vec![4, 5]), - // text search // bug fix ( json!([ @@ -245,6 +244,21 @@ async fn search_projects() { ]), vec![], ), + // Project type change + // Modpack should still be able to search based on former loader, even though technically the loader is 'mrpack' + (json!([["categories:mrpack"]]), vec![4]), + ( + json!([["categories:mrpack"], ["categories:fabric"]]), + vec![4], + ), + ( + json!([ + ["categories:mrpack"], + ["categories:fabric"], + ["project_type:modpack"] + ]), + vec![4], + ), ]; // TODO: versions, game versions // Untested: @@ -274,10 +288,6 @@ async fn search_projects() { .collect(); expected_project_ids.sort(); found_project_ids.sort(); - println!( - "facets: {:?}, expected: {:?}, found: {:?}", - facets, expected_project_ids, found_project_ids - ); assert_eq!(found_project_ids, expected_project_ids); } }) diff --git a/tests/tags.rs b/tests/tags.rs index 51f408ca..5563b635 100644 --- a/tests/tags.rs +++ b/tests/tags.rs @@ -57,9 +57,7 @@ async fn get_tags() { "optimization", "decoration", "mobs", - "magic", - "fabric", - "forge" + "magic" ] .iter() .map(|s| s.to_string())