diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index 73c0cdbcd5195..95920d1ac2b72 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -527,7 +527,7 @@ func (q *fakeQuerier) GetWorkspaceOwnerCountsByTemplateIDs(_ context.Context, te counts := map[uuid.UUID]map[uuid.UUID]struct{}{} for _, templateID := range templateIDs { - found := false + counts[templateID] = map[uuid.UUID]struct{}{} for _, workspace := range q.workspaces { if workspace.TemplateID != templateID { continue @@ -541,11 +541,6 @@ func (q *fakeQuerier) GetWorkspaceOwnerCountsByTemplateIDs(_ context.Context, te } countByOwnerID[workspace.OwnerID] = struct{}{} counts[templateID] = countByOwnerID - found = true - break - } - if !found { - counts[templateID] = map[uuid.UUID]struct{}{} } } res := make([]database.GetWorkspaceOwnerCountsByTemplateIDsRow, 0) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 0471cd9c01735..a85b18bda4c30 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -4058,6 +4058,8 @@ FROM workspaces WHERE template_id = ANY($1 :: uuid [ ]) + -- Ignore deleted workspaces + AND deleted != true GROUP BY template_id ` diff --git a/coderd/database/queries/workspaces.sql b/coderd/database/queries/workspaces.sql index c88f687dfed28..5cb6508a12111 100644 --- a/coderd/database/queries/workspaces.sql +++ b/coderd/database/queries/workspaces.sql @@ -83,6 +83,8 @@ FROM workspaces WHERE template_id = ANY(@ids :: uuid [ ]) + -- Ignore deleted workspaces + AND deleted != true GROUP BY template_id; diff --git a/coderd/templates_test.go b/coderd/templates_test.go index 0e50463c89dd4..9f54d59003e9d 100644 --- a/coderd/templates_test.go +++ b/coderd/templates_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/coderd/coderdtest" + "github.com/coder/coder/coderd/rbac" "github.com/coder/coder/coderd/util/ptr" "github.com/coder/coder/codersdk" ) @@ -27,6 +28,37 @@ func TestTemplate(t *testing.T) { _, err := client.Template(context.Background(), template.ID) require.NoError(t, err) }) + + t.Run("WorkspaceCount", func(t *testing.T) { + t.Parallel() + ctx := context.Background() + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerD: true}) + user := coderdtest.CreateFirstUser(t, client) + member := coderdtest.CreateAnotherUser(t, client, user.OrganizationID, rbac.RoleAdmin()) + memberWithDeleted := coderdtest.CreateAnotherUser(t, client, user.OrganizationID, rbac.RoleAdmin()) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + + // Create 3 workspaces with 3 users. 2 workspaces exist, 1 is deleted + workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) + coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) + + memberWorkspace := coderdtest.CreateWorkspace(t, member, user.OrganizationID, template.ID) + coderdtest.AwaitWorkspaceBuildJob(t, member, memberWorkspace.LatestBuild.ID) + + deletedWorkspace := coderdtest.CreateWorkspace(t, memberWithDeleted, user.OrganizationID, template.ID) + coderdtest.AwaitWorkspaceBuildJob(t, client, deletedWorkspace.LatestBuild.ID) + build, err := client.CreateWorkspaceBuild(ctx, deletedWorkspace.ID, codersdk.CreateWorkspaceBuildRequest{ + Transition: codersdk.WorkspaceTransitionDelete, + }) + require.NoError(t, err) + coderdtest.AwaitWorkspaceBuildJob(t, client, build.ID) + + template, err = client.Template(context.Background(), template.ID) + require.NoError(t, err) + require.Equal(t, 2, int(template.WorkspaceOwnerCount), "workspace count") + }) } func TestPostTemplateByOrganization(t *testing.T) {