How we can run unit tests in parallel mode with failpoint injection taking effect and without injection race

Overview

This is a simple demo to show how we can run unit tests in parallel mode with failpoint injection taking effect and without injection race.

The basic premise is once a failpoint is enabled, its injection terms will take effect until we disable the injection explicitly.

A injection race example

Taking bad_work.go and bad_work_test.go as an example:

bad_work.go defines a function badWork, which has two failpoint injections. In bad_work_test.go we have three test cases, TestBadWorkPath1 and TestBadWorkPath2 enable a failpoint respectively, parallel mode is enabled in each test case. When we enable failpoint and run test cases, we will find the injection race. Pay attention to the output of bad work path..., the injection cf/bad-path1 will always work after its first injection.

➜  failpoint-ctl enable .
➜  go test -count=2 -v -run TestBadWork .
=== RUN   TestBadWorkNormal
=== PAUSE TestBadWorkNormal
=== RUN   TestBadWorkPath1
=== PAUSE TestBadWorkPath1
=== RUN   TestBadWorkPath2
=== PAUSE TestBadWorkPath2
=== CONT  TestBadWorkNormal
=== CONT  TestBadWorkPath2
bad work path2
--- PASS: TestBadWorkPath2 (0.00s)
=== CONT  TestBadWorkPath1
bad work path1
--- PASS: TestBadWorkPath1 (0.00s)
bad work path normal
--- PASS: TestBadWorkNormal (0.00s)
=== RUN   TestBadWorkNormal
=== PAUSE TestBadWorkNormal
=== RUN   TestBadWorkPath1
=== PAUSE TestBadWorkPath1
=== RUN   TestBadWorkPath2
=== PAUSE TestBadWorkPath2
=== CONT  TestBadWorkNormal
bad work path1
--- PASS: TestBadWorkNormal (0.00s)
=== CONT  TestBadWorkPath2
=== CONT  TestBadWorkPath1
bad work path1
--- PASS: TestBadWorkPath2 (0.00s)
bad work path1
--- PASS: TestBadWorkPath1 (0.00s)
PASS
ok      cf      0.023s

A workaround for parallel failpoint injection

In work.go, the failpoint injection path is encoded with a dynamic function name, which is the entrypoint of test case, where we have enabled a failpoint. This time the failpoint injection will only take effect when the matching test case is running.

We can use InjectContext and failpoint.WithHook to pass a test independent context key value to achieve running parallel test cases without injection race.

➜  failpoint-ctl enable .
➜  go test -count=2 -v -run TestWork
=== RUN   TestWorkNormal
=== PAUSE TestWorkNormal
=== RUN   TestWorkPath1
=== PAUSE TestWorkPath1
=== RUN   TestWorkPath2
=== PAUSE TestWorkPath2
=== RUN   TestWorkPathPanic
=== PAUSE TestWorkPathPanic
=== CONT  TestWorkNormal
work path normal
--- PASS: TestWorkNormal (0.00s)
=== CONT  TestWorkPathPanic
--- PASS: TestWorkPathPanic (0.00s)
=== CONT  TestWorkPath2
work path2
--- PASS: TestWorkPath2 (0.00s)
=== CONT  TestWorkPath1
work path1
--- PASS: TestWorkPath1 (0.00s)
=== RUN   TestWorkNormal
=== PAUSE TestWorkNormal
=== RUN   TestWorkPath1
=== PAUSE TestWorkPath1
=== RUN   TestWorkPath2
=== PAUSE TestWorkPath2
=== RUN   TestWorkPathPanic
=== PAUSE TestWorkPathPanic
=== CONT  TestWorkNormal
work path normal
--- PASS: TestWorkNormal (0.00s)
=== CONT  TestWorkPathPanic
--- PASS: TestWorkPathPanic (0.00s)
=== CONT  TestWorkPath2
work path2
--- PASS: TestWorkPath2 (0.00s)
=== CONT  TestWorkPath1
work path1
--- PASS: TestWorkPath1 (0.00s)
PASS
ok      cf      0.005s

The basic code is as follows

// business code with failpoint injection
func work(ctx context.Context) {
	failpoint.InjectContext(ctx, "path1", func() {
		// do something
	})
	// ...
}

// test case entrypoint, with failpoint enable
func TestWorkPath1(t *testing.T) {
	failpoint.Enable("cf/path1", "return(true)")
	ctx := failpoint.WithHook(context.Background(), func(ctx context.Context, fpname string) bool {
		// only the code is running from this test case contains the context key of `fpname`
		return ctx.Value(fpname) != nil
	})
	ctx = context.WithValue(ctx, "cf/path1", struct{}{})
	work(ctx)
}
Owner
amyangfei
amyangfei
gomonkey is a library to make monkey patching in unit tests easy

