-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathconcurrency_test.go
More file actions
68 lines (55 loc) · 1.71 KB
/
Copy pathconcurrency_test.go
File metadata and controls
68 lines (55 loc) · 1.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package console
import (
"errors"
"sync"
"testing"
"github.com/spf13/cobra"
)
// TestConcurrentStateAccess stresses the console's shared state (filters, the
// menus map, and per-menu interrupt handlers) from many goroutines at once.
//
// It is meant to be run with the race detector (`go test -race`). Before the
// locking fixes, these paths mutated maps/slices under a read lock (or no lock
// at all), which the detector flags and which can panic on concurrent map
// writes in production.
func TestConcurrentStateAccess(t *testing.T) {
c := New("test")
// Give the active menu a small command tree so that ActiveFiltersFor has
// something to recurse over while filters are being mutated concurrently.
menu := c.ActiveMenu()
menu.SetCommands(func() *cobra.Command {
root := &cobra.Command{Use: "root"}
child := &cobra.Command{
Use: "child",
Annotations: map[string]string{CommandFilterKey: "filterA,filterB"},
Run: func(*cobra.Command, []string) {},
}
root.AddCommand(child)
return root
})
menu.resetPreRun()
errInt := errors.New("interrupt")
const workers = 64
var wg sync.WaitGroup
wg.Add(workers)
for i := 0; i < workers; i++ {
go func(i int) {
defer wg.Done()
// Filters: concurrent writers (Hide/Show) and readers (ActiveFiltersFor).
c.HideCommands("filterA", "filterB")
c.ShowCommands("filterA")
m := c.ActiveMenu()
for _, cmd := range m.Command.Commands() {
_ = m.ActiveFiltersFor(cmd)
}
// Menus map: concurrent creation and lookup.
_ = c.NewMenu("menu")
_ = c.Menu("menu")
_ = c.ActiveMenu()
// Interrupt handlers map: concurrent writers.
m.AddInterrupt(errInt, func(*Console) {})
m.DelInterrupt(errInt)
}(i)
}
wg.Wait()
}