diff --git a/.github/workflows/integ-tests.yml b/.github/workflows/integ-tests.yml new file mode 100644 index 0000000..cb2f9dc --- /dev/null +++ b/.github/workflows/integ-tests.yml @@ -0,0 +1,21 @@ +name: Run Integration Tests + +on: + pull_request: + branches: + - develop + +jobs: + integ-tests: + runs-on: ubuntu-latest + environment: + name: prod + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: allows us to build arm64 images + run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes + - name: run integration tests + run: make integ-tests-with-docker \ No newline at end of file diff --git a/Makefile b/Makefile index 80ccb89..1916dae 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ compile-lambda-linux-all: make ARCH=old compile-lambda-linux compile-with-docker: - docker run --env GOPROXY=direct -v $(shell pwd):/LambdaRuntimeLocal -w /LambdaRuntimeLocal golang:1.20 make ARCH=${ARCH} compile-lambda-linux + docker run --env GOPROXY=direct -v $(shell pwd):/LambdaRuntimeLocal -w /LambdaRuntimeLocal golang:1.21 make ARCH=${ARCH} compile-lambda-linux compile-lambda-linux: CGO_ENABLED=0 GOOS=linux GOARCH=${GO_ARCH_${ARCH}} go build -buildvcs=false -ldflags "${RELEASE_BUILD_LINKER_FLAGS}" -o ${DESTINATION_${ARCH}} ./cmd/aws-lambda-rie diff --git a/go.mod b/go.mod index 990a7dd..d48dc60 100644 --- a/go.mod +++ b/go.mod @@ -1,22 +1,21 @@ module go.amzn.com -go 1.20 +go 1.21 require ( - github.com/aws/aws-lambda-go v1.41.0 - github.com/go-chi/chi v4.1.2+incompatible - github.com/google/uuid v1.3.0 + github.com/aws/aws-lambda-go v1.46.0 + github.com/go-chi/chi v1.5.5 + github.com/google/uuid v1.6.0 github.com/jessevdk/go-flags v1.5.0 github.com/sirupsen/logrus v1.9.3 - github.com/stretchr/testify v1.8.4 - golang.org/x/sync v0.2.0 + github.com/stretchr/testify v1.9.0 + golang.org/x/sync v0.6.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/objx v0.5.0 // indirect - golang.org/x/net v0.18.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect golang.org/x/sys v0.14.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 0ea11d6..8974775 100644 --- a/go.sum +++ b/go.sum @@ -1,12 +1,12 @@ -github.com/aws/aws-lambda-go v1.41.0 h1:l/5fyVb6Ud9uYd411xdHZzSf2n86TakxzpvIoz7l+3Y= -github.com/aws/aws-lambda-go v1.41.0/go.mod h1:jwFe2KmMsHmffA1X2R09hH6lFzJQxzI8qK17ewzbQMM= +github.com/aws/aws-lambda-go v1.46.0 h1:UWVnvh2h2gecOlFhHQfIPQcD8pL/f7pVCutmFl+oXU8= +github.com/aws/aws-lambda-go v1.46.0/go.mod h1:dpMpZgvWx5vuQJfBt0zqBha60q7Dd7RfgJv23DymV8A= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= -github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/go-chi/chi v1.5.5 h1:vOB/HbEMt9QqBqErz07QehcOKHaWFtuj87tTDVz2qXE= +github.com/go-chi/chi v1.5.5/go.mod h1:C9JqLr3tIYjDOZpzn+BCuxY8z8vmca43EeMgyZt7irw= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -14,23 +14,17 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/test/integration/local_lambda/test_end_to_end.py b/test/integration/local_lambda/test_end_to_end.py index c5c3e63..fd7f735 100644 --- a/test/integration/local_lambda/test_end_to_end.py +++ b/test/integration/local_lambda/test_end_to_end.py @@ -72,20 +72,34 @@ def tagged_name(self, name, architecture): def get_tag(self, architecture): return "" if architecture == "" else str(f"-{architecture}") + + def run_command(self, cmd): + Popen(cmd.split(" ")).communicate() + + def sleep_1s(self): + time.sleep(SLEEP_TIME) + + def invoke_function(self, port): + return requests.post( + f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={} + ) + + def create_container_and_invoke_function(self, cmd, port): + self.run_command(cmd) + + # sleep 1s to give enough time for the endpoint to be up to curl + self.sleep_1s() + + return self.invoke_function(port) @parameterized.expand([("x86_64", "8000"), ("arm64", "9000"), ("", "9050")]) def test_env_var_with_equal_sign(self, arch, port): image, rie, image_name = self.tagged_name("envvarcheck", arch) cmd = f"docker run --name {image} -d -v {self.path_to_binary}:/local-lambda-runtime-server -p {port}:8080 --entrypoint /local-lambda-runtime-server/{rie} {image_name} {DEFAULT_1P_ENTRYPOINT} main.check_env_var_handler" - Popen(cmd.split(" ")).communicate() - - # sleep 1s to give enough time for the endpoint to be up to curl - time.sleep(SLEEP_TIME) - - r = requests.post( - f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={} - ) + + r = self.create_container_and_invoke_function(cmd, port) + self.assertEqual(b'"4=4"', r.content) @parameterized.expand([("x86_64", "8001"), ("arm64", "9001"), ("", "9051")]) @@ -94,20 +108,13 @@ def test_two_invokes(self, arch, port): cmd = f"docker run --name {image} -d -v {self.path_to_binary}:/local-lambda-runtime-server -p {port}:8080 --entrypoint /local-lambda-runtime-server/{rie} {image_name} {DEFAULT_1P_ENTRYPOINT} main.success_handler" - Popen(cmd.split(" ")).communicate() - - # sleep 1s to give enough time for the endpoint to be up to curl - time.sleep(SLEEP_TIME) - - r = requests.post( - f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={} - ) + r = self.create_container_and_invoke_function(cmd, port) + self.assertEqual(b'"My lambda ran succesfully"', r.content) # Make sure we can invoke the function twice - r = requests.post( - f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={} - ) + r = self.invoke_function(port) + self.assertEqual(b'"My lambda ran succesfully"', r.content) @parameterized.expand([("x86_64", "8002"), ("arm64", "9002"), ("", "9052")]) @@ -116,14 +123,8 @@ def test_lambda_function_arn_exists(self, arch, port): cmd = f"docker run --name {image} -d -v {self.path_to_binary}:/local-lambda-runtime-server -p {port}:8080 --entrypoint /local-lambda-runtime-server/{rie} {image_name} {DEFAULT_1P_ENTRYPOINT} main.assert_lambda_arn_in_context" - Popen(cmd.split(" ")).communicate() - - # sleep 1s to give enough time for the endpoint to be up to curl - time.sleep(SLEEP_TIME) - - r = requests.post( - f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={} - ) + r = self.create_container_and_invoke_function(cmd, port) + self.assertEqual(b'"My lambda ran succesfully"', r.content) @parameterized.expand([("x86_64", "8003"), ("arm64", "9003"), ("", "9053")]) @@ -131,14 +132,9 @@ def test_lambda_function_arn_exists_with_defining_custom_name(self, arch, port): image, rie, image_name = self.tagged_name("customname", arch) cmd = f"docker run --name {image} --env AWS_LAMBDA_FUNCTION_NAME=MyCoolName -d -v {self.path_to_binary}:/local-lambda-runtime-server -p {port}:8080 --entrypoint /local-lambda-runtime-server/{rie} {image_name} {DEFAULT_1P_ENTRYPOINT} main.assert_lambda_arn_in_context" - Popen(cmd.split(" ")).communicate() - - # sleep 1s to give enough time for the endpoint to be up to curl - time.sleep(SLEEP_TIME) - - r = requests.post( - f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={} - ) + + r = self.create_container_and_invoke_function(cmd, port) + self.assertEqual(b'"My lambda ran succesfully"', r.content) @parameterized.expand([("x86_64", "8004"), ("arm64", "9004"), ("", "9054")]) @@ -147,14 +143,8 @@ def test_timeout_invoke(self, arch, port): cmd = f"docker run --name {image} -d --env AWS_LAMBDA_FUNCTION_TIMEOUT=1 -v {self.path_to_binary}:/local-lambda-runtime-server -p {port}:8080 --entrypoint /local-lambda-runtime-server/{rie} {image_name} {DEFAULT_1P_ENTRYPOINT} main.sleep_handler" - Popen(cmd.split(" ")).communicate() - - # sleep 1s to give enough time for the endpoint to be up to curl - time.sleep(SLEEP_TIME) - - r = requests.post( - f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={} - ) + r = self.create_container_and_invoke_function(cmd, port) + self.assertEqual(b"Task timed out after 1.00 seconds", r.content) @parameterized.expand([("x86_64", "8005"), ("arm64", "9005"), ("", "9055")]) @@ -163,14 +153,8 @@ def test_exception_returned(self, arch, port): cmd = f"docker run --name {image} -d -v {self.path_to_binary}:/local-lambda-runtime-server -p {port}:8080 --entrypoint /local-lambda-runtime-server/{rie} {image_name} {DEFAULT_1P_ENTRYPOINT} main.exception_handler" - Popen(cmd.split(" ")).communicate() - - # sleep 1s to give enough time for the endpoint to be up to curl - time.sleep(SLEEP_TIME) - - r = requests.post( - f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={} - ) + r = self.create_container_and_invoke_function(cmd, port) + self.assertEqual( b'{"errorMessage": "Raising an exception", "errorType": "Exception", "stackTrace": [" File \\"/var/task/main.py\\", line 13, in exception_handler\\n raise Exception(\\"Raising an exception\\")\\n"]}', r.content, @@ -182,15 +166,8 @@ def test_context_get_remaining_time_in_three_seconds(self, arch, port): cmd = f"docker run --name {image} -d --env AWS_LAMBDA_FUNCTION_TIMEOUT=3 -v {self.path_to_binary}:/local-lambda-runtime-server -p {port}:8080 --entrypoint /local-lambda-runtime-server/{rie} {image_name} {DEFAULT_1P_ENTRYPOINT} main.check_remaining_time_handler" - Popen(cmd.split(' ')).communicate() - - # sleep 1s to give enough time for the endpoint to be up to curl - time.sleep(SLEEP_TIME) - - r = requests.post( - f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={} - ) - + r = self.create_container_and_invoke_function(cmd, port) + # Execution time is not decided, 1.0s ~ 3.0s is a good estimation self.assertLess(int(r.content), 3000) self.assertGreater(int(r.content), 1000) @@ -201,15 +178,8 @@ def test_context_get_remaining_time_in_ten_seconds(self, arch, port): cmd = f"docker run --name {image} -d --env AWS_LAMBDA_FUNCTION_TIMEOUT=10 -v {self.path_to_binary}:/local-lambda-runtime-server -p {port}:8080 --entrypoint /local-lambda-runtime-server/{rie} {image_name} {DEFAULT_1P_ENTRYPOINT} main.check_remaining_time_handler" - Popen(cmd.split(' ')).communicate() - - # sleep 1s to give enough time for the endpoint to be up to curl - time.sleep(SLEEP_TIME) - - r = requests.post( - f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={} - ) - + r = self.create_container_and_invoke_function(cmd, port) + # Execution time is not decided, 8.0s ~ 10.0s is a good estimation self.assertLess(int(r.content), 10000) self.assertGreater(int(r.content), 8000) @@ -220,14 +190,7 @@ def test_context_get_remaining_time_in_default_deadline(self, arch, port): cmd = f"docker run --name {image} -d -v {self.path_to_binary}:/local-lambda-runtime-server -p {port}:8080 --entrypoint /local-lambda-runtime-server/{rie} {image_name} {DEFAULT_1P_ENTRYPOINT} main.check_remaining_time_handler" - Popen(cmd.split(' ')).communicate() - - # sleep 1s to give enough time for the endpoint to be up to curl - time.sleep(SLEEP_TIME) - - r = requests.post( - f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={} - ) + r = self.create_container_and_invoke_function(cmd, port) # Executation time is not decided, 298.0s ~ 300.0s is a good estimation self.assertLess(int(r.content), 300000) @@ -239,14 +202,8 @@ def test_invoke_with_pre_runtime_api_runtime(self, arch, port): cmd = f"docker run --name {image} -d -v {self.path_to_binary}:/local-lambda-runtime-server -p {port}:8080 --entrypoint /local-lambda-runtime-server/{rie} {image_name} {DEFAULT_1P_ENTRYPOINT} main.success_handler" - Popen(cmd.split(" ")).communicate() - - # sleep 1s to give enough time for the endpoint to be up to curl - time.sleep(SLEEP_TIME) - - r = requests.post( - f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={} - ) + r = self.create_container_and_invoke_function(cmd, port) + self.assertEqual(b'"My lambda ran succesfully"', r.content) @parameterized.expand([("x86_64", "8010"), ("arm64", "9010"), ("", "9060")]) @@ -255,14 +212,8 @@ def test_function_name_is_overriden(self, arch, port): cmd = f"docker run --name {image} -d --env AWS_LAMBDA_FUNCTION_NAME=MyCoolName -v {self.path_to_binary}:/local-lambda-runtime-server -p {port}:8080 --entrypoint /local-lambda-runtime-server/{rie} {image_name} {DEFAULT_1P_ENTRYPOINT} main.assert_env_var_is_overwritten" - Popen(cmd.split(" ")).communicate() - - # sleep 1s to give enough time for the endpoint to be up to curl - time.sleep(SLEEP_TIME) - - r = requests.post( - f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={} - ) + r = self.create_container_and_invoke_function(cmd, port) + self.assertEqual(b'"My lambda ran succesfully"', r.content) @parameterized.expand([("x86_64", "8011"), ("arm64", "9011"), ("", "9061")]) @@ -272,14 +223,8 @@ def test_port_override(self, arch, port): # Use port 8081 inside the container instead of 8080 cmd = f"docker run --name {image} -d -v {self.path_to_binary}:/local-lambda-runtime-server -p {port}:8081 --entrypoint /local-lambda-runtime-server/{rie} {image_name} {DEFAULT_1P_ENTRYPOINT} main.success_handler --runtime-interface-emulator-address 0.0.0.0:8081" - Popen(cmd.split(" ")).communicate() - - # sleep 1s to give enough time for the endpoint to be up to curl - time.sleep(SLEEP_TIME) - - r = requests.post( - f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={} - ) + r = self.create_container_and_invoke_function(cmd, port) + self.assertEqual(b'"My lambda ran succesfully"', r.content)