gomonkey is a library to make monkey patching in unit tests easy, and the core idea of monkey patching comes from Bouke, you can read this blogpost for an explanation on how it works.

Zhang Xiaolong 902 Jan 18, 2022
Rr-e2e-tests - Roadrunner end-to-end tests repository

RoadRunner end-to-end plugins tests License: The MIT License (MIT). Please see L

RoadRunner 1 Jan 18, 2022
go websocket client for unit testing of a websocket handler

wstest A websocket client for unit-testing a websocket server The gorilla organization provides full featured websocket implementation that the standa

Eyal Posener 86 Dec 14, 2021
Easier way to unit test terraform

Unit testing terraform (WIP) Disclaimer Currently, the only way to compare values is using JSON query path and all types are strings. want := terraf

Thiago Nache Carvalho 47 Nov 28, 2021
A mock of Go's net package for unit/integration testing

netmock: Simulate Go network connections netmock is a Go package for simulating net connections, including delays and disconnects. This is work in pro

Lucas Wolf 1 Oct 27, 2021
Go Unit Testing Clean Arch

Golang Unit Testing Tutorial melakukan unit testing di Golang yang sudah menerapkan clean architecture Menjalankan Service PSQL_HOST=<IP Database Serv

Edward Suwirya 1 Jan 4, 2022
A simple yet intuitive golang unit test framework.

gotest Intuitive and simple golang testing framework which helps in writing unit tests in a way which improves the readability of the test. Here is an

null 1 Jan 1, 2022
Vault mock - Mock of Hashicorp Vault used for unit testing

vault_mock Mock of Hashicorp Vault used for unit testing Notice This is a person

Elliot Rotenstein 0 Jan 19, 2022
Record and replay your HTTP interactions for fast, deterministic and accurate tests

go-vcr go-vcr simplifies testing by recording your HTTP interactions and replaying them in future runs in order to provide fast, deterministic and acc

Marin Atanasov Nikolov 842 Jan 20, 2022
Testing framework for Go. Allows writing self-documenting tests/specifications, and executes them concurrently and safely isolated. [UNMAINTAINED]

GoSpec GoSpec is a BDD-style testing framework for the Go programming language. It allows writing self-documenting tests/specs, and executes them in p

Esko Luontola 114 Dec 23, 2021
Extremely flexible golang deep comparison, extends the go testing package and tests HTTP APIs

go-testdeep Extremely flexible golang deep comparison, extends the go testing package. Latest news Synopsis Description Installation Functions Availab

Maxime Soulé 241 Jan 10, 2022
A next-generation testing tool. Orion provides a powerful DSL to write and automate your acceptance tests

Orion is born to change the way we implement our acceptance tests. It takes advantage of HCL from Hashicorp t o provide a simple DSL to write the acceptance tests.

Wesovi Labs 32 Dec 21, 2021
Robust framework for running complex workload scenarios in isolation, using Go; for integration, e2e tests, benchmarks and more! 💪

e2e Go Module providing robust framework for running complex workload scenarios in isolation, using Go and Docker. For integration, e2e tests, benchma

null 51 Dec 31, 2021
A simple and expressive HTTP server mocking library for end-to-end tests in Go.

mockhttp A simple and expressive HTTP server mocking library for end-to-end tests in Go. Installation go get -d github.com/americanas-go/mockhttp Exa

Americanas Go 6 Dec 19, 2021
Package for comparing Go values in tests

Package for equality of Go values This package is intended to be a more powerful and safer alternative to reflect.DeepEqual for comparing whether two

Google 2.7k Jan 15, 2022
Go testing in the browser. Integrates with `go test`. Write behavioral tests in Go.

GoConvey is awesome Go testing Welcome to GoConvey, a yummy Go testing tool for gophers. Works with go test. Use it in the terminal or browser accordi

SmartyStreets 6.9k Jan 19, 2022
Ruby on Rails like test fixtures for Go. Write tests against a real database

testfixtures Warning: this package will wipe the database data before loading the fixtures! It is supposed to be used on a test database. Please, doub

null 732 Jan 18, 2022
Automatically update your Go tests

autogold - automatically update your Go tests autogold makes go test -update automatically update your Go tests (golden files and Go values in e.g. fo

Hexops 109 Dec 22, 2021
A simple `fs.FS` implementation to be used inside tests.

testfs A simple fs.FS which is contained in a test (using testing.TB's TempDir()) and with a few helper methods. PS: This lib only works on Go 1.16+.

Carlos Alexandro Becker 32 Nov 25, 2021