mirror of
https://github.com/coder/coder.git
synced 2025-07-15 22:20:27 +00:00
WIP: db tests
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
package prebuilds
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"testing"
|
||||
"time"
|
||||
@ -11,6 +12,7 @@ import (
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbgen"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtestutil"
|
||||
"github.com/coder/coder/v2/coderd/database/pubsub"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
"github.com/coder/coder/v2/testutil"
|
||||
"github.com/coder/serpent"
|
||||
@ -108,6 +110,128 @@ func TestNoReconciliationActionsIfNoPrebuilds(t *testing.T) {
|
||||
require.Empty(t, jobs)
|
||||
}
|
||||
|
||||
func setupTestDBTemplate(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
db database.Store,
|
||||
) (
|
||||
orgID uuid.UUID,
|
||||
userID uuid.UUID,
|
||||
templateID uuid.UUID,
|
||||
) {
|
||||
t.Helper()
|
||||
org := dbgen.Organization(t, db, database.Organization{})
|
||||
user := dbgen.User(t, db, database.User{})
|
||||
|
||||
template := dbgen.Template(t, db, database.Template{
|
||||
CreatedBy: user.ID,
|
||||
OrganizationID: org.ID,
|
||||
})
|
||||
|
||||
return org.ID, user.ID, template.ID
|
||||
}
|
||||
func setupTestDBPrebuild(
|
||||
t *testing.T,
|
||||
ctx context.Context,
|
||||
db database.Store,
|
||||
pubsub pubsub.Pubsub,
|
||||
prebuildStatus database.WorkspaceStatus,
|
||||
orgID uuid.UUID,
|
||||
userID uuid.UUID,
|
||||
templateID uuid.UUID,
|
||||
) (
|
||||
templateVersionID uuid.UUID,
|
||||
presetID uuid.UUID,
|
||||
prebuildID uuid.UUID,
|
||||
) {
|
||||
templateVersionJob := dbgen.ProvisionerJob(t, db, pubsub, database.ProvisionerJob{
|
||||
ID: uuid.New(),
|
||||
CreatedAt: time.Now().Add(-2 * time.Hour),
|
||||
CompletedAt: sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true},
|
||||
OrganizationID: orgID,
|
||||
InitiatorID: userID,
|
||||
})
|
||||
templateVersion := dbgen.TemplateVersion(t, db, database.TemplateVersion{
|
||||
TemplateID: uuid.NullUUID{UUID: templateID, Valid: true},
|
||||
OrganizationID: orgID,
|
||||
CreatedBy: userID,
|
||||
JobID: templateVersionJob.ID,
|
||||
})
|
||||
db.UpdateTemplateActiveVersionByID(ctx, database.UpdateTemplateActiveVersionByIDParams{
|
||||
ID: templateID,
|
||||
ActiveVersionID: templateVersion.ID,
|
||||
})
|
||||
preset, err := db.InsertPreset(ctx, database.InsertPresetParams{
|
||||
TemplateVersionID: templateVersion.ID,
|
||||
Name: "test",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = db.InsertPresetParameters(ctx, database.InsertPresetParametersParams{
|
||||
TemplateVersionPresetID: preset.ID,
|
||||
Names: []string{"test"},
|
||||
Values: []string{"test"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = db.InsertPresetPrebuild(ctx, database.InsertPresetPrebuildParams{
|
||||
ID: uuid.New(),
|
||||
PresetID: preset.ID,
|
||||
DesiredInstances: 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
completedAt := sql.NullTime{}
|
||||
cancelledAt := sql.NullTime{}
|
||||
transition := database.WorkspaceTransitionStart
|
||||
deleted := false
|
||||
buildError := sql.NullString{}
|
||||
switch prebuildStatus {
|
||||
case database.WorkspaceStatusRunning:
|
||||
completedAt = sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true}
|
||||
case database.WorkspaceStatusStopped:
|
||||
completedAt = sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true}
|
||||
transition = database.WorkspaceTransitionStop
|
||||
case database.WorkspaceStatusFailed:
|
||||
completedAt = sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true}
|
||||
buildError = sql.NullString{String: "build failed", Valid: true}
|
||||
case database.WorkspaceStatusCanceled:
|
||||
completedAt = sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true}
|
||||
cancelledAt = sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true}
|
||||
case database.WorkspaceStatusDeleted:
|
||||
completedAt = sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true}
|
||||
transition = database.WorkspaceTransitionDelete
|
||||
deleted = true
|
||||
case database.WorkspaceStatusPending:
|
||||
completedAt = sql.NullTime{}
|
||||
transition = database.WorkspaceTransitionStart
|
||||
default:
|
||||
}
|
||||
|
||||
workspace := dbgen.Workspace(t, db, database.WorkspaceTable{
|
||||
TemplateID: templateID,
|
||||
OrganizationID: orgID,
|
||||
OwnerID: OwnerID,
|
||||
Deleted: deleted,
|
||||
})
|
||||
job := dbgen.ProvisionerJob(t, db, pubsub, database.ProvisionerJob{
|
||||
InitiatorID: OwnerID,
|
||||
CreatedAt: time.Now().Add(-2 * time.Hour),
|
||||
CompletedAt: completedAt,
|
||||
CanceledAt: cancelledAt,
|
||||
OrganizationID: orgID,
|
||||
Error: buildError,
|
||||
})
|
||||
prebuild := dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{
|
||||
WorkspaceID: workspace.ID,
|
||||
InitiatorID: OwnerID,
|
||||
TemplateVersionID: templateVersion.ID,
|
||||
JobID: job.ID,
|
||||
TemplateVersionPresetID: uuid.NullUUID{UUID: preset.ID, Valid: true},
|
||||
Transition: transition,
|
||||
})
|
||||
|
||||
return templateVersion.ID, preset.ID, prebuild.ID
|
||||
}
|
||||
|
||||
func TestPrebuildCreation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@ -116,41 +240,63 @@ func TestPrebuildCreation(t *testing.T) {
|
||||
name string
|
||||
prebuildStatus database.WorkspaceStatus
|
||||
shouldCreateNewPrebuild bool
|
||||
shouldDeleteOldPrebuild bool
|
||||
templateVersionActive bool
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "running prebuild",
|
||||
prebuildStatus: database.WorkspaceStatusRunning,
|
||||
templateVersionActive: true,
|
||||
shouldCreateNewPrebuild: false,
|
||||
shouldDeleteOldPrebuild: false,
|
||||
},
|
||||
{
|
||||
name: "stopped prebuild",
|
||||
prebuildStatus: database.WorkspaceStatusStopped,
|
||||
shouldCreateNewPrebuild: true,
|
||||
},
|
||||
{
|
||||
name: "failed prebuild",
|
||||
prebuildStatus: database.WorkspaceStatusFailed,
|
||||
shouldCreateNewPrebuild: true,
|
||||
},
|
||||
{
|
||||
name: "canceled prebuild",
|
||||
prebuildStatus: database.WorkspaceStatusCanceled,
|
||||
shouldCreateNewPrebuild: true,
|
||||
},
|
||||
{
|
||||
name: "deleted prebuild",
|
||||
prebuildStatus: database.WorkspaceStatusDeleted,
|
||||
shouldCreateNewPrebuild: true,
|
||||
},
|
||||
{
|
||||
name: "pending prebuild",
|
||||
prebuildStatus: database.WorkspaceStatusPending,
|
||||
shouldCreateNewPrebuild: false,
|
||||
},
|
||||
// {
|
||||
// name: "stopped prebuild",
|
||||
// prebuildStatus: database.WorkspaceStatusStopped,
|
||||
// templateVersionActive: true,
|
||||
// shouldCreateNewPrebuild: true,
|
||||
// shouldDeleteOldPrebuild: false,
|
||||
// },
|
||||
// {
|
||||
// name: "failed prebuild",
|
||||
// prebuildStatus: database.WorkspaceStatusFailed,
|
||||
// templateVersionActive: true,
|
||||
// shouldCreateNewPrebuild: true,
|
||||
// shouldDeleteOldPrebuild: true,
|
||||
// },
|
||||
// {
|
||||
// name: "canceled prebuild",
|
||||
// prebuildStatus: database.WorkspaceStatusCanceled,
|
||||
// templateVersionActive: true,
|
||||
// shouldCreateNewPrebuild: true,
|
||||
// shouldDeleteOldPrebuild: true,
|
||||
// },
|
||||
// {
|
||||
// name: "deleted prebuild",
|
||||
// prebuildStatus: database.WorkspaceStatusDeleted,
|
||||
// templateVersionActive: true,
|
||||
// shouldCreateNewPrebuild: true,
|
||||
// shouldDeleteOldPrebuild: false,
|
||||
// },
|
||||
// {
|
||||
// name: "pending prebuild",
|
||||
// prebuildStatus: database.WorkspaceStatusPending,
|
||||
// templateVersionActive: true,
|
||||
// shouldCreateNewPrebuild: false,
|
||||
// shouldDeleteOldPrebuild: false,
|
||||
// },
|
||||
// {
|
||||
// name: "inactive template version",
|
||||
// prebuildStatus: database.WorkspaceStatusRunning,
|
||||
// shouldDeleteOldPrebuild: true,
|
||||
// templateVersionActive: false,
|
||||
// shouldCreateNewPrebuild: false,
|
||||
// },
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := testutil.Context(t, testutil.WaitShort)
|
||||
@ -159,102 +305,50 @@ func TestPrebuildCreation(t *testing.T) {
|
||||
logger := testutil.Logger(t)
|
||||
controller := NewController(db, pubsub, cfg, logger)
|
||||
|
||||
// given a user
|
||||
org := dbgen.Organization(t, db, database.Organization{})
|
||||
user := dbgen.User(t, db, database.User{})
|
||||
|
||||
template := dbgen.Template(t, db, database.Template{
|
||||
CreatedBy: user.ID,
|
||||
OrganizationID: org.ID,
|
||||
})
|
||||
templateVersionJob := dbgen.ProvisionerJob(t, db, pubsub, database.ProvisionerJob{
|
||||
ID: uuid.New(),
|
||||
CreatedAt: time.Now().Add(-2 * time.Hour),
|
||||
CompletedAt: sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true},
|
||||
OrganizationID: org.ID,
|
||||
InitiatorID: user.ID,
|
||||
})
|
||||
templateVersion := dbgen.TemplateVersion(t, db, database.TemplateVersion{
|
||||
TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true},
|
||||
OrganizationID: org.ID,
|
||||
CreatedBy: user.ID,
|
||||
JobID: templateVersionJob.ID,
|
||||
})
|
||||
db.UpdateTemplateActiveVersionByID(ctx, database.UpdateTemplateActiveVersionByIDParams{
|
||||
ID: template.ID,
|
||||
ActiveVersionID: templateVersion.ID,
|
||||
})
|
||||
preset, err := db.InsertPreset(ctx, database.InsertPresetParams{
|
||||
TemplateVersionID: templateVersion.ID,
|
||||
Name: "test",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = db.InsertPresetParameters(ctx, database.InsertPresetParametersParams{
|
||||
TemplateVersionPresetID: preset.ID,
|
||||
Names: []string{"test"},
|
||||
Values: []string{"test"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = db.InsertPresetPrebuild(ctx, database.InsertPresetPrebuildParams{
|
||||
ID: uuid.New(),
|
||||
PresetID: preset.ID,
|
||||
DesiredInstances: 1,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
completedAt := sql.NullTime{}
|
||||
cancelledAt := sql.NullTime{}
|
||||
transition := database.WorkspaceTransitionStart
|
||||
deleted := false
|
||||
buildError := sql.NullString{}
|
||||
switch tc.prebuildStatus {
|
||||
case database.WorkspaceStatusRunning:
|
||||
completedAt = sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true}
|
||||
case database.WorkspaceStatusStopped:
|
||||
completedAt = sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true}
|
||||
transition = database.WorkspaceTransitionStop
|
||||
case database.WorkspaceStatusFailed:
|
||||
completedAt = sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true}
|
||||
buildError = sql.NullString{String: "build failed", Valid: true}
|
||||
case database.WorkspaceStatusCanceled:
|
||||
completedAt = sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true}
|
||||
cancelledAt = sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true}
|
||||
case database.WorkspaceStatusDeleted:
|
||||
completedAt = sql.NullTime{Time: time.Now().Add(-time.Hour), Valid: true}
|
||||
transition = database.WorkspaceTransitionDelete
|
||||
deleted = true
|
||||
case database.WorkspaceStatusPending:
|
||||
completedAt = sql.NullTime{}
|
||||
transition = database.WorkspaceTransitionStart
|
||||
default:
|
||||
orgID, userID, templateID := setupTestDBTemplate(t, ctx, db)
|
||||
_, _, prebuildID := setupTestDBPrebuild(
|
||||
t,
|
||||
ctx,
|
||||
db,
|
||||
pubsub,
|
||||
tc.prebuildStatus,
|
||||
orgID,
|
||||
userID,
|
||||
templateID,
|
||||
)
|
||||
if !tc.templateVersionActive {
|
||||
_, _, _ = setupTestDBPrebuild(
|
||||
t,
|
||||
ctx,
|
||||
db,
|
||||
pubsub,
|
||||
tc.prebuildStatus,
|
||||
orgID,
|
||||
userID,
|
||||
templateID,
|
||||
)
|
||||
}
|
||||
|
||||
workspace := dbgen.Workspace(t, db, database.WorkspaceTable{
|
||||
TemplateID: template.ID,
|
||||
OrganizationID: org.ID,
|
||||
OwnerID: OwnerID,
|
||||
Deleted: deleted,
|
||||
})
|
||||
job := dbgen.ProvisionerJob(t, db, pubsub, database.ProvisionerJob{
|
||||
InitiatorID: OwnerID,
|
||||
CreatedAt: time.Now().Add(-2 * time.Hour),
|
||||
CompletedAt: completedAt,
|
||||
CanceledAt: cancelledAt,
|
||||
OrganizationID: org.ID,
|
||||
Error: buildError,
|
||||
})
|
||||
dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{
|
||||
WorkspaceID: workspace.ID,
|
||||
InitiatorID: OwnerID,
|
||||
TemplateVersionID: templateVersion.ID,
|
||||
JobID: job.ID,
|
||||
TemplateVersionPresetID: uuid.NullUUID{UUID: preset.ID, Valid: true},
|
||||
Transition: transition,
|
||||
})
|
||||
|
||||
controller.reconcile(ctx, nil)
|
||||
jobs, err := db.GetProvisionerJobsCreatedAfter(ctx, time.Now().Add(-time.Hour))
|
||||
|
||||
createdNewPrebuild := false
|
||||
deletedOldPrebuild := false
|
||||
workspaces, err := db.GetWorkspacesByTemplateID(ctx, templateID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.shouldCreateNewPrebuild, len(jobs) == 1)
|
||||
for _, workspace := range workspaces {
|
||||
if workspace.ID == prebuildID && workspace.Deleted {
|
||||
deletedOldPrebuild = true
|
||||
}
|
||||
|
||||
if workspace.ID != prebuildID && !workspace.Deleted {
|
||||
createdNewPrebuild = true
|
||||
}
|
||||
}
|
||||
require.Equal(t, tc.shouldCreateNewPrebuild, createdNewPrebuild)
|
||||
|
||||
// workspacebuilds, err := db.GetWorkspaceBuildsCreatedAfter(ctx, time.Now().Add(-24*time.Hour))
|
||||
// require.NoError(t, err)
|
||||
|
||||
require.Equal(t, tc.shouldDeleteOldPrebuild, deletedOldPrebuild)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -269,9 +363,60 @@ func TestDeleteUnwantedPrebuilds(t *testing.T) {
|
||||
logger := testutil.Logger(t)
|
||||
controller := NewController(db, pubsub, cfg, logger)
|
||||
|
||||
type testCase struct {
|
||||
name string
|
||||
prebuildStatus database.WorkspaceStatus
|
||||
shouldDelete bool
|
||||
}
|
||||
|
||||
testCases := []testCase{
|
||||
{
|
||||
name: "running prebuild",
|
||||
prebuildStatus: database.WorkspaceStatusRunning,
|
||||
shouldDelete: false,
|
||||
},
|
||||
{
|
||||
name: "stopped prebuild",
|
||||
prebuildStatus: database.WorkspaceStatusStopped,
|
||||
shouldDelete: true,
|
||||
},
|
||||
{
|
||||
name: "failed prebuild",
|
||||
prebuildStatus: database.WorkspaceStatusFailed,
|
||||
shouldDelete: true,
|
||||
},
|
||||
{
|
||||
name: "canceled prebuild",
|
||||
prebuildStatus: database.WorkspaceStatusCanceled,
|
||||
shouldDelete: true,
|
||||
},
|
||||
{
|
||||
name: "deleted prebuild",
|
||||
prebuildStatus: database.WorkspaceStatusDeleted,
|
||||
shouldDelete: true,
|
||||
},
|
||||
{
|
||||
name: "pending prebuild",
|
||||
prebuildStatus: database.WorkspaceStatusPending,
|
||||
shouldDelete: false,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := testutil.Context(t, testutil.WaitShort)
|
||||
db, pubsub := dbtestutil.NewDB(t)
|
||||
cfg := codersdk.PrebuildsConfig{}
|
||||
logger := testutil.Logger(t)
|
||||
controller := NewController(db, pubsub, cfg, logger)
|
||||
controller.reconcile(ctx, nil)
|
||||
jobs, err := db.GetProvisionerJobsCreatedAfter(ctx, time.Now().Add(-time.Hour))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.shouldDelete, len(jobs) == 1)
|
||||
})
|
||||
}
|
||||
// when does a prebuild get deleted?
|
||||
// * when it is in some way permanently ineligible to be claimed
|
||||
// * this could be because the build failed or was canceled
|
||||
// * or it belongs to a template version that is no longer active
|
||||
// * or it belongs to a template version that is deprecated
|
||||
// * when there are more prebuilds than the preset desires
|
||||
|
Reference in New Issue
Block a user