Skip to content

Commit 77c3a65

Browse files
authored
Add Localstack container support (#107)
* Add Localstack container support * Fix python version compatibility * PR review * Improve localstack ready match * Fix after review * Rename get_endpoint_url for get_url
1 parent 657ec29 commit 77c3a65

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

README.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Currently available features:
2121
* PostgreSQL Db container
2222
* Microsoft SQL Server container
2323
* Generic docker containers
24+
* LocalStack
2425

2526
Installation
2627
------------

testcontainers/localstack.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#
2+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
3+
# not use this file except in compliance with the License. You may obtain
4+
# a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11+
# License for the specific language governing permissions and limitations
12+
# under the License.
13+
from testcontainers.core.waiting_utils import wait_for_logs
14+
from testcontainers.core.container import DockerContainer
15+
16+
17+
class LocalStackContainer(DockerContainer):
18+
"""
19+
Localstack container.
20+
21+
Example
22+
-------
23+
::
24+
localstack = LocalStackContainer(image="localstack/localstack:0.11.3")
25+
localstack.with_services("dynamodb", "lambda")
26+
localstack.start()
27+
dynamo_endpoint = localstack.get_endpoint_override()
28+
dynamo_client = boto3.client("dynamodb", endpoint_url=dynamo_endpoint)
29+
scan_result = dynamo_client.scan(TableName='foo')
30+
# Do something with the scan result
31+
"""
32+
EDGE_PORT = 4566
33+
IMAGE = 'localstack/localstack:0.11.4'
34+
35+
def __init__(self, image=IMAGE):
36+
super(LocalStackContainer, self).__init__(image)
37+
self.with_exposed_ports(LocalStackContainer.EDGE_PORT)
38+
39+
def with_services(self, *services):
40+
"""
41+
Restrict what services to run. By default all localstack services are launched.
42+
:return: the DockerContainer to allow chaining of 'with_*' calls.
43+
"""
44+
return self.with_env('SERVICES', ','.join(services))
45+
46+
def get_url(self):
47+
"""
48+
Use this to call localstack instead of real AWS services.
49+
ex: boto3.client('lambda', endpoint_url=localstack.get_url())
50+
:return: the endpoint where localstack is reachable.
51+
"""
52+
host = self.get_container_host_ip()
53+
port = self.get_exposed_port(LocalStackContainer.EDGE_PORT)
54+
return 'http://{}:{}'.format(host, port)
55+
56+
def start(self, timeout=60):
57+
super().start()
58+
wait_for_logs(self, r'Ready\.\n', timeout=timeout)
59+
return self

tests/test_localstack.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import json
2+
import urllib
3+
4+
from testcontainers.localstack import LocalStackContainer
5+
6+
7+
def test_docker_run_localstack():
8+
config = LocalStackContainer()
9+
with config as localstack:
10+
resp = urllib.request.urlopen('{}/health'.format(localstack.get_url()))
11+
services = json.loads(resp.read().decode())['services']
12+
13+
# Check that all services are running
14+
assert all(value == 'running' for value in services.values())
15+
# Check that some of the services keys
16+
assert all(test_service in services.keys() for test_service in ['dynamodb', 'sns', 'sqs'])

0 commit comments

Comments
 (0)