Skip to content

Commit 2a1a2fe

Browse files
committed
refactor test cases
1 parent 4c2c20d commit 2a1a2fe

File tree

3 files changed

+159
-127
lines changed

3 files changed

+159
-127
lines changed

Makefile

+26-3
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,32 @@ integ-tests-and-compile: tests
3939
integ-tests-with-docker: tests-with-docker
4040
make compile-with-docker-all
4141
make integ-tests
42-
43-
integ-tests:
42+
43+
prep-python:
4444
python3 -m venv .venv
4545
.venv/bin/pip install --upgrade pip
4646
.venv/bin/pip install requests parameterized
47-
.venv/bin/python3 test/integration/local_lambda/test_end_to_end.py
47+
48+
integ-tests:
49+
make prep-python
50+
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
51+
TEST_ARCH=x86_64 TEST_PORT=8002 .venv/bin/python3 test/integration/local_lambda/test_end_to_end.py
52+
TEST_ARCH=arm64 TEST_PORT=9002 .venv/bin/python3 test/integration/local_lambda/test_end_to_end.py
53+
TEST_ARCH="" TEST_PORT=9052 .venv/bin/python3 test/integration/local_lambda/test_end_to_end.py
54+
55+
integ-tests-with-docker-x86-64:
56+
make ARCH=x86_64 compile-with-docker
57+
make prep-python
58+
TEST_ARCH=x86_64 TEST_PORT=8002 .venv/bin/python3 test/integration/local_lambda/test_end_to_end.py
59+
60+
integ-tests-with-docker-arm64:
61+
make ARCH=arm64 compile-with-docker
62+
make prep-python
63+
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
64+
TEST_ARCH="arm64" TEST_PORT=9002 .venv/bin/python3 test/integration/local_lambda/test_end_to_end.py
65+
66+
integ-tests-with-docker-old:
67+
make ARCH=old compile-with-docker
68+
make prep-python
69+
TEST_ARCH="" TEST_PORT=9052 .venv/bin/python3 test/integration/local_lambda/test_end_to_end.py
70+

test/integration/local_lambda/test_end_to_end.py

+131-123
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,20 @@
55
from unittest import TestCase, main
66
from pathlib import Path
77
import time
8-
8+
import os
99
import requests
10+
from contextlib import contextmanager
1011
from parameterized import parameterized
1112

1213
SLEEP_TIME = 2
1314
DEFAULT_1P_ENTRYPOINT = "/lambda-entrypoint.sh"
1415
ARCHS = ["x86_64", "arm64", ""]
1516

1617

18+
1719
class TestEndToEnd(TestCase):
20+
ARCH = os.environ.get('TEST_ARCH', "")
21+
PORT = os.environ.get('TEST_PORT', 8002)
1822
@classmethod
1923
def setUpClass(cls):
2024
testdata_path = Path(__file__).resolve().parents[1].joinpath("testdata")
@@ -23,48 +27,30 @@ def setUpClass(cls):
2327
cls.path_to_binary = Path().resolve().joinpath("bin")
2428

2529
# build image
26-
for arch in ARCHS:
27-
image_name = cls.image_name if arch == "" else f"{cls.image_name}-{arch}"
28-
architecture = arch if arch == "arm64" else "amd64"
29-
build_cmd = [
30-
"docker",
31-
"build",
32-
"--platform",
33-
f"linux/{architecture}",
34-
"-t",
35-
image_name,
36-
"-f",
37-
str(dockerfile_path),
38-
str(testdata_path),
39-
]
40-
Popen(build_cmd).communicate()
30+
image_name = cls.image_name if cls.ARCH == "" else f"{cls.image_name}-{cls.ARCH}"
31+
architecture = cls.ARCH if cls.ARCH == "arm64" else "amd64"
32+
docker_arch = cls.ARCH if cls.ARCH == "arm64" else "x86_64"
33+
34+
build_cmd = [
35+
"docker",
36+
"build",
37+
"--platform",
38+
f"linux/{architecture}",
39+
"-t",
40+
image_name,
41+
"-f",
42+
str(dockerfile_path),
43+
str(testdata_path),
44+
"--build-arg",
45+
f"IMAGE_ARCH={docker_arch}",
46+
]
47+
print (build_cmd)
48+
Popen(build_cmd).communicate()
4149

