From 3c8b130be89fbb0e58e2ee23f07ad56a3b9de2e7 Mon Sep 17 00:00:00 2001 From: Andrew Guschin Date: Fri, 30 Oct 2026 05:15:56 +0400 Subject: Reject streamed diagnostic error documents and record VM qualification --- tests/diagnostics_acceptance.rs | 36 ++++++++++++++++++++++++++++++++++++ tests/vm_diagnostics_acceptance.py | 7 ++++++- 2 files changed, 42 insertions(+), 1 deletion(-) (limited to 'tests') diff --git a/tests/diagnostics_acceptance.rs b/tests/diagnostics_acceptance.rs index f1db2de..0dcba04 100644 --- a/tests/diagnostics_acceptance.rs +++ b/tests/diagnostics_acceptance.rs @@ -603,3 +603,39 @@ async fn cancelling_a_bus_diagnostic_stops_it_without_changing_proxy_intent() { .all(|entry| entry.speed_bytes_per_second.is_none()) ); } + +#[tokio::test] +async fn controller_rejects_streamed_json_errors_without_misclassifying_payload_fields() { + let mut context = Context::open().await; + for path in ["/long-error", "/late-error", "/escaped-error"] { + context.settings("/empty", path, 1, 1).await; + let error = context + .controller + .diagnostic(&Caller::root(), None, true) + .await + .unwrap_err(); + assert!( + error.to_string().contains("error document"), + "Long provider error was not recognized for {path}: {error}" + ); + } + context.settings("/empty", "/late-html", 1, 1).await; + assert!( + context + .controller + .diagnostic(&Caller::root(), None, true) + .await + .unwrap_err() + .to_string() + .contains("HTML") + ); + context.settings("/empty", "/json-data", 1, 1).await; + let observation = context + .controller + .diagnostic(&Caller::root(), None, true) + .await + .unwrap(); + assert!(observation.success); + assert!(observation.bytes > 30000); + assert_eq!(observation.stop_reason, "complete"); +} diff --git a/tests/vm_diagnostics_acceptance.py b/tests/vm_diagnostics_acceptance.py index 1984585..001f1a3 100644 --- a/tests/vm_diagnostics_acceptance.py +++ b/tests/vm_diagnostics_acceptance.py @@ -75,9 +75,14 @@ def main(binary): self.send_response(206); self.end_headers(); self.wfile.write(b'partial'); return self.send_response(200) if self.path == '/error': self.send_header('Content-Type', 'application/problem+json') - if self.path == '/json-error': self.send_header('Content-Type', 'application/json') + if self.path in ['/json-error', '/long-error', '/late-error', '/escaped-error', '/json-data']: self.send_header('Content-Type', 'application/json') body = b'' if self.path in ['/error', '/json-error']: body = b'{"error":"fixture-provider-error"}' + if self.path == '/long-error': body = json.dumps({'error':'x'*30000}).encode() + if self.path == '/late-error': body = json.dumps({'metadata':'x'*30000, 'error':'provider failure'}).encode() + if self.path == '/escaped-error': body = b'{"\\u0065rror":"' + b'x'*20000 + b'"}' + if self.path == '/json-data': body = json.dumps({'data':{'error':'nested payload'},'metadata':'x'*30000 + '"error":not a field', 'error':None,'errors':[]}).encode() + if self.path == '/late-html': body = b' ' * 30000 + b'provider error' if self.path == '/html': body = b'unexpected page' if self.path == '/oversize': body = b'x' * 4097 if self.path == '/large': body = b'x' * (8 * 1048576) -- cgit v1.2.3