Skip to content

Commit 690b9b4

Browse files
authored
fix: Add memcached container (#322)
Adding [Memcached](https://memcached.org/) container. You have implemented a new container and would like to contribute it? Great! Here are the necessary steps. - [x] Create a new feature directory and populate it with the package structure [described in the documentation](https://testcontainers-python.readthedocs.io/en/latest/#package-structure). Copying one of the existing features is likely the best way to get started. - [x] Implement the new feature (typically in `__init__.py`) and corresponding tests. - [x] Add a line `-e file:[feature name]` to `requirements.in` and run `make requirements`. This command will find any new requirements and generate lock files to ensure reproducible builds (see the [pip-tools documentation](https://pip-tools.readthedocs.io/en/latest/) for details). Then run `pip install -r requirements/[your python version].txt` to install the new requirements. - [x] Update the feature `README.rst` and add it to the table of contents (`toctree` directive) in the top-level `README.rst`. - [x] Add a line `[feature name]` to the list of components in the GitHub Action workflow in `.github/workflows/main.yml` to run tests, build, and publish your package when pushed to the `master` branch. - [x] Rebase your development branch on `master` (or merge `master` into your development branch).
1 parent 396079a commit 690b9b4

File tree

7 files changed

+114
-5
lines changed

7 files changed

+114
-5
lines changed

index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ testcontainers-python facilitates the use of Docker containers for functional an
2727
modules/kafka/README
2828
modules/keycloak/README
2929
modules/localstack/README
30+
modules/memcached/README
3031
modules/minio/README
3132
modules/mongodb/README
3233
modules/mssql/README

modules/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

modules/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 find_namespace_packages, setup
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:1", port_to_expose=11211, **kwargs):
38+
super().__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))
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import socket
2+
3+
from testcontainers.memcached import MemcachedContainer
4+
5+
import pytest
6+
7+
8+
def test_memcached_host_and_exposed_port():
9+
with MemcachedContainer("memcached:1.6-alpine") as memcached:
10+
host, port = memcached.get_host_and_port()
11+
assert host == "localhost"
12+
assert port != 11211
13+
14+
15+
@pytest.mark.parametrize("image", ["memcached:1.6-bookworm", "memcached:1.6-alpine"])
16+
def test_memcached_can_connect_and_retrieve_data(image):
17+
with MemcachedContainer(image) as memcached:
18+
host, port = memcached.get_host_and_port()
19+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
20+
s.connect((host, port))
21+
s.sendall(b"stats\n\r")
22+
data = s.recv(1024)
23+
assert len(data) > 0, "We should have received some data from memcached"
24+
25+
pid_stat, uptime_stat, *_ = data.decode().split("\r\n")
26+
27+
assert pid_stat.startswith("STAT pid")
28+
assert uptime_stat.startswith("STAT uptime")

poetry.lock

Lines changed: 6 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ packages = [
4040
{ include = "testcontainers", from = "modules/kafka" },
4141
{ include = "testcontainers", from = "modules/keycloak" },
4242
{ include = "testcontainers", from = "modules/localstack" },
43+
{ include = "testcontainers", from = "modules/memcached" },
4344
{ include = "testcontainers", from = "modules/minio" },
4445
{ include = "testcontainers", from = "modules/mongodb" },
4546
{ include = "testcontainers", from = "modules/mssql" },
@@ -111,6 +112,7 @@ k3s = ["kubernetes", "pyyaml"]
111112
kafka = []
112113
keycloak = ["python-keycloak"]
113114
localstack = ["boto3"]
115+
memcached = []
114116
minio = ["minio"]
115117
mongodb = ["pymongo"]
116118
mssql = ["sqlalchemy", "pymssql"]

0 commit comments

Comments
 (0)