@@ -3,6 +3,7 @@ package coderd_test
3
3
import (
4
4
"net/http"
5
5
"testing"
6
+ "time"
6
7
7
8
"github.com/google/uuid"
8
9
"github.com/stretchr/testify/assert"
@@ -265,6 +266,119 @@ func TestTasks(t *testing.T) {
265
266
assert .Equal (t ,workspace .ID ,task .WorkspaceID .UUID ,"workspace id should match" )
266
267
assert .NotEmpty (t ,task .Status ,"task status should not be empty" )
267
268
})
269
+
270
+ t .Run ("Delete" ,func (t * testing.T ) {
271
+ t .Parallel ()
272
+
273
+ t .Run ("OK" ,func (t * testing.T ) {
274
+ t .Parallel ()
275
+
276
+ client := coderdtest .New (t ,& coderdtest.Options {IncludeProvisionerDaemon :true })
277
+ user := coderdtest .CreateFirstUser (t ,client )
278
+ template := createAITemplate (t ,client ,user )
279
+
280
+ ws := coderdtest .CreateWorkspace (t ,client ,template .ID ,func (req * codersdk.CreateWorkspaceRequest ) {
281
+ req .RichParameterValues = []codersdk.WorkspaceBuildParameter {
282
+ {Name :codersdk .AITaskPromptParameterName ,Value :"delete-me" },
283
+ }
284
+ })
285
+ coderdtest .AwaitWorkspaceBuildJobCompleted (t ,client ,ws .LatestBuild .ID )
286
+
287
+ ctx := testutil .Context (t ,testutil .WaitLong )
288
+
289
+ exp := codersdk .NewExperimentalClient (client )
290
+ err := exp .DeleteTask (ctx ,"me" ,ws .ID )
291
+ require .NoError (t ,err ,"delete task request should be accepted" )
292
+
293
+ // Poll until the workspace is deleted.
294
+ for {
295
+ dws ,derr := client .DeletedWorkspace (ctx ,ws .ID )
296
+ if derr == nil && dws .LatestBuild .Status == codersdk .WorkspaceStatusDeleted {
297
+ break
298
+ }
299
+ if ctx .Err ()!= nil {
300
+ require .NoError (t ,derr ,"expected to fetch deleted workspace before deadline" )
301
+ require .Equal (t ,codersdk .WorkspaceStatusDeleted ,dws .LatestBuild .Status ,"workspace should be deleted before deadline" )
302
+ break
303
+ }
304
+ time .Sleep (testutil .IntervalMedium )
305
+ }
306
+ })
307
+
308
+ t .Run ("NotFound" ,func (t * testing.T ) {
309
+ t .Parallel ()
310
+
311
+ client := coderdtest .New (t ,& coderdtest.Options {IncludeProvisionerDaemon :true })
312
+ _ = coderdtest .CreateFirstUser (t ,client )
313
+
314
+ ctx := testutil .Context (t ,testutil .WaitShort )
315
+
316
+ exp := codersdk .NewExperimentalClient (client )
317
+ err := exp .DeleteTask (ctx ,"me" ,uuid .New ())
318
+
319
+ var sdkErr * codersdk.Error
320
+ require .Error (t ,err ,"expected an error for non-existent task" )
321
+ require .ErrorAs (t ,err ,& sdkErr )
322
+ require .Equal (t ,404 ,sdkErr .StatusCode ())
323
+ })
324
+
325
+ t .Run ("NotTaskWorkspace" ,func (t * testing.T ) {
326
+ t .Parallel ()
327
+
328
+ client := coderdtest .New (t ,& coderdtest.Options {IncludeProvisionerDaemon :true })
329
+ user := coderdtest .CreateFirstUser (t ,client )
330
+
331
+ ctx := testutil .Context (t ,testutil .WaitShort )
332
+
333
+ // Create a template without AI tasks support and a workspace from it.
334
+ version := coderdtest .CreateTemplateVersion (t ,client ,user .OrganizationID ,nil )
335
+ coderdtest .AwaitTemplateVersionJobCompleted (t ,client ,version .ID )
336
+ template := coderdtest .CreateTemplate (t ,client ,user .OrganizationID ,version .ID )
337
+ ws := coderdtest .CreateWorkspace (t ,client ,template .ID )
338
+ coderdtest .AwaitWorkspaceBuildJobCompleted (t ,client ,ws .LatestBuild .ID )
339
+
340
+ exp := codersdk .NewExperimentalClient (client )
341
+ err := exp .DeleteTask (ctx ,"me" ,ws .ID )
342
+
343
+ var sdkErr * codersdk.Error
344
+ require .Error (t ,err ,"expected an error for non-task workspace delete via tasks endpoint" )
345
+ require .ErrorAs (t ,err ,& sdkErr )
346
+ require .Equal (t ,404 ,sdkErr .StatusCode ())
347
+ })
348
+
349
+ t .Run ("UnauthorizedUserCannotDeleteOthersTask" ,func (t * testing.T ) {
350
+ t .Parallel ()
351
+
352
+ client := coderdtest .New (t ,& coderdtest.Options {IncludeProvisionerDaemon :true })
353
+ owner := coderdtest .CreateFirstUser (t ,client )
354
+
355
+ // Owner's AI-capable template and workspace (task).
356
+ template := createAITemplate (t ,client ,owner )
357
+ ws := coderdtest .CreateWorkspace (t ,client ,template .ID ,func (req * codersdk.CreateWorkspaceRequest ) {
358
+ req .RichParameterValues = []codersdk.WorkspaceBuildParameter {
359
+ {Name :codersdk .AITaskPromptParameterName ,Value :"secure" },
360
+ }
361
+ })
362
+ coderdtest .AwaitWorkspaceBuildJobCompleted (t ,client ,ws .LatestBuild .ID )
363
+
364
+ ctx := testutil .Context (t ,testutil .WaitShort )
365
+
366
+ // Another regular org member without elevated permissions.
367
+ otherClient ,_ := coderdtest .CreateAnotherUser (t ,client ,owner .OrganizationID )
368
+ expOther := codersdk .NewExperimentalClient (otherClient )
369
+
370
+ // Attempt to delete the owner's task as a non-owner without permissions.
371
+ err := expOther .DeleteTask (ctx ,"me" ,ws .ID )
372
+
373
+ var authErr * codersdk.Error
374
+ require .Error (t ,err ,"expected an authorization error when deleting another user's task" )
375
+ require .ErrorAs (t ,err ,& authErr )
376
+ // Accept either 403 or 404 depending on authz behavior.
377
+ if authErr .StatusCode ()!= 403 && authErr .StatusCode ()!= 404 {
378
+ t .Fatalf ("unexpected status code: %d (expected 403 or 404)" ,authErr .StatusCode ())
379
+ }
380
+ })
381
+ })
268
382
}
269
383
270
384
func TestTasksCreate (t * testing.T ) {