Skip to content

About

Light, fluffy, and always free - Testcontainers for Java: run the Floci local AWS and Azure emulators in your integration tests.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

65 stars

Watchers

3 watching

Forks

Repository files navigation

Floci Floci

Any Cloud. Locally.
Light, fluffy, and always free: Testcontainers for Java
No account. No auth token. No feature gates.

Maven Central CI License: MIT GitHub Stars

Quick Start · Configuration · Emulators · Docs


What is this?

Testcontainers modules for Floci, the free, open-source local cloud emulators. Each module starts a Floci emulator container for your integration tests and gives you an endpoint and credentials to point the cloud SDK at, plus a typed, per-service configuration API over the emulator's environment variables. No cloud account, no auth token.

Module Description
testcontainers-floci Starts a Floci (AWS) container: FlociContainer
testcontainers-floci-az Starts a Floci Azure container: FlociAzContainer
testcontainers-floci-core Shared base classes of the modules above (not used directly)
spring-boot-testcontainers-floci (decommissioned) Superseded by Spring Cloud AWS's own testcontainers module

The Floci emulators

testcontainers-floci is the Java member of the Floci Testcontainers family. Floci is named after floccus, the cloud formation that looks like popcorn.

Emulator Cloud Port Supported
floci AWS 4566 ✅ testcontainers-floci
floci-az Azure 4577 ✅ testcontainers-floci-az
floci-gcp GCP 4588 Planned
floci-oci OCI 4599 Planned

Installation

Version compatibility

testcontainers-floci Spring Boot integration Testcontainers Release badges
2.x via spring-cloud-aws-testcontainers (4.1.0+) 2.x Maven Central
1.x spring-boot-testcontainers-floci (Spring Boot 3.5.x / Spring Cloud AWS 3.4.x) 1.x Maven Central

AWS: testcontainers-floci

Maven:

<dependency>
    <groupId>io.floci</groupId>
    <artifactId>testcontainers-floci</artifactId>
    <version>${testcontainers-floci.version}</version>
    <scope>test</scope>
</dependency>

Gradle (Kotlin DSL):

testImplementation("io.floci:testcontainers-floci:${testcontainersFlociVersion}")

Gradle (Groovy DSL):

testImplementation "io.floci:testcontainers-floci:${testcontainersFlociVersion}"

Azure: testcontainers-floci-az

<dependency>
    <groupId>io.floci</groupId>
    <artifactId>testcontainers-floci-az</artifactId>
    <version>${testcontainers-floci.version}</version>
    <scope>test</scope>
</dependency>

Spring Boot integration

spring-boot-testcontainers-floci has been decommissioned on main and is no longer published for testcontainers-floci 2.x. The same @ServiceConnection integration between FlociContainer and Spring Cloud AWS is now provided directly by the Spring Cloud AWS project itself, via its own spring-cloud-aws-testcontainers module, starting from Spring Cloud AWS 4.1.0. Depend on that module instead:

<dependency>
    <groupId>io.awspring.cloud</groupId>
    <artifactId>spring-cloud-aws-testcontainers</artifactId>
    <version>4.1.0</version>
    <scope>test</scope>
</dependency>

It is still used together with testcontainers-floci (for FlociContainer itself) — only the Spring Boot glue code moves to Spring Cloud AWS. See the Spring Cloud AWS documentation for usage details.

The 1.x line (Spring Boot 3.x / Spring Cloud AWS 3.4.x) still ships spring-boot-testcontainers-floci on the releases/1.x branch and is unaffected by this change.

Quick start

AWS (Java)

import io.floci.testcontainers.FlociContainer;
import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

import java.net.URI;

import static org.assertj.core.api.Assertions.assertThat;

@Testcontainers
class S3IntegrationTest {

    @Container
    static FlociContainer floci = new FlociContainer();

    @Test
    void shouldCreateBucket() {
        S3Client s3 = S3Client.builder()
                .endpointOverride(URI.create(floci.getEndpoint()))
                .region(Region.of(floci.getRegion()))
                .credentialsProvider(StaticCredentialsProvider.create(
                        AwsBasicCredentials.create(floci.getAccessKey(), floci.getSecretKey())))
                .forcePathStyle(true)
                .build();

        s3.createBucket(b -> b.bucket("my-bucket"));

        var buckets = s3.listBuckets().buckets();
        assertThat(buckets).anyMatch(b -> b.name().equals("my-bucket"));
    }
}

AWS (Kotlin)

import io.floci.testcontainers.FlociContainer
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.testcontainers.junit.jupiter.Container
import org.testcontainers.junit.jupiter.Testcontainers
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider
import software.amazon.awssdk.regions.Region
import software.amazon.awssdk.services.s3.S3Client
import java.net.URI

@Testcontainers
class S3IntegrationTest {

    companion object {
        @Container
        @JvmStatic
        val floci = FlociContainer()
    }

    @Test
    fun `should create bucket`() {
        val s3 = S3Client.builder()
            .endpointOverride(URI.create(floci.getEndpoint()))
            .region(Region.of(floci.getRegion()))
            .credentialsProvider(
                StaticCredentialsProvider.create(
                    AwsBasicCredentials.create(floci.accessKey, floci.secretKey)
                )
            )
            .forcePathStyle(true)
            .build()

        s3.createBucket { it.bucket("my-bucket") }

        val buckets = s3.listBuckets().buckets()
        assertThat(buckets).anyMatch { it.name() == "my-bucket" }
    }
}

Azure

@Testcontainers
class BlobStorageTest {

    @Container
    static FlociAzContainer floci = new FlociAzContainer();

    @Test
    void shouldUploadBlob() {
        BlobServiceClient blobs = new BlobServiceClientBuilder()
                .connectionString(floci.getStorageConnectionString())
                .buildClient();

        BlobClient blob = blobs.createBlobContainer("my-container").getBlobClient("hello.txt");
        blob.upload(BinaryData.fromString("hello"));

        assertThat(blob.downloadContent().toString()).isEqualTo("hello");
    }
}

Storage data planes live under account-prefixed paths of the default account devstoreaccount1 (getBlobEndpoint(), getQueueEndpoint(), getTableEndpoint()); ARM management calls go to getEndpoint() + "/subscriptions/" + getSubscriptionId() + ....

Service configuration

AWS

Method Description
FlociContainer() Creates a container with the default image (floci/floci:latest)
FlociContainer(String) Creates a container with a custom image tag
withRegion(String) Sets the AWS region (default: us-east-1)
withDefaultAvailabilityZone(String) Sets the default availability zone (default: us-east-1a)
withDefaultAccountId(String) Sets the default AWS account ID (default: 000000000000)
withLogLevel(Level) Sets the Floci log level (TRACE, DEBUG, INFO, WARN, ERROR)
withAiMockConfigFile(String) Points the fixed-stub AI services (Textract, Comprehend, Rekognition, Translate) at a container mock file
withAiMockConfig(String) Same, but takes the mock-response file content and copies it into the container for you
withDedicatedNetwork() Creates a dedicated Docker network shared by Floci and its sibling containers (RDS, Lambda, ElastiCache, etc.)
withDockerSocket(boolean) Overrides whether the host Docker socket is mounted, bypassing auto-detection (see below)
withTlsConfig(...) Configures TLS/HTTPS (self-signed by default; optionally provide cert/key paths)
withStorageConfig(...) Configures persistent storage and volume behaviour
withSecurityConfig(...) Configures security settings (CORS, private JWT issuer targets, network exposure)
withProtocolsConfig(...) Configures RPC wire-protocol handling (e.g. strict protocol claiming)
withAuthConfig(...) Configures authentication settings (e.g. SigV4 signature validation, presign secret)
withInitHooksConfig(...) Configures lifecycle init hook execution (shell, timeouts)
withPartitionsConfig(...) Configures the served AWS partition and partition/region strictness
withNetworkConfig(...) Configures network settings (e.g. security-group enforcement for EC2/ECS containers)
with*Config(...) Configures service-specific settings

Each AWS service emulated by Floci can be individually configured via a with*Config(...) method on FlociContainer. Every service configuration supports at least an enabled(boolean) flag to enable or disable the service. Some services expose additional settings. See the Floci documentation for the full list of supported services.

Example — disable a service and customize another:

FlociContainer floci = new FlociContainer()
    .withSqsConfig(c -> c.defaultVisibilityTimeout(60).maxMessageSize(131072))
    .withDynamoDbConfig(c -> c.enabled(false));

Docker socket

Some services (RDS, Lambda, ElastiCache, ECS, and others) spin up sibling Docker containers and need access to the host Docker socket. FlociContainer mounts the socket automatically, but only when at least one currently enabled service actually needs it — e.g. a container that only uses S3/SQS/DynamoDB never gets the socket mounted once the Docker-backed services are disabled (all services are enabled by default).

Use withDockerSocket(boolean) to override this auto-detection entirely, regardless of which services are enabled:

// Never mount the socket, e.g. on hosts where mounting it doesn't work
// (such as rootless Podman with SELinux) and no Docker-backed service is needed
FlociContainer floci = new FlociContainer().withDockerSocket(false);

// Always mount the socket, even if no currently enabled service is detected as needing it
FlociContainer floci = new FlociContainer().withDockerSocket(true);

Azure

Method Description
FlociAzContainer() Creates a container with the default image (floci/floci-az:latest)
FlociAzContainer(String) Creates a container with a custom image tag
withLogLevel(Level) Sets the Floci Azure log level (TRACE, DEBUG, INFO, WARN, ERROR)
withDedicatedNetwork() Creates a dedicated Docker network shared by Floci Azure and the containers it spawns
withDockerSocket(boolean) Overrides whether the host Docker socket is mounted, bypassing auto-detection
withTlsConfig(...) Configures TLS/HTTPS (self-signed by default; optionally provide cert/key paths)
withAuthConfig(...) Configures authentication, e.g. keys of additional storage accounts used to validate SAS tokens
with*Config(...) Configures service-specific settings, e.g. withServiceBusConfig(c -> c.mocked(false))

