Documentation ¶
Overview ¶
Package gosim contains the main API for interacting with Gosim simulations. Gosim is a simulation testing framework that aims to make it easier to write reliable distributed systems code in go. See the README.md file for an introduction to Gosim.
Introduction ¶
Distributed systems can fail in many surprising ways. Exhaustively thinking of all things that can go wrong and writing tests for them is infeasible. Gosim simulates the external components that a program might interact with, such as the disk, network, clocks, and more. Gosim has an API to introduce failures in these systems (like chaos testing) to test that a program can handle otherwise difficult-to-reproduce failures.
Writing and running gosim tests ¶
Gosim tests are normal Go tests that are run in a Gosim simulation. To run Gosim tests, use the 'gosim test' command with similar arguments as the standard 'go test' command:
# run an normal test go test -run TestName -v ./path/to/pkg # run a gosim test go run github.com/jellevandenhooff/gosim/cmd/gosim test -run TestName -v ./path/to/pkg
For more information on the 'gosim' command see its documentation at github.com/jellevandenhooff/gosim/cmd/gosim. To run Gosim tests from within a Go test, use the github.com/jellevandenhooff/gosim/metatesting package.
Gosim simulation ¶
When tests run inside Gosim they run in a simulation and they do not interact with the normal operating system. Gosim simulates:
Real time. The time is simulated by Gosim (like on the Go playground) so that it advances automatically when all goroutines are paused. This means tests run quickly even if they sleep for a long time.
The filesystem. Gosim implements its own filesystem that can simulate data loss when writes are not fsync-ed properly.
The network. Gosim implements its own network that can introduce extra latency and partition machines.
Machines. Inside of Gosim a single Go test can create multiple machines which are new instantiations of a Go program with their own global variables, their own disk, and their own network address.
Gosim implements its simulation at the Go runtime and system call level, emulating Linux system calls. Gosim compiles all code with GOOS set to linux. To interact with the simulation, programs can use the standard library with functions like time.Sleep, os.OpenFile, net.Dial, and all others working as you would expect.
To control the simulation, this package has functions like NewMachine and Machine.Crash to create and manipulate machines and SetConnected to manipulate the network.
Gosim internals ¶
For a description of how Gosim works, see the design in https://github.com/jellevandenhooff/gosim/blob/main/docs/design.md
Index ¶
- func IsSim() bool
- func SetConnected(a, b string, connected bool) error
- func SetDelay(a, b string, delay time.Duration) error
- func SetSimulationTimeout(d time.Duration)
- func Yield()
- type InodeInfo
- type Machine
- func (m Machine) Crash()
- func (m Machine) GetInodeInfo(inode int) InodeInfo
- func (m Machine) IterDiskCrashStates(program func()) iter.Seq[Machine]
- func (m Machine) Label() string
- func (m Machine) Restart()
- func (m Machine) RestartWithPartialDisk()
- func (m Machine) SetMainFunc(mainFunc func())
- func (m Machine) SetSometimesCrashOnSync(crash bool)
- func (m Machine) Stop()
- func (m Machine) Wait()
- type MachineConfig
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsSim ¶
func IsSim() bool
IsSim returns if the program is running inside of a gosim simulation.
To include or exclude code or tests only if running inside of a gosim the gosim tool also supports a build tag. Use the `//go:build sim` build constraint at the top of a go file to only include it in simulated builds or `//go:build !sim` to exclude it from simulated from builds.
func SetConnected ¶
SetConnected configures the network connectivity between addresses a and b.
TODO: How will this fail? Unrouteable or rejected TODO: Support asymmetry
func SetDelay ¶
SetDelay configures the network latency between addresses a and b.
TODO: Support asymmetry
func SetSimulationTimeout ¶
SetSimulationTimeout resets the simulation timeout to the given duration. After the simulated duration the simululation will fail with a test timeout error.
func Yield ¶
func Yield()
Yield yields the processor, allowing other goroutines to run. Similar to runtime.Gosched but for gosim's scheduler.
TODO: Replace with runtime.Gosched() instead?
Types ¶
type InodeInfo ¶
type InodeInfo struct { MemLinks int MemExists bool DiskLinks int DiskExists bool Handles int Ops int }
InodeInfo holds low-level information of the requested inode.
TODO: make internal? TODO: copy pasted from fs
type Machine ¶
type Machine struct {
// contains filtered or unexported fields
}
A Machine represents a simulated machine. Each machine has its own disk, network stack, and set of global variables. Machines can only communicate over the network.
A Machine can be stopped and restarted. After a restart, a Machine has a new, freshly-initialized set of global variables, but the same disk and network address as before.
Once a machine's main function returns, the machine stops as if called Machine.Stop with all writes flushed to disk and all network connections closed gracefully.
When a machine stops all code running on the machine is stopped without running any pending `defer`ed calls. All timers are stopped and will not fire.
func CurrentMachine ¶
func CurrentMachine() Machine
CurrentMachine returns the Machine the caller is running on.
func NewMachine ¶
func NewMachine(opts MachineConfig) Machine
NewMachine creates a new Machine with the given configuration. The Machine will start immediately.
See Machine for a detailed description of machines and their behavior.
func NewSimpleMachine ¶
func NewSimpleMachine(mainFunc func()) Machine
NewSimpleMachine creates a new Machine that will run the given main function. The Machine will start immediately.
See Machine for a detailed description of machines and their behavior.
func (Machine) Crash ¶
func (m Machine) Crash()
Crash stops the machine harshly. A crash does not flush any non-fsynced writes to disk, and does not properly close open network connections.
func (Machine) GetInodeInfo ¶
GetInodeInfo inspects the disk of the machine, returning low-level information of the requested inode.
func (Machine) IterDiskCrashStates ¶
IterDiskCrashStates iterates over all possible subsets of partially fsync-ed writes on the disk of the crashed machine.
TODO: Make this iterate over disks instead? TODO: Make internal?
func (Machine) Restart ¶
func (m Machine) Restart()
Restart restarts the machine. The machine must be stopped before Restart can be called.
func (Machine) RestartWithPartialDisk ¶
func (m Machine) RestartWithPartialDisk()
RestartWithPartialDisk restarts the machine. A random subset of non-fsynced writes will be flushed to disk. TODO: Move this partial flushing to crash instead.
func (Machine) SetMainFunc ¶
func (m Machine) SetMainFunc(mainFunc func())
SetMainFunc changes the main function of the machine for future restarts.
func (Machine) SetSometimesCrashOnSync ¶
SetSometimesCrashOnSync configures the machine to sometimes crash before or after the fsync system call.
TODO: What is the probability? TODO: Have a generic mechanism that covers all system calls instead?
func (Machine) Stop ¶
func (m Machine) Stop()
Stop stops the machine gracefully. Pending writes will be fsynced to disk, and open network connections will be closed.
func (Machine) Wait ¶
func (m Machine) Wait()
Wait waits for the machine to finish to stop. A machine stops when its main function returns or when it is explicitly stopped with Machine.Stop or Machine.Crash. For details, see the documentation of Machine.
type MachineConfig ¶
type MachineConfig struct { // Label is the displayed name of a machine in the logs and the hostname // returned by os.Hostname. Optional, will be a numbered machine if // empty. Label string // Addr is the network address of the machine. Only IPv4 addresses are // currently supported. Optional, will be allocated if empty. Addr netip.Addr // MainFunc is the starting function of the machine. When MainFunc returns // the machine will be stopped. MainFunc func() }
MachineConfig configures a Machine.
Directories ¶
Path | Synopsis |
---|---|
cmd
|
|
gosim
Gosim is a tool for working with gosim simulation testing framework.
|
Gosim is a tool for working with gosim simulation testing framework. |
Package gosimruntime simulates the go runtime for programs tested using gosim.
|
Package gosimruntime simulates the go runtime for programs tested using gosim. |
internal
|
|
hooks/go123
Package go123 is the wrapper layer between go1.23's standard library and the gosim runtime.
|
Package go123 is the wrapper layer between go1.23's standard library and the gosim runtime. |
prettylog
MIT License
|
MIT License |
race
Package race is a copy of the built-in package internal/race.
|
Package race is a copy of the built-in package internal/race. |
reflect
Package reflect is a shim of the built-in reflect package.
|
Package reflect is a shim of the built-in reflect package. |
simulation
Code generated by gensyscall.
|
Code generated by gensyscall. |
simulation/gensyscall
This program generates wrappers for system calls in gosim to ergonomically invoke them, implement them, and hook them in the go standard library.
|
This program generates wrappers for system calls in gosim to ergonomically invoke them, implement them, and hook them in the go standard library. |
translate
Code generated by gensyscall.
|
Code generated by gensyscall. |
Package metatesting is a package for writing normal go tests that invoke gosim tests.
|
Package metatesting is a package for writing normal go tests that invoke gosim tests. |
Package nemesis contains pre-built scenarios that introduce problems into distributed systems to try and trigger rare bugs.
|
Package nemesis contains pre-built scenarios that introduce problems into distributed systems to try and trigger rare bugs. |