@@ -2,6 +2,9 @@ package coderd_test
2
2
3
3
import (
4
4
"context"
5
+ "encoding/json"
6
+ "fmt"
7
+ "net/http"
5
8
"sync"
6
9
"testing"
7
10
@@ -20,15 +23,31 @@ import (
20
23
"github.com/coder/coder/v2/testutil"
21
24
)
22
25
23
- func verifyQuota (ctx context.Context , t * testing.T , client * codersdk.Client , consumed , total int ) {
26
+ func verifyQuota (ctx context.Context , t * testing.T , client * codersdk.Client , organizationID string , consumed , total int ) {
24
27
t .Helper ()
25
28
26
- got , err := client .WorkspaceQuota (ctx , codersdk .Me )
29
+ got , err := client .WorkspaceQuota (ctx , organizationID , codersdk .Me )
27
30
require .NoError (t , err )
28
31
require .EqualValues (t , codersdk.WorkspaceQuota {
29
32
Budget : total ,
30
33
CreditsConsumed : consumed ,
31
34
}, got )
35
+
36
+ // Remove this check when the deprecated endpoint is removed.
37
+ // This just makes sure the deprecated endpoint is still working
38
+ // as intended. It will only work for the default organization.
39
+ deprecatedGot , err := deprecatedQuotaEndpoint (ctx , client , codersdk .Me )
40
+ require .NoError (t , err , "deprecated endpoint" )
41
+ // Only continue to check if the values differ
42
+ if deprecatedGot .Budget != got .Budget || deprecatedGot .CreditsConsumed != got .CreditsConsumed {
43
+ org , err := client .OrganizationByName (ctx , organizationID )
44
+ if err != nil {
45
+ return
46
+ }
47
+ if org .IsDefault {
48
+ require .Equal (t , got , deprecatedGot )
49
+ }
50
+ }
32
51
}
33
52
34
53
func TestWorkspaceQuota (t * testing.T ) {
@@ -52,14 +71,14 @@ func TestWorkspaceQuota(t *testing.T) {
52
71
})
53
72
coderdtest .NewProvisionerDaemon (t , api .AGPL )
54
73
55
- verifyQuota (ctx , t , client , 0 , 0 )
74
+ verifyQuota (ctx , t , client , user . OrganizationID . String (), 0 , 0 )
56
75
57
76
// Patch the 'Everyone' group to verify its quota allowance is being accounted for.
58
77
_ , err := client .PatchGroup (ctx , user .OrganizationID , codersdk.PatchGroupRequest {
59
78
QuotaAllowance : ptr .Ref (1 ),
60
79
})
61
80
require .NoError (t , err )
62
- verifyQuota (ctx , t , client , 0 , 1 )
81
+ verifyQuota (ctx , t , client , user . OrganizationID . String (), 0 , 1 )
63
82
64
83
// Add user to two groups, granting them a total budget of 4.
65
84
group1 , err := client .CreateGroup (ctx , user .OrganizationID , codersdk.CreateGroupRequest {
@@ -84,7 +103,7 @@ func TestWorkspaceQuota(t *testing.T) {
84
103
})
85
104
require .NoError (t , err )
86
105
87
- verifyQuota (ctx , t , client , 0 , 4 )
106
+ verifyQuota (ctx , t , client , user . OrganizationID . String (), 0 , 4 )
88
107
89
108
authToken := uuid .NewString ()
90
109
version := coderdtest .CreateTemplateVersion (t , client , user .OrganizationID , & echo.Responses {
@@ -123,14 +142,14 @@ func TestWorkspaceQuota(t *testing.T) {
123
142
}()
124
143
}
125
144
wg .Wait ()
126
- verifyQuota (ctx , t , client , 4 , 4 )
145
+ verifyQuota (ctx , t , client , user . OrganizationID . String (), 4 , 4 )
127
146
128
147
// Next one must fail
129
148
workspace := coderdtest .CreateWorkspace (t , client , template .ID )
130
149
build := coderdtest .AwaitWorkspaceBuildJobCompleted (t , client , workspace .LatestBuild .ID )
131
150
132
151
// Consumed shouldn't bump
133
- verifyQuota (ctx , t , client , 4 , 4 )
152
+ verifyQuota (ctx , t , client , user . OrganizationID . String (), 4 , 4 )
134
153
require .Equal (t , codersdk .WorkspaceStatusFailed , build .Status )
135
154
require .Contains (t , build .Job .Error , "quota" )
136
155
@@ -146,15 +165,15 @@ func TestWorkspaceQuota(t *testing.T) {
146
165
})
147
166
require .NoError (t , err )
148
167
coderdtest .AwaitWorkspaceBuildJobCompleted (t , client , build .ID )
149
- verifyQuota (ctx , t , client , 3 , 4 )
168
+ verifyQuota (ctx , t , client , user . OrganizationID . String (), 3 , 4 )
150
169
break
151
170
}
152
171
153
172
// Next one should now succeed
154
173
workspace = coderdtest .CreateWorkspace (t , client , template .ID )
155
174
build = coderdtest .AwaitWorkspaceBuildJobCompleted (t , client , workspace .LatestBuild .ID )
156
175
157
- verifyQuota (ctx , t , client , 4 , 4 )
176
+ verifyQuota (ctx , t , client , user . OrganizationID . String (), 4 , 4 )
158
177
require .Equal (t , codersdk .WorkspaceStatusRunning , build .Status )
159
178
})
160
179
@@ -174,14 +193,14 @@ func TestWorkspaceQuota(t *testing.T) {
174
193
})
175
194
coderdtest .NewProvisionerDaemon (t , api .AGPL )
176
195
177
- verifyQuota (ctx , t , client , 0 , 0 )
196
+ verifyQuota (ctx , t , client , user . OrganizationID . String (), 0 , 0 )
178
197
179
198
// Patch the 'Everyone' group to verify its quota allowance is being accounted for.
180
199
_ , err := client .PatchGroup (ctx , user .OrganizationID , codersdk.PatchGroupRequest {
181
200
QuotaAllowance : ptr .Ref (4 ),
182
201
})
183
202
require .NoError (t , err )
184
- verifyQuota (ctx , t , client , 0 , 4 )
203
+ verifyQuota (ctx , t , client , user . OrganizationID . String (), 0 , 4 )
185
204
186
205
version := coderdtest .CreateTemplateVersion (t , client , user .OrganizationID , & echo.Responses {
187
206
Parse : echo .ParseComplete ,
@@ -208,29 +227,29 @@ func TestWorkspaceQuota(t *testing.T) {
208
227
assert .Equal (t , codersdk .WorkspaceStatusRunning , build .Status )
209
228
}
210
229
wg .Wait ()
211
- verifyQuota (ctx , t , client , 4 , 4 )
230
+ verifyQuota (ctx , t , client , user . OrganizationID . String (), 4 , 4 )
212
231
213
232
// Next one must fail
214
233
workspace := coderdtest .CreateWorkspace (t , client , template .ID )
215
234
build := coderdtest .AwaitWorkspaceBuildJobCompleted (t , client , workspace .LatestBuild .ID )
216
235
require .Contains (t , build .Job .Error , "quota" )
217
236
218
237
// Consumed shouldn't bump
219
- verifyQuota (ctx , t , client , 4 , 4 )
238
+ verifyQuota (ctx , t , client , user . OrganizationID . String (), 4 , 4 )
220
239
require .Equal (t , codersdk .WorkspaceStatusFailed , build .Status )
221
240
222
241
build = coderdtest .CreateWorkspaceBuild (t , client , workspaces [0 ], database .WorkspaceTransitionStop )
223
242
build = coderdtest .AwaitWorkspaceBuildJobCompleted (t , client , build .ID )
224
243
225
244
// Quota goes down one
226
- verifyQuota (ctx , t , client , 3 , 4 )
245
+ verifyQuota (ctx , t , client , user . OrganizationID . String (), 3 , 4 )
227
246
require .Equal (t , codersdk .WorkspaceStatusStopped , build .Status )
228
247
229
248
build = coderdtest .CreateWorkspaceBuild (t , client , workspaces [0 ], database .WorkspaceTransitionStart )
230
249
build = coderdtest .AwaitWorkspaceBuildJobCompleted (t , client , build .ID )
231
250
232
251
// Quota goes back up
233
- verifyQuota (ctx , t , client , 4 , 4 )
252
+ verifyQuota (ctx , t , client , user . OrganizationID . String (), 4 , 4 )
234
253
require .Equal (t , codersdk .WorkspaceStatusRunning , build .Status )
235
254
})
236
255
@@ -273,13 +292,27 @@ func TestWorkspaceQuota(t *testing.T) {
273
292
})
274
293
require .NoError (t , err )
275
294
276
- verifyQuota (ctx , t , member , 0 , 30 )
277
- // This currently reports the total site wide quotas. We might want to
278
- // org scope this api call in the future.
279
- verifyQuota (ctx , t , owner , 0 , 45 )
295
+ verifyQuota (ctx , t , member , first .OrganizationID .String (), 0 , 30 )
296
+
297
+ // Verify org scoped quota limits
298
+ verifyQuota (ctx , t , owner , first .OrganizationID .String (), 0 , 30 )
299
+ verifyQuota (ctx , t , owner , second .ID .String (), 0 , 15 )
280
300
})
281
301
}
282
302
303
+ func deprecatedQuotaEndpoint (ctx context.Context , client * codersdk.Client , userID string ) (codersdk.WorkspaceQuota , error ) {
304
+ res , err := client .Request (ctx , http .MethodGet , fmt .Sprintf ("/api/v2/workspace-quota/%s" , userID ), nil )
305
+ if err != nil {
306
+ return codersdk.WorkspaceQuota {}, err
307
+ }
308
+ defer res .Body .Close ()
309
+ if res .StatusCode != http .StatusOK {
310
+ return codersdk.WorkspaceQuota {}, codersdk .ReadBodyAsError (res )
311
+ }
312
+ var quota codersdk.WorkspaceQuota
313
+ return quota , json .NewDecoder (res .Body ).Decode (& quota )
314
+ }
315
+
283
316
func planWithCost (cost int32 ) []* proto.Response {
284
317
return []* proto.Response {{
285
318
Type : & proto.Response_Plan {
0 commit comments