Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ containers to make testing nice for Ebean ORM, see https://ebean.io/docs/testing

## Supported Containers

Postgres, ClickHouse, CockroachDB, DB2, ElasticSearch, Hana, LocalDynamoDB, Localstack, MariaDB, MySql, NuoDB, Oracle, Postgres, Redis, SqlServer, Yugabyte.
Postgres, ClickHouse, CockroachDB, DB2, ElasticSearch, Floci, Hana, LocalDynamoDB, Localstack, MariaDB, MySql, NuoDB, Oracle, Postgres, Redis, SqlServer, Yugabyte.

## Dependency

Expand Down Expand Up @@ -211,6 +211,25 @@ occurring automatically on JVM shutdown.

```

#### Floci - `hectorvent/floci`

```java
FlociContainer container = FlociContainer.builder("latest")
.services("dynamodb,kinesis,sns,sqs,s3,kms")
//.awsRegion("ap-southeast-2")
//.port(4566)
//.image("hectorvent/floci:latest")
.start();

AwsSDKv2 sdk = container.sdk2();
DynamoDbClient dynamoDb = sdk.dynamoDBClient();
SqsClient sqs = sdk.sqsClient();
SnsClient sns = sdk.snsClient();

// setup - create dynamoDB tables, queues etc

```

#### LocalDynamoDB - `amazon/dynamodb-local`

```java
Expand Down Expand Up @@ -319,4 +338,3 @@ occurring automatically on JVM shutdown.
Refer to the ebean testing documentation (https://ebean.io/docs/testing/) ...
where we use ebean-test to hook into the Ebean lifecycle and automatically
start the docker containers as needed (prior to running tests etc).

207 changes: 207 additions & 0 deletions src/main/java/io/ebean/test/containers/FlociContainer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
package io.ebean.test.containers;

import java.io.IOException;
import java.lang.System.Logger.Level;
import java.net.URI;
import java.util.List;
import java.util.Properties;

/**
* Floci container that supports AWS SDK v2.
*
* <pre>{@code
*
* FlociContainer container = FlociContainer.builder("latest")
* // .port(4566)
* // .image("hectorvent/floci:latest")
* .build();
*
* container.start();
*
* AwsSDKv2 sdk = container.sdk2();
* var amazonDynamoDB = sdk.dynamoDBClient();
* createTable(amazonDynamoDB);
*
* }</pre>
*/
public class FlociContainer extends BaseContainer<FlociContainer> {

@Override
public FlociContainer start() {
startOrThrow();
return this;
}

/**
* Create a builder for FlociContainer given the Floci image version.
*/
public static Builder builder(String version) {
return new Builder(version);
}

/**
* Builder for FlociContainer.
*/
public static class Builder extends BaseBuilder<FlociContainer, Builder> {

private String services = "dynamodb";
private String awsRegion = "ap-southeast-2";
private String healthUri = "_floci/health";

/**
* Create with a version of hectorvent/floci (example, latest)
*/
private Builder(String version) {
super("floci", 4566, 4566, version);
this.image = "hectorvent/floci:" + version;
}

@Override
protected void extraProperties(Properties properties) {
super.extraProperties(properties);
services = prop(properties, "services", services);
awsRegion = prop(properties, "awsRegion", awsRegion);
healthUri = prop(properties, "healthUri", healthUri);
}

/**
* Set the services desired (comma delimited). Defaults to "dynamodb".
* <p>
* Examples: "dynamodb", "dynamodb,sns,sqs,kinesis"
*/
public Builder services(String services) {
this.services = services;
return self();
}

/**
* Set the AWS region to use. For example, "ap-southeast-2".
*/
public Builder awsRegion(String awsRegion) {
this.awsRegion = awsRegion;
return self();
}

/**
* Set the healthUri option - defaults to _floci/health.
*/
public Builder healthUri(String healthUri) {
this.healthUri = healthUri;
return self();
}

/**
* Build and return the FlociContainer to then start().
*/
public FlociContainer build() {
return new FlociContainer(this);
}

@Override
public FlociContainer start() {
return build().start();
}
}

private final List<String> serviceNames;
private final String awsRegion;
private final String healthUri;

/**
* Create the container using the given config.
*/
public FlociContainer(Builder builder) {
super(builder);
this.awsRegion = builder.awsRegion;
this.healthUri = builder.healthUri;
this.serviceNames = TrimSplit.split(builder.services);
}

private String healthUrl() {
return String.format("http://%s:%s/%s", config.getHost(), config.getPort(), healthUri);
}

/**
* Return the AWS v2 SDK compatible helper that provides API for
* DynamoDB client, SnsClient, SqsClient etc.
*/
public AwsSDKv2 sdk() {
return sdk2();
}

/**
* Return the AWS v2 SDK compatible helper that provides API for
* DynamoDB client, SnsClient, SqsClient etc.
*/
public AwsSDKv2 sdk2() {
return new LocalstackSdkV2(awsRegion, endpoint());
}

/**
* Return the endpoint as URI.
*/
public URI endpoint() {
return URI.create(endpointUrl());
}

/**
* Return the endpoint as String.
*/
public String endpointUrl() {
return String.format("http://%s:%s/", config.getHost(), config.getPort());
}

/**
* Return the AWS region.
*/
public String awsRegion() {
return awsRegion;
}

@Override
boolean checkConnectivity() {
try {
String content = readUrlContent(healthUrl());
if (log.isLoggable(Level.TRACE)) {
log.log(Level.TRACE, "checkConnectivity content: {0}", content);
}
return checkStatus(content);
} catch (IOException e) {
return false;
}
}

private boolean checkStatus(String content) {
String[] serviceEntries = content.split(",");
for (String serviceName : serviceNames) {
if (!isServiceReady(serviceName, serviceEntries)) {
return false;
}
}
return true;
}

private boolean isServiceReady(String serviceName, String[] serviceEntries) {
String key = "\"" + serviceName + "\":";
for (String serviceEntry : serviceEntries) {
if (serviceEntry.contains(key) && (serviceEntry.contains("\"running\"") || serviceEntry.contains("\"available\""))) {
return true;
}
}
return false;
}

protected ProcessBuilder runProcess() {
List<String> args = dockerRun();
if (config.getAdminPort() > 0) {
args.add("-p");
args.add(config.getAdminPort() + ":" + config.getAdminInternalPort());
}
if (notEmpty(awsRegion)) {
args.add("-e");
args.add("FLOCI_DEFAULT_REGION=" + awsRegion);
}
args.add(config.image());
return createProcessBuilder(args);
}
}
Loading
Loading