Documentation
Storage
In-memory object storage modelled on S3, Azure Blob Storage, GCS, and OCI Object Storage, driven with the real cloud SDKs
aws S3azr Blob Storagegcp GCSoci Object Storage
Emulates managed object storage — the S3/Blob/GCS bucket where your app keeps uploads, exports, and config blobs. You create named buckets, then put, get, list, and copy objects as byte payloads with a content type and metadata. Everything lives in memory, so a test run starts from an empty store and leaves nothing behind.
Reach for it whenever your code writes a file to a bucket and reads it back, paginates a listing, or copies objects between prefixes — so you can exercise those paths without a real S3 account or network. Because the SDK-compat server speaks the real wire protocol, your production upload/download code runs unchanged against it.
| Provider | Service | SDK-compat | Driver |
|---|---|---|---|
| AWS | S3 | ✓ Live | aws.S3 |
| Azure | Blob Storage | ✓ Live | azure.BlobStorage |
| GCP | GCS | ✓ Live | gcp.GCS |
| OCI | Object Storage | ✓ Live | oci.ObjectStorage |
Drive it with the real SDK#
Run cloudemu as a server and point your existing production code at it — the same client, with only the endpoint redirected. Start it with cloudemu serve (or docker run --rm -p 4566:4566 ghcr.io/stackshy/cloudemu), which serves the AWS API on http://localhost:4566:
cloudemu serve # AWS API on http://localhost:4566Then create the stock S3 client, point it at that endpoint, and create a bucket, write an object, and read it back exactly as the real client would:
import (
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
client := s3.NewFromConfig(cfg, func(o *s3.Options) {
o.BaseEndpoint = aws.String("http://localhost:4566")
o.UsePathStyle = true
})
client.CreateBucket(ctx, &s3.CreateBucketInput{Bucket: aws.String("my-bucket")})
client.PutObject(ctx, &s3.PutObjectInput{
Bucket: aws.String("my-bucket"),
Key: aws.String("config.yaml"),
Body: bytes.NewReader([]byte("port: 8080")),
})
out, _ := client.GetObject(ctx, &s3.GetObjectInput{
Bucket: aws.String("my-bucket"), Key: aws.String("config.yaml"),
})The same pattern works with armappservice / azblob (Azure) and cloud.google.com/go/storage (GCP). See the SDK-Compat Server page for full quick starts per provider.
In-process (Go unit tests)#
For Go unit tests written inside cloudemu-aware code, stand the same wire server up in-process with httptest.NewServer and point the client at ts.URL. The Drivers you pass name exactly the drivers this service needs:
import (
"github.com/stackshy/cloudemu/v2"
awsserver "github.com/stackshy/cloudemu/v2/server/aws"
)
cloud := cloudemu.NewAWS()
ts := httptest.NewServer(awsserver.New(awsserver.Drivers{S3: cloud.S3}))
defer ts.Close()
// point the same s3 client at ts.URL instead of the running endpointCall the driver directly#
When you don't need to drive a real SDK — for example in cloudemu-only setup code — skip the HTTP hop and call the driver. The same three operations, minus the client boilerplate:
aws.S3.CreateBucket(ctx, "my-bucket")
aws.S3.PutObject(ctx, "my-bucket", "config.yaml", []byte("..."), "text/yaml", nil)
obj, _ := aws.S3.GetObject(ctx, "my-bucket", "config.yaml")PutObject's last two arguments are the content type and an optional metadata map (pass nil for none). GetObject returns the object with its data and info; a missing bucket or key returns an error.
Behavior & fidelity#
| Behavior | What happens |
|---|---|
| Listings paginate and group | ListObjectsV2 honours prefix, delimiter (with common prefixes), MaxKeys, and a continuation token — the paging contract your listing loop expects. |
| Server-side copy | CopyObject duplicates the object and its metadata into the destination without a round-trip through your process. |
| Portable-API-only extras | Multipart upload, presigned URLs, lifecycle policies, versioning, tagging, CORS, and encryption config are driver-only — reach for them through the Portable Go API. |
SDK-compat — Live#
Real S3, Blob, and GCS clients drive object storage end-to-end — see SDK-Compat for the full operation list.