coder/coderd/wsbuilder/wsbuilder_test.go

797 lines
27 KiB
Go

package wsbuilder_test
import (
"context"
"database/sql"
"encoding/json"
"net/http"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/database/dbmock"
"github.com/coder/coder/coderd/database/dbtype"
"github.com/coder/coder/coderd/provisionerdserver"
"github.com/coder/coder/coderd/wsbuilder"
"github.com/coder/coder/codersdk"
)
var (
// use fixed IDs so logs are easier to read
templateID = uuid.MustParse("12341234-0000-0000-0001-000000000000")
activeVersionID = uuid.MustParse("12341234-0000-0000-0002-000000000000")
inactiveVersionID = uuid.MustParse("12341234-0000-0000-0003-000000000000")
activeJobID = uuid.MustParse("12341234-0000-0000-0004-000000000000")
inactiveJobID = uuid.MustParse("12341234-0000-0000-0005-000000000000")
orgID = uuid.MustParse("12341234-0000-0000-0006-000000000000")
workspaceID = uuid.MustParse("12341234-0000-0000-0007-000000000000")
userID = uuid.MustParse("12341234-0000-0000-0008-000000000000")
activeFileID = uuid.MustParse("12341234-0000-0000-0009-000000000000")
inactiveFileID = uuid.MustParse("12341234-0000-0000-000a-000000000000")
lastBuildID = uuid.MustParse("12341234-0000-0000-000b-000000000000")
lastBuildJobID = uuid.MustParse("12341234-0000-0000-000c-000000000000")
otherUserID = uuid.MustParse("12341234-0000-0000-000d-000000000000")
)
func TestBuilder_NoOptions(t *testing.T) {
t.Parallel()
req := require.New(t)
asrt := assert.New(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
var buildID uuid.UUID
mDB := expectDB(t,
// Inputs
withTemplate,
withInactiveVersion(nil),
withLastBuildFound,
withRichParameters(nil),
withParameterSchemas(inactiveJobID, nil),
// Outputs
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {
asrt.Equal(userID, job.InitiatorID)
asrt.Equal(inactiveFileID, job.FileID)
input := provisionerdserver.WorkspaceProvisionJob{}
err := json.Unmarshal(job.Input, &input)
req.NoError(err)
// store build ID for later
buildID = input.WorkspaceBuildID
}),
expectBuild(func(bld database.InsertWorkspaceBuildParams) {
asrt.Equal(inactiveVersionID, bld.TemplateVersionID)
asrt.Equal(workspaceID, bld.WorkspaceID)
asrt.Equal(int32(2), bld.BuildNumber)
asrt.Equal("last build state", string(bld.ProvisionerState))
asrt.Equal(userID, bld.InitiatorID)
asrt.Equal(database.WorkspaceTransitionStart, bld.Transition)
asrt.Equal(database.BuildReasonInitiator, bld.Reason)
asrt.Equal(buildID, bld.ID)
}),
expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) {
asrt.Equal(buildID, params.WorkspaceBuildID)
asrt.Empty(params.Name)
asrt.Empty(params.Value)
}),
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
uut := wsbuilder.New(ws, database.WorkspaceTransitionStart)
_, _, err := uut.Build(ctx, mDB, nil)
req.NoError(err)
}
func TestBuilder_Initiator(t *testing.T) {
t.Parallel()
req := require.New(t)
asrt := assert.New(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mDB := expectDB(t,
// Inputs
withTemplate,
withInactiveVersion(nil),
withLastBuildFound,
withRichParameters(nil),
withParameterSchemas(inactiveJobID, nil),
// Outputs
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {
asrt.Equal(otherUserID, job.InitiatorID)
}),
expectBuild(func(bld database.InsertWorkspaceBuildParams) {
asrt.Equal(otherUserID, bld.InitiatorID)
}),
expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) {
}),
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
uut := wsbuilder.New(ws, database.WorkspaceTransitionStart).Initiator(otherUserID)
_, _, err := uut.Build(ctx, mDB, nil)
req.NoError(err)
}
func TestBuilder_Reason(t *testing.T) {
t.Parallel()
req := require.New(t)
asrt := assert.New(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mDB := expectDB(t,
// Inputs
withTemplate,
withInactiveVersion(nil),
withLastBuildFound,
withRichParameters(nil),
withParameterSchemas(inactiveJobID, nil),
// Outputs
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {
}),
expectBuild(func(bld database.InsertWorkspaceBuildParams) {
asrt.Equal(database.BuildReasonAutostart, bld.Reason)
}),
expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) {
}),
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
uut := wsbuilder.New(ws, database.WorkspaceTransitionStart).Reason(database.BuildReasonAutostart)
_, _, err := uut.Build(ctx, mDB, nil)
req.NoError(err)
}
func TestBuilder_ActiveVersion(t *testing.T) {
t.Parallel()
req := require.New(t)
asrt := assert.New(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mDB := expectDB(t,
// Inputs
withTemplate,
withActiveVersion(nil),
withLastBuildNotFound,
withParameterSchemas(activeJobID, nil),
// previous rich parameters are not queried because there is no previous build.
// Outputs
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {
asrt.Equal(activeFileID, job.FileID)
}),
expectBuild(func(bld database.InsertWorkspaceBuildParams) {
asrt.Equal(activeVersionID, bld.TemplateVersionID)
// no previous build...
asrt.Equal(int32(1), bld.BuildNumber)
asrt.Len(bld.ProvisionerState, 0)
}),
expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) {
}),
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
uut := wsbuilder.New(ws, database.WorkspaceTransitionStart).ActiveVersion()
_, _, err := uut.Build(ctx, mDB, nil)
req.NoError(err)
}
func TestWorkspaceBuildWithRichParameters(t *testing.T) {
t.Parallel()
const (
firstParameterName = "first_parameter"
firstParameterDescription = "This is first parameter"
firstParameterValue = "1"
secondParameterName = "second_parameter"
secondParameterDescription = "This is second parameter"
secondParameterValue = "2"
immutableParameterName = "immutable_parameter"
immutableParameterDescription = "This is immutable parameter"
immutableParameterValue = "3"
)
initialBuildParameters := []database.WorkspaceBuildParameter{
{Name: firstParameterName, Value: firstParameterValue},
{Name: secondParameterName, Value: secondParameterValue},
{Name: immutableParameterName, Value: immutableParameterValue},
}
richParameters := []database.TemplateVersionParameter{
{Name: firstParameterName, Description: firstParameterDescription, Mutable: true, Options: json.RawMessage("[]")},
{Name: secondParameterName, Description: secondParameterDescription, Mutable: true, Options: json.RawMessage("[]")},
{Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false, Options: json.RawMessage("[]")},
}
t.Run("UpdateParameterValues", func(t *testing.T) {
t.Parallel()
req := require.New(t)
asrt := assert.New(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
const updatedParameterValue = "3"
nextBuildParameters := []codersdk.WorkspaceBuildParameter{
{Name: firstParameterName, Value: firstParameterValue},
{Name: secondParameterName, Value: updatedParameterValue},
}
expectedParams := map[string]string{
firstParameterName: firstParameterValue,
secondParameterName: updatedParameterValue,
immutableParameterName: immutableParameterValue,
}
mDB := expectDB(t,
// Inputs
withTemplate,
withInactiveVersion(richParameters),
withLastBuildFound,
withRichParameters(initialBuildParameters),
withParameterSchemas(inactiveJobID, nil),
// Outputs
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
expectBuild(func(bld database.InsertWorkspaceBuildParams) {}),
expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) {
asrt.Len(params.Name, len(expectedParams))
for i := range params.Name {
value, ok := expectedParams[params.Name[i]]
asrt.True(ok, "unexpected name %s", params.Name[i])
asrt.Equal(value, params.Value[i])
}
}),
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
uut := wsbuilder.New(ws, database.WorkspaceTransitionStart).RichParameterValues(nextBuildParameters)
_, _, err := uut.Build(ctx, mDB, nil)
req.NoError(err)
})
t.Run("UsePreviousParameterValues", func(t *testing.T) {
t.Parallel()
req := require.New(t)
asrt := assert.New(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
nextBuildParameters := []codersdk.WorkspaceBuildParameter{}
expectedParams := map[string]string{}
for _, p := range initialBuildParameters {
expectedParams[p.Name] = p.Value
}
mDB := expectDB(t,
// Inputs
withTemplate,
withInactiveVersion(richParameters),
withLastBuildFound,
withRichParameters(initialBuildParameters),
withParameterSchemas(inactiveJobID, nil),
// Outputs
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
expectBuild(func(bld database.InsertWorkspaceBuildParams) {}),
expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) {
asrt.Len(params.Name, len(expectedParams))
for i := range params.Name {
value, ok := expectedParams[params.Name[i]]
asrt.True(ok, "unexpected name %s", params.Name[i])
asrt.Equal(value, params.Value[i])
}
}),
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
uut := wsbuilder.New(ws, database.WorkspaceTransitionStart).RichParameterValues(nextBuildParameters)
_, _, err := uut.Build(ctx, mDB, nil)
req.NoError(err)
})
t.Run("StartWorkspaceWithLegacyParameterValues", func(t *testing.T) {
t.Parallel()
req := require.New(t)
asrt := assert.New(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
schemas := []database.ParameterSchema{
{
Name: "not-replaced",
DefaultDestinationScheme: database.ParameterDestinationSchemeEnvironmentVariable,
},
{
Name: "replaced",
DefaultDestinationScheme: database.ParameterDestinationSchemeEnvironmentVariable,
},
}
mDB := expectDB(t,
// Inputs
withTemplate,
withInactiveVersion(richParameters),
withLastBuildFound,
withRichParameters(nil),
withParameterSchemas(inactiveJobID, schemas),
// Outputs
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
expectBuild(func(bld database.InsertWorkspaceBuildParams) {}),
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
uut := wsbuilder.New(ws, database.WorkspaceTransitionStart)
_, _, err := uut.Build(ctx, mDB, nil)
bldErr := wsbuilder.BuildError{}
req.ErrorAs(err, &bldErr)
asrt.Equal(http.StatusBadRequest, bldErr.Status)
})
t.Run("DoNotModifyImmutables", func(t *testing.T) {
t.Parallel()
req := require.New(t)
asrt := assert.New(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
nextBuildParameters := []codersdk.WorkspaceBuildParameter{
{Name: immutableParameterName, Value: "BAD"},
}
mDB := expectDB(t,
// Inputs
withTemplate,
withInactiveVersion(richParameters),
withLastBuildFound,
withRichParameters(initialBuildParameters),
withParameterSchemas(inactiveJobID, nil),
// Outputs
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
expectBuild(func(bld database.InsertWorkspaceBuildParams) {}),
// no build parameters, since we hit an error validating.
// expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) {}),
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
uut := wsbuilder.New(ws, database.WorkspaceTransitionStart).RichParameterValues(nextBuildParameters)
_, _, err := uut.Build(ctx, mDB, nil)
bldErr := wsbuilder.BuildError{}
req.ErrorAs(err, &bldErr)
asrt.Equal(http.StatusBadRequest, bldErr.Status)
})
t.Run("NewImmutableRequiredParameterAdded", func(t *testing.T) {
t.Parallel()
req := require.New(t)
asrt := assert.New(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// new template revision
const newImmutableParameterName = "new_immutable_parameter"
const newImmutableParameterDescription = "This is also an immutable parameter"
version2params := []database.TemplateVersionParameter{
{Name: firstParameterName, Description: firstParameterDescription, Mutable: true, Options: json.RawMessage("[]")},
{Name: secondParameterName, Description: secondParameterDescription, Mutable: true, Options: json.RawMessage("[]")},
{Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false, Options: json.RawMessage("[]")},
{Name: newImmutableParameterName, Description: newImmutableParameterDescription, Mutable: false, Required: true, Options: json.RawMessage("[]")},
}
nextBuildParameters := []codersdk.WorkspaceBuildParameter{
{Name: newImmutableParameterName, Value: "good"},
}
expectedParams := map[string]string{
firstParameterName: firstParameterValue,
secondParameterName: secondParameterValue,
immutableParameterName: immutableParameterValue,
newImmutableParameterName: "good",
}
mDB := expectDB(t,
// Inputs
withTemplate,
withActiveVersion(version2params),
withLastBuildFound,
withRichParameters(initialBuildParameters),
withParameterSchemas(activeJobID, nil),
// Outputs
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
expectBuild(func(bld database.InsertWorkspaceBuildParams) {}),
expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) {
asrt.Len(params.Name, len(expectedParams))
for i := range params.Name {
value, ok := expectedParams[params.Name[i]]
asrt.True(ok, "unexpected name %s", params.Name[i])
asrt.Equal(value, params.Value[i])
}
}),
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
uut := wsbuilder.New(ws, database.WorkspaceTransitionStart).
RichParameterValues(nextBuildParameters).
VersionID(activeVersionID)
_, _, err := uut.Build(ctx, mDB, nil)
req.NoError(err)
})
t.Run("NewImmutableOptionalParameterAdded", func(t *testing.T) {
t.Parallel()
req := require.New(t)
asrt := assert.New(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// new template revision
const newImmutableParameterName = "new_immutable_parameter"
const newImmutableParameterDescription = "This is also an immutable parameter"
version2params := []database.TemplateVersionParameter{
{Name: firstParameterName, Description: firstParameterDescription, Mutable: true, Options: json.RawMessage("[]")},
{Name: secondParameterName, Description: secondParameterDescription, Mutable: true, Options: json.RawMessage("[]")},
{Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false, Options: json.RawMessage("[]")},
{Name: newImmutableParameterName, Description: newImmutableParameterDescription, Mutable: false, DefaultValue: "12345", Options: json.RawMessage("[]")},
}
nextBuildParameters := []codersdk.WorkspaceBuildParameter{
{Name: newImmutableParameterName, Value: "good"},
}
expectedParams := map[string]string{
firstParameterName: firstParameterValue,
secondParameterName: secondParameterValue,
immutableParameterName: immutableParameterValue,
newImmutableParameterName: "good",
}
mDB := expectDB(t,
// Inputs
withTemplate,
withActiveVersion(version2params),
withLastBuildFound,
withRichParameters(initialBuildParameters),
withParameterSchemas(activeJobID, nil),
// Outputs
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
expectBuild(func(bld database.InsertWorkspaceBuildParams) {}),
expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) {
asrt.Len(params.Name, len(expectedParams))
for i := range params.Name {
value, ok := expectedParams[params.Name[i]]
asrt.True(ok, "unexpected name %s", params.Name[i])
asrt.Equal(value, params.Value[i])
}
}),
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
uut := wsbuilder.New(ws, database.WorkspaceTransitionStart).
RichParameterValues(nextBuildParameters).
VersionID(activeVersionID)
_, _, err := uut.Build(ctx, mDB, nil)
req.NoError(err)
})
t.Run("NewImmutableOptionalParameterUsesDefault", func(t *testing.T) {
t.Parallel()
req := require.New(t)
asrt := assert.New(t)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// new template revision
const newImmutableParameterName = "new_immutable_parameter"
const newImmutableParameterDescription = "This is also an immutable parameter"
version2params := []database.TemplateVersionParameter{
{Name: firstParameterName, Description: firstParameterDescription, Mutable: true, Options: json.RawMessage("[]")},
{Name: secondParameterName, Description: secondParameterDescription, Mutable: true, Options: json.RawMessage("[]")},
{Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false, Options: json.RawMessage("[]")},
{Name: newImmutableParameterName, Description: newImmutableParameterDescription, Mutable: false, DefaultValue: "12345", Options: json.RawMessage("[]")},
}
nextBuildParameters := []codersdk.WorkspaceBuildParameter{}
expectedParams := map[string]string{
firstParameterName: firstParameterValue,
secondParameterName: secondParameterValue,
immutableParameterName: immutableParameterValue,
newImmutableParameterName: "12345",
}
mDB := expectDB(t,
// Inputs
withTemplate,
withActiveVersion(version2params),
withLastBuildFound,
withRichParameters(initialBuildParameters),
withParameterSchemas(activeJobID, nil),
// Outputs
expectProvisionerJob(func(job database.InsertProvisionerJobParams) {}),
expectBuild(func(bld database.InsertWorkspaceBuildParams) {}),
expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) {
asrt.Len(params.Name, len(expectedParams))
for i := range params.Name {
value, ok := expectedParams[params.Name[i]]
asrt.True(ok, "unexpected name %s", params.Name[i])
asrt.Equal(value, params.Value[i])
}
}),
)
ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID}
uut := wsbuilder.New(ws, database.WorkspaceTransitionStart).
RichParameterValues(nextBuildParameters).
VersionID(activeVersionID)
_, _, err := uut.Build(ctx, mDB, nil)
req.NoError(err)
})
}
type txExpect func(mTx *dbmock.MockStore)
func expectDB(t *testing.T, opts ...txExpect) *dbmock.MockStore {
t.Helper()
ctrl := gomock.NewController(t)
mDB := dbmock.NewMockStore(ctrl)
mTx := dbmock.NewMockStore(ctrl)
// we expect to be run in a transaction; we use mTx to record the
// "in transaction" calls.
mDB.EXPECT().InTx(
gomock.Any(), gomock.Eq(&sql.TxOptions{Isolation: sql.LevelRepeatableRead}),
).
DoAndReturn(func(f func(database.Store) error, _ *sql.TxOptions) error {
err := f(mTx)
return err
})
// txExpect args set up the expectations for what happens in the transaction.
for _, o := range opts {
o(mTx)
}
return mDB
}
func withTemplate(mTx *dbmock.MockStore) {
mTx.EXPECT().GetTemplateByID(gomock.Any(), templateID).
Times(1).
Return(database.Template{
ID: templateID,
OrganizationID: orgID,
Provisioner: database.ProvisionerTypeTerraform,
ActiveVersionID: activeVersionID,
}, nil)
}
func withActiveVersion(params []database.TemplateVersionParameter) func(mTx *dbmock.MockStore) {
return func(mTx *dbmock.MockStore) {
mTx.EXPECT().GetTemplateVersionByID(gomock.Any(), activeVersionID).
Times(1).
Return(database.TemplateVersion{
ID: activeVersionID,
TemplateID: uuid.NullUUID{UUID: templateID, Valid: true},
OrganizationID: orgID,
Name: "active",
JobID: activeJobID,
}, nil)
mTx.EXPECT().GetProvisionerJobByID(gomock.Any(), activeJobID).
Times(1).Return(database.ProvisionerJob{
ID: activeJobID,
OrganizationID: orgID,
InitiatorID: userID,
Provisioner: database.ProvisionerTypeTerraform,
StorageMethod: database.ProvisionerStorageMethodFile,
Type: database.ProvisionerJobTypeTemplateVersionImport,
Input: nil,
Tags: dbtype.StringMap{
"version": "active",
provisionerdserver.TagScope: provisionerdserver.ScopeUser,
},
FileID: activeFileID,
StartedAt: sql.NullTime{Time: database.Now(), Valid: true},
UpdatedAt: time.Now(),
CompletedAt: sql.NullTime{Time: database.Now(), Valid: true},
}, nil)
paramsCall := mTx.EXPECT().GetTemplateVersionParameters(gomock.Any(), activeVersionID).
Times(1)
if len(params) > 0 {
paramsCall.Return(params, nil)
} else {
paramsCall.Return(nil, sql.ErrNoRows)
}
}
}
func withInactiveVersion(params []database.TemplateVersionParameter) func(mTx *dbmock.MockStore) {
return func(mTx *dbmock.MockStore) {
mTx.EXPECT().GetTemplateVersionByID(gomock.Any(), inactiveVersionID).
Times(1).
Return(database.TemplateVersion{
ID: inactiveVersionID,
TemplateID: uuid.NullUUID{UUID: templateID, Valid: true},
OrganizationID: orgID,
Name: "inactive",
JobID: inactiveJobID,
}, nil)
mTx.EXPECT().GetProvisionerJobByID(gomock.Any(), inactiveJobID).
Times(1).Return(database.ProvisionerJob{
ID: inactiveJobID,
OrganizationID: orgID,
InitiatorID: userID,
Provisioner: database.ProvisionerTypeTerraform,
StorageMethod: database.ProvisionerStorageMethodFile,
Type: database.ProvisionerJobTypeTemplateVersionImport,
Input: nil,
Tags: dbtype.StringMap{
"version": "inactive",
provisionerdserver.TagScope: provisionerdserver.ScopeUser,
},
FileID: inactiveFileID,
StartedAt: sql.NullTime{Time: database.Now(), Valid: true},
UpdatedAt: time.Now(),
CompletedAt: sql.NullTime{Time: database.Now(), Valid: true},
}, nil)
paramsCall := mTx.EXPECT().GetTemplateVersionParameters(gomock.Any(), inactiveVersionID).
Times(1)
if len(params) > 0 {
paramsCall.Return(params, nil)
} else {
paramsCall.Return(nil, sql.ErrNoRows)
}
}
}
func withLastBuildFound(mTx *dbmock.MockStore) {
mTx.EXPECT().GetLatestWorkspaceBuildByWorkspaceID(gomock.Any(), workspaceID).
Times(1).
Return(database.WorkspaceBuild{
ID: lastBuildID,
WorkspaceID: workspaceID,
TemplateVersionID: inactiveVersionID,
BuildNumber: 1,
Transition: database.WorkspaceTransitionStart,
InitiatorID: userID,
JobID: lastBuildJobID,
ProvisionerState: []byte("last build state"),
Reason: database.BuildReasonInitiator,
}, nil)
mTx.EXPECT().GetProvisionerJobByID(gomock.Any(), lastBuildJobID).
Times(1).
Return(database.ProvisionerJob{
ID: lastBuildJobID,
OrganizationID: orgID,
InitiatorID: userID,
Provisioner: database.ProvisionerTypeTerraform,
StorageMethod: database.ProvisionerStorageMethodFile,
FileID: inactiveFileID,
Type: database.ProvisionerJobTypeWorkspaceBuild,
StartedAt: sql.NullTime{Time: database.Now(), Valid: true},
UpdatedAt: time.Now(),
CompletedAt: sql.NullTime{Time: database.Now(), Valid: true},
}, nil)
}
func withLastBuildNotFound(mTx *dbmock.MockStore) {
mTx.EXPECT().GetLatestWorkspaceBuildByWorkspaceID(gomock.Any(), workspaceID).
Times(1).
Return(database.WorkspaceBuild{}, sql.ErrNoRows)
}
func withParameterSchemas(jobID uuid.UUID, schemas []database.ParameterSchema) func(mTx *dbmock.MockStore) {
return func(mTx *dbmock.MockStore) {
c := mTx.EXPECT().GetParameterSchemasByJobID(
gomock.Any(),
jobID).
Times(1)
if len(schemas) > 0 {
c.Return(schemas, nil)
} else {
c.Return(nil, sql.ErrNoRows)
}
}
}
func withRichParameters(params []database.WorkspaceBuildParameter) func(mTx *dbmock.MockStore) {
return func(mTx *dbmock.MockStore) {
c := mTx.EXPECT().GetWorkspaceBuildParameters(gomock.Any(), lastBuildID).
Times(1)
if len(params) > 0 {
c.Return(params, nil)
} else {
c.Return(nil, sql.ErrNoRows)
}
}
}
// Since there is expected to be only one each of job, build, and build-parameters inserted, instead
// of building matchers, we match any call and then assert its parameters. This will feel
// more familiar to the way we write other tests.
// expectProvisionerJob captures a call to InsertProvisionerJob and runs the provided assertions
// against it.
func expectProvisionerJob(
assertions func(job database.InsertProvisionerJobParams),
) func(mTx *dbmock.MockStore) {
return func(mTx *dbmock.MockStore) {
mTx.EXPECT().InsertProvisionerJob(gomock.Any(), gomock.Any()).
Times(1).
DoAndReturn(
func(ctx context.Context, params database.InsertProvisionerJobParams) (database.ProvisionerJob, error) {
assertions(params)
// there is no point copying anything other than the ID, since this object is just
// returned to our test code, and we've already asserted what we care about.
return database.ProvisionerJob{ID: params.ID}, nil
},
)
}
}
// expectBuild captures a call to InsertWorkspaceBuild and runs the provided assertions
// against it.
func expectBuild(
assertions func(job database.InsertWorkspaceBuildParams),
) func(mTx *dbmock.MockStore) {
return func(mTx *dbmock.MockStore) {
mTx.EXPECT().InsertWorkspaceBuild(gomock.Any(), gomock.Any()).
Times(1).
DoAndReturn(
func(ctx context.Context, params database.InsertWorkspaceBuildParams) (database.WorkspaceBuild, error) {
assertions(params)
// there is no point copying anything other than the ID, since this object is just
// returned to our test code, and we've already asserted what we care about.
return database.WorkspaceBuild{ID: params.ID}, nil
},
)
}
}
// expectBuildParameters captures a call to InsertWorkspaceBuildParameters and runs the provided assertions
// against it.
func expectBuildParameters(
assertions func(database.InsertWorkspaceBuildParametersParams),
) func(mTx *dbmock.MockStore) {
return func(mTx *dbmock.MockStore) {
mTx.EXPECT().InsertWorkspaceBuildParameters(gomock.Any(), gomock.Any()).
Times(1).
DoAndReturn(
func(ctx context.Context, params database.InsertWorkspaceBuildParametersParams) error {
assertions(params)
return nil
},
)
}
}