(t *testing.T)
| 551 | } |
| 552 | |
| 553 | func TestPatchCancelWorkspaceBuild(t *testing.T) { |
| 554 | t.Parallel() |
| 555 | t.Run("User is allowed to cancel", func(t *testing.T) { |
| 556 | t.Parallel() |
| 557 | |
| 558 | client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) |
| 559 | user := coderdtest.CreateFirstUser(t, client) |
| 560 | version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ |
| 561 | Parse: echo.ParseComplete, |
| 562 | ProvisionInit: echo.InitComplete, |
| 563 | ProvisionGraph: echo.GraphComplete, |
| 564 | ProvisionPlan: echo.PlanComplete, |
| 565 | // Echo will never applying since there is no complete message |
| 566 | ProvisionApply: []*proto.Response{{ |
| 567 | Type: &proto.Response_Log{ |
| 568 | Log: &proto.Log{}, |
| 569 | }, |
| 570 | }}, |
| 571 | }) |
| 572 | coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID) |
| 573 | template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) |
| 574 | workspace := coderdtest.CreateWorkspace(t, client, template.ID) |
| 575 | var build codersdk.WorkspaceBuild |
| 576 | |
| 577 | ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) |
| 578 | defer cancel() |
| 579 | |
| 580 | require.Eventually(t, func() bool { |
| 581 | var err error |
| 582 | build, err = client.WorkspaceBuild(ctx, workspace.LatestBuild.ID) |
| 583 | return assert.NoError(t, err) && build.Job.Status == codersdk.ProvisionerJobRunning |
| 584 | }, testutil.WaitShort, testutil.IntervalFast) |
| 585 | |
| 586 | require.Eventually(t, func() bool { |
| 587 | err := client.CancelWorkspaceBuild(ctx, build.ID, codersdk.CancelWorkspaceBuildParams{}) |
| 588 | return err == nil |
| 589 | }, testutil.WaitShort, testutil.IntervalMedium) |
| 590 | |
| 591 | require.Eventually(t, func() bool { |
| 592 | var err error |
| 593 | build, err = client.WorkspaceBuild(ctx, build.ID) |
| 594 | // job gets marked Failed when there is an Error; in practice we never get to Status = Canceled |
| 595 | // because provisioners report an Error when canceled. We check the Error string to ensure we don't mask |
| 596 | // other errors in this test. |
| 597 | return assert.NoError(t, err) && |
| 598 | build.Job.Error == "canceled" && |
| 599 | build.Job.Status == codersdk.ProvisionerJobFailed |
| 600 | }, testutil.WaitShort, testutil.IntervalFast) |
| 601 | }) |
| 602 | t.Run("User is not allowed to cancel", func(t *testing.T) { |
| 603 | t.Parallel() |
| 604 | |
| 605 | // need to include our own logger because the provisioner (rightly) drops error logs when we shut down the |
| 606 | // test with a build in progress. |
| 607 | logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}).Leveled(slog.LevelDebug) |
| 608 | client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true, Logger: &logger}) |
| 609 | owner := coderdtest.CreateFirstUser(t, client) |
| 610 | version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, &echo.Responses{ |
nothing calls this directly
no test coverage detected