diff --git a/migrations/2025-01-23-112938_instance-topic/down.sql b/migrations/2025-01-23-112938_instance-topic/down.sql new file mode 100644 index 0000000..355fe31 --- /dev/null +++ b/migrations/2025-01-23-112938_instance-topic/down.sql @@ -0,0 +1,2 @@ +alter table instance rename topic to description; +alter table instance drop column name; \ No newline at end of file diff --git a/migrations/2025-01-23-112938_instance-topic/up.sql b/migrations/2025-01-23-112938_instance-topic/up.sql new file mode 100644 index 0000000..d14630f --- /dev/null +++ b/migrations/2025-01-23-112938_instance-topic/up.sql @@ -0,0 +1,2 @@ +alter table instance rename description to topic; +alter table instance add column name text; \ No newline at end of file diff --git a/src/backend/api/instance.rs b/src/backend/api/instance.rs index 3694b6d..35b63df 100644 --- a/src/backend/api/instance.rs +++ b/src/backend/api/instance.rs @@ -1,11 +1,18 @@ +use super::empty_to_none; use crate::{ backend::{ - database::IbisContext, + database::{instance::DbInstanceUpdateForm, IbisContext}, federation::activities::follow::Follow, utils::error::MyResult, }, common::{ - instance::{DbInstance, FollowInstanceParams, GetInstanceParams, InstanceView}, + instance::{ + DbInstance, + FollowInstanceParams, + GetInstanceParams, + InstanceView, + UpdateInstanceParams, + }, user::LocalUserView, ResolveObjectParams, SuccessResponse, @@ -25,6 +32,19 @@ pub(in crate::backend::api) async fn get_instance( Ok(Json(local_instance)) } +pub(in crate::backend::api) async fn update_instance( + context: Data, + Form(mut params): Form, +) -> MyResult> { + empty_to_none(&mut params.name); + empty_to_none(&mut params.topic); + let form = DbInstanceUpdateForm { + name: params.name, + topic: params.topic, + }; + Ok(Json(DbInstance::update(form, &context)?)) +} + /// Make the local instance follow a given remote instance, to receive activities about new and /// updated articles. #[debug_handler] @@ -53,9 +73,9 @@ pub(super) async fn resolve_instance( } #[debug_handler] -pub(in crate::backend::api) async fn list_remote_instances( +pub(in crate::backend::api) async fn list_instances( context: Data, ) -> MyResult>> { - let instances = DbInstance::read_remote(&context)?; + let instances = DbInstance::list(false, &context)?; Ok(Json(instances)) } diff --git a/src/backend/api/mod.rs b/src/backend/api/mod.rs index 4694ae2..02028a6 100644 --- a/src/backend/api/mod.rs +++ b/src/backend/api/mod.rs @@ -36,7 +36,7 @@ use axum::{ Router, }; use axum_macros::debug_handler; -use instance::list_remote_instances; +use instance::{list_instances, update_instance}; use user::{count_notifications, list_notifications, update_user_profile}; mod article; @@ -60,9 +60,10 @@ pub fn api_routes() -> Router<()> { .route("/comment", post(create_comment)) .route("/comment", patch(edit_comment)) .route("/instance", get(get_instance)) + .route("/instance", patch(update_instance)) .route("/instance/follow", post(follow_instance)) .route("/instance/resolve", get(resolve_instance)) - .route("/instance/list", get(list_remote_instances)) + .route("/instance/list", get(list_instances)) .route("/search", get(search_article)) .route("/user", get(get_user)) .route("/user/notifications/list", get(list_notifications)) diff --git a/src/backend/database/instance.rs b/src/backend/database/instance.rs index 1cb8408..6bf6dbd 100644 --- a/src/backend/database/instance.rs +++ b/src/backend/database/instance.rs @@ -23,6 +23,7 @@ use activitypub_federation::{ use chrono::{DateTime, Utc}; use diesel::{ insert_into, + update, AsChangeset, ExpressionMethods, Insertable, @@ -37,7 +38,7 @@ use std::{fmt::Debug, ops::DerefMut}; pub struct DbInstanceForm { pub domain: String, pub ap_id: ObjectId, - pub description: Option, + pub topic: Option, pub articles_url: Option>, pub inbox_url: String, pub public_key: String, @@ -45,6 +46,14 @@ pub struct DbInstanceForm { pub last_refreshed_at: DateTime, pub local: bool, pub instances_url: Option>, + pub name: Option, +} + +#[derive(Debug, Clone, AsChangeset)] +#[diesel(table_name = instance, check_for_backend(diesel::pg::Pg))] +pub struct DbInstanceUpdateForm { + pub topic: Option, + pub name: Option, } impl DbInstance { @@ -63,6 +72,14 @@ impl DbInstance { Ok(instance::table.find(id).get_result(conn.deref_mut())?) } + pub fn update(form: DbInstanceUpdateForm, context: &IbisContext) -> MyResult { + let mut conn = context.db_pool.get()?; + Ok(update(instance::table) + .filter(instance::local) + .set(form) + .get_result(conn.deref_mut())?) + } + pub fn read_from_ap_id( ap_id: &ObjectId, context: &Data, @@ -130,11 +147,13 @@ impl DbInstance { .get_results(conn.deref_mut())?) } - pub fn read_remote(context: &Data) -> MyResult> { + pub fn list(only_remote: bool, context: &Data) -> MyResult> { let mut conn = context.db_pool.get()?; - Ok(instance::table - .filter(instance::local.eq(false)) - .get_results(conn.deref_mut())?) + let mut query = instance::table.into_boxed(); + if only_remote { + query = query.filter(instance::local.eq(false)); + } + Ok(query.get_results(conn.deref_mut())?) } /// Read the instance where an article is hosted, based on a comment id. diff --git a/src/backend/database/schema.rs b/src/backend/database/schema.rs index e7ee154..dd552f0 100644 --- a/src/backend/database/schema.rs +++ b/src/backend/database/schema.rs @@ -67,7 +67,7 @@ diesel::table! { domain -> Text, #[max_length = 255] ap_id -> Varchar, - description -> Nullable, + topic -> Nullable, #[max_length = 255] articles_url -> Nullable, #[max_length = 255] @@ -78,6 +78,7 @@ diesel::table! { local -> Bool, #[max_length = 255] instances_url -> Nullable, + name -> Nullable, } } diff --git a/src/backend/federation/objects/instance.rs b/src/backend/federation/objects/instance.rs index 9906714..31d3c25 100644 --- a/src/backend/federation/objects/instance.rs +++ b/src/backend/federation/objects/instance.rs @@ -28,7 +28,8 @@ pub struct ApubInstance { #[serde(rename = "type")] kind: ServiceType, pub id: ObjectId, - content: Option, + name: Option, + summary: Option, articles: Option>, instances: Option>, inbox: Url, @@ -89,11 +90,12 @@ impl Object for DbInstance { Ok(ApubInstance { kind: Default::default(), id: self.ap_id.clone(), - content: self.description.clone(), + summary: self.topic.clone(), articles: self.articles_url.clone(), instances: self.instances_url.clone(), inbox: Url::parse(&self.inbox_url)?, public_key: self.public_key(), + name: self.name, }) } @@ -115,7 +117,7 @@ impl Object for DbInstance { let form = DbInstanceForm { domain, ap_id: json.id, - description: json.content, + topic: json.summary, articles_url: json.articles, instances_url: json.instances, inbox_url: json.inbox.to_string(), @@ -123,6 +125,7 @@ impl Object for DbInstance { private_key: None, last_refreshed_at: Utc::now(), local: false, + name: json.name, }; let instance = DbInstance::create(&form, context)?; diff --git a/src/backend/federation/objects/instance_collection.rs b/src/backend/federation/objects/instance_collection.rs index 270eaa6..98eb424 100644 --- a/src/backend/federation/objects/instance_collection.rs +++ b/src/backend/federation/objects/instance_collection.rs @@ -48,7 +48,7 @@ impl Collection for DbInstanceCollection { _owner: &Self::Owner, context: &Data, ) -> Result { - let instances = DbInstance::read_remote(context)?; + let instances = DbInstance::list(true, context)?; let instances = future::try_join_all( instances .into_iter() diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 79b6996..e352336 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -97,7 +97,6 @@ async fn setup(context: &Data) -> Result<(), Error> { let form = DbInstanceForm { domain: domain.to_string(), ap_id, - description: Some("New Ibis instance".to_string()), articles_url: Some(local_articles_url(domain)?), instances_url: Some(linked_instances_url(domain)?), inbox_url, @@ -105,6 +104,8 @@ async fn setup(context: &Data) -> Result<(), Error> { private_key: Some(keypair.private_key), last_refreshed_at: Utc::now(), local: true, + topic: None, + name: None, }; let instance = DbInstance::create(&form, context)?; diff --git a/src/common/instance.rs b/src/common/instance.rs index b2aaf81..cec2f34 100644 --- a/src/common/instance.rs +++ b/src/common/instance.rs @@ -28,7 +28,7 @@ pub struct DbInstance { pub ap_id: ObjectId, #[cfg(not(feature = "ssr"))] pub ap_id: String, - pub description: Option, + pub topic: Option, #[cfg(feature = "ssr")] pub articles_url: Option>, #[cfg(not(feature = "ssr"))] @@ -42,6 +42,7 @@ pub struct DbInstance { pub local: bool, #[cfg(feature = "ssr")] pub instances_url: Option>, + pub name: Option, } impl DbInstance { @@ -91,3 +92,9 @@ pub struct GetInstanceParams { pub struct FollowInstanceParams { pub id: InstanceId, } + +#[derive(Deserialize, Serialize, Clone, Debug)] +pub struct UpdateInstanceParams { + pub name: Option, + pub topic: Option, +} diff --git a/src/frontend/api.rs b/src/frontend/api.rs index 0e0fe6c..32af1d4 100644 --- a/src/frontend/api.rs +++ b/src/frontend/api.rs @@ -80,16 +80,14 @@ impl ApiClient { &self, data: &CreateArticleParams, ) -> Result { - self.send(Method::POST, "/api/v1/article", Some(&data)) - .await + self.post("/api/v1/article", Some(&data)).await } pub async fn edit_article_with_conflict( &self, params: &EditArticleParams, ) -> Result, ServerFnError> { - self.send(Method::PATCH, "/api/v1/article", Some(¶ms)) - .await + self.patch("/api/v1/article", Some(¶ms)).await } #[cfg(debug_assertions)] @@ -120,8 +118,7 @@ impl ApiClient { &self, params: &EditCommentParams, ) -> Result { - self.send(Method::PATCH, "/api/v1/comment", Some(¶ms)) - .await + self.patch("/api/v1/comment", Some(¶ms)).await } pub async fn notifications_list(&self) -> Option> { @@ -169,6 +166,13 @@ impl ApiClient { self.get("/api/v1/instance/list", None::).await } + pub async fn update_local_instance( + &self, + params: &UpdateInstanceParams, + ) -> Result { + self.patch("/api/v1/instance", Some(params)).await + } + pub async fn follow_instance_with_resolve(&self, follow_instance: &str) -> Option { // fetch beta instance on alpha let params = ResolveObjectParams { @@ -272,6 +276,14 @@ impl ApiClient { self.send(Method::POST, endpoint, query).await } + async fn patch(&self, endpoint: &str, query: Option) -> Result + where + T: for<'de> Deserialize<'de>, + R: Serialize + Debug, + { + self.send(Method::PATCH, endpoint, query).await + } + #[cfg(feature = "ssr")] async fn send( &self, diff --git a/src/frontend/app.rs b/src/frontend/app.rs index ea939f6..b29a306 100644 --- a/src/frontend/app.rs +++ b/src/frontend/app.rs @@ -4,6 +4,7 @@ use crate::{ api::CLIENT, components::{nav::Nav, protected_route::IbisProtectedRoute}, dark_mode::DarkMode, + instance_title, pages::{ article::{ actions::ArticleActions, @@ -15,7 +16,7 @@ use crate::{ read::ReadArticle, }, diff::EditDiff, - instance::{details::InstanceDetails, list::ListInstances}, + instance::{details::InstanceDetails, list::ListInstances, settings::InstanceSettings}, login::Login, notifications::Notifications, register::Register, @@ -94,15 +95,29 @@ pub fn App() -> impl IntoView { let darkmode = DarkMode::init(); provide_context(darkmode.clone()); - // TODO: use instance name/description for title + let instance = Resource::new( + || (), + |_| async move { CLIENT.get_local_instance().await.unwrap() }, + ); view! { - <Body {..} class="h-full max-sm:flex max-sm:flex-col" /> <> <Stylesheet id="ibis" href="/pkg/ibis.css" /> <Stylesheet id="katex" href="/katex.min.css" /> <Router> + <Suspense> + {move || { + instance + .get() + .map(|i| { + let formatter = move |text| { + format!("{text} — {}", instance_title(&i.instance)) + }; + view! { <Title formatter /> } + }) + }} + </Suspense> <Nav /> <main class="p-4 md:ml-64"> <Routes fallback=|| "Page not found.".into_view()> @@ -129,6 +144,7 @@ pub fn App() -> impl IntoView { <Route path=path!("/search") view=Search /> <IbisProtectedRoute path=path!("/edit_profile") view=UserEditProfile /> <IbisProtectedRoute path=path!("/notifications") view=Notifications /> + <IbisProtectedRoute path=path!("/settings") view=InstanceSettings /> </Routes> </main> </Router> diff --git a/src/frontend/components/comment.rs b/src/frontend/components/comment.rs index 04cd69b..774b495 100644 --- a/src/frontend/components/comment.rs +++ b/src/frontend/components/comment.rs @@ -72,9 +72,9 @@ pub fn CommentView( view! { <CommentEditorView article=article - parent_id=Some(comment.comment.id) - set_show_editor=Some(show_editor.1) - edit_params=Some(edit_params.clone()) + parent_id=comment.comment.id + set_show_editor=show_editor.1 + edit_params=edit_params.clone() /> } } @@ -115,9 +115,8 @@ pub fn CommentView( <Show when=move || show_editor.0.get() == comment.comment.id> <CommentEditorView article=article - parent_id=Some(comment.comment.id) - set_show_editor=Some(show_editor.1) - edit_params=None + parent_id=comment.comment.id + set_show_editor=show_editor.1 /> </Show> </div> diff --git a/src/frontend/components/comment_editor.rs b/src/frontend/components/comment_editor.rs index 876cd37..5b91dde 100644 --- a/src/frontend/components/comment_editor.rs +++ b/src/frontend/components/comment_editor.rs @@ -19,10 +19,12 @@ pub struct EditParams { #[component] pub fn CommentEditorView( article: Resource<DbArticleView>, - parent_id: Option<CommentId>, + #[prop(optional)] parent_id: Option<CommentId>, /// Set this to CommentId(-1) to hide all editors + #[prop(optional)] set_show_editor: Option<WriteSignal<CommentId>>, /// If this is present we are editing an existing comment + #[prop(optional)] edit_params: Option<EditParams>, ) -> impl IntoView { let textarea_ref = NodeRef::<Textarea>::new(); diff --git a/src/frontend/components/nav.rs b/src/frontend/components/nav.rs index a0bf1f8..09b32df 100644 --- a/src/frontend/components/nav.rs +++ b/src/frontend/components/nav.rs @@ -1,7 +1,8 @@ use crate::frontend::{ api::CLIENT, - app::{is_logged_in, site, DefaultResource}, + app::{is_admin, is_logged_in, site, DefaultResource}, dark_mode::DarkMode, + instance_title, }; use leptos::{component, prelude::*, view, IntoView, *}; use leptos_router::hooks::use_navigate; @@ -16,6 +17,10 @@ pub fn Nav() -> impl IntoView { || (), move |_| async move { CLIENT.notifications_count().await.unwrap_or_default() }, ); + let instance = Resource::new( + || (), + |_| async move { CLIENT.get_local_instance().await.unwrap() }, + ); let (search_query, set_search_query) = signal(String::new()); let mut dark_mode = expect_context::<DarkMode>(); @@ -27,17 +32,15 @@ pub fn Nav() -> impl IntoView { > <h1 class="w-min font-serif text-3xl font-bold md:hidden">Ibis</h1> <div class="flex-grow md:hidden"></div> - <button tabindex="0" class="lg:hidden btn btn-outline"> - Menu - </button> - <div - tabindex="0" - class="p-2 md:h-full menu dropdown-content max-sm:rounded-box max-sm:z-[1] max-sm:shadow" - > + <button class="lg:hidden btn btn-outline">Menu</button> + <div class="md:h-full menu dropdown-content max-sm:rounded-box max-sm:z-[1] max-sm:shadow"> <Transition> <a href="/"> <img src="/logo.png" class="m-auto max-sm:hidden" /> </a> + <h2 class="m-4 font-serif text-xl font-bold"> + {move || { instance.get().map(|i| instance_title(&i.instance)) }} + </h2> <ul> <li> <a href="/">"Main Page"</a> @@ -61,6 +64,11 @@ pub fn Nav() -> impl IntoView { </a> </li> </Show> + <Show when=is_admin> + <li> + <a href="/settings">"Settings"</a> + </li> + </Show> <li> <form class="p-1 m-0 form-control" diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index bd6e474..cb50f2f 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -1,4 +1,9 @@ -use crate::common::{article::DbArticle, user::DbPerson, utils::extract_domain}; +use crate::common::{ + article::DbArticle, + instance::DbInstance, + user::DbPerson, + utils::extract_domain, +}; use chrono::{DateTime, Duration, Local, Utc}; use codee::string::FromToStringCodec; use leptos::prelude::*; @@ -103,3 +108,25 @@ fn time_ago(time: DateTime<Utc>) -> String { let duration = std::time::Duration::from_secs(secs.try_into().unwrap_or_default()); INSTANCE.get_or_init(Formatter::new).convert(duration) } + +fn instance_title_with_domain(instance: &DbInstance) -> String { + let name = instance.name.clone(); + let domain = instance.domain.clone(); + if let Some(name) = name { + format!("{name} ({domain})") + } else { + domain + } +} + +fn instance_title(instance: &DbInstance) -> String { + instance.name.clone().unwrap_or(instance.domain.clone()) +} + +fn instance_updated(instance: &DbInstance) -> String { + if instance.local { + "Local".to_string() + } else { + format!("Updated {}", time_ago(instance.last_refreshed_at)) + } +} diff --git a/src/frontend/pages/article/discussion.rs b/src/frontend/pages/article/discussion.rs index feb6ae0..cdcf5c0 100644 --- a/src/frontend/pages/article/discussion.rs +++ b/src/frontend/pages/article/discussion.rs @@ -21,12 +21,7 @@ pub fn ArticleDiscussion() -> impl IntoView { view! { <ArticleNav article=article active_tab=ActiveTab::Discussion /> <Suspense fallback=|| view! { "Loading..." }> - <CommentEditorView - article=article - parent_id=None - set_show_editor=None - edit_params=None - /> + <CommentEditorView article=article /> <div> <For each=move || { diff --git a/src/frontend/pages/instance/details.rs b/src/frontend/pages/instance/details.rs index 3984f73..b92a49b 100644 --- a/src/frontend/pages/instance/details.rs +++ b/src/frontend/pages/instance/details.rs @@ -5,6 +5,8 @@ use crate::{ article_path, article_title, components::instance_follow_button::InstanceFollowButton, + instance_title_with_domain, + instance_updated, }, }; use leptos::prelude::*; @@ -41,20 +43,19 @@ pub fn InstanceDetails() -> impl IntoView { .unwrap() }, ); - let title = instance.clone().description.unwrap_or(instance.clone().domain); + let title = instance_title_with_domain(&instance); let instance_ = instance.clone(); view! { - <Title text=title /> + <Title text=title.clone() /> <div class="grid gap-3 mt-4"> <div class="flex flex-row items-center"> - <h1 class="w-full font-serif text-4xl font-bold"> - {instance.domain} - </h1> + <h1 class="w-full font-serif text-4xl font-bold">{title}</h1> + {instance_updated(&instance_)} <InstanceFollowButton instance=instance_.clone() /> </div> <div class="divider"></div> - <div>{instance.description}</div> + <div>{instance.topic}</div> <h2 class="font-serif text-xl font-bold">Articles</h2> <ul class="list-none"> <Suspense> diff --git a/src/frontend/pages/instance/list.rs b/src/frontend/pages/instance/list.rs index 36f481e..d5a6b11 100644 --- a/src/frontend/pages/instance/list.rs +++ b/src/frontend/pages/instance/list.rs @@ -1,4 +1,9 @@ -use crate::frontend::{api::CLIENT, components::connect::ConnectView}; +use crate::frontend::{ + api::CLIENT, + components::connect::ConnectView, + instance_title_with_domain, + instance_updated, +}; use leptos::prelude::*; use leptos_meta::Title; @@ -26,12 +31,20 @@ pub fn ListInstances() -> impl IntoView { .map(|ref i| { view! { <li> - <a - class="text-lg link" - href=format!("/instance/{}", i.domain) - > - {i.domain.to_string()} - </a> + <div class="m-4 shadow card bg-base-100"> + <div class="p-4 card-body"> + <div class="flex"> + <a + class="card-title grow" + href=format!("/instance/{}", i.domain) + > + {instance_title_with_domain(i)} + </a> + {instance_updated(i)} + </div> + <p>{i.topic.clone()}</p> + </div> + </div> </li> } }) diff --git a/src/frontend/pages/instance/mod.rs b/src/frontend/pages/instance/mod.rs index bbd0b02..ab754b2 100644 --- a/src/frontend/pages/instance/mod.rs +++ b/src/frontend/pages/instance/mod.rs @@ -1,2 +1,3 @@ pub(crate) mod details; pub(crate) mod list; +pub(crate) mod settings; diff --git a/src/frontend/pages/instance/settings.rs b/src/frontend/pages/instance/settings.rs new file mode 100644 index 0000000..7fcdb14 --- /dev/null +++ b/src/frontend/pages/instance/settings.rs @@ -0,0 +1,112 @@ +use crate::{common::instance::UpdateInstanceParams, frontend::api::CLIENT}; +use leptos::prelude::*; +use leptos_meta::Title; + +#[component] +pub fn InstanceSettings() -> impl IntoView { + let (saved, set_saved) = signal(false); + let (submit_error, set_submit_error) = signal(None::<String>); + let instance = Resource::new( + || (), + |_| async move { CLIENT.get_local_instance().await.unwrap() }, + ); + + let submit_action = Action::new(move |params: &UpdateInstanceParams| { + let params = params.clone(); + async move { + let result = CLIENT.update_local_instance(¶ms).await; + match result { + Ok(_res) => { + instance.refetch(); + set_saved.set(true); + set_submit_error.set(None); + } + Err(err) => { + let msg = err.to_string(); + log::warn!("Unable to update profile: {msg}"); + set_submit_error.set(Some(msg)); + } + } + } + }); + + // TODO: It would make sense to use a table for the labels and inputs, but for some reason + // that completely breaks reactivity. + view! { + <Title text="Instance Settings" /> + <Suspense fallback=|| { + view! { "Loading..." } + }> + {move || Suspend::new(async move { + let instance = instance.await; + let (name, set_name) = signal(instance.instance.name.unwrap_or_default()); + let (topic, set_topic) = signal(instance.instance.topic.unwrap_or_default()); + view! { + <h1 class="flex-auto my-6 font-serif text-4xl font-bold grow"> + "Instance Settings" + </h1> + {move || { + submit_error + .get() + .map(|err| { + view! { <p class="alert alert-error">{err}</p> } + }) + }} + <div class="flex flex-row mb-2"> + <label class="block w-20" for="name"> + Name + </label> + <input + type="text" + id="name" + class="w-80 input input-secondary input-bordered" + prop:value=name + value=name + on:change=move |ev| { + let val = event_target_value(&ev); + set_name.set(val); + } + /> + </div> + <div class="flex flex-row mb-2"> + <label class="block w-20" for="topic"> + "Topic" + </label> + <input + type="text" + id="name" + class="w-80 input input-secondary input-bordered" + prop:value=topic + value=topic + on:change=move |ev| { + let val = event_target_value(&ev); + set_topic.set(val); + } + /> + </div> + <button + class="btn btn-primary" + on:click=move |_| { + let form = UpdateInstanceParams { + name: Some(name.get()), + topic: Some(topic.get()), + }; + submit_action.dispatch(form); + } + > + Submit + </button> + + <Show when=move || saved.get()> + <div class="toast"> + <div class="alert alert-info"> + <span>Saved!</span> + </div> + </div> + </Show> + } + })} + + </Suspense> + } +} diff --git a/tests/test.rs b/tests/test.rs index 49692ad..c4bd231 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -763,7 +763,7 @@ async fn test_synchronize_instances() -> Result<()> { .await .unwrap(); let beta_instances = beta.list_instances().await.unwrap(); - assert_eq!(1, beta_instances.len()); + assert_eq!(2, beta_instances.len()); // fetch beta instance on gamma gamma @@ -777,7 +777,7 @@ async fn test_synchronize_instances() -> Result<()> { let res = gamma.list_instances().await; match res { None => Err(RetryPolicy::<String>::Retry(None)), - Some(i) if i.len() < 2 => Err(RetryPolicy::Retry(None)), + Some(i) if i.len() < 3 => Err(RetryPolicy::Retry(None)), Some(i) => Ok(i), } }, @@ -786,7 +786,7 @@ async fn test_synchronize_instances() -> Result<()> { .await?; // now gamma also knows about alpha - assert_eq!(2, gamma_instances.len()); + assert_eq!(3, gamma_instances.len()); assert!(gamma_instances.iter().any(|i| i.domain == alpha.hostname)); TestData::stop(alpha, beta, gamma)