Run a test as a streaming function, so an event stream can be asserted - #331
Merged
Merged
Conversation
From the 0.32 trial: C-02, reframed. The reported symptom is that Lambda streaming mode dies on the first request against the AWS Lambda Test Tool, and both causes are AWS's own, confirmed by decompiling RuntimeSupport 2.2.0. RawStreamingHttpClient reads AWS_LAMBDA_RUNTIME_API as host:port and parses the rest as a port number, while the tool needs a function name in the path; and the same client writes a request line with no function name in it, so shortening the endpoint would leave the tool unable to route. Neither is reachable from here. What the finding was really about is that an event stream could not be checked in the mode it deploys in. That did not need those two to talk. The seam already existed - IResponseStreamFactory, which exists because AWS's own factory is static with an internal setter - and the testing library simply had no wiring for it or for the response mode, so an application could not run its own Lambda as a streaming function at all. [LambdaWebTesting(ResponseMode = LambdaResponseMode.Stream)] registers StreamedResponseCapture over the runtime's factory and amends the mode. A streamed invocation returns Stream.Null and writes to the response stream, so the host builds its answer from the prelude's status and headers and the bytes. That closes a hole the repository already named: ServerSentEventManifestTests says the manifest and the buffered-mode warning are each covered and "neither says the two meet". Now something does. The frames are not a discriminator. A buffered invocation writes identical bytes, which is what the buffered-mode warning is about, so three of the four new tests pass with the mode switched off - verified by switching it off. The test that takes IResponseStreamFactory and asserts a stream was opened is the one that fails, and the guide says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
From the 0.32 trial: C-02, reframed. The reported symptom is real and confirmed; the fix it implied is not the one worth building.
What the finding got right
Both causes are AWS's, confirmed by decompiling
Amazon.Lambda.RuntimeSupport2.2.0 rather than relayed.localhost:5050/Telemetry.Hostsplits into exactly two parts, so the guard passes andint.Parsethrows. The trial's account is exact, and it is not thenet11.0arm's doing — the parsing is the same on every target.The second cause rules out the obvious fix. The same client hardcodes its request line as
POST /2018-06-01/runtime/invocation/{id}/response, with the function name nowhere in it. The Lambda Test Tool runs every function on one port and routes by a/{FunctionName}prefix, andlambda-test-tool starthas no per-function-port flag — so shortening the endpoint fixes the parse and leaves the tool unable to route.Neither is reachable from here, and neither is reported:
RawStreamingHttpClientappears in no GitHub issue anywhere, searched acrossaws/aws-lambda-dotnetopen and closed.What it got wrong
"SSE cannot be exercised locally in the mode it deploys in." The locally is a platform-wide gap, not ours: RIE implements no response streaming for any language (#175 open since April with no comments, #179 unreviewed since May), and SAM local runs RIE underneath. Node had streaming years before .NET and cannot do this either.
The exercised was ours, and it did not need those two AWS pieces to talk.
IResponseStreamFactoryalready exists as the seam —LambdaResponseStreamFactoryis static with an internal setter, so nothing built on it can be driven from a test — andHardened.Aws.Lambda.Testingsimply had no wiring for it or for the response mode. An application could not run its own Lambda as a streaming function at all.What this does
The mode registers
StreamedResponseCaptureover the runtime's factory and amends the configuration. A streamed invocation returnsStream.Nulland writes to the response stream, so the host builds its answer from the prelude's status and headers and the bytes — the sameStreamedpath a deployed function takes.It asks what happened rather than assuming the mode decided it: an adapter with no caller holding a connection stays buffered under the same mode, opens nothing, and the host reads its envelope as usual.
This closes a hole the repository already named.
ServerSentEventManifestTestssays the manifest and the buffered-mode warning are each covered and "neither says the two meet". Now something does.The frames are not a discriminator
Three of the four new tests pass with the mode switched off. I know because I switched it off: 17 of 18 still passed. A buffered invocation writes identical SSE bytes — that is exactly what the buffered-mode warning is about, every event delivered at the end rather than as it happens — so a test asserting only on the body proves nothing about the mode.
That is the one that fails, and
aws/testing.mdsays so in bold, because anyone writing one of these would otherwise write the vacuous version.Verification
dotnet test Hardened.slnx— 74 assemblies, 0 failures.dotnet build Hardened.slnx --configuration Release -p:ContinuousIntegrationBuild=true— 0 warnings, 0 errors.scripts/verify-templates.sh— every combination, no failures.npm run buildindocs/— no dead links.ResponseModeandStreamedResponseCapture. The streaming constructor onLambdaWebHostis internal, because a host built with a capture nothing resolves reads an empty response for every request.aws/testing.mdgains Testing a streaming function and states plainly why the Test Tool cannot do this;streaming.mdpoints at it from the host table.🤖 Generated with Claude Code