fix: align tui status and list viewports
This commit is contained in:
@@ -8,7 +8,7 @@ use wip_fs_server::{ServerConfig, WipFsServer};
|
||||
use wip_https::encode_protocol_error_response;
|
||||
use wip_https::http::{Request, Response};
|
||||
use wip_protocol::{ProtocolError, ProtocolErrorCode, ProtocolInteraction};
|
||||
use wip_tui::app::{Focus, HistoryKind, InputKey, Modal, ViewState};
|
||||
use wip_tui::app::{ConnectionState, Focus, HistoryKind, InputKey, Modal, ViewState};
|
||||
use wip_tui::config::Config;
|
||||
use wip_tui::runtime::{
|
||||
Runtime, Transport, TransportError, TransportErrorKind, default_wire_limits,
|
||||
@@ -20,7 +20,9 @@ struct ScriptedTransport {
|
||||
delayed_after_startup: bool,
|
||||
unknown_calls: bool,
|
||||
fail_call_prepare: bool,
|
||||
fail_tree_prepare: bool,
|
||||
panic_calls: bool,
|
||||
root_tree_protocol_failures: Arc<AtomicUsize>,
|
||||
}
|
||||
|
||||
impl ScriptedTransport {
|
||||
@@ -31,7 +33,9 @@ impl ScriptedTransport {
|
||||
delayed_after_startup: false,
|
||||
unknown_calls: false,
|
||||
fail_call_prepare: false,
|
||||
fail_tree_prepare: false,
|
||||
panic_calls: false,
|
||||
root_tree_protocol_failures: Arc::new(AtomicUsize::new(0)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,11 +50,35 @@ impl Transport for ScriptedTransport {
|
||||
detail: "scripted local conversion failure".into(),
|
||||
});
|
||||
}
|
||||
if self.fail_tree_prepare && request.uri().path().ends_with("/v1/fetch_tree") {
|
||||
return Err(TransportError {
|
||||
kind: TransportErrorKind::Disconnect,
|
||||
detail: "scripted tree conversion failure".into(),
|
||||
});
|
||||
}
|
||||
Ok(request)
|
||||
}
|
||||
|
||||
fn execute(&self, request: Self::Prepared) -> Result<Response<Vec<u8>>, TransportError> {
|
||||
let sequence = self.sequence.fetch_add(1, Ordering::AcqRel);
|
||||
if request.uri().path().ends_with("/v1/fetch_tree")
|
||||
&& self
|
||||
.root_tree_protocol_failures
|
||||
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |remaining| {
|
||||
remaining.checked_sub(1)
|
||||
})
|
||||
.is_ok()
|
||||
{
|
||||
return Ok(encode_protocol_error_response(
|
||||
ProtocolInteraction::FetchTree,
|
||||
&ProtocolError {
|
||||
code: ProtocolErrorCode::Internal,
|
||||
message: "scripted startup failure".into(),
|
||||
},
|
||||
default_wire_limits(),
|
||||
)
|
||||
.expect("encode tree failure"));
|
||||
}
|
||||
if self.delayed_after_startup && sequence > 0 {
|
||||
// Each refresh starts object then tree. Make the first pair lose to
|
||||
// the second pair to exercise exact RequestId ownership.
|
||||
@@ -123,6 +151,56 @@ fn out_of_order_refresh_and_cancel_keep_request_identity_safe() {
|
||||
assert!(runtime.app().operation_rows().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn startup_transport_preparation_failure_enters_failed_state() {
|
||||
let temporary = tempdir().expect("temporary root");
|
||||
let server = Arc::new(
|
||||
WipFsServer::new(ServerConfig::for_root(temporary.path())).expect("filesystem server"),
|
||||
);
|
||||
let mut transport = ScriptedTransport::new(server);
|
||||
transport.fail_tree_prepare = true;
|
||||
let config = config();
|
||||
let mut runtime = Runtime::new(&config, transport).expect("runtime");
|
||||
|
||||
runtime.connect();
|
||||
settle(&mut runtime);
|
||||
assert!(matches!(
|
||||
runtime.app().connection,
|
||||
ConnectionState::Failed(ref detail) if detail.contains("scripted tree conversion failure")
|
||||
));
|
||||
assert!(runtime.app().status.contains("press R to reconnect"));
|
||||
assert!(runtime.app().in_flight.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn startup_protocol_failure_enters_failed_state_and_reconnects() {
|
||||
let temporary = tempdir().expect("temporary root");
|
||||
let server = Arc::new(
|
||||
WipFsServer::new(ServerConfig::for_root(temporary.path())).expect("filesystem server"),
|
||||
);
|
||||
let transport = ScriptedTransport::new(server);
|
||||
transport
|
||||
.root_tree_protocol_failures
|
||||
.store(1, Ordering::Release);
|
||||
let config = config();
|
||||
let mut runtime = Runtime::new(&config, transport).expect("runtime");
|
||||
|
||||
runtime.connect();
|
||||
settle(&mut runtime);
|
||||
assert!(matches!(
|
||||
runtime.app().connection,
|
||||
ConnectionState::Failed(ref detail) if detail.contains("scripted startup failure")
|
||||
));
|
||||
assert!(runtime.app().status.contains("press R to reconnect"));
|
||||
assert!(runtime.app().history.iter().any(|item| {
|
||||
item.kind == HistoryKind::DomainFailure && item.detail.contains("scripted startup failure")
|
||||
}));
|
||||
|
||||
runtime.handle_key(InputKey::Reconnect);
|
||||
settle(&mut runtime);
|
||||
assert_eq!(runtime.app().connection, ConnectionState::Connected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn local_transport_preparation_failure_is_definitely_not_dispatched() {
|
||||
let temporary = tempdir().expect("temporary root");
|
||||
@@ -150,6 +228,10 @@ fn local_transport_preparation_failure_is_definitely_not_dispatched() {
|
||||
assert!(runtime.app().in_flight.is_empty());
|
||||
assert_eq!(runtime.app().history[0].kind, HistoryKind::TransportFailure);
|
||||
assert!(runtime.app().history[0].detail.contains("not dispatched"));
|
||||
assert_eq!(
|
||||
runtime.app().status,
|
||||
"operation not dispatched; not executed"
|
||||
);
|
||||
assert_eq!(runtime.app().entries["/file"].state, ViewState::Fresh);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user