8000 Refactor API GW tests, assert correct JSON content-type for DDB integration by whummer · Pull Request #7843 · localstack/localstack · GitHub
[go: up one dir, main page]

Skip to content

Refactor API GW tests, assert correct JSON content-type for DDB integration #7843

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 6 commits into from
Mar 16, 2023

Conversation

whummer
Copy link
Member
@whummer whummer commented Mar 13, 2023

Refactor API Gateway tests, assert correct JSON content-type for DynamoDB integration.

Summary of changes:

  • move the remaining API GW tests into the tests/integration/apigateway module
  • move IAM policies required by fixtures in conftest.py into that same file
  • minor change to initialize response in the invocation context (to avoid AttributeError)
  • fix DynamoDB integration to return proper content-type (application/json)
  • extend test_rest_api_to_dynamodb_integration snapshot test to also capture the response headers (to verify that the content-type matches)
  • use echo_http_server fixture instead of making httpbin.org requests (should fix some flaky tests with 504 timeouts) - some TODOs still remaining in the codebase

Side note: As also mentioned in the PR comment below, in a future iteration we should unify the logic/interface of integration response handling. 👍 /cc @calvernaz @bentsku

@whummer whummer temporarily deployed to localstack-ext-tests March 13, 2023 01:41 — with GitHub Actions Inactive
@whummer whummer changed the title [wip] Refactor API GW tests, assert correct JSON content-type [wip] Refactor API GW tests, assert correct JSON content-type for DDB integration Mar 13, 2023
@github-actions
Copy link
github-actions bot commented Mar 13, 2023

LocalStack integration with Pro

       3 files  ±0         3 suites  ±0   1h 41m 45s ⏱️ + 1m 27s
1 801 tests  - 1  1 420 ✔️ +1  381 💤  - 2  0 ±0 
2 527 runs   - 1  1 794 ✔️ +1  733 💤  - 2  0 ±0 

Results for commit ca9f093. ± Comparison against base commit 61b2648.

♻️ This comment has been updated with latest results.

@whummer whummer force-pushed the apigw-dynamodb-responses branch from 67f9dce to 504c7da Compare March 15, 2023 12:58
@whummer whummer temporarily deployed to localstack-ext-tests March 15, 2023 12:58 — with GitHub Actions Inactive
@@ -449,12 +449,14 @@ def invoke(self, invocation_context: ApiInvocationContext):

# apply response templates
response_content = json.dumps(remove_attributes(response, ["ResponseMetadata"]))
response_obj = requests_response(content=response_content)
invocation_context.response = response_obj = requests_response(content=response_content)
Copy link
Member Author
@whummer whummer Mar 15, 2023

Choose a reason for hiding this comment

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

Note: In one of the next refactoring iterations, we should unify the response handling for API GW integrations.

Most of the BackendIntegration implementations are returning a Response from invoke(..) (even though it is not defined in the interface), and some of the implementations also update the invocation_context.response property on the context.

We should think about how we can unify this (either having the response only on the context, or only returning it from invoke), to have a clear interface and make the request processing less ambiguous. 👍

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed, if the integrations are self-contained as they're leaning to im not sure we will have the invocation_context.response anymore because all the work is done, meaning the response from the integration and the response templating is done. Food for thought, I guess

@whummer whummer changed the title [wip] Refactor API GW tests, assert correct JSON content-type for DDB integration Refactor API GW tests, assert correct JSON content-type for DDB integration Mar 15, 2023
@whummer whummer temporarily deployed to localstack-ext-tests March 15, 2023 13:20 — with GitHub Actions Inactive
@whummer whummer temporarily deployed to localstack-ext-tests March 15, 2023 14:25 — with GitHub Actions Inactive
@whummer whummer force-pushed the apigw-dynamodb-responses branch from 9d4b209 to c0fe894 Compare March 15, 2023 14:27
@whummer whummer temporarily deployed to localstack-ext-tests March 15, 2023 14:27 — with GitHub Actions Inactive
@whummer whummer marked this pull request as ready for review March 15, 2023 14:27
@whummer whummer temporarily deployed to localstack-ext-tests March 15, 2023 14:43 — with GitHub Actions Inactive
@whummer whummer temporarily deployed to localstack-ext-tests March 15, 2023 15:11 — with GitHub Actions Inactive
@whummer whummer requested a review from bentsku March 15, 2023 16:14
Copy link
Contributor
@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.

LGTM! Just one question and a comment about using httpbin to validate the tests against AWS. Thanks a lot for this big refactoring and moving files, the structure will be much cleaner, hope we can split it further with time! 🎉

