Testing bug fixes (#788)

* fixes

* adds tests- fixes failures

* changes

* moved transaction commits/caches around

* collections nullable

* merge fixes

* sqlx prepare

* revs

* lf fixes

* made changes back

* added collections update

---------

Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
This commit is contained in:
Wyatt Verchere
2023-12-14 15:19:50 -07:00
committed by GitHub
parent 50e89ad98b
commit f939e59463
33 changed files with 494 additions and 112 deletions

View File

@@ -80,6 +80,8 @@ delegate_api_variant!(
[add_gallery_item, ServiceResponse, id_or_slug: &str, image: ImageData, featured: bool, title: Option<String>, description: Option<String>, ordering: Option<i32>, pat: Option<&str>],
[remove_gallery_item, ServiceResponse, id_or_slug: &str, image_url: &str, pat: Option<&str>],
[edit_gallery_item, ServiceResponse, id_or_slug: &str, image_url: &str, patch: HashMap<String, String>, pat: Option<&str>],
[create_report, ServiceResponse, report_type: &str, id: &str, item_type: crate::common::api_common::models::CommonItemType, body: &str, pat: Option<&str>],
[get_report, ServiceResponse, id: &str, pat: Option<&str>],
}
);

View File

@@ -1,8 +1,8 @@
use std::collections::HashMap;
use self::models::{
CommonCategoryData, CommonLoaderData, CommonNotification, CommonProject, CommonTeamMember,
CommonVersion,
CommonCategoryData, CommonItemType, CommonLoaderData, CommonNotification, CommonProject,
CommonTeamMember, CommonVersion,
};
use self::request_data::{ImageData, ProjectCreationRequestData};
use actix_web::dev::ServiceResponse;
@@ -118,6 +118,15 @@ pub trait ApiProject {
patch: HashMap<String, String>,
pat: Option<&str>,
) -> ServiceResponse;
async fn create_report(
&self,
report_type: &str,
id: &str,
item_type: CommonItemType,
body: &str,
pat: Option<&str>,
) -> ServiceResponse;
async fn get_report(&self, id: &str, pat: Option<&str>) -> ServiceResponse;
}
#[async_trait(?Send)]

View File

@@ -11,7 +11,7 @@ use labrinth::models::{
users::{User, UserId},
};
use rust_decimal::Decimal;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
// Fields shared by every version of the API.
// No struct in here should have ANY field that
@@ -119,3 +119,23 @@ pub struct CommonNotification {
pub struct CommonNotificationAction {
pub action_route: (String, String),
}
#[derive(Serialize, Deserialize, Clone)]
#[serde(rename_all = "kebab-case")]
pub enum CommonItemType {
Project,
Version,
User,
Unknown,
}
impl CommonItemType {
pub fn as_str(&self) -> &'static str {
match self {
CommonItemType::Project => "project",
CommonItemType::Version => "version",
CommonItemType::User => "user",
CommonItemType::Unknown => "unknown",
}
}
}

View File

