Impressive stuff! Some potentially interesting overlap with the new "synctest" package. Do you have any thoughts on that?
On Tue, 10 Dec 2024 at 17:41, Jelle van den Hooff <je...@vandenhooff.name> wrote: > Hi golang-nuts, > > I am excited to share Gosim: simulation testing for Go ( > https://github.com/jellevandenhooff/gosim). Gosim is a project I have > been working on for quite a while that aims to make testing distributed > systems easier. It implements simulation testing as popularized by > FoundationDB (https://www.youtube.com/watch?v=4fFDFbi3toc). > > Gosim runs mostly-standard Go code in its simulated environment. It > supports standard packages like `os`, `net`, gRPC, protobuf, and more; the > largest real-world program I have successfully run is etcd. Inside of the > simulation, Gosim implements fake time, network, disks, and machines. Tests > can manipulate the network to eg. partition a host, or restart a machine, > and verify that code still behaves as it should -- and all that without > needing to manage real VMs or containers. > > Gosim works by source-translating Go to replace all references to > concurrency primitives, the operating system, and non-deterministic code to > its own runtime. So `go foo()` becomes `gosimruntime.Go(foo)`, etc. Then, > Gosim implements a (subset of) the Linux system call interface to simulate > disk and network. More details on the design are in > https://github.com/jellevandenhooff/gosim/blob/main/docs/design.md. > Gosim's system call implementations are (currently) in > https://github.com/jellevandenhooff/gosim/blob/main/internal/simulation/os_linux.go > . > > To give you a taste of the kinds of tests Gosim can write, below is a > snippet of a test running Etcd (taken from > https://github.com/jellevandenhooff/gosim/blob/main/examples/etcd/etcd_test.go). > The test creates several Gosim machines that have their own network stack, > disk, global variables, and more, and lets them run and communicate. From > the point of view of the code, each Etcd instance runs on its own machine > and is its own independent process. The simulation however runs all > machines in the same Go process so that you can easily debug what happens, > the test is reproducible, and overhead is low. > > I have tried to make Gosim easy to use. To get started you can run a test > by replacing `go test ...` with `gosim test`. If Gosim might be useful for > you, I would be happy to chat and prioritize future features. Some things I > would certainly like to add are support for running main() functions; > simulating clock drift; support for running different versions of code; and > built-in simulation of common cloud APIs like S3. > > Gosim is experimental, so it will change and break, and only runs Go code. > So it can test systems that are written in Go, but it will not work with > external dependencies. I have some ideas on using eg. Wazero to run Sqlite > or Postgres inside of the Go process but those are, well, still ideas. > > Jelle > > // TestEtcd runs a 3 node etcd cluster, partitions the network between the >> // nodes, and makes sure key-value puts and gets work. >> func TestEtcd(t *testing.T) { >> gosim.SetSimulationTimeout(2 * time.Minute) >> >> // run machines: >> gosim.NewMachine(gosim.MachineConfig{ >> Label: "etcd-1", >> Addr: netip.MustParseAddr("10.0.0.1"), >> MainFunc: func() { >> runEtcdNode("etcd-1", "10.0.0.1") >> }, >> }) >> gosim.NewMachine(gosim.MachineConfig{ >> Label: "etcd-2", >> Addr: netip.MustParseAddr("10.0.0.2"), >> MainFunc: func() { >> time.Sleep(100 * time.Millisecond) >> runEtcdNode("etcd-2", "10.0.0.2") >> }, >> }) >> gosim.NewMachine(gosim.MachineConfig{ >> Label: "etcd-3", >> Addr: netip.MustParseAddr("10.0.0.3"), >> MainFunc: func() { >> time.Sleep(200 * time.Millisecond) >> runEtcdNode("etcd-3", "10.0.0.3") >> }, >> }) >> >> // mess with the network in the background >> go nemesis.Sequence( >> nemesis.Sleep{ >> Duration: 10 * time.Second, >> }, >> nemesis.PartitionMachines{ >> Addresses: []string{ >> "10.0.0.1", >> "10.0.0.2", >> "10.0.0.3", >> }, >> Duration: 30 * time.Second, >> }, >> ).Run() >> >> > > -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > To view this discussion visit > https://groups.google.com/d/msgid/golang-nuts/CAP%3DJquaBu1O5rN6aR6fMs03q4O92cPAc9DfGQZ9fck9zB2sEkw%40mail.gmail.com > <https://groups.google.com/d/msgid/golang-nuts/CAP%3DJquaBu1O5rN6aR6fMs03q4O92cPAc9DfGQZ9fck9zB2sEkw%40mail.gmail.com?utm_medium=email&utm_source=footer> > . > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/golang-nuts/CAJhgacjRqnaJhagjGnq%3DpMvfy8LLa40nDGYBiiA%3DcPnEkyVD-A%40mail.gmail.com.