chore: refactor ResolveAutostart tests to use dbfake (#10603)

This commit is contained in:
Jon Ayers 2023-11-30 19:33:04 -06:00 committed by GitHub
parent 12a4b114de
commit 967db2801b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 475 additions and 295 deletions

View File

@ -31,11 +31,10 @@ func TestWorkspaceAgent(t *testing.T) {
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db). r := dbfake.WorkspaceBuild(t, db, database.Workspace{
Seed(database.Workspace{ OrganizationID: user.OrganizationID,
OrganizationID: user.OrganizationID, OwnerID: user.UserID,
OwnerID: user.UserID, }).
}).
WithAgent(). WithAgent().
Do() Do()
logDir := t.TempDir() logDir := t.TempDir()
@ -68,7 +67,7 @@ func TestWorkspaceAgent(t *testing.T) {
AzureCertificates: certificates, AzureCertificates: certificates,
}) })
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent { }).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@ -105,7 +104,7 @@ func TestWorkspaceAgent(t *testing.T) {
AWSCertificates: certificates, AWSCertificates: certificates,
}) })
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent { }).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@ -143,7 +142,7 @@ func TestWorkspaceAgent(t *testing.T) {
}) })
owner := coderdtest.CreateFirstUser(t, client) owner := coderdtest.CreateFirstUser(t, client)
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: owner.OrganizationID, OrganizationID: owner.OrganizationID,
OwnerID: memberUser.ID, OwnerID: memberUser.ID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent { }).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@ -195,13 +194,10 @@ func TestWorkspaceAgent(t *testing.T) {
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db). r := dbfake.WorkspaceBuild(t, db, database.Workspace{
Seed(database.Workspace{ OrganizationID: user.OrganizationID,
OrganizationID: user.OrganizationID, OwnerID: user.UserID,
OwnerID: user.UserID, }).WithAgent().Do()
}).
WithAgent().
Do()
logDir := t.TempDir() logDir := t.TempDir()
inv, _ := clitest.New(t, inv, _ := clitest.New(t,

View File

@ -77,13 +77,10 @@ func TestConfigSSH(t *testing.T) {
}) })
owner := coderdtest.CreateFirstUser(t, client) owner := coderdtest.CreateFirstUser(t, client)
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
r := dbfake.Workspace(t, db). r := dbfake.WorkspaceBuild(t, db, database.Workspace{
Seed(database.Workspace{ OrganizationID: owner.OrganizationID,
OrganizationID: owner.OrganizationID, OwnerID: memberUser.ID,
OwnerID: memberUser.ID, }).WithAgent().Do()
}).
WithAgent().
Do()
_ = agenttest.New(t, client.URL, r.AgentToken) _ = agenttest.New(t, client.URL, r.AgentToken)
resources := coderdtest.AwaitWorkspaceAgents(t, client, r.Workspace.ID) resources := coderdtest.AwaitWorkspaceAgents(t, client, r.Workspace.ID)
agentConn, err := client.DialWorkspaceAgent(context.Background(), resources[0].Agents[0].ID, nil) agentConn, err := client.DialWorkspaceAgent(context.Background(), resources[0].Agents[0].ID, nil)
@ -575,7 +572,7 @@ func TestConfigSSH_FileWriteAndOptionsFlow(t *testing.T) {
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
if tt.hasAgent { if tt.hasAgent {
_ = dbfake.Workspace(t, db).Seed(database.Workspace{ _ = dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent().Do() }).WithAgent().Do()
@ -695,11 +692,10 @@ func TestConfigSSH_Hostnames(t *testing.T) {
owner := coderdtest.CreateFirstUser(t, client) owner := coderdtest.CreateFirstUser(t, client)
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: owner.OrganizationID, OrganizationID: owner.OrganizationID,
OwnerID: memberUser.ID, OwnerID: memberUser.ID,
}).Do() }).Resource(resources...).Do()
dbfake.WorkspaceBuild(t, db, r.Workspace).Resource(resources...).Do()
sshConfigFile := sshConfigFileName(t) sshConfigFile := sshConfigFileName(t)
inv, root := clitest.New(t, "config-ssh", "--ssh-config-file", sshConfigFile) inv, root := clitest.New(t, "config-ssh", "--ssh-config-file", sshConfigFile)

View File

@ -48,13 +48,11 @@ func prepareTestGitSSH(ctx context.Context, t *testing.T) (*agentsdk.Client, str
require.NoError(t, err) require.NoError(t, err)
// setup template // setup template
r := dbfake.Workspace(t, db). r := dbfake.WorkspaceBuild(t, db, database.Workspace{
Seed(database.Workspace{ OrganizationID: user.OrganizationID,
OrganizationID: user.OrganizationID, OwnerID: user.UserID,
OwnerID: user.UserID, }).WithAgent().Do()
}).
WithAgent().
Do()
// start workspace agent // start workspace agent
agentClient := agentsdk.New(client.URL) agentClient := agentsdk.New(client.URL)
agentClient.SetSessionToken(r.AgentToken) agentClient.SetSessionToken(r.AgentToken)

View File

@ -25,10 +25,12 @@ func TestList(t *testing.T) {
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
owner := coderdtest.CreateFirstUser(t, client) owner := coderdtest.CreateFirstUser(t, client)
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ // setup template
r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: owner.OrganizationID, OrganizationID: owner.OrganizationID,
OwnerID: memberUser.ID, OwnerID: memberUser.ID,
}).WithAgent().Do() }).WithAgent().Do()
inv, root := clitest.New(t, "ls") inv, root := clitest.New(t, "ls")
clitest.SetupConfig(t, member, root) clitest.SetupConfig(t, member, root)
pty := ptytest.New(t).Attach(inv) pty := ptytest.New(t).Attach(inv)
@ -52,7 +54,7 @@ func TestList(t *testing.T) {
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
owner := coderdtest.CreateFirstUser(t, client) owner := coderdtest.CreateFirstUser(t, client)
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
dbfake.Workspace(t, db).Seed(database.Workspace{ _ = dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: owner.OrganizationID, OrganizationID: owner.OrganizationID,
OwnerID: memberUser.ID, OwnerID: memberUser.ID,
}).WithAgent().Do() }).WithAgent().Do()

View File

