8000 fix validator and model check during invocation by bentsku · Pull Request #7846 · localstack/localstack · GitHub
[go: up one dir, main page]

Skip to content

fix validator and model check during invocation #7846

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 8 commits into from
Mar 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add test
  • Loading branch information
bentsku committed Mar 16, 2023
commit 90b9420c4f82dae6fe47737c98719ba4b77006d0
8 changes: 5 additions & 3 deletions localstack/services/apigateway/invocations.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,13 @@ def is_request_valid(self) -> bool:
return True

def validate_body(self, resource):
# we need a model to validate the body
# if there's no model to validate the body, use the Empty model
# https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_aws-apigateway.EmptyModel.html
if "requestModels" not in resource or not resource["requestModels"]:
return False
schema_name = "Empty"
else:
schema_name = resource["requestModels"].get(APPLICATION_JSON)

schema_name = resource["requestModels"].get(APPLICATION_JSON)
try:
model = self.apigateway_client.get_model(
restApiId=self.context.api_id,
Expand Down
167 changes: 167 additions & 0 deletions tests/integration/apigateway/test_apigateway_common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import json

import pytest
import requests

from localstack.services.awslambda.lambda_utils import LAMBDA_RUNTIME_PYTHON39
from localstack.utils.aws.arns import parse_arn
from localstack.utils.strings import short_uid
from tests.integration.apigateway_fixtures import api_invoke_url
from tests.integration.awslambda.test_lambda import TEST_LAMBDA_AWS_PROXY


class TestApiGatewayCommon:
"""
In this class we won't test individual CRUD API calls but how those will affect the integrations and
requests/responses from the API.
"""

@pytest.mark.aws_validated
def test_api_gateway_request_validator(
self,
apigateway_client,
create_lambda_function,
crea 8000 te_rest_apigw,
lambda_client,
):
# TODO: create fixture which will provide basic integrations where we can test behaviour
# see once we have more cases how we can regroup functionality into one or several fixtures
# example: create a basic echo lambda + integrations + deploy stage

fn_name = f"test-{short_uid()}"
create_lambda_function(
func_name=fn_name,
handler_file=TEST_LAMBDA_AWS_PROXY,
runtime=LAMBDA_RUNTIME_PYTHON39,
)
lambda_arn = lambda_client.get_function(FunctionName=fn_name)["Configuration"][
"FunctionArn"
]
parsed_arn = parse_arn(lambda_arn)
region = parsed_arn["region"]
account_id = parsed_arn["account"]

api_id, _, root = create_rest_apigw(name="aws lambda api")

resource_1 = apigateway_client.create_resource(
restApiId=api_id, parentId=root, pathPart="test"
)["id"]

resource_id = apigateway_client.create_resource(
restApiId=api_id, parentId=resource_1, pathPart="{test}"
)["id"]

validator_id = apigateway_client.create_request_validator(
restApiId=api_id,
name="test-validator",
validateRequestParameters=True,
validateRequestBody=True,
)["id"]

apigateway_client.put_method(
restApiId=api_id,
resourceId=resource_id,
httpMethod="POST",
authorizationType="NONE",
requestValidatorId=validator_id,
requestParameters={"method.request.path.test": True},
)

apigateway_client.put_integration(
Copy link
Member

Choose a reason for hiding this comment

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

nit: for simple integrations, we could try leveraging and extending the create_rest_api_with_integration fixture. It currently only supports dynamodb and kinesis integrations, but Lambda would be a great addition.. 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense! I need to take a look at it, and how we can customise it. I guess we can always create simple integrations and use update_* afterwards, for example the requestParameters in that case. There are so many parameters possible.
I'll take a good look a those once I'm starting with integrations. This PR was a bit outside my "normal" work for now, as I was fixing the change in logic now that we are raising exceptions for non-existing resources. 😄

restApiId=api_id,
resourceId=resource_id,
httpMethod="POST",
integrationHttpMethod="POST",
type="AWS_PROXY",
uri=f"arn:aws:apigateway:{region}:lambda:path//2015-03-31/functions/"
f"{lambda_arn}/invocations",
)
apigateway_client.put_method_response(
restApiId=api_id,
resourceId=resource_id,
httpMethod="POST",
statusCode="200",
)
apigateway_client.put_integration_response(
restApiId=api_id,
resourceId=resource_id,
httpMethod="POST",
statusCode="200",
)

deployment_id = apigateway_client.create_deployment(restApiId=api_id)["id"]

stage = apigateway_client.create_stage(
restApiId=api_id, stageName="local", deploymentId=deployment_id
)["stageName"]

source_arn = f"arn:aws:execute-api:{region}:{account_id}:{api_id}/*/*/test/*"

lambda_client.add_permission(
FunctionName=lambda_arn,
StatementId=str(short_uid()),
Action="lambda:InvokeFunction",
Principal="apigateway.amazonaws.com",
SourceArn=source_arn,
)

url = api_invoke_url(api_id, stage=stage, path="/test/value")
response = requests.post(url, json={"test": "test"})
assert response.ok
assert json.loads(response.json()["body"]) == {"test": "test"}

apigateway_client.update_method(
restApiId=api_id,
resourceId=resource_id,
httpMethod="POST",
patchOperations=[
{
"op": "add",
"path": "/requestParameters/method.request.path.issuer",
"value": "true",
},
{
"op": "remove",
"path": "/requestParameters/method.request.path.test",
"value": "true",
},
],
)

response = requests.post(url, json={"test": "test"})
assert response.ok
assert json.loads(response.json()["body"]) == {"test": "test"}

# create Model schema to validate body
apigateway_client.create_model(
restApiId=api_id,
name="testSchema",
contentType="application/json",
schema=json.dumps({}),
)
# then attach the schema to the method
apigateway_client.update_method(
restApiId=api_id,
resourceId=resource_id,
httpMethod="POST",
patchOperations=[
{"op": "add", "path": "/requestModels/application~1json", "value": "testSchema"},
],
)
# the validator should then check against this schema

apigateway_client.update_method(
restApiId=api_id,
resourceId=resource_id,
httpMethod="POST",
patchOperations=[
{
" 4AAB op": "replace",
"path": "/requestValidatorId",
"value": "",
},
],
)
response = requests.post(url, json={"test": "test"})
assert response.ok
assert json.loads(response.json()["body"]) == {"test": "test"}
0