1
0

Expose test utils to Labrinth dependents (#4703)

* Expose test utils to Labrinth dependents

* Feature gate `labrinth::test`

* Unify db migrators

* Expose `NotificationBuilder::insert_many_deliveries`

* Add logging utils to common crate

* Remove unused console-subscriber layer

* fix CI
This commit is contained in:
aecsocket
2025-11-08 12:26:24 -08:00
committed by GitHub
parent 1efdceacfd
commit f8a5a77daa
45 changed files with 378 additions and 567 deletions

View File

@@ -12,6 +12,7 @@ path = "src/main.rs"
[dependencies]
actix-cors = { workspace = true }
actix-files = { workspace = true }
actix-http = { workspace = true, optional = true }
actix-multipart = { workspace = true }
actix-rt = { workspace = true }
actix-web = { workspace = true }
@@ -36,7 +37,6 @@ clap = { workspace = true, features = ["derive"] }
clickhouse = { workspace = true, features = ["time", "uuid"] }
color-eyre = { workspace = true }
color-thief = { workspace = true }
console-subscriber = { workspace = true }
const_format = { workspace = true }
dashmap = { workspace = true }
deadpool-redis.workspace = true
@@ -71,6 +71,7 @@ json-patch = { workspace = true }
lettre = { workspace = true }
meilisearch-sdk = { workspace = true, features = ["reqwest"] }
modrinth-maxmind = { workspace = true }
modrinth-util = { workspace = true }
muralpay = { workspace = true, features = ["utoipa"] }
murmur2 = { workspace = true }
paste = { workspace = true }
@@ -119,8 +120,6 @@ tokio-stream = { workspace = true }
totp-rs = { workspace = true, features = ["gen_secret"] }
tracing = { workspace = true }
tracing-actix-web = { workspace = true }
tracing-ecs = { workspace = true }
tracing-subscriber = { workspace = true }
url = { workspace = true }
urlencoding = { workspace = true }
utoipa = { workspace = true }
@@ -135,7 +134,7 @@ zip = { workspace = true }
zxcvbn = { workspace = true }
[dev-dependencies]
actix-http = { workspace = true }
labrinth = { path = ".", features = ["test"] }
[build-dependencies]
chrono = { workspace = true }
@@ -150,5 +149,8 @@ tikv-jemallocator = { workspace = true, features = [
"unprefixed_malloc_on_supported_platforms",
] }
[features]
test = ["dep:actix-http"]
[lints]
workspace = true

View File

@@ -160,7 +160,7 @@ impl NotificationBuilder {
Ok(())
}
async fn insert_many_deliveries(
pub async fn insert_many_deliveries(
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
redis: &RedisPool,
notification_ids: &[i64],

View File

@@ -37,10 +37,12 @@ pub mod routes;
pub mod scheduler;
pub mod search;
pub mod sync;
pub mod test;
pub mod util;
pub mod validate;
#[cfg(feature = "test")]
pub mod test;
#[derive(Clone)]
pub struct Pepper {
pub pepper: String,

View File

@@ -17,15 +17,9 @@ use labrinth::util::ratelimit::rate_limit_middleware;
use labrinth::utoipa_app_config;
use labrinth::{check_env_vars, clickhouse, database, file_hosting};
use std::ffi::CStr;
use std::str::FromStr;
use std::sync::Arc;
use tracing::level_filters::LevelFilter;
use tracing::{Instrument, error, info, info_span};
use tracing_actix_web::TracingLogger;
use tracing_ecs::ECSLayerBuilder;
use tracing_subscriber::EnvFilter;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use utoipa::OpenApi;
use utoipa_actix_web::AppExt;
use utoipa_swagger_ui::SwaggerUi;
@@ -59,59 +53,13 @@ struct Args {
run_background_task: Option<BackgroundTask>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
enum OutputFormat {
#[default]
Human,
Json,
}
impl FromStr for OutputFormat {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"human" => Ok(Self::Human),
"json" => Ok(Self::Json),
_ => Err(()),
}
}
}
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
let args = Args::parse();
color_eyre::install().expect("failed to install `color-eyre`");
dotenvy::dotenv().ok();
let console_layer = console_subscriber::spawn();
let env_filter = EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.from_env_lossy();
let output_format =
dotenvy::var("LABRINTH_FORMAT").map_or(OutputFormat::Human, |format| {
format
.parse::<OutputFormat>()
.unwrap_or_else(|_| panic!("invalid output format '{format}'"))
});
match output_format {
OutputFormat::Human => {
tracing_subscriber::registry()
.with(console_layer)
.with(env_filter)
.with(tracing_subscriber::fmt::layer())
.init();
}
OutputFormat::Json => {
tracing_subscriber::registry()
.with(console_layer)
.with(env_filter)
.with(ECSLayerBuilder::default().stdout())
.init();
}
}
modrinth_util::log::init().expect("failed to initialize logging");
if check_env_vars() {
error!("Some environment variables are missing!");

View File

@@ -1,13 +1,13 @@
use std::collections::HashMap;
use crate::common::{api_v2::ApiV2, api_v3::ApiV3, dummy_data::TestFile};
use actix_web::dev::ServiceResponse;
use async_trait::async_trait;
use labrinth::models::ids::ProjectId;
use labrinth::models::{
use crate::models::ids::ProjectId;
use crate::models::{
projects::VersionType,
teams::{OrganizationPermissions, ProjectPermissions},
};
use crate::test::{api_v2::ApiV2, api_v3::ApiV3, dummy_data::TestFile};
use actix_web::dev::ServiceResponse;
use async_trait::async_trait;
use super::{
Api, ApiProject, ApiTags, ApiTeams, ApiUser, ApiVersion,
@@ -81,7 +81,7 @@ delegate_api_variant!(
[add_gallery_item, ServiceResponse, id_or_slug: &str, image: ImageData, featured: bool, title: Option<String>, description: Option<String>, ordering: Option<i32>, pat: Option<&str>],
[remove_gallery_item, ServiceResponse, id_or_slug: &str, image_url: &str, pat: Option<&str>],
[edit_gallery_item, ServiceResponse, id_or_slug: &str, image_url: &str, patch: HashMap<String, String>, pat: Option<&str>],
[create_report, ServiceResponse, report_type: &str, id: &str, item_type: crate::common::api_common::models::CommonItemType, body: &str, pat: Option<&str>],
[create_report, ServiceResponse, report_type: &str, id: &str, item_type: crate::test::api_common::models::CommonItemType, body: &str, pat: Option<&str>],
[get_report, ServiceResponse, id: &str, pat: Option<&str>],
[get_reports, ServiceResponse, ids: &[&str], pat: Option<&str>],
[get_user_reports, ServiceResponse, pat: Option<&str>],
@@ -100,9 +100,9 @@ delegate_api_variant!(
#[async_trait(?Send)]
impl ApiTags for GenericApi {
[get_loaders, ServiceResponse,],
[get_loaders_deserialized_common, Vec<crate::common::api_common::models::CommonLoaderData>,],
[get_loaders_deserialized_common, Vec<crate::test::api_common::models::CommonLoaderData>,],
[get_categories, ServiceResponse,],
[get_categories_deserialized_common, Vec<crate::common::api_common::models::CommonCategoryData>,],
[get_categories_deserialized_common, Vec<crate::test::api_common::models::CommonCategoryData>,],
}
);
@@ -110,18 +110,18 @@ delegate_api_variant!(
#[async_trait(?Send)]
impl ApiTeams for GenericApi {
[get_team_members, ServiceResponse, team_id: &str, pat: Option<&str>],
[get_team_members_deserialized_common, Vec<crate::common::api_common::models::CommonTeamMember>, team_id: &str, pat: Option<&str>],
[get_team_members_deserialized_common, Vec<crate::test::api_common::models::CommonTeamMember>, team_id: &str, pat: Option<&str>],
[get_teams_members, ServiceResponse, ids: &[&str], pat: Option<&str>],
[get_project_members, ServiceResponse, id_or_slug: &str, pat: Option<&str>],
[get_project_members_deserialized_common, Vec<crate::common::api_common::models::CommonTeamMember>, id_or_slug: &str, pat: Option<&str>],
[get_project_members_deserialized_common, Vec<crate::test::api_common::models::CommonTeamMember>, id_or_slug: &str, pat: Option<&str>],
[get_organization_members, ServiceResponse, id_or_title: &str, pat: Option<&str>],
[get_organization_members_deserialized_common, Vec<crate::common::api_common::models::CommonTeamMember>, id_or_title: &str, pat: Option<&str>],
[get_organization_members_deserialized_common, Vec<crate::test::api_common::models::CommonTeamMember>, id_or_title: &str, pat: Option<&str>],
[join_team, ServiceResponse, team_id: &str, pat: Option<&str>],
[remove_from_team, ServiceResponse, team_id: &str, user_id: &str, pat: Option<&str>],
[edit_team_member, ServiceResponse, team_id: &str, user_id: &str, patch: serde_json::Value, pat: Option<&str>],
[transfer_team_ownership, ServiceResponse, team_id: &str, user_id: &str, pat: Option<&str>],
[get_user_notifications, ServiceResponse, user_id: &str, pat: Option<&str>],
[get_user_notifications_deserialized_common, Vec<crate::common::api_common::models::CommonNotification>, user_id: &str, pat: Option<&str>],
[get_user_notifications_deserialized_common, Vec<crate::test::api_common::models::CommonNotification>, user_id: &str, pat: Option<&str>],
[get_notification, ServiceResponse, notification_id: &str, pat: Option<&str>],
[get_notifications, ServiceResponse, ids: &[&str], pat: Option<&str>],
[mark_notification_read, ServiceResponse, notification_id: &str, pat: Option<&str>],

View File

@@ -6,16 +6,16 @@ use self::models::{
};
use self::request_data::{ImageData, ProjectCreationRequestData};
use super::dummy_data::TestFile;
use actix_web::dev::ServiceResponse;
use async_trait::async_trait;
use labrinth::models::ids::ProjectId;
use labrinth::{
use crate::models::ids::ProjectId;
use crate::{
LabrinthConfig,
models::{
projects::VersionType,
teams::{OrganizationPermissions, ProjectPermissions},
},
};
use actix_web::dev::ServiceResponse;
use async_trait::async_trait;
pub mod generic;
pub mod models;

View File

@@ -1,10 +1,8 @@
use ariadne::ids::UserId;
use chrono::{DateTime, Utc};
use labrinth::models::ids::{
use crate::models::ids::{
ImageId, NotificationId, OrganizationId, ProjectId, ReportId, TeamId,
ThreadId, ThreadMessageId, VersionId,
};
use labrinth::{
use crate::{
auth::AuthProvider,
models::{
projects::{
@@ -16,6 +14,8 @@ use labrinth::{
users::{Badges, Role, User, UserPayoutData},
},
};
use ariadne::ids::UserId;
use chrono::{DateTime, Utc};
use rust_decimal::Decimal;
use serde::Deserialize;
// Fields shared by every version of the API.

View File

@@ -1,9 +1,9 @@
// The structures for project/version creation.
// These are created differently, but are essentially the same between versions.
use labrinth::util::actix::MultipartSegment;
use crate::util::actix::MultipartSegment;
use crate::common::dummy_data::TestFile;
use crate::test::dummy_data::TestFile;
pub struct ProjectCreationRequestData {
pub slug: String,

View File

@@ -2,9 +2,9 @@ use super::{
api_common::{Api, ApiBuildable},
environment::LocalService,
};
use crate::LabrinthConfig;
use actix_web::{App, dev::ServiceResponse, test};
use async_trait::async_trait;
use labrinth::LabrinthConfig;
use std::rc::Rc;
use utoipa_actix_web::AppExt;
@@ -26,12 +26,10 @@ impl ApiBuildable for ApiV2 {
let app = App::new()
.into_utoipa_app()
.configure(|cfg| {
labrinth::utoipa_app_config(cfg, labrinth_config.clone())
crate::utoipa_app_config(cfg, labrinth_config.clone())
})
.into_app()
.configure(|cfg| {
labrinth::app_config(cfg, labrinth_config.clone())
});
.configure(|cfg| crate::app_config(cfg, labrinth_config.clone()));
let test_app: Rc<dyn LocalService> =
Rc::new(test::init_service(app).await);

View File

@@ -1,15 +1,17 @@
use std::{collections::HashMap, fmt::Write};
use crate::{
assert_status,
common::{
api_common::{
Api, ApiProject, AppendsOptionalPat,
models::{CommonItemType, CommonProject, CommonVersion},
request_data::{ImageData, ProjectCreationRequestData},
},
dummy_data::TestFile,
use crate::test::asserts::assert_status;
use crate::test::{
api_common::{
Api, ApiProject, AppendsOptionalPat,
models::{CommonItemType, CommonProject, CommonVersion},
request_data::{ImageData, ProjectCreationRequestData},
},
dummy_data::TestFile,
};
use crate::{
models::v2::{projects::LegacyProject, search::LegacySearchResults},
util::actix::AppendsMultipart,
};
use actix_http::StatusCode;
use actix_web::{
@@ -18,13 +20,9 @@ use actix_web::{
};
use async_trait::async_trait;
use bytes::Bytes;
use labrinth::{
models::v2::{projects::LegacyProject, search::LegacySearchResults},
util::actix::AppendsMultipart,
};
use serde_json::json;
use crate::common::database::MOD_USER_PAT;
use crate::test::database::MOD_USER_PAT;
use super::{
ApiV2,

View File

@@ -1,13 +1,13 @@
use serde_json::json;
use crate::common::{
use crate::models::ids::ProjectId;
use crate::test::{
api_common::request_data::{
ProjectCreationRequestData, VersionCreationRequestData,
},
dummy_data::TestFile,
};
use labrinth::models::ids::ProjectId;
use labrinth::util::actix::{MultipartSegment, MultipartSegmentData};
use crate::util::actix::{MultipartSegment, MultipartSegmentData};
pub fn get_public_project_creation_data(
slug: &str,

View File

@@ -1,22 +1,20 @@
use crate::routes::v2::tags::{
CategoryData, DonationPlatformQueryData, GameVersionQueryData, LoaderData,
};
use actix_http::StatusCode;
use actix_web::{
dev::ServiceResponse,
test::{self, TestRequest},
};
use async_trait::async_trait;
use labrinth::routes::v2::tags::{
CategoryData, DonationPlatformQueryData, GameVersionQueryData, LoaderData,
};
use crate::{
assert_status,
common::{
api_common::{
Api, ApiTags, AppendsOptionalPat,
models::{CommonCategoryData, CommonLoaderData},
},
database::ADMIN_USER_PAT,
use crate::test::asserts::assert_status;
use crate::test::{
api_common::{
Api, ApiTags, AppendsOptionalPat,
models::{CommonCategoryData, CommonLoaderData},
},
database::ADMIN_USER_PAT,
};
use super::ApiV2;

View File

@@ -1,19 +1,17 @@
use actix_http::StatusCode;
use actix_web::{dev::ServiceResponse, test};
use async_trait::async_trait;
use labrinth::models::{
use crate::models::{
teams::{OrganizationPermissions, ProjectPermissions},
v2::{notifications::LegacyNotification, teams::LegacyTeamMember},
};
use actix_http::StatusCode;
use actix_web::{dev::ServiceResponse, test};
use async_trait::async_trait;
use serde_json::json;
use crate::{
assert_status,
common::api_common::{
Api, ApiTeams, AppendsOptionalPat,
models::{CommonNotification, CommonTeamMember},
},
use crate::test::api_common::{
Api, ApiTeams, AppendsOptionalPat,
models::{CommonNotification, CommonTeamMember},
};
use crate::test::asserts::assert_status;
use super::ApiV2;

View File

@@ -1,5 +1,5 @@
use super::ApiV2;
use crate::common::api_common::{Api, ApiUser, AppendsOptionalPat};
use crate::test::api_common::{Api, ApiUser, AppendsOptionalPat};
use actix_web::{dev::ServiceResponse, test};
use async_trait::async_trait;

View File

@@ -5,14 +5,16 @@ use super::{
ApiV2,
request_data::{self, get_public_version_creation_data},
};
use crate::models::ids::ProjectId;
use crate::test::asserts::assert_status;
use crate::test::{
api_common::{Api, ApiVersion, AppendsOptionalPat, models::CommonVersion},
dummy_data::TestFile,
};
use crate::{
assert_status,
common::{
api_common::{
Api, ApiVersion, AppendsOptionalPat, models::CommonVersion,
},
dummy_data::TestFile,
},
models::{projects::VersionType, v2::projects::LegacyVersion},
routes::v2::version_file::FileUpdateData,
util::actix::AppendsMultipart,
};
use actix_http::StatusCode;
use actix_web::{
@@ -20,12 +22,6 @@ use actix_web::{
test::{self, TestRequest},
};
use async_trait::async_trait;
use labrinth::models::ids::ProjectId;
use labrinth::{
models::{projects::VersionType, v2::projects::LegacyVersion},
routes::v2::version_file::FileUpdateData,
util::actix::AppendsMultipart,
};
use serde_json::json;
pub fn url_encode_json_serialized_vec(elements: &[String]) -> String {

View File

@@ -1,16 +1,16 @@
use crate::models::{collections::Collection, v3::projects::Project};
use actix_http::StatusCode;
use actix_web::{
dev::ServiceResponse,
test::{self, TestRequest},
};
use bytes::Bytes;
use labrinth::models::{collections::Collection, v3::projects::Project};
use serde_json::json;
use crate::{
assert_status,
common::api_common::{Api, AppendsOptionalPat, request_data::ImageData},
use crate::test::api_common::{
Api, AppendsOptionalPat, request_data::ImageData,
};
use crate::test::asserts::assert_status;
use super::ApiV3;

View File

@@ -1,13 +1,11 @@
use crate::models::v3::user_limits::UserLimits;
use actix_http::StatusCode;
use actix_web::test;
use labrinth::models::v3::user_limits::UserLimits;
use crate::{
assert_status,
common::{
api_common::{Api, AppendsOptionalPat},
api_v3::ApiV3,
},
use crate::test::asserts::assert_status;
use crate::test::{
api_common::{Api, AppendsOptionalPat},
api_v3::ApiV3,
};
impl ApiV3 {

View File

@@ -2,9 +2,9 @@ use super::{
api_common::{Api, ApiBuildable},
environment::LocalService,
};
use crate::LabrinthConfig;
use actix_web::{App, dev::ServiceResponse, test};
use async_trait::async_trait;
use labrinth::LabrinthConfig;
use std::rc::Rc;
use utoipa_actix_web::AppExt;
@@ -31,12 +31,10 @@ impl ApiBuildable for ApiV3 {
let app = App::new()
.into_utoipa_app()
.configure(|cfg| {
labrinth::utoipa_app_config(cfg, labrinth_config.clone())
crate::utoipa_app_config(cfg, labrinth_config.clone())
})
.into_app()
.configure(|cfg| {
labrinth::app_config(cfg, labrinth_config.clone())
});
.configure(|cfg| crate::app_config(cfg, labrinth_config.clone()));
let test_app: Rc<dyn LocalService> =
Rc::new(test::init_service(app).await);

View File

@@ -1,20 +1,18 @@
use std::collections::HashMap;
use crate::auth::oauth::{
OAuthClientAccessRequest, RespondToOAuthClientScopes, TokenRequest,
TokenResponse,
};
use actix_http::StatusCode;
use actix_web::http::header::{AUTHORIZATION, LOCATION};
use actix_web::{
dev::ServiceResponse,
test::{self, TestRequest},
};
use labrinth::auth::oauth::{
OAuthClientAccessRequest, RespondToOAuthClientScopes, TokenRequest,
TokenResponse,
};
use crate::{
assert_status,
common::api_common::{Api, AppendsOptionalPat},
};
use crate::test::api_common::{Api, AppendsOptionalPat};
use crate::test::asserts::assert_status;
use super::ApiV3;

View File

@@ -1,21 +1,19 @@
use actix_http::StatusCode;
use actix_web::{
dev::ServiceResponse,
test::{self, TestRequest},
};
use labrinth::{
use crate::{
models::{
oauth_clients::{OAuthClient, OAuthClientAuthorization},
pats::Scopes,
},
routes::v3::oauth_clients::OAuthClientEdit,
};
use actix_http::StatusCode;
use actix_web::{
dev::ServiceResponse,
test::{self, TestRequest},
};
use serde_json::json;
use crate::{
assert_status,
common::api_common::{Api, AppendsOptionalPat},
};
use crate::test::api_common::{Api, AppendsOptionalPat};
use crate::test::asserts::assert_status;
use super::ApiV3;

View File

@@ -1,7 +1,8 @@
use crate::{
assert_status,
common::api_common::{Api, AppendsOptionalPat, request_data::ImageData},
use crate::models::{organizations::Organization, v3::projects::Project};
use crate::test::api_common::{
Api, AppendsOptionalPat, request_data::ImageData,
};
use crate::test::asserts::assert_status;
use actix_http::StatusCode;
use actix_web::{
dev::ServiceResponse,
@@ -9,7 +10,6 @@ use actix_web::{
};
use ariadne::ids::UserId;
use bytes::Bytes;
use labrinth::models::{organizations::Organization, v3::projects::Project};
use serde_json::json;
use super::ApiV3;

View File

@@ -1,5 +1,10 @@
use std::{collections::HashMap, fmt::Write};
use crate::{
models::{organizations::Organization, projects::Project},
search::SearchResults,
util::actix::AppendsMultipart,
};
use actix_http::StatusCode;
use actix_web::{
dev::ServiceResponse,
@@ -8,25 +13,18 @@ use actix_web::{
use async_trait::async_trait;
use bytes::Bytes;
use chrono::{DateTime, Utc};
use labrinth::{
models::{organizations::Organization, projects::Project},
search::SearchResults,
util::actix::AppendsMultipart,
};
use rust_decimal::Decimal;
use serde_json::json;
use crate::{
assert_status,
common::{
api_common::{
Api, ApiProject, AppendsOptionalPat,
models::{CommonItemType, CommonProject, CommonVersion},
request_data::{ImageData, ProjectCreationRequestData},
},
database::MOD_USER_PAT,
dummy_data::TestFile,
use crate::test::asserts::assert_status;
use crate::test::{
api_common::{
Api, ApiProject, AppendsOptionalPat,
models::{CommonItemType, CommonProject, CommonVersion},
request_data::{ImageData, ProjectCreationRequestData},
},
database::MOD_USER_PAT,
dummy_data::TestFile,
};
use super::{

View File

@@ -1,13 +1,13 @@
use serde_json::json;
use crate::common::{
use crate::models::ids::ProjectId;
use crate::test::{
api_common::request_data::{
ProjectCreationRequestData, VersionCreationRequestData,
},
dummy_data::TestFile,
};
use labrinth::models::ids::ProjectId;
use labrinth::util::actix::{MultipartSegment, MultipartSegmentData};
use crate::util::actix::{MultipartSegment, MultipartSegmentData};
pub fn get_public_project_creation_data(
slug: &str,

View File

@@ -1,24 +1,22 @@
use crate::routes::v3::tags::{GameData, LoaderData};
use crate::{
database::models::loader_fields::LoaderFieldEnumValue,
routes::v3::tags::CategoryData,
};
use actix_http::StatusCode;
use actix_web::{
dev::ServiceResponse,
test::{self, TestRequest},
};
use async_trait::async_trait;
use labrinth::routes::v3::tags::{GameData, LoaderData};
use labrinth::{
database::models::loader_fields::LoaderFieldEnumValue,
routes::v3::tags::CategoryData,
};
use crate::{
assert_status,
common::{
api_common::{
Api, ApiTags, AppendsOptionalPat,
models::{CommonCategoryData, CommonLoaderData},
},
database::ADMIN_USER_PAT,
use crate::test::asserts::assert_status;
use crate::test::{
api_common::{
Api, ApiTags, AppendsOptionalPat,
models::{CommonCategoryData, CommonLoaderData},
},
database::ADMIN_USER_PAT,
};
use super::ApiV3;

View File

@@ -1,19 +1,17 @@
use actix_http::StatusCode;
use actix_web::{dev::ServiceResponse, test};
use async_trait::async_trait;
use labrinth::models::{
use crate::models::{
notifications::Notification,
teams::{OrganizationPermissions, ProjectPermissions, TeamMember},
};
use actix_http::StatusCode;
use actix_web::{dev::ServiceResponse, test};
use async_trait::async_trait;
use serde_json::json;
use crate::{
assert_status,
common::api_common::{
Api, ApiTeams, AppendsOptionalPat,
models::{CommonNotification, CommonTeamMember},
},
use crate::test::api_common::{
Api, ApiTeams, AppendsOptionalPat,
models::{CommonNotification, CommonTeamMember},
};
use crate::test::asserts::assert_status;
use super::ApiV3;

View File

@@ -1,7 +1,7 @@
use actix_web::{dev::ServiceResponse, test};
use async_trait::async_trait;
use crate::common::api_common::{Api, ApiUser, AppendsOptionalPat};
use crate::test::api_common::{Api, ApiUser, AppendsOptionalPat};
use super::ApiV3;

View File

@@ -5,14 +5,16 @@ use super::{
ApiV3,
request_data::{self, get_public_version_creation_data},
};
use crate::models::ids::ProjectId;
use crate::test::asserts::assert_status;
use crate::test::{
api_common::{Api, ApiVersion, AppendsOptionalPat, models::CommonVersion},
dummy_data::TestFile,
};
use crate::{
assert_status,
common::{
api_common::{
Api, ApiVersion, AppendsOptionalPat, models::CommonVersion,
},
dummy_data::TestFile,
},
models::{projects::VersionType, v3::projects::Version},
routes::v3::version_file::FileUpdateData,
util::actix::AppendsMultipart,
};
use actix_http::StatusCode;
use actix_web::{
@@ -20,12 +22,6 @@ use actix_web::{
test::{self, TestRequest},
};
use async_trait::async_trait;
use labrinth::models::ids::ProjectId;
use labrinth::{
models::{projects::VersionType, v3::projects::Version},
routes::v3::version_file::FileUpdateData,
util::actix::AppendsMultipart,
};
use serde_json::json;
pub fn url_encode_json_serialized_vec(elements: &[String]) -> String {

View File

@@ -1,10 +1,9 @@
use crate::common::get_json_val_str;
use crate::models::v3::projects::Version;
use crate::test::get_json_val_str;
use itertools::Itertools;
use labrinth::models::v3::projects::Version;
use super::api_common::models::CommonVersion;
#[macro_export]
macro_rules! assert_status {
($response:expr, $status:expr) => {
assert_eq!(
@@ -16,17 +15,7 @@ macro_rules! assert_status {
};
}
#[macro_export]
macro_rules! assert_any_status_except {
($response:expr, $status:expr) => {
assert_ne!(
$response.status(),
$status,
"{:#?}",
$response.response().body()
);
};
}
pub(crate) use assert_status;
pub fn assert_version_ids(versions: &[Version], expected_ids: Vec<String>) {
let version_ids = versions

View File

@@ -1,11 +1,11 @@
use labrinth::database::ReadOnlyPgPool;
use labrinth::database::redis::RedisPool;
use labrinth::search;
use crate::database::redis::RedisPool;
use crate::database::{MIGRATOR, ReadOnlyPgPool};
use crate::search;
use sqlx::{PgPool, postgres::PgPoolOptions};
use std::time::Duration;
use url::Url;
use crate::common::{dummy_data, environment::TestEnvironment};
use crate::test::{dummy_data, environment::TestEnvironment};
use super::{api_v3::ApiV3, dummy_data::DUMMY_DATA_UPDATE};
@@ -40,7 +40,7 @@ pub struct TemporaryDatabase {
pub pool: PgPool,
pub ro_pool: ReadOnlyPgPool,
pub redis_pool: RedisPool,
pub search_config: labrinth::search::SearchConfig,
pub search_config: crate::search::SearchConfig,
pub database_name: String,
}
@@ -82,8 +82,7 @@ impl TemporaryDatabase {
println!("Running migrations on temporary database");
// Performs migrations
let migrations = sqlx::migrate!("./migrations");
migrations.run(&pool).await.expect("Migrations failed");
MIGRATOR.run(&pool).await.expect("Migrations failed");
println!("Migrations complete");
@@ -182,8 +181,7 @@ impl TemporaryDatabase {
}
// Run migrations on the template
let migrations = sqlx::migrate!("./migrations");
migrations.run(&pool).await.expect("Migrations failed");
MIGRATOR.run(&pool).await.expect("Migrations failed");
if !dummy_data_exists {
// Add dummy data

View File

@@ -1,17 +1,15 @@
use std::io::{Cursor, Write};
use crate::{
assert_status,
common::{api_common::Api, api_v3, database::USER_USER_PAT},
};
use actix_http::StatusCode;
use actix_web::test::{self, TestRequest};
use labrinth::models::ids::ProjectId;
use labrinth::models::{
use crate::models::ids::ProjectId;
use crate::models::{
oauth_clients::OAuthClient,
organizations::Organization,
projects::{Project, Version},
};
use crate::test::asserts::assert_status;
use crate::test::{api_common::Api, api_v3, database::USER_USER_PAT};
use actix_http::StatusCode;
use actix_web::test::{self, TestRequest};
use serde_json::json;
use zip::{CompressionMethod, ZipWriter, write::FileOptions};
@@ -289,7 +287,7 @@ pub async fn add_dummy_data(api: &ApiV3, db: TemporaryDatabase) -> DummyData {
// Adds basic dummy data to the database directly with sql (user, pats)
let pool = &db.pool.clone();
labrinth::test::db::add_dummy_data(pool).await.unwrap();
crate::test::db::add_dummy_data(pool).await.unwrap();
let (alpha_project, alpha_version) = add_project_alpha(api).await;
let (beta_project, beta_version) = add_project_beta(api).await;

View File

@@ -5,7 +5,8 @@ use super::{
database::{FRIEND_USER_ID, TemporaryDatabase, USER_USER_PAT},
dummy_data,
};
use crate::{assert_status, common::setup};
use crate::test::asserts::assert_status;
use crate::test::setup;
use actix_http::StatusCode;
use actix_web::dev::ServiceResponse;
use futures::Future;

View File

@@ -1 +1,76 @@
use crate::queue::email::EmailQueue;
use crate::util::anrok;
use crate::util::gotenberg::GotenbergClient;
use crate::{LabrinthConfig, file_hosting};
use crate::{check_env_vars, clickhouse};
use modrinth_maxmind::MaxMind;
use std::sync::Arc;
pub mod api_common;
pub mod api_v2;
pub mod api_v3;
pub mod asserts;
pub mod database;
pub mod db;
pub mod dummy_data;
pub mod environment;
pub mod pats;
pub mod permissions;
pub mod scopes;
pub mod search;
// Testing equivalent to 'setup' function, producing a LabrinthConfig
// If making a test, you should probably use environment::TestEnvironment::build() (which calls this)
pub async fn setup(db: &database::TemporaryDatabase) -> LabrinthConfig {
println!("Setting up labrinth config");
dotenvy::dotenv().ok();
if check_env_vars() {
println!("Some environment variables are missing!");
}
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
let pool = db.pool.clone();
let ro_pool = db.ro_pool.clone();
let redis_pool = db.redis_pool.clone();
let search_config = db.search_config.clone();
let file_host: Arc<dyn file_hosting::FileHost + Send + Sync> =
Arc::new(file_hosting::MockHost::new());
let mut clickhouse = clickhouse::init_client().await.unwrap();
let maxmind_reader = MaxMind::new().await;
let stripe_client =
stripe::Client::new(dotenvy::var("STRIPE_API_KEY").unwrap());
let anrok_client = anrok::Client::from_env().unwrap();
let email_queue =
EmailQueue::init(pool.clone(), redis_pool.clone()).unwrap();
let gotenberg_client =
GotenbergClient::from_env().expect("Failed to create Gotenberg client");
crate::app_setup(
pool.clone(),
ro_pool.clone(),
redis_pool.clone(),
search_config,
&mut clickhouse,
file_host.clone(),
maxmind_reader,
stripe_client,
anrok_client,
email_queue,
gotenberg_client,
false,
)
}
pub fn get_json_val_str(val: impl serde::Serialize) -> String {
serde_json::to_value(val)
.unwrap()
.as_str()
.unwrap()
.to_string()
}

View File

@@ -1,8 +1,8 @@
use chrono::Utc;
use labrinth::{
use crate::{
database::{self, models::generate_pat_id},
models::pats::Scopes,
};
use chrono::Utc;
use super::database::TemporaryDatabase;

View File

@@ -1,11 +1,11 @@
use crate::models::teams::{OrganizationPermissions, ProjectPermissions};
use actix_http::StatusCode;
use actix_web::{dev::ServiceResponse, test};
use futures::Future;
use itertools::Itertools;
use labrinth::models::teams::{OrganizationPermissions, ProjectPermissions};
use serde_json::json;
use crate::common::{
use crate::test::{
api_common::ApiTeams,
database::{ADMIN_USER_PAT, generate_random_name},
};

View File

@@ -1,6 +1,6 @@
use crate::models::pats::Scopes;
use actix_web::{dev::ServiceResponse, test};
use futures::Future;
use labrinth::models::pats::Scopes;
use super::{
api_common::Api, database::USER_USER_ID_PARSED,

View File

@@ -3,13 +3,11 @@ use std::{collections::HashMap, sync::Arc};
use actix_http::StatusCode;
use serde_json::json;
use crate::{
assert_status,
common::{
api_common::{Api, ApiProject, ApiVersion},
database::{FRIEND_USER_PAT, MOD_USER_PAT, USER_USER_PAT},
dummy_data::{DUMMY_CATEGORIES, TestFile},
},
use crate::test::asserts::assert_status;
use crate::test::{
api_common::{Api, ApiProject, ApiVersion},
database::{FRIEND_USER_PAT, MOD_USER_PAT, USER_USER_PAT},
dummy_data::{DUMMY_CATEGORIES, TestFile},
};
use super::{api_v3::ApiV3, environment::TestEnvironment};

View File

@@ -0,0 +1,32 @@
//! Re-exports all [`labrinth::test`] items for compatibility.
//!
//! Previously, tests used `mod common` and `common::item` imports for testing.
//! This has been moved into [`labrinth::test`] under a feature flag, and this
//! module remains for backwards compatibility with tests which expect the
//! `common` module.
pub use labrinth::test::*;
#[macro_export]
macro_rules! assert_status {
($response:expr, $status:expr) => {
assert_eq!(
$response.status(),
$status,
"{:#?}",
$response.response().body()
);
};
}
#[macro_export]
macro_rules! assert_any_status_except {
($response:expr, $status:expr) => {
assert_ne!(
$response.status(),
$status,
"{:#?}",
$response.response().body()
);
};
}

View File

@@ -1,75 +0,0 @@
use labrinth::queue::email::EmailQueue;
use labrinth::util::anrok;
use labrinth::util::gotenberg::GotenbergClient;
use labrinth::{LabrinthConfig, file_hosting};
use labrinth::{check_env_vars, clickhouse};
use modrinth_maxmind::MaxMind;
use std::sync::Arc;
pub mod api_common;
pub mod api_v2;
pub mod api_v3;
pub mod asserts;
pub mod database;
pub mod dummy_data;
pub mod environment;
pub mod pats;
pub mod permissions;
pub mod scopes;
pub mod search;
// Testing equivalent to 'setup' function, producing a LabrinthConfig
// If making a test, you should probably use environment::TestEnvironment::build() (which calls this)
pub async fn setup(db: &database::TemporaryDatabase) -> LabrinthConfig {
println!("Setting up labrinth config");
dotenvy::dotenv().ok();
if check_env_vars() {
println!("Some environment variables are missing!");
}
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
let pool = db.pool.clone();
let ro_pool = db.ro_pool.clone();
let redis_pool = db.redis_pool.clone();
let search_config = db.search_config.clone();
let file_host: Arc<dyn file_hosting::FileHost + Send + Sync> =
Arc::new(file_hosting::MockHost::new());
let mut clickhouse = clickhouse::init_client().await.unwrap();
let maxmind_reader = MaxMind::new().await;
let stripe_client =
stripe::Client::new(dotenvy::var("STRIPE_API_KEY").unwrap());
let anrok_client = anrok::Client::from_env().unwrap();
let email_queue =
EmailQueue::init(pool.clone(), redis_pool.clone()).unwrap();
let gotenberg_client =
GotenbergClient::from_env().expect("Failed to create Gotenberg client");
labrinth::app_setup(
pool.clone(),
ro_pool.clone(),
redis_pool.clone(),
search_config,
&mut clickhouse,
file_host.clone(),
maxmind_reader,
stripe_client,
anrok_client,
email_queue,
gotenberg_client,
false,
)
}
pub fn get_json_val_str(val: impl serde::Serialize) -> String {
serde_json::to_value(val)
.unwrap()
.as_str()
.unwrap()
.to_string()
}

View File

@@ -1,15 +1,16 @@
use crate::assert_status;
use crate::common::api_common::ApiProject;
use actix_http::StatusCode;
use actix_web::test;
use bytes::Bytes;
use crate::assert_status;
use crate::common::database::USER_USER_PAT;
use crate::common::{
api_v2::ApiV2,
environment::{TestEnvironment, with_test_environment},
};
#[actix_rt::test]
pub async fn error_404_empty() {
with_test_environment(