mirror of
https://github.com/Nutomic/ibis.git
synced 2024-11-25 23:01:08 +00:00
move some api methods to struct
This commit is contained in:
parent
150415e8ad
commit
173249ea8e
3 changed files with 158 additions and 151 deletions
|
@ -1,11 +1,17 @@
|
||||||
use crate::common::GetArticleData;
|
use crate::backend::api::article::{CreateArticleData, EditArticleData};
|
||||||
|
use crate::backend::api::instance::FollowInstance;
|
||||||
|
use crate::backend::api::{ResolveObject, SearchArticleData};
|
||||||
|
use crate::backend::database::conflict::ApiConflict;
|
||||||
|
use crate::backend::database::instance::{DbInstance, InstanceView};
|
||||||
use crate::common::LocalUserView;
|
use crate::common::LocalUserView;
|
||||||
use crate::common::{ArticleView, LoginUserData, RegisterUserData};
|
use crate::common::{ArticleView, LoginUserData, RegisterUserData};
|
||||||
|
use crate::common::{DbArticle, GetArticleData};
|
||||||
use crate::frontend::error::MyResult;
|
use crate::frontend::error::MyResult;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use reqwest::{Client, RequestBuilder};
|
use reqwest::{Client, RequestBuilder, StatusCode};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
pub static CLIENT: Lazy<Client> = Lazy::new(Client::new);
|
pub static CLIENT: Lazy<Client> = Lazy::new(Client::new);
|
||||||
|
|
||||||
|
@ -55,6 +61,84 @@ impl ApiClient {
|
||||||
.form(&login_form);
|
.form(&login_form);
|
||||||
handle_json_res::<LocalUserView>(req).await
|
handle_json_res::<LocalUserView>(req).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn create_article(&self, title: String, new_text: String) -> MyResult<ArticleView> {
|
||||||
|
let create_form = CreateArticleData {
|
||||||
|
title: title.clone(),
|
||||||
|
};
|
||||||
|
let req = self
|
||||||
|
.client
|
||||||
|
.post(format!("http://{}/api/v1/article", &self.hostname))
|
||||||
|
.form(&create_form);
|
||||||
|
let article: ArticleView = handle_json_res(req).await?;
|
||||||
|
|
||||||
|
// create initial edit to ensure that conflicts are generated (there are no conflicts on empty file)
|
||||||
|
// TODO: maybe take initial text directly in create article, no reason to have empty article
|
||||||
|
let edit_form = EditArticleData {
|
||||||
|
article_id: article.article.id,
|
||||||
|
new_text,
|
||||||
|
previous_version_id: article.latest_version,
|
||||||
|
resolve_conflict_id: None,
|
||||||
|
};
|
||||||
|
Ok(self.edit_article(&edit_form).await.unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn edit_article_with_conflict(
|
||||||
|
&self,
|
||||||
|
edit_form: &EditArticleData,
|
||||||
|
) -> MyResult<Option<ApiConflict>> {
|
||||||
|
let req = self
|
||||||
|
.client
|
||||||
|
.patch(format!("http://{}/api/v1/article", self.hostname))
|
||||||
|
.form(edit_form);
|
||||||
|
handle_json_res(req).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn edit_article(&self, edit_form: &EditArticleData) -> MyResult<ArticleView> {
|
||||||
|
let edit_res = self.edit_article_with_conflict(edit_form).await?;
|
||||||
|
assert!(edit_res.is_none());
|
||||||
|
|
||||||
|
self.get_article(GetArticleData {
|
||||||
|
title: None,
|
||||||
|
instance_id: None,
|
||||||
|
id: Some(edit_form.article_id),
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn search(&self, search_form: &SearchArticleData) -> MyResult<Vec<DbArticle>> {
|
||||||
|
self.get_query("search", Some(search_form)).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_local_instance(&self) -> MyResult<InstanceView> {
|
||||||
|
self.get_query("instance", None::<i32>).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn follow_instance(&self, follow_instance: &str) -> MyResult<DbInstance> {
|
||||||
|
// fetch beta instance on alpha
|
||||||
|
let resolve_form = ResolveObject {
|
||||||
|
id: Url::parse(&format!("http://{}", follow_instance))?,
|
||||||
|
};
|
||||||
|
let instance_resolved: DbInstance =
|
||||||
|
get_query(&self.hostname, "instance/resolve", Some(resolve_form)).await?;
|
||||||
|
|
||||||
|
// send follow
|
||||||
|
let follow_form = FollowInstance {
|
||||||
|
id: instance_resolved.id,
|
||||||
|
};
|
||||||
|
// cant use post helper because follow doesnt return json
|
||||||
|
let res = self
|
||||||
|
.client
|
||||||
|
.post(format!("http://{}/api/v1/instance/follow", self.hostname))
|
||||||
|
.form(&follow_form)
|
||||||
|
.send()
|
||||||
|
.await?;
|
||||||
|
if res.status() == StatusCode::OK {
|
||||||
|
Ok(instance_resolved)
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("API error: {}", res.text().await?).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_query<T, R>(hostname: &str, endpoint: &str, query: Option<R>) -> MyResult<T>
|
pub async fn get_query<T, R>(hostname: &str, endpoint: &str, query: Option<R>) -> MyResult<T>
|
||||||
|
@ -83,11 +167,13 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: cover in integration test
|
||||||
pub async fn my_profile(hostname: &str) -> MyResult<LocalUserView> {
|
pub async fn my_profile(hostname: &str) -> MyResult<LocalUserView> {
|
||||||
let req = CLIENT.get(format!("http://{}/api/v1/account/my_profile", hostname));
|
let req = CLIENT.get(format!("http://{}/api/v1/account/my_profile", hostname));
|
||||||
handle_json_res::<LocalUserView>(req).await
|
handle_json_res::<LocalUserView>(req).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: cover in integration test
|
||||||
pub async fn logout(hostname: &str) -> MyResult<()> {
|
pub async fn logout(hostname: &str) -> MyResult<()> {
|
||||||
CLIENT
|
CLIENT
|
||||||
.get(format!("http://{}/api/v1/account/logout", hostname))
|
.get(format!("http://{}/api/v1/account/logout", hostname))
|
||||||
|
|
104
tests/common.rs
104
tests/common.rs
|
@ -1,12 +1,12 @@
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use ibis_lib::backend::api::article::{CreateArticleData, EditArticleData, ForkArticleData};
|
use ibis_lib::backend::api::article::ForkArticleData;
|
||||||
use ibis_lib::backend::api::instance::FollowInstance;
|
use ibis_lib::backend::api::instance::FollowInstance;
|
||||||
use ibis_lib::backend::api::ResolveObject;
|
use ibis_lib::backend::api::ResolveObject;
|
||||||
use ibis_lib::backend::database::conflict::ApiConflict;
|
use ibis_lib::backend::database::conflict::ApiConflict;
|
||||||
use ibis_lib::backend::database::instance::DbInstance;
|
use ibis_lib::backend::database::instance::DbInstance;
|
||||||
use ibis_lib::backend::start;
|
use ibis_lib::backend::start;
|
||||||
|
use ibis_lib::common::ArticleView;
|
||||||
use ibis_lib::common::RegisterUserData;
|
use ibis_lib::common::RegisterUserData;
|
||||||
use ibis_lib::common::{ArticleView, GetArticleData};
|
|
||||||
use ibis_lib::frontend::api::ApiClient;
|
use ibis_lib::frontend::api::ApiClient;
|
||||||
use ibis_lib::frontend::api::{get_query, handle_json_res};
|
use ibis_lib::frontend::api::{get_query, handle_json_res};
|
||||||
use ibis_lib::frontend::error::MyResult;
|
use ibis_lib::frontend::error::MyResult;
|
||||||
|
@ -166,45 +166,6 @@ impl Deref for IbisInstance {
|
||||||
}
|
}
|
||||||
pub const TEST_ARTICLE_DEFAULT_TEXT: &str = "some\nexample\ntext\n";
|
pub const TEST_ARTICLE_DEFAULT_TEXT: &str = "some\nexample\ntext\n";
|
||||||
|
|
||||||
pub async fn create_article(instance: &IbisInstance, title: String) -> MyResult<ArticleView> {
|
|
||||||
let create_form = CreateArticleData {
|
|
||||||
title: title.clone(),
|
|
||||||
};
|
|
||||||
let req = instance
|
|
||||||
.api_client
|
|
||||||
.client
|
|
||||||
.post(format!(
|
|
||||||
"http://{}/api/v1/article",
|
|
||||||
&instance.api_client.hostname
|
|
||||||
))
|
|
||||||
.form(&create_form);
|
|
||||||
let article: ArticleView = handle_json_res(req).await?;
|
|
||||||
|
|
||||||
// create initial edit to ensure that conflicts are generated (there are no conflicts on empty file)
|
|
||||||
let edit_form = EditArticleData {
|
|
||||||
article_id: article.article.id,
|
|
||||||
new_text: TEST_ARTICLE_DEFAULT_TEXT.to_string(),
|
|
||||||
previous_version_id: article.latest_version,
|
|
||||||
resolve_conflict_id: None,
|
|
||||||
};
|
|
||||||
Ok(edit_article(instance, &edit_form).await.unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn edit_article_with_conflict(
|
|
||||||
instance: &IbisInstance,
|
|
||||||
edit_form: &EditArticleData,
|
|
||||||
) -> MyResult<Option<ApiConflict>> {
|
|
||||||
let req = instance
|
|
||||||
.api_client
|
|
||||||
.client
|
|
||||||
.patch(format!(
|
|
||||||
"http://{}/api/v1/article",
|
|
||||||
instance.api_client.hostname
|
|
||||||
))
|
|
||||||
.form(edit_form);
|
|
||||||
handle_json_res(req).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get_conflicts(instance: &IbisInstance) -> MyResult<Vec<ApiConflict>> {
|
pub async fn get_conflicts(instance: &IbisInstance) -> MyResult<Vec<ApiConflict>> {
|
||||||
let req = instance.api_client.client.get(format!(
|
let req = instance.api_client.client.get(format!(
|
||||||
"http://{}/api/v1/edit_conflicts",
|
"http://{}/api/v1/edit_conflicts",
|
||||||
|
@ -213,30 +174,6 @@ pub async fn get_conflicts(instance: &IbisInstance) -> MyResult<Vec<ApiConflict>
|
||||||
Ok(handle_json_res(req).await.unwrap())
|
Ok(handle_json_res(req).await.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn edit_article(
|
|
||||||
instance: &IbisInstance,
|
|
||||||
edit_form: &EditArticleData,
|
|
||||||
) -> MyResult<ArticleView> {
|
|
||||||
let edit_res = edit_article_with_conflict(instance, edit_form).await?;
|
|
||||||
assert!(edit_res.is_none());
|
|
||||||
|
|
||||||
instance
|
|
||||||
.api_client
|
|
||||||
.get_article(GetArticleData {
|
|
||||||
title: None,
|
|
||||||
instance_id: None,
|
|
||||||
id: Some(edit_form.article_id),
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn get<T>(hostname: &str, endpoint: &str) -> MyResult<T>
|
|
||||||
where
|
|
||||||
T: for<'de> Deserialize<'de>,
|
|
||||||
{
|
|
||||||
Ok(get_query(hostname, endpoint, None::<i32>).await.unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn fork_article(
|
pub async fn fork_article(
|
||||||
instance: &IbisInstance,
|
instance: &IbisInstance,
|
||||||
form: &ForkArticleData,
|
form: &ForkArticleData,
|
||||||
|
@ -251,40 +188,3 @@ pub async fn fork_article(
|
||||||
.form(form);
|
.form(form);
|
||||||
Ok(handle_json_res(req).await.unwrap())
|
Ok(handle_json_res(req).await.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn follow_instance(
|
|
||||||
instance: &IbisInstance,
|
|
||||||
follow_instance: &str,
|
|
||||||
) -> MyResult<DbInstance> {
|
|
||||||
// fetch beta instance on alpha
|
|
||||||
let resolve_form = ResolveObject {
|
|
||||||
id: Url::parse(&format!("http://{}", follow_instance))?,
|
|
||||||
};
|
|
||||||
let instance_resolved: DbInstance = get_query(
|
|
||||||
&instance.api_client.hostname,
|
|
||||||
"instance/resolve",
|
|
||||||
Some(resolve_form),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// send follow
|
|
||||||
let follow_form = FollowInstance {
|
|
||||||
id: instance_resolved.id,
|
|
||||||
};
|
|
||||||
// cant use post helper because follow doesnt return json
|
|
||||||
let res = instance
|
|
||||||
.api_client
|
|
||||||
.client
|
|
||||||
.post(format!(
|
|
||||||
"http://{}/api/v1/instance/follow",
|
|
||||||
instance.api_client.hostname
|
|
||||||
))
|
|
||||||
.form(&follow_form)
|
|
||||||
.send()
|
|
||||||
.await?;
|
|
||||||
if res.status() == StatusCode::OK {
|
|
||||||
Ok(instance_resolved)
|
|
||||||
} else {
|
|
||||||
Err(anyhow!("API error: {}", res.text().await?).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
115
tests/test.rs
115
tests/test.rs
|
@ -4,10 +4,7 @@ mod common;
|
||||||
|
|
||||||
use crate::common::fork_article;
|
use crate::common::fork_article;
|
||||||
use crate::common::get_conflicts;
|
use crate::common::get_conflicts;
|
||||||
use crate::common::{
|
use crate::common::{TestData, TEST_ARTICLE_DEFAULT_TEXT};
|
||||||
create_article, edit_article, edit_article_with_conflict, follow_instance, get, TestData,
|
|
||||||
TEST_ARTICLE_DEFAULT_TEXT,
|
|
||||||
};
|
|
||||||
use ibis_lib::backend::api::article::{CreateArticleData, EditArticleData, ForkArticleData};
|
use ibis_lib::backend::api::article::{CreateArticleData, EditArticleData, ForkArticleData};
|
||||||
use ibis_lib::backend::api::{ResolveObject, SearchArticleData};
|
use ibis_lib::backend::api::{ResolveObject, SearchArticleData};
|
||||||
use ibis_lib::backend::database::instance::{DbInstance, InstanceView};
|
use ibis_lib::backend::database::instance::{DbInstance, InstanceView};
|
||||||
|
@ -25,7 +22,10 @@ async fn test_create_read_and_edit_local_article() -> MyResult<()> {
|
||||||
|
|
||||||
// create article
|
// create article
|
||||||
let title = "Manu_Chao".to_string();
|
let title = "Manu_Chao".to_string();
|
||||||
let create_res = create_article(&data.alpha, title.clone()).await?;
|
let create_res = data
|
||||||
|
.alpha
|
||||||
|
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||||
|
.await?;
|
||||||
assert_eq!(title, create_res.article.title);
|
assert_eq!(title, create_res.article.title);
|
||||||
assert!(create_res.article.local);
|
assert!(create_res.article.local);
|
||||||
|
|
||||||
|
@ -35,11 +35,7 @@ async fn test_create_read_and_edit_local_article() -> MyResult<()> {
|
||||||
instance_id: None,
|
instance_id: None,
|
||||||
id: None,
|
id: None,
|
||||||
};
|
};
|
||||||
let get_res = data
|
let get_res = data.alpha.get_article(get_article_data.clone()).await?;
|
||||||
.alpha
|
|
||||||
.get_article(get_article_data.clone())
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(title, get_res.article.title);
|
assert_eq!(title, get_res.article.title);
|
||||||
assert_eq!(TEST_ARTICLE_DEFAULT_TEXT, get_res.article.text);
|
assert_eq!(TEST_ARTICLE_DEFAULT_TEXT, get_res.article.text);
|
||||||
assert!(get_res.article.local);
|
assert!(get_res.article.local);
|
||||||
|
@ -55,17 +51,14 @@ async fn test_create_read_and_edit_local_article() -> MyResult<()> {
|
||||||
previous_version_id: get_res.latest_version,
|
previous_version_id: get_res.latest_version,
|
||||||
resolve_conflict_id: None,
|
resolve_conflict_id: None,
|
||||||
};
|
};
|
||||||
let edit_res = edit_article(&data.alpha, &edit_form).await?;
|
let edit_res = data.alpha.edit_article(&edit_form).await?;
|
||||||
assert_eq!(edit_form.new_text, edit_res.article.text);
|
assert_eq!(edit_form.new_text, edit_res.article.text);
|
||||||
assert_eq!(2, edit_res.edits.len());
|
assert_eq!(2, edit_res.edits.len());
|
||||||
|
|
||||||
let search_form = SearchArticleData {
|
let search_form = SearchArticleData {
|
||||||
query: title.clone(),
|
query: title.clone(),
|
||||||
};
|
};
|
||||||
let search_res: Vec<DbArticle> =
|
let search_res = data.alpha.search(&search_form).await?;
|
||||||
get_query(&data.alpha.api_client.hostname, "search", Some(search_form))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(1, search_res.len());
|
assert_eq!(1, search_res.len());
|
||||||
assert_eq!(edit_res.article, search_res[0]);
|
assert_eq!(edit_res.article, search_res[0]);
|
||||||
|
|
||||||
|
@ -78,11 +71,17 @@ async fn test_create_duplicate_article() -> MyResult<()> {
|
||||||
|
|
||||||
// create article
|
// create article
|
||||||
let title = "Manu_Chao".to_string();
|
let title = "Manu_Chao".to_string();
|
||||||
let create_res = create_article(&data.alpha, title.clone()).await?;
|
let create_res = data
|
||||||
|
.alpha
|
||||||
|
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||||
|
.await?;
|
||||||
assert_eq!(title, create_res.article.title);
|
assert_eq!(title, create_res.article.title);
|
||||||
assert!(create_res.article.local);
|
assert!(create_res.article.local);
|
||||||
|
|
||||||
let create_res = create_article(&data.alpha, title.clone()).await;
|
let create_res = data
|
||||||
|
.alpha
|
||||||
|
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||||
|
.await;
|
||||||
assert!(create_res.is_err());
|
assert!(create_res.is_err());
|
||||||
|
|
||||||
data.stop()
|
data.stop()
|
||||||
|
@ -93,17 +92,17 @@ async fn test_follow_instance() -> MyResult<()> {
|
||||||
let data = TestData::start().await;
|
let data = TestData::start().await;
|
||||||
|
|
||||||
// check initial state
|
// check initial state
|
||||||
let alpha_instance: InstanceView = get(&data.alpha.hostname, "instance").await?;
|
let alpha_instance = data.alpha.get_local_instance().await?;
|
||||||
assert_eq!(0, alpha_instance.followers.len());
|
assert_eq!(0, alpha_instance.followers.len());
|
||||||
assert_eq!(0, alpha_instance.following.len());
|
assert_eq!(0, alpha_instance.following.len());
|
||||||
let beta_instance: InstanceView = get(&data.beta.hostname, "instance").await?;
|
let beta_instance = data.beta.get_local_instance().await?;
|
||||||
assert_eq!(0, beta_instance.followers.len());
|
assert_eq!(0, beta_instance.followers.len());
|
||||||
assert_eq!(0, beta_instance.following.len());
|
assert_eq!(0, beta_instance.following.len());
|
||||||
|
|
||||||
follow_instance(&data.alpha, &data.beta.hostname).await?;
|
data.alpha.follow_instance(&data.beta.hostname).await?;
|
||||||
|
|
||||||
// check that follow was federated
|
// check that follow was federated
|
||||||
let alpha_instance: InstanceView = get(&data.alpha.hostname, "instance").await?;
|
let alpha_instance = data.alpha.get_local_instance().await?;
|
||||||
assert_eq!(1, alpha_instance.following.len());
|
assert_eq!(1, alpha_instance.following.len());
|
||||||
assert_eq!(0, alpha_instance.followers.len());
|
assert_eq!(0, alpha_instance.followers.len());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -111,7 +110,7 @@ async fn test_follow_instance() -> MyResult<()> {
|
||||||
alpha_instance.following[0].ap_id
|
alpha_instance.following[0].ap_id
|
||||||
);
|
);
|
||||||
|
|
||||||
let beta_instance: InstanceView = get(&data.beta.hostname, "instance").await?;
|
let beta_instance = data.beta.get_local_instance().await?;
|
||||||
assert_eq!(0, beta_instance.following.len());
|
assert_eq!(0, beta_instance.following.len());
|
||||||
assert_eq!(1, beta_instance.followers.len());
|
assert_eq!(1, beta_instance.followers.len());
|
||||||
// TODO: compare full ap_id of alpha user, but its not available through api yet
|
// TODO: compare full ap_id of alpha user, but its not available through api yet
|
||||||
|
@ -129,7 +128,10 @@ async fn test_synchronize_articles() -> MyResult<()> {
|
||||||
|
|
||||||
// create article on alpha
|
// create article on alpha
|
||||||
let title = "Manu_Chao".to_string();
|
let title = "Manu_Chao".to_string();
|
||||||
let create_res = create_article(&data.alpha, title.clone()).await?;
|
let create_res = data
|
||||||
|
.alpha
|
||||||
|
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||||
|
.await?;
|
||||||
assert_eq!(title, create_res.article.title);
|
assert_eq!(title, create_res.article.title);
|
||||||
assert_eq!(1, create_res.edits.len());
|
assert_eq!(1, create_res.edits.len());
|
||||||
assert!(create_res.article.local);
|
assert!(create_res.article.local);
|
||||||
|
@ -141,7 +143,7 @@ async fn test_synchronize_articles() -> MyResult<()> {
|
||||||
previous_version_id: create_res.latest_version,
|
previous_version_id: create_res.latest_version,
|
||||||
resolve_conflict_id: None,
|
resolve_conflict_id: None,
|
||||||
};
|
};
|
||||||
edit_article(&data.alpha, &edit_form).await?;
|
data.alpha.edit_article(&edit_form).await?;
|
||||||
|
|
||||||
// fetch alpha instance on beta, articles are also fetched automatically
|
// fetch alpha instance on beta, articles are also fetched automatically
|
||||||
let resolve_object = ResolveObject {
|
let resolve_object = ResolveObject {
|
||||||
|
@ -180,11 +182,14 @@ async fn test_synchronize_articles() -> MyResult<()> {
|
||||||
async fn test_edit_local_article() -> MyResult<()> {
|
async fn test_edit_local_article() -> MyResult<()> {
|
||||||
let data = TestData::start().await;
|
let data = TestData::start().await;
|
||||||
|
|
||||||
let beta_instance = follow_instance(&data.alpha, &data.beta.hostname).await?;
|
let beta_instance = data.alpha.follow_instance(&data.beta.hostname).await?;
|
||||||
|
|
||||||
// create new article
|
// create new article
|
||||||
let title = "Manu_Chao".to_string();
|
let title = "Manu_Chao".to_string();
|
||||||
let create_res = create_article(&data.beta, title.clone()).await?;
|
let create_res = data
|
||||||
|
.beta
|
||||||
|
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||||
|
.await?;
|
||||||
assert_eq!(title, create_res.article.title);
|
assert_eq!(title, create_res.article.title);
|
||||||
assert!(create_res.article.local);
|
assert!(create_res.article.local);
|
||||||
|
|
||||||
|
@ -207,7 +212,7 @@ async fn test_edit_local_article() -> MyResult<()> {
|
||||||
previous_version_id: get_res.latest_version,
|
previous_version_id: get_res.latest_version,
|
||||||
resolve_conflict_id: None,
|
resolve_conflict_id: None,
|
||||||
};
|
};
|
||||||
let edit_res = edit_article(&data.beta, &edit_form).await?;
|
let edit_res = data.beta.edit_article(&edit_form).await?;
|
||||||
assert_eq!(edit_res.article.text, edit_form.new_text);
|
assert_eq!(edit_res.article.text, edit_form.new_text);
|
||||||
assert_eq!(edit_res.edits.len(), 2);
|
assert_eq!(edit_res.edits.len(), 2);
|
||||||
assert!(edit_res.edits[0]
|
assert!(edit_res.edits[0]
|
||||||
|
@ -228,12 +233,15 @@ async fn test_edit_local_article() -> MyResult<()> {
|
||||||
async fn test_edit_remote_article() -> MyResult<()> {
|
async fn test_edit_remote_article() -> MyResult<()> {
|
||||||
let data = TestData::start().await;
|
let data = TestData::start().await;
|
||||||
|
|
||||||
let beta_id_on_alpha = follow_instance(&data.alpha, &data.beta.hostname).await?;
|
let beta_id_on_alpha = data.alpha.follow_instance(&data.beta.hostname).await?;
|
||||||
let beta_id_on_gamma = follow_instance(&data.gamma, &data.beta.hostname).await?;
|
let beta_id_on_gamma = data.gamma.follow_instance(&data.beta.hostname).await?;
|
||||||
|
|
||||||
// create new article
|
// create new article
|
||||||
let title = "Manu_Chao".to_string();
|
let title = "Manu_Chao".to_string();
|
||||||
let create_res = create_article(&data.beta, title.clone()).await?;
|
let create_res = data
|
||||||
|
.beta
|
||||||
|
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||||
|
.await?;
|
||||||
assert_eq!(&title, &create_res.article.title);
|
assert_eq!(&title, &create_res.article.title);
|
||||||
assert!(create_res.article.local);
|
assert!(create_res.article.local);
|
||||||
|
|
||||||
|
@ -269,7 +277,7 @@ async fn test_edit_remote_article() -> MyResult<()> {
|
||||||
previous_version_id: get_res.latest_version,
|
previous_version_id: get_res.latest_version,
|
||||||
resolve_conflict_id: None,
|
resolve_conflict_id: None,
|
||||||
};
|
};
|
||||||
let edit_res = edit_article(&data.alpha, &edit_form).await?;
|
let edit_res = data.alpha.edit_article(&edit_form).await?;
|
||||||
assert_eq!(edit_form.new_text, edit_res.article.text);
|
assert_eq!(edit_form.new_text, edit_res.article.text);
|
||||||
assert_eq!(2, edit_res.edits.len());
|
assert_eq!(2, edit_res.edits.len());
|
||||||
assert!(!edit_res.article.local);
|
assert!(!edit_res.article.local);
|
||||||
|
@ -298,7 +306,10 @@ async fn test_local_edit_conflict() -> MyResult<()> {
|
||||||
|
|
||||||
// create new article
|
// create new article
|
||||||
let title = "Manu_Chao".to_string();
|
let title = "Manu_Chao".to_string();
|
||||||
let create_res = create_article(&data.alpha, title.clone()).await?;
|
let create_res = data
|
||||||
|
.alpha
|
||||||
|
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||||
|
.await?;
|
||||||
assert_eq!(title, create_res.article.title);
|
assert_eq!(title, create_res.article.title);
|
||||||
assert!(create_res.article.local);
|
assert!(create_res.article.local);
|
||||||
|
|
||||||
|
@ -309,7 +320,7 @@ async fn test_local_edit_conflict() -> MyResult<()> {
|
||||||
previous_version_id: create_res.latest_version.clone(),
|
previous_version_id: create_res.latest_version.clone(),
|
||||||
resolve_conflict_id: None,
|
resolve_conflict_id: None,
|
||||||
};
|
};
|
||||||
let edit_res = edit_article(&data.alpha, &edit_form).await?;
|
let edit_res = data.alpha.edit_article(&edit_form).await?;
|
||||||
assert_eq!(edit_res.article.text, edit_form.new_text);
|
assert_eq!(edit_res.article.text, edit_form.new_text);
|
||||||
assert_eq!(2, edit_res.edits.len());
|
assert_eq!(2, edit_res.edits.len());
|
||||||
|
|
||||||
|
@ -320,7 +331,9 @@ async fn test_local_edit_conflict() -> MyResult<()> {
|
||||||
previous_version_id: create_res.latest_version,
|
previous_version_id: create_res.latest_version,
|
||||||
resolve_conflict_id: None,
|
resolve_conflict_id: None,
|
||||||
};
|
};
|
||||||
let edit_res = edit_article_with_conflict(&data.alpha, &edit_form)
|
let edit_res = data
|
||||||
|
.alpha
|
||||||
|
.edit_article_with_conflict(&edit_form)
|
||||||
.await?
|
.await?
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!("<<<<<<< ours\nIpsum Lorem\n||||||| original\nsome\nexample\ntext\n=======\nLorem Ipsum\n>>>>>>> theirs\n", edit_res.three_way_merge);
|
assert_eq!("<<<<<<< ours\nIpsum Lorem\n||||||| original\nsome\nexample\ntext\n=======\nLorem Ipsum\n>>>>>>> theirs\n", edit_res.three_way_merge);
|
||||||
|
@ -335,7 +348,7 @@ async fn test_local_edit_conflict() -> MyResult<()> {
|
||||||
previous_version_id: edit_res.previous_version_id,
|
previous_version_id: edit_res.previous_version_id,
|
||||||
resolve_conflict_id: Some(edit_res.id),
|
resolve_conflict_id: Some(edit_res.id),
|
||||||
};
|
};
|
||||||
let edit_res = edit_article(&data.alpha, &edit_form).await?;
|
let edit_res = data.alpha.edit_article(&edit_form).await?;
|
||||||
assert_eq!(edit_form.new_text, edit_res.article.text);
|
assert_eq!(edit_form.new_text, edit_res.article.text);
|
||||||
|
|
||||||
let conflicts = get_conflicts(&data.alpha).await?;
|
let conflicts = get_conflicts(&data.alpha).await?;
|
||||||
|
@ -348,11 +361,14 @@ async fn test_local_edit_conflict() -> MyResult<()> {
|
||||||
async fn test_federated_edit_conflict() -> MyResult<()> {
|
async fn test_federated_edit_conflict() -> MyResult<()> {
|
||||||
let data = TestData::start().await;
|
let data = TestData::start().await;
|
||||||
|
|
||||||
let beta_id_on_alpha = follow_instance(&data.alpha, &data.beta.hostname).await?;
|
let beta_id_on_alpha = data.alpha.follow_instance(&data.beta.hostname).await?;
|
||||||
|
|
||||||
// create new article
|
// create new article
|
||||||
let title = "Manu_Chao".to_string();
|
let title = "Manu_Chao".to_string();
|
||||||
let create_res = create_article(&data.beta, title.clone()).await?;
|
let create_res = data
|
||||||
|
.beta
|
||||||
|
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||||
|
.await?;
|
||||||
assert_eq!(title, create_res.article.title);
|
assert_eq!(title, create_res.article.title);
|
||||||
assert!(create_res.article.local);
|
assert!(create_res.article.local);
|
||||||
|
|
||||||
|
@ -383,7 +399,7 @@ async fn test_federated_edit_conflict() -> MyResult<()> {
|
||||||
previous_version_id: create_res.latest_version.clone(),
|
previous_version_id: create_res.latest_version.clone(),
|
||||||
resolve_conflict_id: None,
|
resolve_conflict_id: None,
|
||||||
};
|
};
|
||||||
let edit_res = edit_article(&data.alpha, &edit_form).await?;
|
let edit_res = data.alpha.edit_article(&edit_form).await?;
|
||||||
assert_eq!(edit_res.article.text, edit_form.new_text);
|
assert_eq!(edit_res.article.text, edit_form.new_text);
|
||||||
assert_eq!(2, edit_res.edits.len());
|
assert_eq!(2, edit_res.edits.len());
|
||||||
assert!(!edit_res.article.local);
|
assert!(!edit_res.article.local);
|
||||||
|
@ -400,7 +416,7 @@ async fn test_federated_edit_conflict() -> MyResult<()> {
|
||||||
previous_version_id: create_res.latest_version,
|
previous_version_id: create_res.latest_version,
|
||||||
resolve_conflict_id: None,
|
resolve_conflict_id: None,
|
||||||
};
|
};
|
||||||
let edit_res = edit_article(&data.gamma, &edit_form).await?;
|
let edit_res = data.gamma.edit_article(&edit_form).await?;
|
||||||
assert_ne!(edit_form.new_text, edit_res.article.text);
|
assert_ne!(edit_form.new_text, edit_res.article.text);
|
||||||
assert_eq!(1, edit_res.edits.len());
|
assert_eq!(1, edit_res.edits.len());
|
||||||
assert!(!edit_res.article.local);
|
assert!(!edit_res.article.local);
|
||||||
|
@ -415,7 +431,7 @@ async fn test_federated_edit_conflict() -> MyResult<()> {
|
||||||
previous_version_id: conflicts[0].previous_version_id.clone(),
|
previous_version_id: conflicts[0].previous_version_id.clone(),
|
||||||
resolve_conflict_id: Some(conflicts[0].id.clone()),
|
resolve_conflict_id: Some(conflicts[0].id.clone()),
|
||||||
};
|
};
|
||||||
let edit_res = edit_article(&data.gamma, &edit_form).await?;
|
let edit_res = data.gamma.edit_article(&edit_form).await?;
|
||||||
assert_eq!(edit_form.new_text, edit_res.article.text);
|
assert_eq!(edit_form.new_text, edit_res.article.text);
|
||||||
assert_eq!(3, edit_res.edits.len());
|
assert_eq!(3, edit_res.edits.len());
|
||||||
|
|
||||||
|
@ -431,7 +447,10 @@ async fn test_overlapping_edits_no_conflict() -> MyResult<()> {
|
||||||
|
|
||||||
// create new article
|
// create new article
|
||||||
let title = "Manu_Chao".to_string();
|
let title = "Manu_Chao".to_string();
|
||||||
let create_res = create_article(&data.alpha, title.clone()).await?;
|
let create_res = data
|
||||||
|
.alpha
|
||||||
|
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||||
|
.await?;
|
||||||
assert_eq!(title, create_res.article.title);
|
assert_eq!(title, create_res.article.title);
|
||||||
assert!(create_res.article.local);
|
assert!(create_res.article.local);
|
||||||
|
|
||||||
|
@ -442,7 +461,7 @@ async fn test_overlapping_edits_no_conflict() -> MyResult<()> {
|
||||||
previous_version_id: create_res.latest_version.clone(),
|
previous_version_id: create_res.latest_version.clone(),
|
||||||
resolve_conflict_id: None,
|
resolve_conflict_id: None,
|
||||||
};
|
};
|
||||||
let edit_res = edit_article(&data.alpha, &edit_form).await?;
|
let edit_res = data.alpha.edit_article(&edit_form).await?;
|
||||||
assert_eq!(edit_res.article.text, edit_form.new_text);
|
assert_eq!(edit_res.article.text, edit_form.new_text);
|
||||||
assert_eq!(2, edit_res.edits.len());
|
assert_eq!(2, edit_res.edits.len());
|
||||||
|
|
||||||
|
@ -453,7 +472,7 @@ async fn test_overlapping_edits_no_conflict() -> MyResult<()> {
|
||||||
previous_version_id: create_res.latest_version,
|
previous_version_id: create_res.latest_version,
|
||||||
resolve_conflict_id: None,
|
resolve_conflict_id: None,
|
||||||
};
|
};
|
||||||
let edit_res = edit_article(&data.alpha, &edit_form).await?;
|
let edit_res = data.alpha.edit_article(&edit_form).await?;
|
||||||
let conflicts = get_conflicts(&data.alpha).await?;
|
let conflicts = get_conflicts(&data.alpha).await?;
|
||||||
assert_eq!(0, conflicts.len());
|
assert_eq!(0, conflicts.len());
|
||||||
assert_eq!(3, edit_res.edits.len());
|
assert_eq!(3, edit_res.edits.len());
|
||||||
|
@ -468,7 +487,10 @@ async fn test_fork_article() -> MyResult<()> {
|
||||||
|
|
||||||
// create article
|
// create article
|
||||||
let title = "Manu_Chao".to_string();
|
let title = "Manu_Chao".to_string();
|
||||||
let create_res = create_article(&data.alpha, title.clone()).await?;
|
let create_res = data
|
||||||
|
.alpha
|
||||||
|
.create_article(title.clone(), TEST_ARTICLE_DEFAULT_TEXT.to_string())
|
||||||
|
.await?;
|
||||||
assert_eq!(title, create_res.article.title);
|
assert_eq!(title, create_res.article.title);
|
||||||
assert!(create_res.article.local);
|
assert!(create_res.article.local);
|
||||||
|
|
||||||
|
@ -497,15 +519,14 @@ async fn test_fork_article() -> MyResult<()> {
|
||||||
assert_ne!(resolved_article.ap_id, forked_article.ap_id);
|
assert_ne!(resolved_article.ap_id, forked_article.ap_id);
|
||||||
assert!(forked_article.local);
|
assert!(forked_article.local);
|
||||||
|
|
||||||
let beta_instance: InstanceView = get(&data.beta.hostname, "instance").await?;
|
let beta_instance = data.beta.get_local_instance().await?;
|
||||||
assert_eq!(forked_article.instance_id, beta_instance.instance.id);
|
assert_eq!(forked_article.instance_id, beta_instance.instance.id);
|
||||||
|
|
||||||
// now search returns two articles for this title (original and forked)
|
// now search returns two articles for this title (original and forked)
|
||||||
let search_form = SearchArticleData {
|
let search_form = SearchArticleData {
|
||||||
query: title.clone(),
|
query: title.clone(),
|
||||||
};
|
};
|
||||||
let search_res: Vec<DbArticle> =
|
let search_res = data.beta.search(&search_form).await?;
|
||||||
get_query(&data.beta.hostname, "search", Some(search_form)).await?;
|
|
||||||
assert_eq!(2, search_res.len());
|
assert_eq!(2, search_res.len());
|
||||||
|
|
||||||
data.stop()
|
data.stop()
|
||||||
|
|
Loading…
Reference in a new issue