You've already forked AstralRinth
forked from didirus/AstralRinth
Add redis caching to getting user notifications and projects [MOD-540] (#723)
* Add redis caching to getting a user's project ids * Run `cargo sqlx prepare` to update the sqlx-data.json * Add redis caching for getting user notifications * Fix new clippy warnings * Remove log that shouldn't have been committed * Batch insert of notifications (untested) * sqlx prepare... * Fix merge conflict things and use new redis struct * Fix bug with calling delete_many without any elements (caught by tests) * cargo sqlx prepare * Add tests around cache invalidation (and fix bug they caught!) * Some test reorg based on code review suggestions
This commit is contained in:
175
tests/common/api_v2.rs
Normal file
175
tests/common/api_v2.rs
Normal file
@@ -0,0 +1,175 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use super::{
|
||||
actix::AppendsMultipart,
|
||||
asserts::assert_status,
|
||||
database::{MOD_USER_PAT, USER_USER_PAT},
|
||||
environment::LocalService,
|
||||
request_data::ProjectCreationRequestData,
|
||||
};
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::{
|
||||
dev::ServiceResponse,
|
||||
test::{self, TestRequest},
|
||||
};
|
||||
use labrinth::models::{
|
||||
notifications::Notification,
|
||||
projects::{Project, Version},
|
||||
};
|
||||
use serde_json::json;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct ApiV2 {
|
||||
pub test_app: Rc<Box<dyn LocalService>>,
|
||||
}
|
||||
|
||||
impl ApiV2 {
|
||||
pub async fn call(&self, req: actix_http::Request) -> ServiceResponse {
|
||||
self.test_app.call(req).await.unwrap()
|
||||
}
|
||||
|
||||
pub async fn add_public_project(
|
||||
&self,
|
||||
creation_data: ProjectCreationRequestData,
|
||||
) -> (Project, Version) {
|
||||
// Add a project.
|
||||
let req = TestRequest::post()
|
||||
.uri("/v2/project")
|
||||
.append_header(("Authorization", USER_USER_PAT))
|
||||
.set_multipart(creation_data.segment_data)
|
||||
.to_request();
|
||||
let resp = self.call(req).await;
|
||||
assert_status(resp, StatusCode::OK);
|
||||
|
||||
// Approve as a moderator.
|
||||
let req = TestRequest::patch()
|
||||
.uri(&format!("/v2/project/{}", creation_data.slug))
|
||||
.append_header(("Authorization", MOD_USER_PAT))
|
||||
.set_json(json!(
|
||||
{
|
||||
"status": "approved"
|
||||
}
|
||||
))
|
||||
.to_request();
|
||||
let resp = self.call(req).await;
|
||||
assert_status(resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let project = self
|
||||
.get_project_deserialized(&creation_data.slug, USER_USER_PAT)
|
||||
.await;
|
||||
|
||||
// Get project's versions
|
||||
let req = TestRequest::get()
|
||||
.uri(&format!("/v2/project/{}/version", creation_data.slug))
|
||||
.append_header(("Authorization", USER_USER_PAT))
|
||||
.to_request();
|
||||
let resp = self.call(req).await;
|
||||
let versions: Vec<Version> = test::read_body_json(resp).await;
|
||||
let version = versions.into_iter().next().unwrap();
|
||||
|
||||
(project, version)
|
||||
}
|
||||
|
||||
pub async fn remove_project(&self, project_slug_or_id: &str, pat: &str) -> ServiceResponse {
|
||||
let req = test::TestRequest::delete()
|
||||
.uri(&format!("/v2/project/{project_slug_or_id}"))
|
||||
.append_header(("Authorization", pat))
|
||||
.to_request();
|
||||
let resp = self.call(req).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
resp
|
||||
}
|
||||
|
||||
pub async fn get_project_deserialized(&self, slug: &str, pat: &str) -> Project {
|
||||
let req = TestRequest::get()
|
||||
.uri(&format!("/v2/project/{slug}"))
|
||||
.append_header(("Authorization", pat))
|
||||
.to_request();
|
||||
let resp = self.call(req).await;
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
pub async fn get_user_projects_deserialized(
|
||||
&self,
|
||||
user_id_or_username: &str,
|
||||
pat: &str,
|
||||
) -> Vec<Project> {
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!("/v2/user/{}/projects", user_id_or_username))
|
||||
.append_header(("Authorization", pat))
|
||||
.to_request();
|
||||
let resp = self.call(req).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
pub async fn add_user_to_team(
|
||||
&self,
|
||||
team_id: &str,
|
||||
user_id: &str,
|
||||
pat: &str,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::post()
|
||||
.uri(&format!("/v2/team/{team_id}/members"))
|
||||
.append_header(("Authorization", pat))
|
||||
.set_json(json!( {
|
||||
"user_id": user_id
|
||||
}))
|
||||
.to_request();
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
pub async fn join_team(&self, team_id: &str, pat: &str) -> ServiceResponse {
|
||||
let req = test::TestRequest::post()
|
||||
.uri(&format!("/v2/team/{team_id}/join"))
|
||||
.append_header(("Authorization", pat))
|
||||
.to_request();
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
pub async fn remove_from_team(
|
||||
&self,
|
||||
team_id: &str,
|
||||
user_id: &str,
|
||||
pat: &str,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::delete()
|
||||
.uri(&format!("/v2/team/{team_id}/members/{user_id}"))
|
||||
.append_header(("Authorization", pat))
|
||||
.to_request();
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
pub async fn get_user_notifications_deserialized(
|
||||
&self,
|
||||
user_id: &str,
|
||||
pat: &str,
|
||||
) -> Vec<Notification> {
|
||||
let req = test::TestRequest::get()
|
||||
.uri(&format!("/v2/user/{user_id}/notifications"))
|
||||
.append_header(("Authorization", pat))
|
||||
.to_request();
|
||||
let resp = self.call(req).await;
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
pub async fn mark_notification_read(
|
||||
&self,
|
||||
notification_id: &str,
|
||||
pat: &str,
|
||||
) -> ServiceResponse {
|
||||
let req = test::TestRequest::patch()
|
||||
.uri(&format!("/v2/notification/{notification_id}"))
|
||||
.append_header(("Authorization", pat))
|
||||
.to_request();
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
pub async fn delete_notification(&self, notification_id: &str, pat: &str) -> ServiceResponse {
|
||||
let req = test::TestRequest::delete()
|
||||
.uri(&format!("/v2/notification/{notification_id}"))
|
||||
.append_header(("Authorization", pat))
|
||||
.to_request();
|
||||
self.call(req).await
|
||||
}
|
||||
}
|
||||
3
tests/common/asserts.rs
Normal file
3
tests/common/asserts.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub fn assert_status(response: actix_web::dev::ServiceResponse, status: actix_http::StatusCode) {
|
||||
assert_eq!(response.status(), status, "{:#?}", response.response());
|
||||
}
|
||||
@@ -3,16 +3,15 @@ use labrinth::{models::projects::Project, models::projects::Version};
|
||||
use serde_json::json;
|
||||
use sqlx::Executor;
|
||||
|
||||
use crate::common::{
|
||||
actix::AppendsMultipart,
|
||||
database::{MOD_USER_PAT, USER_USER_PAT},
|
||||
};
|
||||
use crate::common::{actix::AppendsMultipart, database::USER_USER_PAT};
|
||||
|
||||
use super::{
|
||||
actix::{MultipartSegment, MultipartSegmentData},
|
||||
environment::TestEnvironment,
|
||||
request_data::get_public_project_creation_data,
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const DUMMY_CATEGORIES: &'static [&str] = &[
|
||||
"combat",
|
||||
"decoration",
|
||||
@@ -23,6 +22,14 @@ pub const DUMMY_CATEGORIES: &'static [&str] = &[
|
||||
"optimization",
|
||||
];
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum DummyJarFile {
|
||||
DummyProjectAlpha,
|
||||
DummyProjectBeta,
|
||||
BasicMod,
|
||||
BasicModDifferent,
|
||||
}
|
||||
|
||||
pub struct DummyData {
|
||||
pub alpha_team_id: String,
|
||||
pub beta_team_id: String,
|
||||
@@ -75,94 +82,19 @@ pub async fn add_dummy_data(test_env: &TestEnvironment) -> DummyData {
|
||||
}
|
||||
|
||||
pub async fn add_project_alpha(test_env: &TestEnvironment) -> (Project, Version) {
|
||||
// Adds dummy data to the database with sqlx (projects, versions, threads)
|
||||
// Generate test project data.
|
||||
let json_data = json!(
|
||||
{
|
||||
"title": "Test Project Alpha",
|
||||
"slug": "alpha",
|
||||
"description": "A dummy project for testing with.",
|
||||
"body": "This project is approved, and versions are listed.",
|
||||
"client_side": "required",
|
||||
"server_side": "optional",
|
||||
"initial_versions": [{
|
||||
"file_parts": ["dummy-project-alpha.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 file
|
||||
let file_segment = MultipartSegment {
|
||||
name: "dummy-project-alpha.jar".to_string(),
|
||||
filename: Some("dummy-project-alpha.jar".to_string()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/dummy-project-alpha.jar").to_vec(),
|
||||
),
|
||||
};
|
||||
|
||||
// Add a project.
|
||||
let req = 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;
|
||||
assert_eq!(resp.status(), 200);
|
||||
|
||||
// Approve as a moderator.
|
||||
let req = TestRequest::patch()
|
||||
.uri("/v2/project/alpha")
|
||||
.append_header(("Authorization", MOD_USER_PAT))
|
||||
.set_json(json!(
|
||||
{
|
||||
"status": "approved"
|
||||
}
|
||||
test_env
|
||||
.v2
|
||||
.add_public_project(get_public_project_creation_data(
|
||||
"alpha",
|
||||
DummyJarFile::DummyProjectAlpha,
|
||||
))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
|
||||
// Get project
|
||||
let req = TestRequest::get()
|
||||
.uri("/v2/project/alpha")
|
||||
.append_header(("Authorization", USER_USER_PAT))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
let project: Project = test::read_body_json(resp).await;
|
||||
|
||||
// Get project's versions
|
||||
let req = TestRequest::get()
|
||||
.uri("/v2/project/alpha/version")
|
||||
.append_header(("Authorization", USER_USER_PAT))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
let versions: Vec<Version> = test::read_body_json(resp).await;
|
||||
let version = versions.into_iter().next().unwrap();
|
||||
|
||||
(project, version)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn add_project_beta(test_env: &TestEnvironment) -> (Project, Version) {
|
||||
// Adds dummy data to the database with sqlx (projects, versions, threads)
|
||||
// Generate test project data.
|
||||
let jar = DummyJarFile::DummyProjectBeta;
|
||||
let json_data = json!(
|
||||
{
|
||||
"title": "Test Project Beta",
|
||||
@@ -172,7 +104,7 @@ pub async fn add_project_beta(test_env: &TestEnvironment) -> (Project, Version)
|
||||
"client_side": "required",
|
||||
"server_side": "optional",
|
||||
"initial_versions": [{
|
||||
"file_parts": ["dummy-project-beta.jar"],
|
||||
"file_parts": [jar.filename()],
|
||||
"version_number": "1.2.3",
|
||||
"version_title": "start",
|
||||
"status": "unlisted",
|
||||
@@ -200,12 +132,10 @@ pub async fn add_project_beta(test_env: &TestEnvironment) -> (Project, Version)
|
||||
|
||||
// Basic file
|
||||
let file_segment = MultipartSegment {
|
||||
name: "dummy-project-beta.jar".to_string(),
|
||||
filename: Some("dummy-project-beta.jar".to_string()),
|
||||
name: jar.filename(),
|
||||
filename: Some(jar.filename()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
data: MultipartSegmentData::Binary(
|
||||
include_bytes!("../../tests/files/dummy-project-beta.jar").to_vec(),
|
||||
),
|
||||
data: MultipartSegmentData::Binary(jar.bytes()),
|
||||
};
|
||||
|
||||
// Add a project.
|
||||
@@ -237,3 +167,30 @@ pub async fn add_project_beta(test_env: &TestEnvironment) -> (Project, Version)
|
||||
|
||||
(project, version)
|
||||
}
|
||||
|
||||
impl DummyJarFile {
|
||||
pub fn filename(&self) -> String {
|
||||
match self {
|
||||
DummyJarFile::DummyProjectAlpha => "dummy-project-alpha.jar",
|
||||
DummyJarFile::DummyProjectBeta => "dummy-project-beta.jar",
|
||||
DummyJarFile::BasicMod => "basic-mod.jar",
|
||||
DummyJarFile::BasicModDifferent => "basic-mod-different.jar",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
|
||||
pub fn bytes(&self) -> Vec<u8> {
|
||||
match self {
|
||||
DummyJarFile::DummyProjectAlpha => {
|
||||
include_bytes!("../../tests/files/dummy-project-alpha.jar").to_vec()
|
||||
}
|
||||
DummyJarFile::DummyProjectBeta => {
|
||||
include_bytes!("../../tests/files/dummy-project-beta.jar").to_vec()
|
||||
}
|
||||
DummyJarFile::BasicMod => include_bytes!("../../tests/files/basic-mod.jar").to_vec(),
|
||||
DummyJarFile::BasicModDifferent => {
|
||||
include_bytes!("../../tests/files/basic-mod-different.jar").to_vec()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use super::{database::TemporaryDatabase, dummy_data};
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::{
|
||||
api_v2::ApiV2,
|
||||
asserts::assert_status,
|
||||
database::{TemporaryDatabase, FRIEND_USER_ID, USER_USER_PAT},
|
||||
dummy_data,
|
||||
};
|
||||
use crate::common::setup;
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::{dev::ServiceResponse, test, App};
|
||||
use futures::Future;
|
||||
|
||||
@@ -22,8 +30,9 @@ where
|
||||
// temporary sqlx db like #[sqlx::test] would.
|
||||
// Use .call(req) on it directly to make a test call as if test::call_service(req) were being used.
|
||||
pub struct TestEnvironment {
|
||||
test_app: Box<dyn LocalService>,
|
||||
test_app: Rc<Box<dyn LocalService>>,
|
||||
pub db: TemporaryDatabase,
|
||||
pub v2: ApiV2,
|
||||
|
||||
pub dummy: Option<dummy_data::DummyData>,
|
||||
}
|
||||
@@ -40,9 +49,12 @@ impl TestEnvironment {
|
||||
let db = TemporaryDatabase::create().await;
|
||||
let labrinth_config = setup(&db).await;
|
||||
let app = App::new().configure(|cfg| labrinth::app_config(cfg, labrinth_config.clone()));
|
||||
let test_app = test::init_service(app).await;
|
||||
let test_app: Rc<Box<dyn LocalService>> = Rc::new(Box::new(test::init_service(app).await));
|
||||
Self {
|
||||
test_app: Box::new(test_app),
|
||||
v2: ApiV2 {
|
||||
test_app: test_app.clone(),
|
||||
},
|
||||
test_app,
|
||||
db,
|
||||
dummy: None,
|
||||
}
|
||||
@@ -54,9 +66,21 @@ impl TestEnvironment {
|
||||
pub async fn call(&self, req: actix_http::Request) -> ServiceResponse {
|
||||
self.test_app.call(req).await.unwrap()
|
||||
}
|
||||
|
||||
pub async fn generate_friend_user_notification(&self) {
|
||||
let resp = self
|
||||
.v2
|
||||
.add_user_to_team(
|
||||
&self.dummy.as_ref().unwrap().alpha_team_id,
|
||||
FRIEND_USER_ID,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status(resp, StatusCode::NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
||||
trait LocalService {
|
||||
pub trait LocalService {
|
||||
fn call(
|
||||
&self,
|
||||
req: actix_http::Request,
|
||||
|
||||
@@ -5,10 +5,13 @@ use std::sync::Arc;
|
||||
use self::database::TemporaryDatabase;
|
||||
|
||||
pub mod actix;
|
||||
pub mod api_v2;
|
||||
pub mod asserts;
|
||||
pub mod database;
|
||||
pub mod dummy_data;
|
||||
pub mod environment;
|
||||
pub mod pats;
|
||||
pub mod request_data;
|
||||
pub mod scopes;
|
||||
|
||||
// Testing equivalent to 'setup' function, producing a LabrinthConfig
|
||||
|
||||
60
tests/common/request_data.rs
Normal file
60
tests/common/request_data.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
use serde_json::json;
|
||||
|
||||
use super::{actix::MultipartSegment, dummy_data::DummyJarFile};
|
||||
use crate::common::actix::MultipartSegmentData;
|
||||
|
||||
pub struct ProjectCreationRequestData {
|
||||
pub slug: String,
|
||||
pub jar: DummyJarFile,
|
||||
pub segment_data: Vec<MultipartSegment>,
|
||||
}
|
||||
|
||||
pub fn get_public_project_creation_data(
|
||||
slug: &str,
|
||||
jar: DummyJarFile,
|
||||
) -> ProjectCreationRequestData {
|
||||
let json_data = json!(
|
||||
{
|
||||
"title": format!("Test Project {slug}"),
|
||||
"slug": slug,
|
||||
"description": "A dummy project for testing with.",
|
||||
"body": "This project is approved, and versions are listed.",
|
||||
"client_side": "required",
|
||||
"server_side": "optional",
|
||||
"initial_versions": [{
|
||||
"file_parts": [jar.filename()],
|
||||
"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 file
|
||||
let file_segment = MultipartSegment {
|
||||
name: jar.filename(),
|
||||
filename: Some(jar.filename()),
|
||||
content_type: Some("application/java-archive".to_string()),
|
||||
data: MultipartSegmentData::Binary(jar.bytes()),
|
||||
};
|
||||
|
||||
ProjectCreationRequestData {
|
||||
slug: slug.to_string(),
|
||||
jar,
|
||||
segment_data: vec![json_segment.clone(), file_segment.clone()],
|
||||
}
|
||||
}
|
||||
@@ -83,9 +83,10 @@ impl<'a> ScopeTest<'a> {
|
||||
|
||||
if resp.status().as_u16() != self.expected_failure_code {
|
||||
return Err(format!(
|
||||
"Expected failure code {}, got {}",
|
||||
"Expected failure code {}, got {} ({:#?})",
|
||||
self.expected_failure_code,
|
||||
resp.status().as_u16()
|
||||
resp.status().as_u16(),
|
||||
resp.response()
|
||||
));
|
||||
}
|
||||
|
||||
@@ -106,8 +107,9 @@ impl<'a> ScopeTest<'a> {
|
||||
|
||||
if !(resp.status().is_success() || resp.status().is_redirection()) {
|
||||
return Err(format!(
|
||||
"Expected success code, got {}",
|
||||
resp.status().as_u16()
|
||||
"Expected success code, got {} ({:#?})",
|
||||
resp.status().as_u16(),
|
||||
resp.response()
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
70
tests/notifications.rs
Normal file
70
tests/notifications.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
use common::{
|
||||
database::{FRIEND_USER_ID, FRIEND_USER_PAT, USER_USER_PAT},
|
||||
environment::with_test_environment,
|
||||
};
|
||||
|
||||
mod common;
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn get_user_notifications_after_team_invitation_returns_notification() {
|
||||
with_test_environment(|test_env| async move {
|
||||
let alpha_team_id = test_env.dummy.as_ref().unwrap().alpha_team_id.clone();
|
||||
let api = test_env.v2;
|
||||
api.get_user_notifications_deserialized(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
|
||||
api.add_user_to_team(&alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
|
||||
let notifications = api
|
||||
.get_user_notifications_deserialized(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(1, notifications.len());
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn get_user_notifications_after_reading_indicates_notification_read() {
|
||||
with_test_environment(|test_env| async move {
|
||||
test_env.generate_friend_user_notification().await;
|
||||
let api = test_env.v2;
|
||||
let notifications = api
|
||||
.get_user_notifications_deserialized(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(1, notifications.len());
|
||||
let notification_id = notifications[0].id.to_string();
|
||||
|
||||
api.mark_notification_read(¬ification_id, FRIEND_USER_PAT)
|
||||
.await;
|
||||
|
||||
let notifications = api
|
||||
.get_user_notifications_deserialized(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(1, notifications.len());
|
||||
assert!(notifications[0].read);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn get_user_notifications_after_deleting_does_not_show_notification() {
|
||||
with_test_environment(|test_env| async move {
|
||||
test_env.generate_friend_user_notification().await;
|
||||
let api = test_env.v2;
|
||||
let notifications = api
|
||||
.get_user_notifications_deserialized(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(1, notifications.len());
|
||||
let notification_id = notifications[0].id.to_string();
|
||||
|
||||
api.delete_notification(¬ification_id, FRIEND_USER_PAT)
|
||||
.await;
|
||||
|
||||
let notifications = api
|
||||
.get_user_notifications_deserialized(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(0, notifications.len());
|
||||
})
|
||||
.await;
|
||||
}
|
||||
@@ -269,11 +269,7 @@ async fn test_add_remove_project() {
|
||||
let id = body["id"].to_string();
|
||||
|
||||
// Remove the project
|
||||
let req = test::TestRequest::delete()
|
||||
.uri("/v2/project/demo")
|
||||
.append_header(("Authorization", USER_USER_PAT))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
let resp = test_env.v2.remove_project("demo", USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
|
||||
// Confirm that the project is gone from the cache
|
||||
|
||||
@@ -92,14 +92,10 @@ pub async fn notifications_scopes() {
|
||||
|
||||
// We will invite user 'friend' to project team, and use that as a notification
|
||||
// Get notifications
|
||||
let req = TestRequest::post()
|
||||
.uri(&format!("/v2/team/{alpha_team_id}/members"))
|
||||
.append_header(("Authorization", USER_USER_PAT))
|
||||
.set_json(json!( {
|
||||
"user_id": FRIEND_USER_ID // friend
|
||||
}))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
let resp = test_env
|
||||
.v2
|
||||
.add_user_to_team(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
|
||||
// Notification get
|
||||
@@ -164,14 +160,10 @@ pub async fn notifications_scopes() {
|
||||
|
||||
// Mass notification delete
|
||||
// We invite mod, get the notification ID, and do mass delete using that
|
||||
let req = test::TestRequest::post()
|
||||
.uri(&format!("/v2/team/{alpha_team_id}/members"))
|
||||
.append_header(("Authorization", USER_USER_PAT))
|
||||
.set_json(json!( {
|
||||
"user_id": MOD_USER_ID // mod
|
||||
}))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
let resp = test_env
|
||||
.v2
|
||||
.add_user_to_team(alpha_team_id, MOD_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
let read_notifications = Scopes::NOTIFICATION_READ;
|
||||
let req_gen = || test::TestRequest::get().uri(&format!("/v2/user/{MOD_USER_ID}/notifications"));
|
||||
|
||||
102
tests/user.rs
Normal file
102
tests/user.rs
Normal file
@@ -0,0 +1,102 @@
|
||||
use common::{
|
||||
database::{FRIEND_USER_ID, FRIEND_USER_PAT, USER_USER_ID, USER_USER_PAT},
|
||||
environment::with_test_environment,
|
||||
};
|
||||
|
||||
use crate::common::{dummy_data::DummyJarFile, request_data::get_public_project_creation_data};
|
||||
|
||||
mod common;
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn get_user_projects_after_creating_project_returns_new_project() {
|
||||
with_test_environment(|test_env| async move {
|
||||
let api = test_env.v2;
|
||||
api.get_user_projects_deserialized(USER_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
|
||||
let (project, _) = api
|
||||
.add_public_project(get_public_project_creation_data(
|
||||
"slug",
|
||||
DummyJarFile::BasicMod,
|
||||
))
|
||||
.await;
|
||||
|
||||
let resp_projects = api
|
||||
.get_user_projects_deserialized(USER_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert!(resp_projects.iter().any(|p| p.id == project.id));
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn get_user_projects_after_deleting_project_shows_removal() {
|
||||
with_test_environment(|test_env| async move {
|
||||
let api = test_env.v2;
|
||||
let (project, _) = api
|
||||
.add_public_project(get_public_project_creation_data(
|
||||
"iota",
|
||||
DummyJarFile::BasicMod,
|
||||
))
|
||||
.await;
|
||||
api.get_user_projects_deserialized(USER_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
|
||||
api.remove_project(&project.slug.as_ref().unwrap(), USER_USER_PAT)
|
||||
.await;
|
||||
|
||||
let resp_projects = api
|
||||
.get_user_projects_deserialized(USER_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert!(!resp_projects.iter().any(|p| p.id == project.id));
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn get_user_projects_after_joining_team_shows_team_projects() {
|
||||
with_test_environment(|test_env| async move {
|
||||
let alpha_team_id = &test_env.dummy.as_ref().unwrap().alpha_team_id;
|
||||
let alpha_project_id = &test_env.dummy.as_ref().unwrap().alpha_project_id;
|
||||
let api = test_env.v2;
|
||||
api.get_user_projects_deserialized(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
|
||||
api.add_user_to_team(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
api.join_team(&alpha_team_id, FRIEND_USER_PAT).await;
|
||||
|
||||
let projects = api
|
||||
.get_user_projects_deserialized(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert!(projects
|
||||
.iter()
|
||||
.any(|p| p.id.to_string() == *alpha_project_id));
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
pub async fn get_user_projects_after_leaving_team_shows_no_team_projects() {
|
||||
with_test_environment(|test_env| async move {
|
||||
let alpha_team_id = &test_env.dummy.as_ref().unwrap().alpha_team_id;
|
||||
let alpha_project_id = &test_env.dummy.as_ref().unwrap().alpha_project_id;
|
||||
let api = test_env.v2;
|
||||
api.add_user_to_team(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
api.join_team(&alpha_team_id, FRIEND_USER_PAT).await;
|
||||
api.get_user_projects_deserialized(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
|
||||
api.remove_from_team(&alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
|
||||
let projects = api
|
||||
.get_user_projects_deserialized(FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert!(!projects
|
||||
.iter()
|
||||
.any(|p| p.id.to_string() == *alpha_project_id));
|
||||
})
|
||||
.await;
|
||||
}
|
||||
Reference in New Issue
Block a user