Skip to content
cloudemu
Services

Serverless

In-memory functions-as-a-service modelled on Lambda, Azure Functions, and Cloud Functions, driven with the real cloud SDKs

aws Lambdaazr Functionsgcp Cloud Functions

Emulates functions-as-a-service — the Lambda/Azure Functions/Cloud Functions control plane where you create a function and invoke it with a payload. Instead of deploying a zip, you register a plain Go function as the handler; an Invoke then runs it in-process and returns its response bytes. That keeps the create/invoke path fast and deterministic while still exercising your production wiring.

Reach for it in tests when your code creates a function, invokes it synchronously, and reads the response — for example verifying an orchestration that fans out to Lambdas, or a caller that depends on a function's output shape — without deploying to a real cloud. You get the function's response back exactly as the SDK would deliver it.

ProviderServiceSDK-compatDriver
AWSLambda (REST + JSON)✓ Liveaws.Lambda
AzureFunctions (Function Apps + /api/{name} invoke)✓ Liveazure.Functions
GCPCloud Functions v1 (Create LRO + :call)✓ Livegcp.CloudFunctions

Drive it with the real SDK#

The recommended path is to point the real SDK at the SDK-compat server. Because there's no real runtime, you register a Go handler so Invoke has something to execute — then the stock Lambda client creates and calls the function unchanged:

import (
    "github.com/aws/aws-sdk-go-v2/service/lambda"
    lambdatypes "github.com/aws/aws-sdk-go-v2/service/lambda/types"
    awsserver "github.com/stackshy/cloudemu/v2/server/aws"
)

cloud := cloudemu.NewAWS()
ts := httptest.NewServer(awsserver.New(awsserver.Drivers{Lambda: cloud.Lambda}))

client := lambda.NewFromConfig(cfg, func(o *lambda.Options) {
    o.BaseEndpoint = aws.String(ts.URL)
})

client.CreateFunction(ctx, &lambda.CreateFunctionInput{
    FunctionName: aws.String("my-handler"),
    Runtime:      lambdatypes.RuntimeGo1x,
    Role:         aws.String("arn:aws:iam::000000000000:role/test"),
    Handler:      aws.String("main"),
    Code:         &lambdatypes.FunctionCode{ZipFile: []byte("z")},
})

// Register a Go handler so Invoke has something to run.
cloud.Lambda.RegisterHandler("my-handler", func(ctx context.Context, payload []byte) ([]byte, error) {
    return []byte(`{"status":"ok"}`), nil
})

resp, _ := client.Invoke(ctx, &lambda.InvokeInput{
    FunctionName: aws.String("my-handler"),
    Payload:      []byte(`{"key":"value"}`),
})
fmt.Println(string(resp.Payload)) // {"status":"ok"}

Same shape with armappservice (Azure) and google.golang.org/api/cloudfunctions/v1 (GCP) — see SDK-Compat Server.

Call the driver directly#

For in-process setup you can skip the HTTP hop. The flow is the same three steps — create, register a handler, invoke — with the driver's own input structs:

import sdriver "github.com/stackshy/cloudemu/v2/services/serverless/driver"

aws.Lambda.CreateFunction(ctx, sdriver.FunctionConfig{
    Name: "my-handler", Runtime: "go1.x", Handler: "main",
})
aws.Lambda.RegisterHandler("my-handler", func(_ context.Context, p []byte) ([]byte, error) {
    return []byte(`{"ok":true}`), nil
})
out, _ := aws.Lambda.Invoke(ctx, sdriver.InvokeInput{
    FunctionName: "my-handler", Payload: []byte(`{}`),
})

Invoke returns an InvokeOutput carrying the status code, response payload, and any handler error string.

Behavior & fidelity#

  • Invoke runs your registered handler. A function created but never given a handler via RegisterHandler has nothing to execute; register one keyed by function name before invoking. The handler's returned bytes come straight back as the invocation payload.
  • Handler errors surface as invocation errors. An error returned from the handler is reported on the invocation result rather than as a transport failure — matching how the real services distinguish a function error from a call failure.
  • GCP create/delete are long-running. Cloud Functions Create and Delete return an LRO you poll via Operations.Get, mirroring the real v1 API; :call is the synchronous invoke.
  • Portable-API-only extras. The driver also exposes surface not yet on the SDK-compat layer — published versions, weighted aliases, layers, reserved/provisioned concurrency, and event source mappings. Reach for these through the Portable Go API when a test needs them.
  • SDK-compat status — Live. Lambda (CreateFunction, GetFunction, ListFunctions, DeleteFunction, sync Invoke), Azure Functions (Microsoft.Web/sites CRUD + /api/{name} invoke), and GCP Cloud Functions (Create/Delete LROs, Get, List, :call) all work through the real SDKs. See SDK-Compat for the full surface.

On this page

On this page