-
Notifications
You must be signed in to change notification settings - Fork 17.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
internal/synctest: new package for testing concurrent code
Add an internal (for now) implementation of testing/synctest. The synctest.Run function executes a tree of goroutines in an isolated environment using a fake clock. The synctest.Wait function allows a test to wait for all other goroutines within the test to reach a blocking point. For #67434 For #69687 Change-Id: Icb39e54c54cece96517e58ef9cfb18bf68506cfc Reviewed-on: https://go-review.googlesource.com/c/go/+/591997 Reviewed-by: Michael Pratt <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
- Loading branch information
Showing
26 changed files
with
1,154 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// Copyright 2024 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
// Package synctest provides support for testing concurrent code. | ||
package synctest | ||
|
||
import ( | ||
_ "unsafe" // for go:linkname | ||
) | ||
|
||
// Run executes f in a new goroutine. | ||
// | ||
// The new goroutine and any goroutines transitively started by it form | ||
// an isolated "bubble". | ||
// Run waits for all goroutines in the bubble to exit before returning. | ||
// | ||
// Goroutines in the bubble use a synthetic time implementation. | ||
// The initial time is midnight UTC 2000-01-01. | ||
// | ||
// Time advances when every goroutine in the bubble is blocked. | ||
// For example, a call to time.Sleep will block until all other | ||
// goroutines are blocked and return after the bubble's clock has | ||
// advanced. See [Wait] for the specific definition of blocked. | ||
// | ||
// If every goroutine is blocked and there are no timers scheduled, | ||
// Run panics. | ||
// | ||
// Channels, time.Timers, and time.Tickers created within the bubble | ||
// are associated with it. Operating on a bubbled channel, timer, or ticker | ||
// from outside the bubble panics. | ||
// | ||
//go:linkname Run | ||
func Run(f func()) | ||
|
||
// Wait blocks until every goroutine within the current bubble, | ||
// other than the current goroutine, is durably blocked. | ||
// It panics if called from a non-bubbled goroutine, | ||
// or if two goroutines in the same bubble call Wait at the same time. | ||
// | ||
// A goroutine is durably blocked if can only be unblocked by another | ||
// goroutine in its bubble. The following operations durably block | ||
// a goroutine: | ||
// - a send or receive on a channel from within the bubble | ||
// - a select statement where every case is a channel within the bubble | ||
// - sync.Cond.Wait | ||
// - time.Sleep | ||
// | ||
// A goroutine executing a system call or waiting for an external event | ||
// such as a network operation is not durably blocked. | ||
// For example, a goroutine blocked reading from an network connection | ||
// is not durably blocked even if no data is currently available on the | ||
// connection, because it may be unblocked by data written from outside | ||
// the bubble or may be in the process of receiving data from a kernel | ||
// network buffer. | ||
// | ||
// A goroutine is not durably blocked when blocked on a send or receive | ||
// on a channel that was not created within its bubble, because it may | ||
// be unblocked by a channel receive or send from outside its bubble. | ||
// | ||
//go:linkname Wait | ||
func Wait() |
Oops, something went wrong.