Skip to content
cloudemu

Portable API

Wrap any driver with recording, metrics, rate limiting, and error injection

Wrap any driver with recording, metrics, rate limiting, latency, and error injection — no HTTP involved. Every service category has its own portable wrapper.

two surfaces, one backend

your testreal SDKHTTPsdk-compatyour testcloud.S3.PutObject(ctx, ...)direct callcloudemusame drivers · same state

Basic usage#

import (
    "github.com/stackshy/cloudemu/v2/services/storage"
    "github.com/stackshy/cloudemu/v2/features/recorder"
    "github.com/stackshy/cloudemu/v2/features/metrics"
    "github.com/stackshy/cloudemu/v2/features/inject"
    "github.com/stackshy/cloudemu/v2/features/ratelimit"
)

rec := &recorder.Recorder{}
mc := &metrics.Collector{}
inj := inject.NewInjector()
limiter := ratelimit.NewLimiter(100) // 100 requests/sec

bucket := storage.NewBucket(aws.S3,
    storage.WithRecorder(rec),
    storage.WithMetrics(mc),
    storage.WithErrorInjection(inj),
    storage.WithRateLimiter(limiter),
    storage.WithLatency(5 * time.Millisecond),
)

// Use bucket exactly like aws.S3 — same interface
bucket.CreateBucket(ctx, "my-bucket")
bucket.PutObject(ctx, "my-bucket", "key", data, "text/plain", nil)

How it works#

Every operation passes through a middleware chain:

  1. Error Injection — if configured, checks whether the call should fail
  2. Rate Limiting — if configured, checks the token bucket
  3. Latency — if configured, sleeps for the specified duration
  4. Driver Call — executes the actual operation
  5. Metrics — records calls_total, call_duration, errors_total
  6. Recording — logs service, operation, input, output, error, duration

Available wrappers#

Each service has its own portable type:

ServicePortable TypeImport
Storagestorage.Bucketcloudemu/v2/services/storage
Computecompute.Computecloudemu/v2/services/compute
Databasedatabase.Databasecloudemu/v2/services/database
Serverlessserverless.Serverlesscloudemu/v2/services/serverless
Monitoringmonitoring.Monitoringcloudemu/v2/services/monitoring
Message Queuemessagequeue.MessageQueuecloudemu/v2/services/messagequeue
And more...

All wrappers support the same set of With* options.

Cross-provider testing#

The portable API lets one test body run against all three providers:

func testStorage(t *testing.T, bucket *storage.Bucket) {
    ctx := context.Background()
    bucket.CreateBucket(ctx, "test")
    bucket.PutObject(ctx, "test", "key", []byte("value"), "text/plain", nil)

    obj, err := bucket.GetObject(ctx, "test", "key")
    assert.NoError(t, err)
    assert.Equal(t, []byte("value"), obj.Data)
}

func TestAWS(t *testing.T) {
    testStorage(t, storage.NewBucket(cloudemu.NewAWS().S3))
}

func TestAzure(t *testing.T) {
    testStorage(t, storage.NewBucket(cloudemu.NewAzure().BlobStorage))
}

func TestGCP(t *testing.T) {
    testStorage(t, storage.NewBucket(cloudemu.NewGCP().GCS))
}

On this page

On this page