4250
@classmethod
4351
def tearDownClass(cls):
44-
images_to_delete = [
45-
"envvarcheck",
46-
"twoinvokes",
47-
"arnexists",
48-
"customname",
49-
"timeout",
50-
"exception",
51-
"remaining_time_in_three_seconds",
52-
"remaining_time_in_ten_seconds",
53-
"remaining_time_in_default_deadline",
54-
"pre-runtime-api",
55-
"assert-overwritten",
56-
"port_override"
57-
]
58-
59-
for image in images_to_delete:
60-
for arch in ARCHS:
61-
arch_tag = "" if arch == "" else f"-{arch}"
62-
cmd = f"docker rm -f {image}{arch_tag}"
63-
Popen(cmd.split(" ")).communicate()
64-
65-
for arch in ARCHS:
66-
arch_tag = "" if arch == "" else f"-{arch}"
67-
Popen(f"docker rmi {cls.image_name}{arch_tag}".split(" ")).communicate()
52+
arch_tag = "" if cls.ARCH == "" else f"-{cls.ARCH}"
53+
Popen(f"docker rmi {cls.image_name}{arch_tag}".split(" ")).communicate()
6854

6955
def tagged_name(self, name, architecture):
7056
tag = self.get_tag(architecture)
@@ -84,148 +70,170 @@ def invoke_function(self, port):
8470
f"http://localhost:{port}/2015-03-31/functions/function/invocations", json={}
8571
)
8672

87-
def create_container_and_invoke_function(self, cmd, port):
88-
self.run_command(cmd)
89-
90-
# sleep 1s to give enough time for the endpoint to be up to curl
91-
self.sleep_1s()
92-
93-
return self.invoke_function(port)
94-
95-
@parameterized.expand([("x86_64", "8000"), ("arm64", "9000"), ("", "9050")])
96-
def test_env_var_with_equal_sign(self, arch, port):
73+
@contextmanager
74+
def create_container(self, cmd, image):
75+
try:
76+
platform = "x86_64" if self.ARCH == "" else self.ARCH
77+
cmd_full = f"docker run --platform linux/{platform} {cmd}"
78+
self.run_command(cmd_full)
79+
80+
# sleep 1s to give enough time for the endpoint to be up to curl
81+
self.sleep_1s()
82+
yield
83+
except Exception as e:
84+
print(f"An error occurred while executing cmd: {cmd_full}. error: {e}")
85+
raise e
86+
finally:
87+
self.run_command(f"docker stop {image}")
88+
self.run_command(f"docker rm -f {image}")
89+
90+
91+
def test_env_var_with_equal_sign(self, arch=ARCH, port=PORT):
9792
image, rie, image_name = self.tagged_name("envvarcheck", arch)
98-
99-
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"
93+
cmd = f"--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"
10094

101-
r = self.create_container_and_invoke_function(cmd, port)
95+
with self.create_container(cmd, image):
96+
r = self.invoke_function(port)
10297

103-
self.assertEqual(b'"4=4"', r.content)
98+
self.assertEqual(b'"4=4"', r.content)
99+
104100

105-
@parameterized.expand([("x86_64", "8001"), ("arm64", "9001"), ("", "9051")])
106-
def test_two_invokes(self, arch, port):
101+
def test_two_invokes(self, arch=ARCH, port=PORT):
107102
image, rie, image_name = self.tagged_name("twoinvokes", arch)
108103

109-
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"
104+
cmd = f"--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"
110105

111-
r = self.create_container_and_invoke_function(cmd, port)
106+
with self.create_container(cmd, image):
107+
r = self.invoke_function(port)
112108

113-
self.assertEqual(b'"My lambda ran succesfully"', r.content)
109+
self.assertEqual(b'"My lambda ran succesfully"', r.content)
110+
111+
# Make sure we can invoke the function twice
112+
r = self.invoke_function(port)
113+
114+
self.assertEqual(b'"My lambda ran succesfully"', r.content)
114115

115-
# Make sure we can invoke the function twice
116-
r = self.invoke_function(port)
117-
118-
self.assertEqual(b'"My lambda ran succesfully"', r.content)
119116

