Skip to content

Commit 30a1f3e

Browse files
committed
Add memcached container
1 parent 2bcb931 commit 30a1f3e

File tree

11 files changed

+278
-183
lines changed

11 files changed

+278
-183
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ jobs:
2525
- kafka
2626
- keycloak
2727
- localstack
28+
- memcached
2829
- meta
2930
- minio
3031
- mongodb

README.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ testcontainers-python facilitates the use of Docker containers for functional an
2222
kafka/README
2323
keycloak/README
2424
localstack/README
25+
memcached/README
2526
minio/README
2627
mongodb/README
2728
mssql/README

memcached/README.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.. autoclass:: testcontainers.memcached.MemcachedContainer

memcached/setup.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from setuptools import setup, find_namespace_packages
2+
3+
description = "Memcached component of testcontainers-python."
4+
5+
setup(
6+
name="testcontainers-memcached",
7+
version="0.0.1rc1",
8+
packages=find_namespace_packages(),
9+
description=description,
10+
long_description=description,
11+
long_description_content_type="text/x-rst",
12+
url="https://github.com/testcontainers/testcontainers-python",
13+
install_requires=[
14+
"testcontainers-core",
15+
],
16+
python_requires=">=3.7",
17+
)
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+
import socket
14+
15+
from testcontainers.core.container import DockerContainer
16+
from testcontainers.core.waiting_utils import wait_container_is_ready
17+
18+
19+
class MemcachedNotReady(Exception):
20+
pass
21+
22+
23+
class MemcachedContainer(DockerContainer):
24+
"""
25+
Test container for Memcached. The example below spins up a Memcached server
26+
27+
Example:
28+
29+
.. doctest::
30+
31+
>>> from testcontainers.memcached import MemcachedContainer
32+
33+
>>> with MemcachedContainer() as memcached_container:
34+
... host, port = memcached_container.get_host_and_port()
35+
"""
36+
37+
def __init__(self, image="memcached:latest", port_to_expose=11211, **kwargs):
38+
super(MemcachedContainer, self).__init__(image, **kwargs)
39+
self.port_to_expose = port_to_expose
40+
self.with_exposed_ports(port_to_expose)
41+
42+
@wait_container_is_ready(MemcachedNotReady)
43+
def _connect(self):
44+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
45+
host = self.get_container_host_ip()
46+
port = int(self.get_exposed_port(self.port_to_expose))
47+
s.connect((host, port))
48+
s.sendall(b"stats\n\r")
49+
data = s.recv(1024)
50+
if len(data) == 0:
51+
raise MemcachedNotReady("Memcached not ready yet")
52+
53+
def start(self):
54+
super().start()
55+
self._connect()
56+
return self
57+
58+
def get_host_and_port(self):
59+
return self.get_container_host_ip(), int(self.get_exposed_port(self.port_to_expose))

memcached/tests/test_memcached.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import socket
2+
3+
from memcached.testcontainers.memcached import MemcachedContainer
4+
5+
6+
def test_memcached_host_and_exposed_port():
7+
with MemcachedContainer() as memcached:
8+
host, port = memcached.get_host_and_port()
9+
assert host == 'localhost'
10+
assert port != 11211
11+
12+
13+
def test_memcached_can_connect_and_retrieve_data():
14+
with MemcachedContainer() as memcached:
15+
host, port = memcached.get_host_and_port()
16+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
17+
s.connect((host, port))
18+
s.sendall(b"stats\n\r")
19+
data = s.recv(1024)
20+
assert len(data) > 0, 'We should have received some data from memcached'
21+
22+
pid_stat, uptime_stat, *_ = data.decode().split('\r\n')
23+
24+
assert pid_stat.startswith('STAT pid')
25+
assert uptime_stat.startswith('STAT uptime')

requirements.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
-e file:kafka
99
-e file:keycloak
1010
-e file:localstack
11+
-e file:memcached
1112
-e file:meta
1213
-e file:minio
1314
-e file:mongodb

0 commit comments

Comments
 (0)