@ -305,10 +305,11 @@ func runAgent(t *testing.T, client *codersdk.Client, owner uuid.UUID, db databas
require.NoError(t, err, "specified user does not exist") require.NoError(t, err, "specified user does not exist")
require.Greater(t, len(user.OrganizationIDs), 0, "user has no organizations") require.Greater(t, len(user.OrganizationIDs), 0, "user has no organizations")
orgID := user.OrganizationIDs[0] orgID := user.OrganizationIDs[0]
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: orgID, OrganizationID: orgID,
OwnerID: owner, OwnerID: owner,
}).WithAgent().Do() }).WithAgent().Do()
_ = agenttest.New(t, client.URL, r.AgentToken, _ = agenttest.New(t, client.URL, r.AgentToken,
func(o *agent.Options) { func(o *agent.Options) {
o.SSHMaxTimeout = 60 * time.Second o.SSHMaxTimeout = 60 * time.Second

View File

@ -38,26 +38,27 @@ func setupTestSchedule(t *testing.T, sched *cron.Schedule) (ownerClient, memberC
memberClient, memberUser := coderdtest.CreateAnotherUserMutators(t, ownerClient, owner.OrganizationID, nil, func(r *codersdk.CreateUserRequest) { memberClient, memberUser := coderdtest.CreateAnotherUserMutators(t, ownerClient, owner.OrganizationID, nil, func(r *codersdk.CreateUserRequest) {
r.Username = "testuser2" // ensure deterministic ordering r.Username = "testuser2" // ensure deterministic ordering
}) })
_ = dbfake.Workspace(t, db).Seed(database.Workspace{ _ = dbfake.WorkspaceBuild(t, db, database.Workspace{
Name: "a-owner", Name: "a-owner",
OwnerID: owner.UserID, OwnerID: owner.UserID,
OrganizationID: owner.OrganizationID, OrganizationID: owner.OrganizationID,
AutostartSchedule: sql.NullString{String: sched.String(), Valid: true}, AutostartSchedule: sql.NullString{String: sched.String(), Valid: true},
Ttl: sql.NullInt64{Int64: 8 * time.Hour.Nanoseconds(), Valid: true}, Ttl: sql.NullInt64{Int64: 8 * time.Hour.Nanoseconds(), Valid: true},
}).WithAgent().Do() }).WithAgent().Do()
_ = dbfake.Workspace(t, db).Seed(database.Workspace{
_ = dbfake.WorkspaceBuild(t, db, database.Workspace{
Name: "b-owner", Name: "b-owner",
OwnerID: owner.UserID, OwnerID: owner.UserID,
OrganizationID: owner.OrganizationID, OrganizationID: owner.OrganizationID,
AutostartSchedule: sql.NullString{String: sched.String(), Valid: true}, AutostartSchedule: sql.NullString{String: sched.String(), Valid: true},
}).WithAgent().Do() }).WithAgent().Do()
_ = dbfake.Workspace(t, db).Seed(database.Workspace{ _ = dbfake.WorkspaceBuild(t, db, database.Workspace{
Name: "c-member", Name: "c-member",
OwnerID: memberUser.ID, OwnerID: memberUser.ID,
OrganizationID: owner.OrganizationID, OrganizationID: owner.OrganizationID,
Ttl: sql.NullInt64{Int64: 8 * time.Hour.Nanoseconds(), Valid: true}, Ttl: sql.NullInt64{Int64: 8 * time.Hour.Nanoseconds(), Valid: true},
}).WithAgent().Do() }).WithAgent().Do()
_ = dbfake.Workspace(t, db).Seed(database.Workspace{ _ = dbfake.WorkspaceBuild(t, db, database.Workspace{
Name: "d-member", Name: "d-member",
OwnerID: memberUser.ID, OwnerID: memberUser.ID,
OrganizationID: owner.OrganizationID, OrganizationID: owner.OrganizationID,

View File

@ -52,13 +52,10 @@ func setupWorkspaceForAgent(t *testing.T, mutations ...func([]*proto.Agent) []*p
client.SetLogger(slogtest.Make(t, nil).Named("client").Leveled(slog.LevelDebug)) client.SetLogger(slogtest.Make(t, nil).Named("client").Leveled(slog.LevelDebug))
first := coderdtest.CreateFirstUser(t, client) first := coderdtest.CreateFirstUser(t, client)
userClient, user := coderdtest.CreateAnotherUser(t, client, first.OrganizationID) userClient, user := coderdtest.CreateAnotherUser(t, client, first.OrganizationID)
r := dbfake.Workspace(t, store). r := dbfake.WorkspaceBuild(t, store, database.Workspace{
Seed(database.Workspace{ OrganizationID: first.OrganizationID,
OrganizationID: first.OrganizationID, OwnerID: user.ID,
OwnerID: user.ID, }).WithAgent(mutations...).Do()
}).
WithAgent(mutations...).
Do()
return userClient, r.Workspace, r.AgentToken return userClient, r.Workspace, r.AgentToken
} }
@ -130,7 +127,7 @@ func TestSSH(t *testing.T) {
client.SetLogger(slogtest.Make(t, nil).Named("client").Leveled(slog.LevelDebug)) client.SetLogger(slogtest.Make(t, nil).Named("client").Leveled(slog.LevelDebug))
first := coderdtest.CreateFirstUser(t, client) first := coderdtest.CreateFirstUser(t, client)
userClient, user := coderdtest.CreateAnotherUser(t, client, first.OrganizationID) userClient, user := coderdtest.CreateAnotherUser(t, client, first.OrganizationID)
r := dbfake.Workspace(t, store).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, store, database.Workspace{
OrganizationID: first.OrganizationID, OrganizationID: first.OrganizationID,
OwnerID: user.ID, OwnerID: user.ID,
}).WithAgent().Do() }).WithAgent().Do()
@ -469,7 +466,7 @@ func TestSSH(t *testing.T) {
client.SetLogger(slogtest.Make(t, nil).Named("client").Leveled(slog.LevelDebug)) client.SetLogger(slogtest.Make(t, nil).Named("client").Leveled(slog.LevelDebug))
first := coderdtest.CreateFirstUser(t, client) first := coderdtest.CreateFirstUser(t, client)
userClient, user := coderdtest.CreateAnotherUser(t, client, first.OrganizationID) userClient, user := coderdtest.CreateAnotherUser(t, client, first.OrganizationID)
r := dbfake.Workspace(t, store).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, store, database.Workspace{
OrganizationID: first.OrganizationID, OrganizationID: first.OrganizationID,
OwnerID: user.ID, OwnerID: user.ID,
}).WithAgent().Do() }).WithAgent().Do()

View File

@ -753,6 +753,8 @@ func CreateWorkspaceBuild(
transition database.WorkspaceTransition, transition database.WorkspaceTransition,
mutators ...func(*codersdk.CreateWorkspaceBuildRequest), mutators ...func(*codersdk.CreateWorkspaceBuildRequest),
) codersdk.WorkspaceBuild { ) codersdk.WorkspaceBuild {
t.Helper()
req := codersdk.CreateWorkspaceBuildRequest{ req := codersdk.CreateWorkspaceBuildRequest{
Transition: codersdk.WorkspaceTransition(transition), Transition: codersdk.WorkspaceTransition(transition),
} }

View File

@ -16,37 +16,71 @@ import (
"github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/database/dbtime"
"github.com/coder/coder/v2/coderd/database/pubsub" "github.com/coder/coder/v2/coderd/database/pubsub"
"github.com/coder/coder/v2/coderd/provisionerdserver" "github.com/coder/coder/v2/coderd/provisionerdserver"
"github.com/coder/coder/v2/coderd/rbac"
"github.com/coder/coder/v2/coderd/telemetry" "github.com/coder/coder/v2/coderd/telemetry"
"github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk"
sdkproto "github.com/coder/coder/v2/provisionersdk/proto" sdkproto "github.com/coder/coder/v2/provisionersdk/proto"
) )
type WorkspaceBuilder struct { var ownerCtx = dbauthz.As(context.Background(), rbac.Subject{
t testing.TB ID: "owner",
db database.Store Roles: rbac.Roles(must(rbac.RoleNames{rbac.RoleOwner()}.Expand())),
seed database.Workspace Groups: []string{},
resources []*sdkproto.Resource Scope: rbac.ExpandableScope(rbac.ScopeAll),
agentToken string })
}
type WorkspaceResponse struct { type WorkspaceResponse struct {
Workspace database.Workspace Workspace database.Workspace
Template database.Template
Build database.WorkspaceBuild Build database.WorkspaceBuild
AgentToken string AgentToken string
TemplateVersionResponse
} }
func Workspace(t testing.TB, db database.Store) WorkspaceBuilder { // WorkspaceBuildBuilder generates workspace builds and associated
return WorkspaceBuilder{t: t, db: db} // resources.
type WorkspaceBuildBuilder struct {
t testing.TB
db database.Store
ps pubsub.Pubsub
ws database.Workspace
seed database.WorkspaceBuild
resources []*sdkproto.Resource
params []database.WorkspaceBuildParameter
agentToken string
} }
func (b WorkspaceBuilder) Seed(seed database.Workspace) WorkspaceBuilder { // WorkspaceBuild generates a workspace build for the provided workspace.
// Pass a database.Workspace{} with a nil ID to also generate a new workspace.
// Omitting the template ID on a workspace will also generate a new template
// with a template version.
func WorkspaceBuild(t testing.TB, db database.Store, ws database.Workspace) WorkspaceBuildBuilder {
return WorkspaceBuildBuilder{t: t, db: db, ws: ws}
}
func (b WorkspaceBuildBuilder) Pubsub(ps pubsub.Pubsub) WorkspaceBuildBuilder {
// nolint: revive // returns modified struct
b.ps = ps
return b
}
func (b WorkspaceBuildBuilder) Seed(seed database.WorkspaceBuild) WorkspaceBuildBuilder {
//nolint: revive // returns modified struct //nolint: revive // returns modified struct
b.seed = seed b.seed = seed
return b return b
} }
func (b WorkspaceBuilder) WithAgent(mutations ...func([]*sdkproto.Agent) []*sdkproto.Agent) WorkspaceBuilder { func (b WorkspaceBuildBuilder) Resource(resource ...*sdkproto.Resource) WorkspaceBuildBuilder {
//nolint: revive // returns modified struct
b.resources = append(b.resources, resource...)
return b
}
func (b WorkspaceBuildBuilder) Params(params ...database.WorkspaceBuildParameter) WorkspaceBuildBuilder {
b.params = params
return b
}
func (b WorkspaceBuildBuilder) WithAgent(mutations ...func([]*sdkproto.Agent) []*sdkproto.Agent) WorkspaceBuildBuilder {
//nolint: revive // returns modified struct //nolint: revive // returns modified struct
b.agentToken = uuid.NewString() b.agentToken = uuid.NewString()
agents := []*sdkproto.Agent{{ agents := []*sdkproto.Agent{{
@ -66,75 +100,57 @@ func (b WorkspaceBuilder) WithAgent(mutations ...func([]*sdkproto.Agent) []*sdkp
return b return b
} }
func (b WorkspaceBuilder) Do() WorkspaceResponse { // Do generates all the resources associated with a workspace build.
var r WorkspaceResponse // Template and TemplateVersion will be optionally populated if no
// This intentionally fulfills the minimum requirements of the schema. // TemplateID is set on the provided workspace.
// Tests can provide a custom template ID if necessary. // Workspace will be optionally populated if no ID is set on the provided
if b.seed.TemplateID == uuid.Nil { // workspace.
r.Template = dbgen.Template(b.t, b.db, database.Template{ func (b WorkspaceBuildBuilder) Do() WorkspaceResponse {
OrganizationID: b.seed.OrganizationID,
CreatedBy: b.seed.OwnerID,
})
b.seed.TemplateID = r.Template.ID
b.seed.OwnerID = r.Template.CreatedBy
b.seed.OrganizationID = r.Template.OrganizationID
}
r.Workspace = dbgen.Workspace(b.t, b.db, b.seed)
if b.agentToken != "" {
r.AgentToken = b.agentToken
r.Build = WorkspaceBuild(b.t, b.db, r.Workspace).
Resource(b.resources...).
Do()
}
return r
}
type WorkspaceBuildBuilder struct {
t testing.TB
db database.Store
ps pubsub.Pubsub
ws database.Workspace
seed database.WorkspaceBuild
resources []*sdkproto.Resource
}
func WorkspaceBuild(t testing.TB, db database.Store, ws database.Workspace) WorkspaceBuildBuilder {
return WorkspaceBuildBuilder{t: t, db: db, ws: ws}
}
func (b WorkspaceBuildBuilder) Pubsub(ps pubsub.Pubsub) WorkspaceBuildBuilder {
//nolint: revive // returns modified struct
b.ps = ps
return b
}
func (b WorkspaceBuildBuilder) Seed(seed database.WorkspaceBuild) WorkspaceBuildBuilder {
//nolint: revive // returns modified struct
b.seed = seed
return b
}
func (b WorkspaceBuildBuilder) Resource(resource ...*sdkproto.Resource) WorkspaceBuildBuilder {
//nolint: revive // returns modified struct
b.resources = append(b.resources, resource...)
return b
}
func (b WorkspaceBuildBuilder) Do() database.WorkspaceBuild {
b.t.Helper() b.t.Helper()
jobID := uuid.New() jobID := uuid.New()
b.seed.ID = uuid.New() b.seed.ID = uuid.New()
b.seed.JobID = jobID b.seed.JobID = jobID
resp := WorkspaceResponse{
AgentToken: b.agentToken,
}
if b.ws.TemplateID == uuid.Nil {
resp.TemplateVersionResponse = TemplateVersion(b.t, b.db).
Resources(b.resources...).
Pubsub(b.ps).
Seed(database.TemplateVersion{
OrganizationID: b.ws.OrganizationID,
CreatedBy: b.ws.OwnerID,
}).
Do()
b.ws.TemplateID = resp.Template.ID
b.seed.TemplateVersionID = resp.TemplateVersion.ID
}
// If no template version is set assume the active version.
if b.seed.TemplateVersionID == uuid.Nil {
template, err := b.db.GetTemplateByID(ownerCtx, b.ws.TemplateID)
require.NoError(b.t, err)
require.NotNil(b.t, template.ActiveVersionID, "active version ID unexpectedly nil")
b.seed.TemplateVersionID = template.ActiveVersionID
}
// No ID on the workspace implies we should generate an entry.
if b.ws.ID == uuid.Nil {
// nolint: revive
b.ws = dbgen.Workspace(b.t, b.db, b.ws)
resp.Workspace = b.ws
}
b.seed.WorkspaceID = b.ws.ID b.seed.WorkspaceID = b.ws.ID
b.seed.InitiatorID = takeFirst(b.seed.InitiatorID, b.ws.OwnerID)
// Create a provisioner job for the build! // Create a provisioner job for the build!
payload, err := json.Marshal(provisionerdserver.WorkspaceProvisionJob{ payload, err := json.Marshal(provisionerdserver.WorkspaceProvisionJob{
WorkspaceBuildID: b.seed.ID, WorkspaceBuildID: b.seed.ID,
}) })
require.NoError(b.t, err) require.NoError(b.t, err)
//nolint:gocritic // This is only used by tests.
ctx := dbauthz.AsSystemRestricted(context.Background()) job, err := b.db.InsertProvisionerJob(ownerCtx, database.InsertProvisionerJobParams{
job, err := b.db.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{
ID: jobID, ID: jobID,
CreatedAt: dbtime.Now(), CreatedAt: dbtime.Now(),
UpdatedAt: dbtime.Now(), UpdatedAt: dbtime.Now(),
@ -149,7 +165,8 @@ func (b WorkspaceBuildBuilder) Do() database.WorkspaceBuild {
TraceMetadata: pqtype.NullRawMessage{}, TraceMetadata: pqtype.NullRawMessage{},
}) })
require.NoError(b.t, err, "insert job") require.NoError(b.t, err, "insert job")
err = b.db.UpdateProvisionerJobWithCompleteByID(ctx, database.UpdateProvisionerJobWithCompleteByIDParams{
err = b.db.UpdateProvisionerJobWithCompleteByID(ownerCtx, database.UpdateProvisionerJobWithCompleteByIDParams{
ID: job.ID, ID: job.ID,
UpdatedAt: dbtime.Now(), UpdatedAt: dbtime.Now(),
Error: sql.NullString{}, Error: sql.NullString{},
@ -161,42 +178,20 @@ func (b WorkspaceBuildBuilder) Do() database.WorkspaceBuild {
}) })
require.NoError(b.t, err, "complete job") require.NoError(b.t, err, "complete job")
// This intentionally fulfills the minimum requirements of the schema. resp.Build = dbgen.WorkspaceBuild(b.t, b.db, b.seed)
// Tests can provide a custom version ID if necessary.
if b.seed.TemplateVersionID == uuid.Nil {
jobID := uuid.New()
templateVersion := dbgen.TemplateVersion(b.t, b.db, database.TemplateVersion{
JobID: jobID,
OrganizationID: b.ws.OrganizationID,
CreatedBy: b.ws.OwnerID,
TemplateID: uuid.NullUUID{
UUID: b.ws.TemplateID,
Valid: true,
},
})
payload, _ := json.Marshal(provisionerdserver.TemplateVersionImportJob{
TemplateVersionID: templateVersion.ID,
})
dbgen.ProvisionerJob(b.t, b.db, nil, database.ProvisionerJob{
ID: jobID,
OrganizationID: b.ws.OrganizationID,
Input: payload,
Type: database.ProvisionerJobTypeTemplateVersionImport,
CompletedAt: sql.NullTime{
Time: dbtime.Now(),
Valid: true,
},
})
ProvisionerJobResources(b.t, b.db, jobID, b.seed.Transition, b.resources...).Do()
b.seed.TemplateVersionID = templateVersion.ID
}
build := dbgen.WorkspaceBuild(b.t, b.db, b.seed)
ProvisionerJobResources(b.t, b.db, job.ID, b.seed.Transition, b.resources...).Do() ProvisionerJobResources(b.t, b.db, job.ID, b.seed.Transition, b.resources...).Do()
for i := range b.params {
b.params[i].WorkspaceBuildID = resp.Build.ID
}
_ = dbgen.WorkspaceBuildParameters(b.t, b.db, b.params)
if b.ps != nil { if b.ps != nil {
err = b.ps.Publish(codersdk.WorkspaceNotifyChannel(build.WorkspaceID), []byte{}) err = b.ps.Publish(codersdk.WorkspaceNotifyChannel(resp.Build.WorkspaceID), []byte{})
require.NoError(b.t, err) require.NoError(b.t, err)
} }
return build
return resp
} }
type ProvisionerJobResourcesBuilder struct { type ProvisionerJobResourcesBuilder struct {
@ -229,7 +224,148 @@ func (b ProvisionerJobResourcesBuilder) Do() {
} }
for _, resource := range b.resources { for _, resource := range b.resources {
//nolint:gocritic // This is only used by tests. //nolint:gocritic // This is only used by tests.
err := provisionerdserver.InsertWorkspaceResource(dbauthz.AsSystemRestricted(context.Background()), b.db, b.jobID, transition, resource, &telemetry.Snapshot{}) err := provisionerdserver.InsertWorkspaceResource(ownerCtx, b.db, b.jobID, transition, resource, &telemetry.Snapshot{})
require.NoError(b.t, err) require.NoError(b.t, err)
} }
} }
type TemplateVersionResponse struct {
Template database.Template
TemplateVersion database.TemplateVersion
}
type TemplateVersionBuilder struct {
t testing.TB
db database.Store
seed database.TemplateVersion
ps pubsub.Pubsub
resources []*sdkproto.Resource
params []database.TemplateVersionParameter
promote bool
}
// TemplateVersion generates a template version and optionally a parent
// template if no template ID is set on the seed.
func TemplateVersion(t testing.TB, db database.Store) TemplateVersionBuilder {
return TemplateVersionBuilder{
t: t,
db: db,
promote: true,
}
}
func (t TemplateVersionBuilder) Seed(v database.TemplateVersion) TemplateVersionBuilder {
// nolint: revive // returns modified struct
t.seed = v
return t
}
func (t TemplateVersionBuilder) Pubsub(ps pubsub.Pubsub) TemplateVersionBuilder {
// nolint: revive // returns modified struct
t.ps = ps
return t
}
func (t TemplateVersionBuilder) Resources(rs ...*sdkproto.Resource) TemplateVersionBuilder {
// nolint: revive // returns modified struct
t.resources = rs
return t
}
func (t TemplateVersionBuilder) Params(ps ...database.TemplateVersionParameter) TemplateVersionBuilder {
// nolint: revive // returns modified struct
t.params = ps
return t
}
func (t TemplateVersionBuilder) Do() TemplateVersionResponse {
t.t.Helper()
t.seed.OrganizationID = takeFirst(t.seed.OrganizationID, uuid.New())
t.seed.ID = takeFirst(t.seed.ID, uuid.New())
t.seed.CreatedBy = takeFirst(t.seed.CreatedBy, uuid.New())
var resp TemplateVersionResponse
if t.seed.TemplateID.UUID == uuid.Nil {
resp.Template = dbgen.Template(t.t, t.db, database.Template{
ActiveVersionID: t.seed.ID,
OrganizationID: t.seed.OrganizationID,
CreatedBy: t.seed.CreatedBy,
})
t.seed.TemplateID = uuid.NullUUID{
Valid: true,
UUID: resp.Template.ID,
}
}
version := dbgen.TemplateVersion(t.t, t.db, t.seed)
// Always make this version the active version. We can easily
// add a conditional to the builder to opt out of this when
// necessary.
err := t.db.UpdateTemplateActiveVersionByID(ownerCtx, database.UpdateTemplateActiveVersionByIDParams{
ID: t.seed.TemplateID.UUID,
ActiveVersionID: t.seed.ID,
UpdatedAt: dbtime.Now(),
})
require.NoError(t.t, err)
payload, err := json.Marshal(provisionerdserver.TemplateVersionImportJob{
TemplateVersionID: t.seed.ID,
})
require.NoError(t.t, err)
job := dbgen.ProvisionerJob(t.t, t.db, t.ps, database.ProvisionerJob{
ID: version.JobID,
OrganizationID: t.seed.OrganizationID,
InitiatorID: t.seed.CreatedBy,
Type: database.ProvisionerJobTypeTemplateVersionImport,
Input: payload,
CompletedAt: sql.NullTime{
Time: dbtime.Now(),
Valid: true,
},
})
t.seed.JobID = job.ID
ProvisionerJobResources(t.t, t.db, job.ID, "", t.resources...).Do()
for i, param := range t.params {
param.TemplateVersionID = version.ID
t.params[i] = dbgen.TemplateVersionParameter(t.t, t.db, param)
}
resp.TemplateVersion = version
return resp
}
func must[V any](v V, err error) V {
if err != nil {
panic(err)
}
return v
}
// takeFirstF takes the first value that returns true
func takeFirstF[Value any](values []Value, take func(v Value) bool) Value {
for _, v := range values {
if take(v) {
return v
}
}
// If all empty, return the last element
if len(values) > 0 {
return values[len(values)-1]
}
var empty Value
return empty
}
// takeFirst will take the first non-empty value.
func takeFirst[Value comparable](values ...Value) Value {
var empty Value
return takeFirstF(values, func(v Value) bool {
return v != empty
})
}

View File

@ -167,6 +167,8 @@ func WorkspaceAgent(t testing.TB, db database.Store, orig database.WorkspaceAgen
} }
func Workspace(t testing.TB, db database.Store, orig database.Workspace) database.Workspace { func Workspace(t testing.TB, db database.Store, orig database.Workspace) database.Workspace {
t.Helper()
workspace, err := db.InsertWorkspace(genCtx, database.InsertWorkspaceParams{ workspace, err := db.InsertWorkspace(genCtx, database.InsertWorkspaceParams{
ID: takeFirst(orig.ID, uuid.New()), ID: takeFirst(orig.ID, uuid.New()),
OwnerID: takeFirst(orig.OwnerID, uuid.New()), OwnerID: takeFirst(orig.OwnerID, uuid.New()),
@ -197,6 +199,8 @@ func WorkspaceAgentLogSource(t testing.TB, db database.Store, orig database.Work
} }
func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuild) database.WorkspaceBuild { func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuild) database.WorkspaceBuild {
t.Helper()
buildID := takeFirst(orig.ID, uuid.New()) buildID := takeFirst(orig.ID, uuid.New())
var build database.WorkspaceBuild var build database.WorkspaceBuild
err := db.InTx(func(db database.Store) error { err := db.InTx(func(db database.Store) error {
@ -229,6 +233,38 @@ func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuil
return build return build
} }
func WorkspaceBuildParameters(t testing.TB, db database.Store, orig []database.WorkspaceBuildParameter) []database.WorkspaceBuildParameter {
if len(orig) == 0 {
return nil
}
var (
names = make([]string, 0, len(orig))
values = make([]string, 0, len(orig))
params []database.WorkspaceBuildParameter
)
for _, param := range orig {
names = append(names, param.Name)
values = append(values, param.Value)
}
err := db.InTx(func(tx database.Store) error {
id := takeFirst(orig[0].WorkspaceBuildID, uuid.New())
err := tx.InsertWorkspaceBuildParameters(genCtx, database.InsertWorkspaceBuildParametersParams{
WorkspaceBuildID: id,
Name: names,
Value: values,
})
if err != nil {
return err
}
params, err = tx.GetWorkspaceBuildParameters(genCtx, id)
return err
}, nil)
require.NoError(t, err)
return params
}
func User(t testing.TB, db database.Store, orig database.User) database.User { func User(t testing.TB, db database.Store, orig database.User) database.User {
user, err := db.InsertUser(genCtx, database.InsertUserParams{ user, err := db.InsertUser(genCtx, database.InsertUserParams{
ID: takeFirst(orig.ID, uuid.New()), ID: takeFirst(orig.ID, uuid.New()),
@ -335,6 +371,8 @@ func GroupMember(t testing.TB, db database.Store, orig database.GroupMember) dat
// ProvisionerJob is a bit more involved to get the values such as "completedAt", "startedAt", "cancelledAt" set. ps // ProvisionerJob is a bit more involved to get the values such as "completedAt", "startedAt", "cancelledAt" set. ps
// can be set to nil if you are SURE that you don't require a provisionerdaemon to acquire the job in your test. // can be set to nil if you are SURE that you don't require a provisionerdaemon to acquire the job in your test.
func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig database.ProvisionerJob) database.ProvisionerJob { func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig database.ProvisionerJob) database.ProvisionerJob {
t.Helper()
jobID := takeFirst(orig.ID, uuid.New()) jobID := takeFirst(orig.ID, uuid.New())
// Always set some tags to prevent Acquire from grabbing jobs it should not. // Always set some tags to prevent Acquire from grabbing jobs it should not.
if !orig.StartedAt.Time.IsZero() { if !orig.StartedAt.Time.IsZero() {
@ -545,7 +583,7 @@ func TemplateVersion(t testing.TB, db database.Store, orig database.TemplateVers
versionID := takeFirst(orig.ID, uuid.New()) versionID := takeFirst(orig.ID, uuid.New())
err := db.InsertTemplateVersion(genCtx, database.InsertTemplateVersionParams{ err := db.InsertTemplateVersion(genCtx, database.InsertTemplateVersionParams{
ID: versionID, ID: versionID,
TemplateID: orig.TemplateID, TemplateID: takeFirst(orig.TemplateID, uuid.NullUUID{}),
OrganizationID: takeFirst(orig.OrganizationID, uuid.New()), OrganizationID: takeFirst(orig.OrganizationID, uuid.New()),
CreatedAt: takeFirst(orig.CreatedAt, dbtime.Now()), CreatedAt: takeFirst(orig.CreatedAt, dbtime.Now()),
UpdatedAt: takeFirst(orig.UpdatedAt, dbtime.Now()), UpdatedAt: takeFirst(orig.UpdatedAt, dbtime.Now()),
@ -585,6 +623,32 @@ func TemplateVersionVariable(t testing.TB, db database.Store, orig database.Temp
return version return version
} }
func TemplateVersionParameter(t testing.TB, db database.Store, orig database.TemplateVersionParameter) database.TemplateVersionParameter {
t.Helper()
version, err := db.InsertTemplateVersionParameter(genCtx, database.InsertTemplateVersionParameterParams{
TemplateVersionID: takeFirst(orig.TemplateVersionID, uuid.New()),
Name: takeFirst(orig.Name, namesgenerator.GetRandomName(1)),
Description: takeFirst(orig.Description, namesgenerator.GetRandomName(1)),
Type: takeFirst(orig.Type, "string"),
Mutable: takeFirst(orig.Mutable, false),
DefaultValue: takeFirst(orig.DefaultValue, namesgenerator.GetRandomName(1)),
Icon: takeFirst(orig.Icon, namesgenerator.GetRandomName(1)),
Options: takeFirstSlice(orig.Options, []byte("[]")),
ValidationRegex: takeFirst(orig.ValidationRegex, ""),
ValidationMin: takeFirst(orig.ValidationMin, sql.NullInt32{}),
ValidationMax: takeFirst(orig.ValidationMax, sql.NullInt32{}),
ValidationError: takeFirst(orig.ValidationError, ""),
ValidationMonotonic: takeFirst(orig.ValidationMonotonic, ""),
Required: takeFirst(orig.Required, false),
DisplayName: takeFirst(orig.DisplayName, namesgenerator.GetRandomName(1)),
DisplayOrder: takeFirst(orig.DisplayOrder, 0),
Ephemeral: takeFirst(orig.Ephemeral, false),
})
require.NoError(t, err, "insert template version parameter")
return version
}
func WorkspaceAgentStat(t testing.TB, db database.Store, orig database.WorkspaceAgentStat) database.WorkspaceAgentStat { func WorkspaceAgentStat(t testing.TB, db database.Store, orig database.WorkspaceAgentStat) database.WorkspaceAgentStat {
if orig.ConnectionsByProto == nil { if orig.ConnectionsByProto == nil {
orig.ConnectionsByProto = json.RawMessage([]byte("{}")) orig.ConnectionsByProto = json.RawMessage([]byte("{}"))

View File

@ -173,6 +173,22 @@ func TestGenerator(t *testing.T) {
exp := dbgen.GitSSHKey(t, db, database.GitSSHKey{}) exp := dbgen.GitSSHKey(t, db, database.GitSSHKey{})
require.Equal(t, exp, must(db.GetGitSSHKey(context.Background(), exp.UserID))) require.Equal(t, exp, must(db.GetGitSSHKey(context.Background(), exp.UserID)))
}) })
t.Run("WorkspaceBuildParameters", func(t *testing.T) {
t.Parallel()
db := dbmem.New()
exp := dbgen.WorkspaceBuildParameters(t, db, []database.WorkspaceBuildParameter{{}, {}, {}})
require.Equal(t, exp, must(db.GetWorkspaceBuildParameters(context.Background(), exp[0].WorkspaceBuildID)))
})
t.Run("TemplateVersionParameter", func(t *testing.T) {
t.Parallel()
db := dbmem.New()
exp := dbgen.TemplateVersionParameter(t, db, database.TemplateVersionParameter{})
actual := must(db.GetTemplateVersionParameters(context.Background(), exp.TemplateVersionID))
require.Len(t, actual, 1)
require.Equal(t, exp, actual[0])
})
} }
func must[T any](value T, err error) T { func must[T any](value T, err error) T {

View File

@ -47,7 +47,7 @@ func TestWorkspaceAgent(t *testing.T) {
tmpDir := t.TempDir() tmpDir := t.TempDir()
anotherClient, anotherUser := coderdtest.CreateAnotherUser(t, client, user.OrganizationID) anotherClient, anotherUser := coderdtest.CreateAnotherUser(t, client, user.OrganizationID)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: anotherUser.ID, OwnerID: anotherUser.ID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent { }).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@ -69,7 +69,7 @@ func TestWorkspaceAgent(t *testing.T) {
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
tmpDir := t.TempDir() tmpDir := t.TempDir()
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent { }).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@ -97,7 +97,7 @@ func TestWorkspaceAgent(t *testing.T) {
wantTroubleshootingURL := "https://example.com/troubleshoot" wantTroubleshootingURL := "https://example.com/troubleshoot"
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent { }).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@ -138,7 +138,7 @@ func TestWorkspaceAgent(t *testing.T) {
PortForwardingHelper: true, PortForwardingHelper: true,
SshHelper: true, SshHelper: true,
} }
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent { }).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@ -171,7 +171,7 @@ func TestWorkspaceAgent(t *testing.T) {
apps.WebTerminal = false apps.WebTerminal = false
// Creating another workspace is easier // Creating another workspace is easier
r = dbfake.Workspace(t, db).Seed(database.Workspace{ r = dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent { }).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@ -195,7 +195,7 @@ func TestWorkspaceAgentLogs(t *testing.T) {
ctx := testutil.Context(t, testutil.WaitMedium) ctx := testutil.Context(t, testutil.WaitMedium)
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent().Do() }).WithAgent().Do()
@ -237,7 +237,7 @@ func TestWorkspaceAgentLogs(t *testing.T) {
ctx := testutil.Context(t, testutil.WaitMedium) ctx := testutil.Context(t, testutil.WaitMedium)
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent().Do() }).WithAgent().Do()
@ -279,7 +279,7 @@ func TestWorkspaceAgentLogs(t *testing.T) {
ctx := testutil.Context(t, testutil.WaitMedium) ctx := testutil.Context(t, testutil.WaitMedium)
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent().Do() }).WithAgent().Do()
@ -322,7 +322,7 @@ func TestWorkspaceAgentListen(t *testing.T) {
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent().Do() }).WithAgent().Do()
@ -408,7 +408,7 @@ func TestWorkspaceAgentTailnet(t *testing.T) {
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent().Do() }).WithAgent().Do()
@ -454,7 +454,7 @@ func TestWorkspaceAgentTailnetDirectDisabled(t *testing.T) {
DeploymentValues: dv, DeploymentValues: dv,
}) })
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent().Do() }).WithAgent().Do()
@ -517,7 +517,7 @@ func TestWorkspaceAgentListeningPorts(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent { }).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@ -752,7 +752,7 @@ func TestWorkspaceAgentAppHealth(t *testing.T) {
}, },
}, },
} }
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent { }).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@ -819,7 +819,7 @@ func TestWorkspaceAgentReportStats(t *testing.T) {
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent().Do() }).WithAgent().Do()
@ -886,7 +886,7 @@ func TestWorkspaceAgent_LifecycleState(t *testing.T) {
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent().Do() }).WithAgent().Do()
@ -951,7 +951,7 @@ func TestWorkspaceAgent_Metadata(t *testing.T) {
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent { }).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@ -1129,7 +1129,7 @@ func TestWorkspaceAgent_Metadata_CatchMemoryLeak(t *testing.T) {
Logger: &logger, Logger: &logger,
}) })
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent(func(agents []*proto.Agent) []*proto.Agent { }).WithAgent(func(agents []*proto.Agent) []*proto.Agent {
@ -1258,7 +1258,7 @@ func TestWorkspaceAgent_Startup(t *testing.T) {
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent().Do() }).WithAgent().Do()
@ -1304,7 +1304,7 @@ func TestWorkspaceAgent_Startup(t *testing.T) {
client, db := coderdtest.NewWithDatabase(t, nil) client, db := coderdtest.NewWithDatabase(t, nil)
user := coderdtest.CreateFirstUser(t, client) user := coderdtest.CreateFirstUser(t, client)
r := dbfake.Workspace(t, db).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, db, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent().Do() }).WithAgent().Do()
@ -1352,7 +1352,7 @@ func TestWorkspaceAgent_UpdatedDERP(t *testing.T) {
api.DERPMapper.Store(&derpMapFn) api.DERPMapper.Store(&derpMapFn)
// Start workspace a workspace agent. // Start workspace a workspace agent.
r := dbfake.Workspace(t, api.Database).Seed(database.Workspace{ r := dbfake.WorkspaceBuild(t, api.Database, database.Workspace{
OrganizationID: user.OrganizationID, OrganizationID: user.OrganizationID,
OwnerID: user.UserID, OwnerID: user.UserID,
}).WithAgent().Do() }).WithAgent().Do()

View File

@ -23,6 +23,7 @@ import (
"github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/database/dbauthz"
"github.com/coder/coder/v2/coderd/database/dbfake"
"github.com/coder/coder/v2/coderd/database/dbgen" "github.com/coder/coder/v2/coderd/database/dbgen"
"github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/dbtestutil"
"github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/database/dbtime"
@ -343,94 +344,71 @@ func TestWorkspace(t *testing.T) {
func TestResolveAutostart(t *testing.T) { func TestResolveAutostart(t *testing.T) {
t.Parallel() t.Parallel()
t.Run("OK", func(t *testing.T) { ownerClient, db := coderdtest.NewWithDatabase(t, nil)
t.Parallel() owner := coderdtest.CreateFirstUser(t, ownerClient)
ownerClient := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
owner := coderdtest.CreateFirstUser(t, ownerClient)
version1 := coderdtest.CreateTemplateVersion(t, ownerClient, owner.OrganizationID, nil)
coderdtest.AwaitTemplateVersionJobCompleted(t, ownerClient, version1.ID)
template := coderdtest.CreateTemplate(t, ownerClient, owner.OrganizationID, version1.ID)
params := &echo.Responses{ param := database.TemplateVersionParameter{
Parse: echo.ParseComplete, Name: "param",
ProvisionPlan: []*proto.Response{ DefaultValue: "",
{ Required: true,
Type: &proto.Response_Plan{ }
Plan: &proto.PlanComplete{
Parameters: []*proto.RichParameter{
{
Name: "param",
Description: "param",
Required: true,
Mutable: true,
},
},
},
},
},
},
ProvisionApply: echo.ApplyComplete,
}
version2 := coderdtest.CreateTemplateVersion(t, ownerClient, owner.OrganizationID, params, func(ctvr *codersdk.CreateTemplateVersionRequest) {
ctvr.TemplateID = template.ID
})
coderdtest.AwaitTemplateVersionJobCompleted(t, ownerClient, version2.ID)
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel() defer cancel()
client, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID) client, member := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID)
workspace := coderdtest.CreateWorkspace(t, client, owner.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { resp := dbfake.WorkspaceBuild(t, db, database.Workspace{
cwr.AutomaticUpdates = codersdk.AutomaticUpdatesAlways OwnerID: member.ID,
}) OrganizationID: owner.OrganizationID,
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID) AutomaticUpdates: database.AutomaticUpdatesAlways,
}).Seed(database.WorkspaceBuild{
InitiatorID: member.ID,
}).Do()
err := ownerClient.UpdateActiveTemplateVersion(ctx, template.ID, codersdk.UpdateActiveTemplateVersion{ workspace := resp.Workspace
ID: version2.ID, version1 := resp.TemplateVersion
})
require.NoError(t, err)
// Autostart shouldn't be possible if parameters do not match. version2 := dbfake.TemplateVersion(t, db).
resp, err := client.ResolveAutostart(ctx, workspace.ID.String()) Seed(database.TemplateVersion{
require.NoError(t, err) CreatedBy: owner.UserID,
require.True(t, resp.ParameterMismatch) OrganizationID: owner.OrganizationID,
TemplateID: version1.TemplateID,
}).
Params(param).Do()
update, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ // Autostart shouldn't be possible if parameters do not match.
TemplateVersionID: version2.ID, resolveResp, err := client.ResolveAutostart(ctx, workspace.ID.String())
Transition: codersdk.WorkspaceTransitionStart, require.NoError(t, err)
RichParameterValues: []codersdk.WorkspaceBuildParameter{ require.True(t, resolveResp.ParameterMismatch)
{
Name: "param",
Value: "Hello",
},
},
})
require.NoError(t, err)
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, update.ID)
// We should be able to autostart since parameters are updated. _ = dbfake.WorkspaceBuild(t, db, workspace).
resp, err = client.ResolveAutostart(ctx, workspace.ID.String()) Seed(database.WorkspaceBuild{
require.NoError(t, err) BuildNumber: 2,
require.False(t, resp.ParameterMismatch) TemplateVersionID: version2.TemplateVersion.ID,
}).
Params(database.WorkspaceBuildParameter{
Name: "param",
Value: "hello",
}).Do()
// Create one last version where the parameters are the same as the previous // We should be able to autostart since parameters are updated.
// version. resolveResp, err = client.ResolveAutostart(ctx, workspace.ID.String())
version3 := coderdtest.CreateTemplateVersion(t, ownerClient, owner.OrganizationID, params, func(ctvr *codersdk.CreateTemplateVersionRequest) { require.NoError(t, err)
ctvr.TemplateID = template.ID require.False(t, resolveResp.ParameterMismatch)
})
coderdtest.AwaitTemplateVersionJobCompleted(t, ownerClient, version3.ID)
err = ownerClient.UpdateActiveTemplateVersion(ctx, template.ID, codersdk.UpdateActiveTemplateVersion{ // Create another version that has the same parameters as version2.
ID: version3.ID, // We should be able to update without issue.
}) _ = dbfake.TemplateVersion(t, db).Seed(database.TemplateVersion{
require.NoError(t, err) CreatedBy: owner.UserID,
OrganizationID: owner.OrganizationID,
TemplateID: version1.TemplateID,
}).Params(param).Do()
// Even though we're out of date we should still be able to autostart // Even though we're out of date we should still be able to autostart
// since parameters resolve. // since parameters resolve.
resp, err = client.ResolveAutostart(ctx, workspace.ID.String()) resolveResp, err = client.ResolveAutostart(ctx, workspace.ID.String())
require.NoError(t, err) require.NoError(t, err)
require.False(t, resp.ParameterMismatch) require.False(t, resolveResp.ParameterMismatch)
})
} }
func TestAdminViewAllWorkspaces(t *testing.T) { func TestAdminViewAllWorkspaces(t *testing.T) {

View File

@ -10,6 +10,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbmem"
"github.com/coder/coder/v2/coderd/database/pubsub" "github.com/coder/coder/v2/coderd/database/pubsub"
@ -67,6 +68,11 @@ func New(t *testing.T, options *Options) (*codersdk.Client, codersdk.CreateFirst
return client, user return client, user
} }
func NewWithDatabase(t *testing.T, options *Options) (*codersdk.Client, database.Store, codersdk.CreateFirstUserResponse) {
client, _, api, user := NewWithAPI(t, options)
return client, api.Database, user
}
func NewWithAPI(t *testing.T, options *Options) ( func NewWithAPI(t *testing.T, options *Options) (
*codersdk.Client, io.Closer, *coderd.API, codersdk.CreateFirstUserResponse, *codersdk.Client, io.Closer, *coderd.API, codersdk.CreateFirstUserResponse,
) { ) {

View File

@ -16,6 +16,7 @@ import (
"github.com/coder/coder/v2/coderd/autobuild" "github.com/coder/coder/v2/coderd/autobuild"
"github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/coderdtest"
"github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbfake"
"github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/dbtestutil"
"github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/coderd/rbac"
agplschedule "github.com/coder/coder/v2/coderd/schedule" agplschedule "github.com/coder/coder/v2/coderd/schedule"
@ -28,7 +29,6 @@ import (
"github.com/coder/coder/v2/enterprise/coderd/license" "github.com/coder/coder/v2/enterprise/coderd/license"
"github.com/coder/coder/v2/enterprise/coderd/schedule" "github.com/coder/coder/v2/enterprise/coderd/schedule"
"github.com/coder/coder/v2/provisioner/echo" "github.com/coder/coder/v2/provisioner/echo"
"github.com/coder/coder/v2/provisionersdk/proto"
"github.com/coder/coder/v2/testutil" "github.com/coder/coder/v2/testutil"
) )
@ -1169,10 +1169,9 @@ func TestWorkspaceLock(t *testing.T) {
func TestResolveAutostart(t *testing.T) { func TestResolveAutostart(t *testing.T) {
t.Parallel() t.Parallel()
ownerClient, owner := coderdenttest.New(t, &coderdenttest.Options{ ownerClient, db, owner := coderdenttest.NewWithDatabase(t, &coderdenttest.Options{
Options: &coderdtest.Options{ Options: &coderdtest.Options{
IncludeProvisionerDaemon: true, TemplateScheduleStore: &schedule.EnterpriseTemplateScheduleStore{},
TemplateScheduleStore: &schedule.EnterpriseTemplateScheduleStore{},
}, },
LicenseOptions: &coderdenttest.LicenseOptions{ LicenseOptions: &coderdenttest.LicenseOptions{
Features: license.Features{ Features: license.Features{
@ -1181,52 +1180,40 @@ func TestResolveAutostart(t *testing.T) {
}, },
}) })
version1 := coderdtest.CreateTemplateVersion(t, ownerClient, owner.OrganizationID, nil) version1 := dbfake.TemplateVersion(t, db).
coderdtest.AwaitTemplateVersionJobCompleted(t, ownerClient, version1.ID) Seed(database.TemplateVersion{
template := coderdtest.CreateTemplate(t, ownerClient, owner.OrganizationID, version1.ID, func(ctr *codersdk.CreateTemplateRequest) { CreatedBy: owner.UserID,
ctr.RequireActiveVersion = true OrganizationID: owner.OrganizationID,
}) }).Do()
params := &echo.Responses{
Parse: echo.ParseComplete,
ProvisionPlan: []*proto.Response{
{
Type: &proto.Response_Plan{
Plan: &proto.PlanComplete{
Parameters: []*proto.RichParameter{
{
Name: "param",
Description: "param",
Required: true,
Mutable: true,
},
},
},
},
},
},
ProvisionApply: echo.ApplyComplete,
}
version2 := coderdtest.CreateTemplateVersion(t, ownerClient, owner.OrganizationID, params, func(ctvr *codersdk.CreateTemplateVersionRequest) {
ctvr.TemplateID = template.ID
})
coderdtest.AwaitTemplateVersionJobCompleted(t, ownerClient, version2.ID)
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel() defer cancel()
client, _ := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID) _, err := ownerClient.UpdateTemplateMeta(ctx, version1.Template.ID, codersdk.UpdateTemplateMeta{
workspace := coderdtest.CreateWorkspace(t, client, owner.OrganizationID, template.ID) RequireActiveVersion: true,
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
//nolint:gocritic
err := ownerClient.UpdateActiveTemplateVersion(ctx, template.ID, codersdk.UpdateActiveTemplateVersion{
ID: version2.ID,
}) })
require.NoError(t, err) require.NoError(t, err)
// Autostart shouldn't be possible since the template requires automatic client, member := coderdtest.CreateAnotherUser(t, ownerClient, owner.OrganizationID)
// updates.
workspace := dbfake.WorkspaceBuild(t, db, database.Workspace{
OwnerID: member.ID,
OrganizationID: owner.OrganizationID,
TemplateID: version1.Template.ID,
}).Seed(database.WorkspaceBuild{
TemplateVersionID: version1.TemplateVersion.ID,
}).Do().Workspace
_ = dbfake.TemplateVersion(t, db).Seed(database.TemplateVersion{
CreatedBy: owner.UserID,
OrganizationID: owner.OrganizationID,
TemplateID: version1.TemplateVersion.TemplateID,
}).Params(database.TemplateVersionParameter{
Name: "param",
Required: true,
}).Do()
// Autostart shouldn't be possible if parameters do not match.
resp, err := client.ResolveAutostart(ctx, workspace.ID.String()) resp, err := client.ResolveAutostart(ctx, workspace.ID.String())
require.NoError(t, err) require.NoError(t, err)
require.True(t, resp.ParameterMismatch) require.True(t, resp.ParameterMismatch)