@@ -2,7 +2,7 @@ use std::collections::HashMap;
use crate::common::{
api_common::{
models::{CommonProject, CommonVersion},
models::{CommonItemType, CommonProject, CommonVersion},
request_data::{ImageData, ProjectCreationRequestData},
Api, ApiProject, AppendsOptionalPat,
},
@@ -266,6 +266,39 @@ impl ApiProject for ApiV2 {
}
}
async fn create_report(
&self,
report_type: &str,
id: &str,
item_type: CommonItemType,
body: &str,
pat: Option<&str>,
) -> ServiceResponse {
let req = test::TestRequest::post()
.uri("/v3/report")
.append_pat(pat)
.set_json(json!(
{
"report_type": report_type,
"item_id": id,
"item_type": item_type.as_str(),
"body": body,
}
))
.to_request();
self.call(req).await
}
async fn get_report(&self, id: &str, pat: Option<&str>) -> ServiceResponse {
let req = test::TestRequest::get()
.uri(&format!("/v3/report/{id}", id = id))
.append_pat(pat)
.to_request();
self.call(req).await
}
async fn schedule_project(
&self,
id_or_slug: &str,

View File

@@ -3,7 +3,9 @@ use actix_web::{
test::{self, TestRequest},
};
use async_trait::async_trait;
use labrinth::routes::v2::tags::{CategoryData, GameVersionQueryData, LoaderData};
use labrinth::routes::v2::tags::{
CategoryData, DonationPlatformQueryData, GameVersionQueryData, LoaderData,
};
use crate::common::{
api_common::{
@@ -57,6 +59,21 @@ impl ApiV2 {
assert_eq!(resp.status(), 200);
test::read_body_json(resp).await
}
pub async fn get_donation_platforms(&self) -> ServiceResponse {
let req = TestRequest::get()
.uri("/v2/tag/donation_platform")
.append_pat(ADMIN_USER_PAT)
.to_request();
self.call(req).await
}
pub async fn get_donation_platforms_deserialized(&self) -> Vec<DonationPlatformQueryData> {
let resp = self.get_donation_platforms().await;
println!("Response: {:?}", resp.response().body());
assert_eq!(resp.status(), 200);
test::read_body_json(resp).await
}
}
#[async_trait(?Send)]

View File

@@ -17,7 +17,7 @@ use serde_json::json;
use crate::common::{
api_common::{
models::{CommonProject, CommonVersion},
models::{CommonItemType, CommonProject, CommonVersion},
request_data::{ImageData, ProjectCreationRequestData},
Api, ApiProject, AppendsOptionalPat,
},
@@ -219,6 +219,39 @@ impl ApiProject for ApiV3 {
}
}
async fn create_report(
&self,
report_type: &str,
id: &str,
item_type: CommonItemType,
body: &str,
pat: Option<&str>,
) -> ServiceResponse {
let req = test::TestRequest::post()
.uri("/v3/report")
.append_pat(pat)
.set_json(json!(
{
"report_type": report_type,
"item_id": id,
"item_type": item_type.as_str(),
"body": body,
}
))
.to_request();
self.call(req).await
}
async fn get_report(&self, id: &str, pat: Option<&str>) -> ServiceResponse {
let req = test::TestRequest::get()
.uri(&format!("/v3/report/{id}", id = id))
.append_pat(pat)
.to_request();
self.call(req).await
}
async fn schedule_project(
&self,
id_or_slug: &str,

View File

@@ -18,6 +18,7 @@ use labrinth::models::teams::ProjectPermissions;
use labrinth::util::actix::{MultipartSegment, MultipartSegmentData};
use serde_json::json;
use crate::common::api_common::models::CommonItemType;
use crate::common::api_common::request_data::ProjectCreationRequestData;
use crate::common::api_common::{ApiProject, ApiTeams, ApiVersion, AppendsOptionalPat};
use crate::common::dummy_data::{DummyImage, TestFile};
@@ -590,6 +591,94 @@ pub async fn test_bulk_edit_links() {
.await;
}
#[actix_rt::test]
async fn delete_project_with_report() {
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
let api = &test_env.api;
let alpha_project_id: &str = &test_env.dummy.as_ref().unwrap().project_alpha.project_id;
let beta_project_id: &str = &test_env.dummy.as_ref().unwrap().project_beta.project_id;
// Create a report for the project
let resp = api
.create_report(
"copyright",
alpha_project_id,
CommonItemType::Project,
"Hey! This is my project, copied without permission!",
ENEMY_USER_PAT, // Enemy makes a report
)
.await;
assert_eq!(resp.status(), StatusCode::OK);
let value = test::read_body_json::<serde_json::Value, _>(resp).await;
let alpha_report_id = value["id"].as_str().unwrap();
// Confirm existence
let resp = api
.get_report(
alpha_report_id,
ENEMY_USER_PAT, // Enemy makes a report
)
.await;
assert_eq!(resp.status(), StatusCode::OK);
// Do the same for beta
let resp = api
.create_report(
"copyright",
beta_project_id,
CommonItemType::Project,
"Hey! This is my project, copied without permission!",
ENEMY_USER_PAT, // Enemy makes a report
)
.await;
assert_eq!(resp.status(), StatusCode::OK);
let value = test::read_body_json::<serde_json::Value, _>(resp).await;
let beta_report_id = value["id"].as_str().unwrap();
// Delete the project
let resp = api.remove_project(alpha_project_id, USER_USER_PAT).await;
assert_eq!(resp.status(), StatusCode::NO_CONTENT);
// Confirm that the project is gone from the cache
let mut redis_pool = test_env.db.redis_pool.connect().await.unwrap();
assert_eq!(
redis_pool
.get(PROJECTS_SLUGS_NAMESPACE, "demo")
.await
.unwrap()
.and_then(|x| x.parse::<i64>().ok()),
None
);
assert_eq!(
redis_pool
.get(PROJECTS_SLUGS_NAMESPACE, alpha_project_id)
.await
.unwrap()
.and_then(|x| x.parse::<i64>().ok()),
None
);
// Report for alpha no longer exists
let resp = api
.get_report(
alpha_report_id,
ENEMY_USER_PAT, // Enemy makes a report
)
.await;
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
// Confirm that report for beta still exists
let resp = api
.get_report(
beta_report_id,
ENEMY_USER_PAT, // Enemy makes a report
)
.await;
assert_eq!(resp.status(), StatusCode::OK);
})
.await;
}
#[actix_rt::test]
async fn permissions_patch_project_v3() {
with_test_environment(Some(8), |test_env: TestEnvironment<ApiV3>| async move {

View File

@@ -1,4 +1,5 @@
use itertools::Itertools;
use labrinth::routes::v2::tags::DonationPlatformQueryData;
use std::collections::HashSet;
@@ -62,3 +63,45 @@ async fn get_tags() {
})
.await;
}
#[actix_rt::test]
async fn get_donation_platforms() {
with_test_environment(None, |test_env: TestEnvironment<ApiV2>| async move {
let api = &test_env.api;
let mut donation_platforms_unsorted = api.get_donation_platforms_deserialized().await;
// These tests match dummy data and will need to be updated if the dummy data changes
let mut included = vec![
DonationPlatformQueryData {
short: "patreon".to_string(),
name: "Patreon".to_string(),
},
DonationPlatformQueryData {
short: "ko-fi".to_string(),
name: "Ko-fi".to_string(),
},
DonationPlatformQueryData {
short: "paypal".to_string(),
name: "PayPal".to_string(),
},
DonationPlatformQueryData {
short: "bmac".to_string(),
name: "Buy Me A Coffee".to_string(),
},
DonationPlatformQueryData {
short: "github".to_string(),
name: "GitHub Sponsors".to_string(),
},
DonationPlatformQueryData {
short: "other".to_string(),
name: "Other".to_string(),
},
];
included.sort_by(|a, b| a.short.cmp(&b.short));
donation_platforms_unsorted.sort_by(|a, b| a.short.cmp(&b.short));
assert_eq!(donation_platforms_unsorted, included);
})
.await;
}