Skip to content
This repository was archived by the owner on Mar 19, 2024. It is now read-only.

Commit 0293f63

Browse files
Merge pull request #30 from Andrea-Scuderi/feature/lambdaci-test
Test Lambda with LambCI and LocalStack
2 parents d7a4578 + b163bc5 commit 0293f63

17 files changed

+282
-22
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.DS_Store
22
/.build
3+
.tmp
34
/Packages
45
/*.xcodeproj
56
lambda.zip

.travis.yml

+27-1
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,23 @@ dist: xenial
77
services:
88
- docker
99

10+
env:
11+
global:
12+
- AWS_REGION=us-east-1
13+
- AWS_ACCESS_KEY_ID=AKFAKEACCESSKEYID
14+
- AWS_DEFAULT_REGION=us-east-1
15+
- AWS_SECRET_ACCESS_KEY=AKFAKESECRETACCESSKEY
16+
- AWS_PROFILE=default
17+
1018
addons:
1119
snaps:
1220
- name: aws-cli
1321
confinement: classic # or devmode
1422
channel: latest/edge
1523

24+
before_install:
25+
- ./scripts/aws_travis_credentials.sh
26+
1627
install:
1728
- make --version
1829
- make docker_build
@@ -23,4 +34,19 @@ script:
2334
- make package_lambda
2435
- make swift_test
2536
- make swift_test SWIFT_EXECUTABLE=HTTPSRequest SWIFT_PROJECT_PATH=Examples/HTTPSRequest LAMBDA_FUNCTION_NAME=HTTPSRequest LAMBDA_HANDLER=HTTPSRequest.getHttps
26-
- make swift_test SWIFT_EXECUTABLE=S3Test SWIFT_PROJECT_PATH=Examples/S3Test LAMBDA_FUNCTION_NAME=S3Test LAMBDA_HANDLER=S3Test.getObject
37+
- make swift_test SWIFT_EXECUTABLE=S3Test SWIFT_PROJECT_PATH=Examples/S3Test LAMBDA_FUNCTION_NAME=S3Test LAMBDA_HANDLER=S3Test.getObject
38+
- make build_lambda_local
39+
- make start_docker_compose_env
40+
- make invoke_lambda_local
41+
- make stop_docker_compose_env
42+
- make test_lambda_local_output
43+
- make build_lambda_local SWIFT_EXECUTABLE=HTTPSRequest SWIFT_PROJECT_PATH=Examples/HTTPSRequest LAMBDA_FUNCTION_NAME=HTTPSRequest LAMBDA_HANDLER=HTTPSRequest.getHttps
44+
- make start_docker_compose_env SWIFT_EXECUTABLE=HTTPSRequest SWIFT_PROJECT_PATH=Examples/HTTPSRequest LAMBDA_FUNCTION_NAME=HTTPSRequest LAMBDA_HANDLER=HTTPSRequest.getHttps
45+
- make invoke_lambda_local SWIFT_EXECUTABLE=HTTPSRequest SWIFT_PROJECT_PATH=Examples/HTTPSRequest LAMBDA_FUNCTION_NAME=HTTPSRequest LAMBDA_HANDLER=HTTPSRequest.getHttps
46+
- make stop_docker_compose_env SWIFT_EXECUTABLE=HTTPSRequest SWIFT_PROJECT_PATH=Examples/HTTPSRequest LAMBDA_FUNCTION_NAME=HTTPSRequest LAMBDA_HANDLER=HTTPSRequest.getHttps
47+
- make test_lambda_local_output SWIFT_EXECUTABLE=HTTPSRequest SWIFT_PROJECT_PATH=Examples/HTTPSRequest LAMBDA_FUNCTION_NAME=HTTPSRequest LAMBDA_HANDLER=HTTPSRequest.getHttps
48+
- make build_lambda_local SWIFT_EXECUTABLE=S3Test SWIFT_PROJECT_PATH=Examples/S3Test LAMBDA_FUNCTION_NAME=S3Test LAMBDA_HANDLER=S3Test.getObject
49+
- make start_docker_compose_env SWIFT_EXECUTABLE=S3Test SWIFT_PROJECT_PATH=Examples/S3Test LAMBDA_FUNCTION_NAME=S3Test LAMBDA_HANDLER=S3Test.getObject
50+
- make invoke_lambda_local SWIFT_EXECUTABLE=S3Test SWIFT_PROJECT_PATH=Examples/S3Test LAMBDA_FUNCTION_NAME=S3Test LAMBDA_HANDLER=S3Test.getObject
51+
- make stop_docker_compose_env SWIFT_EXECUTABLE=S3Test SWIFT_PROJECT_PATH=Examples/S3Test LAMBDA_FUNCTION_NAME=S3Test LAMBDA_HANDLER=S3Test.getObject
52+
- make test_lambda_local_output SWIFT_EXECUTABLE=S3Test SWIFT_PROJECT_PATH=Examples/S3Test LAMBDA_FUNCTION_NAME=S3Test LAMBDA_HANDLER=S3Test.getObject

Examples/HTTPSRequest/Makefile

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Note: This must be launched from the root path
2+
SWIFT_PROJECT_PATH=Examples/HTTPSRequest
3+
4+
start_docker_compose_env:
5+
cd $(SWIFT_PROJECT_PATH); docker-compose up -d ; sleep 2
6+
7+
stop_docker_compose_env:
8+
cd $(SWIFT_PROJECT_PATH); docker-compose stop

Examples/HTTPSRequest/Sources/HTTPSRequest/main.swift

+5-8
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ struct Event: Codable {
2828
}
2929

3030
struct Response: Codable {
31-
let url: String
3231
let content: String
3332
}
3433

@@ -59,7 +58,7 @@ let syncCodableNIOLambda: SyncCodableNIOLambda<Event, Response> = { (event, cont
5958
}
6059
return value
6160
}.map { content -> Response in
62-
return Response(url: event.url, content: content)
61+
return Response(content: content)
6362
}
6463
return future
6564
}
@@ -92,8 +91,7 @@ let syncDictionaryNIOLambda: SyncDictionaryNIOLambda = { (event, context) throws
9291
}
9392
return value
9493
}.map { content -> [String: Any] in
95-
return ["url": url,
96-
"content": content]
94+
return ["content": content]
9795
}
9896
return future
9997
}
@@ -126,8 +124,7 @@ let asynchDictionayNIOLambda: AsyncDictionaryNIOLambda = { (event, context, comp
126124
}
127125
return value
128126
}.map { content -> [String: Any] in
129-
return ["url": url,
130-
"content": content]
127+
return ["content": content]
131128
}
132129
.wait()
133130
completion(.success(dictionary))
@@ -160,7 +157,7 @@ let asyncCodableNIOLambda: AsyncCodableNIOLambda<Event, Response> = { (event, co
160157
}
161158
return value
162159
}.map { content -> Response in
163-
return Response(url: event.url, content: content)
160+
return Response(content: content)
164161
}
165162
.wait()
166163
completion(.success(reponse))
@@ -198,7 +195,7 @@ let lambda: SyncCodableLambda<Event, Response> = { (input, context) throws -> Re
198195
}
199196
let content = String(data: data, encoding: .utf8) ?? ""
200197

201-
return Response(url: input.url, content: content)
198+
return Response(content: content)
202199
}
203200

204201

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
version: '3'
2+
services:
3+
lambci:
4+
image: "lambci/lambda:provided"
5+
volumes:
6+
- ../../.build/local:/var/task:ro,delegated
7+
- ../../bootstrap:/opt/bootstrap:ro,delegated
8+
- ../../swift-shared-libs:/opt/swift-shared-libs:ro,delegated
9+
environment:
10+
- DOCKER_LAMBDA_STAY_OPEN=1
11+
- AWS_LAMBDA_FUNCTION_TIMEOUT=3
12+
- LAMB_CI_EXEC=1
13+
command:
14+
- HTTPSRequest.getHttps
15+
ports:
16+
- "9001:9001"

Examples/HTTPSRequest/event.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"url": "https://swift.org"
2+
"url": "https://www.example.com"
33
}

Examples/HTTPSRequest/outfile.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"content":"<!doctype html>\n<html>\n<head>\n <title>Example Domain<\/title>\n\n <meta charset=\"utf-8\" \/>\n <meta http-equiv=\"Content-type\" content=\"text\/html; charset=utf-8\" \/>\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" \/>\n <style type=\"text\/css\">\n body {\n background-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n }\n div {\n width: 600px;\n margin: 5em auto;\n padding: 2em;\n background-color: #fdfdff;\n border-radius: 0.5em;\n box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);\n }\n a:link, a:visited {\n color: #38488f;\n text-decoration: none;\n }\n @media (max-width: 700px) {\n div {\n margin: 0 auto;\n width: auto;\n }\n }\n <\/style> \n<\/head>\n\n<body>\n<div>\n <h1>Example Domain<\/h1>\n <p>This domain is for use in illustrative examples in documents. You may use this\n domain in literature without prior coordination or asking for permission.<\/p>\n <p><a href=\"https:\/\/www.iana.org\/domains\/example\">More information...<\/a><\/p>\n<\/div>\n<\/body>\n<\/html>\n"}

Examples/HelloWorld/Makefile

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Note: This must be launched from the root path
2+
SWIFT_PROJECT_PATH=Examples/HelloWorld
3+
4+
start_docker_compose_env:
5+
cd $(SWIFT_PROJECT_PATH); docker-compose up -d ; sleep 2
6+
7+
stop_docker_compose_env:
8+
cd $(SWIFT_PROJECT_PATH); docker-compose stop
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
version: '3'
2+
services:
3+
lambci:
4+
image: "lambci/lambda:provided"
5+
volumes:
6+
- ../../.build/local:/var/task:ro,delegated
7+
- ../../bootstrap:/opt/bootstrap:ro,delegated
8+
- ../../swift-shared-libs:/opt/swift-shared-libs:ro,delegated
9+
environment:
10+
- DOCKER_LAMBDA_STAY_OPEN=1
11+
- AWS_LAMBDA_FUNCTION_TIMEOUT=3
12+
- LAMB_CI_EXEC=1
13+
command:
14+
- HelloWorld.helloWorld
15+
ports:
16+
- "9001:9001"

Examples/HelloWorld/outfile.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"message":"Hello World! Hello Swift-Sprinter!"}

Examples/S3Test/Makefile

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Note: This must be launched from the root path
2+
SWIFT_PROJECT_PATH=Examples/S3Test
3+
4+
start_docker_compose_env:
5+
cd $(SWIFT_PROJECT_PATH); docker-compose up -d ; sleep 2
6+
aws --endpoint http://localhost:4572 s3 mb s3://my-s3-bucket
7+
aws --endpoint http://localhost:4572 s3 cp $(SWIFT_PROJECT_PATH)/hello.txt s3://my-s3-bucket/hello.txt
8+
9+
stop_docker_compose_env:
10+
cd $(SWIFT_PROJECT_PATH); docker-compose stop

Examples/S3Test/Sources/S3Test/main.swift

+18-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import Logging
2121
import S3
2222
import NIO
2323
import NIOFoundationCompat
24+
import AWSSDKSwiftCore
2425

2526
struct Bucket: Codable {
2627
let name: String
@@ -31,10 +32,25 @@ struct Response: Codable {
3132
let value: String?
3233
}
3334

34-
let s3 = S3(region: .useast1)
35-
3635
let logger = Logger(label: "AWS.Lambda.S3Test")
3736

37+
var s3: S3!
38+
39+
if ProcessInfo.processInfo.environment["LAMB_CI_EXEC"] == "1" {
40+
//Used for local test
41+
s3 = S3(region: .useast1, endpoint: "http://localstack:4572")
42+
logger.info("Endpoint-URI: http://localstack:4572")
43+
} else if let awsRegion = ProcessInfo.processInfo.environment["AWS_REGION"],
44+
//The S3 Bucket must be in the same region of the Lambda
45+
let region = Region(rawValue: awsRegion) {
46+
s3 = S3(region: region)
47+
logger.info("AWS_REGION: \(region)")
48+
} else {
49+
//Default configuration
50+
s3 = S3(region: .useast1)
51+
logger.info("AWS_REGION: us-east-1")
52+
}
53+
3854
/**
3955
How to use the `SyncCodableNIOLambda<Bucket, Response>` lambda handler with S3.
4056

Examples/S3Test/docker-compose.yml

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
version: '3'
2+
services:
3+
lambci:
4+
image: "lambci/lambda:provided"
5+
volumes:
6+
- ../../.build/local:/var/task:ro,delegated
7+
- ../../bootstrap:/opt/bootstrap:ro,delegated
8+
- ../../swift-shared-libs:/opt/swift-shared-libs:ro,delegated
9+
environment:
10+
- DOCKER_LAMBDA_STAY_OPEN=1
11+
- AWS_LAMBDA_FUNCTION_TIMEOUT=3
12+
- LAMB_CI_EXEC=1
13+
command:
14+
- S3Test.getObject
15+
ports:
16+
- "9001:9001"
17+
localstack:
18+
image: localstack/localstack
19+
ports:
20+
- "4567-4584:4567-4584"
21+
environment:
22+
- SERVICES=s3
23+
volumes:
24+
- ".tmp:/tmp/localstack"

Examples/S3Test/outfile.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"value":"Hello World!"}

Makefile

+37
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ LAYER_ZIP=swift-lambda-runtime-$(LAYER_VERSION).zip
4242
ROOT_BUILD_PATH=./.build
4343
LAYER_BUILD_PATH=$(ROOT_BUILD_PATH)/layer
4444
LAMBDA_BUILD_PATH=$(ROOT_BUILD_PATH)/lambda
45+
LOCAL_LAMBDA_PATH=$(ROOT_BUILD_PATH)/local
46+
LOCALSTACK_TMP=$(ROOT_BUILD_PATH)/.tmp
4547
TMP_BUILD_PATH=$(ROOT_BUILD_PATH)/tmp
4648
DATETIME=$(shell date +'%y%m%d-%H%M%S')
4749

@@ -207,3 +209,38 @@ quick_build_lambda: build_lambda create_build_directory
207209

208210
quick_deploy_lambda: quick_build_lambda create_build_directory
209211
aws lambda update-function-code --function-name $(LAMBDA_FUNCTION_NAME) --zip-file fileb://$(LAMBDA_BUILD_PATH)/$(LAMBDA_ZIP) --profile $(AWS_PROFILE)
212+
213+
build_lambda_local: build_lambda
214+
if [ ! -d "$(LOCAL_LAMBDA_PATH)" ]; then mkdir -p $(LOCAL_LAMBDA_PATH); fi
215+
cp $(SWIFT_PROJECT_PATH)/.build/$(SWIFT_CONFIGURATION)/$(SWIFT_EXECUTABLE) $(LOCAL_LAMBDA_PATH)/.
216+
217+
invoke_lambda_local_once:
218+
$(eval LOCAL_LAMBDA_EVENT := '$(shell cat $(SWIFT_PROJECT_PATH)/event.json)')
219+
docker run --rm \
220+
-v "$(PWD)/$(LOCAL_LAMBDA_PATH)":/var/task:ro,delegated \
221+
-v "$(PWD)/bootstrap":/opt/bootstrap:ro,delegated \
222+
-v "$(PWD)/$(SHARED_LIBS_FOLDER)":/opt/swift-shared-libs:ro,delegated \
223+
lambci/lambda:provided $(LAMBDA_HANDLER) $(LOCAL_LAMBDA_EVENT)
224+
225+
start_lambda_local_env:
226+
docker run --rm \
227+
-e DOCKER_LAMBDA_STAY_OPEN=1 \
228+
-p 9001:9001 \
229+
-v "$(PWD)/$(LOCAL_LAMBDA_PATH)":/var/task:ro,delegated \
230+
-v "$(PWD)/bootstrap":/opt/bootstrap:ro,delegated \
231+
-v "$(PWD)/$(SHARED_LIBS_FOLDER)":/opt/swift-shared-libs:ro,delegated \
232+
lambci/lambda:provided \
233+
$(LAMBDA_HANDLER)
234+
235+
invoke_lambda_local:
236+
aws lambda invoke --endpoint http://localhost:9001 --no-sign-request --function-name $(LAMBDA_FUNCTION_NAME) --payload "fileb://$(SWIFT_PROJECT_PATH)/event.json" $(TMP_BUILD_PATH)/outfile && echo "\nResult:" && cat $(TMP_BUILD_PATH)/outfile && echo "\n"
237+
238+
start_docker_compose_env:
239+
if [ ! -d "$(LOCALSTACK_TMP)" ]; then mkdir -p $(LOCALSTACK_TMP); fi
240+
make -f $(SWIFT_PROJECT_PATH)/Makefile start_docker_compose_env
241+
242+
stop_docker_compose_env:
243+
make -f $(SWIFT_PROJECT_PATH)/Makefile stop_docker_compose_env
244+
245+
test_lambda_local_output:
246+
cmp $(TMP_BUILD_PATH)/outfile $(SWIFT_PROJECT_PATH)/outfile.json

0 commit comments

Comments
 (0)