Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita7187b2

Browse files
committed
add tests
1 parent9c4c3ef commita7187b2

File tree

5 files changed

+134
-26
lines changed

5 files changed

+134
-26
lines changed

‎coderd/files/cache.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ func NewFromStore(store database.Store) Cache {
2929
}
3030

3131
returnCache{
32+
lock: sync.Mutex{},
33+
data:make(map[uuid.UUID]*cacheEntry),
3234
fetcher:fetcher,
3335
}
3436
}
@@ -41,15 +43,16 @@ func NewFromStore(store database.Store) Cache {
4143
typeCachestruct {
4244
lock sync.Mutex
4345
datamap[uuid.UUID]*cacheEntry
44-
45-
fetcherfunc(context.Context, uuid.UUID) (fs.FS,error)
46+
fetcher
4647
}
4748

4849
typecacheEntrystruct {
4950
refCount*atomic.Int64
5051
value*lazy.ValueWithError[fs.FS]
5152
}
5253

54+
typefetcherfunc(context.Context, uuid.UUID) (fs.FS,error)
55+
5356
// Acquire will load the fs.FS for the given file. It guarantees that parallel
5457
// calls for the same fileID will only result in one fetch, and that parallel
5558
// calls for distinct fileIDs will fetch in parallel.

‎coderd/files/cache_internal_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package files
2+
3+
import (
4+
"context"
5+
"io/fs"
6+
"sync"
7+
"sync/atomic"
8+
"testing"
9+
"time"
10+
11+
"github.com/coder/coder/v2/testutil"
12+
"github.com/google/uuid"
13+
"github.com/spf13/afero"
14+
"github.com/stretchr/testify/require"
15+
"golang.org/x/sync/errgroup"
16+
)
17+
18+
funcTestTryAgain(t*testing.T) {
19+
varfetches atomic.Int64
20+
c:=newTestCache(func(_ context.Context,_ uuid.UUID) (fs.FS,error) {
21+
fetches.Add(1)
22+
// Wait long enough before returning to make sure that all of the goroutines
23+
// will be waiting in line, ensuring that no one duplicated a fetch.
24+
time.Sleep(testutil.IntervalMedium)
25+
returnafero.NewIOFS(afero.NewMemMapFs()),nil
26+
})
27+
28+
batches:=1000
29+
groups:=make([]*errgroup.Group,0,batches)
30+
forrangebatches {
31+
groups=append(groups,new(errgroup.Group))
32+
}
33+
34+
// Call Acquire with a unique ID per batch, many times per batch, with many
35+
// batches all in parallel. This gives us
36+
batchSize:=10
37+
for_,g:=rangegroups {
38+
id:=uuid.New()
39+
forrangebatchSize {
40+
g.Go(func()error {
41+
_,err:=c.Acquire(t.Context(),id)
42+
returnerr
43+
})
44+
}
45+
}
46+
47+
for_,g:=rangegroups {
48+
require.NoError(t,g.Wait())
49+
}
50+
require.Equal(t,int64(batches),fetches.Load())
51+
}
52+
53+
funcnewTestCache(fetcherfunc(context.Context, uuid.UUID) (fs.FS,error))Cache {
54+
returnCache{
55+
lock: sync.Mutex{},
56+
data:make(map[uuid.UUID]*cacheEntry),
57+
fetcher:fetcher,
58+
}
59+
}

‎coderd/util/lazy/value.go

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,3 @@ func (v *Value[T]) Load() T {
2626
funcNew[Tany](fnfunc()T)*Value[T] {
2727
return&Value[T]{fn:fn}
2828
}
29-
30-
typeValueWithError[Tany]struct {
31-
innerValue[result[T]]
32-
}
33-
34-
typeresult[Tany]struct {
35-
valueT
36-
errerror
37-
}
38-
39-
// NewWithError allows you to provide a lazy initializer that can fail.
40-
funcNewWithError[Tany](fnfunc() (T,error))*ValueWithError[T] {
41-
return&ValueWithError[T]{
42-
inner:Value[result[T]]{fn:func()result[T] {
43-
value,err:=fn()
44-
returnresult[T]{value:value,err:err}
45-
}},
46-
}
47-
}
48-
49-
func (v*ValueWithError[T])Load() (T,error) {
50-
result:=v.inner.Load()
51-
returnresult.value,result.err
52-
}

‎coderd/util/lazy/valuewitherror.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package lazy
2+
3+
typeValueWithError[Tany]struct {
4+
innerValue[result[T]]
5+
}
6+
7+
typeresult[Tany]struct {
8+
valueT
9+
errerror
10+
}
11+
12+
// NewWithError allows you to provide a lazy initializer that can fail.
13+
funcNewWithError[Tany](fnfunc() (T,error))*ValueWithError[T] {
14+
return&ValueWithError[T]{
15+
inner:Value[result[T]]{fn:func()result[T] {
16+
value,err:=fn()
17+
returnresult[T]{value:value,err:err}
18+
}},
19+
}
20+
}
21+
22+
func (v*ValueWithError[T])Load() (T,error) {
23+
result:=v.inner.Load()
24+
returnresult.value,result.err
25+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package lazy_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/coder/coder/v2/coderd/util/lazy"
7+
"github.com/stretchr/testify/require"
8+
"golang.org/x/xerrors"
9+
)
10+
11+
funcTestLazyWithErrorOK(t*testing.T) {
12+
l:=lazy.NewWithError(func() (int,error) {
13+
return1,nil
14+
})
15+
16+
i,err:=l.Load()
17+
require.NoError(t,err)
18+
require.Equal(t,1,i)
19+
}
20+
21+
funcTestLazyWithErrorErr(t*testing.T) {
22+
l:=lazy.NewWithError(func() (int,error) {
23+
return0,xerrors.New("oh no! everything that could went horribly wrong!")
24+
})
25+
26+
i,err:=l.Load()
27+
require.Error(t,err)
28+
require.Equal(t,0,i)
29+
}
30+
31+
funcTestLazyWithErrorPointers(t*testing.T) {
32+
a:=1
33+
l:=lazy.NewWithError(func() (*int,error) {
34+
return&a,nil
35+
})
36+
37+
b,err:=l.Load()
38+
require.NoError(t,err)
39+
c,err:=l.Load()
40+
require.NoError(t,err)
41+
42+
*b+=1
43+
*c+=1
44+
require.Equal(t,3,a)
45+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp