Skip to content

APIGW: migrate TestInvokeMethod to NextGen #12514

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 11, 2025
Merged

APIGW: migrate TestInvokeMethod to NextGen #12514

merged 5 commits into from
Apr 11, 2025

Conversation

bentsku
Copy link
Contributor

@bentsku bentsku commented Apr 10, 2025

Motivation

The TestInvokeMethod operation was still relying on the legacy invocation logic of API Gateway. This PR migrates it to not rely on old code anymore and use the new handler chain, create one and invoke it.

I've also improved the test, it is now fully transformed and can run against AWS with snapshot validation enabled.

Also took the opportunity to remove some old "fixtures" doing nothing.

Changes

  • implement new TestInvokeOperation for the NextGen provider
  • create new file keeping all of this together (might be better organized to be honest... but it's also not very important at the moment? should it have better encapsulation?)
  • adapt the existing test to allow better parity
  • clean up some old APIGW "fixtures"

@bentsku bentsku added aws:apigateway Amazon API Gateway semver: patch Non-breaking changes which can be included in patch releases labels Apr 10, 2025
@bentsku bentsku added this to the 4.4 milestone Apr 10, 2025
@bentsku bentsku self-assigned this Apr 10, 2025
Copy link

github-actions bot commented Apr 10, 2025

LocalStack Community integration with Pro

    2 files  ±    0      2 suites  ±0   29m 17s ⏱️ - 1h 23m 39s
1 102 tests  - 3 248  1 037 ✅  - 2 946  65 💤  - 302  0 ❌ ±0 
1 104 runs   - 3 248  1 037 ✅  - 2 946  67 💤  - 302  0 ❌ ±0 

Results for commit 5560ff0. ± Comparison against base commit 073eab9.

This pull request removes 3248 tests.
tests.aws.scenario.bookstore.test_bookstore.TestBookstoreApplication ‑ test_lambda_dynamodb
tests.aws.scenario.bookstore.test_bookstore.TestBookstoreApplication ‑ test_opensearch_crud
tests.aws.scenario.bookstore.test_bookstore.TestBookstoreApplication ‑ test_search_books
tests.aws.scenario.bookstore.test_bookstore.TestBookstoreApplication ‑ test_setup
tests.aws.scenario.kinesis_firehose.test_kinesis_firehose.TestKinesisFirehoseScenario ‑ test_kinesis_firehose_s3
tests.aws.scenario.lambda_destination.test_lambda_destination_scenario.TestLambdaDestinationScenario ‑ test_destination_sns
tests.aws.scenario.lambda_destination.test_lambda_destination_scenario.TestLambdaDestinationScenario ‑ test_infra
tests.aws.scenario.loan_broker.test_loan_broker.TestLoanBrokerScenario ‑ test_prefill_dynamodb_table
tests.aws.scenario.loan_broker.test_loan_broker.TestLoanBrokerScenario ‑ test_stepfunctions_input_recipient_list[step_function_input0-SUCCEEDED]
tests.aws.scenario.loan_broker.test_loan_broker.TestLoanBrokerScenario ‑ test_stepfunctions_input_recipient_list[step_function_input1-SUCCEEDED]
…

♻️ This comment has been updated with latest results.

@bentsku bentsku force-pushed the apigw-test-invoke branch from 836bfdb to 6421bf2 Compare April 10, 2025 22:56
@bentsku bentsku marked this pull request as ready for review April 11, 2025 08:45
@bentsku bentsku requested a review from cloutierMat as a code owner April 11, 2025 08:45
Copy link
Contributor

@cloutierMat cloutierMat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super impressive work! I really like the solution you came up with to facilitate snapshotting the logs.

I love how we can reuse the handler chain for this! 👍

Comment on lines +56 to +57
# TODO: funny enough, in AWS for the `endpoint_response_headers` in AWS_PROXY, they log the response headers from
# lambda HTTP Invoke call even though we use the headers from the lambda response itself
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😢 Never stop being surprised!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is kinda weird 😄 somewhat leaking implementation details

Comment on lines +91 to +103
def create_test_chain() -> HandlerChain[RestApiInvocationContext]:
return HandlerChain(
request_handlers=[
handlers.method_request_handler,
handlers.integration_request_handler,
handlers.integration_handler,
handlers.integration_response_handler,
handlers.method_response_handler,
],
exception_handlers=[
handlers.gateway_exception_handler,
],
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So clean! This really makes that work we did shine bright!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And it was so nice to actually be able to only pick a few handlers that we needed, skipping the parsing and routing of the request 👌

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean you could add them all, and have a if is_test_invoke in them to produce a different result! 🤣

Comment on lines 167 to 170
def _fix_headers(headers: Headers) -> Headers:
headers.remove("Content-Length")

return headers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this feels a bit out of place in the middle of the file 🫤 Maybe we could move it up with the _dump_headers util?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah agreed, it did multiple things before like adding the trace-id, but it looked like MOCK wasn't adding it... so I've just added the removal of Content-Length straight in the run method now. If we ever need to add more, we'll move it to its own function?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the cleanup! 🙏

Comment on lines +1344 to +1345
def _transform_log(_log: str) -> dict[str, str]:
return {f"line{index:02d}": line for index, line in enumerate(_log.split("\n"))}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice attention! It will be much easier to see the error when it arises! 🙏

Copy link
Contributor Author

@bentsku bentsku left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the review! I've just realized that I hadn't re-ran the test against AWS after fixing some regex shenanigans, I'll fix it and merge. This was a fun one 😄

Comment on lines +56 to +57
# TODO: funny enough, in AWS for the `endpoint_response_headers` in AWS_PROXY, they log the response headers from
# lambda HTTP Invoke call even though we use the headers from the lambda response itself
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is kinda weird 😄 somewhat leaking implementation details

Comment on lines +91 to +103
def create_test_chain() -> HandlerChain[RestApiInvocationContext]:
return HandlerChain(
request_handlers=[
handlers.method_request_handler,
handlers.integration_request_handler,
handlers.integration_handler,
handlers.integration_response_handler,
handlers.method_response_handler,
],
exception_handlers=[
handlers.gateway_exception_handler,
],
)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And it was so nice to actually be able to only pick a few handlers that we needed, skipping the parsing and routing of the request 👌

Comment on lines 167 to 170
def _fix_headers(headers: Headers) -> Headers:
headers.remove("Content-Length")

return headers
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah agreed, it did multiple things before like adding the trace-id, but it looked like MOCK wasn't adding it... so I've just added the removal of Content-Length straight in the run method now. If we ever need to add more, we'll move it to its own function?

@bentsku bentsku merged commit a1eec50 into master Apr 11, 2025
31 checks passed
@bentsku bentsku deleted the apigw-test-invoke branch April 11, 2025 19:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
aws:apigateway Amazon API Gateway semver: patch Non-breaking changes which can be included in patch releases
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants