Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
basic search test
Browse files Browse the repository at this point in the history
  • Loading branch information
thesuzerain committed Oct 17, 2023
1 parent e3c207f commit 81834ef
Show file tree
Hide file tree
Showing 9 changed files with 408 additions and 41 deletions.
26 changes: 16 additions & 10 deletions migrations/20231005230721_dynamic-fields.sql
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
CREATE TABLE loader_field_enums (
id serial PRIMARY KEY,
enum_name varchar(64) NOT NULL,
ordering int NULL,
hidable BOOLEAN NOT NULL DEFAULT FALSE,
metadata varchar(128)
);

CREATE TABLE loader_fields (
id serial PRIMARY KEY,
loader_id integer REFERENCES loaders ON UPDATE CASCADE NOT NULL,
field varchar(64) NOT NULL,
-- "int", "text", "enum", "bool",
-- "array(int)", "array(text)", "array(enum)", "array(bool)"
field_type varchar(64) NOT NULL,
-- only for enum
enum_type integer REFERENCES loader_field_enums ON UPDATE CASCADE NULL,
optional BOOLEAN NOT NULL DEFAULT true,
-- for int- min/max val, for text- min len, for enum- min items, for bool- nth
-- for int- min/max val, for text- min len, for enum- min items, for bool- nothing
min_val integer NULL,
max_val integer NULL
);

CREATE TABLE loader_field_enums (
id serial PRIMARY KEY,
enum_name varchar(64) NOT NULL,
ordering int NULL,
hidable BOOLEAN NOT NULL DEFAULT FALSE,
metadata
);

ALTER TABLE loaders ADD COLUMN hidable boolean NOT NULL default false;

CREATE TABLE version_fields (
Expand All @@ -28,4 +31,7 @@ CREATE TABLE version_fields (
int_value integer NULL,
enum_value integer REFERENCES loader_field_enums ON UPDATE CASCADE NULL,
string_value text NULL
);
);

-- DROP TABLE side_types;
-- DROP TABLE game_versions;
14 changes: 13 additions & 1 deletion src/routes/v2/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::queue::download::DownloadQueue;
use crate::queue::maxmind::MaxMindIndexer;
use crate::queue::session::AuthQueue;
use crate::routes::ApiError;
use crate::search::SearchConfig;
use crate::util::date::get_current_tenths_of_ms;
use crate::util::guards::admin_key_guard;
use crate::util::routes::read_from_payload;
Expand All @@ -28,7 +29,8 @@ pub fn config(cfg: &mut web::ServiceConfig) {
cfg.service(
web::scope("admin")
.service(count_download)
.service(trolley_webhook),
.service(trolley_webhook)
.service(force_reindex)
);
}

Expand Down Expand Up @@ -319,3 +321,13 @@ pub async fn trolley_webhook(

Ok(HttpResponse::NoContent().finish())
}

