You've already forked AstralRinth
forked from didirus/AstralRinth
Fixes failing tests (#813)
* fixes failing tests * fmt clippy * updated dockerfile * fixes failing tests; adds important fix from extracts_versions PR * assert_eq -> assert_status, giving better error messages * fixed random failure bug * fmt, clippy, etc
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
FROM rust:1.68.0 as build
|
||||
FROM rust:1.75.0 as build
|
||||
ENV PKG_CONFIG_ALLOW_CROSS=1
|
||||
|
||||
WORKDIR /usr/src/labrinth
|
||||
|
||||
@@ -47,8 +47,9 @@ impl FileHost for MockHost {
|
||||
) -> Result<DeleteFileData, FileHostingError> {
|
||||
let path = std::path::Path::new(&dotenvy::var("MOCK_FILE_PATH").unwrap())
|
||||
.join(file_name.replace("../", ""));
|
||||
std::fs::remove_file(path)?;
|
||||
|
||||
if path.exists() {
|
||||
std::fs::remove_file(path)?;
|
||||
}
|
||||
Ok(DeleteFileData {
|
||||
file_id: file_id.to_string(),
|
||||
file_name: file_name.to_string(),
|
||||
|
||||
@@ -57,6 +57,7 @@ pub struct LabrinthConfig {
|
||||
pub fn app_setup(
|
||||
pool: sqlx::Pool<Postgres>,
|
||||
redis_pool: RedisPool,
|
||||
search_config: search::SearchConfig,
|
||||
clickhouse: &mut Client,
|
||||
file_host: Arc<dyn file_hosting::FileHost + Send + Sync>,
|
||||
maxmind: Arc<queue::maxmind::MaxMindIndexer>,
|
||||
@@ -66,11 +67,6 @@ pub fn app_setup(
|
||||
dotenvy::var("BIND_ADDR").unwrap()
|
||||
);
|
||||
|
||||
let search_config = search::SearchConfig {
|
||||
address: dotenvy::var("MEILISEARCH_ADDR").unwrap(),
|
||||
key: dotenvy::var("MEILISEARCH_KEY").unwrap(),
|
||||
};
|
||||
|
||||
let mut scheduler = scheduler::Scheduler::new();
|
||||
|
||||
// The interval in seconds at which the local database is indexed
|
||||
|
||||
@@ -6,10 +6,10 @@ use labrinth::file_hosting::S3Host;
|
||||
use labrinth::ratelimit::errors::ARError;
|
||||
use labrinth::ratelimit::memory::{MemoryStore, MemoryStoreActor};
|
||||
use labrinth::ratelimit::middleware::RateLimiter;
|
||||
use labrinth::search;
|
||||
use labrinth::util::env::parse_var;
|
||||
use labrinth::{check_env_vars, clickhouse, database, file_hosting, queue};
|
||||
use log::{error, info};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -93,11 +93,13 @@ async fn main() -> std::io::Result<()> {
|
||||
.build()
|
||||
.expect("Failed to create prometheus metrics middleware");
|
||||
|
||||
let search_config = search::SearchConfig::new(None);
|
||||
info!("Starting Actix HTTP server!");
|
||||
|
||||
let labrinth_config = labrinth::app_setup(
|
||||
pool.clone(),
|
||||
redis_pool.clone(),
|
||||
search_config.clone(),
|
||||
&mut clickhouse,
|
||||
file_host.clone(),
|
||||
maxmind_reader.clone(),
|
||||
|
||||
@@ -17,7 +17,7 @@ pub struct Organization {
|
||||
pub id: OrganizationId,
|
||||
/// The slug of the organization
|
||||
pub slug: String,
|
||||
/// The title (and slug) of the organization
|
||||
/// The title of the organization
|
||||
pub name: String,
|
||||
/// The associated team of the organization
|
||||
pub team_id: TeamId,
|
||||
|
||||
@@ -81,7 +81,7 @@ pub fn root_config(cfg: &mut web::ServiceConfig) {
|
||||
pub enum ApiError {
|
||||
#[error("Environment Error")]
|
||||
Env(#[from] dotenvy::Error),
|
||||
#[error("Error while uploading file")]
|
||||
#[error("Error while uploading file: {0}")]
|
||||
FileHosting(#[from] FileHostingError),
|
||||
#[error("Database Error: {0}")]
|
||||
Database(#[from] crate::database::models::DatabaseError),
|
||||
|
||||
@@ -8,7 +8,7 @@ use sqlx::PgPool;
|
||||
use validator::Validate;
|
||||
|
||||
use crate::{
|
||||
auth::get_user_from_headers,
|
||||
auth::{filter_visible_projects, get_user_from_headers},
|
||||
database::{models::User, redis::RedisPool},
|
||||
file_hosting::FileHost,
|
||||
models::{
|
||||
@@ -65,23 +65,12 @@ pub async fn projects_list(
|
||||
let id_option = User::get(&info.into_inner().0, &**pool, &redis).await?;
|
||||
|
||||
if let Some(id) = id_option.map(|x| x.id) {
|
||||
let user_id: UserId = id.into();
|
||||
|
||||
let can_view_private = user
|
||||
.map(|y| y.role.is_mod() || y.id == user_id)
|
||||
.unwrap_or(false);
|
||||
|
||||
let project_data = User::get_projects(id, &**pool, &redis).await?;
|
||||
|
||||
let response: Vec<_> =
|
||||
crate::database::Project::get_many_ids(&project_data, &**pool, &redis)
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter(|x| can_view_private || x.inner.status.is_searchable())
|
||||
.map(Project::from)
|
||||
.collect();
|
||||
|
||||
Ok(HttpResponse::Ok().json(response))
|
||||
let projects: Vec<_> =
|
||||
crate::database::Project::get_many_ids(&project_data, &**pool, &redis).await?;
|
||||
let projects = filter_visible_projects(projects, &user, &pool).await?;
|
||||
Ok(HttpResponse::Ok().json(projects))
|
||||
} else {
|
||||
Err(ApiError::NotFound)
|
||||
}
|
||||
|
||||
@@ -107,11 +107,12 @@ pub async fn get_indexes(
|
||||
config: &SearchConfig,
|
||||
) -> Result<Vec<Index>, meilisearch_sdk::errors::Error> {
|
||||
let client = config.make_client();
|
||||
|
||||
let projects_index = create_or_update_index(&client, "projects", None).await?;
|
||||
let project_name = config.get_index_name("projects");
|
||||
let project_filtered_name = config.get_index_name("projects_filtered");
|
||||
let projects_index = create_or_update_index(&client, &project_name, None).await?;
|
||||
let projects_filtered_index = create_or_update_index(
|
||||
&client,
|
||||
"projects_filtered",
|
||||
&project_filtered_name,
|
||||
Some(&[
|
||||
"sort",
|
||||
"words",
|
||||
@@ -128,7 +129,7 @@ pub async fn get_indexes(
|
||||
|
||||
async fn create_or_update_index(
|
||||
client: &Client,
|
||||
name: &'static str,
|
||||
name: &str,
|
||||
custom_rules: Option<&'static [&'static str]>,
|
||||
) -> Result<Index, meilisearch_sdk::errors::Error> {
|
||||
info!("Updating/creating index.");
|
||||
@@ -207,7 +208,6 @@ async fn create_or_update_index(
|
||||
typo_tolerance: None, // We don't use typo tolerance right now
|
||||
dictionary: None, // We don't use dictionary right now
|
||||
};
|
||||
|
||||
if old_settings.synonyms != settings.synonyms
|
||||
|| old_settings.stop_words != settings.stop_words
|
||||
|| old_settings.ranking_rules != settings.ranking_rules
|
||||
@@ -294,16 +294,23 @@ async fn update_and_add_to_index(
|
||||
new_filterable_attributes.extend(additional_fields.iter().map(|s| s.to_string()));
|
||||
new_displayed_attributes.extend(additional_fields.iter().map(|s| s.to_string()));
|
||||
info!("add attributes.");
|
||||
index
|
||||
let filterable_task = index
|
||||
.set_filterable_attributes(new_filterable_attributes)
|
||||
.await?;
|
||||
index
|
||||
let displayable_task = index
|
||||
.set_displayed_attributes(new_displayed_attributes)
|
||||
.await?;
|
||||
filterable_task
|
||||
.wait_for_completion(client, None, Some(TIMEOUT))
|
||||
.await?;
|
||||
displayable_task
|
||||
.wait_for_completion(client, None, Some(TIMEOUT))
|
||||
.await?;
|
||||
|
||||
info!("Adding to index.");
|
||||
|
||||
add_to_index(client, index, projects).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -315,7 +322,6 @@ pub async fn add_projects(
|
||||
) -> Result<(), IndexingError> {
|
||||
let client = config.make_client();
|
||||
for index in indices {
|
||||
info!("adding projects part1 or 2.");
|
||||
update_and_add_to_index(&client, index, &projects, &additional_fields).await?;
|
||||
}
|
||||
|
||||
@@ -329,7 +335,6 @@ fn default_settings() -> Settings {
|
||||
sorted_sortable.sort();
|
||||
let mut sorted_attrs = DEFAULT_ATTRIBUTES_FOR_FACETING.to_vec();
|
||||
sorted_attrs.sort();
|
||||
|
||||
Settings::new()
|
||||
.with_distinct_attribute("project_id")
|
||||
.with_displayed_attributes(sorted_display)
|
||||
|
||||
@@ -59,16 +59,34 @@ impl actix_web::ResponseError for SearchError {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SearchConfig {
|
||||
pub address: String,
|
||||
pub key: String,
|
||||
pub meta_namespace: String,
|
||||
}
|
||||
|
||||
impl SearchConfig {
|
||||
// Panics if the environment variables are not set,
|
||||
// but these are already checked for on startup.
|
||||
pub fn new(meta_namespace: Option<String>) -> Self {
|
||||
let address = dotenvy::var("MEILISEARCH_ADDR").expect("MEILISEARCH_ADDR not set");
|
||||
let key = dotenvy::var("MEILISEARCH_KEY").expect("MEILISEARCH_KEY not set");
|
||||
|
||||
Self {
|
||||
address,
|
||||
key,
|
||||
meta_namespace: meta_namespace.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_client(&self) -> Client {
|
||||
Client::new(self.address.as_str(), Some(self.key.as_str()))
|
||||
}
|
||||
|
||||
pub fn get_index_name(&self, index: &str) -> String {
|
||||
format!("{}_{}", self.meta_namespace, index)
|
||||
}
|
||||
}
|
||||
|
||||
/// A project document used for uploading projects to MeiliSearch's indices.
|
||||
@@ -172,13 +190,18 @@ pub struct ResultSearchProject {
|
||||
pub loader_fields: HashMap<String, Vec<serde_json::Value>>,
|
||||
}
|
||||
|
||||
pub fn get_sort_index(index: &str) -> Result<(&str, [&str; 1]), SearchError> {
|
||||
pub fn get_sort_index(
|
||||
config: &SearchConfig,
|
||||
index: &str,
|
||||
) -> Result<(String, [&'static str; 1]), SearchError> {
|
||||
let projects_name = config.get_index_name("projects");
|
||||
let projects_filtered_name = config.get_index_name("projects_filtered");
|
||||
Ok(match index {
|
||||
"relevance" => ("projects", ["downloads:desc"]),
|
||||
"downloads" => ("projects_filtered", ["downloads:desc"]),
|
||||
"follows" => ("projects", ["follows:desc"]),
|
||||
"updated" => ("projects", ["date_modified:desc"]),
|
||||
"newest" => ("projects", ["date_created:desc"]),
|
||||
"relevance" => (projects_name, ["downloads:desc"]),
|
||||
"downloads" => (projects_filtered_name, ["downloads:desc"]),
|
||||
"follows" => (projects_name, ["follows:desc"]),
|
||||
"updated" => (projects_name, ["date_modified:desc"]),
|
||||
"newest" => (projects_name, ["date_created:desc"]),
|
||||
i => return Err(SearchError::InvalidIndex(i.to_string())),
|
||||
})
|
||||
}
|
||||
@@ -193,8 +216,7 @@ pub async fn search_for_project(
|
||||
let index = info.index.as_deref().unwrap_or("relevance");
|
||||
let limit = info.limit.as_deref().unwrap_or("10").parse()?;
|
||||
|
||||
let sort = get_sort_index(index)?;
|
||||
|
||||
let sort = get_sort_index(config, index)?;
|
||||
let meilisearch_index = client.get_index(sort.0).await?;
|
||||
|
||||
let mut filter_string = String::new();
|
||||
|
||||
@@ -35,7 +35,7 @@ impl ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> LegacyProject {
|
||||
let resp = self.get_project(id_or_slug, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ impl ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<LegacyProject> {
|
||||
let resp = self.get_user_projects(user_id_or_username, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -72,8 +72,7 @@ impl ApiV2 {
|
||||
.append_pat(pat)
|
||||
.to_request();
|
||||
let resp = self.call(req).await;
|
||||
let status = resp.status();
|
||||
assert_eq!(status, 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
}
|
||||
@@ -164,7 +163,7 @@ impl ApiProject for ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> CommonProject {
|
||||
let resp = self.get_project(id_or_slug, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let project: LegacyProject = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -214,7 +213,7 @@ impl ApiProject for ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<CommonProject> {
|
||||
let resp = self.get_user_projects(user_id_or_username, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let projects: Vec<LegacyProject> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::{
|
||||
dev::ServiceResponse,
|
||||
test::{self, TestRequest},
|
||||
@@ -12,6 +13,7 @@ use crate::common::{
|
||||
models::{CommonCategoryData, CommonLoaderData},
|
||||
Api, ApiTags, AppendsOptionalPat,
|
||||
},
|
||||
asserts::assert_status,
|
||||
database::ADMIN_USER_PAT,
|
||||
};
|
||||
|
||||
@@ -30,7 +32,7 @@ impl ApiV2 {
|
||||
|
||||
pub async fn get_side_types_deserialized(&self) -> Vec<String> {
|
||||
let resp = self.get_side_types().await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -44,19 +46,19 @@ impl ApiV2 {
|
||||
|
||||
pub async fn get_game_versions_deserialized(&self) -> Vec<GameVersionQueryData> {
|
||||
let resp = self.get_game_versions().await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
pub async fn get_loaders_deserialized(&self) -> Vec<LoaderData> {
|
||||
let resp = self.get_loaders().await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
pub async fn get_categories_deserialized(&self) -> Vec<CategoryData> {
|
||||
let resp = self.get_categories().await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -70,8 +72,7 @@ impl ApiV2 {
|
||||
|
||||
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);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
}
|
||||
@@ -88,7 +89,7 @@ impl ApiTags for ApiV2 {
|
||||
|
||||
async fn get_loaders_deserialized_common(&self) -> Vec<CommonLoaderData> {
|
||||
let resp = self.get_loaders().await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: Vec<LoaderData> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -106,7 +107,7 @@ impl ApiTags for ApiV2 {
|
||||
|
||||
async fn get_categories_deserialized_common(&self) -> Vec<CommonCategoryData> {
|
||||
let resp = self.get_categories().await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: Vec<CategoryData> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
|
||||
@@ -24,7 +24,7 @@ impl ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<LegacyTeamMember> {
|
||||
let resp = self.get_organization_members(id_or_title, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ impl ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<LegacyTeamMember> {
|
||||
let resp = self.get_team_members(team_id, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ impl ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<LegacyNotification> {
|
||||
let resp = self.get_user_notifications(user_id, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ impl ApiTeams for ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<CommonTeamMember> {
|
||||
let resp = self.get_team_members(id_or_title, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// TODO: Note, this does NOT deserialize to any other struct first, as currently TeamMember is the same in v2 and v3.
|
||||
// CommonTeamMember = TeamMember (v3)
|
||||
// This may yet change, so we should keep common struct.
|
||||
@@ -102,7 +102,7 @@ impl ApiTeams for ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<CommonTeamMember> {
|
||||
let resp = self.get_project_members(id_or_title, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// TODO: Note, this does NOT deserialize to any other struct first, as currently TeamMember is the same in v2 and v3.
|
||||
// CommonTeamMember = TeamMember (v3)
|
||||
// This may yet change, so we should keep common struct.
|
||||
@@ -127,7 +127,7 @@ impl ApiTeams for ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<CommonTeamMember> {
|
||||
let resp = self.get_organization_members(id_or_title, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// TODO: Note, this does NOT deserialize to any other struct first, as currently TeamMember is the same in v2 and v3.
|
||||
// CommonTeamMember = TeamMember (v3)
|
||||
// This may yet change, so we should keep common struct.
|
||||
|
||||
@@ -33,7 +33,7 @@ pub fn url_encode_json_serialized_vec(elements: &[String]) -> String {
|
||||
impl ApiV2 {
|
||||
pub async fn get_version_deserialized(&self, id: &str, pat: Option<&str>) -> LegacyVersion {
|
||||
let resp = self.get_version(id, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ impl ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> LegacyVersion {
|
||||
let resp = self.get_version_from_hash(hash, algorithm, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ impl ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> HashMap<String, LegacyVersion> {
|
||||
let resp = self.get_versions_from_hashes(hashes, algorithm, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ impl ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> HashMap<String, LegacyVersion> {
|
||||
let resp = self.update_individual_files(algorithm, hashes, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
}
|
||||
@@ -135,7 +135,7 @@ impl ApiVersion for ApiV2 {
|
||||
pat,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: LegacyVersion = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -153,7 +153,7 @@ impl ApiVersion for ApiV2 {
|
||||
|
||||
async fn get_version_deserialized_common(&self, id: &str, pat: Option<&str>) -> CommonVersion {
|
||||
let resp = self.get_version(id, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: LegacyVersion = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -212,7 +212,7 @@ impl ApiVersion for ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> CommonVersion {
|
||||
let resp = self.get_version_from_hash(hash, algorithm, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: LegacyVersion = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -244,7 +244,7 @@ impl ApiVersion for ApiV2 {
|
||||
pat: Option<&str>,
|
||||
) -> HashMap<String, CommonVersion> {
|
||||
let resp = self.get_versions_from_hashes(hashes, algorithm, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: HashMap<String, LegacyVersion> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -287,7 +287,7 @@ impl ApiVersion for ApiV2 {
|
||||
let resp = self
|
||||
.get_update_from_hash(hash, algorithm, loaders, game_versions, version_types, pat)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: LegacyVersion = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -337,7 +337,7 @@ impl ApiVersion for ApiV2 {
|
||||
pat,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: HashMap<String, LegacyVersion> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -420,7 +420,7 @@ impl ApiVersion for ApiV2 {
|
||||
pat,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: Vec<LegacyVersion> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::{
|
||||
dev::ServiceResponse,
|
||||
test::{self, TestRequest},
|
||||
@@ -6,7 +7,10 @@ use bytes::Bytes;
|
||||
use labrinth::models::{collections::Collection, v3::projects::Project};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::common::api_common::{request_data::ImageData, Api, AppendsOptionalPat};
|
||||
use crate::common::{
|
||||
api_common::{request_data::ImageData, Api, AppendsOptionalPat},
|
||||
asserts::assert_status,
|
||||
};
|
||||
|
||||
use super::ApiV3;
|
||||
|
||||
@@ -40,7 +44,7 @@ impl ApiV3 {
|
||||
|
||||
pub async fn get_collection_deserialized(&self, id: &str, pat: Option<&str>) -> Collection {
|
||||
let resp = self.get_collection(id, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -70,7 +74,7 @@ impl ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<Project> {
|
||||
let resp = self.get_collection_projects(id, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -145,7 +149,7 @@ impl ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<Collection> {
|
||||
let resp = self.get_user_collections(user_id_or_username, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let projects: Vec<Project> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::{
|
||||
dev::ServiceResponse,
|
||||
test::{self, TestRequest},
|
||||
@@ -6,7 +7,10 @@ use bytes::Bytes;
|
||||
use labrinth::models::{organizations::Organization, users::UserId, v3::projects::Project};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::common::api_common::{request_data::ImageData, Api, AppendsOptionalPat};
|
||||
use crate::common::{
|
||||
api_common::{request_data::ImageData, Api, AppendsOptionalPat},
|
||||
asserts::assert_status,
|
||||
};
|
||||
|
||||
use super::ApiV3;
|
||||
|
||||
@@ -14,6 +18,7 @@ impl ApiV3 {
|
||||
pub async fn create_organization(
|
||||
&self,
|
||||
organization_title: &str,
|
||||
organization_slug: &str,
|
||||
description: &str,
|
||||
pat: Option<&str>,
|
||||
) -> ServiceResponse {
|
||||
@@ -22,6 +27,7 @@ impl ApiV3 {
|
||||
.append_pat(pat)
|
||||
.set_json(json!({
|
||||
"name": organization_title,
|
||||
"slug": organization_slug,
|
||||
"description": description,
|
||||
}))
|
||||
.to_request();
|
||||
@@ -42,7 +48,7 @@ impl ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> Organization {
|
||||
let resp = self.get_organization(id_or_title, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -80,7 +86,7 @@ impl ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<Project> {
|
||||
let resp = self.get_organization_projects(id_or_title, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ impl ApiProject for ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> CommonProject {
|
||||
let resp = self.get_project(id_or_slug, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let project: Project = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -169,7 +169,7 @@ impl ApiProject for ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<CommonProject> {
|
||||
let resp = self.get_user_projects(user_id_or_username, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let projects: Vec<Project> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -383,10 +383,7 @@ impl ApiProject for ApiV3 {
|
||||
.append_pat(pat)
|
||||
.to_request();
|
||||
|
||||
let t = self.call(req).await;
|
||||
println!("Status: {}", t.status());
|
||||
println!("respone Body: {:?}", t.response().body());
|
||||
t
|
||||
self.call(req).await
|
||||
}
|
||||
|
||||
async fn remove_gallery_item(
|
||||
@@ -480,7 +477,7 @@ impl ApiProject for ApiV3 {
|
||||
impl ApiV3 {
|
||||
pub async fn get_project_deserialized(&self, id_or_slug: &str, pat: Option<&str>) -> Project {
|
||||
let resp = self.get_project(id_or_slug, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -503,7 +500,7 @@ impl ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> Organization {
|
||||
let resp = self.get_project_organization(id_or_slug, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -530,8 +527,7 @@ impl ApiV3 {
|
||||
.append_pat(pat)
|
||||
.to_request();
|
||||
let resp = self.call(req).await;
|
||||
let status = resp.status();
|
||||
assert_eq!(status, 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -598,7 +594,7 @@ impl ApiV3 {
|
||||
pat,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::{
|
||||
dev::ServiceResponse,
|
||||
test::{self, TestRequest},
|
||||
@@ -13,6 +14,7 @@ use crate::common::{
|
||||
models::{CommonCategoryData, CommonLoaderData},
|
||||
Api, ApiTags, AppendsOptionalPat,
|
||||
},
|
||||
asserts::assert_status,
|
||||
database::ADMIN_USER_PAT,
|
||||
};
|
||||
|
||||
@@ -30,7 +32,7 @@ impl ApiTags for ApiV3 {
|
||||
|
||||
async fn get_loaders_deserialized_common(&self) -> Vec<CommonLoaderData> {
|
||||
let resp = self.get_loaders().await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: Vec<LoaderData> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -48,7 +50,7 @@ impl ApiTags for ApiV3 {
|
||||
|
||||
async fn get_categories_deserialized_common(&self) -> Vec<CommonCategoryData> {
|
||||
let resp = self.get_categories().await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: Vec<CategoryData> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -60,7 +62,7 @@ impl ApiTags for ApiV3 {
|
||||
impl ApiV3 {
|
||||
pub async fn get_loaders_deserialized(&self) -> Vec<LoaderData> {
|
||||
let resp = self.get_loaders().await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -77,7 +79,7 @@ impl ApiV3 {
|
||||
loader_field: &str,
|
||||
) -> Vec<LoaderFieldEnumValue> {
|
||||
let resp = self.get_loader_field_variants(loader_field).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -92,7 +94,7 @@ impl ApiV3 {
|
||||
|
||||
pub async fn get_games_deserialized(&self) -> Vec<GameData> {
|
||||
let resp = self.get_games().await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ impl ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<TeamMember> {
|
||||
let resp = self.get_organization_members(id_or_title, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ impl ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<TeamMember> {
|
||||
let resp = self.get_team_members(team_id, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ impl ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<TeamMember> {
|
||||
let resp = self.get_project_members(project_id, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,7 @@ impl ApiTeams for ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<CommonTeamMember> {
|
||||
let resp = self.get_team_members(id_or_title, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: Vec<TeamMember> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -103,7 +103,7 @@ impl ApiTeams for ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<CommonTeamMember> {
|
||||
let resp = self.get_project_members(id_or_title, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: Vec<TeamMember> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -129,7 +129,7 @@ impl ApiTeams for ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> Vec<CommonTeamMember> {
|
||||
let resp = self.get_organization_members(id_or_title, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: Vec<TeamMember> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
|
||||
@@ -60,7 +60,7 @@ impl ApiV3 {
|
||||
|
||||
pub async fn get_version_deserialized(&self, id: &str, pat: Option<&str>) -> Version {
|
||||
let resp = self.get_version(id, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ impl ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> HashMap<String, Version> {
|
||||
let resp = self.update_individual_files(algorithm, hashes, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
test::read_body_json(resp).await
|
||||
}
|
||||
}
|
||||
@@ -158,7 +158,7 @@ impl ApiVersion for ApiV3 {
|
||||
|
||||
async fn get_version_deserialized_common(&self, id: &str, pat: Option<&str>) -> CommonVersion {
|
||||
let resp = self.get_version(id, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: Version = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -217,7 +217,7 @@ impl ApiVersion for ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> CommonVersion {
|
||||
let resp = self.get_version_from_hash(hash, algorithm, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: Version = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -249,7 +249,7 @@ impl ApiVersion for ApiV3 {
|
||||
pat: Option<&str>,
|
||||
) -> HashMap<String, CommonVersion> {
|
||||
let resp = self.get_versions_from_hashes(hashes, algorithm, pat).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: HashMap<String, Version> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -301,7 +301,7 @@ impl ApiVersion for ApiV3 {
|
||||
let resp = self
|
||||
.get_update_from_hash(hash, algorithm, loaders, game_versions, version_types, pat)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: Version = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -361,7 +361,7 @@ impl ApiVersion for ApiV3 {
|
||||
pat,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: HashMap<String, Version> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
@@ -444,7 +444,7 @@ impl ApiVersion for ApiV3 {
|
||||
pat,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
// First, deserialize to the non-common format (to test the response is valid for this api version)
|
||||
let v: Vec<Version> = test::read_body_json(resp).await;
|
||||
// Then, deserialize to the common format
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use labrinth::database::redis::RedisPool;
|
||||
use labrinth::{database::redis::RedisPool, search};
|
||||
use sqlx::{postgres::PgPoolOptions, PgPool};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
@@ -39,6 +39,7 @@ const TEMPLATE_DATABASE_NAME: &str = "labrinth_tests_template";
|
||||
pub struct TemporaryDatabase {
|
||||
pub pool: PgPool,
|
||||
pub redis_pool: RedisPool,
|
||||
pub search_config: labrinth::search::SearchConfig,
|
||||
pub database_name: String,
|
||||
}
|
||||
|
||||
@@ -84,10 +85,13 @@ impl TemporaryDatabase {
|
||||
// Gets new Redis pool
|
||||
let redis_pool = RedisPool::new(Some(temp_database_name.clone()));
|
||||
|
||||
// Create new meilisearch config
|
||||
let search_config = search::SearchConfig::new(Some(temp_database_name.clone()));
|
||||
Self {
|
||||
pool,
|
||||
database_name: temp_database_name,
|
||||
redis_pool,
|
||||
search_config,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,10 +172,12 @@ impl TemporaryDatabase {
|
||||
|
||||
if !dummy_data_exists {
|
||||
// Add dummy data
|
||||
let name = generate_random_name("test_template_");
|
||||
let db = TemporaryDatabase {
|
||||
pool: pool.clone(),
|
||||
database_name: TEMPLATE_DATABASE_NAME.to_string(),
|
||||
redis_pool: RedisPool::new(Some(generate_random_name("test_template_"))),
|
||||
redis_pool: RedisPool::new(Some(name.clone())),
|
||||
search_config: search::SearchConfig::new(Some(name)),
|
||||
};
|
||||
let setup_api = TestEnvironment::<ApiV3>::build_setup_api(&db).await;
|
||||
dummy_data::add_dummy_data(&setup_api, db.clone()).await;
|
||||
|
||||
@@ -207,7 +207,7 @@ impl DummyData {
|
||||
organization_zeta: DummyOrganizationZeta {
|
||||
organization_id: organization_zeta.id.to_string(),
|
||||
team_id: organization_zeta.team_id.to_string(),
|
||||
organization_name: organization_zeta.name,
|
||||
organization_slug: organization_zeta.slug,
|
||||
},
|
||||
|
||||
oauth_client_alpha: DummyOAuthClientAlpha {
|
||||
@@ -249,7 +249,7 @@ pub struct DummyProjectBeta {
|
||||
#[derive(Clone)]
|
||||
pub struct DummyOrganizationZeta {
|
||||
pub organization_id: String,
|
||||
pub organization_name: String,
|
||||
pub organization_slug: String,
|
||||
pub team_id: String,
|
||||
}
|
||||
|
||||
@@ -390,7 +390,7 @@ pub async fn add_project_beta(api: &ApiV3) -> (Project, Version) {
|
||||
.set_multipart(vec![json_segment.clone(), file_segment.clone()])
|
||||
.to_request();
|
||||
let resp = api.call(req).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
get_project_beta(api).await
|
||||
}
|
||||
@@ -401,13 +401,14 @@ pub async fn add_organization_zeta(api: &ApiV3) -> Organization {
|
||||
.uri("/v3/organization")
|
||||
.append_pat(USER_USER_PAT)
|
||||
.set_json(json!({
|
||||
"name": "zeta",
|
||||
"name": "Zeta",
|
||||
"slug": "zeta",
|
||||
"description": "A dummy organization for testing with."
|
||||
}))
|
||||
.to_request();
|
||||
let resp = api.call(req).await;
|
||||
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
get_organization_zeta(api).await
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ pub async fn setup(db: &database::TemporaryDatabase) -> LabrinthConfig {
|
||||
|
||||
let pool = db.pool.clone();
|
||||
let redis_pool = db.redis_pool.clone();
|
||||
let search_config = db.search_config.clone();
|
||||
let file_host: Arc<dyn file_hosting::FileHost + Send + Sync> =
|
||||
Arc::new(file_hosting::MockHost::new());
|
||||
let mut clickhouse = clickhouse::init_client().await.unwrap();
|
||||
@@ -36,6 +37,7 @@ pub async fn setup(db: &database::TemporaryDatabase) -> LabrinthConfig {
|
||||
labrinth::app_setup(
|
||||
pool.clone(),
|
||||
redis_pool.clone(),
|
||||
search_config,
|
||||
&mut clickhouse,
|
||||
file_host.clone(),
|
||||
maxmind_reader,
|
||||
|
||||
@@ -356,12 +356,13 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
.await;
|
||||
if !self.allowed_failure_codes.contains(&resp.status().as_u16()) {
|
||||
return Err(format!(
|
||||
"Failure permissions test failed. Expected failure codes {} got {}",
|
||||
"Failure permissions test failed. Expected failure codes {} got {}. Body: {:#?}",
|
||||
self.allowed_failure_codes
|
||||
.iter()
|
||||
.map(|code| code.to_string())
|
||||
.join(","),
|
||||
resp.status().as_u16()
|
||||
resp.status().as_u16(),
|
||||
resp.response().body()
|
||||
));
|
||||
}
|
||||
|
||||
@@ -385,8 +386,9 @@ impl<'a, A: Api> PermissionsTest<'a, A> {
|
||||
.await;
|
||||
if !resp.status().is_success() {
|
||||
return Err(format!(
|
||||
"Success permissions test failed. Expected success, got {}",
|
||||
resp.status().as_u16()
|
||||
"Success permissions test failed. Expected success, got {}. Body: {:#?}",
|
||||
resp.status().as_u16(),
|
||||
resp.response().body()
|
||||
));
|
||||
}
|
||||
|
||||
@@ -1007,15 +1009,15 @@ async fn create_dummy_project(setup_api: &ApiV3) -> (String, String) {
|
||||
|
||||
async fn create_dummy_org(setup_api: &ApiV3) -> (String, String) {
|
||||
// Create a very simple organization
|
||||
let name = generate_random_name("test_org");
|
||||
let slug = generate_random_name("test_org");
|
||||
|
||||
let resp = setup_api
|
||||
.create_organization(&name, "Example description.", ADMIN_USER_PAT)
|
||||
.create_organization("Example org", &slug, "Example description.", ADMIN_USER_PAT)
|
||||
.await;
|
||||
assert!(resp.status().is_success());
|
||||
|
||||
let organization = setup_api
|
||||
.get_organization_deserialized(&name, ADMIN_USER_PAT)
|
||||
.get_organization_deserialized(&slug, ADMIN_USER_PAT)
|
||||
.await;
|
||||
let organizaion_id = organization.id.to_string();
|
||||
let team_id = organization.team_id.to_string();
|
||||
@@ -1109,7 +1111,7 @@ async fn get_project_permissions(
|
||||
.await;
|
||||
let permissions = members
|
||||
.iter()
|
||||
.find(|member| &member.user.id.to_string() == user_id)
|
||||
.find(|member| member.user.id.to_string() == user_id)
|
||||
.and_then(|member| member.permissions);
|
||||
|
||||
let organization_members = match organization {
|
||||
@@ -1123,7 +1125,7 @@ async fn get_project_permissions(
|
||||
let organization_default_project_permissions = match organization_members {
|
||||
Some(members) => members
|
||||
.iter()
|
||||
.find(|member| &member.user.id.to_string() == user_id)
|
||||
.find(|member| member.user.id.to_string() == user_id)
|
||||
.and_then(|member| member.permissions),
|
||||
None => None,
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use actix_http::StatusCode;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::common::{
|
||||
@@ -10,7 +11,7 @@ use crate::common::{
|
||||
dummy_data::{TestFile, DUMMY_CATEGORIES},
|
||||
};
|
||||
|
||||
use super::{api_v3::ApiV3, environment::TestEnvironment};
|
||||
use super::{api_v3::ApiV3, asserts::assert_status, environment::TestEnvironment};
|
||||
|
||||
pub async fn setup_search_projects(test_env: &TestEnvironment<ApiV3>) -> Arc<HashMap<u64, u64>> {
|
||||
// Test setup and dummy data
|
||||
@@ -47,7 +48,7 @@ pub async fn setup_search_projects(test_env: &TestEnvironment<ApiV3>) -> Arc<Has
|
||||
MOD_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
(project.id.0, id)
|
||||
}
|
||||
};
|
||||
@@ -209,7 +210,7 @@ pub async fn setup_search_projects(test_env: &TestEnvironment<ApiV3>) -> Arc<Has
|
||||
|
||||
// Forcibly reset the search index
|
||||
let resp = api.reset_search_index().await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
id_conversion
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::test;
|
||||
use bytes::Bytes;
|
||||
use common::api_common::ApiProject;
|
||||
@@ -6,6 +7,8 @@ use common::api_v3::ApiV3;
|
||||
use common::database::USER_USER_PAT;
|
||||
use common::environment::{with_test_environment, TestEnvironment};
|
||||
|
||||
use crate::common::asserts::assert_status;
|
||||
|
||||
mod common;
|
||||
|
||||
#[actix_rt::test]
|
||||
@@ -14,7 +17,7 @@ pub async fn error_404_body() {
|
||||
// 3 errors should have 404 as non-blank body, for missing resources
|
||||
let api = &test_env.api;
|
||||
let resp = api.get_project("does-not-exist", USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 404);
|
||||
assert_status(&resp, StatusCode::NOT_FOUND);
|
||||
let body = test::read_body(resp).await;
|
||||
let empty_bytes = Bytes::from_static(b"");
|
||||
assert_ne!(body, empty_bytes);
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use actix_http::StatusCode;
|
||||
use common::api_v3::ApiV3;
|
||||
use common::environment::{with_test_environment, TestEnvironment};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::common::api_common::ApiVersion;
|
||||
use crate::common::asserts::assert_status;
|
||||
use crate::common::database::*;
|
||||
|
||||
use crate::common::dummy_data::{DummyProjectAlpha, DummyProjectBeta, TestFile};
|
||||
@@ -49,7 +51,7 @@ async fn creating_loader_fields() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
// - Patch
|
||||
let resp = api
|
||||
.edit_version(
|
||||
@@ -60,7 +62,7 @@ async fn creating_loader_fields() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Cannot create a version with a loader field that isnt used by the loader
|
||||
// TODO: - Create project
|
||||
@@ -82,7 +84,7 @@ async fn creating_loader_fields() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
// - Patch
|
||||
let resp = api
|
||||
.edit_version(
|
||||
@@ -93,7 +95,7 @@ async fn creating_loader_fields() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Cannot create a version without an applicable loader field that is not optional
|
||||
// TODO: - Create project
|
||||
@@ -115,7 +117,7 @@ async fn creating_loader_fields() {
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Cannot create a version without a loader field array that has a minimum of 1
|
||||
// TODO: - Create project
|
||||
@@ -136,7 +138,7 @@ async fn creating_loader_fields() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// TODO: Create a test for too many elements in the array when we have a LF that has a max (past max)
|
||||
// Cannot create a version with a loader field array that has fewer than the minimum elements
|
||||
@@ -159,7 +161,7 @@ async fn creating_loader_fields() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// - Patch
|
||||
let resp = api
|
||||
@@ -171,7 +173,7 @@ async fn creating_loader_fields() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Cannot create an invalid data type for the loader field type (including bad variant for the type)
|
||||
for bad_type_game_versions in [
|
||||
@@ -199,7 +201,7 @@ async fn creating_loader_fields() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// - Patch
|
||||
let resp = api
|
||||
@@ -211,7 +213,7 @@ async fn creating_loader_fields() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Can create with optional loader fields (other tests have checked if we can create without them)
|
||||
@@ -245,7 +247,7 @@ async fn creating_loader_fields() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
let v = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
.await;
|
||||
@@ -296,7 +298,7 @@ async fn creating_loader_fields() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
let v = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
.await;
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
use crate::common::{
|
||||
api_common::{ApiProject, ApiTeams},
|
||||
asserts::assert_status,
|
||||
database::{
|
||||
generate_random_name, ADMIN_USER_PAT, ENEMY_USER_ID_PARSED, ENEMY_USER_PAT,
|
||||
FRIEND_USER_ID_PARSED, MOD_USER_ID, MOD_USER_PAT, USER_USER_ID, USER_USER_ID_PARSED,
|
||||
},
|
||||
dummy_data::{DummyImage, DummyOrganizationZeta, DummyProjectAlpha, DummyProjectBeta},
|
||||
};
|
||||
use actix_http::StatusCode;
|
||||
use common::{
|
||||
api_v3::ApiV3,
|
||||
database::{FRIEND_USER_ID, FRIEND_USER_PAT, USER_USER_PAT},
|
||||
@@ -27,45 +29,61 @@ async fn create_organization() {
|
||||
let zeta_organization_slug = &test_env.dummy.organization_zeta.organization_id;
|
||||
|
||||
// Failed creations title:
|
||||
// - too short title
|
||||
// - too long title
|
||||
for title in ["a", &"a".repeat(100)] {
|
||||
let resp = api
|
||||
.create_organization(title, "theta", "theta_description", USER_USER_PAT)
|
||||
.await;
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Failed creations slug:
|
||||
// - slug collision with zeta
|
||||
// - too short slug
|
||||
// - too long slug
|
||||
// - not url safe slug
|
||||
for title in [
|
||||
for slug in [
|
||||
zeta_organization_slug,
|
||||
"a",
|
||||
&"a".repeat(100),
|
||||
"not url safe%&^!#$##!@#$%^&*()",
|
||||
] {
|
||||
let resp = api
|
||||
.create_organization(title, "theta_description", USER_USER_PAT)
|
||||
.create_organization("Theta Org", slug, "theta_description", USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Failed creations description:
|
||||
// - too short slug
|
||||
// - too long slug
|
||||
// - too short desc
|
||||
// - too long desc
|
||||
for description in ["a", &"a".repeat(300)] {
|
||||
let resp = api
|
||||
.create_organization("theta", description, USER_USER_PAT)
|
||||
.create_organization("Theta Org", "theta", description, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Create 'theta' organization
|
||||
let resp = api
|
||||
.create_organization("theta", "not url safe%&^!#$##!@#$%^&", USER_USER_PAT)
|
||||
.create_organization(
|
||||
"Theta Org",
|
||||
"theta",
|
||||
"not url safe%&^!#$##!@#$%^&",
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Get organization using slug
|
||||
let theta = api
|
||||
.get_organization_deserialized("theta", USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(theta.name, "theta");
|
||||
assert_eq!(theta.name, "Theta Org");
|
||||
assert_eq!(theta.slug, "theta");
|
||||
assert_eq!(theta.description, "not url safe%&^!#$##!@#$%^&");
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Get created team
|
||||
let members = api
|
||||
@@ -95,7 +113,7 @@ async fn get_project_organization() {
|
||||
let resp = api
|
||||
.organization_add_project(zeta_organization_id, alpha_project_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Get project organization
|
||||
let zeta = api
|
||||
@@ -115,9 +133,25 @@ async fn patch_organization() {
|
||||
|
||||
// Create 'theta' organization
|
||||
let resp = api
|
||||
.create_organization("theta", "theta_description", USER_USER_PAT)
|
||||
.create_organization("Theta Org", "theta", "theta_description", USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Failed patch to theta title:
|
||||
// - too short title
|
||||
// - too long title
|
||||
for title in ["a", &"a".repeat(100)] {
|
||||
let resp = api
|
||||
.edit_organization(
|
||||
"theta",
|
||||
json!({
|
||||
"name": title,
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Failed patch to zeta slug:
|
||||
// - slug collision with theta
|
||||
@@ -134,13 +168,13 @@ async fn patch_organization() {
|
||||
.edit_organization(
|
||||
zeta_organization_id,
|
||||
json!({
|
||||
"name": title,
|
||||
"slug": title,
|
||||
"description": "theta_description"
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Failed patch to zeta description:
|
||||
@@ -156,7 +190,7 @@ async fn patch_organization() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Successful patch to many fields
|
||||
@@ -165,18 +199,20 @@ async fn patch_organization() {
|
||||
zeta_organization_id,
|
||||
json!({
|
||||
"name": "new_title",
|
||||
"slug": "new_slug",
|
||||
"description": "not url safe%&^!#$##!@#$%^&" // not-URL-safe description should still work
|
||||
}),
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Get project using new slug
|
||||
let new_title = api
|
||||
.get_organization_deserialized("new_title", USER_USER_PAT)
|
||||
.get_organization_deserialized("new_slug", USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(new_title.name, "new_title");
|
||||
assert_eq!(new_title.slug, "new_slug");
|
||||
assert_eq!(new_title.description, "not url safe%&^!#$##!@#$%^&");
|
||||
})
|
||||
.await;
|
||||
@@ -185,7 +221,7 @@ async fn patch_organization() {
|
||||
// add/remove icon
|
||||
#[actix_rt::test]
|
||||
async fn add_remove_icon() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
with_test_environment(Some(10), |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let api = &test_env.api;
|
||||
let zeta_organization_id = &test_env.dummy.organization_zeta.organization_id;
|
||||
|
||||
@@ -205,7 +241,7 @@ async fn add_remove_icon() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Get project
|
||||
let zeta_org = api
|
||||
@@ -218,7 +254,7 @@ async fn add_remove_icon() {
|
||||
let resp = api
|
||||
.edit_organization_icon(zeta_organization_id, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Get project
|
||||
let zeta_org = api
|
||||
@@ -239,13 +275,13 @@ async fn delete_org() {
|
||||
let resp = api
|
||||
.delete_organization(zeta_organization_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Get organization, which should no longer exist
|
||||
let resp = api
|
||||
.get_organization(zeta_organization_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 404);
|
||||
assert_status(&resp, StatusCode::NOT_FOUND);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
@@ -264,7 +300,7 @@ async fn add_remove_organization_projects() {
|
||||
.api
|
||||
.organization_add_project(zeta_organization_id, alpha, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Get organization projects
|
||||
let projects = test_env
|
||||
@@ -284,7 +320,7 @@ async fn add_remove_organization_projects() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Get organization projects
|
||||
let projects = test_env
|
||||
@@ -338,11 +374,11 @@ async fn add_remove_organization_project_ownership_to_user() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Accept invites
|
||||
let resp = test_env.api.join_team(team, FRIEND_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
}
|
||||
|
||||
// For each team, confirm there are two members, but only one owner of the project, and it is USER_USER_ID
|
||||
@@ -362,7 +398,7 @@ async fn add_remove_organization_project_ownership_to_user() {
|
||||
.api
|
||||
.transfer_team_ownership(beta_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Confirm there are still two users, but now FRIEND_USER_ID is the owner
|
||||
let members = test_env
|
||||
@@ -383,7 +419,7 @@ async fn add_remove_organization_project_ownership_to_user() {
|
||||
.api
|
||||
.organization_add_project(zeta_organization_id, project_id, pat)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Get and confirm it has been added
|
||||
let project = test_env.api.get_project_deserialized(project_id, pat).await;
|
||||
@@ -416,7 +452,7 @@ async fn add_remove_organization_project_ownership_to_user() {
|
||||
.api
|
||||
.transfer_team_ownership(zeta_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Confirm there are no members of the alpha project OR the beta project
|
||||
// - Friend was removed as a member of these projects when ownership was transferred to them
|
||||
@@ -433,14 +469,14 @@ async fn add_remove_organization_project_ownership_to_user() {
|
||||
.api
|
||||
.add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// As friend, can add user to alpha project, as they are not the org owner
|
||||
let resp = test_env
|
||||
.api
|
||||
.add_user_to_team(alpha_team_id, USER_USER_ID, None, None, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// At this point, friend owns the org
|
||||
// Alpha member has user as a member, but not as an owner
|
||||
@@ -457,7 +493,7 @@ async fn add_remove_organization_project_ownership_to_user() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Set user's permissions within the project that it is a member of to none (for a later test)
|
||||
let resp = test_env
|
||||
@@ -471,7 +507,7 @@ async fn add_remove_organization_project_ownership_to_user() {
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Remove project from organization with a user that is an organization member, and a project member
|
||||
// This should succeed
|
||||
@@ -484,7 +520,7 @@ async fn add_remove_organization_project_ownership_to_user() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Remove project from organization with a user that is an organization member, but not a project member
|
||||
// This should succeed
|
||||
@@ -497,7 +533,7 @@ async fn add_remove_organization_project_ownership_to_user() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// For each of alpha and beta, confirm:
|
||||
// - There is one member of each project, the owner, USER_USER_ID
|
||||
@@ -559,11 +595,11 @@ async fn delete_organization_means_all_projects_to_org_owner() {
|
||||
.api
|
||||
.add_user_to_team(zeta_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Accept invite
|
||||
let resp = test_env.api.join_team(zeta_team_id, FRIEND_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Confirm there is only one owner of the project, and it is USER_USER_ID
|
||||
let members = test_env
|
||||
@@ -579,7 +615,7 @@ async fn delete_organization_means_all_projects_to_org_owner() {
|
||||
.api
|
||||
.organization_add_project(zeta_organization_id, alpha_project_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Add beta to zeta organization
|
||||
test_env
|
||||
@@ -592,13 +628,13 @@ async fn delete_organization_means_all_projects_to_org_owner() {
|
||||
.api
|
||||
.add_user_to_team(beta_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Try to accept invite
|
||||
// This returns a failure, because since beta and FRIEND are in the organizations,
|
||||
// they can be added to the project without an invite
|
||||
let resp = test_env.api.join_team(beta_team_id, FRIEND_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Confirm there is NO owner of the project, as it is owned by the organization
|
||||
let members = test_env
|
||||
@@ -613,7 +649,7 @@ async fn delete_organization_means_all_projects_to_org_owner() {
|
||||
.api
|
||||
.transfer_team_ownership(zeta_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Confirm there is NO owner of the project, as it is owned by the organization
|
||||
let members = test_env
|
||||
@@ -628,7 +664,7 @@ async fn delete_organization_means_all_projects_to_org_owner() {
|
||||
.api
|
||||
.delete_organization(zeta_organization_id, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Confirm there is only one owner of the alpha project, and it is now FRIEND_USER_ID
|
||||
let members = test_env
|
||||
@@ -708,7 +744,7 @@ async fn permissions_patch_organization() {
|
||||
// Not covered by PATCH /organization
|
||||
#[actix_rt::test]
|
||||
async fn permissions_edit_details() {
|
||||
with_test_environment(None, |test_env: TestEnvironment<ApiV3>| async move {
|
||||
with_test_environment(Some(12), |test_env: TestEnvironment<ApiV3>| async move {
|
||||
let zeta_organization_id = &test_env.dummy.organization_zeta.organization_id;
|
||||
let zeta_team_id = &test_env.dummy.organization_zeta.team_id;
|
||||
|
||||
@@ -814,9 +850,9 @@ async fn permissions_manage_invites() {
|
||||
let resp = api
|
||||
.add_user_to_team(zeta_team_id, MOD_USER_ID, None, None, ADMIN_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
let resp = api.join_team(zeta_team_id, MOD_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// remove existing member (requires remove_member)
|
||||
let remove_member = OrganizationPermissions::REMOVE_MEMBER;
|
||||
@@ -852,13 +888,13 @@ async fn permissions_add_remove_project() {
|
||||
let resp = api
|
||||
.add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
let resp = api.join_team(alpha_team_id, FRIEND_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Now, FRIEND_USER_ID owns the alpha project
|
||||
// Add alpha project to zeta organization
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::test;
|
||||
use chrono::{Duration, Utc};
|
||||
use common::{database::*, environment::with_test_environment_all};
|
||||
@@ -5,7 +6,7 @@ use common::{database::*, environment::with_test_environment_all};
|
||||
use labrinth::models::pats::Scopes;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::common::api_common::AppendsOptionalPat;
|
||||
use crate::common::{api_common::AppendsOptionalPat, asserts::assert_status};
|
||||
|
||||
mod common;
|
||||
|
||||
@@ -30,7 +31,7 @@ pub async fn pat_full_test() {
|
||||
}))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status().as_u16(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
let success: serde_json::Value = test::read_body_json(resp).await;
|
||||
let id = success["id"].as_str().unwrap();
|
||||
|
||||
@@ -48,7 +49,7 @@ pub async fn pat_full_test() {
|
||||
.uri("/_internal/pat")
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status().as_u16(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
let success: serde_json::Value = test::read_body_json(resp).await;
|
||||
|
||||
// Ensure access token is NOT returned for any PATs
|
||||
@@ -87,7 +88,7 @@ pub async fn pat_full_test() {
|
||||
}))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status().as_u16(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
assert_eq!(mock_pat_test(access_token).await, 401); // No longer works
|
||||
|
||||
// Change scopes back, and set expiry to the past, and test again
|
||||
@@ -100,7 +101,7 @@ pub async fn pat_full_test() {
|
||||
}))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status().as_u16(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Wait 1 second before testing again for expiry
|
||||
tokio::time::sleep(Duration::seconds(1).to_std().unwrap()).await;
|
||||
@@ -115,7 +116,7 @@ pub async fn pat_full_test() {
|
||||
}))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status().as_u16(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
assert_eq!(mock_pat_test(access_token).await, 200); // Works again
|
||||
|
||||
// Patching to a bad expiry should fail
|
||||
@@ -127,7 +128,7 @@ pub async fn pat_full_test() {
|
||||
}))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status().as_u16(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Similar to above with PAT creation, patching to a bad scope should fail
|
||||
for i in 0..64 {
|
||||
@@ -156,7 +157,7 @@ pub async fn pat_full_test() {
|
||||
.uri(&format!("/_internal/pat/{}", id))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status().as_u16(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
@@ -175,7 +176,7 @@ pub async fn bad_pats() {
|
||||
}))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status().as_u16(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Name too short or too long should fail
|
||||
for name in ["n", "this_name_is_too_long".repeat(16).as_str()] {
|
||||
@@ -189,7 +190,7 @@ pub async fn bad_pats() {
|
||||
}))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status().as_u16(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Creating a PAT with an expiry in the past should fail
|
||||
@@ -203,7 +204,7 @@ pub async fn bad_pats() {
|
||||
}))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status().as_u16(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Make a PAT with each scope, with the result varying by whether that scope is restricted
|
||||
for i in 0..64 {
|
||||
@@ -238,7 +239,7 @@ pub async fn bad_pats() {
|
||||
}))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status().as_u16(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
let success: serde_json::Value = test::read_body_json(resp).await;
|
||||
let id = success["id"].as_str().unwrap();
|
||||
|
||||
@@ -252,7 +253,7 @@ pub async fn bad_pats() {
|
||||
}))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status().as_u16(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Patching to a bad expiry should fail
|
||||
@@ -264,7 +265,7 @@ pub async fn bad_pats() {
|
||||
}))
|
||||
.to_request();
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status().as_u16(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Similar to above with PAT creation, patching to a bad scope should fail
|
||||
for i in 0..64 {
|
||||
|
||||
214
tests/project.rs
214
tests/project.rs
@@ -3,6 +3,7 @@ use std::collections::HashMap;
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::test;
|
||||
use common::api_v3::ApiV3;
|
||||
use common::asserts::assert_status;
|
||||
use common::database::*;
|
||||
use common::dummy_data::DUMMY_CATEGORIES;
|
||||
|
||||
@@ -20,7 +21,9 @@ 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};
|
||||
use crate::common::dummy_data::{DummyImage, DummyProjectAlpha, DummyProjectBeta, TestFile};
|
||||
use crate::common::dummy_data::{
|
||||
DummyImage, DummyOrganizationZeta, DummyProjectAlpha, DummyProjectBeta, TestFile,
|
||||
};
|
||||
mod common;
|
||||
|
||||
#[actix_rt::test]
|
||||
@@ -42,10 +45,9 @@ async fn test_get_project() {
|
||||
|
||||
// Perform request on dummy data
|
||||
let resp = api.get_project(alpha_project_id, USER_USER_PAT).await;
|
||||
let status = resp.status();
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
let body: serde_json::Value = test::read_body_json(resp).await;
|
||||
|
||||
assert_eq!(status, 200);
|
||||
assert_eq!(body["id"], json!(alpha_project_id));
|
||||
assert_eq!(body["slug"], json!(alpha_project_slug));
|
||||
let versions = body["versions"].as_array().unwrap();
|
||||
@@ -75,8 +77,7 @@ async fn test_get_project() {
|
||||
|
||||
// Make the request again, this time it should be cached
|
||||
let resp = api.get_project(alpha_project_id, USER_USER_PAT).await;
|
||||
let status = resp.status();
|
||||
assert_eq!(status, 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
let body: serde_json::Value = test::read_body_json(resp).await;
|
||||
assert_eq!(body["id"], json!(alpha_project_id));
|
||||
@@ -84,11 +85,11 @@ async fn test_get_project() {
|
||||
|
||||
// Request should fail on non-existent project
|
||||
let resp = api.get_project("nonexistent", USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 404);
|
||||
assert_status(&resp, StatusCode::NOT_FOUND);
|
||||
|
||||
// Similarly, request should fail on non-authorized user, on a yet-to-be-approved or hidden project, with a 404 (hiding the existence of the project)
|
||||
let resp = api.get_project(beta_project_id, ENEMY_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 404);
|
||||
assert_status(&resp, StatusCode::NOT_FOUND);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
@@ -170,8 +171,7 @@ async fn test_add_remove_project() {
|
||||
)
|
||||
.await;
|
||||
|
||||
let status = resp.status();
|
||||
assert_eq!(status, 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Get the project we just made, and confirm that it's correct
|
||||
let project = api
|
||||
@@ -204,7 +204,7 @@ async fn test_add_remove_project() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Reusing with the same slug and a different file should fail
|
||||
let resp = api
|
||||
@@ -220,7 +220,7 @@ async fn test_add_remove_project() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Different slug, different file should succeed
|
||||
let resp = api
|
||||
@@ -236,7 +236,7 @@ async fn test_add_remove_project() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Get
|
||||
let project = api
|
||||
@@ -246,7 +246,7 @@ async fn test_add_remove_project() {
|
||||
|
||||
// Remove the project
|
||||
let resp = test_env.api.remove_project("demo", USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Confirm that the project is gone from the cache
|
||||
let mut redis_pool = test_env.db.redis_pool.connect().await.unwrap();
|
||||
@@ -269,7 +269,7 @@ async fn test_add_remove_project() {
|
||||
|
||||
// Old slug no longer works
|
||||
let resp = api.get_project("demo", USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 404);
|
||||
assert_status(&resp, StatusCode::NOT_FOUND);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
@@ -293,7 +293,7 @@ pub async fn test_patch_project() {
|
||||
ENEMY_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
assert_status(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// Failure because we are setting URL fields to invalid urls.
|
||||
for url_type in ["issues", "source", "wiki", "discord"] {
|
||||
@@ -308,7 +308,7 @@ pub async fn test_patch_project() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Failure because these are illegal requested statuses for a normal user.
|
||||
@@ -322,7 +322,7 @@ pub async fn test_patch_project() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Failure because these should not be able to be set by a non-mod
|
||||
@@ -336,7 +336,7 @@ pub async fn test_patch_project() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
assert_status(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// (should work for a mod, though)
|
||||
let resp = api
|
||||
@@ -348,7 +348,7 @@ pub async fn test_patch_project() {
|
||||
MOD_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
}
|
||||
|
||||
// Failed patch to alpha slug:
|
||||
@@ -372,7 +372,7 @@ pub async fn test_patch_project() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Not allowed to directly set status, as 'beta_project_slug' (the other project) is "processing" and cannot have its status changed like this.
|
||||
@@ -385,7 +385,7 @@ pub async fn test_patch_project() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
assert_status(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// Sucessful request to patch many fields.
|
||||
let resp = api
|
||||
@@ -406,11 +406,11 @@ pub async fn test_patch_project() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Old slug no longer works
|
||||
let resp = api.get_project(alpha_project_slug, USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 404);
|
||||
assert_status(&resp, StatusCode::NOT_FOUND);
|
||||
|
||||
// New slug does work
|
||||
let project = api.get_project_deserialized("newslug", USER_USER_PAT).await;
|
||||
@@ -447,7 +447,7 @@ pub async fn test_patch_project() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
let project = api.get_project_deserialized("newslug", USER_USER_PAT).await;
|
||||
assert_eq!(project.link_urls.len(), 3);
|
||||
assert!(!project.link_urls.contains_key("issues"));
|
||||
@@ -475,7 +475,7 @@ pub async fn test_patch_v3() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let project = api
|
||||
.get_project_deserialized(alpha_project_slug, USER_USER_PAT)
|
||||
@@ -509,7 +509,7 @@ pub async fn test_bulk_edit_categories() {
|
||||
ADMIN_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), StatusCode::NO_CONTENT);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let alpha_body = api
|
||||
.get_project_deserialized_common(alpha_project_id, ADMIN_USER_PAT)
|
||||
@@ -552,7 +552,7 @@ pub async fn test_bulk_edit_links() {
|
||||
ADMIN_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), StatusCode::NO_CONTENT);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let alpha_body = api
|
||||
.get_project_deserialized(alpha_project_id, ADMIN_USER_PAT)
|
||||
@@ -597,7 +597,7 @@ async fn delete_project_with_report() {
|
||||
ENEMY_USER_PAT, // Enemy makes a report
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
let value = test::read_body_json::<serde_json::Value, _>(resp).await;
|
||||
let alpha_report_id = value["id"].as_str().unwrap();
|
||||
|
||||
@@ -608,7 +608,7 @@ async fn delete_project_with_report() {
|
||||
ENEMY_USER_PAT, // Enemy makes a report
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Do the same for beta
|
||||
let resp = api
|
||||
@@ -620,13 +620,13 @@ async fn delete_project_with_report() {
|
||||
ENEMY_USER_PAT, // Enemy makes a report
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_status(&resp, 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);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Confirm that the project is gone from the cache
|
||||
let mut redis_pool = test_env.db.redis_pool.connect().await.unwrap();
|
||||
@@ -654,7 +654,7 @@ async fn delete_project_with_report() {
|
||||
ENEMY_USER_PAT, // Enemy makes a report
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
|
||||
assert_status(&resp, StatusCode::NOT_FOUND);
|
||||
|
||||
// Confirm that report for beta still exists
|
||||
let resp = api
|
||||
@@ -663,7 +663,7 @@ async fn delete_project_with_report() {
|
||||
ENEMY_USER_PAT, // Enemy makes a report
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
@@ -815,7 +815,7 @@ async fn permissions_patch_project_v3() {
|
||||
// MOD_USER_PAT,
|
||||
// )
|
||||
// .await;
|
||||
// assert_eq!(resp.status(), 204);
|
||||
// assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// // Schedule version
|
||||
// let req_gen = |ctx: PermissionsTestContext| async move {
|
||||
@@ -839,7 +839,7 @@ async fn permissions_patch_project_v3() {
|
||||
// Not covered by PATCH /project
|
||||
#[actix_rt::test]
|
||||
async fn permissions_edit_details() {
|
||||
with_test_environment_all(None, |test_env| async move {
|
||||
with_test_environment_all(Some(10), |test_env| async move {
|
||||
let DummyProjectAlpha {
|
||||
project_id: alpha_project_id,
|
||||
team_id: alpha_team_id,
|
||||
@@ -1112,11 +1112,11 @@ async fn permissions_manage_invites() {
|
||||
ADMIN_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Accept invite
|
||||
let resp = api.join_team(alpha_team_id, MOD_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// remove existing member (requires remove_member)
|
||||
let remove_member = ProjectPermissions::REMOVE_MEMBER;
|
||||
@@ -1223,7 +1223,7 @@ async fn align_search_projects() {
|
||||
let project_model = api
|
||||
.get_project(&project.id.to_string(), USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(project_model.status(), 200);
|
||||
assert_status(&project_model, StatusCode::OK);
|
||||
let mut project_model: Project = test::read_body_json(project_model).await;
|
||||
|
||||
// Body/description is huge- don't store it in search, so it's OK if they differ here
|
||||
@@ -1233,9 +1233,24 @@ async fn align_search_projects() {
|
||||
// Aggregate project loader fields will not match exactly,
|
||||
// because the search will only return the matching version, whereas the project returns the aggregate.
|
||||
// So, we remove them from both.
|
||||
let project_model_mrpack_loaders: Vec<_> = project_model
|
||||
.fields
|
||||
.remove("mrpack_loaders")
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.filter_map(|v| v.as_str().map(|v| v.to_string()))
|
||||
.collect();
|
||||
project_model.fields = HashMap::new();
|
||||
project.fields = HashMap::new();
|
||||
|
||||
// For a similar reason we also remove the mrpack loaders from the additional categories of the search model
|
||||
// (Becasue they are not returned by the search)
|
||||
// TODO: get models to match *exactly* without an additional project fetch,
|
||||
// including these fields removed here
|
||||
project
|
||||
.additional_categories
|
||||
.retain(|x| !project_model_mrpack_loaders.contains(x));
|
||||
|
||||
let project_model = serde_json::to_value(project_model).unwrap();
|
||||
let searched_project_serialized = serde_json::to_value(project).unwrap();
|
||||
assert_eq!(project_model, searched_project_serialized);
|
||||
@@ -1244,6 +1259,129 @@ async fn align_search_projects() {
|
||||
.await
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn projects_various_visibility() {
|
||||
// For testing the filter_visible_projects and is_visible_project
|
||||
with_test_environment(
|
||||
None,
|
||||
|env: common::environment::TestEnvironment<ApiV3>| async move {
|
||||
let DummyProjectAlpha {
|
||||
project_id: alpha_project_id,
|
||||
project_id_parsed: alpha_project_id_parsed,
|
||||
..
|
||||
} = &env.dummy.project_alpha;
|
||||
let DummyProjectBeta {
|
||||
project_id: beta_project_id,
|
||||
project_id_parsed: beta_project_id_parsed,
|
||||
..
|
||||
} = &env.dummy.project_beta;
|
||||
let DummyOrganizationZeta {
|
||||
organization_id: zeta_organization_id,
|
||||
team_id: zeta_team_id,
|
||||
..
|
||||
} = &env.dummy.organization_zeta;
|
||||
|
||||
// Invite friend to org zeta and accept it
|
||||
let resp = env
|
||||
.api
|
||||
.add_user_to_team(
|
||||
zeta_team_id,
|
||||
FRIEND_USER_ID,
|
||||
Some(ProjectPermissions::empty()),
|
||||
None,
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
let resp = env.api.join_team(zeta_team_id, FRIEND_USER_PAT).await;
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let visible_pat_pairs = vec![
|
||||
(&alpha_project_id_parsed, USER_USER_PAT, StatusCode::OK),
|
||||
(&alpha_project_id_parsed, FRIEND_USER_PAT, StatusCode::OK),
|
||||
(&alpha_project_id_parsed, ENEMY_USER_PAT, StatusCode::OK),
|
||||
(&beta_project_id_parsed, USER_USER_PAT, StatusCode::OK),
|
||||
(
|
||||
&beta_project_id_parsed,
|
||||
FRIEND_USER_PAT,
|
||||
StatusCode::NOT_FOUND,
|
||||
),
|
||||
(
|
||||
&beta_project_id_parsed,
|
||||
ENEMY_USER_PAT,
|
||||
StatusCode::NOT_FOUND,
|
||||
),
|
||||
];
|
||||
|
||||
// Tests get_project, a route that uses is_visible_project
|
||||
for (project_id, pat, expected_status) in visible_pat_pairs {
|
||||
let resp = env.api.get_project(&project_id.to_string(), pat).await;
|
||||
assert_status(&resp, expected_status);
|
||||
}
|
||||
|
||||
// Test get_user_projects, a route that uses filter_visible_projects
|
||||
let visible_pat_pairs = vec![
|
||||
(USER_USER_PAT, 2),
|
||||
(FRIEND_USER_PAT, 1),
|
||||
(ENEMY_USER_PAT, 1),
|
||||
];
|
||||
for (pat, expected_count) in visible_pat_pairs {
|
||||
let projects = env
|
||||
.api
|
||||
.get_user_projects_deserialized_common(USER_USER_ID, pat)
|
||||
.await;
|
||||
assert_eq!(projects.len(), expected_count);
|
||||
}
|
||||
|
||||
// Add projects to org zeta
|
||||
let resp = env
|
||||
.api
|
||||
.organization_add_project(zeta_organization_id, alpha_project_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
let resp = env
|
||||
.api
|
||||
.organization_add_project(zeta_organization_id, beta_project_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Test get_project, a route that uses is_visible_project
|
||||
let visible_pat_pairs = vec![
|
||||
(&alpha_project_id_parsed, USER_USER_PAT, StatusCode::OK),
|
||||
(&alpha_project_id_parsed, FRIEND_USER_PAT, StatusCode::OK),
|
||||
(&alpha_project_id_parsed, ENEMY_USER_PAT, StatusCode::OK),
|
||||
(&beta_project_id_parsed, USER_USER_PAT, StatusCode::OK),
|
||||
(&beta_project_id_parsed, FRIEND_USER_PAT, StatusCode::OK),
|
||||
(
|
||||
&beta_project_id_parsed,
|
||||
ENEMY_USER_PAT,
|
||||
StatusCode::NOT_FOUND,
|
||||
),
|
||||
];
|
||||
|
||||
for (project_id, pat, expected_status) in visible_pat_pairs {
|
||||
let resp = env.api.get_project(&project_id.to_string(), pat).await;
|
||||
assert_status(&resp, expected_status);
|
||||
}
|
||||
|
||||
// Test get_user_projects, a route that uses filter_visible_projects
|
||||
let visible_pat_pairs = vec![
|
||||
(USER_USER_PAT, 2),
|
||||
(FRIEND_USER_PAT, 2),
|
||||
(ENEMY_USER_PAT, 1),
|
||||
];
|
||||
for (pat, expected_count) in visible_pat_pairs {
|
||||
let projects = env
|
||||
.api
|
||||
.get_user_projects_deserialized_common(USER_USER_ID, pat)
|
||||
.await;
|
||||
assert_eq!(projects.len(), expected_count);
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
// Route tests:
|
||||
// TODO: Missing routes on projects
|
||||
// TODO: using permissions/scopes, can we SEE projects existence that we are not allowed to? (ie 401 instead of 404)
|
||||
|
||||
@@ -2,12 +2,14 @@ use std::collections::HashMap;
|
||||
|
||||
use crate::common::api_common::{ApiProject, ApiTeams, ApiUser, ApiVersion, AppendsOptionalPat};
|
||||
use crate::common::dummy_data::{DummyImage, DummyProjectAlpha, DummyProjectBeta};
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::test;
|
||||
use chrono::{Duration, Utc};
|
||||
use common::api_common::models::CommonItemType;
|
||||
use common::api_common::Api;
|
||||
use common::api_v3::request_data::get_public_project_creation_data;
|
||||
use common::api_v3::ApiV3;
|
||||
use common::asserts::assert_status;
|
||||
use common::dummy_data::TestFile;
|
||||
use common::environment::{with_test_environment, with_test_environment_all, TestEnvironment};
|
||||
use common::{database::*, scopes::ScopeTest};
|
||||
@@ -114,7 +116,7 @@ pub async fn notifications_scopes() {
|
||||
.api
|
||||
.add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Notification get
|
||||
let read_notifications = Scopes::NOTIFICATION_READ;
|
||||
@@ -187,7 +189,7 @@ pub async fn notifications_scopes() {
|
||||
.api
|
||||
.add_user_to_team(alpha_team_id, MOD_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
let read_notifications = Scopes::NOTIFICATION_READ;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_user_notifications(MOD_USER_ID, pat.as_deref())
|
||||
@@ -386,7 +388,7 @@ pub async fn project_version_reads_scopes() {
|
||||
.api
|
||||
.edit_version(beta_version_id, json!({ "status": "draft" }), USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.get_version_from_hash(beta_file_hash, "sha1", pat.as_deref())
|
||||
@@ -1084,7 +1086,7 @@ pub async fn organization_scopes() {
|
||||
// Create organization
|
||||
let organization_create = Scopes::ORGANIZATION_CREATE;
|
||||
let req_gen = |pat: Option<String>| async move {
|
||||
api.create_organization("TestOrg", "TestOrg Description", pat.as_deref())
|
||||
api.create_organization("Test Org", "TestOrg", "TestOrg Description", pat.as_deref())
|
||||
.await
|
||||
};
|
||||
let (_, success) = ScopeTest::new(&test_env)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::common::{api_common::ApiTeams, database::*};
|
||||
use crate::common::{api_common::ApiTeams, asserts::assert_status, database::*};
|
||||
use actix_http::StatusCode;
|
||||
use common::{
|
||||
api_v3::ApiV3,
|
||||
environment::{with_test_environment, with_test_environment_all, TestEnvironment},
|
||||
@@ -39,7 +40,7 @@ async fn test_get_team() {
|
||||
let resp = api
|
||||
.add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Team check directly
|
||||
let members = api
|
||||
@@ -92,7 +93,7 @@ async fn test_get_team() {
|
||||
// An accepted member of the team should appear in the team members list
|
||||
// and should be able to see private data about the team
|
||||
let resp = api.join_team(alpha_team_id, FRIEND_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Team check directly
|
||||
let members = api
|
||||
@@ -163,7 +164,7 @@ async fn test_get_team_organization() {
|
||||
let resp = api
|
||||
.add_user_to_team(zeta_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Team check directly
|
||||
let members = api
|
||||
@@ -217,7 +218,7 @@ async fn test_get_team_organization() {
|
||||
// An accepted member of the team should appear in the team members list
|
||||
// and should be able to see private data about the team
|
||||
let resp = api.join_team(zeta_team_id, FRIEND_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Team check directly
|
||||
let members = api
|
||||
@@ -272,17 +273,17 @@ async fn test_get_team_project_orgs() {
|
||||
.api
|
||||
.organization_add_project(zeta_organization_id, alpha_project_id, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Invite and add friend to zeta
|
||||
let resp = test_env
|
||||
.api
|
||||
.add_user_to_team(zeta_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let resp = test_env.api.join_team(zeta_team_id, FRIEND_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// The team members route from teams (on a project's team):
|
||||
// - the members of the project team specifically
|
||||
@@ -315,19 +316,19 @@ async fn test_patch_project_team_member() {
|
||||
|
||||
// Edit team as admin/mod but not a part of the team should be OK
|
||||
let resp = api.edit_team_member(alpha_team_id, USER_USER_ID, json!({}), ADMIN_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// As a non-owner with full permissions, attempt to edit the owner's permissions
|
||||
let resp = api.edit_team_member(alpha_team_id, USER_USER_ID, json!({
|
||||
"permissions": 0
|
||||
}), ADMIN_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Should not be able to edit organization permissions of a project team
|
||||
let resp = api.edit_team_member(alpha_team_id, USER_USER_ID, json!({
|
||||
"organization_permissions": 0
|
||||
}), USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Should not be able to add permissions to a user that the adding-user does not have
|
||||
// (true for both project and org)
|
||||
@@ -336,24 +337,24 @@ async fn test_patch_project_team_member() {
|
||||
let resp = api.add_user_to_team(alpha_team_id, FRIEND_USER_ID,
|
||||
Some(ProjectPermissions::EDIT_MEMBER | ProjectPermissions::EDIT_BODY),
|
||||
None, USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// accept
|
||||
let resp = api.join_team(alpha_team_id, FRIEND_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// try to add permissions
|
||||
let resp = api.edit_team_member(alpha_team_id, FRIEND_USER_ID, json!({
|
||||
"permissions": (ProjectPermissions::EDIT_MEMBER | ProjectPermissions::EDIT_DETAILS).bits()
|
||||
}), FRIEND_USER_PAT).await; // should this be friend_user_pat
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Cannot set payouts outside of 0 and 5000
|
||||
for payout in [-1, 5001] {
|
||||
let resp = api.edit_team_member(alpha_team_id, FRIEND_USER_ID, json!({
|
||||
"payouts_split": payout
|
||||
}), USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Successful patch
|
||||
@@ -363,7 +364,7 @@ async fn test_patch_project_team_member() {
|
||||
"role": "membe2r",
|
||||
"ordering": 5
|
||||
}), FRIEND_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Check results
|
||||
let members = api.get_team_members_deserialized_common(alpha_team_id, FRIEND_USER_PAT).await;
|
||||
@@ -387,14 +388,14 @@ async fn test_patch_organization_team_member() {
|
||||
.api
|
||||
.edit_team_member(zeta_team_id, USER_USER_ID, json!({}), ADMIN_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// As a non-owner with full permissions, attempt to edit the owner's permissions
|
||||
let resp = test_env
|
||||
.api
|
||||
.edit_team_member(zeta_team_id, USER_USER_ID, json!({ "permissions": 0 }), ADMIN_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Should not be able to add permissions to a user that the adding-user does not have
|
||||
// (true for both project and org)
|
||||
@@ -404,18 +405,18 @@ async fn test_patch_organization_team_member() {
|
||||
.api
|
||||
.add_user_to_team(zeta_team_id, FRIEND_USER_ID, None, Some(OrganizationPermissions::EDIT_MEMBER | OrganizationPermissions::EDIT_MEMBER_DEFAULT_PERMISSIONS), USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// accept
|
||||
let resp = test_env.api.join_team(zeta_team_id, FRIEND_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// try to add permissions- fails, as we do not have EDIT_DETAILS
|
||||
let resp = test_env
|
||||
.api
|
||||
.edit_team_member(zeta_team_id, FRIEND_USER_ID, json!({ "organization_permissions": (OrganizationPermissions::EDIT_MEMBER | OrganizationPermissions::EDIT_DETAILS).bits() }), FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Cannot set payouts outside of 0 and 5000
|
||||
for payout in [-1, 5001] {
|
||||
@@ -423,7 +424,7 @@ async fn test_patch_organization_team_member() {
|
||||
.api
|
||||
.edit_team_member(zeta_team_id, FRIEND_USER_ID, json!({ "payouts_split": payout }), USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Successful patch
|
||||
@@ -442,7 +443,7 @@ async fn test_patch_organization_team_member() {
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Check results
|
||||
let members = test_env
|
||||
@@ -481,39 +482,39 @@ async fn transfer_ownership_v3() {
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
assert_status(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// first, invite friend
|
||||
let resp = api
|
||||
.add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// still cannot set friend as owner (not accepted)
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// accept
|
||||
let resp = api.join_team(alpha_team_id, FRIEND_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Cannot set ourselves as owner if we are not owner
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
assert_status(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// Can set friend as owner
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Check
|
||||
let members = api
|
||||
@@ -542,7 +543,7 @@ async fn transfer_ownership_v3() {
|
||||
let resp = api
|
||||
.remove_from_team(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
assert_status(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// V3 only- confirm the owner can change their role without losing ownership
|
||||
let resp = api
|
||||
@@ -555,7 +556,7 @@ async fn transfer_ownership_v3() {
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let members = api
|
||||
.get_team_members_deserialized(alpha_team_id, USER_USER_PAT)
|
||||
@@ -588,25 +589,25 @@ async fn transfer_ownership_v3() {
|
||||
|
||||
// // Link alpha team to zeta org
|
||||
// let resp = api.organization_add_project(zeta_organization_id, alpha_project_id, USER_USER_PAT).await;
|
||||
// assert_eq!(resp.status(), 200);
|
||||
// assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// // Invite friend to zeta team with all project default permissions
|
||||
// let resp = api.add_user_to_team(&zeta_team_id, FRIEND_USER_ID, Some(ProjectPermissions::all()), Some(OrganizationPermissions::all()), USER_USER_PAT).await;
|
||||
// assert_eq!(resp.status(), 204);
|
||||
// assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// // Accept invite to zeta team
|
||||
// let resp = api.join_team(&zeta_team_id, FRIEND_USER_PAT).await;
|
||||
// assert_eq!(resp.status(), 204);
|
||||
// assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// // Attempt, as friend, to edit details of alpha project (should succeed, org invite accepted)
|
||||
// let resp = api.edit_project(alpha_project_id, json!({
|
||||
// "title": "new name"
|
||||
// }), FRIEND_USER_PAT).await;
|
||||
// assert_eq!(resp.status(), 204);
|
||||
// assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// // Invite friend to alpha team with *no* project permissions
|
||||
// let resp = api.add_user_to_team(&alpha_team_id, FRIEND_USER_ID, Some(ProjectPermissions::empty()), None, USER_USER_PAT).await;
|
||||
// assert_eq!(resp.status(), 204);
|
||||
// assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// // Do not accept invite to alpha team
|
||||
|
||||
@@ -614,7 +615,7 @@ async fn transfer_ownership_v3() {
|
||||
// let resp = api.edit_project(alpha_project_id, json!({
|
||||
// "title": "new name"
|
||||
// }), FRIEND_USER_PAT).await;
|
||||
// assert_eq!(resp.status(), 401);
|
||||
// assert_status(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// test_env.cleanup().await;
|
||||
// }
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::common::api_common::ApiProject;
|
||||
use crate::common::asserts::assert_status;
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::test;
|
||||
use bytes::Bytes;
|
||||
|
||||
@@ -13,7 +15,7 @@ pub async fn error_404_empty() {
|
||||
// V2 errors should have 404 as blank body, for missing resources
|
||||
let api = &test_env.api;
|
||||
let resp = api.get_project("does-not-exist", USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 404);
|
||||
assert_status(&resp, StatusCode::NOT_FOUND);
|
||||
let body = test::read_body(resp).await;
|
||||
let empty_bytes = Bytes::from_static(b"");
|
||||
assert_eq!(body, empty_bytes);
|
||||
|
||||
@@ -3,6 +3,7 @@ use std::sync::Arc;
|
||||
use crate::common::{
|
||||
api_common::{ApiProject, ApiVersion, AppendsOptionalPat},
|
||||
api_v2::{request_data::get_public_project_creation_data_json, ApiV2},
|
||||
asserts::assert_status,
|
||||
database::{
|
||||
generate_random_name, ADMIN_USER_PAT, FRIEND_USER_ID, FRIEND_USER_PAT, USER_USER_PAT,
|
||||
},
|
||||
@@ -132,10 +133,8 @@ async fn test_add_remove_project() {
|
||||
.append_pat(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 resp: actix_web::dev::ServiceResponse = test_env.call(req).await;
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Get the project we just made, and confirm that it's correct
|
||||
let project = api.get_project_deserialized("demo", USER_USER_PAT).await;
|
||||
@@ -163,7 +162,7 @@ async fn test_add_remove_project() {
|
||||
.to_request();
|
||||
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Reusing with the same slug and a different file should fail
|
||||
let req = test::TestRequest::post()
|
||||
@@ -176,7 +175,7 @@ async fn test_add_remove_project() {
|
||||
.to_request();
|
||||
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// Different slug, different file should succeed
|
||||
let req = test::TestRequest::post()
|
||||
@@ -189,7 +188,7 @@ async fn test_add_remove_project() {
|
||||
.to_request();
|
||||
|
||||
let resp = test_env.call(req).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
|
||||
// Get
|
||||
let project = api.get_project_deserialized("demo", USER_USER_PAT).await;
|
||||
@@ -197,7 +196,7 @@ async fn test_add_remove_project() {
|
||||
|
||||
// Remove the project
|
||||
let resp = test_env.api.remove_project("demo", USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Confirm that the project is gone from the cache
|
||||
let mut redis_conn = test_env.db.redis_pool.connect().await.unwrap();
|
||||
@@ -220,7 +219,7 @@ async fn test_add_remove_project() {
|
||||
|
||||
// Old slug no longer works
|
||||
let resp = api.get_project("demo", USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 404);
|
||||
assert_status(&resp, StatusCode::NOT_FOUND);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
@@ -344,7 +343,7 @@ pub async fn test_patch_v2() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let project = api
|
||||
.get_project_deserialized(alpha_project_slug, USER_USER_PAT)
|
||||
@@ -456,7 +455,7 @@ pub async fn test_bulk_edit_links() {
|
||||
ADMIN_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), StatusCode::NO_CONTENT);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let alpha_body = api
|
||||
.get_project_deserialized(alpha_project_id, ADMIN_USER_PAT)
|
||||
@@ -496,7 +495,7 @@ pub async fn test_bulk_edit_links() {
|
||||
ADMIN_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), StatusCode::NO_CONTENT);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let alpha_body = api
|
||||
.get_project_deserialized(alpha_project_id, ADMIN_USER_PAT)
|
||||
@@ -568,7 +567,7 @@ pub async fn test_bulk_edit_links() {
|
||||
ADMIN_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), StatusCode::NO_CONTENT);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let alpha_body = api
|
||||
.get_project_deserialized(alpha_project_id, ADMIN_USER_PAT)
|
||||
|
||||
@@ -2,11 +2,13 @@ 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::asserts::assert_status;
|
||||
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 actix_http::StatusCode;
|
||||
use futures::stream::StreamExt;
|
||||
use labrinth::models::ids::base62_impl::parse_base62;
|
||||
use serde_json::json;
|
||||
@@ -53,7 +55,7 @@ async fn search_projects() {
|
||||
MOD_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
(project.id.0, id)
|
||||
}
|
||||
};
|
||||
@@ -282,7 +284,7 @@ async fn search_projects() {
|
||||
|
||||
// Forcibly reset the search index
|
||||
let resp = api.reset_search_index().await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Test searches
|
||||
let stream = futures::stream::iter(pairs);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use actix_http::StatusCode;
|
||||
use labrinth::models::teams::ProjectPermissions;
|
||||
use serde_json::json;
|
||||
|
||||
use crate::common::{
|
||||
api_common::ApiTeams,
|
||||
api_v2::ApiV2,
|
||||
asserts::assert_status,
|
||||
database::{
|
||||
FRIEND_USER_ID, FRIEND_USER_ID_PARSED, FRIEND_USER_PAT, USER_USER_ID_PARSED, USER_USER_PAT,
|
||||
},
|
||||
@@ -23,35 +25,35 @@ async fn transfer_ownership_v2() {
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// first, invite friend
|
||||
let resp = api
|
||||
.add_user_to_team(alpha_team_id, FRIEND_USER_ID, None, None, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// still cannot set friend as owner (not accepted)
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
|
||||
// accept
|
||||
let resp = api.join_team(alpha_team_id, FRIEND_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Cannot set ourselves as owner if we are not owner
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, FRIEND_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
assert_status(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// Can set friend as owner
|
||||
let resp = api
|
||||
.transfer_team_ownership(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
// Check
|
||||
let members = api
|
||||
@@ -78,7 +80,7 @@ async fn transfer_ownership_v2() {
|
||||
let resp = api
|
||||
.remove_from_team(alpha_team_id, FRIEND_USER_ID, USER_USER_PAT)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
assert_status(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// V2 only- confirm the owner changing the role to member does nothing
|
||||
let resp = api
|
||||
@@ -91,7 +93,7 @@ async fn transfer_ownership_v2() {
|
||||
FRIEND_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
let members = api
|
||||
.get_team_members_deserialized(alpha_team_id, USER_USER_PAT)
|
||||
.await;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use actix_http::StatusCode;
|
||||
use actix_web::test;
|
||||
use futures::StreamExt;
|
||||
use labrinth::models::projects::VersionId;
|
||||
@@ -9,6 +10,7 @@ use serde_json::json;
|
||||
|
||||
use crate::common::api_common::{ApiProject, ApiVersion};
|
||||
use crate::common::api_v2::ApiV2;
|
||||
use crate::common::asserts::assert_status;
|
||||
use crate::common::dummy_data::{DummyProjectAlpha, DummyProjectBeta};
|
||||
use crate::common::environment::{with_test_environment, TestEnvironment};
|
||||
use crate::common::{
|
||||
@@ -34,7 +36,7 @@ pub async fn test_patch_version() {
|
||||
ENEMY_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
assert_status(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// Failure because these are illegal requested statuses for a normal user.
|
||||
for req in ["unknown", "scheduled"] {
|
||||
@@ -48,7 +50,7 @@ pub async fn test_patch_version() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Sucessful request to patch many fields.
|
||||
@@ -72,7 +74,7 @@ pub async fn test_patch_version() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
@@ -100,7 +102,7 @@ pub async fn test_patch_version() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
@@ -117,7 +119,7 @@ pub async fn test_patch_version() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let version = api
|
||||
.get_version_deserialized(alpha_version_id, USER_USER_PAT)
|
||||
@@ -260,12 +262,12 @@ async fn version_updates() {
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
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_status(&resp, StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
// update_files
|
||||
|
||||
@@ -61,7 +61,7 @@ async fn test_get_version() {
|
||||
|
||||
// Request should fail on non-existent version
|
||||
let resp = api.get_version("false", USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 404);
|
||||
assert_status(&resp, StatusCode::NOT_FOUND);
|
||||
|
||||
// Similarly, request should fail on non-authorized user, on a yet-to-be-approved or hidden project, with a 404 (hiding the existence of the project)
|
||||
// TODO: beta version should already be draft in dummy data, but theres a bug in finding it that
|
||||
@@ -74,9 +74,9 @@ async fn test_get_version() {
|
||||
)
|
||||
.await;
|
||||
let resp = api.get_version(beta_version_id, USER_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
let resp = api.get_version(beta_version_id, ENEMY_USER_PAT).await;
|
||||
assert_eq!(resp.status(), 404);
|
||||
assert_status(&resp, StatusCode::NOT_FOUND);
|
||||
})
|
||||
.await;
|
||||
}
|
||||
@@ -219,12 +219,12 @@ async fn version_updates() {
|
||||
)
|
||||
.await;
|
||||
if success {
|
||||
assert_eq!(resp.status(), 200);
|
||||
assert_status(&resp, StatusCode::OK);
|
||||
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_status(&resp, StatusCode::NOT_FOUND);
|
||||
}
|
||||
|
||||
// update_files
|
||||
@@ -405,7 +405,7 @@ pub async fn test_patch_version() {
|
||||
ENEMY_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 401);
|
||||
assert_status(&resp, StatusCode::UNAUTHORIZED);
|
||||
|
||||
// Failure because these are illegal requested statuses for a normal user.
|
||||
for req in ["unknown", "scheduled"] {
|
||||
@@ -419,7 +419,7 @@ pub async fn test_patch_version() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 400);
|
||||
assert_status(&resp, StatusCode::BAD_REQUEST);
|
||||
}
|
||||
|
||||
// Sucessful request to patch many fields.
|
||||
@@ -447,7 +447,7 @@ pub async fn test_patch_version() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let version = api
|
||||
.get_version_deserialized_common(alpha_version_id, USER_USER_PAT)
|
||||
@@ -483,7 +483,7 @@ pub async fn test_patch_version() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let version = api
|
||||
.get_version_deserialized_common(alpha_version_id, USER_USER_PAT)
|
||||
@@ -499,7 +499,7 @@ pub async fn test_patch_version() {
|
||||
USER_USER_PAT,
|
||||
)
|
||||
.await;
|
||||
assert_eq!(resp.status(), 204);
|
||||
assert_status(&resp, StatusCode::NO_CONTENT);
|
||||
|
||||
let version = api
|
||||
.get_version_deserialized_common(alpha_version_id, USER_USER_PAT)
|
||||
|
||||
Reference in New Issue
Block a user