fix(ls-api): align mock with LocalStack API and add regression test#101
fix(ls-api): align mock with LocalStack API and add regression test#101joe4dev wants to merge 12 commits into
Conversation
…on tests
- Return 202 Accepted from all handlers to match executor_endpoint.py
- Add missing InvokedFunctionArn and TraceId fields to InvokeRequest
- Parse {"logs":"..."} JSON in invokeLogsHandler instead of raw bytes
- Read and log request body in invokeErrorHandler
- Downgrade log.Fatal to log.Error in statusHandler goroutine
- Add main_test.go with 7 regression tests covering all endpoints,
JSON field names, and the async invoke triggered on status/ready
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
dfangl
left a comment
There was a problem hiding this comment.
I'm not quite sure what the purpose of this PR is - where is this ls-api mock used? It definitely improves the mock, but I don't quite understand where the mock itself is used and how we use it to test regressions?
Sorry for the noise. You're spot on. Converted back to draft. The test is not even using the mock nor the other code 🤦 |
It's using the handlers of the mock at least, but that is about it :) |
The previous tests only exercised cmd/ls-api (a manual testing tool), so a change to the actual RIE production code in cmd/localstack would not have been caught. - Extract SendLogs and SendResult from the inline goroutine into LocalStackAdapter methods, making the API call sites testable - Add cmd/localstack/custom_interop_test.go with 8 contract tests that drive the production types and methods directly: InvokeRequest/LogResponse JSON field names, SendStatus URL routing, SendLogs format, SendResult response-vs-error routing - Remove the two misleading JSON contract tests from cmd/ls-api — they tested a separate struct copy and gave false confidence Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…t mock Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…acOS - Makefile: build-rie (Go cross-compilation), start-mock (native go run), start-rie (Docker; exposes port 9563 so host mock can reach RIE /invoke) - handler.py: minimal Python Lambda function used by start-rie - README: replace raw Linux binary instructions with make commands, add prerequisites section and ARCH=arm64 note Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
xraydaemon.go calls GetEnvOrDie("AWS_REGION") unconditionally at startup
regardless of whether X-Ray telemetry is enabled, causing an immediate panic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… startup log - /test and /fail endpoints now log errors instead of exiting on connection failure, consistent with the same fix applied earlier to statusHandler - Log the listen port on startup for easier debugging - Update README-LOCALSTACK.md: remove "likely outdated" label, link to ls-api README Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ation
Adds a smoke-test.sh script and Makefile target that build the RIE and
ls-api mock, run both, verify a successful and a failing Lambda invocation
against the mock endpoint, then clean up. Used in the new ls-smoke-tests
CI workflow (.github/workflows/ls-smoke-tests.yml).
Also renames the /test trigger endpoint to /success, adds structured
logging to invokeResponseHandler/invokeErrorHandler for reliable grepping,
updates handler.py to raise on {"fail": ...} so the error path is
exercised, and builds both binaries into bin/.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…bug output 172.17.0.1 is unreachable from Docker containers on macOS (Docker Desktop runs inside a VM). Switch to host.docker.internal on Darwin and keep 172.17.0.1 for Linux where it is the standard bridge gateway. On timeout, also print RIE container status and logs alongside the ls-api log so failures are easier to diagnose. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the uname conditional (host.docker.internal vs 172.17.0.1) with --add-host=host.docker.internal:host-gateway, which Docker resolves to the correct gateway IP on both Linux and macOS. Single address, no branching. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… output Two fixes: 1. Add --platform linux/amd64 to docker run so Docker always pulls the x86_64 image. On Apple Silicon, Docker otherwise selects the arm64 image, causing an exec format error when mounting the linux/amd64 RIE binary -- the container exits immediately without sending any callbacks. 2. Drop --rm and do explicit docker rm in cleanup instead. With --rm the container and its logs are deleted on exit before wait_for_log can retrieve them, making failures invisible. Without --rm, docker logs and docker inspect work correctly even after the container has stopped. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r flags Two changes: 1. Add AWS_LAMBDA_FUNCTION_VERSION (and --platform/--add-host) to a shared RIE_DOCKER_OPTS variable in the Makefile. smoke-test.sh was missing this env var, causing a startup panic in the RIE. RIE_DOCKER_OPTS uses deferred assignment (=) so $$LATEST survives to recipe expansion time. 2. Replace the duplicated docker_opts array in smoke-test.sh with a call to the new start-rie-detached Makefile target. Both start-rie and start-rie-detached now use the same RIE_DOCKER_OPTS, so env vars stay in sync automatically. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| } | ||
|
|
||
| // SendLogs posts the captured invocation logs to LocalStack. | ||
| func (l *LocalStackAdapter) SendLogs(invokeId string, logs LogResponse) error { |
There was a problem hiding this comment.
These are the main refactoring changes to LS RIE production code. Extracting SendLogs and SendResult is needed for testing.
Summary
The LocalStack ↔ RIE API contract (JSON field names, HTTP status codes, endpoint paths) is unversioned. A silent rename or status code change is a breaking change with no safe rollback, especially in Kubernetes deployments where LocalStack and the Lambda container images can be at mismatched versions.
This PR pins the contract with tests and adds a CI workflow that catches integration regressions before they reach the LocalStack main pipeline.
Changes
cmd/localstack/custom_interop_test.go— contract tests (moved to production code)Unit tests that pin the exact field names and routing logic of the LS↔RIE API:
InvokeRequest(invoke-id,invoked-function-arn,payload,trace-id)LogResponse(logs)SendStatusroutes toPOST /status/{runtime_id}/readyand/errorSendLogsmarshals with the"logs"keySendResultroutes to/responseon success and/erroron failure (both explicit flag and body inspection)cmd/ls-api/— mock aligned withexecutor_endpoint.pyand automatedThe mock was drifting from the real LocalStack API. Fixed:
202 Accepted(was200 OK)InvokeRequestgains the missinginvoked-function-arnandtrace-idfieldsinvokeErrorHandlerandinvokeLogsHandlernow read and log request bodieslog.Fatalin the status goroutine downgraded tolog.Error/testtrigger endpoint renamed to/successfor clarityhandler.pyraises on{"fail": ...}so the error path actually exercisesinvokeErrorHandlerNew
smoke-test.sh+ Makefile targets (start-rie-detached,smoke-test) run a full end-to-end check locally and in CI: build RIE → start ls-api mock → verify a success invocation (auto-triggered on ready) → verify an error invocation → clean up..github/workflows/ls-smoke-tests.yml— new CI workflowRuns on every push and PR to the
localstackbranch. Three steps: checkout, set up Go,make smoke-test.Tests
I manually tested the
ls-apiusing the make targets and confirm it works as expected.The
invoke-id→request-idrename was used to validate test effectiveness:TestInvokeRequestContract(unit)""make smoke-test(e2e)The unit tests in
custom_interop_test.goare the effective guard for contract regressions. The smoke test complements them by catching startup failures, binary crashes, and end-to-end invocation flow breakage.