Implement closed typed effect path
This commit is contained in:
@@ -19,7 +19,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use tower::ServiceExt;
|
||||
|
||||
static MUTATION_CALLS: AtomicUsize = AtomicUsize::new(0);
|
||||
static BOUNDARY_TEST_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
|
||||
static BOUNDARY_TEST_LOCK: tokio::sync::Mutex<()> = tokio::sync::Mutex::const_new(());
|
||||
|
||||
async fn bounded_mutation(_: InteractionRequest) -> StatusCode {
|
||||
MUTATION_CALLS.fetch_add(1, Ordering::SeqCst);
|
||||
@@ -40,10 +40,7 @@ async fn multipart_mutation(request: InteractionRequest) -> StatusCode {
|
||||
|
||||
#[tokio::test]
|
||||
async fn interaction_boundary_honors_media_type_and_host_body_limit() {
|
||||
// test req: security/003
|
||||
let _guard = BOUNDARY_TEST_LOCK
|
||||
.lock()
|
||||
.unwrap_or_else(|error| error.into_inner());
|
||||
let _guard = BOUNDARY_TEST_LOCK.lock().await;
|
||||
MUTATION_CALLS.store(0, Ordering::SeqCst);
|
||||
let app = Router::new()
|
||||
.route("/mutate", post(bounded_mutation))
|
||||
@@ -104,9 +101,7 @@ async fn interaction_boundary_honors_media_type_and_host_body_limit() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn interaction_boundary_extracts_multipart_fields_and_files() {
|
||||
let _guard = BOUNDARY_TEST_LOCK
|
||||
.lock()
|
||||
.unwrap_or_else(|error| error.into_inner());
|
||||
let _guard = BOUNDARY_TEST_LOCK.lock().await;
|
||||
let boundary = "hemx-boundary";
|
||||
let body = concat!(
|
||||
"--hemx-boundary\r\n",
|
||||
@@ -136,14 +131,11 @@ async fn interaction_boundary_extracts_multipart_fields_and_files() {
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(response.status(), StatusCode::NO_CONTENT);
|
||||
// test req: multipart/001 req: multipart/002 req: multipart/003
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interaction_boundary_skips_unnamed_parts_and_rejects_invalid_multipart() {
|
||||
let _guard = BOUNDARY_TEST_LOCK
|
||||
.lock()
|
||||
.unwrap_or_else(|error| error.into_inner());
|
||||
let _guard = BOUNDARY_TEST_LOCK.lock().await;
|
||||
let app = Router::new().route("/mutate", post(bounded_mutation));
|
||||
let missing_boundary = app
|
||||
.clone()
|
||||
@@ -208,7 +200,6 @@ async fn interaction_boundary_skips_unnamed_parts_and_rejects_invalid_multipart(
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
|
||||
// test req: multipart/001 req: multipart/003
|
||||
}
|
||||
|
||||
fn selector(value: &str) -> Selector {
|
||||
@@ -266,12 +257,10 @@ fn page_mode_detects_only_explicit_partial_header_values() {
|
||||
headers.insert(HEMX_PARTIAL_HEADER, value.parse().unwrap());
|
||||
assert_eq!(PageMode::from_headers(&headers), PageMode::Partial);
|
||||
}
|
||||
// test req: page_swap/001
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn page_request_wraps_full_pages_and_leaves_partials_unwrapped() {
|
||||
// req: test/005
|
||||
assert!(!PageRequest {
|
||||
mode: PageMode::Full
|
||||
}
|
||||
@@ -321,7 +310,6 @@ fn page_request_wraps_full_pages_and_leaves_partials_unwrapped() {
|
||||
|
||||
#[test]
|
||||
fn page_request_wraps_safe_html_full_pages_and_leaves_partials_unwrapped() {
|
||||
// req: axum_integration/001 req: html_safety/001 req: html_safety/002 req: test/005
|
||||
let full = PageRequest {
|
||||
mode: PageMode::Full,
|
||||
}
|
||||
@@ -389,7 +377,6 @@ fn page_response_constructors_preserve_mode_and_optional_fingerprint() {
|
||||
partial.fingerprint(fingerprint).fingerprint,
|
||||
Some(fingerprint)
|
||||
);
|
||||
// test req: page_swap/001 req: abi/005
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -410,7 +397,6 @@ async fn full_page_response_preserves_html_and_fingerprint_without_partial_heade
|
||||
to_bytes(response.into_body(), 1024).await.unwrap().as_ref(),
|
||||
b"<html>Full</html>"
|
||||
);
|
||||
// test req: page_swap/001 req: abi/005
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -447,7 +433,6 @@ fn interaction_form_parses_handle_and_fields() {
|
||||
|
||||
#[test]
|
||||
fn interaction_form_parses_typed_values() {
|
||||
// req: form/004 req: dx/003
|
||||
let form =
|
||||
InteractionForm::parse_urlencoded(b"__h=42&count=7&bad=nope").expect("form should parse");
|
||||
|
||||
@@ -470,7 +455,6 @@ fn interaction_form_requires_numeric_handle() {
|
||||
|
||||
#[test]
|
||||
fn interaction_form_preserves_hidden_csrf_fields_for_extractors() {
|
||||
// req: auth/004
|
||||
let form = InteractionForm::parse_urlencoded(b"__h=42&csrf_token=abc123&title=Hello").unwrap();
|
||||
|
||||
assert_eq!(form.handle_id, 42);
|
||||
@@ -480,7 +464,6 @@ fn interaction_form_preserves_hidden_csrf_fields_for_extractors() {
|
||||
|
||||
#[test]
|
||||
fn interaction_request_dispatches_with_concise_handlers_helper() {
|
||||
// req: axum_integration/003 req: ceremony/001 req: dx/003
|
||||
let request = InteractionRequest::from(InteractionForm::for_handle(
|
||||
Handle::<()>::new(7),
|
||||
Vec::new(),
|
||||
@@ -498,7 +481,6 @@ fn interaction_request_dispatches_with_concise_handlers_helper() {
|
||||
|
||||
#[test]
|
||||
fn state_interactions_starts_stateful_wiring_without_nested_closures() {
|
||||
// req: axum_integration/003 req: ceremony/001 req: dx/003
|
||||
fn ping(prefix: String) -> impl IntoEffect {
|
||||
Slot::<String>::new(3).text(format!("{prefix}: ping"))
|
||||
}
|
||||
@@ -568,7 +550,6 @@ fn interaction_form_accessors_preserve_repeated_values_and_decode_diagnostics()
|
||||
.fields()
|
||||
.iter()
|
||||
.any(|pair| pair == &("count".into(), "7".into())));
|
||||
// test req: form/002 req: form/004 req: multipart/001
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -607,12 +588,10 @@ async fn interaction_form_rejections_return_stable_status_and_diagnostic() {
|
||||
message.as_bytes()
|
||||
);
|
||||
}
|
||||
// test req: failure/003 req: multipart/003
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn interaction_request_dispatches_typed_form_inputs() {
|
||||
// req: axum_integration/003 req: form/004 req: canonical_authoring/003
|
||||
let request = InteractionRequest::from(InteractionForm::for_handle(
|
||||
Handle::<()>::new(8),
|
||||
vec![("project_id".to_owned(), "42".to_owned())],
|
||||
@@ -632,7 +611,6 @@ fn interaction_request_dispatches_typed_form_inputs() {
|
||||
|
||||
#[test]
|
||||
fn interaction_request_rejects_invalid_typed_form_inputs() {
|
||||
// req: axum_integration/003 req: form/004 req: canonical_authoring/004
|
||||
let request = InteractionRequest::from(InteractionForm::for_handle(
|
||||
Handle::<()>::new(8),
|
||||
vec![("project_id".to_owned(), "nope".to_owned())],
|
||||
@@ -654,7 +632,6 @@ fn interaction_request_rejects_invalid_typed_form_inputs() {
|
||||
|
||||
#[test]
|
||||
fn interaction_request_dispatches_typed_state_handlers() {
|
||||
// req: axum_integration/003 req: form/004 req: canonical_authoring/003
|
||||
fn open_project(multiplier: u32, input: OpenProject) -> impl IntoEffect {
|
||||
Slot::<String>::new(3).text(input.project_id.0 * multiplier)
|
||||
}
|
||||
@@ -702,7 +679,6 @@ impl IntoHandlerFailure for UiFailure {
|
||||
|
||||
#[tokio::test]
|
||||
async fn interaction_request_dispatches_async_typed_state_extractors() {
|
||||
// req: axum_integration/003 req: form/004 req: canonical_authoring/003
|
||||
async fn open_project(
|
||||
State(multiplier): State<u32>,
|
||||
Form(input): Form<OpenProject>,
|
||||
@@ -729,7 +705,6 @@ async fn interaction_request_dispatches_async_typed_state_extractors() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn interaction_request_reports_async_result_handler_errors() {
|
||||
// req: axum_integration/003 req: form/004 req: failure/003
|
||||
async fn open_project(
|
||||
State(_multiplier): State<u32>,
|
||||
Form(_input): Form<OpenProject>,
|
||||
@@ -762,7 +737,6 @@ async fn interaction_request_reports_async_result_handler_errors() {
|
||||
|
||||
#[tokio::test]
|
||||
async fn interaction_request_maps_async_result_errors_to_effects() {
|
||||
// req: axum_integration/003 req: failure/004
|
||||
async fn open_project(
|
||||
State(_multiplier): State<u32>,
|
||||
Form(_input): Form<OpenProject>,
|
||||
@@ -792,7 +766,6 @@ async fn interaction_request_maps_async_result_errors_to_effects() {
|
||||
|
||||
#[test]
|
||||
fn interaction_request_maps_sync_result_errors_to_effects() {
|
||||
// req: axum_integration/003 req: failure/004
|
||||
fn open_project(
|
||||
State(_multiplier): State<u32>,
|
||||
Form(_input): Form<OpenProject>,
|
||||
@@ -821,7 +794,6 @@ fn interaction_request_maps_sync_result_errors_to_effects() {
|
||||
|
||||
#[test]
|
||||
fn interactions_dispatch_by_checked_handle() {
|
||||
// req: ceremony/004 req: public_api/001
|
||||
let title = Slot::<String>::new(7);
|
||||
let create = Handle::<()>::new(42);
|
||||
let request = InteractionRequest::from(InteractionForm::for_handle(
|
||||
@@ -862,7 +834,6 @@ async fn registry_contains_registered_sync_and_async_handles_and_async_falls_bac
|
||||
sync_response.batch.ops,
|
||||
vec![Slot::<String>::new(1).text("sync")]
|
||||
);
|
||||
// test req: axum_integration/003 req: public_api/001
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -883,9 +854,8 @@ async fn state_result_registration_paths_preserve_state_form_and_failures() {
|
||||
typed,
|
||||
String::from("typed"),
|
||||
|state: State<String>, Form(form): Form<OpenProject>| {
|
||||
Err::<Effect, _>(HandlerBoom).map_err(|error| {
|
||||
Err::<Effect, _>(HandlerBoom).inspect_err(|_| {
|
||||
let _ = (state, form);
|
||||
error
|
||||
})
|
||||
},
|
||||
)
|
||||
@@ -1011,7 +981,6 @@ async fn state_result_registration_paths_preserve_state_form_and_failures() {
|
||||
response.batch.ops,
|
||||
vec![Slot::<String>::new(1).text("typed-async:9")]
|
||||
);
|
||||
// test req: axum_integration/003 req: derive_handler/005
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1074,7 +1043,6 @@ async fn effect_and_dispatch_responses_preserve_status_wire_and_diagnostics() {
|
||||
|
||||
let response = DispatchRejection::HandlerError(HandlerFailure::Effects(batch)).into_response();
|
||||
assert_eq!(response.headers()[header::CONTENT_TYPE], HEMX_CONTENT_TYPE);
|
||||
// test req: axum_integration/003 req: failure/005 req: wire/007
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -1106,7 +1074,6 @@ async fn runtime_js_response_serves_embedded_runtime() {
|
||||
);
|
||||
}
|
||||
|
||||
// req: axum_integration/005
|
||||
#[test]
|
||||
fn runtime_js_path_is_content_hashed() {
|
||||
let path = runtime_js_path();
|
||||
|
||||
Reference in New Issue
Block a user