Skip to content

Commit

Permalink
fix: Add memcached container (#322)
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
romulojales committed May 11, 2024
1 parent 396079a commit 690b9b4
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 5 deletions.
1 change: 1 addition & 0 deletions index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ testcontainers-python facilitates the use of Docker containers for functional an
modules/kafka/README
modules/keycloak/README
modules/localstack/README
modules/memcached/README
modules/minio/README
modules/mongodb/README
modules/mssql/README
Expand Down
1 change: 1 addition & 0 deletions modules/memcached/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.. autoclass:: testcontainers.memcached.MemcachedContainer
17 changes: 17 additions & 0 deletions modules/memcached/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from setuptools import find_namespace_packages, setup

description = "Memcached component of testcontainers-python."

setup(
name="testcontainers-memcached",
version="0.0.1rc1",
packages=find_namespace_packages(),
description=description,
long_description=description,
long_description_content_type="text/x-rst",
url="https://github.com/testcontainers/testcontainers-python",
install_requires=[
"testcontainers-core",
],
python_requires=">=3.7",
)
59 changes: 59 additions & 0 deletions modules/memcached/testcontainers/memcached/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import socket

from testcontainers.core.container import DockerContainer
from testcontainers.core.waiting_utils import wait_container_is_ready


class MemcachedNotReady(Exception):
pass


class MemcachedContainer(DockerContainer):
"""
Test container for Memcached. The example below spins up a Memcached server
Example:
.. doctest::
>>> from testcontainers.memcached import MemcachedContainer
>>> with MemcachedContainer() as memcached_container:
... host, port = memcached_container.get_host_and_port()
"""

def __init__(self, image="memcached:1", port_to_expose=11211, **kwargs):
super().__init__(image, **kwargs)
self.port_to_expose = port_to_expose
self.with_exposed_ports(port_to_expose)

@wait_container_is_ready(MemcachedNotReady)
def _connect(self):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
host = self.get_container_host_ip()
port = int(self.get_exposed_port(self.port_to_expose))
s.connect((host, port))
s.sendall(b"stats\n\r")
data = s.recv(1024)
if len(data) == 0:
raise MemcachedNotReady("Memcached not ready yet")

def start(self):
super().start()
self._connect()
return self

def get_host_and_port(self):
return self.get_container_host_ip(), int(self.get_exposed_port(self.port_to_expose))
28 changes: 28 additions & 0 deletions modules/memcached/tests/test_memcached.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import socket

from testcontainers.memcached import MemcachedContainer

import pytest


def test_memcached_host_and_exposed_port():
with MemcachedContainer("memcached:1.6-alpine") as memcached:
host, port = memcached.get_host_and_port()
assert host == "localhost"
assert port != 11211


@pytest.mark.parametrize("image", ["memcached:1.6-bookworm", "memcached:1.6-alpine"])
def test_memcached_can_connect_and_retrieve_data(image):
with MemcachedContainer(image) as memcached:
host, port = memcached.get_host_and_port()
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((host, port))
s.sendall(b"stats\n\r")
data = s.recv(1024)
assert len(data) > 0, "We should have received some data from memcached"

pid_stat, uptime_stat, *_ = data.decode().split("\r\n")

assert pid_stat.startswith("STAT pid")
assert uptime_stat.startswith("STAT uptime")
11 changes: 6 additions & 5 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ packages = [
{ include = "testcontainers", from = "modules/kafka" },
{ include = "testcontainers", from = "modules/keycloak" },
{ include = "testcontainers", from = "modules/localstack" },
{ include = "testcontainers", from = "modules/memcached" },
{ include = "testcontainers", from = "modules/minio" },
{ include = "testcontainers", from = "modules/mongodb" },
{ include = "testcontainers", from = "modules/mssql" },
Expand Down Expand Up @@ -111,6 +112,7 @@ k3s = ["kubernetes", "pyyaml"]
kafka = []
keycloak = ["python-keycloak"]
localstack = ["boto3"]
memcached = []
minio = ["minio"]
mongodb = ["pymongo"]
mssql = ["sqlalchemy", "pymssql"]
Expand Down

0 comments on commit 690b9b4

Please sign in to comment.