@@ -10,19 +10,20 @@ import (
10
10
11
11
"github.com/coder/coder/v2/testutil"
12
12
"github.com/google/uuid"
13
- "github.com/spf13/afero"
14
13
"github.com/stretchr/testify/require"
15
14
"golang.org/x/sync/errgroup"
16
15
)
17
16
18
- func TestTryAgain (t * testing.T ) {
17
+ func TestConcurrency (t * testing.T ) {
18
+ t .Parallel ()
19
+
19
20
var fetches atomic.Int64
20
21
c := newTestCache (func (_ context.Context ,_ uuid.UUID ) (fs.FS ,error ) {
21
22
fetches .Add (1 )
22
23
// Wait long enough before returning to make sure that all of the goroutines
23
24
// will be waiting in line, ensuring that no one duplicated a fetch.
24
25
time .Sleep (testutil .IntervalMedium )
25
- return afero . NewIOFS ( afero . NewMemMapFs ()) ,nil
26
+ return nil ,nil
26
27
})
27
28
28
29
batches := 1000
@@ -32,7 +33,8 @@ func TestTryAgain(t *testing.T) {
32
33
}
33
34
34
35
// Call Acquire with a unique ID per batch, many times per batch, with many
35
- // batches all in parallel. This gives us
36
+ // batches all in parallel. This is pretty much the worst-case scenario:
37
+ // thousands of concurrent reads, with both warm and cold loads happening.
36
38
batchSize := 10
37
39
for _ ,g := range groups {
38
40
id := uuid .New ()
@@ -50,6 +52,41 @@ func TestTryAgain(t *testing.T) {
50
52
require .Equal (t ,int64 (batches ),fetches .Load ())
51
53
}
52
54
55
+ func TestRelease (t * testing.T ) {
56
+ t .Parallel ()
57
+
58
+ c := newTestCache (func (_ context.Context ,_ uuid.UUID ) (fs.FS ,error ) {
59
+ return nil ,nil
60
+ })
61
+
62
+ batches := 100
63
+ ids := make ([]uuid.UUID ,0 ,batches )
64
+ for range batches {
65
+ ids = append (ids ,uuid .New ())
66
+ }
67
+
68
+ // Acquire a bunch of references
69
+ batchSize := 10
70
+ for _ ,id := range ids {
71
+ for range batchSize {
72
+ c .Acquire (t .Context (),id )
73
+ }
74
+ }
75
+
76
+ // Make sure cache is fully loaded
77
+ require .Equal (t ,len (c .data ),batches )
78
+
79
+ // Now release all of the references
80
+ for _ ,id := range ids {
81
+ for range batchSize {
82
+ c .Release (id )
83
+ }
84
+ }
85
+
86
+ // ...and make sure that the cache has emptied itself.
87
+ require .Equal (t ,len (c .data ),0 )
88
+ }
89
+
53
90
func newTestCache (fetcher func (context.Context , uuid.UUID ) (fs.FS ,error ))Cache {
54
91
return Cache {
55
92
lock : sync.Mutex {},