120-
@parameterized.expand([("x86_64", "8002"), ("arm64", "9002"), ("", "9052")])
121-
def test_lambda_function_arn_exists(self, arch, port):
117+
def test_lambda_function_arn_exists(self, arch=ARCH, port=PORT):
122118
image, rie, image_name = self.tagged_name("arnexists", arch)
123119

124-
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"
120+
cmd = f"--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"
125121

126-
r = self.create_container_and_invoke_function(cmd, port)
122+
with self.create_container(cmd, image):
123+
r = self.invoke_function(port)
127124

128-
self.assertEqual(b'"My lambda ran succesfully"', r.content)
125+
self.assertEqual(b'"My lambda ran succesfully"', r.content)
129126

130-
@parameterized.expand([("x86_64", "8003"), ("arm64", "9003"), ("", "9053")])
131-
def test_lambda_function_arn_exists_with_defining_custom_name(self, arch, port):
127+
128+
def test_lambda_function_arn_exists_with_defining_custom_name(self, arch=ARCH, port=PORT):
132129
image, rie, image_name = self.tagged_name("customname", arch)
133130

134-
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"
131+
cmd = f"--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"
135132

136-
r = self.create_container_and_invoke_function(cmd, port)
133+
with self.create_container(cmd, image):
134+
r = self.invoke_function(port)
137135

138-
self.assertEqual(b'"My lambda ran succesfully"', r.content)
136+
self.assertEqual(b'"My lambda ran succesfully"', r.content)
137+
139138

140-
@parameterized.expand([("x86_64", "8004"), ("arm64", "9004"), ("", "9054")])
141-
def test_timeout_invoke(self, arch, port):
139+
def test_timeout_invoke(self, arch=ARCH, port=PORT):
142140
image, rie, image_name = self.tagged_name("timeout", arch)
143141

144-
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"
142+
cmd = f"--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"
145143

146-
r = self.create_container_and_invoke_function(cmd, port)
144+
with self.create_container(cmd, image):
145+
r = self.invoke_function(port)
147146

148-
self.assertEqual(b"Task timed out after 1.00 seconds", r.content)
147+
self.assertEqual(b"Task timed out after 1.00 seconds", r.content)
149148

150-
@parameterized.expand([("x86_64", "8005"), ("arm64", "9005"), ("", "9055")])
151-
def test_exception_returned(self, arch, port):
149+
150+
def test_exception_returned(self, arch=ARCH, port=PORT):
152151
image, rie, image_name = self.tagged_name("exception", arch)
153152

154-
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"
153+
cmd = f"--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"
154+
155+
with self.create_container(cmd, image):
156+
r = self.invoke_function(port)
157+
158+
# ignore request_id in python3.12 lambda
159+
result = r.json()
160+
self.assertEqual(result["errorMessage"],"Raising an exception")
161+
self.assertEqual(result["errorType"],"Exception")
162+
self.assertEqual(result["stackTrace"],[" File \"/var/task/main.py\", line 13, in exception_handler\n raise Exception(\"Raising an exception\")\n"])
155163

156-
r = self.create_container_and_invoke_function(cmd, port)
157-
158-
self.assertEqual(
159-
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"]}',
160-
r.content,
161-
)
162164

163-
@parameterized.expand([("x86_64", "8006"), ("arm64", "9006"), ("", "9056")])
164-
def test_context_get_remaining_time_in_three_seconds(self, arch, port):
165+
def test_context_get_remaining_time_in_three_seconds(self, arch=ARCH, port=PORT):
165166
image, rie, image_name = self.tagged_name("remaining_time_in_three_seconds", arch)
166167

167-
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"
168+
cmd = f"--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"
168169

169-
r = self.create_container_and_invoke_function(cmd, port)
170+
with self.create_container(cmd, image):
171+
r = self.invoke_function(port)
170172

171-
# Execution time is not decided, 1.0s ~ 3.0s is a good estimation
172-
self.assertLess(int(r.content), 3000)
173-
self.assertGreater(int(r.content), 1000)
173+
# Execution time is not decided, 1.0s ~ 3.0s is a good estimation
174+
self.assertLess(int(r.content), 3000)
175+
self.assertGreater(int(r.content), 1000)
174176

