From 0fa2cb68e16cec01f03e605725a358df00713e44 Mon Sep 17 00:00:00 2001 From: Rickard von Essen Date: Fri, 7 Aug 2026 10:16:06 +0200 Subject: [PATCH 1/2] Add Memcached module (#953) Adds a new `testcontainers-memcached` module with `MemcachedContainer`, a test using SpyMemcached, documentation, and labeler/mkdocs wiring. Co-Authored-By: Claude Sonnet 4.6 --- .github/labeler.yml | 4 ++ docs/modules/memcached.md | 31 +++++++++++++++ mkdocs.yml | 1 + modules/memcached/build.gradle | 7 ++++ .../memcached/MemcachedContainer.java | 27 +++++++++++++ .../memcached/MemcachedContainerTest.java | 38 +++++++++++++++++++ .../src/test/resources/logback-test.xml | 16 ++++++++ 7 files changed, 124 insertions(+) create mode 100644 docs/modules/memcached.md create mode 100644 modules/memcached/build.gradle create mode 100644 modules/memcached/src/main/java/org/testcontainers/memcached/MemcachedContainer.java create mode 100644 modules/memcached/src/test/java/org/testcontainers/memcached/MemcachedContainerTest.java create mode 100644 modules/memcached/src/test/resources/logback-test.xml diff --git a/.github/labeler.yml b/.github/labeler.yml index f4649bd7f99..fb702a3852e 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -119,6 +119,10 @@ - changed-files: - any-glob-to-any-file: - modules/mariadb/**/* +"modules/memcached": + - changed-files: + - any-glob-to-any-file: + - modules/memcached/**/* "modules/milvus": - changed-files: - any-glob-to-any-file: diff --git a/docs/modules/memcached.md b/docs/modules/memcached.md new file mode 100644 index 00000000000..6f78d5aadf0 --- /dev/null +++ b/docs/modules/memcached.md @@ -0,0 +1,31 @@ +# Memcached Module + +Memcached is an in-memory key-value cache. + +## Usage example + + +[Creating a Memcached container](../../modules/memcached/src/test/java/org/testcontainers/memcached/MemcachedContainerTest.java) inside_block:creatingContainer + + + +[Connect and operate](../../modules/memcached/src/test/java/org/testcontainers/memcached/MemcachedContainerTest.java) inside_block:connectAndOperate + + +## Adding this module to your project dependencies + +Add the following dependency to your `pom.xml`/`build.gradle` file: + +=== "Gradle" + ```groovy + testImplementation "org.testcontainers:testcontainers-memcached:{{latest_version}}" + ``` +=== "Maven" + ```xml + + org.testcontainers + testcontainers-memcached + {{latest_version}} + test + + ``` diff --git a/mkdocs.yml b/mkdocs.yml index ae447212912..6eda6860cfe 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -92,6 +92,7 @@ nav: - modules/kafka.md - modules/ldap.md - modules/localstack.md + - modules/memcached.md - modules/milvus.md - modules/minio.md - modules/mockserver.md diff --git a/modules/memcached/build.gradle b/modules/memcached/build.gradle new file mode 100644 index 00000000000..f48c0ce4c44 --- /dev/null +++ b/modules/memcached/build.gradle @@ -0,0 +1,7 @@ +description = "Testcontainers :: Memcached" + +dependencies { + api project(':testcontainers') + + testImplementation 'net.spy:spymemcached:2.12.3' +} diff --git a/modules/memcached/src/main/java/org/testcontainers/memcached/MemcachedContainer.java b/modules/memcached/src/main/java/org/testcontainers/memcached/MemcachedContainer.java new file mode 100644 index 00000000000..34d5f564f2c --- /dev/null +++ b/modules/memcached/src/main/java/org/testcontainers/memcached/MemcachedContainer.java @@ -0,0 +1,27 @@ +package org.testcontainers.memcached; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.utility.DockerImageName; + +public class MemcachedContainer extends GenericContainer { + + private static final int DEFAULT_PORT = 11211; + + private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("memcached"); + + public MemcachedContainer(String dockerImageName) { + this(DockerImageName.parse(dockerImageName)); + } + + public MemcachedContainer(DockerImageName dockerImageName) { + super(dockerImageName); + dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); + withExposedPorts(DEFAULT_PORT); + waitingFor(Wait.forListeningPort()); + } + + public String getHostPort() { + return getHost() + ":" + getMappedPort(DEFAULT_PORT); + } +} diff --git a/modules/memcached/src/test/java/org/testcontainers/memcached/MemcachedContainerTest.java b/modules/memcached/src/test/java/org/testcontainers/memcached/MemcachedContainerTest.java new file mode 100644 index 00000000000..bd9711a5086 --- /dev/null +++ b/modules/memcached/src/test/java/org/testcontainers/memcached/MemcachedContainerTest.java @@ -0,0 +1,38 @@ +package org.testcontainers.memcached; + +import net.spy.memcached.MemcachedClient; +import org.junit.jupiter.api.Test; +import org.testcontainers.utility.DockerImageName; + +import java.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; + +class MemcachedContainerTest { + + private static final DockerImageName MEMCACHED_IMAGE = DockerImageName.parse("memcached:1.6-alpine"); + + @Test + void testSimple() throws Exception { + try ( + // creatingContainer { + MemcachedContainer memcached = new MemcachedContainer(MEMCACHED_IMAGE) + // } + ) { + memcached.start(); + + // connectAndOperate { + MemcachedClient client = new MemcachedClient( + new InetSocketAddress(memcached.getHost(), memcached.getMappedPort(11211)) + ); + try { + client.set("hello", 60, "world").get(5, TimeUnit.SECONDS); + assertThat(client.get("hello")).isEqualTo("world"); + } finally { + client.shutdown(); + } + // } + } + } +} diff --git a/modules/memcached/src/test/resources/logback-test.xml b/modules/memcached/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/memcached/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + From 39da0f1d328487147a670133729f73a4e5ca5e8b Mon Sep 17 00:00:00 2001 From: Rickard von Essen Date: Fri, 7 Aug 2026 11:00:00 +0200 Subject: [PATCH 2/2] Add Memcached to issue templates, dependabot, and labeler Co-Authored-By: Claude Sonnet 4.6 --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 5 +++++ 4 files changed, 8 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index c31dd05e048..a01914d4372 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -37,6 +37,7 @@ body: - LDAP - LocalStack - MariaDB + - Memcached - Milvus - MinIO - MockServer diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index 9b9a06ecf6a..400b204545a 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -37,6 +37,7 @@ body: - LDAP - LocalStack - MariaDB + - Memcached - Milvus - MinIO - MockServer diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index b655b4ac505..49c7b8d9c6f 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -37,6 +37,7 @@ body: - LDAP - LocalStack - MariaDB + - Memcached - Milvus - MinIO - MockServer diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 789ec351da2..2348b3da712 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -210,6 +210,11 @@ updates: ignore: - dependency-name: "org.mariadb:r2dbc-mariadb" update-types: [ "version-update:semver-minor" ] + - package-ecosystem: "gradle" + directory: "/modules/memcached" + schedule: + interval: "monthly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/milvus" schedule: