Help us shape the future of Go! Take the 2026 Go Developer Survey

squall

module
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 18, 2026 License: Apache-2.0

README

squall

CI Go Reference OpenSSF Scorecard

In-memory stand-ins for cloud APIs that fail on cue, for testing code that must survive partial failure.

Code that creates cloud resources has to cope with calls that fail after they took effect: an insert that succeeded but whose response was lost, an operation that ended in an error, a retry that finds the resource already there. Those paths are where leaked resources and stuck records come from, and they are hard to reach against a real cloud. A squall server answers the same API calls the official client libraries make, keeps the resources in memory, and fails exactly the calls you choose, or a seeded random share of them, so a failure replays from its seed.

Packages

Package What it does
fault Decides which calls fail and how: rejected, applied with the response lost, applied with an error, an operation that ends in an error, or slow. Scripted rules and a seeded random rate.
aws/ec2 Amazon EC2: instances (run with client tokens, describe with filters and pages, start, stop, terminate, change type), images, instance types, EBS volumes (create, describe, attach, detach, delete), placement groups, tags, Elastic IP addresses (allocate, describe, release, associate with an interface or instance, disassociate) and network interfaces (create with client tokens, describe, delete).
gcp/compute Compute Engine: regional addresses (get, list with filters, insert, delete, setLabels) and region operations.

Coverage grows with use: each stand-in implements the methods someone needed, answers anything else with 404, and documents how faithful it is. Contributions of more methods and services are welcome.

Example

faults := fault.New().Add(fault.Rule{
	Method: "compute.addresses.insert",
	Nth:    1,
	Fault:  fault.LoseResponse(), // takes effect, but the caller never hears back
})
s := compute.New(compute.WithFaults(faults))
srv := httptest.NewServer(s)
defer srv.Close()

client, _ := gcompute.NewAddressesRESTClient(ctx,
	option.WithEndpoint(srv.URL), option.WithoutAuthentication())

// Run the code under test with client, then check what it left behind:
for _, a := range s.Addresses() {
	fmt.Println(a.Name, a.Address, a.Labels)
}

For a property test, inject random faults and check that every seed converges:

for seed := range uint64(100) {
	faults := fault.New(fault.Seed(seed)).Random(0.3,
		fault.Unavailable(), fault.LoseResponse(), fault.FailAfter(500))
	// ... run the code under test against compute.New(compute.WithFaults(faults))
	// and on failure report the seed and faults.Injected().
}

Faithfulness

Each stand-in follows the real API's requests, response shapes and error codes for the methods it covers, and is tested through the official Go client library. Where it simplifies, the package documentation says so. For Compute Engine:

  • Long-running operations finish before the call that started them returns.
  • A call that repeats an earlier call's requestId in the same project, for the same method, gets that call's operation back without taking effect again, as the real API does for retries. The server keeps the last 10,000 operations.
  • List filters support field = value and field != value comparisons on name, description, status, address, addressType and labels, joined by AND or in parentheses. Lists are ordered by name. Anything else, such as a wildcard or orderBy=creationTimestamp desc, is rejected with 400 rather than ignored.
  • IP addresses come from 100.64.0.0/10 (external) and 10.0.0.0/8 (internal), never from routable ranges. An external address is unique across every project and region; an internal one is unique within its region, which stands in for its subnetwork.
  • A fault rule's Resource for an insert is the resource being created, so a rule can target the insert of one name.

For Amazon EC2:

  • Signatures are not checked. The region comes from the SigV4 credential scope, and each region keeps its own resources.
  • Subnet and security group IDs and key pair names are not validated, and there are no VPCs, default or otherwise: RunInstances needs a subnet or a network interface. Images are registered by the test with PutImage; instance types come from a small built-in set or PutInstanceType.
  • RunInstances records metadata, private DNS name and CPU options, and the primary interface's type (interface or efa; with an existing interface, only that interface's type) and network card index (only 0, the same launch as leaving it out); DescribeInstances returns them, with metadata options pending until the instance first settles. EFA and AMD SEV-SNP are not checked against the instance type. CPU options take up to the type's default cores and threads per core, which DescribeInstanceTypes reports, and any core count from 1 up, where EC2 accepts only the counts it lists for each type.
  • Instances and volumes move through EC2's states when describes see them. By default the first DescribeInstances or DescribeVolumes after a change shows the state it settles in, so the SDK's waiters return at once; WithSettleAfter holds them in transition for more describes, or until the test calls Settle. Describes are consistent at once, not eventually.
  • Terminated instances stay visible, as in EC2, until the test calls ForgetInstance. Termination deletes the interface and volumes marked to delete on termination and releases the rest.
  • A CreateNetworkInterface, RunInstances or CreateVolume that repeats a ClientToken with the same parameters gets what the first call created, as the real API does for retries; with other parameters it fails with IdempotentParameterMismatch.
  • Filters take EC2's * and ? wildcards. Filter names and parameters the stand-in does not support are rejected with 400 rather than ignored.
  • Public IP addresses come from 100.64.0.0/10 and private ones from 10.0.0.0/8. There is no address quota unless the test sets one.
  • EC2 has no long-running operations, so a failed operation fails the call before it takes effect. A fault's reason is the EC2 error code it answers with, and the generic ones become InternalError, Unavailable and RequestLimitExceeded. A fault rule's Resource is the region and ID, such as us-east-1/eipalloc-…, and for a create, the resource being created (the first instance, for RunInstances). A rejected call has no effect, so a rejected describe does not move an instance along.

Requirements

Go 1.27 or later. The module requires nothing beyond the standard library; the tests that use the official client libraries live in the separate sdktest module.

Contributing

See CONTRIBUTING.md. Security issues: SECURITY.md.

License

Apache 2.0.

Directories

Path Synopsis
aws
ec2
Package ec2 is a stand-in for the Amazon EC2 API, for testing code that calls it through the official SDKs.
Package ec2 is a stand-in for the Amazon EC2 API, for testing code that calls it through the official SDKs.
Package fault decides which API calls a stand-in server fails, and how.
Package fault decides which API calls a stand-in server fails, and how.
gcp
compute
Package compute is a stand-in for the Compute Engine API, for testing code that calls it through the official client libraries.
Package compute is a stand-in for the Compute Engine API, for testing code that calls it through the official client libraries.
internal
stub
Package stub runs a stand-in's calls under the faults the injector decides.
Package stub runs a stand-in's calls under the faults the injector decides.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL