mirror of https://github.com/coder/coder.git
797 lines
27 KiB
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
|
|
},
|
|
)
|
|
}
|
|
}
|