Docker-backed services (Functions, AKS, Container Registry, Redis, Event Hubs, Service Bus, SQL Database, PostgreSQL, MySQL, MariaDB, Cosmos DB API engines, Container Instances, Virtual Machines, Container Apps) mount the host Docker socket automatically while they are enabled and not mocked, exactly like the AWS module. Their sidecar containers publish their ports directly on the Docker host; the port ranges they use default to 10 ports each (e.g. withAksConfig(c -> c.apiServerPortRange(6443, 10))).

HTTPS

Several Azure SDKs (Key Vault, App Configuration, Communication Services, Cosmos DB) only talk HTTPS. Enable TLS and let the client trust the certificate Floci Azure serves; HTTP and HTTPS share the same port:

FlociAzContainer floci = new FlociAzContainer().withTlsConfig(c -> c.enabled(true));
floci.start();

String certificatePem = floci.getTlsCertificate();      // add it to the trust store of your HTTP client
SecretClient secrets = new SecretClientBuilder()
        .vaultUrl(floci.getHttpsEndpoint() + "/devstoreaccount1-keyvault")
        // ...
        .buildClient();

Note: Floci Azure generates some URLs (e.g. the polling URL of long-running Email operations) from its own base URL http://localhost:4577, which does not match the randomly mapped host port of the container. Clients following such URLs need to rewrite them to getEndpoint()/getHttpsEndpoint().

Container options

AWS

Method Description Default
getEndpoint() HTTP endpoint URL (e.g. http://localhost:32781) —
getRegion() Configured AWS region us-east-1
getDefaultAvailabilityZone() Configured default availability zone us-east-1a
getDefaultAccountId() Configured default AWS account ID 000000000000
getAccessKey() AWS access key test
getSecretKey() AWS secret key test
getLogLevel() Configured log level WARN
getDedicatedNetworkName() Name of the dedicated Docker network, or null if not configured null
getTlsConfig() Current TLS configuration —
getStorageConfig() Current storage configuration —
getSecurityConfig() Current security configuration —
getProtocolsConfig() Current protocols configuration —
getAuthConfig() Current auth configuration —
getInitHooksConfig() Current init hooks configuration —
getPartitionsConfig() Current partitions configuration —
getNetworkConfig() Current network configuration —
get*Config() Current configuration of a service —

Azure

Method Description Default
getEndpoint() HTTP endpoint URL (e.g. http://localhost:32781) —
getHttpsEndpoint() HTTPS endpoint URL (requires TLS to be enabled) —
getTlsCertificate() PEM certificate served for HTTPS (requires TLS to be enabled) —
getAccountName() Default storage account devstoreaccount1
getAccountKey() Key of the default storage account well-known development storage key
getBlobEndpoint() Blob Storage endpoint of the default account —
getQueueEndpoint() Queue Storage endpoint of the default account —
getTableEndpoint() Table Storage endpoint of the default account —
getStorageConnectionString() Connection string for Blob, Queue and Table Storage —
getSubscriptionId() Default subscription id (withArmConfig(...)) 00000000-0000-0000-0000-000000000001
getTenantId() Default Microsoft Entra ID tenant id (withEntraConfig(...)) 00000000-0000-0000-0000-000000000002
getLogLevel() Configured log level WARN
get*Config() Current configuration of a service or of TLS/auth —

Docker image tags

By default each module runs the floating latest tag of its emulator image (floci/floci:latest, floci/floci-az:latest), so you always test against the current emulator. Pass an image name to the constructor to pin a release or follow main:

new FlociContainer("floci/floci:x.y.z");      // a specific release
new FlociAzContainer("floci/floci-az:nightly"); // built from main every night

Every emulator publishes latest, x.y.z and nightly tags.

Requirements

  • Java 17+
  • Docker

Building and testing

mvn -B verify                                              # all modules, unit and integration tests
mvn -pl testcontainers-floci test -Dtest=IamConfigTest     # a single test class

There is no separate integration-test phase: mvn verify starts real Floci containers, so Docker must be running. See CONTRIBUTING.md for the project layout, the branching model, and how to add a service.

Other languages

Language Repository
Java testcontainers-floci (this repo)
Node.js / TypeScript testcontainers-floci-node
Python testcontainers-floci-python
Go testcontainers-floci-go
.NET testcontainers-floci-dotnet

Community

License

MIT. See LICENSE.


Floci™ is a trademark of Hector Ventura. Code is MIT-licensed; see TRADEMARK.md for name and logo use.

About

Light, fluffy, and always free - Testcontainers for Java: run the Floci local AWS and Azure emulators in your integration tests.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

65 stars

Watchers

3 watching

Forks

Releases

Used by

Contributors

Languages