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. UpdateFunction(ctx, name, config) patches an existing function's configuration in place and returns the updated FunctionInfo.

Behavior & fidelity#

BehaviorWhat happens
Invoke runs your handlerA function with no handler registered via RegisterHandler has nothing to execute; the handler's returned bytes come straight back as the invocation payload.
Handler errors are invocation errorsAn error from the handler is reported on the invocation result, not as a transport failure — the same way the real services separate a function error from a call failure.
GCP create/delete are long-runningCloud 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 extrasLayers and reserved/provisioned concurrency are not yet on the SDK-compat layer — reach for them through the Portable Go API.

SDK-compat — Live#

Real lambda, armappservice, and cloudfunctions/v1 clients drive the emulator end-to-end:

ProviderCoverage
AWS LambdaFunction CRUD, versions, aliases, event source mappings, resource policy, tagging, sync invoke
Azure FunctionsFunction-app CRUD plus HTTP invoke
GCP Cloud FunctionsCreate/Delete LROs, get, list, synchronous call

See SDK-Compat for the full per-operation list.

On this page

On this page