fix(desktop): identify stale hosted catalog results
This commit is contained in:
@@ -329,7 +329,35 @@ async fn hosted_actual_app_tasks_publish_edit_conflict_correct_credentials_reloa
|
||||
app.sync();
|
||||
app.hosted.base = base.clone();
|
||||
app.hosted.token = Secret(token.into());
|
||||
dispatch(&mut app, Message::Hosted(Event::Connect)).await;
|
||||
assert!(!app.hosted.catalog_stale);
|
||||
assert!(app.hosted.catalog.is_empty());
|
||||
assert!(
|
||||
app.hosted
|
||||
.catalog_message()
|
||||
.unwrap()
|
||||
.starts_with("No models found")
|
||||
);
|
||||
dispatch(&mut app, Message::Hosted(Event::Publish)).await;
|
||||
assert!(app.hosted.catalog_stale);
|
||||
assert!(
|
||||
!app.hosted
|
||||
.catalog_message()
|
||||
.unwrap()
|
||||
.starts_with("No models found")
|
||||
);
|
||||
dispatch(&mut app, Message::Hosted(Event::Close)).await;
|
||||
dispatch(&mut app, Message::Hosted(Event::Show)).await;
|
||||
assert!(app.hosted.catalog_stale);
|
||||
assert!(
|
||||
app.hosted.request.is_none(),
|
||||
"Showing the dialog does not poll"
|
||||
);
|
||||
dispatch(&mut app, Message::Hosted(Event::Connect)).await;
|
||||
assert!(!app.hosted.catalog_stale);
|
||||
assert_eq!(app.hosted.catalog.len(), 1);
|
||||
assert_eq!(app.hosted.catalog[0].revision, 1);
|
||||
dispatch(&mut app, Message::Hosted(Event::Close)).await;
|
||||
let session = app
|
||||
.hosted
|
||||
.session
|
||||
@@ -347,6 +375,15 @@ async fn hosted_actual_app_tasks_publish_edit_conflict_correct_credentials_reloa
|
||||
)
|
||||
.await;
|
||||
dispatch(&mut app, Message::Save(false)).await;
|
||||
assert!(app.hosted.catalog_stale);
|
||||
assert_eq!(
|
||||
app.hosted.catalog[0].revision, 1,
|
||||
"Old results stay identified as a snapshot"
|
||||
);
|
||||
dispatch(&mut app, Message::Hosted(Event::Connect)).await;
|
||||
assert!(!app.hosted.catalog_stale);
|
||||
assert_eq!(app.hosted.catalog[0].revision, 2);
|
||||
assert_eq!(app.hosted.catalog[0].name, "Graphical update");
|
||||
let external = Connection::new(&base, Secret(token.into())).unwrap();
|
||||
let remote = external.open(session.resource_id).await.unwrap();
|
||||
assert_eq!(remote.compiled.decoded.project.name, "Graphical update");
|
||||
@@ -558,3 +595,137 @@ fn hosted_failed_or_cancelled_local_open_keeps_the_existing_document_and_destina
|
||||
assert_eq!(app.hosted.session.as_ref().unwrap().resource_id, resource);
|
||||
}
|
||||
}
|
||||
|
||||
fn catalog_result(app: &App, resource: Id, revision: u64) -> Outcome {
|
||||
Outcome::Catalog(crate::hosted::client::Catalog {
|
||||
items: vec![crate::hosted::client::Summary {
|
||||
resource_id: resource,
|
||||
revision,
|
||||
model_id: app.project().id,
|
||||
name: format!("Catalog snapshot {revision}"),
|
||||
elements: app.project().elements.len(),
|
||||
relations: app.project().relations.len(),
|
||||
}],
|
||||
next_after: Some(resource),
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hosted_catalog_search_credentials_and_failed_refresh_never_mix_result_scopes() {
|
||||
let mut app = App::with_project(Project::empty());
|
||||
let first = Id::new_v4();
|
||||
send(&mut app, Event::Connect);
|
||||
let catalog = catalog_result(&app, first, 1);
|
||||
complete(&mut app, Ok(catalog));
|
||||
assert!(!app.hosted.catalog_stale);
|
||||
send(&mut app, Event::More);
|
||||
assert_eq!(
|
||||
app.hosted.request.as_ref().unwrap().operation,
|
||||
Operation::Catalog(true)
|
||||
);
|
||||
let next_page = catalog_result(&app, Id::new_v4(), 1);
|
||||
complete(&mut app, Ok(next_page));
|
||||
assert_eq!(app.hosted.catalog.len(), 2);
|
||||
send(&mut app, Event::Select(first));
|
||||
send(&mut app, Event::Query("different search".into()));
|
||||
assert!(app.hosted.catalog_stale);
|
||||
assert!(app.hosted.next.is_none());
|
||||
assert!(app.hosted.selected.is_none());
|
||||
assert_eq!(app.hosted.catalog.len(), 2);
|
||||
assert!(
|
||||
app.hosted
|
||||
.catalog_message()
|
||||
.unwrap()
|
||||
.contains("Connect / refresh")
|
||||
);
|
||||
send(&mut app, Event::More);
|
||||
assert!(app.hosted.request.is_none());
|
||||
send(&mut app, Event::Connect);
|
||||
complete(&mut app, Err(failure(None, false)));
|
||||
assert!(app.hosted.catalog_stale);
|
||||
assert_eq!(app.hosted.catalog[0].resource_id, first);
|
||||
send(&mut app, Event::Connect);
|
||||
let second = Id::new_v4();
|
||||
let catalog = catalog_result(&app, second, 1);
|
||||
complete(&mut app, Ok(catalog));
|
||||
assert!(!app.hosted.catalog_stale);
|
||||
assert_eq!(app.hosted.catalog.len(), 1);
|
||||
assert_eq!(app.hosted.catalog[0].resource_id, second);
|
||||
send(&mut app, Event::Query("different search".into()));
|
||||
assert!(
|
||||
!app.hosted.catalog_stale,
|
||||
"Unchanged query preserves the snapshot"
|
||||
);
|
||||
send(
|
||||
&mut app,
|
||||
Event::Token(Secret("different-credential".into())),
|
||||
);
|
||||
assert!(app.hosted.catalog_stale);
|
||||
assert!(app.hosted.catalog.is_empty());
|
||||
assert!(app.hosted.connection.is_none());
|
||||
assert!(app.hosted.next.is_none());
|
||||
assert!(app.hosted.selected.is_none());
|
||||
assert!(
|
||||
!app.hosted
|
||||
.catalog_message()
|
||||
.unwrap()
|
||||
.starts_with("No models found")
|
||||
);
|
||||
send(&mut app, Event::Connect);
|
||||
let catalog = catalog_result(&app, second, 2);
|
||||
complete(&mut app, Ok(catalog));
|
||||
send(&mut app, Event::Base("http://127.0.0.1:9876".into()));
|
||||
assert!(app.hosted.catalog.is_empty());
|
||||
assert!(app.hosted.connection.is_none());
|
||||
assert!(app.hosted.catalog_stale);
|
||||
assert!(app.hosted.request.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hosted_catalog_invalidation_follows_service_writes_and_observed_revision_changes() {
|
||||
let mut app = App::with_project(Project::empty());
|
||||
let resource = bind(&mut app);
|
||||
let other = Id::new_v4();
|
||||
send(&mut app, Event::Base("http://127.0.0.1:9876".into()));
|
||||
send(&mut app, Event::Connect);
|
||||
let catalog = catalog_result(&app, other, 7);
|
||||
complete(&mut app, Ok(catalog));
|
||||
rename(&mut app, "Saved to original service");
|
||||
send(&mut app, Event::Save);
|
||||
let saved = remote(app.document.snapshot(), resource, 2);
|
||||
complete(&mut app, Ok(Outcome::Remote(saved)));
|
||||
assert!(
|
||||
!app.hosted.catalog_stale,
|
||||
"A write to A cannot invalidate B's catalog"
|
||||
);
|
||||
assert_eq!(app.hosted.next, Some(other));
|
||||
assert_eq!(app.hosted.catalog[0].resource_id, other);
|
||||
|
||||
send(&mut app, Event::Base("http://127.0.0.1:8787".into()));
|
||||
send(&mut app, Event::Connect);
|
||||
let catalog = catalog_result(&app, resource, 2);
|
||||
complete(&mut app, Ok(catalog));
|
||||
send(&mut app, Event::Check);
|
||||
let changed = remote(app.document.snapshot(), resource, 3);
|
||||
complete(&mut app, Ok(Outcome::Remote(changed)));
|
||||
assert!(
|
||||
app.hosted.catalog_stale,
|
||||
"A known newer server revision invalidates old metadata"
|
||||
);
|
||||
assert!(app.hosted.next.is_none());
|
||||
send(&mut app, Event::Connect);
|
||||
let catalog = catalog_result(&app, resource, 3);
|
||||
complete(&mut app, Ok(catalog));
|
||||
send(&mut app, Event::Reload);
|
||||
rename(&mut app, "Write with uncertain outcome");
|
||||
send(&mut app, Event::Save);
|
||||
complete(&mut app, Err(failure(None, true)));
|
||||
assert!(app.hosted.catalog_stale);
|
||||
assert!(app.hosted.next.is_none());
|
||||
assert_eq!(app.hosted.catalog[0].revision, 3);
|
||||
app.hosted.leave_document();
|
||||
assert!(
|
||||
app.hosted.catalog_stale,
|
||||
"Leaving the hosted destination cannot make old results fresh"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user