175-
@parameterized.expand([("x86_64", "8007"), ("arm64", "9007"), ("", "9057")])
176-
def test_context_get_remaining_time_in_ten_seconds(self, arch, port):
177+
178+
def test_context_get_remaining_time_in_ten_seconds(self, arch=ARCH, port=PORT):
177179
image, rie, image_name = self.tagged_name("remaining_time_in_ten_seconds", arch)
178180

179-
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"
181+
cmd = f"--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"
180182

181-
r = self.create_container_and_invoke_function(cmd, port)
183+
with self.create_container(cmd, image):
184+
r = self.invoke_function(port)
182185

183-
# Execution time is not decided, 8.0s ~ 10.0s is a good estimation
184-
self.assertLess(int(r.content), 10000)
185-
self.assertGreater(int(r.content), 8000)
186+
# Execution time is not decided, 8.0s ~ 10.0s is a good estimation
187+
self.assertLess(int(r.content), 10000)
188+
self.assertGreater(int(r.content), 8000)
189+
186190

187-
@parameterized.expand([("x86_64", "8008"), ("arm64", "9008"), ("", "9058")])
188-
def test_context_get_remaining_time_in_default_deadline(self, arch, port):
191+
def test_context_get_remaining_time_in_default_deadline(self, arch=ARCH, port=PORT):
189192
image, rie, image_name = self.tagged_name("remaining_time_in_default_deadline", arch)
190193

191-
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"
194+
cmd = f"--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"
195+
196+
with self.create_container(cmd, image):
197+
r = self.invoke_function(port)
192198

193-
r = self.create_container_and_invoke_function(cmd, port)
199+
# Executation time is not decided, 298.0s ~ 300.0s is a good estimation
200+
self.assertLess(int(r.content), 300000)
201+
self.assertGreater(int(r.content), 298000)
194202

195-
# Executation time is not decided, 298.0s ~ 300.0s is a good estimation
196-
self.assertLess(int(r.content), 300000)
197-
self.assertGreater(int(r.content), 298000)
198203

199-
@parameterized.expand([("x86_64", "8009"), ("arm64", "9009"), ("", "9059")])
200-
def test_invoke_with_pre_runtime_api_runtime(self, arch, port):
204+
def test_invoke_with_pre_runtime_api_runtime(self, arch=ARCH, port=PORT):
201205
image, rie, image_name = self.tagged_name("pre-runtime-api", arch)
202206

203-
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"
207+
cmd = f"--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"
204208

205-
r = self.create_container_and_invoke_function(cmd, port)
209+
with self.create_container(cmd, image):
210+
r = self.invoke_function(port)
206211

207-
self.assertEqual(b'"My lambda ran succesfully"', r.content)
212+
self.assertEqual(b'"My lambda ran succesfully"', r.content)
208213

209-
@parameterized.expand([("x86_64", "8010"), ("arm64", "9010"), ("", "9060")])
210-
def test_function_name_is_overriden(self, arch, port):
214+
215+
def test_function_name_is_overriden(self, arch=ARCH, port=PORT):
211216
image, rie, image_name = self.tagged_name("assert-overwritten", arch)
212217

213-
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"
218+
cmd = f"--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"
214219

215-
r = self.create_container_and_invoke_function(cmd, port)
220+
with self.create_container(cmd, image):
221+
r = self.invoke_function(port)
216222

217-
self.assertEqual(b'"My lambda ran succesfully"', r.content)
223+
self.assertEqual(b'"My lambda ran succesfully"', r.content)
224+
218225

219-
@parameterized.expand([("x86_64", "8011"), ("arm64", "9011"), ("", "9061")])
220-
def test_port_override(self, arch, port):
226+
def test_port_override(self, arch=ARCH, port=PORT):
221227
image, rie, image_name = self.tagged_name("port_override", arch)
222228

223229
# Use port 8081 inside the container instead of 8080
224-
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"
230+
cmd = f"--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"
225231

226-
r = self.create_container_and_invoke_function(cmd, port)
232+
with self.create_container(cmd, image):
233+
r = self.invoke_function(port)
227234

228-
self.assertEqual(b'"My lambda ran succesfully"', r.content)
235+
self.assertEqual(b'"My lambda ran succesfully"', r.content)
236+
229237

230238

231239
if __name__ == "__main__":

0 commit comments

Comments
 (0)