Floci¶
dev.rightsize.modules.FlociContainer — a floci.io cloud
emulator: one native Quarkus image per cloud provider, each speaking that
provider's REST APIs against an in-memory backing store. One module class covers
all three variants; pick one with the aws()/azure()/gcp() factory functions
rather than the constructor directly — each factory pins the provider's own image
and guest port.
Defaults¶
| Default images | floci/floci:1.5.30 (AWS), floci/floci-az:0.8.0 (Azure), floci/floci-gcp:0.4.0 (GCP) |
| Exposed ports | 4566 (AWS), 4577 (Azure), 4588 (GCP) — one per variant |
| Wait strategy | Wait.forHttp("/health").forPort(<variant port>) |
Helpers¶
| Member | Returns |
|---|---|
FlociContainer.aws(image: String = "floci/floci:1.5.30"): FlociContainer |
The AWS emulator — S3, DynamoDB, SQS, etc. |
FlociContainer.azure(image: String = "floci/floci-az:0.8.0"): FlociContainer |
The Azure emulator |
FlociContainer.gcp(image: String = "floci/floci-gcp:0.4.0"): FlociContainer |
The GCP emulator |
endpointUrl: String |
This variant's REST endpoint — the base URI for every emulated API call |
There's no constructor to call directly — always go through one of the three factory functions, which pin the right image and guest port for that provider.
Example¶
package dev.rightsize.modules
import dev.rightsize.modules.FlociContainer
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
import java.net.http.HttpResponse
class FlociContainerTest {
private val http = HttpClient.newHttpClient()
@Test
fun `AWS variant S3 create-bucket, put, and get round-trips with no request signing`() {
val floci = FlociContainer.aws()
floci.start()
try {
val put = http.send(
HttpRequest.newBuilder(URI("${floci.endpointUrl}/rightsize-test-bucket"))
.PUT(HttpRequest.BodyPublishers.noBody()).build(),
HttpResponse.BodyHandlers.discarding(),
)
assertEquals(200, put.statusCode(), "create-bucket failed")
val putObj = http.send(
HttpRequest.newBuilder(URI("${floci.endpointUrl}/rightsize-test-bucket/hello.txt"))
.PUT(HttpRequest.BodyPublishers.ofString("hello world")).build(),
HttpResponse.BodyHandlers.discarding(),
)
assertEquals(200, putObj.statusCode(), "put-object failed")
val getObj = http.send(
HttpRequest.newBuilder(URI("${floci.endpointUrl}/rightsize-test-bucket/hello.txt")).GET().build(),
HttpResponse.BodyHandlers.ofString(),
)
assertEquals(200, getObj.statusCode(), "get-object failed")
assertEquals("hello world", getObj.body())
} finally {
floci.stop()
}
}
}
Backend notes¶
/health works uniformly across all three variants — the AWS-flavored
/_localstack/health doesn't carry over. The AWS variant ships a
LocalStack-compatible /_localstack/health endpoint, but the Azure and GCP variants
do not carry that path (Azure: 501; GCP: 404). All three, however, answer a
plain GET /health with 200 and a small JSON status body the moment the embedded
Quarkus HTTP listener is up — verified directly against real boots of
floci/floci:1.5.30, floci/floci-az:0.8.0, and floci/floci-gcp:0.4.0. /health
is pinned as the one wait path that works across all three variants; no log-wait
fallback was needed.
No signing needed — verified against the AWS variant's S3 surface. The AWS
variant's S3-shaped REST endpoints accept unsigned requests with no
Authorization header at all: PUT /<bucket>, PUT /<bucket>/<key>, and
GET /<bucket>/<key> all round-trip successfully with a bare HttpClient call —
no SigV4, no AWS SDK dependency required. This module's IT exercises that plain-REST
path rather than pulling in the AWS SDK.
No withMemoryLimit override is needed for any variant — all three images are
native (GraalVM) Quarkus binaries that settle at roughly 11–27 MiB RSS (docker
stats, real boot), and each boots and answers /health under msb's default
microVM RAM with no memory-ladder escalation.