#[post("/_force_reindex")]
pub async fn force_reindex(
pool: web::Data<PgPool>,
config: web::Data<SearchConfig>,
) -> Result<HttpResponse, ApiError> {
use crate::search::indexing::index_projects;
index_projects(pool.as_ref().clone(), &config).await?;
Ok(HttpResponse::NoContent().finish())
}
1 change: 1 addition & 0 deletions tests/common/api_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use labrinth::models::{
use serde_json::json;
use std::rc::Rc;

#[derive(Clone)]
pub struct ApiV2 {
pub test_app: Rc<Box<dyn LocalService>>,
}
Expand Down
2 changes: 1 addition & 1 deletion tests/common/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl TemporaryDatabase {

let pool = PgPoolOptions::new()
.min_connections(0)
.max_connections(4)
.max_connections(16)
.max_lifetime(Some(Duration::from_secs(60 * 60)))
.connect(&temp_db_url)
.await
Expand Down
142 changes: 129 additions & 13 deletions tests/common/dummy_data.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::io::{Write, Cursor};

use actix_web::test::{self, TestRequest};
use labrinth::{models::projects::Project, models::projects::Version};
use serde_json::json;
use sqlx::Executor;
use zip::{write::FileOptions, ZipWriter, CompressionMethod};

use crate::common::{actix::AppendsMultipart, database::USER_USER_PAT};

Expand All @@ -23,13 +26,110 @@ pub const DUMMY_CATEGORIES: &'static [&str] = &[
];

#[allow(dead_code)]
pub enum DummyJarFile {
pub enum TestFile {
DummyProjectAlpha,
DummyProjectBeta,
BasicMod,
BasicModDifferent,
// Randomly generates a valid .jar with a random hash.
// Unlike the other dummy jar files, this one is not a static file.
// and BasicModRandom.bytes() will return a different file each time.
BasicModRandom {
filename: String,
bytes: Vec<u8>,
},
BasicModpackRandom {
filename: String,
bytes: Vec<u8>,
},
}

impl TestFile {
pub fn build_random_jar() -> Self {
let filename = format!("random-mod-{}.jar", rand::random::<u64>());

let fabric_mod_json = serde_json::json!({
"schemaVersion": 1,
"id": filename,
"version": "1.0.1",

"name": filename,
"description": "Does nothing",
"authors": [
"user"
],
"contact": {
"homepage": "https://www.modrinth.com",
"sources": "https://www.modrinth.com",
"issues": "https://www.modrinth.com"
},

"license": "MIT",
"icon": "none.png",

"environment": "client",
"entrypoints": {
"main": [
"io.github.modrinth.Modrinth"
]
},
"depends": {
"minecraft": ">=1.20-"
}
}
).to_string();

// Create a simulated zip file
let mut cursor = Cursor::new(Vec::new());
{
let mut zip = ZipWriter::new(&mut cursor);
zip.start_file("fabric.mod.json", FileOptions::default().compression_method(CompressionMethod::Stored)).unwrap();
zip.write_all(fabric_mod_json.as_bytes()).unwrap();
zip.finish().unwrap();
}
let bytes = cursor.into_inner();

TestFile::BasicModRandom {
filename,
bytes,
}
}

pub fn build_random_mrpack() -> Self {
let filename = format!("random-modpack-{}.mrpack", rand::random::<u64>());

let modrinth_index_json = serde_json::json!({
"formatVersion": 1,
"game": "minecraft",
"versionId": "1.20.1-9.6",
"name": filename,
"files": [],
"dependencies": {
"fabric-loader": "0.14.22",
"minecraft": "1.20.1"
}
}
).to_string();

// Create a simulated zip file
let mut cursor = Cursor::new(Vec::new());
{
let mut zip = ZipWriter::new(&mut cursor);
zip.start_file("modrinth.index.json", FileOptions::default().compression_method(CompressionMethod::Stored)).unwrap();
zip.write_all(modrinth_index_json.as_bytes()).unwrap();
zip.finish().unwrap();
}
let bytes = cursor.into_inner();

TestFile::BasicModpackRandom {
filename,
bytes,
}
}

}

#[derive(Clone)]
pub struct DummyData {
pub alpha_team_id: String,
pub beta_team_id: String,
Expand Down Expand Up @@ -86,15 +186,15 @@ pub async fn add_project_alpha(test_env: &TestEnvironment) -> (Project, Version)
.v2
.add_public_project(get_public_project_creation_data(
"alpha",
DummyJarFile::DummyProjectAlpha,
TestFile::DummyProjectAlpha,
))
.await
}

pub async fn add_project_beta(test_env: &TestEnvironment) -> (Project, Version) {
// Adds dummy data to the database with sqlx (projects, versions, threads)
// Generate test project data.
let jar = DummyJarFile::DummyProjectBeta;
let jar = TestFile::DummyProjectBeta;
let json_data = json!(
{
"title": "Test Project Beta",
Expand Down Expand Up @@ -168,29 +268,45 @@ pub async fn add_project_beta(test_env: &TestEnvironment) -> (Project, Version)
(project, version)
}

impl DummyJarFile {
impl TestFile {
pub fn filename(&self) -> String {
match self {
DummyJarFile::DummyProjectAlpha => "dummy-project-alpha.jar",
DummyJarFile::DummyProjectBeta => "dummy-project-beta.jar",
DummyJarFile::BasicMod => "basic-mod.jar",
DummyJarFile::BasicModDifferent => "basic-mod-different.jar",
TestFile::DummyProjectAlpha => "dummy-project-alpha.jar",
TestFile::DummyProjectBeta => "dummy-project-beta.jar",
TestFile::BasicMod => "basic-mod.jar",
TestFile::BasicModDifferent => "basic-mod-different.jar",
TestFile::BasicModRandom { filename, .. } => filename,
TestFile::BasicModpackRandom { filename, .. } => filename,
}
.to_string()
}

pub fn bytes(&self) -> Vec<u8> {
match self {
DummyJarFile::DummyProjectAlpha => {
TestFile::DummyProjectAlpha => {
include_bytes!("../../tests/files/dummy-project-alpha.jar").to_vec()
}
DummyJarFile::DummyProjectBeta => {
TestFile::DummyProjectBeta => {
include_bytes!("../../tests/files/dummy-project-beta.jar").to_vec()
}
DummyJarFile::BasicMod => include_bytes!("../../tests/files/basic-mod.jar").to_vec(),
DummyJarFile::BasicModDifferent => {
TestFile::BasicMod => include_bytes!("../../tests/files/basic-mod.jar").to_vec(),
TestFile::BasicModDifferent => {
include_bytes!("../../tests/files/basic-mod-different.jar").to_vec()
}
},
TestFile::BasicModRandom { bytes, .. } => bytes.clone(),
TestFile::BasicModpackRandom { bytes, .. } => bytes.clone(),
}
}

pub fn project_type(&self) -> String {
match self {
TestFile::DummyProjectAlpha => "mod",
TestFile::DummyProjectBeta => "mod",
TestFile::BasicMod => "mod",
TestFile::BasicModDifferent => "mod",
TestFile::BasicModRandom { .. } => "mod",

TestFile::BasicModpackRandom { .. } => "modpack",
}.to_string()
}
}
1 change: 1 addition & 0 deletions tests/common/environment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ where
// Must be called in an #[actix_rt::test] context. It also simulates a
// temporary sqlx db like #[sqlx::test] would.
// Use .call(req) on it directly to make a test call as if test::call_service(req) were being used.
#[derive(Clone)]
pub struct TestEnvironment {
test_app: Rc<Box<dyn LocalService>>,
pub db: TemporaryDatabase,
Expand Down
41 changes: 28 additions & 13 deletions tests/common/request_data.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
use serde_json::json;

use super::{actix::MultipartSegment, dummy_data::DummyJarFile};
use super::{actix::MultipartSegment, dummy_data::TestFile};
use crate::common::actix::MultipartSegmentData;

pub struct ProjectCreationRequestData {
pub slug: String,
pub jar: DummyJarFile,
pub jar: TestFile,
pub segment_data: Vec<MultipartSegment>,
}

pub fn get_public_project_creation_data(
slug: &str,
jar: DummyJarFile,
jar: TestFile,
) -> ProjectCreationRequestData {
let json_data = json!(
let json_data = get_public_project_creation_data_json(slug, &jar);
let multipart_data = get_public_project_creation_data_multipart(&json_data, &jar);
ProjectCreationRequestData {
slug: slug.to_string(),
jar,
segment_data: multipart_data,
}
}

pub fn get_public_project_creation_data_json(
slug: &str,
jar: &TestFile,
) -> serde_json::Value {
json!(
{
"title": format!("Test Project {slug}"),
"slug": slug,
"project_type": jar.project_type(),
"description": "A dummy project for testing with.",
"body": "This project is approved, and versions are listed.",
"client_side": "required",
Expand All @@ -32,16 +46,21 @@ pub fn get_public_project_creation_data(
"featured": true
}],
"categories": [],
"license_id": "MIT"
"license_id": "MIT",
}
);
)
}

pub fn get_public_project_creation_data_multipart(
json_data: &serde_json::Value,
jar: &TestFile,
) -> Vec<MultipartSegment> {
// Basic json
let json_segment = MultipartSegment {
name: "data".to_string(),
filename: None,
content_type: Some("application/json".to_string()),
data: MultipartSegmentData::Text(serde_json::to_string(&json_data).unwrap()),
data: MultipartSegmentData::Text(serde_json::to_string(json_data).unwrap()),
};

// Basic file
Expand All @@ -52,9 +71,5 @@ pub fn get_public_project_creation_data(
data: MultipartSegmentData::Binary(jar.bytes()),
};

ProjectCreationRequestData {
slug: slug.to_string(),
jar,
segment_data: vec![json_segment.clone(), file_segment.clone()],
}
}
vec![json_segment, file_segment]
}
Loading

0 comments on commit 81834ef

Please sign in to comment.