Skip to content

Commit d61b447

Browse files
committed
[ci skip] table test
1 parent a65369a commit d61b447

File tree

1 file changed

+99
-74
lines changed

1 file changed

+99
-74
lines changed

agent/containers_internal_test.go

Lines changed: 99 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -73,80 +73,105 @@ func TestContainersHandler(t *testing.T) {
7373
t.Run("list", func(t *testing.T) {
7474
t.Parallel()
7575

76-
// Given: a containersHandler backed by a mock
77-
var (
78-
ctx = testutil.Context(t, testutil.WaitShort)
79-
clk = quartz.NewMock(t)
80-
ctrl = gomock.NewController(t)
81-
mockLister = NewMockContainerLister(ctrl)
82-
now = time.Now().UTC()
83-
ch = containersHandler{
84-
cacheDuration: time.Second,
85-
cl: mockLister,
86-
clock: clk,
87-
}
88-
expected = []codersdk.WorkspaceAgentContainer{fakeContainer(t)}
89-
)
90-
91-
clk.Set(now).MustWait(ctx)
92-
93-
// When: getContainers is called for the first time
94-
ch.mtime = time.Time{}
95-
mockLister.EXPECT().List(gomock.Any()).Return(expected, nil)
96-
actual, err := ch.getContainers(ctx)
97-
98-
// Then: the underlying lister is called and the result is returned
99-
require.NoError(t, err, "expected no error on first call")
100-
require.Equal(t, expected, actual, "expected containers to be equal on first call")
101-
// Then: the result is cached
102-
require.Equal(t, now, ch.mtime, "expected container mtime to be set on first call")
103-
require.NotEmpty(t, ch.containers, "expected cached data to not be empty on first call")
104-
105-
// When: getContainers is called again
106-
actual, err = ch.getContainers(ctx)
107-
108-
// Then: the underlying lister is not called and the cached result is
109-
// returned
110-
require.NoError(t, err, "expected no error on second call")
111-
require.Equal(t, expected, actual, "expected containers to be equal on second call")
112-
// Then: the result is cached
113-
require.Equal(t, now, ch.mtime, "expected container mtime to not have changed on second call")
114-
require.Equal(t, expected, ch.containers, "expected cached data to not have changed on second call")
115-
116-
// When: getContainers is called after the cache duration has expired
117-
expected = append(expected, fakeContainer(t))
118-
later := now.Add(defaultGetContainersCacheDuration).Add(time.Second)
119-
clk.Set(later).MustWait(ctx)
120-
mockLister.EXPECT().List(gomock.Any()).Return(expected, nil)
121-
actual, err = ch.getContainers(ctx)
122-
123-
// Then: the underlying lister is called and the result is returned
124-
require.NoError(t, err, "expected no error on third call")
125-
require.Equal(t, expected, actual, "expected containers to be equal on third call")
126-
// Then: the result is cached
127-
require.Equal(t, later, ch.mtime, "expected container mtime to later on third call")
128-
require.Equal(t, expected, ch.containers, "expected cached data to not have changed on third call")
129-
130-
// When: getContainers is called again but the underlying lister returns an error
131-
actual, err = ch.getContainers(ctx)
132-
require.NoError(t, err)
133-
134-
// Then: the cached data is not updated
135-
require.Equal(t, expected, actual, "expected containers to be equal on fourth call")
136-
require.Equal(t, later, ch.mtime, "expected container mtime to not have changed on fourth call")
137-
require.Equal(t, expected, ch.containers, "expected cached data to not have changed on fourth call")
138-
139-
// When: time advances past mtime
140-
laterlater := later.Add(defaultGetContainersCacheDuration).Add(time.Second)
141-
clk.Set(laterlater).MustWait(ctx)
142-
mockLister.EXPECT().List(gomock.Any()).Return(nil, assert.AnError)
143-
actual, err = ch.getContainers(ctx)
144-
// Then: the underlying error is returned
145-
require.ErrorContains(t, err, assert.AnError.Error(), "expected error on fifth call")
146-
require.Nil(t, actual, "expected no data to be returned on fifth call")
147-
// Then: the underlying cached data remains the same
148-
require.Equal(t, later, ch.mtime, "expected container mtime to not have changed on fifth call")
149-
require.Equal(t, expected, ch.containers, "expected cached data to not have changed on fifth call")
76+
fakeCt := fakeContainer(t)
77+
fakeCt2 := fakeContainer(t)
78+
79+
// Each test case is called multiple times to ensure idempotency
80+
for _, tc := range []struct {
81+
name string
82+
// data to be stored in the handler
83+
cacheData []codersdk.WorkspaceAgentContainer
84+
// duration of cache
85+
cacheDur time.Duration
86+
// relative age of the cached data
87+
cacheAge time.Duration
88+
// function to set up expectations for the mock
89+
setupMock func(*MockContainerLister)
90+
// expected result
91+
expected []codersdk.WorkspaceAgentContainer
92+
// expected error
93+
expectedErr string
94+
}{
95+
{
96+
name: "no cache",
97+
setupMock: func(mcl *MockContainerLister) {
98+
mcl.EXPECT().List(gomock.Any()).Return([]codersdk.WorkspaceAgentContainer{fakeCt}, nil).AnyTimes()
99+
},
100+
expected: []codersdk.WorkspaceAgentContainer{fakeCt},
101+
},
102+
{
103+
name: "no data",
104+
cacheData: nil,
105+
cacheAge: 2 * time.Second,
106+
cacheDur: time.Second,
107+
setupMock: func(mcl *MockContainerLister) {
108+
mcl.EXPECT().List(gomock.Any()).Return([]codersdk.WorkspaceAgentContainer{fakeCt}, nil).AnyTimes()
109+
},
110+
expected: []codersdk.WorkspaceAgentContainer{fakeCt},
111+
},
112+
{
113+
name: "cached data",
114+
cacheAge: time.Second,
115+
cacheData: []codersdk.WorkspaceAgentContainer{fakeCt},
116+
cacheDur: 2 * time.Second,
117+
expected: []codersdk.WorkspaceAgentContainer{fakeCt},
118+
},
119+
{
120+
name: "lister error",
121+
setupMock: func(mcl *MockContainerLister) {
122+
mcl.EXPECT().List(gomock.Any()).Return(nil, assert.AnError).AnyTimes()
123+
},
124+
expectedErr: assert.AnError.Error(),
125+
},
126+
{
127+
name: "stale cache",
128+
cacheAge: 2 * time.Second,
129+
cacheData: []codersdk.WorkspaceAgentContainer{fakeCt},
130+
cacheDur: time.Second,
131+
setupMock: func(mcl *MockContainerLister) {
132+
mcl.EXPECT().List(gomock.Any()).Return([]codersdk.WorkspaceAgentContainer{fakeCt2}, nil).AnyTimes()
133+
},
134+
expected: []codersdk.WorkspaceAgentContainer{fakeCt2},
135+
},
136+
} {
137+
tc := tc
138+
t.Run(tc.name, func(t *testing.T) {
139+
t.Parallel()
140+
var (
141+
ctx = testutil.Context(t, testutil.WaitShort)
142+
clk = quartz.NewMock(t)
143+
ctrl = gomock.NewController(t)
144+
mockLister = NewMockContainerLister(ctrl)
145+
now = time.Now().UTC()
146+
ch = containersHandler{
147+
cacheDuration: tc.cacheDur,
148+
cl: mockLister,
149+
clock: clk,
150+
containers: tc.cacheData,
151+
}
152+
)
153+
if tc.cacheAge != 0 {
154+
ch.mtime = now.Add(-tc.cacheAge)
155+
}
156+
if tc.setupMock != nil {
157+
tc.setupMock(mockLister)
158+
}
159+
160+
clk.Set(now).MustWait(ctx)
161+
162+
// Repeat the test to ensure idempotency
163+
for i := 0; i < 2; i++ {
164+
actual, err := ch.getContainers(ctx)
165+
if tc.expectedErr != "" {
166+
require.Empty(t, actual, "expected no data (attempt %d)", i)
167+
require.ErrorContains(t, err, tc.expectedErr, "expected error (attempt %d)", i)
168+
} else {
169+
require.NoError(t, err, "expected no error (attempt %d)", i)
170+
require.Equal(t, tc.expected, actual, "expected containers to be equal (attempt %d)", i)
171+
}
172+
}
173+
})
174+
}
150175
})
151176
}
152177

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy