Expand Up @@ -4,6 +4,7 @@ import ( "context" "database/sql" "encoding/json" "errors" "fmt" "os" "reflect" Expand All @@ -25,7 +26,6 @@ import ( "github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbgen" "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/prometheusmetrics" Expand All @@ -51,13 +51,15 @@ func TestActiveUsers(t *testing.T) { }{{ Name: "None", Database: func(t *testing.T) database.Store { return dbmem.New() db, _ := dbtestutil.NewDB(t) return db }, Count: 0, }, { Name: "One", Database: func(t *testing.T) database.Store { db := dbmem.New() db, _ := dbtestutil.NewDB(t) dbtestutil.DisableForeignKeysAndTriggers(t, db) dbgen.APIKey(t, db, database.APIKey{ LastUsed: dbtime.Now(), }) Expand All @@ -67,7 +69,8 @@ func TestActiveUsers(t *testing.T) { }, { Name: "OneWithExpired", Database: func(t *testing.T) database.Store { db := dbmem.New() db, _ := dbtestutil.NewDB(t) dbtestutil.DisableForeignKeysAndTriggers(t, db) dbgen.APIKey(t, db, database.APIKey{ LastUsed: dbtime.Now(), Expand All @@ -84,7 +87,8 @@ func TestActiveUsers(t *testing.T) { }, { Name: "Multiple", Database: func(t *testing.T) database.Store { db := dbmem.New() db, _ := dbtestutil.NewDB(t) dbtestutil.DisableForeignKeysAndTriggers(t, db) dbgen.APIKey(t, db, database.APIKey{ LastUsed: dbtime.Now(), }) Expand Down Expand Up @@ -123,21 +127,22 @@ func TestUsers(t *testing.T) { }{{ Name: "None", Database: func(t *testing.T) database.Store { return dbmem.New() db, _ := dbtestutil.NewDB(t) return db }, Count: map[database.UserStatus]int{}, }, { Name: "One", Database: func(t *testing.T) database.Store { db :=dbmem.New( ) db, _ :=dbtestutil.NewDB(t ) dbgen.User(t, db, database.User{Status: database.UserStatusActive}) return db }, Count: map[database.UserStatus]int{database.UserStatusActive: 1}, }, { Name: "MultipleStatuses", Database: func(t *testing.T) database.Store { db :=dbmem.New( ) db, _ :=dbtestutil.NewDB(t ) dbgen.User(t, db, database.User{Status: database.UserStatusActive}) dbgen.User(t, db, database.User{Status: database.UserStatusDormant}) Expand All @@ -148,7 +153,7 @@ func TestUsers(t *testing.T) { }, { Name: "MultipleActive", Database: func(t *testing.T) database.Store { db :=dbmem.New( ) db, _ :=dbtestutil.NewDB(t ) dbgen.User(t, db, database.User{Status: database.UserStatusActive}) dbgen.User(t, db, database.User{Status: database.UserStatusActive}) dbgen.User(t, db, database.User{Status: database.UserStatusActive}) Expand Down Expand Up @@ -216,20 +221,25 @@ func TestWorkspaceLatestBuildTotals(t *testing.T) { Total int Status map[codersdk.ProvisionerJobStatus]int }{{ Name: "None", Database: dbmem.New, Total: 0, Name: "None", Database: func() database.Store { db, _ := dbtestutil.NewDB(t) return db }, Total: 0, }, { Name: "Multiple", Database: func() database.Store { db := dbmem.New() insertCanceled(t, db) insertFailed(t, db) insertFailed(t, db) insertSuccess(t, db) insertSuccess(t, db) insertSuccess(t, db) insertRunning(t, db) db, _ := dbtestutil.NewDB(t) u := dbgen.User(t, db, database.User{}) org := dbgen.Organization(t, db, database.Organization{}) insertCanceled(t, db, u, org) insertFailed(t, db, u, org) insertFailed(t, db, u, org) insertSuccess(t, db, u, org) insertSuccess(t, db, u, org) insertSuccess(t, db, u, org) insertRunning(t, db, u, org) return db }, Total: 7, Expand Down Expand Up @@ -287,21 +297,26 @@ func TestWorkspaceLatestBuildStatuses(t *testing.T) { ExpectedWorkspaces int ExpectedStatuses map[codersdk.ProvisionerJobStatus]int }{{ Name: "None", Database: dbmem.New, Name: "None", Database: func() database.Store { db, _ := dbtestutil.NewDB(t) return db }, ExpectedWorkspaces: 0, }, { Name: "Multiple", Database: func() database.Store { db := dbmem.New() insertTemplates(t, db) insertCanceled(t, db) insertFailed(t, db) insertFailed(t, db) insertSuccess(t, db) insertSuccess(t, db) insertSuccess(t, db) insertRunning(t, db) db, _ := dbtestutil.NewDB(t) u := dbgen.User(t, db, database.User{}) org := dbgen.Organization(t, db, database.Organization{}) insertTemplates(t, db, u, org) insertCanceled(t, db, u, org) insertFailed(t, db, u, org) insertFailed(t, db, u, org) insertSuccess(t, db, u, org) insertSuccess(t, db, u, org) insertSuccess(t, db, u, org) insertRunning(t, db, u, org) return db }, ExpectedWorkspaces: 7, Expand Down Expand Up @@ -727,76 +742,102 @@ var ( templateVersionB = uuid.New() ) func insertTemplates(t *testing.T, db database.Store) { func insertTemplates(t *testing.T, db database.Store, u database.User, org database.Organization ) { require.NoError(t, db.InsertTemplate(context.Background(), database.InsertTemplateParams{ ID: templateA, Name: "template-a", Provisioner: database.ProvisionerTypeTerraform, MaxPortSharingLevel: database.AppSharingLevelAuthenticated, CreatedBy: u.ID, OrganizationID: org.ID, })) pj := dbgen.ProvisionerJob(t, db, nil, database.ProvisionerJob{}) require.NoError(t, db.InsertTemplateVersion(context.Background(), database.InsertTemplateVersionParams{ ID: templateVersionA, TemplateID: uuid.NullUUID{UUID: templateA}, Name: "version-1a", ID: templateVersionA, TemplateID: uuid.NullUUID{UUID: templateA}, Name: "version-1a", JobID: pj.ID, OrganizationID: org.ID, CreatedBy: u.ID, })) require.NoError(t, db.InsertTemplate(context.Background(), database.InsertTemplateParams{ ID: templateB, Name: "template-b", Provisioner: database.ProvisionerTypeTerraform, MaxPortSharingLevel: database.AppSharingLevelAuthenticated, CreatedBy: u.ID, OrganizationID: org.ID, })) require.NoError(t, db.InsertTemplateVersion(context.Background(), database.InsertTemplateVersionParams{ ID: templateVersionB, TemplateID: uuid.NullUUID{UUID: templateB}, Name: "version-1b", ID: templateVersionB, TemplateID: uuid.NullUUID{UUID: templateB}, Name: "version-1b", JobID: pj.ID, OrganizationID: org.ID, CreatedBy: u.ID, })) } func insertUser(t *testing.T, db database.Store) database.User { username, err := cryptorand.String(8) require.NoError(t, err) user, err := db.InsertUser(context.Background(), database.InsertUserParams{ ID: uuid.New(), Username: username, LoginType: database.LoginTypeNone, }) func insertRunning(t *testing.T, db database.Store, u database.User, org database.Organization) database.ProvisionerJob { var templateID, templateVersionID uuid.UUID rnd, err := cryptorand.Intn(10) require.NoError(t, err) return user } pairs := []struct { tplID uuid.UUID versionID uuid.UUID }{ {templateA, templateVersionA}, {templateB, templateVersionB}, } for _, pair := range pairs { _, err := db.GetTemplateByID(context.Background(), pair.tplID) if errors.Is(err, sql.ErrNoRows) { _ = dbgen.Template(t, db, database.Template{ ID: pair.tplID, OrganizationID: org.ID, CreatedBy: u.ID, }) _ = dbgen.TemplateVersion(t, db, database.TemplateVersion{ ID: pair.versionID, OrganizationID: org.ID, CreatedBy: u.ID, }) } else { require.NoError(t, err) } } func insertRunning(t *testing.T, db database.Store) database.ProvisionerJob { var template, templateVersion uuid.UUID rnd, err := cryptorand.Intn(10) require.NoError(t, err) if rnd > 5 { template = templateBtemplateVersion = templateVersionBtemplateID = templateBtemplateVersionID = templateVersionB} else { template = templateAtemplateVersion = templateVersionAtemplateID = templateAtemplateVersionID = templateVersionA} workspace, err := db.InsertWorkspace(context.Background(), database.InsertWorkspaceParams{ ID: uuid.New(), OwnerID:insertUser(t, db) .ID, OwnerID:u .ID, Name: uuid.NewString(), TemplateID:template , TemplateID:templateID , AutomaticUpdates: database.AutomaticUpdatesNever, OrganizationID: org.ID, }) require.NoError(t, err) job, err := db.InsertProvisionerJob(context.Background(), database.InsertProvisionerJobParams{ ID: uuid.New(), CreatedAt: dbtime.Now(), UpdatedAt: dbtime.Now(), Provisioner: database.ProvisionerTypeEcho, StorageMethod: database.ProvisionerStorageMethodFile, Type: database.ProvisionerJobTypeWorkspaceBuild, ID: uuid.New(), CreatedAt: dbtime.Now(), UpdatedAt: dbtime.Now(), Provisioner: database.ProvisionerTypeEcho, StorageMethod: database.ProvisionerStorageMethodFile, Type: database.ProvisionerJobTypeWorkspaceBuild, Input: json.RawMessage("{}"), OrganizationID: org.ID, }) require.NoError(t, err) err = db.InsertWorkspaceBuild(context.Background(), database.InsertWorkspaceBuildParams{ Expand All @@ -806,7 +847,7 @@ func insertRunning(t *testing.T, db database.Store) database.ProvisionerJob { BuildNumber: 1, Transition: database.WorkspaceTransitionStart, Reason: database.BuildReasonInitiator, TemplateVersionID:templateVersion , TemplateVersionID:templateVersionID , }) require.NoError(t, err) // This marks the job as started. Expand All @@ -816,14 +857,15 @@ func insertRunning(t *testing.T, db database.Store) database.ProvisionerJob { Time: dbtime.Now(), Valid: true, }, Types: []database.ProvisionerType{database.ProvisionerTypeEcho}, Types: []database.ProvisionerType{database.ProvisionerTypeEcho}, ProvisionerTags: must(json.Marshal(job.Tags)), }) require.NoError(t, err) return job } func insertCanceled(t *testing.T, db database.Store) { job := insertRunning(t, db) func insertCanceled(t *testing.T, db database.Store, u database.User, org database.Organization ) { job := insertRunning(t, db, u, org ) err := db.UpdateProvisionerJobWithCancelByID(context.Background(), database.UpdateProvisionerJobWithCancelByIDParams{ ID: job.ID, CanceledAt: sql.NullTime{ Expand All @@ -842,8 +884,8 @@ func insertCanceled(t *testing.T, db database.Store) { require.NoError(t, err) } func insertFailed(t *testing.T, db database.Store) { job := insertRunning(t, db) func insertFailed(t *testing.T, db database.Store, u database.User, org database.Organization ) { job := insertRunning(t, db, u, org ) err := db.UpdateProvisionerJobWithCompleteByID(context.Background(), database.UpdateProvisionerJobWithCompleteByIDParams{ ID: job.ID, CompletedAt: sql.NullTime{ Expand All @@ -858,8 +900,8 @@ func insertFailed(t *testing.T, db database.Store) { require.NoError(t, err) } func insertSuccess(t *testing.T, db database.Store) { job := insertRunning(t, db) func insertSuccess(t *testing.T, db database.Store, u database.User, org database.Organization ) { job := insertRunning(t, db, u, org ) err := db.UpdateProvisionerJobWithCompleteByID(context.Background(), database.UpdateProvisionerJobWithCompleteByIDParams{ ID: job.ID, CompletedAt: sql.NullTime{ Expand Down