test(axum): prove registry dispatch boundary

Exercise registered sync and async handles through public dispatch_async, prove membership semantics, and serialize shared-boundary tests so mutation workers remain deterministic.

req: axum_integration/003

req: public_api/001
This commit is contained in:
slhx agent
2026-07-17 00:17:24 +02:00
parent e38489621b
commit b0a8275b03
2 changed files with 37 additions and 1 deletions
+1 -1
View File
@@ -21,7 +21,7 @@
- [ ] **State:** In progress — the package-native capped xtask entry point is reachable, rejects unknown packages, propagates mutest failure, and mutation-tests `hemx-core`, `hemx-js`, and the full `hemx-test` package cleanly; full package closure remains.
- **User value:** maintainers can run one bounded repository command and trust that meaningful Rust logic across every mutation-applicable library is either killed or explicitly justified.
- **Build:** add a capped `hemx-xtask` mutation command that invokes `/opt/repositories/mutest`/`mutest` through package-native test targets rather than the broken workspace-wide example path; enumerate only current mutation-applicable library/proc-macro packages; finish adversarial tests or simplify code until every survivor is classified; keep equivalent, invariant-only, and infrastructure-inapplicable classifications inspectable and minimal; document the exact local release command in the existing readiness surface.
- **Blocked by:** none; broad survivors currently remain in `hemx-axum`, `hemx-build`, `hemx-derive`, and `hemx-lsp` outside already-clean focused contracts; the current `hemx-axum` frontier now proves page-mode, response constructors, form accessors/rejections, media-type limits, and multipart success/error semantics mutation-clean; registry and remaining response paths remain.
- **Blocked by:** none; broad survivors currently remain in `hemx-axum`, `hemx-build`, `hemx-derive`, and `hemx-lsp` outside already-clean focused contracts; the current `hemx-axum` frontier now proves page-mode, response constructors, form accessors/rejections, media-type limits, multipart success/error semantics, and sync/async registry dispatch mutation-clean; remaining response and integration paths remain.
- **Proof:** the new xtask mutation command exits zero within its documented bound, covers each applicable package, emits no unexplained missed mutant, and a deliberate adjacent mutation makes it fail. `cargo run -p hemx-xtask -- test` remains green. req: test/020 req: test/021
## 3. Elect and enforce the release license policy
+36
View File
@@ -19,6 +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(());
async fn bounded_mutation(_: InteractionRequest) -> StatusCode {
MUTATION_CALLS.fetch_add(1, Ordering::SeqCst);
@@ -40,6 +41,9 @@ 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());
MUTATION_CALLS.store(0, Ordering::SeqCst);
let app = Router::new()
.route("/mutate", post(bounded_mutation))
@@ -100,6 +104,9 @@ 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 boundary = "hemx-boundary";
let body = concat!(
"--hemx-boundary\r\n",
@@ -134,6 +141,9 @@ async fn interaction_boundary_extracts_multipart_fields_and_files() {
#[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 accepted = concat!(
"--b\r\n",
"Content-Disposition: form-data; filename=\"ignored.txt\"\r\n\r\n",
@@ -781,6 +791,32 @@ fn interactions_dispatch_by_checked_handle() {
assert_eq!(response.batch.ops, vec![title.text("Hello")]);
}
#[tokio::test]
async fn registry_contains_registered_sync_and_async_handles_and_async_falls_back_to_sync() {
let sync = Handle::<()>::new(21);
let asynchronous = Handle::<()>::new(22);
let registry = interactions(BuildFingerprint(55))
.on(sync, |_| Slot::<String>::new(1).text("sync"))
.on_async(asynchronous, |_| async {
Slot::<String>::new(1).text("async")
});
assert!(registry.contains(sync.id().id));
assert!(registry.contains(asynchronous.id().id));
assert!(!registry.contains(99));
let sync_response = InteractionRequest::from(InteractionForm::for_handle(sync, []))
.dispatch_async(registry)
.await
.unwrap();
assert_eq!(sync_response.batch.fingerprint, BuildFingerprint(55));
assert_eq!(
sync_response.batch.ops,
vec![Slot::<String>::new(1).text("sync")]
);
// test req: axum_integration/003 req: public_api/001
}
#[test]
fn interactions_reject_unknown_handle_ids() {
let request = InteractionRequest::from(InteractionForm::new(9, []));