A process model for go. Ifrit is a small set of interfaces for composing single-purpose units of work into larger programs. Users divide their program into single purpose units of work, each of which implements the `Runner` interface Each `Runner` can be invoked to create a `Process` which can be monitored and signaled to stop. The name Ifrit comes from a type of daemon in arabic folklore. It's a play on the unix term 'daemon' to indicate a process that is managed by the init system. Ifrit ships with a standard library which contains packages for common processes - http servers, integration test helpers - alongside packages which model process supervision and orchestration. These packages can be combined to form complex servers which start and shutdown cleanly. The advantage of small, single-responsibility processes is that they are simple, and thus can be made reliable. Ifrit's interfaces are designed to be free of race conditions and edge cases, allowing larger orcestrated process to also be made reliable. The overall effect is less code and more reliability as your system grows with grace.
A process model for go. Ifrit is a small set of interfaces for composing single-purpose units of work into larger programs. Users divide their program into single purpose units of work, each of which implements the `Runner` interface Each `Runner` can be invoked to create a `Process` which can be monitored and signaled to stop. The name Ifrit comes from a type of daemon in arabic folklore. It's a play on the unix term 'daemon' to indicate a process that is managed by the init system. Ifrit ships with a standard library which contains packages for common processes - http servers, integration test helpers - alongside packages which model process supervision and orchestration. These packages can be combined to form complex servers which start and shutdown cleanly. The advantage of small, single-responsibility processes is that they are simple, and thus can be made reliable. Ifrit's interfaces are designed to be free of race conditions and edge cases, allowing larger orcestrated process to also be made reliable. The overall effect is less code and more reliability as your system grows with grace.
Package golden provides functions for testing commands using smart strings and gold masters. A command must implement the Runner interface. It represents a black box system with inputs (the argument list) and outputs (the standard and error outputs, the panic and error messages, the exit code, and an optional file output). A test case is a value of Case type. It represents a set of input and output values. A test is performed using the Test function. The following example tests a command named "hello" that should print "Hello World!" to its standard output with an argument list equal to []string{"hello", "World"} (the first argument must be the command name). The command under test may be implemented using inner functions or may be generated from an external hello program using the Program function: The Test function supports smart validation strings and gold master files that define very flexible matches. The gold master pattern is commonly used when testing complex output: the expected string is saved to a file, the gold master, rather than to a validation string. The syntax of a smart validation string is very simple. A string equal to "golden" with an optional extension encodes a match to the content of a gold master file with the same extension. The file is stored in testdata/golden with name derived from the test case name: A string representing a valid regular expression delimited by the "^" and "$" characters encodes a full pattern matching: A string starting or ending with the "..." ellipsis encodes a partial match: A string escaped by the equal symbol represents the substring after the symbol: Any other string represents itself: All the gold masters used by TestXxx are updated by running the test with the update flag: All the gold masters are updates by running: See the testing files for usage examples.
Package rununtil has been created to run a provided function until it has been signalled to stop. The main usage of rununtil is to run your main app indefinitely until a SIGINT or SIGTERM signal has been received. The `AwaitKillSignal` is a blocking function which waits until a kill signal has been received. It takes in `RunnerFunc`s which are nonblocking functions which set off go routines (e.g. to run an HTTP server or a gRPC server) and return a `ShutdownFunc`. The `ShutdownFunc`s are executed when a kill signal has been received to allow for graceful shutdown of the go routines set off by the `RunnerFunc`s. For example: The `AwaitKillSignal` function blocks until either a kill signal has been received or `CancelAll` has been triggered. A nice pattern is to create a function that takes in the various depencies required, for example, a logger (but could be anything, e.g. configs, database, etc.), and returns a runner function: It is of course possible to specify which signals you would like to use to kill your application using the `AwaitKillSignals` function, for example: For testing purposes you may want to run your main function, which is using `rununtil.AwaitKillSignal`, and then kill it by simulating sending a kill signal when you're done with your tests. To aid with this you can: The `CancelAll` function results in the same behaviour as sending a real kill signal to your program would, i.e.~graceful shutdown is initiated. The old functions `KillSignal`, `Signals` and `Killed` are still here (for backwards compatibility), but they have been deprecated. Please use `AwaitKillSignal` instead of `KillSignal`, `AwaitKillSignals` instead of `Signals`, and `CancelAll` instead of `Killed` (now you can just run in a go routine main and then execute `CancelAll` to finish the `AwaitKillSignal`).
A process model for go. Ifrit is a small set of interfaces for composing single-purpose units of work into larger programs. Users divide their program into single purpose units of work, each of which implements the `Runner` interface Each `Runner` can be invoked to create a `Process` which can be monitored and signaled to stop. The name Ifrit comes from a type of daemon in arabic folklore. It's a play on the unix term 'daemon' to indicate a process that is managed by the init system. Ifrit ships with a standard library which contains packages for common processes - http servers, integration test helpers - alongside packages which model process supervision and orchestration. These packages can be combined to form complex servers which start and shutdown cleanly. The advantage of small, single-responsibility processes is that they are simple, and thus can be made reliable. Ifrit's interfaces are designed to be free of race conditions and edge cases, allowing larger orcestrated process to also be made reliable. The overall effect is less code and more reliability as your system grows with grace.
Package runner exposes a simple interface for executing commands, enabling easy mocking and wrapping of executed commands. The Runner interface is basic and minimal, but it is sufficient for most use cases. This makes it easy to mock Runner for testing purposes. It's also easy to create wrapper runners which modify commands before executing them. The Sudo struct is a simple example of this.
Package nktest provides a Nakama test runner that makes it easy to build and test Nakama module plugins with complex, advanced game logic using nothing but "go test". See also github.com/ascii8/nakama-go package for a web/realtime Nakama Go client.
Package gounit is an augmentation of the go testing framework for test driven development. It comes with a few types to implement test suites and compact assertion to systematically remove noise from tests. It also comes with a command "gounit" which watches the source directory in which it was executed given it is in the directory structure of a go module. The gounit command From the gounit package you will mainly use the types gounit.Suite and gounit.T (gounit.S for Init and Finalize) as well as the function gounit.Run: If all tests of a suite should run concurrently: Note that gounit also reports normal go-tests and go-tests with sub-tests. While on the other hand suite tests are also executed using the "go test" command. A suit test is a method of a gounit.Suite-embedder which is public, not special, and has exactly one argument (which then must be of type *gounit.T but this is not validated, i.e. gounit will panic if not). Special methods are Init, SetUp, TearDown and Finalize as well as Get, Set and Del. The first four methods behave as you expect: Init and Finalize are executed before respectively after all suite-tests. SetUp and TearDown are executed before respectively after each suite-test. The other three methods are considered special because they are implemented by the Fixtures utility and it turned out to be a quite natural use case to embedded the Fixtures-type next to the Suite type in a test suite. Special methods along with compact assertions provided by gounit.T allow you in a systematic way to remove noise from your tests with the goal to make your suite-test implementations the specification of your production API. While suite tests reported in the order they were written will outline the behavior of your production code and the thought process which led there. NOTE: Init and Finalize have not *gounit.T but *gounit.S as argument type. gounit.S wraps the test runner's testing.T instance while gounit.T wraps a test runner's sub-test testing.T instance created to run a particular suite test. A typical full-blown test suite (in pseudo-code) might look like this:
Package goblin provides the Goblin test runner