deploy_cfn_template(
template=TEST_TEMPLATE_1,
parameters={"ApiName": api_name, "IntegrationUri": int_uri},
parameters={"ApiName": api_name, "IntegrationUri": f"{echo_http_server}/post"},
Copy link
Contributor

Choose a reason for hiding this comment

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

I like that much better that we're using the http_server fixture for our tests, it will make the tests much less flaky. However, we won't be able to test them anymore against AWS this way, or it would need a bit more setup. Should we leave some comment on how to AWS validate the test, maybe replacing manually the int_uri to the httpbin one?

Copy link
Member Author
@whummer whummer Mar 15, 2023

Choose a reason for hiding this comment

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

Ah, that's a great catch! Not sure how I could have missed that. 😕 You're totally right, we should add a switch that allows both local and remote testing. Let me see - one option would be to make the echo server return the same response as httpbin, or the other option would be to encapsulate the switch in the fixture itself. Will do another iteration to fix that 👍

Copy link
Member Author

Choose a reason for hiding this comment

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

Done - added a echo_http_server_post fixture that can handle POST requests for both, local testing and AWS parity tests.

Comment on lines -457 to +458
invocation_context.response = response
# TODO: set response header based on response templates
headers = {HEADER_CONTENT_TYPE: APPLICATION_JSON}
response = requests_response(response, headers=headers)
Copy link
Contributor

Choose a reason for hiding this comment

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

So, if I understood well, for now, we're only returning JSON, so we're setting the headers. LGTM 👍
But just a question, we now set the response before being rendered in the template to the invocation_context, whereas before we would set it after, is that wanted?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we need it after, once we move all the templating inside the integrations, that's why we put the response inside the invocation_context, but we should agree on this, whatever it is.

Copy link
Member Author

Choose a reason for hiding this comment

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

Great points. In my view, this is exactly a symptom of the current duality of response handling. In future iterations, we'll need the response details at some point of processing the integration requests (e.g., response mapping templates may contain variables like "$context.responseLength") - agree with Cesar what we should agree on one approach and unify.

Slightly updated the PR and removed the context.response assignment to address this point for now 👍

@bentsku
Copy link
Contributor
bentsku commented Mar 15, 2023

Might still need to update the pro tests here:

../localstack/tests/integration/test_apigateway.py
- name: Run Lambda Tests for lambda executor docker-reuse
env:
DEBUG: 1
DNS_ADDRESS: 0
LAMBDA_EXECUTOR: "docker-reuse"
LOCALSTACK_API_KEY: "test"
HOST_TMP_FOLDER: /tmp/localstack
run: |
# Remove the host tmp folder (might contain remnant files with different permissions)
sudo rm -rf ../localstack/.filesystem/var/lib/localstack/tmp
source .venv/bin/activate
python -m pytest --reruns 2 --durations=10 --show-capture=no --junitxml=target/reports/lambda-docker-reuse.xml -o junit_suite_name='lambda-docker-reuse' \
../localstack/tests/integration/awslambda/ \
../localstack/tests/integration/test_integration.py \
../localstack/tests/integration/test_apigateway.py

@thrau thrau removed their request for review March 15, 2023 20:22
Copy link
Contributor
@calvernaz calvernaz left a comment

Choose a reason for hiding this comment

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

LGTM, the separation is helpful and also good thinking around the responses - another PoV on it is apply the response templates on the integration response but leave the HTTP layer outside of the integrations, but would require some sort of data structure that contains the response dictionary, the content type, etc, so we can build an HTTP response after.

@@ -449,12 +449,14 @@ def invoke(self, invocation_context: ApiInvocationContext):

# apply response templates
response_content = json.dumps(remove_attributes(response, ["ResponseMetadata"]))
response_obj = requests_response(content=response_content)
invocation_context.response = response_obj = requests_response(content=response_content)
Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed, if the integrations are self-contained as they're leaning to im not sure we will have the invocation_context.response anymore because all the work is done, meaning the response from the integration and the response templating is done. Food for thought, I guess

Comment on lines -457 to +458
invocation_context.response = response
# TODO: set response header based on response templates
headers = {HEADER_CONTENT_TYPE: APPLICATION_JSON}
response = requests_response(response, headers=headers)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we need it after, once we move all the templating inside the integrations, that's why we put the response inside the invocation_context, but we should agree on this, whatever it is.

@whummer whummer temporarily deployed to localstack-ext-tests March 15, 2023 21:40 — with GitHub Actions Inactive
@whummer whummer temporarily deployed to localstack-ext-tests March 15, 2023 23:05 — with GitHub Actions Inactive
@coveralls
Copy link

Coverage Status

Changes Unknown when pulling ca9f093 on apigw-dynamodb-responses into ** on master**.

@whummer whummer merged commit 2e24a96 into master Mar 16, 2023
@whummer whummer deleted the apigw-dynamodb-responses branch March 16, 2023 09:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
0