You've already forked AstralRinth
forked from didirus/AstralRinth
Tests v2 recreate (#760)
* added common project information; setup for v2 test change * all tests now use with_test_environment * progress, failing * finished re-adding tests * prepare * cargo sqlx prepare -- --tests * fmt; clippy; prepare * sqlx prepare * adds version_create fix and corresponding test * merge fixes; rev * fmt, clippy, prepare * test cargo sqlx prepare
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
use crate::common::{
|
||||
api_v2::request_data,
|
||||
api_common::ApiProject,
|
||||
api_v2::ApiV2,
|
||||
database::{ENEMY_USER_PAT, FRIEND_USER_ID, FRIEND_USER_PAT, MOD_USER_PAT, USER_USER_PAT},
|
||||
dummy_data::{TestFile, DUMMY_CATEGORIES},
|
||||
environment::TestEnvironment,
|
||||
environment::{with_test_environment, TestEnvironment},
|
||||
permissions::{PermissionsTest, PermissionsTestContext},
|
||||
};
|
||||
use actix_web::test;
|
||||
@@ -16,522 +17,512 @@ use serde_json::json;
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_project_type_sanity() {
|
||||
let test_env = TestEnvironment::build(None).await;
|
||||
let api = &test_env.v2;
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
|
||||
// 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();
|
||||
// Perform all other patch tests on both 'mod' and 'modpack'
|
||||
for (mod_or_modpack, slug, file) in [
|
||||
("mod", "test-mod", TestFile::build_random_jar()),
|
||||
("modpack", "test-modpack", TestFile::build_random_mrpack()),
|
||||
] {
|
||||
let (test_project, test_version) = api
|
||||
.add_public_project(slug, Some(file), None, 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"]
|
||||
);
|
||||
// TODO:
|
||||
// assert_eq!(test_project.project_type, mod_or_modpack);
|
||||
assert_eq!(test_project.loaders, vec!["fabric"]);
|
||||
assert_eq!(test_version[0].loaders, 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 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"]
|
||||
);
|
||||
}
|
||||
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 v3 routes.
|
||||
// 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 v3 routes.
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_add_remove_project() {
|
||||
// Test setup and dummy data
|
||||
let test_env = TestEnvironment::build(None).await;
|
||||
let api = &test_env.v2;
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
|
||||
// Generate test project data.
|
||||
let mut json_data = json!(
|
||||
{
|
||||
"title": "Test_Add_Project project",
|
||||
"slug": "demo",
|
||||
"description": "Example description.",
|
||||
"body": "Example body.",
|
||||
"client_side": "required",
|
||||
"server_side": "optional",
|
||||
"initial_versions": [{
|
||||
"file_parts": ["basic-mod.jar"],
|
||||
"version_number": "1.2.3",
|
||||
"version_title": "start",
|
||||
"dependencies": [],
|
||||
"game_versions": ["1.20.1"] ,
|
||||
"release_channel": "release",
|
||||
"loaders": ["fabric"],
|
||||
"featured": true
|
||||
}],
|
||||
"categories": [],
|
||||
"license_id": "MIT"
|
||||
}
|
||||
);
|
||||
// Generate test project data.
|
||||
let mut json_data = json!(
|
||||
{
|
||||
"title": "Test_Add_Project project",
|
||||
"slug": "demo",
|
||||
"description": "Example description.",
|
||||
"body": "Example body.",
|
||||
"client_side": "required",
|
||||
"server_side": "optional",
|
||||
"initial_versions": [{
|
||||
"file_parts": ["basic-mod.jar"],
|
||||
"version_number": "1.2.3",
|
||||
"version_title": "start",
|
||||
"dependencies": [],
|
||||
"game_versions": ["1.20.1"] ,
|
||||
"release_channel": "release",
|
||||
"loaders": ["fabric"],
|
||||
"featured": true
|
||||
}],
|
||||
"categories": [],
|
||||
"license_id": "MIT"
|
||||
}
|
||||
);
|
||||
|
||||
// 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()),
|
||||
};
|
||||
// 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()),
|
||||
};
|
||||
|
||||
// Basic json, with a different file
|
||||
json_data["initial_versions"][0]["file_parts"][0] = json!("basic-mod-different.jar");
|
||||
let json_diff_file_segment = MultipartSegment {
|
||||
data: MultipartSegmentData::Text(serde_json::to_string(&json_data).unwrap()),
|
||||
..json_segment.clone()
|
||||
};
|
||||
// Basic json, with a different file
|
||||
json_data["initial_versions"][0]["file_parts"][0] = json!("basic-mod-different.jar");
|
||||
let json_diff_file_segment = MultipartSegment {
|
||||
data: MultipartSegmentData::Text(serde_json::to_string(&json_data).unwrap()),
|
||||
..json_segment.clone()
|
||||
};
|
||||
|
||||
// Basic json, with a different file, and a different slug
|
||||
json_data["slug"] = json!("new_demo");
|
||||
json_data["initial_versions"][0]["file_parts"][0] = json!("basic-mod-different.jar");
|
||||
let json_diff_slug_file_segment = MultipartSegment {
|
||||
data: MultipartSegmentData::Text(serde_json::to_string(&json_data).unwrap()),
|
||||
..json_segment.clone()
|
||||
};
|
||||
// Basic json, with a different file, and a different slug
|
||||
json_data["slug"] = json!("new_demo");
|
||||
json_data["initial_versions"][0]["file_parts"][0] = json!("basic-mod-different.jar");
|
||||
let json_diff_slug_file_segment = MultipartSegment {
|
||||
data: MultipartSegmentData::Text(serde_json::to_string(&json_data).unwrap()),
|
||||
..json_segment.clone()
|
||||
};
|
||||
|
||||
// Basic file
|
||||
let file_segment = MultipartSegment {
|
||||
name: "basic-mod.jar".to_string(),
|
||||
filename: Some("basic-mod.jar".to_string()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
// TODO: look at these: can be simplified with TestFile
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/basic-mod.jar").to_vec(),
|
||||
),
|
||||
};
|
||||
// Basic file
|
||||
let file_segment = MultipartSegment {
|
||||
name: "basic-mod.jar".to_string(),
|
||||
filename: Some("basic-mod.jar".to_string()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
// TODO: look at these: can be simplified with TestFile
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/basic-mod.jar").to_vec(),
|
||||
),
|
||||
};
|
||||
|
||||
// Differently named file, with the same content (for hash testing)
|
||||
let file_diff_name_segment = MultipartSegment {
|
||||
name: "basic-mod-different.jar".to_string(),
|
||||
filename: Some("basic-mod-different.jar".to_string()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/basic-mod.jar").to_vec(),
|
||||
),
|
||||
};
|
||||
// Differently named file, with the same content (for hash testing)
|
||||
let file_diff_name_segment = MultipartSegment {
|
||||
name: "basic-mod-different.jar".to_string(),
|
||||
filename: Some("basic-mod-different.jar".to_string()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/basic-mod.jar").to_vec(),
|
||||
),
|
||||
};
|
||||
|
||||
// Differently named file, with different content
|
||||
let file_diff_name_content_segment = MultipartSegment {
|
||||
name: "basic-mod-different.jar".to_string(),
|
||||
filename: Some("basic-mod-different.jar".to_string()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/basic-mod-different.jar").to_vec(),
|
||||
),
|
||||
};
|
||||
// Differently named file, with different content
|
||||
let file_diff_name_content_segment = MultipartSegment {
|
||||
name: "basic-mod-different.jar".to_string(),
|
||||
filename: Some("basic-mod-different.jar".to_string()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/basic-mod-different.jar").to_vec(),
|
||||
),
|
||||
};
|
||||
|
||||
// Add a project- simple, should work.
|
||||
let req = test::TestRequest::post()
|
||||
.uri("/v2/project")
|
||||
.append_header(("Authorization", USER_USER_PAT))
|
||||
.set_multipart(vec![json_segment.clone(), file_segment.clone()])
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
// Add a project- simple, should work.
|
||||
let req = test::TestRequest::post()
|
||||
.uri("/v2/project")
|
||||
.append_header(("Authorization", 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 status = resp.status();
|
||||
assert_eq!(status, 200);
|
||||
|
||||
// Get the project we just made, and confirm that it's correct
|
||||
let project = api.get_project_deserialized("demo", USER_USER_PAT).await;
|
||||
assert!(project.versions.len() == 1);
|
||||
let uploaded_version_id = project.versions[0];
|
||||
// Get the project we just made, and confirm that it's correct
|
||||
let project = api.get_project_deserialized("demo", USER_USER_PAT).await;
|
||||
assert!(project.versions.len() == 1);
|
||||
let uploaded_version_id = project.versions[0];
|
||||
|
||||
// Checks files to ensure they were uploaded and correctly identify the file
|
||||
let hash = sha1::Sha1::from(include_bytes!("../../tests/files/basic-mod.jar"))
|
||||
.digest()
|
||||
.to_string();
|
||||
let version = api
|
||||
.get_version_from_hash_deserialized(&hash, "sha1", USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(version.id, uploaded_version_id);
|
||||
// Checks files to ensure they were uploaded and correctly identify the file
|
||||
let hash = sha1::Sha1::from(include_bytes!("../../tests/files/basic-mod.jar"))
|
||||
.digest()
|
||||
.to_string();
|
||||
let version = api
|
||||
.get_version_from_hash_deserialized(&hash, "sha1", USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(version.id, uploaded_version_id);
|
||||
|
||||
// Reusing with a different slug and the same file should fail
|
||||
// Even if that file is named differently
|
||||
let req = test::TestRequest::post()
|
||||
.uri("/v2/project")
|
||||
.append_header(("Authorization", USER_USER_PAT))
|
||||
.set_multipart(vec![
|
||||
json_diff_slug_file_segment.clone(), // Different slug, different file name
|
||||
file_diff_name_segment.clone(), // Different file name, same content
|
||||
])
|
||||
.to_request();
|
||||
// Reusing with a different slug and the same file should fail
|
||||
// Even if that file is named differently
|
||||
let req = test::TestRequest::post()
|
||||
.uri("/v2/project")
|
||||
.append_header(("Authorization", USER_USER_PAT))
|
||||
.set_multipart(vec![
|
||||
json_diff_slug_file_segment.clone(), // Different slug, different file name
|
||||
file_diff_name_segment.clone(), // Different file name, same content
|
||||
])
|
||||
.to_request();
|
||||
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
|
||||
// Reusing with the same slug and a different file should fail
|
||||
let req = test::TestRequest::post()
|
||||
.uri("/v2/project")
|
||||
.append_header(("Authorization", USER_USER_PAT))
|
||||
.set_multipart(vec![
|
||||
json_diff_file_segment.clone(), // Same slug, different file name
|
||||
file_diff_name_content_segment.clone(), // Different file name, different content
|
||||
])
|
||||
.to_request();
|
||||
// Reusing with the same slug and a different file should fail
|
||||
let req = test::TestRequest::post()
|
||||
.uri("/v2/project")
|
||||
.append_header(("Authorization", USER_USER_PAT))
|
||||
.set_multipart(vec![
|
||||
json_diff_file_segment.clone(), // Same slug, different file name
|
||||
file_diff_name_content_segment.clone(), // Different file name, different content
|
||||
])
|
||||
.to_request();
|
||||
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
|
||||
// Different slug, different file should succeed
|
||||
let req = test::TestRequest::post()
|
||||
.uri("/v2/project")
|
||||
.append_header(("Authorization", USER_USER_PAT))
|
||||
.set_multipart(vec![
|
||||
json_diff_slug_file_segment.clone(), // Different slug, different file name
|
||||
file_diff_name_content_segment.clone(), // Different file name, same content
|
||||
])
|
||||
.to_request();
|
||||
// Different slug, different file should succeed
|
||||
let req = test::TestRequest::post()
|
||||
.uri("/v2/project")
|
||||
.append_header(("Authorization", USER_USER_PAT))
|
||||
.set_multipart(vec![
|
||||
json_diff_slug_file_segment.clone(), // Different slug, different file name
|
||||
file_diff_name_content_segment.clone(), // Different file name, same content
|
||||
])
|
||||
.to_request();
|
||||
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
|
||||
// Get
|
||||
let project = api.get_project_deserialized("demo", USER_USER_PAT).await;
|
||||
let id = project.id.to_string();
|
||||
// Get
|
||||
let project = api.get_project_deserialized("demo", USER_USER_PAT).await;
|
||||
let id = project.id.to_string();
|
||||
|
||||
// Remove the project
|
||||
let resp = test_env.v2.remove_project("demo", USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
// Remove the project
|
||||
let resp = test_env.api.remove_project("demo", USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
|
||||
// Confirm that the project is gone from the cache
|
||||
let mut redis_conn = test_env.db.redis_pool.connect().await.unwrap();
|
||||
assert_eq!(
|
||||
redis_conn
|
||||
.get(PROJECTS_SLUGS_NAMESPACE, "demo")
|
||||
.await
|
||||
.unwrap()
|
||||
.map(|x| x.parse::<i64>().unwrap()),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
redis_conn
|
||||
.get(PROJECTS_SLUGS_NAMESPACE, &id)
|
||||
.await
|
||||
.unwrap()
|
||||
.map(|x| x.parse::<i64>().unwrap()),
|
||||
None
|
||||
);
|
||||
// Confirm that the project is gone from the cache
|
||||
let mut redis_conn = test_env.db.redis_pool.connect().await.unwrap();
|
||||
assert_eq!(
|
||||
redis_conn
|
||||
.get(PROJECTS_SLUGS_NAMESPACE, "demo")
|
||||
.await
|
||||
.unwrap()
|
||||
.map(|x| x.parse::<i64>().unwrap()),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
redis_conn
|
||||
.get(PROJECTS_SLUGS_NAMESPACE, &id)
|
||||
.await
|
||||
.unwrap()
|
||||
.map(|x| x.parse::<i64>().unwrap()),
|
||||
None
|
||||
);
|
||||
|
||||
// Old slug no longer works
|
||||
let resp = api.get_project("demo", USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 404);
|
||||
|
||||
// Cleanup test db
|
||||
test_env.cleanup().await;
|
||||
// Old slug no longer works
|
||||
let resp = api.get_project("demo", USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 404);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn permissions_upload_version() {
|
||||
let test_env = TestEnvironment::build(None).await;
|
||||
let alpha_project_id = &test_env.dummy.as_ref().unwrap().project_alpha.project_id;
|
||||
let alpha_version_id = &test_env.dummy.as_ref().unwrap().project_alpha.version_id;
|
||||
let alpha_team_id = &test_env.dummy.as_ref().unwrap().project_alpha.team_id;
|
||||
let alpha_file_hash = &test_env.dummy.as_ref().unwrap().project_alpha.file_hash;
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let alpha_project_id = &test_env.dummy.as_ref().unwrap().project_alpha.project_id;
|
||||
let alpha_version_id = &test_env.dummy.as_ref().unwrap().project_alpha.version_id;
|
||||
let alpha_team_id = &test_env.dummy.as_ref().unwrap().project_alpha.team_id;
|
||||
let alpha_file_hash = &test_env.dummy.as_ref().unwrap().project_alpha.file_hash;
|
||||
|
||||
let upload_version = ProjectPermissions::UPLOAD_VERSION;
|
||||
let upload_version = ProjectPermissions::UPLOAD_VERSION;
|
||||
|
||||
// Upload version with basic-mod.jar
|
||||
let req_gen = |ctx: &PermissionsTestContext| {
|
||||
test::TestRequest::post().uri("/v2/version").set_multipart([
|
||||
MultipartSegment {
|
||||
name: "data".to_string(),
|
||||
filename: None,
|
||||
content_type: Some("application/json".to_string()),
|
||||
data: MultipartSegmentData::Text(
|
||||
serde_json::to_string(&json!({
|
||||
"project_id": ctx.project_id.unwrap(),
|
||||
"file_parts": ["basic-mod.jar"],
|
||||
"version_number": "1.0.0",
|
||||
"version_title": "1.0.0",
|
||||
"version_type": "release",
|
||||
"dependencies": [],
|
||||
"game_versions": ["1.20.1"],
|
||||
"loaders": ["fabric"],
|
||||
"featured": false,
|
||||
|
||||
}))
|
||||
.unwrap(),
|
||||
),
|
||||
},
|
||||
MultipartSegment {
|
||||
name: "basic-mod.jar".to_string(),
|
||||
filename: Some("basic-mod.jar".to_string()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/basic-mod.jar").to_vec(),
|
||||
),
|
||||
},
|
||||
])
|
||||
};
|
||||
PermissionsTest::new(&test_env)
|
||||
.simple_project_permissions_test(upload_version, req_gen)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Upload file to existing version
|
||||
// Uses alpha project, as it has an existing version
|
||||
let req_gen = |_: &PermissionsTestContext| {
|
||||
test::TestRequest::post()
|
||||
.uri(&format!("/v2/version/{}/file", alpha_version_id))
|
||||
.set_multipart([
|
||||
// Upload version with basic-mod.jar
|
||||
let req_gen = |ctx: &PermissionsTestContext| {
|
||||
test::TestRequest::post().uri("/v2/version").set_multipart([
|
||||
MultipartSegment {
|
||||
name: "data".to_string(),
|
||||
filename: None,
|
||||
content_type: Some("application/json".to_string()),
|
||||
data: MultipartSegmentData::Text(
|
||||
serde_json::to_string(&json!({
|
||||
"file_parts": ["basic-mod-different.jar"],
|
||||
"project_id": ctx.project_id.unwrap(),
|
||||
"file_parts": ["basic-mod.jar"],
|
||||
"version_number": "1.0.0",
|
||||
"version_title": "1.0.0",
|
||||
"version_type": "release",
|
||||
"dependencies": [],
|
||||
"game_versions": ["1.20.1"],
|
||||
"loaders": ["fabric"],
|
||||
"featured": false,
|
||||
|
||||
}))
|
||||
.unwrap(),
|
||||
),
|
||||
},
|
||||
MultipartSegment {
|
||||
name: "basic-mod-different.jar".to_string(),
|
||||
filename: Some("basic-mod-different.jar".to_string()),
|
||||
name: "basic-mod.jar".to_string(),
|
||||
filename: Some("basic-mod.jar".to_string()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/basic-mod-different.jar").to_vec(),
|
||||
include_bytes!("../../tests/files/basic-mod.jar").to_vec(),
|
||||
),
|
||||
},
|
||||
])
|
||||
};
|
||||
PermissionsTest::new(&test_env)
|
||||
.with_existing_project(alpha_project_id, alpha_team_id)
|
||||
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
||||
.simple_project_permissions_test(upload_version, req_gen)
|
||||
.await
|
||||
.unwrap();
|
||||
};
|
||||
PermissionsTest::new(&test_env)
|
||||
.simple_project_permissions_test(upload_version, req_gen)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Patch version
|
||||
// Uses alpha project, as it has an existing version
|
||||
let req_gen = |_: &PermissionsTestContext| {
|
||||
test::TestRequest::patch()
|
||||
.uri(&format!("/v2/version/{}", alpha_version_id))
|
||||
.set_json(json!({
|
||||
"name": "Basic Mod",
|
||||
}))
|
||||
};
|
||||
PermissionsTest::new(&test_env)
|
||||
.with_existing_project(alpha_project_id, alpha_team_id)
|
||||
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
||||
.simple_project_permissions_test(upload_version, req_gen)
|
||||
.await
|
||||
.unwrap();
|
||||
// Upload file to existing version
|
||||
// Uses alpha project, as it has an existing version
|
||||
let req_gen = |_: &PermissionsTestContext| {
|
||||
test::TestRequest::post()
|
||||
.uri(&format!("/v2/version/{}/file", alpha_version_id))
|
||||
.set_multipart([
|
||||
MultipartSegment {
|
||||
name: "data".to_string(),
|
||||
filename: None,
|
||||
content_type: Some("application/json".to_string()),
|
||||
data: MultipartSegmentData::Text(
|
||||
serde_json::to_string(&json!({
|
||||
"file_parts": ["basic-mod-different.jar"],
|
||||
}))
|
||||
.unwrap(),
|
||||
),
|
||||
},
|
||||
MultipartSegment {
|
||||
name: "basic-mod-different.jar".to_string(),
|
||||
filename: Some("basic-mod-different.jar".to_string()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/basic-mod-different.jar").to_vec(),
|
||||
),
|
||||
},
|
||||
])
|
||||
};
|
||||
PermissionsTest::new(&test_env)
|
||||
.with_existing_project(alpha_project_id, alpha_team_id)
|
||||
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
||||
.simple_project_permissions_test(upload_version, req_gen)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Delete version file
|
||||
// Uses alpha project, as it has an existing version
|
||||
let delete_version = ProjectPermissions::DELETE_VERSION;
|
||||
let req_gen = |_: &PermissionsTestContext| {
|
||||
test::TestRequest::delete().uri(&format!("/v2/version_file/{}", alpha_file_hash))
|
||||
};
|
||||
// Patch version
|
||||
// Uses alpha project, as it has an existing version
|
||||
let req_gen = |_: &PermissionsTestContext| {
|
||||
test::TestRequest::patch()
|
||||
.uri(&format!("/v2/version/{}", alpha_version_id))
|
||||
.set_json(json!({
|
||||
"name": "Basic Mod",
|
||||
}))
|
||||
};
|
||||
PermissionsTest::new(&test_env)
|
||||
.with_existing_project(alpha_project_id, alpha_team_id)
|
||||
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
||||
.simple_project_permissions_test(upload_version, req_gen)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
PermissionsTest::new(&test_env)
|
||||
.with_existing_project(alpha_project_id, alpha_team_id)
|
||||
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
||||
.simple_project_permissions_test(delete_version, req_gen)
|
||||
.await
|
||||
.unwrap();
|
||||
// Delete version file
|
||||
// Uses alpha project, as it has an existing version
|
||||
let delete_version = ProjectPermissions::DELETE_VERSION;
|
||||
let req_gen = |_: &PermissionsTestContext| {
|
||||
test::TestRequest::delete().uri(&format!("/v2/version_file/{}", alpha_file_hash))
|
||||
};
|
||||
|
||||
// Delete version
|
||||
// Uses alpha project, as it has an existing version
|
||||
let req_gen = |_: &PermissionsTestContext| {
|
||||
test::TestRequest::delete().uri(&format!("/v2/version/{}", alpha_version_id))
|
||||
};
|
||||
PermissionsTest::new(&test_env)
|
||||
.with_existing_project(alpha_project_id, alpha_team_id)
|
||||
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
||||
.simple_project_permissions_test(delete_version, req_gen)
|
||||
.await
|
||||
.unwrap();
|
||||
PermissionsTest::new(&test_env)
|
||||
.with_existing_project(alpha_project_id, alpha_team_id)
|
||||
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
||||
.simple_project_permissions_test(delete_version, req_gen)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
test_env.cleanup().await;
|
||||
// Delete version
|
||||
// Uses alpha project, as it has an existing version
|
||||
let req_gen = |_: &PermissionsTestContext| {
|
||||
test::TestRequest::delete().uri(&format!("/v2/version/{}", alpha_version_id))
|
||||
};
|
||||
PermissionsTest::new(&test_env)
|
||||
.with_existing_project(alpha_project_id, alpha_team_id)
|
||||
.with_user(FRIEND_USER_ID, FRIEND_USER_PAT, true)
|
||||
.simple_project_permissions_test(delete_version, req_gen)
|
||||
.await
|
||||
.unwrap();
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn test_patch_project() {
|
||||
let test_env = TestEnvironment::build(None).await;
|
||||
let api = &test_env.v2;
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
|
||||
let alpha_project_slug = &test_env.dummy.as_ref().unwrap().project_alpha.project_slug;
|
||||
let beta_project_slug = &test_env.dummy.as_ref().unwrap().project_beta.project_slug;
|
||||
let alpha_project_slug = &test_env.dummy.as_ref().unwrap().project_alpha.project_slug;
|
||||
let beta_project_slug = &test_env.dummy.as_ref().unwrap().project_beta.project_slug;
|
||||
|
||||
// First, we do some patch requests that should fail.
|
||||
// Failure because the user is not authorized.
|
||||
let resp = api
|
||||
.edit_project(
|
||||
alpha_project_slug,
|
||||
json!({
|
||||
"title": "Test_Add_Project project - test 1",
|
||||
}),
|
||||
ENEMY_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
|
||||
// Failure because we are setting URL fields to invalid urls.
|
||||
for url_type in ["issues_url", "source_url", "wiki_url", "discord_url"] {
|
||||
// First, we do some patch requests that should fail.
|
||||
// Failure because the user is not authorized.
|
||||
let resp = api
|
||||
.edit_project(
|
||||
alpha_project_slug,
|
||||
json!({
|
||||
url_type: "w.fake.url",
|
||||
"title": "Test_Add_Project project - test 1",
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
ENEMY_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
}
|
||||
assert_eq!(resp.status(), 401);
|
||||
|
||||
// Failure because these are illegal requested statuses for a normal user.
|
||||
for req in ["unknown", "processing", "withheld", "scheduled"] {
|
||||
// Failure because we are setting URL fields to invalid urls.
|
||||
for url_type in ["issues_url", "source_url", "wiki_url", "discord_url"] {
|
||||
let resp = api
|
||||
.edit_project(
|
||||
alpha_project_slug,
|
||||
json!({
|
||||
url_type: "w.fake.url",
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
}
|
||||
|
||||
// Failure because these are illegal requested statuses for a normal user.
|
||||
for req in ["unknown", "processing", "withheld", "scheduled"] {
|
||||
let resp = api
|
||||
.edit_project(
|
||||
alpha_project_slug,
|
||||
json!({
|
||||
"requested_status": req,
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
}
|
||||
|
||||
// Failure because these should not be able to be set by a non-mod
|
||||
for key in ["moderation_message", "moderation_message_body"] {
|
||||
let resp = api
|
||||
.edit_project(
|
||||
alpha_project_slug,
|
||||
json!({
|
||||
key: "test",
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
|
||||
// (should work for a mod, though)
|
||||
let resp = api
|
||||
.edit_project(
|
||||
alpha_project_slug,
|
||||
json!({
|
||||
key: "test",
|
||||
}),
|
||||
MOD_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
}
|
||||
|
||||
// Failed patch to alpha slug:
|
||||
// - slug collision with beta
|
||||
// - too short slug
|
||||
// - too long slug
|
||||
// - not url safe slug
|
||||
// - not url safe slug
|
||||
for slug in [
|
||||
beta_project_slug,
|
||||
"a",
|
||||
&"a".repeat(100),
|
||||
"not url safe%&^!#$##!@#$%^&*()",
|
||||
] {
|
||||
let resp = api
|
||||
.edit_project(
|
||||
alpha_project_slug,
|
||||
json!({
|
||||
"slug": slug, // the other dummy project has this slug
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
}
|
||||
|
||||
// Not allowed to directly set status, as 'beta_project_slug' (the other project) is "processing" and cannot have its status changed like this.
|
||||
let resp = api
|
||||
.edit_project(
|
||||
alpha_project_slug,
|
||||
beta_project_slug,
|
||||
json!({
|
||||
"requested_status": req,
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
}
|
||||
|
||||
// Failure because these should not be able to be set by a non-mod
|
||||
for key in ["moderation_message", "moderation_message_body"] {
|
||||
let resp = api
|
||||
.edit_project(
|
||||
alpha_project_slug,
|
||||
json!({
|
||||
key: "test",
|
||||
"status": "private"
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
|
||||
// (should work for a mod, though)
|
||||
// Sucessful request to patch many fields.
|
||||
let resp = api
|
||||
.edit_project(
|
||||
alpha_project_slug,
|
||||
json!({
|
||||
key: "test",
|
||||
}),
|
||||
MOD_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
}
|
||||
|
||||
// Failed patch to alpha slug:
|
||||
// - slug collision with beta
|
||||
// - too short slug
|
||||
// - too long slug
|
||||
// - not url safe slug
|
||||
// - not url safe slug
|
||||
for slug in [
|
||||
beta_project_slug,
|
||||
"a",
|
||||
&"a".repeat(100),
|
||||
"not url safe%&^!#$##!@#$%^&*()",
|
||||
] {
|
||||
let resp = api
|
||||
.edit_project(
|
||||
alpha_project_slug,
|
||||
json!({
|
||||
"slug": slug, // the other dummy project has this slug
|
||||
"slug": "newslug",
|
||||
"title": "New successful title",
|
||||
"description": "New successful description",
|
||||
"body": "New successful body",
|
||||
"categories": [DUMMY_CATEGORIES[0]],
|
||||
"license_id": "MIT",
|
||||
"issues_url": "https://github.com",
|
||||
"discord_url": "https://discord.gg",
|
||||
"wiki_url": "https://wiki.com",
|
||||
"client_side": "optional",
|
||||
"server_side": "required",
|
||||
"donation_urls": [{
|
||||
"id": "patreon",
|
||||
"platform": "Patreon",
|
||||
"url": "https://patreon.com"
|
||||
}]
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
}
|
||||
assert_eq!(resp.status(), 204);
|
||||
|
||||
// Not allowed to directly set status, as 'beta_project_slug' (the other project) is "processing" and cannot have its status changed like this.
|
||||
let resp = api
|
||||
.edit_project(
|
||||
beta_project_slug,
|
||||
json!({
|
||||
"status": "private"
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
// Old slug no longer works
|
||||
let resp = api.get_project(alpha_project_slug, USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 404);
|
||||
|
||||
// Sucessful request to patch many fields.
|
||||
let resp = api
|
||||
.edit_project(
|
||||
alpha_project_slug,
|
||||
json!({
|
||||
"slug": "newslug",
|
||||
"title": "New successful title",
|
||||
"description": "New successful description",
|
||||
"body": "New successful body",
|
||||
"categories": [DUMMY_CATEGORIES[0]],
|
||||
"license_id": "MIT",
|
||||
"issues_url": "https://github.com",
|
||||
"discord_url": "https://discord.gg",
|
||||
"wiki_url": "https://wiki.com",
|
||||
"client_side": "optional",
|
||||
"server_side": "required",
|
||||
"donation_urls": [{
|
||||
"id": "patreon",
|
||||
"platform": "Patreon",
|
||||
"url": "https://patreon.com"
|
||||
}]
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
// New slug does work
|
||||
let project = api.get_project_deserialized("newslug", USER_USER_PAT).await;
|
||||
|
||||
// Old slug no longer works
|
||||
let resp = api.get_project(alpha_project_slug, USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 404);
|
||||
|
||||
// New slug does work
|
||||
let project = api.get_project_deserialized("newslug", USER_USER_PAT).await;
|
||||
|
||||
assert_eq!(project.slug.unwrap(), "newslug");
|
||||
assert_eq!(project.title, "New successful title");
|
||||
assert_eq!(project.description, "New successful description");
|
||||
assert_eq!(project.body, "New successful body");
|
||||
assert_eq!(project.categories, vec![DUMMY_CATEGORIES[0]]);
|
||||
assert_eq!(project.license.id, "MIT");
|
||||
assert_eq!(project.issues_url, Some("https://github.com".to_string()));
|
||||
assert_eq!(project.discord_url, Some("https://discord.gg".to_string()));
|
||||
assert_eq!(project.wiki_url, Some("https://wiki.com".to_string()));
|
||||
assert_eq!(project.client_side.as_str(), "optional");
|
||||
assert_eq!(project.server_side.as_str(), "required");
|
||||
assert_eq!(project.donation_urls.unwrap()[0].url, "https://patreon.com");
|
||||
|
||||
// Cleanup test db
|
||||
test_env.cleanup().await;
|
||||
assert_eq!(project.slug.unwrap(), "newslug");
|
||||
assert_eq!(project.title, "New successful title");
|
||||
assert_eq!(project.description, "New successful description");
|
||||
assert_eq!(project.body, "New successful body");
|
||||
assert_eq!(project.categories, vec![DUMMY_CATEGORIES[0]]);
|
||||
assert_eq!(project.license.id, "MIT");
|
||||
assert_eq!(project.issues_url, Some("https://github.com".to_string()));
|
||||
assert_eq!(project.discord_url, Some("https://discord.gg".to_string()));
|
||||
assert_eq!(project.wiki_url, Some("https://wiki.com".to_string()));
|
||||
assert_eq!(project.client_side.as_str(), "optional");
|
||||
assert_eq!(project.server_side.as_str(), "required");
|
||||
assert_eq!(project.donation_urls.unwrap()[0].url, "https://patreon.com");
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use crate::common::api_v2::ApiV2;
|
||||
use crate::common::environment::with_test_environment;
|
||||
use crate::common::environment::TestEnvironment;
|
||||
use crate::common::scopes::ScopeTest;
|
||||
use actix_web::test;
|
||||
@@ -10,100 +12,98 @@ use serde_json::json;
|
||||
// Project version creation scopes
|
||||
#[actix_rt::test]
|
||||
pub async fn project_version_create_scopes() {
|
||||
let test_env = TestEnvironment::build(None).await;
|
||||
|
||||
// Create project
|
||||
let create_project = Scopes::PROJECT_CREATE;
|
||||
let json_data = json!(
|
||||
{
|
||||
"title": "Test_Add_Project project",
|
||||
"slug": "demo",
|
||||
"description": "Example description.",
|
||||
"body": "Example body.",
|
||||
"initial_versions": [{
|
||||
"file_parts": ["basic-mod.jar"],
|
||||
"version_number": "1.2.3",
|
||||
"version_title": "start",
|
||||
"dependencies": [],
|
||||
"game_versions": ["1.20.1"] ,
|
||||
"client_side": "required",
|
||||
"server_side": "optional",
|
||||
"release_channel": "release",
|
||||
"loaders": ["fabric"],
|
||||
"featured": true
|
||||
}],
|
||||
"categories": [],
|
||||
"license_id": "MIT"
|
||||
}
|
||||
);
|
||||
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()),
|
||||
};
|
||||
let file_segment = MultipartSegment {
|
||||
name: "basic-mod.jar".to_string(),
|
||||
filename: Some("basic-mod.jar".to_string()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/basic-mod.jar").to_vec(),
|
||||
),
|
||||
};
|
||||
|
||||
let req_gen = || {
|
||||
test::TestRequest::post()
|
||||
.uri("/v3/project")
|
||||
.set_multipart(vec![json_segment.clone(), file_segment.clone()])
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
.test(req_gen, create_project)
|
||||
.await
|
||||
.unwrap();
|
||||
let project_id = success["id"].as_str().unwrap();
|
||||
|
||||
// Add version to project
|
||||
let create_version = Scopes::VERSION_CREATE;
|
||||
let json_data = json!(
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
// Create project
|
||||
let create_project = Scopes::PROJECT_CREATE;
|
||||
let json_data = json!(
|
||||
{
|
||||
"project_id": project_id,
|
||||
"file_parts": ["basic-mod-different.jar"],
|
||||
"version_number": "1.2.3.4",
|
||||
"version_title": "start",
|
||||
"dependencies": [],
|
||||
"game_versions": ["1.20.1"] ,
|
||||
"client_side": "required",
|
||||
"server_side": "optional",
|
||||
"release_channel": "release",
|
||||
"loaders": ["fabric"],
|
||||
"featured": true
|
||||
"title": "Test_Add_Project project",
|
||||
"slug": "demo",
|
||||
"description": "Example description.",
|
||||
"body": "Example body.",
|
||||
"initial_versions": [{
|
||||
"file_parts": ["basic-mod.jar"],
|
||||
"version_number": "1.2.3",
|
||||
"version_title": "start",
|
||||
"dependencies": [],
|
||||
"game_versions": ["1.20.1"] ,
|
||||
"client_side": "required",
|
||||
"server_side": "optional",
|
||||
"release_channel": "release",
|
||||
"loaders": ["fabric"],
|
||||
"featured": true
|
||||
}],
|
||||
"categories": [],
|
||||
"license_id": "MIT"
|
||||
}
|
||||
);
|
||||
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()),
|
||||
};
|
||||
let file_segment = MultipartSegment {
|
||||
name: "basic-mod-different.jar".to_string(),
|
||||
filename: Some("basic-mod.jar".to_string()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/basic-mod-different.jar").to_vec(),
|
||||
),
|
||||
};
|
||||
);
|
||||
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()),
|
||||
};
|
||||
let file_segment = MultipartSegment {
|
||||
name: "basic-mod.jar".to_string(),
|
||||
filename: Some("basic-mod.jar".to_string()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/basic-mod.jar").to_vec(),
|
||||
),
|
||||
};
|
||||
|
||||
let req_gen = || {
|
||||
test::TestRequest::post()
|
||||
.uri("/v3/version")
|
||||
.set_multipart(vec![json_segment.clone(), file_segment.clone()])
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, create_version)
|
||||
.await
|
||||
.unwrap();
|
||||
let req_gen = || {
|
||||
test::TestRequest::post()
|
||||
.uri("/v3/project")
|
||||
.set_multipart(vec![json_segment.clone(), file_segment.clone()])
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
.test(req_gen, create_project)
|
||||
.await
|
||||
.unwrap();
|
||||
let project_id = success["id"].as_str().unwrap();
|
||||
|
||||
// Cleanup test db
|
||||
test_env.cleanup().await;
|
||||
// Add version to project
|
||||
let create_version = Scopes::VERSION_CREATE;
|
||||
let json_data = json!(
|
||||
{
|
||||
"project_id": project_id,
|
||||
"file_parts": ["basic-mod-different.jar"],
|
||||
"version_number": "1.2.3.4",
|
||||
"version_title": "start",
|
||||
"dependencies": [],
|
||||
"game_versions": ["1.20.1"] ,
|
||||
"client_side": "required",
|
||||
"server_side": "optional",
|
||||
"release_channel": "release",
|
||||
"loaders": ["fabric"],
|
||||
"featured": true
|
||||
}
|
||||
);
|
||||
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()),
|
||||
};
|
||||
let file_segment = MultipartSegment {
|
||||
name: "basic-mod-different.jar".to_string(),
|
||||
filename: Some("basic-mod.jar".to_string()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/basic-mod-different.jar").to_vec(),
|
||||
),
|
||||
};
|
||||
|
||||
let req_gen = || {
|
||||
test::TestRequest::post()
|
||||
.uri("/v3/version")
|
||||
.set_multipart(vec![json_segment.clone(), file_segment.clone()])
|
||||
};
|
||||
ScopeTest::new(&test_env)
|
||||
.test(req_gen, create_version)
|
||||
.await
|
||||
.unwrap();
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use crate::common::api_v2::request_data;
|
||||
use crate::common::api_v2::request_data::get_public_version_creation_data;
|
||||
use crate::common::api_v2::request_data::ProjectCreationRequestData;
|
||||
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::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 futures::stream::StreamExt;
|
||||
use labrinth::models::ids::base62_impl::parse_base62;
|
||||
@@ -17,283 +19,285 @@ async fn search_projects() {
|
||||
// It should drastically simplify this function
|
||||
|
||||
// Test setup and dummy data
|
||||
let test_env = TestEnvironment::build(Some(10)).await;
|
||||
let api = &test_env.v2;
|
||||
let test_name = test_env.db.database_name.clone();
|
||||
with_test_environment(Some(10), |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
let test_name = test_env.db.database_name.clone();
|
||||
|
||||
// Add dummy projects of various categories for searchability
|
||||
let mut project_creation_futures = vec![];
|
||||
// Add dummy projects of various categories for searchability
|
||||
let mut project_creation_futures = vec![];
|
||||
|
||||
let create_async_future =
|
||||
|id: u64,
|
||||
pat: &'static str,
|
||||
is_modpack: bool,
|
||||
modify_json: Box<dyn Fn(&mut serde_json::Value)>| {
|
||||
let slug = format!("{test_name}-searchable-project-{id}");
|
||||
let create_async_future =
|
||||
|id: u64,
|
||||
pat: &'static str,
|
||||
is_modpack: bool,
|
||||
modify_json: Option<json_patch::Patch>| {
|
||||
let slug = format!("{test_name}-searchable-project-{id}");
|
||||
|
||||
let jar = if is_modpack {
|
||||
TestFile::build_random_mrpack()
|
||||
} else {
|
||||
TestFile::build_random_jar()
|
||||
let jar = if is_modpack {
|
||||
TestFile::build_random_mrpack()
|
||||
} else {
|
||||
TestFile::build_random_jar()
|
||||
};
|
||||
async move {
|
||||
// Add a project- simple, should work.
|
||||
let req = api.add_public_project(&slug, Some(jar), modify_json, pat);
|
||||
let (project, _) = req.await;
|
||||
|
||||
// Approve, so that the project is searchable
|
||||
let resp = api
|
||||
.edit_project(
|
||||
&project.id.to_string(),
|
||||
json!({
|
||||
"status": "approved"
|
||||
}),
|
||||
MOD_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
(project.id.0, id)
|
||||
}
|
||||
};
|
||||
let mut basic_project_json =
|
||||
request_data::get_public_project_creation_data_json(&slug, Some(&jar));
|
||||
modify_json(&mut basic_project_json);
|
||||
|
||||
let basic_project_multipart =
|
||||
request_data::get_public_creation_data_multipart(&basic_project_json, Some(&jar));
|
||||
// Add a project- simple, should work.
|
||||
let req = api.add_public_project(
|
||||
ProjectCreationRequestData {
|
||||
slug,
|
||||
jar: Some(jar),
|
||||
segment_data: basic_project_multipart,
|
||||
},
|
||||
pat,
|
||||
);
|
||||
async move {
|
||||
let (project, _) = req.await;
|
||||
// Test project 0
|
||||
let id = 0;
|
||||
let modify_json = serde_json::from_value(json!([
|
||||
{ "op": "add", "path": "/categories", "value": DUMMY_CATEGORIES[4..6] },
|
||||
{ "op": "add", "path": "/server_side", "value": "required" },
|
||||
{ "op": "add", "path": "/license_id", "value": "LGPL-3.0-or-later" },
|
||||
]))
|
||||
.unwrap();
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
USER_USER_PAT,
|
||||
false,
|
||||
Some(modify_json),
|
||||
));
|
||||
|
||||
// Approve, so that the project is searchable
|
||||
let resp = api
|
||||
.edit_project(
|
||||
&project.id.to_string(),
|
||||
json!({
|
||||
"status": "approved"
|
||||
}),
|
||||
MOD_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
(project.id.0, id)
|
||||
}
|
||||
};
|
||||
// Test project 1
|
||||
let id = 1;
|
||||
let modify_json = serde_json::from_value(json!([
|
||||
{ "op": "add", "path": "/categories", "value": DUMMY_CATEGORIES[0..2] },
|
||||
{ "op": "add", "path": "/client_side", "value": "optional" },
|
||||
]))
|
||||
.unwrap();
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
USER_USER_PAT,
|
||||
false,
|
||||
Some(modify_json),
|
||||
));
|
||||
|
||||
// Test project 0
|
||||
let id = 0;
|
||||
let modify_json = |json: &mut serde_json::Value| {
|
||||
json["categories"] = json!(DUMMY_CATEGORIES[4..6]);
|
||||
json["server_side"] = json!("required");
|
||||
json["license_id"] = json!("LGPL-3.0-or-later");
|
||||
};
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
USER_USER_PAT,
|
||||
false,
|
||||
Box::new(modify_json),
|
||||
));
|
||||
// Test project 2
|
||||
let id = 2;
|
||||
let modify_json = serde_json::from_value(json!([
|
||||
{ "op": "add", "path": "/categories", "value": DUMMY_CATEGORIES[0..2] },
|
||||
{ "op": "add", "path": "/server_side", "value": "required" },
|
||||
{ "op": "add", "path": "/title", "value": "Mysterious Project" },
|
||||
]))
|
||||
.unwrap();
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
USER_USER_PAT,
|
||||
false,
|
||||
Some(modify_json),
|
||||
));
|
||||
|
||||
// Test project 1
|
||||
let id = 1;
|
||||
let modify_json = |json: &mut serde_json::Value| {
|
||||
json["categories"] = json!(DUMMY_CATEGORIES[0..2]);
|
||||
json["client_side"] = json!("optional");
|
||||
};
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
USER_USER_PAT,
|
||||
false,
|
||||
Box::new(modify_json),
|
||||
));
|
||||
// Test project 3
|
||||
let id = 3;
|
||||
let modify_json = serde_json::from_value(json!([
|
||||
{ "op": "add", "path": "/categories", "value": DUMMY_CATEGORIES[0..3] },
|
||||
{ "op": "add", "path": "/server_side", "value": "required" },
|
||||
{ "op": "add", "path": "/initial_versions/0/game_versions", "value": ["1.20.4"] },
|
||||
{ "op": "add", "path": "/title", "value": "Mysterious Project" },
|
||||
{ "op": "add", "path": "/license_id", "value": "LicenseRef-All-Rights-Reserved" },
|
||||
]))
|
||||
.unwrap();
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
FRIEND_USER_PAT,
|
||||
false,
|
||||
Some(modify_json),
|
||||
));
|
||||
|
||||
// Test project 2
|
||||
let id = 2;
|
||||
let modify_json = |json: &mut serde_json::Value| {
|
||||
json["categories"] = json!(DUMMY_CATEGORIES[0..2]);
|
||||
json["server_side"] = json!("required");
|
||||
json["title"] = json!("Mysterious Project");
|
||||
};
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
USER_USER_PAT,
|
||||
false,
|
||||
Box::new(modify_json),
|
||||
));
|
||||
// Test project 4
|
||||
let id = 4;
|
||||
let modify_json = serde_json::from_value(json!([
|
||||
{ "op": "add", "path": "/categories", "value": DUMMY_CATEGORIES[0..3] },
|
||||
{ "op": "add", "path": "/client_side", "value": "optional" },
|
||||
{ "op": "add", "path": "/initial_versions/0/game_versions", "value": ["1.20.5"] },
|
||||
]))
|
||||
.unwrap();
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
USER_USER_PAT,
|
||||
true,
|
||||
Some(modify_json),
|
||||
));
|
||||
|
||||
// Test project 3
|
||||
let id = 3;
|
||||
let modify_json = |json: &mut serde_json::Value| {
|
||||
json["categories"] = json!(DUMMY_CATEGORIES[0..3]);
|
||||
json["server_side"] = json!("required");
|
||||
json["initial_versions"][0]["game_versions"] = json!(["1.20.4"]);
|
||||
json["title"] = json!("Mysterious Project");
|
||||
json["license_id"] = json!("LicenseRef-All-Rights-Reserved"); // closed source
|
||||
};
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
FRIEND_USER_PAT,
|
||||
false,
|
||||
Box::new(modify_json),
|
||||
));
|
||||
// Test project 5
|
||||
let id = 5;
|
||||
let modify_json = serde_json::from_value(json!([
|
||||
{ "op": "add", "path": "/categories", "value": DUMMY_CATEGORIES[5..6] },
|
||||
{ "op": "add", "path": "/client_side", "value": "optional" },
|
||||
{ "op": "add", "path": "/initial_versions/0/game_versions", "value": ["1.20.5"] },
|
||||
{ "op": "add", "path": "/license_id", "value": "LGPL-3.0-or-later" },
|
||||
]))
|
||||
.unwrap();
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
USER_USER_PAT,
|
||||
false,
|
||||
Some(modify_json),
|
||||
));
|
||||
|
||||
// Test project 4
|
||||
let id = 4;
|
||||
let modify_json = |json: &mut serde_json::Value| {
|
||||
json["categories"] = json!(DUMMY_CATEGORIES[0..3]);
|
||||
json["client_side"] = json!("optional");
|
||||
json["initial_versions"][0]["game_versions"] = json!(["1.20.5"]);
|
||||
};
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
USER_USER_PAT,
|
||||
true,
|
||||
Box::new(modify_json),
|
||||
));
|
||||
// Test project 6
|
||||
let id = 6;
|
||||
let modify_json = serde_json::from_value(json!([
|
||||
{ "op": "add", "path": "/categories", "value": DUMMY_CATEGORIES[5..6] },
|
||||
{ "op": "add", "path": "/client_side", "value": "optional" },
|
||||
{ "op": "add", "path": "/server_side", "value": "required" },
|
||||
{ "op": "add", "path": "/license_id", "value": "LGPL-3.0-or-later" },
|
||||
]))
|
||||
.unwrap();
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
FRIEND_USER_PAT,
|
||||
false,
|
||||
Some(modify_json),
|
||||
));
|
||||
|
||||
// Test project 5
|
||||
let id = 5;
|
||||
let modify_json = |json: &mut serde_json::Value| {
|
||||
json["categories"] = json!(DUMMY_CATEGORIES[5..6]);
|
||||
json["client_side"] = json!("optional");
|
||||
json["initial_versions"][0]["game_versions"] = json!(["1.20.5"]);
|
||||
json["license_id"] = json!("LGPL-3.0-or-later");
|
||||
};
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
USER_USER_PAT,
|
||||
false,
|
||||
Box::new(modify_json),
|
||||
));
|
||||
// Test project 7 (testing the search bug)
|
||||
// This project has an initial private forge version that is 1.20.3, and a fabric 1.20.5 version.
|
||||
// This means that a search for fabric + 1.20.3 or forge + 1.20.5 should not return this project.
|
||||
let id = 7;
|
||||
let modify_json = serde_json::from_value(json!([
|
||||
{ "op": "add", "path": "/categories", "value": DUMMY_CATEGORIES[5..6] },
|
||||
{ "op": "add", "path": "/client_side", "value": "optional" },
|
||||
{ "op": "add", "path": "/server_side", "value": "required" },
|
||||
{ "op": "add", "path": "/license_id", "value": "LGPL-3.0-or-later" },
|
||||
{ "op": "add", "path": "/initial_versions/0/loaders", "value": ["forge"] },
|
||||
{ "op": "add", "path": "/initial_versions/0/game_versions", "value": ["1.20.2"] },
|
||||
]))
|
||||
.unwrap();
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
USER_USER_PAT,
|
||||
false,
|
||||
Some(modify_json),
|
||||
));
|
||||
|
||||
// Test project 6
|
||||
let id = 6;
|
||||
let modify_json = |json: &mut serde_json::Value| {
|
||||
json["categories"] = json!(DUMMY_CATEGORIES[5..6]);
|
||||
json["client_side"] = json!("optional");
|
||||
json["server_side"] = json!("required");
|
||||
json["license_id"] = json!("LGPL-3.0-or-later");
|
||||
};
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
FRIEND_USER_PAT,
|
||||
false,
|
||||
Box::new(modify_json),
|
||||
));
|
||||
// Await all project creation
|
||||
// Returns a mapping of:
|
||||
// project id -> test id
|
||||
let id_conversion: Arc<HashMap<u64, u64>> = Arc::new(
|
||||
futures::future::join_all(project_creation_futures)
|
||||
.await
|
||||
.into_iter()
|
||||
.collect(),
|
||||
);
|
||||
|
||||
// Test project 7 (testing the search bug)
|
||||
// This project has an initial private forge version that is 1.20.3, and a fabric 1.20.5 version.
|
||||
// This means that a search for fabric + 1.20.3 or forge + 1.20.5 should not return this project.
|
||||
let id = 7;
|
||||
let modify_json = |json: &mut serde_json::Value| {
|
||||
json["categories"] = json!(DUMMY_CATEGORIES[5..6]);
|
||||
json["client_side"] = json!("optional");
|
||||
json["server_side"] = json!("required");
|
||||
json["license_id"] = json!("LGPL-3.0-or-later");
|
||||
json["initial_versions"][0]["loaders"] = json!(["forge"]);
|
||||
json["initial_versions"][0]["game_versions"] = json!(["1.20.2"]);
|
||||
};
|
||||
project_creation_futures.push(create_async_future(
|
||||
id,
|
||||
USER_USER_PAT,
|
||||
false,
|
||||
Box::new(modify_json),
|
||||
));
|
||||
|
||||
// Await all project creation
|
||||
// Returns a mapping of:
|
||||
// project id -> test id
|
||||
let id_conversion: Arc<HashMap<u64, u64>> = Arc::new(
|
||||
futures::future::join_all(project_creation_futures)
|
||||
.await
|
||||
.into_iter()
|
||||
.collect(),
|
||||
);
|
||||
|
||||
// Create a second version for project 7
|
||||
let project_7 = api
|
||||
.get_project_deserialized(&format!("{test_name}-searchable-project-7"), USER_USER_PAT)
|
||||
// Create a second version for project 7
|
||||
let project_7 = api
|
||||
.get_project_deserialized(&format!("{test_name}-searchable-project-7"), USER_USER_PAT)
|
||||
.await;
|
||||
api.add_public_version(
|
||||
project_7.id,
|
||||
"1.0.0",
|
||||
TestFile::build_random_jar(),
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
api.add_public_version(
|
||||
get_public_version_creation_data(project_7.id, "1.0.0", TestFile::build_random_jar()),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
|
||||
// Pairs of:
|
||||
// 1. vec of search facets
|
||||
// 2. expected project ids to be returned by this search
|
||||
let pairs = vec![
|
||||
(json!([["categories:fabric"]]), vec![0, 1, 2, 3, 4, 5, 6, 7]),
|
||||
(json!([["categories:forge"]]), vec![7]),
|
||||
(
|
||||
json!([["categories:fabric", "categories:forge"]]),
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7],
|
||||
),
|
||||
(json!([["categories:fabric"], ["categories:forge"]]), vec![]),
|
||||
(
|
||||
json!([
|
||||
["categories:fabric"],
|
||||
[&format!("categories:{}", DUMMY_CATEGORIES[0])],
|
||||
]),
|
||||
vec![1, 2, 3, 4],
|
||||
),
|
||||
(json!([["project_types:modpack"]]), vec![4]),
|
||||
(json!([["client_side:required"]]), vec![0, 2, 3, 7]),
|
||||
(json!([["server_side:required"]]), vec![0, 2, 3, 6, 7]),
|
||||
(json!([["open_source:true"]]), vec![0, 1, 2, 4, 5, 6, 7]),
|
||||
(json!([["license:MIT"]]), vec![1, 2, 4]),
|
||||
(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]),
|
||||
// bug fix
|
||||
(
|
||||
json!([
|
||||
// Only the forge one has 1.20.2, so its true that this project 'has'
|
||||
// 1.20.2 and a fabric version, but not true that it has a 1.20.2 fabric version.
|
||||
["categories:fabric"],
|
||||
["versions:1.20.2"]
|
||||
]),
|
||||
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: Untested:
|
||||
// - downloads (not varied)
|
||||
// - color (not varied)
|
||||
// - created_timestamp (not varied)
|
||||
// - modified_timestamp (not varied)
|
||||
|
||||
// Forcibly reset the search index
|
||||
let resp = api.reset_search_index().await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
|
||||
// Test searches
|
||||
let stream = futures::stream::iter(pairs);
|
||||
stream
|
||||
.for_each_concurrent(1, |(facets, mut expected_project_ids)| {
|
||||
let id_conversion = id_conversion.clone();
|
||||
let test_name = test_name.clone();
|
||||
async move {
|
||||
let projects = api
|
||||
.search_deserialized_common(
|
||||
Some(&test_name),
|
||||
Some(facets.clone()),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
let mut found_project_ids: Vec<u64> = projects
|
||||
.hits
|
||||
.into_iter()
|
||||
.map(|p| id_conversion[&parse_base62(&p.project_id).unwrap()])
|
||||
.collect();
|
||||
expected_project_ids.sort();
|
||||
found_project_ids.sort();
|
||||
assert_eq!(found_project_ids, expected_project_ids);
|
||||
}
|
||||
})
|
||||
.await;
|
||||
})
|
||||
.await;
|
||||
|
||||
// Pairs of:
|
||||
// 1. vec of search facets
|
||||
// 2. expected project ids to be returned by this search
|
||||
let pairs = vec![
|
||||
(json!([["categories:fabric"]]), vec![0, 1, 2, 3, 4, 5, 6, 7]),
|
||||
(json!([["categories:forge"]]), vec![7]),
|
||||
(
|
||||
json!([["categories:fabric", "categories:forge"]]),
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7],
|
||||
),
|
||||
(json!([["categories:fabric"], ["categories:forge"]]), vec![]),
|
||||
(
|
||||
json!([
|
||||
["categories:fabric"],
|
||||
[&format!("categories:{}", DUMMY_CATEGORIES[0])],
|
||||
]),
|
||||
vec![1, 2, 3, 4],
|
||||
),
|
||||
(json!([["project_types:modpack"]]), vec![4]),
|
||||
(json!([["client_side:required"]]), vec![0, 2, 3, 7]),
|
||||
(json!([["server_side:required"]]), vec![0, 2, 3, 6, 7]),
|
||||
(json!([["open_source:true"]]), vec![0, 1, 2, 4, 5, 6, 7]),
|
||||
(json!([["license:MIT"]]), vec![1, 2, 4]),
|
||||
(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]),
|
||||
// bug fix
|
||||
(
|
||||
json!([
|
||||
// Only the forge one has 1.20.2, so its true that this project 'has'
|
||||
// 1.20.2 and a fabric version, but not true that it has a 1.20.2 fabric version.
|
||||
["categories:fabric"],
|
||||
["versions:1.20.2"]
|
||||
]),
|
||||
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: Untested:
|
||||
// - downloads (not varied)
|
||||
// - color (not varied)
|
||||
// - created_timestamp (not varied)
|
||||
// - modified_timestamp (not varied)
|
||||
|
||||
// Forcibly reset the search index
|
||||
let resp = api.reset_search_index().await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
|
||||
// Test searches
|
||||
let stream = futures::stream::iter(pairs);
|
||||
stream
|
||||
.for_each_concurrent(1, |(facets, mut expected_project_ids)| {
|
||||
let id_conversion = id_conversion.clone();
|
||||
let test_name = test_name.clone();
|
||||
async move {
|
||||
let projects = api
|
||||
.search_deserialized(Some(&test_name), Some(facets.clone()), USER_USER_PAT)
|
||||
.await;
|
||||
let mut found_project_ids: Vec<u64> = projects
|
||||
.hits
|
||||
.into_iter()
|
||||
.map(|p| id_conversion[&parse_base62(&p.project_id).unwrap()])
|
||||
.collect();
|
||||
expected_project_ids.sort();
|
||||
found_project_ids.sort();
|
||||
assert_eq!(found_project_ids, expected_project_ids);
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
// Cleanup test db
|
||||
test_env.cleanup().await;
|
||||
}
|
||||
|
||||
125
tests/v2/tags.rs
125
tests/v2/tags.rs
@@ -1,74 +1,77 @@
|
||||
use crate::common::environment::TestEnvironment;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::common::{
|
||||
api_v2::ApiV2,
|
||||
environment::{with_test_environment, TestEnvironment},
|
||||
};
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn get_tags() {
|
||||
let test_env = TestEnvironment::build(None).await;
|
||||
let api = &test_env.v2;
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
let game_versions = api.get_game_versions_deserialized().await;
|
||||
let loaders = api.get_loaders_deserialized().await;
|
||||
let side_types = api.get_side_types_deserialized().await;
|
||||
let categories = api.get_categories_deserialized().await;
|
||||
|
||||
let game_versions = api.get_game_versions_deserialized().await;
|
||||
let loaders = api.get_loaders_deserialized().await;
|
||||
let side_types = api.get_side_types_deserialized().await;
|
||||
let categories = api.get_categories_deserialized().await;
|
||||
|
||||
// These tests match dummy data and will need to be updated if the dummy data changes;
|
||||
let game_version_versions = game_versions
|
||||
.into_iter()
|
||||
.map(|x| x.version)
|
||||
.collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
game_version_versions,
|
||||
[
|
||||
"1.20.1",
|
||||
"1.20.2",
|
||||
"1.20.3",
|
||||
"1.20.4",
|
||||
"1.20.5",
|
||||
"Ordering_Negative1",
|
||||
"Ordering_Positive100"
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
|
||||
let loader_names = loaders.into_iter().map(|x| x.name).collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
loader_names,
|
||||
["fabric", "forge", "mrpack"]
|
||||
// These tests match dummy data and will need to be updated if the dummy data changes;
|
||||
let game_version_versions = game_versions
|
||||
.into_iter()
|
||||
.map(|x| x.version)
|
||||
.collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
game_version_versions,
|
||||
[
|
||||
"1.20.1",
|
||||
"1.20.2",
|
||||
"1.20.3",
|
||||
"1.20.4",
|
||||
"1.20.5",
|
||||
"Ordering_Negative1",
|
||||
"Ordering_Positive100"
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
);
|
||||
|
||||
let side_type_names = side_types.into_iter().collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
side_type_names,
|
||||
["unknown", "required", "optional", "unsupported"]
|
||||
let loader_names = loaders.into_iter().map(|x| x.name).collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
loader_names,
|
||||
["fabric", "forge", "mrpack"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
|
||||
let side_type_names = side_types.into_iter().collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
side_type_names,
|
||||
["unknown", "required", "optional", "unsupported"]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
|
||||
let category_names = categories
|
||||
.into_iter()
|
||||
.map(|x| x.name)
|
||||
.collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
category_names,
|
||||
[
|
||||
"combat",
|
||||
"economy",
|
||||
"food",
|
||||
"optimization",
|
||||
"decoration",
|
||||
"mobs",
|
||||
"magic"
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
|
||||
let category_names = categories
|
||||
.into_iter()
|
||||
.map(|x| x.name)
|
||||
.collect::<HashSet<_>>();
|
||||
assert_eq!(
|
||||
category_names,
|
||||
[
|
||||
"combat",
|
||||
"economy",
|
||||
"food",
|
||||
"optimization",
|
||||
"decoration",
|
||||
"mobs",
|
||||
"magic"
|
||||
]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect()
|
||||
);
|
||||
|
||||
test_env.cleanup().await;
|
||||
);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -1,409 +1,466 @@
|
||||
use actix_web::test;
|
||||
use futures::StreamExt;
|
||||
use labrinth::models::projects::{ProjectId, VersionId};
|
||||
use labrinth::models::projects::VersionId;
|
||||
use labrinth::{
|
||||
models::{
|
||||
ids::base62_impl::parse_base62,
|
||||
projects::{Loader, VersionStatus, VersionType},
|
||||
},
|
||||
models::projects::{Loader, VersionStatus, VersionType},
|
||||
routes::v2::version_file::FileUpdateData,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::common::api_v2::request_data::get_public_version_creation_data;
|
||||
use crate::common::api_common::{ApiProject, ApiVersion};
|
||||
use crate::common::api_v2::ApiV2;
|
||||
use crate::common::environment::{with_test_environment, TestEnvironment};
|
||||
use crate::common::{
|
||||
database::{ENEMY_USER_PAT, USER_USER_PAT},
|
||||
dummy_data::TestFile,
|
||||
environment::TestEnvironment,
|
||||
};
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn test_patch_version() {
|
||||
let test_env = TestEnvironment::build(None).await;
|
||||
let api = &test_env.v2;
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
|
||||
let alpha_version_id = &test_env.dummy.as_ref().unwrap().project_alpha.version_id;
|
||||
let alpha_version_id = &test_env.dummy.as_ref().unwrap().project_alpha.version_id;
|
||||
|
||||
// // First, we do some patch requests that should fail.
|
||||
// // Failure because the user is not authorized.
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"name": "test 1",
|
||||
}),
|
||||
ENEMY_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
|
||||
// Failure because these are illegal requested statuses for a normal user.
|
||||
for req in ["unknown", "scheduled"] {
|
||||
// // First, we do some patch requests that should fail.
|
||||
// // Failure because the user is not authorized.
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"status": req,
|
||||
// requested status it not set here, but in /schedule
|
||||
"name": "test 1",
|
||||
}),
|
||||
ENEMY_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
|
||||
// Failure because these are illegal requested statuses for a normal user.
|
||||
for req in ["unknown", "scheduled"] {
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"status": req,
|
||||
// requested status it not set here, but in /schedule
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
}
|
||||
|
||||
// Sucessful request to patch many fields.
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"name": "new version name",
|
||||
"version_number": "1.3.0",
|
||||
"changelog": "new changelog",
|
||||
"version_type": "beta",
|
||||
// // "dependencies": [], TODO: test this
|
||||
"game_versions": ["1.20.5"],
|
||||
"loaders": ["forge"],
|
||||
"featured": false,
|
||||
// "primary_file": [], TODO: test this
|
||||
// // "downloads": 0, TODO: moderator exclusive
|
||||
"status": "draft",
|
||||
// // "filetypes": ["jar"], TODO: test this
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
}
|
||||
assert_eq!(resp.status(), 204);
|
||||
|
||||
// Sucessful request to patch many fields.
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"name": "new version name",
|
||||
"version_number": "1.3.0",
|
||||
"changelog": "new changelog",
|
||||
"version_type": "beta",
|
||||
// // "dependencies": [], TODO: test this
|
||||
"game_versions": ["1.20.5"],
|
||||
"loaders": ["forge"],
|
||||
"featured": false,
|
||||
// "primary_file": [], TODO: test this
|
||||
// // "downloads": 0, TODO: moderator exclusive
|
||||
"status": "draft",
|
||||
// // "filetypes": ["jar"], TODO: test this
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(version.name, "new version name");
|
||||
assert_eq!(version.version_number, "1.3.0");
|
||||
assert_eq!(version.changelog, "new changelog");
|
||||
assert_eq!(
|
||||
version.version_type,
|
||||
serde_json::from_str::<VersionType>("\"beta\"").unwrap()
|
||||
);
|
||||
assert_eq!(version.game_versions, vec!["1.20.5"]);
|
||||
assert_eq!(version.loaders, vec![Loader("forge".to_string())]);
|
||||
assert!(!version.featured);
|
||||
assert_eq!(version.status, VersionStatus::from_string("draft"));
|
||||
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(version.name, "new version name");
|
||||
assert_eq!(version.version_number, "1.3.0");
|
||||
assert_eq!(version.changelog, "new changelog");
|
||||
assert_eq!(
|
||||
version.version_type,
|
||||
serde_json::from_str::<VersionType>("\"beta\"").unwrap()
|
||||
);
|
||||
assert_eq!(version.game_versions, vec!["1.20.5"]);
|
||||
assert_eq!(version.loaders, vec![Loader("forge".to_string())]);
|
||||
assert!(!version.featured);
|
||||
assert_eq!(version.status, VersionStatus::from_string("draft"));
|
||||
// These ones are checking the v2-v3 rerouting, we eneusre that only 'game_versions'
|
||||
// works as expected, as well as only 'loaders'
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"game_versions": ["1.20.1", "1.20.2", "1.20.4"],
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
|
||||
// These ones are checking the v2-v3 rerouting, we eneusre that only 'game_versions'
|
||||
// works as expected, as well as only 'loaders'
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"game_versions": ["1.20.1", "1.20.2", "1.20.4"],
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(version.game_versions, vec!["1.20.1", "1.20.2", "1.20.4"]);
|
||||
assert_eq!(version.loaders, vec![Loader("forge".to_string())]); // From last patch
|
||||
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(version.game_versions, vec!["1.20.1", "1.20.2", "1.20.4"]);
|
||||
assert_eq!(version.loaders, vec![Loader("forge".to_string())]); // From last patch
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"loaders": ["fabric"],
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
|
||||
let resp = api
|
||||
.edit_version(
|
||||
alpha_version_id,
|
||||
json!({
|
||||
"loaders": ["fabric"],
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(version.game_versions, vec!["1.20.1", "1.20.2", "1.20.4"]); // From last patch
|
||||
assert_eq!(version.loaders, vec![Loader("fabric".to_string())]);
|
||||
|
||||
// Cleanup test db
|
||||
test_env.cleanup().await;
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(version.game_versions, vec!["1.20.1", "1.20.2", "1.20.4"]); // From last patch
|
||||
assert_eq!(version.loaders, vec![Loader("fabric".to_string())]);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn version_updates() {
|
||||
// Test setup and dummy data
|
||||
let test_env = TestEnvironment::build(None).await;
|
||||
let api = &test_env.v2;
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
let api = &test_env.api;
|
||||
|
||||
let alpha_project_id: &String = &test_env.dummy.as_ref().unwrap().project_alpha.project_id;
|
||||
let alpha_version_id = &test_env.dummy.as_ref().unwrap().project_alpha.version_id;
|
||||
let beta_version_id = &test_env.dummy.as_ref().unwrap().project_beta.version_id;
|
||||
let alpha_version_hash = &test_env.dummy.as_ref().unwrap().project_alpha.file_hash;
|
||||
let beta_version_hash = &test_env.dummy.as_ref().unwrap().project_beta.file_hash;
|
||||
let alpha_project_id: &String = &test_env.dummy.as_ref().unwrap().project_alpha.project_id;
|
||||
let alpha_project_id_parsed = test_env
|
||||
.dummy
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.project_alpha
|
||||
.project_id_parsed;
|
||||
let alpha_version_id = &test_env.dummy.as_ref().unwrap().project_alpha.version_id;
|
||||
let beta_version_id = &test_env.dummy.as_ref().unwrap().project_beta.version_id;
|
||||
let alpha_version_hash = &test_env.dummy.as_ref().unwrap().project_alpha.file_hash;
|
||||
let beta_version_hash = &test_env.dummy.as_ref().unwrap().project_beta.file_hash;
|
||||
|
||||
// Quick test, using get version from hash
|
||||
let version = api
|
||||
.get_version_from_hash_deserialized(alpha_version_hash, "sha1", USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(&version.id.to_string(), alpha_version_id);
|
||||
|
||||
// Get versions from hash
|
||||
let versions = api
|
||||
.get_versions_from_hashes_deserialized(
|
||||
&[alpha_version_hash.as_str(), beta_version_hash.as_str()],
|
||||
"sha1",
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions.len(), 2);
|
||||
assert_eq!(
|
||||
&versions[alpha_version_hash].id.to_string(),
|
||||
alpha_version_id
|
||||
);
|
||||
assert_eq!(&versions[beta_version_hash].id.to_string(), beta_version_id);
|
||||
|
||||
// When there is only the one version, there should be no updates
|
||||
let version = api
|
||||
.get_update_from_hash_deserialized(
|
||||
alpha_version_hash,
|
||||
"sha1",
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(&version.id.to_string(), alpha_version_id);
|
||||
|
||||
let versions = api
|
||||
.update_files_deserialized(
|
||||
"sha1",
|
||||
vec![alpha_version_hash.to_string()],
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions.len(), 1);
|
||||
assert_eq!(
|
||||
&versions[alpha_version_hash].id.to_string(),
|
||||
alpha_version_id
|
||||
);
|
||||
|
||||
// Add 3 new versions, 1 before, and 2 after, with differing game_version/version_types/loaders
|
||||
let mut update_ids = vec![];
|
||||
for (version_number, patch_value) in [
|
||||
(
|
||||
"0.9.9",
|
||||
json!({
|
||||
"game_versions": ["1.20.1"],
|
||||
}),
|
||||
),
|
||||
(
|
||||
"1.5.0",
|
||||
json!({
|
||||
"game_versions": ["1.20.3"],
|
||||
"loaders": ["fabric"],
|
||||
}),
|
||||
),
|
||||
(
|
||||
"1.5.1",
|
||||
json!({
|
||||
"game_versions": ["1.20.4"],
|
||||
"loaders": ["forge"],
|
||||
"version_type": "beta"
|
||||
}),
|
||||
),
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
// Quick test, using get version from hash
|
||||
let version = api
|
||||
.add_public_version(
|
||||
get_public_version_creation_data(
|
||||
ProjectId(parse_base62(alpha_project_id).unwrap()),
|
||||
version_number,
|
||||
TestFile::build_random_jar(),
|
||||
),
|
||||
.get_version_from_hash_deserialized(alpha_version_hash, "sha1", USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(&version.id.to_string(), alpha_version_id);
|
||||
|
||||
// Get versions from hash
|
||||
let versions = api
|
||||
.get_versions_from_hashes_deserialized(
|
||||
&[alpha_version_hash.as_str(), beta_version_hash.as_str()],
|
||||
"sha1",
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
update_ids.push(version.id);
|
||||
assert_eq!(versions.len(), 2);
|
||||
assert_eq!(
|
||||
&versions[alpha_version_hash].id.to_string(),
|
||||
alpha_version_id
|
||||
);
|
||||
assert_eq!(&versions[beta_version_hash].id.to_string(), beta_version_id);
|
||||
|
||||
// Patch using json
|
||||
api.edit_version(&version.id.to_string(), patch_value.clone(), USER_USER_PAT)
|
||||
.await;
|
||||
}
|
||||
|
||||
let check_expected = |game_versions: Option<Vec<String>>,
|
||||
loaders: Option<Vec<String>>,
|
||||
version_types: Option<Vec<String>>,
|
||||
result_id: Option<VersionId>| async move {
|
||||
let (success, result_id) = match result_id {
|
||||
Some(id) => (true, id),
|
||||
None => (false, VersionId(0)),
|
||||
};
|
||||
// get_update_from_hash
|
||||
let resp = api
|
||||
.get_update_from_hash(
|
||||
// When there is only the one version, there should be no updates
|
||||
let version = api
|
||||
.get_update_from_hash_deserialized_common(
|
||||
alpha_version_hash,
|
||||
"sha1",
|
||||
loaders.clone(),
|
||||
game_versions.clone(),
|
||||
version_types.clone(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(resp.status(), 200);
|
||||
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_eq!(&version.id.to_string(), alpha_version_id);
|
||||
|
||||
// update_files
|
||||
let versions = api
|
||||
.update_files_deserialized(
|
||||
.update_files_deserialized_common(
|
||||
"sha1",
|
||||
vec![alpha_version_hash.to_string()],
|
||||
loaders.clone(),
|
||||
game_versions.clone(),
|
||||
version_types.clone(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(versions.len(), 1);
|
||||
let first = versions.iter().next().unwrap();
|
||||
assert_eq!(first.1.id, result_id);
|
||||
} else {
|
||||
assert_eq!(versions.len(), 0);
|
||||
assert_eq!(versions.len(), 1);
|
||||
assert_eq!(
|
||||
&versions[alpha_version_hash].id.to_string(),
|
||||
alpha_version_id
|
||||
);
|
||||
|
||||
// Add 3 new versions, 1 before, and 2 after, with differing game_version/version_types/loaders
|
||||
let mut update_ids = vec![];
|
||||
for (version_number, patch_value) in [
|
||||
(
|
||||
"0.9.9",
|
||||
json!({
|
||||
"game_versions": ["1.20.1"],
|
||||
}),
|
||||
),
|
||||
(
|
||||
"1.5.0",
|
||||
json!({
|
||||
"game_versions": ["1.20.3"],
|
||||
"loaders": ["fabric"],
|
||||
}),
|
||||
),
|
||||
(
|
||||
"1.5.1",
|
||||
json!({
|
||||
"game_versions": ["1.20.4"],
|
||||
"loaders": ["forge"],
|
||||
"version_type": "beta"
|
||||
}),
|
||||
),
|
||||
]
|
||||
.iter()
|
||||
{
|
||||
let version = api
|
||||
.add_public_version_deserialized_common(
|
||||
alpha_project_id_parsed,
|
||||
version_number,
|
||||
TestFile::build_random_jar(),
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
update_ids.push(version.id);
|
||||
|
||||
// Patch using json
|
||||
api.edit_version(&version.id.to_string(), patch_value.clone(), USER_USER_PAT)
|
||||
.await;
|
||||
}
|
||||
|
||||
// update_individual_files
|
||||
let hashes = vec![FileUpdateData {
|
||||
hash: alpha_version_hash.to_string(),
|
||||
loaders,
|
||||
game_versions,
|
||||
version_types: version_types.map(|v| {
|
||||
v.into_iter()
|
||||
.map(|v| serde_json::from_str(&format!("\"{v}\"")).unwrap())
|
||||
.collect()
|
||||
}),
|
||||
}];
|
||||
let versions = api
|
||||
.update_individual_files_deserialized("sha1", hashes, USER_USER_PAT)
|
||||
let check_expected = |game_versions: Option<Vec<String>>,
|
||||
loaders: Option<Vec<String>>,
|
||||
version_types: Option<Vec<String>>,
|
||||
result_id: Option<VersionId>| async move {
|
||||
let (success, result_id) = match result_id {
|
||||
Some(id) => (true, id),
|
||||
None => (false, VersionId(0)),
|
||||
};
|
||||
// get_update_from_hash
|
||||
let resp = api
|
||||
.get_update_from_hash(
|
||||
alpha_version_hash,
|
||||
"sha1",
|
||||
loaders.clone(),
|
||||
game_versions.clone(),
|
||||
version_types.clone(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(resp.status(), 200);
|
||||
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);
|
||||
}
|
||||
|
||||
// update_files
|
||||
let versions = api
|
||||
.update_files_deserialized_common(
|
||||
"sha1",
|
||||
vec![alpha_version_hash.to_string()],
|
||||
loaders.clone(),
|
||||
game_versions.clone(),
|
||||
version_types.clone(),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(versions.len(), 1);
|
||||
let first = versions.iter().next().unwrap();
|
||||
assert_eq!(first.1.id, result_id);
|
||||
} else {
|
||||
assert_eq!(versions.len(), 0);
|
||||
}
|
||||
|
||||
// update_individual_files
|
||||
let hashes = vec![FileUpdateData {
|
||||
hash: alpha_version_hash.to_string(),
|
||||
loaders,
|
||||
game_versions,
|
||||
version_types: version_types.map(|v| {
|
||||
v.into_iter()
|
||||
.map(|v| serde_json::from_str(&format!("\"{v}\"")).unwrap())
|
||||
.collect()
|
||||
}),
|
||||
}];
|
||||
let versions = api
|
||||
.update_individual_files_deserialized("sha1", hashes, USER_USER_PAT)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(versions.len(), 1);
|
||||
let first = versions.iter().next().unwrap();
|
||||
assert_eq!(first.1.id, result_id);
|
||||
} else {
|
||||
assert_eq!(versions.len(), 0);
|
||||
}
|
||||
};
|
||||
|
||||
let tests = vec![
|
||||
check_expected(
|
||||
Some(vec!["1.20.1".to_string()]),
|
||||
None,
|
||||
None,
|
||||
Some(update_ids[0]),
|
||||
),
|
||||
check_expected(
|
||||
Some(vec!["1.20.3".to_string()]),
|
||||
None,
|
||||
None,
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
check_expected(
|
||||
Some(vec!["1.20.4".to_string()]),
|
||||
None,
|
||||
None,
|
||||
Some(update_ids[2]),
|
||||
),
|
||||
// Loader restrictions
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["fabric".to_string()]),
|
||||
None,
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["forge".to_string()]),
|
||||
None,
|
||||
Some(update_ids[2]),
|
||||
),
|
||||
// Version type restrictions
|
||||
check_expected(
|
||||
None,
|
||||
None,
|
||||
Some(vec!["release".to_string()]),
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
check_expected(
|
||||
None,
|
||||
None,
|
||||
Some(vec!["beta".to_string()]),
|
||||
Some(update_ids[2]),
|
||||
),
|
||||
// Specific combination
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["fabric".to_string()]),
|
||||
Some(vec!["release".to_string()]),
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
// Impossible combination
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["fabric".to_string()]),
|
||||
Some(vec!["beta".to_string()]),
|
||||
None,
|
||||
),
|
||||
// No restrictions, should do the last one
|
||||
check_expected(None, None, None, Some(update_ids[2])),
|
||||
];
|
||||
|
||||
// Wait on all tests, 4 at a time
|
||||
futures::stream::iter(tests)
|
||||
.buffer_unordered(4)
|
||||
.collect::<Vec<_>>()
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(versions.len(), 1);
|
||||
let first = versions.iter().next().unwrap();
|
||||
assert_eq!(first.1.id, result_id);
|
||||
} else {
|
||||
assert_eq!(versions.len(), 0);
|
||||
}
|
||||
};
|
||||
|
||||
let tests = vec![
|
||||
check_expected(
|
||||
Some(vec!["1.20.1".to_string()]),
|
||||
None,
|
||||
None,
|
||||
Some(update_ids[0]),
|
||||
),
|
||||
check_expected(
|
||||
Some(vec!["1.20.3".to_string()]),
|
||||
None,
|
||||
None,
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
check_expected(
|
||||
Some(vec!["1.20.4".to_string()]),
|
||||
None,
|
||||
None,
|
||||
Some(update_ids[2]),
|
||||
),
|
||||
// Loader restrictions
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["fabric".to_string()]),
|
||||
None,
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["forge".to_string()]),
|
||||
None,
|
||||
Some(update_ids[2]),
|
||||
),
|
||||
// Version type restrictions
|
||||
check_expected(
|
||||
None,
|
||||
None,
|
||||
Some(vec!["release".to_string()]),
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
check_expected(
|
||||
None,
|
||||
None,
|
||||
Some(vec!["beta".to_string()]),
|
||||
Some(update_ids[2]),
|
||||
),
|
||||
// Specific combination
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["fabric".to_string()]),
|
||||
Some(vec!["release".to_string()]),
|
||||
Some(update_ids[1]),
|
||||
),
|
||||
// Impossible combination
|
||||
check_expected(
|
||||
None,
|
||||
Some(vec!["fabric".to_string()]),
|
||||
Some(vec!["beta".to_string()]),
|
||||
None,
|
||||
),
|
||||
// No restrictions, should do the last one
|
||||
check_expected(None, None, None, Some(update_ids[2])),
|
||||
];
|
||||
|
||||
// Wait on all tests, 4 at a time
|
||||
futures::stream::iter(tests)
|
||||
.buffer_unordered(4)
|
||||
.collect::<Vec<_>>()
|
||||
.await;
|
||||
|
||||
// We do a couple small tests for get_project_versions_deserialized as well
|
||||
// TODO: expand this more.
|
||||
let versions = api
|
||||
.get_project_versions_deserialized(
|
||||
alpha_project_id,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions.len(), 4);
|
||||
let versions = api
|
||||
.get_project_versions_deserialized(
|
||||
alpha_project_id,
|
||||
None,
|
||||
Some(vec!["forge".to_string()]),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions.len(), 1);
|
||||
|
||||
// Cleanup test db
|
||||
test_env.cleanup().await;
|
||||
// We do a couple small tests for get_project_versions_deserialized as well
|
||||
// TODO: expand this more.
|
||||
let versions = api
|
||||
.get_project_versions_deserialized_common(
|
||||
alpha_project_id,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions.len(), 4);
|
||||
let versions = api
|
||||
.get_project_versions_deserialized_common(
|
||||
alpha_project_id,
|
||||
None,
|
||||
Some(vec!["forge".to_string()]),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(versions.len(), 1);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn add_version_project_types_v2() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
|
||||
// Since v2 no longer keeps project_type at the project level but the version level,
|
||||
// we have to test that the project_type is set correctly when adding a version, if its done in separate requests.
|
||||
let api = &test_env.api;
|
||||
|
||||
// Create a project in v2 with project_type = modpack, and no initial version set.
|
||||
let (test_project, test_versions) = api
|
||||
.add_public_project("test-modpack", None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(test_versions.len(), 0); // No initial version set
|
||||
|
||||
// Get as v2 project
|
||||
let test_project = api
|
||||
.get_project_deserialized(&test_project.slug.unwrap(), USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(test_project.project_type, ""); // No project_type set, as no versions are set
|
||||
// This is a known difference between older v2 ,but is acceptable.
|
||||
// This would be the appropriate test on older v2:
|
||||
// assert_eq!(test_project.project_type, "modpack");
|
||||
|
||||
// Create a version with a modpack file attached
|
||||
let test_version = api
|
||||
.add_public_version_deserialized_common(
|
||||
test_project.id,
|
||||
"1.0.0",
|
||||
TestFile::build_random_mrpack(),
|
||||
None,
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
|
||||
// When we get the version as v2, it should display 'fabric' as the loader (and no project_type)
|
||||
let test_version = api
|
||||
.get_version_deserialized(&test_version.id.to_string(), USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(test_version.loaders, vec![Loader("fabric".to_string())]);
|
||||
|
||||
// When we get the project as v2, it should display 'modpack' as the project_type, and 'fabric' as the loader
|
||||
let test_project = api
|
||||
.get_project_deserialized(&test_project.slug.unwrap(), USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(test_project.project_type, "modpack");
|
||||
assert_eq!(test_project.loaders, vec!["fabric"]);
|
||||
|
||||
// When we get the version as v3, it should display 'mrpack' as the loader, and 'modpack' as the project_type
|
||||
// When we get the project as v3, it should display 'modpack' as the project_type, and 'mrpack' as the loader
|
||||
|
||||
// The project should be a modpack project
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user