From 80e5eb9550cc01f99c860b727f6ca92165cf1176 Mon Sep 17 00:00:00 2001 From: Spike Curtis Date: Fri, 12 May 2023 20:09:50 +0000 Subject: [PATCH 01/10] refactor workspace builds Signed-off-by: Spike Curtis --- cli/templatedelete_test.go | 28 +- .../autobuild/executor/lifecycle_executor.go | 120 +-- coderd/conversion/doc.go | 2 + coderd/conversion/parameters.go | 87 ++ coderd/conversion/provisionerjob.go | 33 + coderd/httpapi/httpapi.go | 6 +- coderd/parameters.go | 1 + coderd/prometheusmetrics/prometheusmetrics.go | 4 +- coderd/provisionerjobs.go | 29 +- coderd/templates.go | 9 + coderd/templates_test.go | 3 +- coderd/workspacebuilds.go | 392 +-------- coderd/workspaces.go | 180 +---- coderd/workspaces_test.go | 23 +- coderd/wsbuilder/wsbuilder.go | 741 ++++++++++++++++++ codersdk/parameters.go | 2 +- codersdk/richparameters.go | 60 ++ 17 files changed, 1046 insertions(+), 674 deletions(-) create mode 100644 coderd/conversion/doc.go create mode 100644 coderd/conversion/parameters.go create mode 100644 coderd/conversion/provisionerjob.go create mode 100644 coderd/wsbuilder/wsbuilder.go diff --git a/cli/templatedelete_test.go b/cli/templatedelete_test.go index 86893f8cd0328..5c029be96fb5e 100644 --- a/cli/templatedelete_test.go +++ b/cli/templatedelete_test.go @@ -51,15 +51,13 @@ func TestTemplateDelete(t *testing.T) { client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) - _ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - templates := []codersdk.Template{ - coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID), - coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID), - coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID), - } + templates := []codersdk.Template{} templateNames := []string{} - for _, template := range templates { + for i := 0; i < 3; i++ { + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + _ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + templates = append(templates, template) templateNames = append(templateNames, template.Name) } @@ -78,15 +76,13 @@ func TestTemplateDelete(t *testing.T) { client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) - _ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - templates := []codersdk.Template{ - coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID), - coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID), - coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID), - } + templates := []codersdk.Template{} templateNames := []string{} - for _, template := range templates { + for i := 0; i < 3; i++ { + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + _ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + templates = append(templates, template) templateNames = append(templateNames, template.Name) } diff --git a/coderd/autobuild/executor/lifecycle_executor.go b/coderd/autobuild/executor/lifecycle_executor.go index b0ac9a213093a..f701396c47a41 100644 --- a/coderd/autobuild/executor/lifecycle_executor.go +++ b/coderd/autobuild/executor/lifecycle_executor.go @@ -2,7 +2,7 @@ package executor import ( "context" - "encoding/json" + "database/sql" "sync/atomic" "time" @@ -13,8 +13,8 @@ import ( "cdr.dev/slog" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/database/dbauthz" - "github.com/coder/coder/coderd/provisionerdserver" "github.com/coder/coder/coderd/schedule" + "github.com/coder/coder/coderd/wsbuilder" ) // Executor automatically starts or stops workspaces. @@ -168,20 +168,35 @@ func (e *Executor) runOnce(t time.Time) Stats { ) return nil } - - log.Info(e.ctx, "scheduling workspace transition", slog.F("transition", validTransition)) - - stats.Transitions[ws.ID] = validTransition - if err := build(e.ctx, db, ws, validTransition, priorHistory, priorJob); err != nil { + builder := wsbuilder.New(ws, validTransition). + SetLastWorkspaceBuildInTx(&priorHistory). + SetLastWorkspaceBuildJobInTx(&priorJob) + + switch validTransition { + case database.WorkspaceTransitionStart: + builder = builder.Reason(database.BuildReasonAutostart) + case database.WorkspaceTransitionStop: + builder = builder.Reason(database.BuildReasonAutostop) + default: + log.Error(e.ctx, "unsupported transition", slog.F("transition", validTransition)) + return nil + } + if _, _, err := builder.Build(e.ctx, db, nil); err != nil { log.Error(e.ctx, "unable to transition workspace", slog.F("transition", validTransition), slog.Error(err), ) return nil } + stats.Transitions[ws.ID] = validTransition + + log.Info(e.ctx, "scheduling workspace transition", slog.F("transition", validTransition)) return nil - }, nil) + + // Run with RepeatableRead isolation so that the build process sees the same data + // as our calculation that determines whether an autobuild is necessary. + }, &sql.TxOptions{Isolation: sql.LevelRepeatableRead}) if err != nil { log.Error(e.ctx, "workspace scheduling failed", slog.Error(err)) } @@ -248,92 +263,3 @@ func getNextTransition( return "", time.Time{}, xerrors.Errorf("last transition not valid for autostart or autostop") } } - -// TODO(cian): this function duplicates most of api.postWorkspaceBuilds. Refactor. -// See: https://github.com/coder/coder/issues/1401 -func build(ctx context.Context, store database.Store, workspace database.Workspace, trans database.WorkspaceTransition, priorHistory database.WorkspaceBuild, priorJob database.ProvisionerJob) error { - template, err := store.GetTemplateByID(ctx, workspace.TemplateID) - if err != nil { - return xerrors.Errorf("get workspace template: %w", err) - } - - priorBuildNumber := priorHistory.BuildNumber - - // This must happen in a transaction to ensure history can be inserted, and - // the prior history can update it's "after" column to point at the new. - workspaceBuildID := uuid.New() - input, err := json.Marshal(provisionerdserver.WorkspaceProvisionJob{ - WorkspaceBuildID: workspaceBuildID, - }) - if err != nil { - return xerrors.Errorf("marshal provision job: %w", err) - } - provisionerJobID := uuid.New() - now := database.Now() - - var buildReason database.BuildReason - switch trans { - case database.WorkspaceTransitionStart: - buildReason = database.BuildReasonAutostart - case database.WorkspaceTransitionStop: - buildReason = database.BuildReasonAutostop - default: - return xerrors.Errorf("Unsupported transition: %q", trans) - } - - lastBuildParameters, err := store.GetWorkspaceBuildParameters(ctx, priorHistory.ID) - if err != nil { - return xerrors.Errorf("fetch prior workspace build parameters: %w", err) - } - - return store.InTx(func(db database.Store) error { - newProvisionerJob, err := store.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{ - ID: provisionerJobID, - CreatedAt: now, - UpdatedAt: now, - InitiatorID: workspace.OwnerID, - OrganizationID: template.OrganizationID, - Provisioner: template.Provisioner, - Type: database.ProvisionerJobTypeWorkspaceBuild, - StorageMethod: priorJob.StorageMethod, - FileID: priorJob.FileID, - Tags: priorJob.Tags, - Input: input, - }) - if err != nil { - return xerrors.Errorf("insert provisioner job: %w", err) - } - workspaceBuild, err := store.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{ - ID: workspaceBuildID, - CreatedAt: now, - UpdatedAt: now, - WorkspaceID: workspace.ID, - TemplateVersionID: priorHistory.TemplateVersionID, - BuildNumber: priorBuildNumber + 1, - ProvisionerState: priorHistory.ProvisionerState, - InitiatorID: workspace.OwnerID, - Transition: trans, - JobID: newProvisionerJob.ID, - Reason: buildReason, - }) - if err != nil { - return xerrors.Errorf("insert workspace build: %w", err) - } - - names := make([]string, 0, len(lastBuildParameters)) - values := make([]string, 0, len(lastBuildParameters)) - for _, param := range lastBuildParameters { - names = append(names, param.Name) - values = append(values, param.Value) - } - err = db.InsertWorkspaceBuildParameters(ctx, database.InsertWorkspaceBuildParametersParams{ - WorkspaceBuildID: workspaceBuild.ID, - Name: names, - Value: values, - }) - if err != nil { - return xerrors.Errorf("insert workspace build parameters: %w", err) - } - return nil - }, nil) -} diff --git a/coderd/conversion/doc.go b/coderd/conversion/doc.go new file mode 100644 index 0000000000000..3eaaaec79c01f --- /dev/null +++ b/coderd/conversion/doc.go @@ -0,0 +1,2 @@ +// Package conversion provides common conversion routines from database types to codersdk types +package conversion diff --git a/coderd/conversion/parameters.go b/coderd/conversion/parameters.go new file mode 100644 index 0000000000000..594aa36b0fcbe --- /dev/null +++ b/coderd/conversion/parameters.go @@ -0,0 +1,87 @@ +package conversion + +import ( + "encoding/json" + + "github.com/coder/coder/coderd/database" + "github.com/coder/coder/coderd/parameter" + "github.com/coder/coder/codersdk" + "github.com/coder/coder/provisionersdk/proto" +) + +func WorkspaceBuildParameters(params []database.WorkspaceBuildParameter) []codersdk.WorkspaceBuildParameter { + out := make([]codersdk.WorkspaceBuildParameter, len(params)) + for i, p := range params { + out[i] = WorkspaceBuildParameter(p) + } + return out +} + +func WorkspaceBuildParameter(p database.WorkspaceBuildParameter) codersdk.WorkspaceBuildParameter { + return codersdk.WorkspaceBuildParameter{ + Name: p.Name, + Value: p.Value, + } +} + +func TemplateVersionParameter(param database.TemplateVersionParameter) (codersdk.TemplateVersionParameter, error) { + var protoOptions []*proto.RichParameterOption + err := json.Unmarshal(param.Options, &protoOptions) + if err != nil { + return codersdk.TemplateVersionParameter{}, err + } + options := make([]codersdk.TemplateVersionParameterOption, 0) + for _, option := range protoOptions { + options = append(options, codersdk.TemplateVersionParameterOption{ + Name: option.Name, + Description: option.Description, + Value: option.Value, + Icon: option.Icon, + }) + } + + descriptionPlaintext, err := parameter.Plaintext(param.Description) + if err != nil { + return codersdk.TemplateVersionParameter{}, err + } + return codersdk.TemplateVersionParameter{ + Name: param.Name, + DisplayName: param.DisplayName, + Description: param.Description, + DescriptionPlaintext: descriptionPlaintext, + Type: param.Type, + Mutable: param.Mutable, + DefaultValue: param.DefaultValue, + Icon: param.Icon, + Options: options, + ValidationRegex: param.ValidationRegex, + ValidationMin: param.ValidationMin, + ValidationMax: param.ValidationMax, + ValidationError: param.ValidationError, + ValidationMonotonic: codersdk.ValidationMonotonicOrder(param.ValidationMonotonic), + Required: param.Required, + LegacyVariableName: param.LegacyVariableName, + }, nil +} + +func Parameters(params []database.ParameterValue) []codersdk.Parameter { + out := make([]codersdk.Parameter, len(params)) + for i, p := range params { + out[i] = Parameter(p) + } + return out +} + +func Parameter(parameterValue database.ParameterValue) codersdk.Parameter { + return codersdk.Parameter{ + ID: parameterValue.ID, + CreatedAt: parameterValue.CreatedAt, + UpdatedAt: parameterValue.UpdatedAt, + Scope: codersdk.ParameterScope(parameterValue.Scope), + ScopeID: parameterValue.ScopeID, + Name: parameterValue.Name, + SourceScheme: codersdk.ParameterSourceScheme(parameterValue.SourceScheme), + DestinationScheme: codersdk.ParameterDestinationScheme(parameterValue.DestinationScheme), + SourceValue: parameterValue.SourceValue, + } +} diff --git a/coderd/conversion/provisionerjob.go b/coderd/conversion/provisionerjob.go new file mode 100644 index 0000000000000..684f4afe0cd7a --- /dev/null +++ b/coderd/conversion/provisionerjob.go @@ -0,0 +1,33 @@ +package conversion + +import ( + "time" + + "github.com/coder/coder/coderd/database" + "github.com/coder/coder/codersdk" +) + +func ProvisionerJobStatus(provisionerJob database.ProvisionerJob) codersdk.ProvisionerJobStatus { + switch { + case provisionerJob.CanceledAt.Valid: + if !provisionerJob.CompletedAt.Valid { + return codersdk.ProvisionerJobCanceling + } + if provisionerJob.Error.String == "" { + return codersdk.ProvisionerJobCanceled + } + return codersdk.ProvisionerJobFailed + case !provisionerJob.StartedAt.Valid: + return codersdk.ProvisionerJobPending + case provisionerJob.CompletedAt.Valid: + if provisionerJob.Error.String == "" { + return codersdk.ProvisionerJobSucceeded + } + return codersdk.ProvisionerJobFailed + case database.Now().Sub(provisionerJob.UpdatedAt) > 30*time.Second: + provisionerJob.Error.String = "Worker failed to update job in time." + return codersdk.ProvisionerJobFailed + default: + return codersdk.ProvisionerJobRunning + } +} diff --git a/coderd/httpapi/httpapi.go b/coderd/httpapi/httpapi.go index bfdfe0d876b47..135b2d4d184dd 100644 --- a/coderd/httpapi/httpapi.go +++ b/coderd/httpapi/httpapi.go @@ -96,12 +96,12 @@ func Is404Error(err error) bool { // Convenience error functions don't take contexts since their responses are // static, it doesn't make much sense to trace them. +var ResourceNotFoundResponse = codersdk.Response{Message: "Resource not found or you do not have access to this resource"} + // ResourceNotFound is intentionally vague. All 404 responses should be identical // to prevent leaking existence of resources. func ResourceNotFound(rw http.ResponseWriter) { - Write(context.Background(), rw, http.StatusNotFound, codersdk.Response{ - Message: "Resource not found or you do not have access to this resource", - }) + Write(context.Background(), rw, http.StatusNotFound, ResourceNotFoundResponse) } func Forbidden(rw http.ResponseWriter) { diff --git a/coderd/parameters.go b/coderd/parameters.go index 8800f6acb6265..77096500443d9 100644 --- a/coderd/parameters.go +++ b/coderd/parameters.go @@ -206,6 +206,7 @@ func convertParameterValue(parameterValue database.ParameterValue) codersdk.Para Name: parameterValue.Name, SourceScheme: codersdk.ParameterSourceScheme(parameterValue.SourceScheme), DestinationScheme: codersdk.ParameterDestinationScheme(parameterValue.DestinationScheme), + SourceValue: parameterValue.SourceValue, } } diff --git a/coderd/prometheusmetrics/prometheusmetrics.go b/coderd/prometheusmetrics/prometheusmetrics.go index 6a616bcc05438..ab4bd087d1e12 100644 --- a/coderd/prometheusmetrics/prometheusmetrics.go +++ b/coderd/prometheusmetrics/prometheusmetrics.go @@ -16,7 +16,7 @@ import ( "cdr.dev/slog" - "github.com/coder/coder/coderd" + "github.com/coder/coder/coderd/conversion" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/database/dbauthz" "github.com/coder/coder/tailnet" @@ -124,7 +124,7 @@ func Workspaces(ctx context.Context, registerer prometheus.Registerer, db databa gauge.Reset() for _, job := range jobs { - status := coderd.ConvertProvisionerJobStatus(job) + status := conversion.ProvisionerJobStatus(job) gauge.WithLabelValues(string(status)).Add(1) } } diff --git a/coderd/provisionerjobs.go b/coderd/provisionerjobs.go index e9c7273dab5e8..70172010c275a 100644 --- a/coderd/provisionerjobs.go +++ b/coderd/provisionerjobs.go @@ -9,13 +9,13 @@ import ( "net/http" "sort" "strconv" - "time" "github.com/google/uuid" "go.uber.org/atomic" "nhooyr.io/websocket" "cdr.dev/slog" + "github.com/coder/coder/coderd/conversion" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/database/dbauthz" "github.com/coder/coder/coderd/httpapi" @@ -329,36 +329,11 @@ func convertProvisionerJob(provisionerJob database.ProvisionerJob) codersdk.Prov if provisionerJob.WorkerID.Valid { job.WorkerID = &provisionerJob.WorkerID.UUID } - job.Status = ConvertProvisionerJobStatus(provisionerJob) + job.Status = conversion.ProvisionerJobStatus(provisionerJob) return job } -func ConvertProvisionerJobStatus(provisionerJob database.ProvisionerJob) codersdk.ProvisionerJobStatus { - switch { - case provisionerJob.CanceledAt.Valid: - if !provisionerJob.CompletedAt.Valid { - return codersdk.ProvisionerJobCanceling - } - if provisionerJob.Error.String == "" { - return codersdk.ProvisionerJobCanceled - } - return codersdk.ProvisionerJobFailed - case !provisionerJob.StartedAt.Valid: - return codersdk.ProvisionerJobPending - case provisionerJob.CompletedAt.Valid: - if provisionerJob.Error.String == "" { - return codersdk.ProvisionerJobSucceeded - } - return codersdk.ProvisionerJobFailed - case database.Now().Sub(provisionerJob.UpdatedAt) > 30*time.Second: - provisionerJob.Error.String = "Worker failed to update job in time." - return codersdk.ProvisionerJobFailed - default: - return codersdk.ProvisionerJobRunning - } -} - func provisionerJobLogsChannel(jobID uuid.UUID) string { return fmt.Sprintf("provisioner-log-logs:%s", jobID) } diff --git a/coderd/templates.go b/coderd/templates.go index 12e62c9a4d059..f15cf1ec3b3f6 100644 --- a/coderd/templates.go +++ b/coderd/templates.go @@ -203,6 +203,15 @@ func (api *API) postTemplateByOrganization(rw http.ResponseWriter, r *http.Reque return } templateVersionAudit.Old = templateVersion + if templateVersion.TemplateID.Valid { + httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ + Message: fmt.Sprintf("Template version %s is already part of a template", createTemplate.VersionID), + Validations: []codersdk.ValidationError{ + {Field: "template_version_id", Detail: "Template version is already part of a template"}, + }, + }) + return + } importJob, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID) if err != nil { diff --git a/coderd/templates_test.go b/coderd/templates_test.go index f0db7a12cadde..34e1637454ad6 100644 --- a/coderd/templates_test.go +++ b/coderd/templates_test.go @@ -347,8 +347,9 @@ func TestTemplatesByOrganization(t *testing.T) { client := coderdtest.New(t, nil) user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + version2 := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + coderdtest.CreateTemplate(t, client, user.OrganizationID, version2.ID) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) defer cancel() diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index dfd83126cea34..8718e68276c99 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -3,7 +3,6 @@ package coderd import ( "context" "database/sql" - "encoding/json" "errors" "fmt" "net/http" @@ -12,17 +11,16 @@ import ( "github.com/go-chi/chi/v5" "github.com/google/uuid" - "github.com/tabbed/pqtype" "golang.org/x/exp/slices" "golang.org/x/xerrors" + "github.com/coder/coder/coderd/conversion" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/database/dbauthz" "github.com/coder/coder/coderd/httpapi" "github.com/coder/coder/coderd/httpmw" - "github.com/coder/coder/coderd/provisionerdserver" "github.com/coder/coder/coderd/rbac" - "github.com/coder/coder/coderd/tracing" + "github.com/coder/coder/coderd/wsbuilder" "github.com/coder/coder/codersdk" ) @@ -313,363 +311,53 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { return } - // Doing this up front saves a lot of work if the user doesn't have permission. - // This is checked again in the dbauthz layer, but the check is cached - // and will be a noop later. - var action rbac.Action - switch createBuild.Transition { - case codersdk.WorkspaceTransitionDelete: - action = rbac.ActionDelete - case codersdk.WorkspaceTransitionStart, codersdk.WorkspaceTransitionStop: - action = rbac.ActionUpdate - default: - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: fmt.Sprintf("Transition %q not supported.", createBuild.Transition), - }) - return - } - if !api.Authorize(r, action, workspace) { - httpapi.ResourceNotFound(rw) - return - } + builder := wsbuilder.New(workspace, database.WorkspaceTransition(createBuild.Transition)). + Initiator(apiKey.UserID). + LegacyParameterValues(createBuild.ParameterValues). + RichParameterValues(createBuild.RichParameterValues). + LogLevel(string(createBuild.LogLevel)) - if createBuild.TemplateVersionID == uuid.Nil { - latestBuild, latestBuildErr := api.Database.GetLatestWorkspaceBuildByWorkspaceID(ctx, workspace.ID) - if latestBuildErr != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching the latest workspace build.", - Detail: latestBuildErr.Error(), - }) - return - } - createBuild.TemplateVersionID = latestBuild.TemplateVersionID - } - - templateVersion, err := api.Database.GetTemplateVersionByID(ctx, createBuild.TemplateVersionID) - if errors.Is(err, sql.ErrNoRows) { - httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Template version not found.", - Validations: []codersdk.ValidationError{{ - Field: "template_version_id", - Detail: "template version not found", - }}, - }) - return - } - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching template version.", - Detail: err.Error(), - }) - return - } - - template, err := api.Database.GetTemplateByID(ctx, templateVersion.TemplateID.UUID) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Failed to get template", - Detail: err.Error(), - }) - return - } - - var state []byte - // If custom state, deny request since user could be corrupting or leaking - // cloud state. - if createBuild.ProvisionerState != nil || createBuild.Orphan { - if !api.Authorize(r, rbac.ActionUpdate, template.RBACObject()) { - httpapi.Write(ctx, rw, http.StatusForbidden, codersdk.Response{ - Message: "Only template managers may provide custom state", - }) - return - } - state = createBuild.ProvisionerState + if createBuild.TemplateVersionID != uuid.Nil { + builder = builder.VersionID(createBuild.TemplateVersionID) } if createBuild.Orphan { if createBuild.Transition != codersdk.WorkspaceTransitionDelete { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: "Orphan is only permitted when deleting a workspace.", - Detail: err.Error(), }) return } - - if createBuild.ProvisionerState != nil && createBuild.Orphan { + if len(createBuild.ProvisionerState) > 0 { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: "ProvisionerState cannot be set alongside Orphan since state intent is unclear.", }) return } - state = []byte{} + builder = builder.Orphan() } - - templateVersionJob, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching provisioner job.", - Detail: err.Error(), - }) - return - } - templateVersionJobStatus := convertProvisionerJob(templateVersionJob).Status - switch templateVersionJobStatus { - case codersdk.ProvisionerJobPending, codersdk.ProvisionerJobRunning: - httpapi.Write(ctx, rw, http.StatusNotAcceptable, codersdk.Response{ - Message: fmt.Sprintf("The provided template version is %s. Wait for it to complete importing!", templateVersionJobStatus), - }) - return - case codersdk.ProvisionerJobFailed: - httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: fmt.Sprintf("The provided template version %q has failed to import: %q. You cannot build workspaces with it!", templateVersion.Name, templateVersionJob.Error.String), - }) - return - case codersdk.ProvisionerJobCanceled: - httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "The provided template version was canceled during import. You cannot builds workspaces with it!", - }) - return - } - - tags := provisionerdserver.MutateTags(workspace.OwnerID, templateVersionJob.Tags) - - // Store prior build number to compute new build number - var priorBuildNum int32 - priorHistory, err := api.Database.GetLatestWorkspaceBuildByWorkspaceID(ctx, workspace.ID) - if err == nil { - priorJob, err := api.Database.GetProvisionerJobByID(ctx, priorHistory.JobID) - if err == nil && convertProvisionerJob(priorJob).Status.Active() { - httpapi.Write(ctx, rw, http.StatusConflict, codersdk.Response{ - Message: "A workspace build is already active.", - }) - return - } - - priorBuildNum = priorHistory.BuildNumber - } else if !errors.Is(err, sql.ErrNoRows) { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching prior workspace build.", - Detail: err.Error(), - }) - return - } - - if state == nil { - state = priorHistory.ProvisionerState - } - - dbTemplateVersionParameters, err := api.Database.GetTemplateVersionParameters(ctx, createBuild.TemplateVersionID) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching template version parameters.", - Detail: err.Error(), - }) - return - } - templateVersionParameters, err := convertTemplateVersionParameters(dbTemplateVersionParameters) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error converting template version parameters.", - Detail: err.Error(), - }) - return + if len(createBuild.ProvisionerState) > 0 { + builder = builder.State(createBuild.ProvisionerState) } - lastBuildParameters, err := api.Database.GetWorkspaceBuildParameters(ctx, priorHistory.ID) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching prior workspace build parameters.", - Detail: err.Error(), - }) - return - } - apiLastBuildParameters := convertWorkspaceBuildParameters(lastBuildParameters) - - legacyParameters, err := api.Database.ParameterValues(ctx, database.ParameterValuesParams{ - Scopes: []database.ParameterScope{database.ParameterScopeWorkspace}, - ScopeIds: []uuid.UUID{workspace.ID}, - }) - if err != nil && !xerrors.Is(err, sql.ErrNoRows) { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Error fetching previous legacy parameters.", - Detail: err.Error(), - }) - return - } - - // Rich parameters migration: include legacy variables to the last build parameters - for _, templateVersionParameter := range templateVersionParameters { - // Check if parameter is defined in previous build - if _, found := findWorkspaceBuildParameter(apiLastBuildParameters, templateVersionParameter.Name); found { - continue - } - - // Check if legacy variable is defined - for _, legacyParameter := range legacyParameters { - if legacyParameter.Name != templateVersionParameter.LegacyVariableName { - continue - } - - apiLastBuildParameters = append(apiLastBuildParameters, codersdk.WorkspaceBuildParameter{ - Name: templateVersionParameter.Name, - Value: legacyParameter.SourceValue, - }) - break - } - } - - err = codersdk.ValidateWorkspaceBuildParameters(templateVersionParameters, createBuild.RichParameterValues, apiLastBuildParameters) - if err != nil { - httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Error validating workspace build parameters.", - Detail: err.Error(), - }) - return - } - - var parameters []codersdk.WorkspaceBuildParameter - for _, templateVersionParameter := range templateVersionParameters { - // Check if parameter value is in request - if buildParameter, found := findWorkspaceBuildParameter(createBuild.RichParameterValues, templateVersionParameter.Name); found { - if !templateVersionParameter.Mutable { - if _, found := findWorkspaceBuildParameter(apiLastBuildParameters, templateVersionParameter.Name); found { - httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: fmt.Sprintf("Parameter %q is not mutable, so it can't be updated after creating a workspace.", templateVersionParameter.Name), - }) - return - } - } - parameters = append(parameters, *buildParameter) - continue - } - - // Check if parameter is defined in previous build - if buildParameter, found := findWorkspaceBuildParameter(apiLastBuildParameters, templateVersionParameter.Name); found { - parameters = append(parameters, *buildParameter) - continue - } - - // Check if default parameter value is in schema - if templateVersionParameter.DefaultValue != "" { - parameters = append(parameters, codersdk.WorkspaceBuildParameter{ - Name: templateVersionParameter.Name, - Value: templateVersionParameter.DefaultValue, - }) - } - } - - if createBuild.LogLevel != "" && !api.Authorize(r, rbac.ActionUpdate, template) { - httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Workspace builds with a custom log level are restricted to template authors only.", + workspaceBuild, provisionerJob, err := builder.Build( + ctx, + api.Database, + func(action rbac.Action, object rbac.Objecter) bool { + return api.Authorize(r, action, object) + }, + ) + var buildErr wsbuilder.BuildError + if xerrors.As(err, &buildErr) { + httpapi.Write(ctx, rw, buildErr.Status, codersdk.Response{ + Message: buildErr.Message, + Detail: buildErr.Error(), }) return } - - var workspaceBuild database.WorkspaceBuild - var provisionerJob database.ProvisionerJob - // This must happen in a transaction to ensure history can be inserted, and - // the prior history can update it's "after" column to point at the new. - err = api.Database.InTx(func(db database.Store) error { - // Write/Update any new params - now := database.Now() - for _, param := range createBuild.ParameterValues { - for _, exists := range legacyParameters { - // If the param exists, delete the old param before inserting the new one - if exists.Name == param.Name { - err = db.DeleteParameterValueByID(ctx, exists.ID) - if err != nil && !xerrors.Is(err, sql.ErrNoRows) { - return xerrors.Errorf("Failed to delete old param %q: %w", exists.Name, err) - } - } - } - - _, err = db.InsertParameterValue(ctx, database.InsertParameterValueParams{ - ID: uuid.New(), - Name: param.Name, - CreatedAt: now, - UpdatedAt: now, - Scope: database.ParameterScopeWorkspace, - ScopeID: workspace.ID, - SourceScheme: database.ParameterSourceScheme(param.SourceScheme), - SourceValue: param.SourceValue, - DestinationScheme: database.ParameterDestinationScheme(param.DestinationScheme), - }) - if err != nil { - return xerrors.Errorf("insert parameter value: %w", err) - } - } - - workspaceBuildID := uuid.New() - input, err := json.Marshal(provisionerdserver.WorkspaceProvisionJob{ - WorkspaceBuildID: workspaceBuildID, - LogLevel: string(createBuild.LogLevel), - }) - if err != nil { - return xerrors.Errorf("marshal provision job: %w", err) - } - traceMetadataRaw, err := json.Marshal(tracing.MetadataFromContext(ctx)) - if err != nil { - return xerrors.Errorf("marshal metadata: %w", err) - } - - provisionerJob, err = db.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{ - ID: uuid.New(), - CreatedAt: database.Now(), - UpdatedAt: database.Now(), - InitiatorID: apiKey.UserID, - OrganizationID: template.OrganizationID, - Provisioner: template.Provisioner, - Type: database.ProvisionerJobTypeWorkspaceBuild, - StorageMethod: templateVersionJob.StorageMethod, - FileID: templateVersionJob.FileID, - Input: input, - Tags: tags, - TraceMetadata: pqtype.NullRawMessage{ - Valid: true, - RawMessage: traceMetadataRaw, - }, - }) - if err != nil { - return xerrors.Errorf("insert provisioner job: %w", err) - } - - workspaceBuild, err = db.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{ - ID: workspaceBuildID, - CreatedAt: database.Now(), - UpdatedAt: database.Now(), - WorkspaceID: workspace.ID, - TemplateVersionID: templateVersion.ID, - BuildNumber: priorBuildNum + 1, - ProvisionerState: state, - InitiatorID: apiKey.UserID, - Transition: database.WorkspaceTransition(createBuild.Transition), - JobID: provisionerJob.ID, - Reason: database.BuildReasonInitiator, - }) - if err != nil { - return xerrors.Errorf("insert workspace build: %w", err) - } - - names := make([]string, 0, len(parameters)) - values := make([]string, 0, len(parameters)) - for _, param := range parameters { - names = append(names, param.Name) - values = append(values, param.Value) - } - err = db.InsertWorkspaceBuildParameters(ctx, database.InsertWorkspaceBuildParametersParams{ - WorkspaceBuildID: workspaceBuildID, - Name: names, - Value: values, - }) - if err != nil { - return xerrors.Errorf("insert workspace build parameters: %w", err) - } - - return nil - }, nil) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error inserting workspace build.", + Message: "Error posting new build", Detail: err.Error(), }) return @@ -688,9 +376,9 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { } apiBuild, err := api.convertWorkspaceBuild( - workspaceBuild, + *workspaceBuild, workspace, - provisionerJob, + *provisionerJob, users, []database.WorkspaceResource{}, []database.WorkspaceResourceMetadatum{}, @@ -852,7 +540,7 @@ func (api *API) workspaceBuildParameters(rw http.ResponseWriter, r *http.Request }) return } - apiParameters := convertWorkspaceBuildParameters(parameters) + apiParameters := conversion.WorkspaceBuildParameters(parameters) httpapi.Write(ctx, rw, http.StatusOK, apiParameters) } @@ -1232,25 +920,3 @@ func convertWorkspaceStatus(jobStatus codersdk.ProvisionerJobStatus, transition // return error status since we should never get here return codersdk.WorkspaceStatusFailed } - -func convertWorkspaceBuildParameters(parameters []database.WorkspaceBuildParameter) []codersdk.WorkspaceBuildParameter { - apiParameters := make([]codersdk.WorkspaceBuildParameter, 0, len(parameters)) - - for _, p := range parameters { - apiParameter := codersdk.WorkspaceBuildParameter{ - Name: p.Name, - Value: p.Value, - } - apiParameters = append(apiParameters, apiParameter) - } - return apiParameters -} - -func findWorkspaceBuildParameter(params []codersdk.WorkspaceBuildParameter, parameterName string) (*codersdk.WorkspaceBuildParameter, bool) { - for _, p := range params { - if p.Name == parameterName { - return &p, true - } - } - return nil, false -} diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 10d0dc9281882..9e5b50fe68c09 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -13,7 +13,6 @@ import ( "github.com/go-chi/chi/v5" "github.com/google/uuid" - "github.com/tabbed/pqtype" "golang.org/x/exp/slices" "golang.org/x/xerrors" @@ -22,13 +21,12 @@ import ( "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/httpapi" "github.com/coder/coder/coderd/httpmw" - "github.com/coder/coder/coderd/provisionerdserver" "github.com/coder/coder/coderd/rbac" "github.com/coder/coder/coderd/schedule" "github.com/coder/coder/coderd/searchquery" "github.com/coder/coder/coderd/telemetry" - "github.com/coder/coder/coderd/tracing" "github.com/coder/coder/coderd/util/ptr" + "github.com/coder/coder/coderd/wsbuilder" "github.com/coder/coder/codersdk" ) @@ -399,77 +397,12 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req return } - templateVersion, err := api.Database.GetTemplateVersionByID(ctx, template.ActiveVersionID) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching template version.", - Detail: err.Error(), - }) - return - } - - dbTemplateVersionParameters, err := api.Database.GetTemplateVersionParameters(ctx, templateVersion.ID) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching template version parameters.", - Detail: err.Error(), - }) - return - } - - templateVersionParameters, err := convertTemplateVersionParameters(dbTemplateVersionParameters) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error converting template version parameters.", - Detail: err.Error(), - }) - return - } - - err = codersdk.ValidateNewWorkspaceParameters(templateVersionParameters, createWorkspace.RichParameterValues) - if err != nil { - httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "Error validating workspace build parameters.", - Detail: err.Error(), - }) - return - } - - templateVersionJob, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching template version job.", - Detail: err.Error(), - }) - return - } - templateVersionJobStatus := convertProvisionerJob(templateVersionJob).Status - switch templateVersionJobStatus { - case codersdk.ProvisionerJobPending, codersdk.ProvisionerJobRunning: - httpapi.Write(ctx, rw, http.StatusNotAcceptable, codersdk.Response{ - Message: fmt.Sprintf("The provided template version is %s. Wait for it to complete importing!", templateVersionJobStatus), - }) - return - case codersdk.ProvisionerJobFailed: - httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: fmt.Sprintf("The provided template version %q has failed to import. You cannot create workspaces using it!", templateVersion.Name), - }) - return - case codersdk.ProvisionerJobCanceled: - httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ - Message: "The provided template version was canceled during import. You cannot create workspaces using it!", - }) - return - } - - tags := provisionerdserver.MutateTags(user.ID, templateVersionJob.Tags) var ( - provisionerJob database.ProvisionerJob - workspaceBuild database.WorkspaceBuild + provisionerJob *database.ProvisionerJob + workspaceBuild *database.WorkspaceBuild ) err = api.Database.InTx(func(db database.Store) error { now := database.Now() - workspaceBuildID := uuid.New() // Workspaces are created without any versions. workspace, err = db.InsertWorkspace(ctx, database.InsertWorkspaceParams{ ID: uuid.New(), @@ -488,92 +421,27 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req if err != nil { return xerrors.Errorf("insert workspace: %w", err) } - for _, parameterValue := range createWorkspace.ParameterValues { - // If the value is empty, we don't want to save it on database so - // Terraform can use the default value - if parameterValue.SourceValue == "" { - continue - } - _, err = db.InsertParameterValue(ctx, database.InsertParameterValueParams{ - ID: uuid.New(), - Name: parameterValue.Name, - CreatedAt: now, - UpdatedAt: now, - Scope: database.ParameterScopeWorkspace, - ScopeID: workspace.ID, - SourceScheme: database.ParameterSourceScheme(parameterValue.SourceScheme), - SourceValue: parameterValue.SourceValue, - DestinationScheme: database.ParameterDestinationScheme(parameterValue.DestinationScheme), + builder := wsbuilder.New(workspace, database.WorkspaceTransitionStart). + Reason(database.BuildReasonInitiator). + Initiator(apiKey.UserID). + ActiveVersion(). + LegacyParameterValues(createWorkspace.ParameterValues). + RichParameterValues(createWorkspace.RichParameterValues) + workspaceBuild, provisionerJob, err = builder.Build( + ctx, db, func(action rbac.Action, object rbac.Objecter) bool { + return api.Authorize(r, action, object) }) - if err != nil { - return xerrors.Errorf("insert parameter value: %w", err) - } - } - - input, err := json.Marshal(provisionerdserver.WorkspaceProvisionJob{ - WorkspaceBuildID: workspaceBuildID, - }) - if err != nil { - return xerrors.Errorf("marshal provision job: %w", err) - } - traceMetadataRaw, err := json.Marshal(tracing.MetadataFromContext(ctx)) - if err != nil { - return xerrors.Errorf("marshal metadata: %w", err) - } - provisionerJob, err = db.InsertProvisionerJob(ctx, database.InsertProvisionerJobParams{ - ID: uuid.New(), - CreatedAt: now, - UpdatedAt: now, - InitiatorID: apiKey.UserID, - OrganizationID: template.OrganizationID, - Provisioner: template.Provisioner, - Type: database.ProvisionerJobTypeWorkspaceBuild, - StorageMethod: templateVersionJob.StorageMethod, - FileID: templateVersionJob.FileID, - Input: input, - Tags: tags, - TraceMetadata: pqtype.NullRawMessage{ - Valid: true, - RawMessage: traceMetadataRaw, - }, - }) - if err != nil { - return xerrors.Errorf("insert provisioner job: %w", err) - } - workspaceBuild, err = db.InsertWorkspaceBuild(ctx, database.InsertWorkspaceBuildParams{ - ID: workspaceBuildID, - CreatedAt: now, - UpdatedAt: now, - WorkspaceID: workspace.ID, - TemplateVersionID: templateVersion.ID, - InitiatorID: apiKey.UserID, - Transition: database.WorkspaceTransitionStart, - JobID: provisionerJob.ID, - BuildNumber: 1, // First build! - Deadline: time.Time{}, // provisionerd will set this upon success - Reason: database.BuildReasonInitiator, - }) - if err != nil { - return xerrors.Errorf("insert workspace build: %w", err) - } - - names := make([]string, 0, len(createWorkspace.RichParameterValues)) - values := make([]string, 0, len(createWorkspace.RichParameterValues)) - for _, param := range createWorkspace.RichParameterValues { - names = append(names, param.Name) - values = append(values, param.Value) - } - err = db.InsertWorkspaceBuildParameters(ctx, database.InsertWorkspaceBuildParametersParams{ - WorkspaceBuildID: workspaceBuildID, - Name: names, - Value: values, - }) - if err != nil { - return xerrors.Errorf("insert workspace build parameters: %w", err) - } - return nil + return err }, nil) + var bldErr wsbuilder.BuildError + if xerrors.As(err, &bldErr) { + httpapi.Write(ctx, rw, bldErr.Status, codersdk.Response{ + Message: bldErr.Message, + Detail: bldErr.Error(), + }) + return + } if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ Message: "Internal error creating workspace.", @@ -594,14 +462,14 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req api.Telemetry.Report(&telemetry.Snapshot{ Workspaces: []telemetry.Workspace{telemetry.ConvertWorkspace(workspace)}, - WorkspaceBuilds: []telemetry.WorkspaceBuild{telemetry.ConvertWorkspaceBuild(workspaceBuild)}, + WorkspaceBuilds: []telemetry.WorkspaceBuild{telemetry.ConvertWorkspaceBuild(*workspaceBuild)}, }) users := []database.User{user, initiator} apiBuild, err := api.convertWorkspaceBuild( - workspaceBuild, + *workspaceBuild, workspace, - provisionerJob, + *provisionerJob, users, []database.WorkspaceResource{}, []database.WorkspaceResourceMetadatum{}, diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 54e65939e719d..f3005b8eb4747 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -746,9 +746,11 @@ func TestWorkspaceFilterManual(t *testing.T) { client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + version2 := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + coderdtest.AwaitTemplateVersionJob(t, client, version2.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - template2 := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + template2 := coderdtest.CreateTemplate(t, client, user.OrganizationID, version2.ID) workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) _ = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template2.ID) @@ -819,9 +821,11 @@ func TestWorkspaceFilterManual(t *testing.T) { client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) + version2 := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, nil) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + coderdtest.AwaitTemplateVersionJob(t, client, version2.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - template2 := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + template2 := coderdtest.CreateTemplate(t, client, user.OrganizationID, version2.ID) workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) _ = coderdtest.CreateWorkspace(t, client, user.OrganizationID, template2.ID) @@ -2038,14 +2042,12 @@ func TestWorkspaceWithOptionalRichParameters(t *testing.T) { require.Equal(t, secondParameterDescription, templateRichParameters[1].Description) require.Equal(t, secondParameterRequired, templateRichParameters[1].Required) - expectedBuildParameters := []codersdk.WorkspaceBuildParameter{ - // First parameter is optional, so coder will pick the default value. - {Name: secondParameterName, Value: secondParameterValue}, - } - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { - cwr.RichParameterValues = expectedBuildParameters + cwr.RichParameterValues = []codersdk.WorkspaceBuildParameter{ + // First parameter is optional, so coder will pick the default value. + {Name: secondParameterName, Value: secondParameterValue}, + } }) workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) @@ -2054,5 +2056,10 @@ func TestWorkspaceWithOptionalRichParameters(t *testing.T) { workspaceBuildParameters, err := client.WorkspaceBuildParameters(ctx, workspaceBuild.ID) require.NoError(t, err) + expectedBuildParameters := []codersdk.WorkspaceBuildParameter{ + // Coderd inserts the default for the missing parameter + {Name: firstParameterName, Value: firstParameterDefaultValue}, + {Name: secondParameterName, Value: secondParameterValue}, + } require.ElementsMatch(t, expectedBuildParameters, workspaceBuildParameters) } diff --git a/coderd/wsbuilder/wsbuilder.go b/coderd/wsbuilder/wsbuilder.go new file mode 100644 index 0000000000000..4c4669ee7d5a8 --- /dev/null +++ b/coderd/wsbuilder/wsbuilder.go @@ -0,0 +1,741 @@ +// Package wsbuilder provides the Builder object, which encapsulates the common business logic of inserting a new +// workspace build into the database. +package wsbuilder + +import ( + "context" + "database/sql" + "encoding/json" + "fmt" + "net/http" + + "github.com/google/uuid" + "github.com/lib/pq" + "github.com/tabbed/pqtype" + "golang.org/x/xerrors" + + "github.com/coder/coder/coderd/conversion" + "github.com/coder/coder/coderd/database" + "github.com/coder/coder/coderd/httpapi" + "github.com/coder/coder/coderd/provisionerdserver" + "github.com/coder/coder/coderd/rbac" + "github.com/coder/coder/coderd/tracing" + "github.com/coder/coder/codersdk" +) + +// Builder encapsulates the business logic of inserting a new workspace build into the database. +// +// Builder follows the so-called "Builder" pattern where options that customize the kind of build you get return +// a new instance of the Builder with the option applied. +// +// Example: +// +// b = wsbuilder.New(workspace, transition).VersionID(vID).Initiator(me) +// build, job, err := b.Build(...) +type Builder struct { + // settings that control the kind of build you get + workspace database.Workspace + trans database.WorkspaceTransition + version versionTarget + state stateTarget + logLevel string + legacyParameterValues []codersdk.CreateParameterRequest + richParameterValues []codersdk.WorkspaceBuildParameter + initiator uuid.UUID + reason database.BuildReason + + // used during build, makes function arguments less verbose + ctx context.Context + store database.Store + + // cache of objects, so we only fetch once + template *database.Template + templateVersion *database.TemplateVersion + templateVersionJob *database.ProvisionerJob + templateVersionParameters *[]database.TemplateVersionParameter + lastBuild *database.WorkspaceBuild + lastBuildErr *error + lastBuildParameters *[]database.WorkspaceBuildParameter + lastParameterValues *[]database.ParameterValue + lastBuildJob *database.ProvisionerJob +} + +type versionTarget struct { + active bool + specific *uuid.UUID +} + +type stateTarget struct { + orphan bool + explicit *[]byte +} + +func New(w database.Workspace, t database.WorkspaceTransition) Builder { + return Builder{workspace: w, trans: t} +} + +// Methods that customize the build are public, have a struct receiver and return a new Builder. + +func (b Builder) VersionID(v uuid.UUID) Builder { + // nolint: revive + b.version = versionTarget{specific: &v} + return b +} + +func (b Builder) ActiveVersion() Builder { + // nolint: revive + b.version = versionTarget{active: true} + return b +} + +func (b Builder) State(state []byte) Builder { + // nolint: revive + b.state = stateTarget{explicit: &state} + return b +} + +func (b Builder) Orphan() Builder { + // nolint: revive + b.state = stateTarget{orphan: true} + return b +} + +func (b Builder) LogLevel(l string) Builder { + // nolint: revive + b.logLevel = l + return b +} + +func (b Builder) Initiator(u uuid.UUID) Builder { + // nolint: revive + b.initiator = u + return b +} + +func (b Builder) Reason(r database.BuildReason) Builder { + // nolint: revive + b.reason = r + return b +} + +func (b Builder) LegacyParameterValues(p []codersdk.CreateParameterRequest) Builder { + // nolint: revive + b.legacyParameterValues = p + return b +} + +func (b Builder) RichParameterValues(p []codersdk.WorkspaceBuildParameter) Builder { + // nolint: revive + b.richParameterValues = p + return b +} + +// SetLastWorkspaceBuildInTx prepopulates the Builder's cache with the last workspace build. This allows us +// to avoid a repeated database query when the Builder's caller also needs the workspace build, e.g. auto-start & +// auto-stop. +// +// CAUTION: only call this method from within a database transaction with RepeatableRead isolation. This transaction +// MUST be the database.Store you call Build() with. +func (b Builder) SetLastWorkspaceBuildInTx(build *database.WorkspaceBuild) Builder { + // nolint: revive + b.lastBuild = build + return b +} + +// SetLastWorkspaceBuildJobInTx prepopulates the Builder's cache with the last workspace build job. This allows us +// to avoid a repeated database query when the Builder's caller also needs the workspace build job, e.g. auto-start & +// auto-stop. +// +// CAUTION: only call this method from within a database transaction with RepeatableRead isolation. This transaction +// MUST be the database.Store you call Build() with. +func (b Builder) SetLastWorkspaceBuildJobInTx(job *database.ProvisionerJob) Builder { + // nolint: revive + b.lastBuildJob = job + return b +} + +type BuildError struct { + // Status is a suitable HTTP status code + Status int + Message string + Wrapped error +} + +func (e BuildError) Error() string { + return e.Wrapped.Error() +} + +func (e BuildError) Unwrap() error { + return e.Wrapped +} + +// Build computes and inserts a new workspace build into the database. If authFunc is provided, it also performs +// authorization preflight checks. +func (b *Builder) Build( + ctx context.Context, + store database.Store, + authFunc func(action rbac.Action, object rbac.Objecter) bool, +) ( + *database.WorkspaceBuild, *database.ProvisionerJob, error, +) { + b.ctx = ctx + + // Run the build in a transaction with RepeatableRead isolation, and retries. + // RepeatableRead isolation ensures that we get a consistent view of the database while + // computing the new build. This simplifies the logic so that we do not need to worry if + // later reads are consistent with earlier ones. + var err error + for retries := 0; retries < 5; retries++ { + var workspaceBuild *database.WorkspaceBuild + var provisionerJob *database.ProvisionerJob + err := store.InTx(func(store database.Store) error { + b.store = store + workspaceBuild, provisionerJob, err = b.buildTx(authFunc) + return err + }, &sql.TxOptions{Isolation: sql.LevelRepeatableRead}) + var pqe *pq.Error + if xerrors.As(err, &pqe) { + if pqe.Code == "40001" { + // serialization error, retry + continue + } + } + if err != nil { + // Other (hard) error + return nil, nil, err + } + return workspaceBuild, provisionerJob, nil + } + return nil, nil, xerrors.Errorf("too many errors; last error: %w", err) +} + +// buildTx contains the business logic of computing a new build. Attributes of the new database objects are computed +// in a functional style, rather than imperative, to emphasize the logic of how they are defined. A simple cache +// of database-fetched objects is stored on the struct to ensure we only fetch things once, even if they are used in +// the calculation of multiple attributes. +// +// In order to utilize this cache, the functions that compute build attributes use a pointer receiver type. +func (b *Builder) buildTx(authFunc func(action rbac.Action, object rbac.Objecter) bool) ( + *database.WorkspaceBuild, *database.ProvisionerJob, error, +) { + if authFunc != nil { + err := b.authorize(authFunc) + if err != nil { + return nil, nil, err + } + } + err := b.checkTemplateVersionMatchesTemplate() + if err != nil { + return nil, nil, err + } + err = b.checkTemplateJobStatus() + if err != nil { + return nil, nil, err + } + err = b.checkRunningBuild() + if err != nil { + return nil, nil, err + } + + template, err := b.getTemplate() + if err != nil { + return nil, nil, BuildError{http.StatusInternalServerError, "failed to fetch template", err} + } + + templateVersionJob, err := b.getTemplateVersionJob() + if err != nil { + return nil, nil, BuildError{ + http.StatusInternalServerError, "failed to fetch template version job", err, + } + } + + legacyParameters, err := b.getLastParameterValues() + if err != nil { + return nil, nil, BuildError{ + http.StatusInternalServerError, + "failed to fetch previous legacy parameters.", + err, + } + } + + // if we haven't been told specifically who initiated, default to owner + if b.initiator == uuid.Nil { + b.initiator = b.workspace.OwnerID + } + // default reason is initiator + if b.reason == "" { + b.reason = database.BuildReasonInitiator + } + + // Write/Update any new params + now := database.Now() + for _, param := range b.legacyParameterValues { + for _, exists := range legacyParameters { + // If the param exists, delete the old param before inserting the new one + if exists.Name == param.Name { + err = b.store.DeleteParameterValueByID(b.ctx, exists.ID) + if err != nil && !xerrors.Is(err, sql.ErrNoRows) { + return nil, nil, BuildError{ + http.StatusInternalServerError, + fmt.Sprintf("Failed to delete old param %q", exists.Name), + err, + } + } + } + } + + // If the value is empty, we don't want to save it on database so + // Terraform can use the default value + if param.SourceValue == "" { + continue + } + + _, err = b.store.InsertParameterValue(b.ctx, database.InsertParameterValueParams{ + ID: uuid.New(), + Name: param.Name, + CreatedAt: now, + UpdatedAt: now, + Scope: database.ParameterScopeWorkspace, + ScopeID: b.workspace.ID, + SourceScheme: database.ParameterSourceScheme(param.SourceScheme), + SourceValue: param.SourceValue, + DestinationScheme: database.ParameterDestinationScheme(param.DestinationScheme), + }) + if err != nil { + return nil, nil, BuildError{http.StatusInternalServerError, "insert parameter value", err} + } + } + + workspaceBuildID := uuid.New() + input, err := json.Marshal(provisionerdserver.WorkspaceProvisionJob{ + WorkspaceBuildID: workspaceBuildID, + LogLevel: b.logLevel, + }) + if err != nil { + return nil, nil, BuildError{ + http.StatusInternalServerError, + "marshal provision job", + err, + } + } + traceMetadataRaw, err := json.Marshal(tracing.MetadataFromContext(b.ctx)) + if err != nil { + return nil, nil, BuildError{http.StatusInternalServerError, "marshal metadata", err} + } + tags := provisionerdserver.MutateTags(b.workspace.OwnerID, templateVersionJob.Tags) + + provisionerJob, err := b.store.InsertProvisionerJob(b.ctx, database.InsertProvisionerJobParams{ + ID: uuid.New(), + CreatedAt: now, + UpdatedAt: now, + InitiatorID: b.initiator, + OrganizationID: template.OrganizationID, + Provisioner: template.Provisioner, + Type: database.ProvisionerJobTypeWorkspaceBuild, + StorageMethod: templateVersionJob.StorageMethod, + FileID: templateVersionJob.FileID, + Input: input, + Tags: tags, + TraceMetadata: pqtype.NullRawMessage{ + Valid: true, + RawMessage: traceMetadataRaw, + }, + }) + if err != nil { + return nil, nil, BuildError{http.StatusInternalServerError, "insert provisioner job", err} + } + + templateVersionID, err := b.getTemplateVersionID() + if err != nil { + return nil, nil, BuildError{http.StatusInternalServerError, "compute template version ID", err} + } + buildNum, err := b.getBuildNumber() + if err != nil { + return nil, nil, BuildError{http.StatusInternalServerError, "compute build number", err} + } + state, err := b.getState() + if err != nil { + return nil, nil, BuildError{http.StatusInternalServerError, "compute build state", err} + } + workspaceBuild, err := b.store.InsertWorkspaceBuild(b.ctx, database.InsertWorkspaceBuildParams{ + ID: workspaceBuildID, + CreatedAt: now, + UpdatedAt: now, + WorkspaceID: b.workspace.ID, + TemplateVersionID: templateVersionID, + BuildNumber: buildNum, + ProvisionerState: state, + InitiatorID: b.initiator, + Transition: b.trans, + JobID: provisionerJob.ID, + Reason: b.reason, + }) + if err != nil { + return nil, nil, BuildError{http.StatusInternalServerError, "insert workspace build", err} + } + + names, values, err := b.getParameters() + if err != nil { + // getParameters already wraps errors in BuildError + return nil, nil, err + } + err = b.store.InsertWorkspaceBuildParameters(b.ctx, database.InsertWorkspaceBuildParametersParams{ + WorkspaceBuildID: workspaceBuildID, + Name: names, + Value: values, + }) + if err != nil { + return nil, nil, BuildError{http.StatusInternalServerError, "insert workspace build parameters: %w", err} + } + + return &workspaceBuild, &provisionerJob, nil +} + +func (b *Builder) getTemplate() (*database.Template, error) { + if b.template != nil { + return b.template, nil + } + t, err := b.store.GetTemplateByID(b.ctx, b.workspace.TemplateID) + if err != nil { + return nil, err + } + b.template = &t + return b.template, nil +} + +func (b *Builder) getTemplateVersionJob() (*database.ProvisionerJob, error) { + if b.templateVersionJob != nil { + return b.templateVersionJob, nil + } + v, err := b.getTemplateVersion() + if err != nil { + return nil, err + } + j, err := b.store.GetProvisionerJobByID(b.ctx, v.JobID) + if err != nil { + return nil, err + } + b.templateVersionJob = &j + return b.templateVersionJob, err +} + +func (b *Builder) getTemplateVersion() (*database.TemplateVersion, error) { + if b.templateVersion != nil { + return b.templateVersion, nil + } + id, err := b.getTemplateVersionID() + if err != nil { + return nil, err + } + v, err := b.store.GetTemplateVersionByID(b.ctx, id) + if err != nil { + return nil, err + } + b.templateVersion = &v + return b.templateVersion, err +} + +func (b *Builder) getTemplateVersionID() (uuid.UUID, error) { + if b.version.specific != nil { + return *b.version.specific, nil + } + if b.version.active { + t, err := b.getTemplate() + if err != nil { + return uuid.Nil, err + } + return t.ActiveVersionID, nil + } + // default is prior version + bld, err := b.getLastBuild() + if err != nil { + return uuid.Nil, err + } + return bld.TemplateVersionID, nil +} + +func (b *Builder) getLastBuild() (*database.WorkspaceBuild, error) { + if b.lastBuild != nil { + return b.lastBuild, nil + } + // last build might not exist, so we also store the error to prevent repeated queries + // for a non-existing build + if b.lastBuildErr != nil { + return nil, *b.lastBuildErr + } + bld, err := b.store.GetLatestWorkspaceBuildByWorkspaceID(b.ctx, b.workspace.ID) + b.lastBuildErr = &err + if err != nil { + return nil, err + } + b.lastBuild = &bld + return b.lastBuild, nil +} + +func (b *Builder) getBuildNumber() (int32, error) { + bld, err := b.getLastBuild() + if xerrors.Is(err, sql.ErrNoRows) { + // first build! + return 1, nil + } + if err != nil { + return 0, err + } + return bld.BuildNumber + 1, nil +} + +func (b *Builder) getState() ([]byte, error) { + if b.state.orphan { + // Orphan means empty state. + return nil, nil + } + if b.state.explicit != nil { + return *b.state.explicit, nil + } + // Default is to use state from prior build + bld, err := b.getLastBuild() + if xerrors.Is(err, sql.ErrNoRows) { + // last build does not exist, which implies empty state + return nil, nil + } + if err != nil { + return nil, err + } + return bld.ProvisionerState, nil +} + +func (b *Builder) getParameters() (names, values []string, err error) { + templateVersionParameters, err := b.getTemplateVersionParameters() + if err != nil { + return nil, nil, BuildError{http.StatusInternalServerError, "failed to fetch template version parameters", err} + } + lastBuildParameters, err := b.getLastBuildParameters() + if err != nil { + return nil, nil, BuildError{http.StatusInternalServerError, "failed to fetch last build parameters", err} + } + lastParameterValues, err := b.getLastParameterValues() + if err != nil { + return nil, nil, BuildError{http.StatusInternalServerError, "failed to fetch last parameter values", err} + } + resolver := codersdk.ParameterResolver{ + Rich: conversion.WorkspaceBuildParameters(lastBuildParameters), + Legacy: conversion.Parameters(lastParameterValues), + } + for _, templateVersionParameter := range templateVersionParameters { + tvp, err := conversion.TemplateVersionParameter(templateVersionParameter) + if err != nil { + return nil, nil, BuildError{http.StatusInternalServerError, "failed to convert template version parameter", err} + } + value, err := resolver.ValidateResolve( + tvp, + b.findNewBuildParameterValue(templateVersionParameter.Name), + ) + if err != nil { + // At this point, we've queried all the data we need from the database, + // so the only errors are problems with the request (missing data, failed + // validation, immutable parameters, etc.) + return nil, nil, BuildError{http.StatusBadRequest, err.Error(), err} + } + names = append(names, templateVersionParameter.Name) + values = append(values, value) + } + return names, values, nil +} + +func (b *Builder) findNewBuildParameterValue(name string) *codersdk.WorkspaceBuildParameter { + for _, v := range b.richParameterValues { + if v.Name == name { + return &v + } + } + return nil +} + +func (b *Builder) getLastBuildParameters() ([]database.WorkspaceBuildParameter, error) { + if b.lastBuildParameters != nil { + return *b.lastBuildParameters, nil + } + bld, err := b.getLastBuild() + if xerrors.Is(err, sql.ErrNoRows) { + // if the build doesn't exist, then clearly there can be no parameters. + b.lastBuildParameters = &[]database.WorkspaceBuildParameter{} + return *b.lastBuildParameters, nil + } + if err != nil { + return nil, err + } + values, err := b.store.GetWorkspaceBuildParameters(b.ctx, bld.ID) + if err != nil && !xerrors.Is(err, sql.ErrNoRows) { + return nil, err + } + b.lastBuildParameters = &values + return values, nil +} + +func (b *Builder) getTemplateVersionParameters() ([]database.TemplateVersionParameter, error) { + if b.templateVersionParameters != nil { + return *b.templateVersionParameters, nil + } + tvID, err := b.getTemplateVersionID() + if err != nil { + return nil, err + } + tvp, err := b.store.GetTemplateVersionParameters(b.ctx, tvID) + if err != nil && !xerrors.Is(err, sql.ErrNoRows) { + return nil, err + } + b.templateVersionParameters = &tvp + return tvp, nil +} + +func (b *Builder) getLastParameterValues() ([]database.ParameterValue, error) { + if b.lastParameterValues != nil { + return *b.lastParameterValues, nil + } + pv, err := b.store.ParameterValues(b.ctx, database.ParameterValuesParams{ + Scopes: []database.ParameterScope{database.ParameterScopeWorkspace}, + ScopeIds: []uuid.UUID{b.workspace.ID}, + }) + if err != nil && !xerrors.Is(err, sql.ErrNoRows) { + return nil, err + } + b.lastParameterValues = &pv + return pv, nil +} + +func (b *Builder) getLastBuildJob() (*database.ProvisionerJob, error) { + if b.lastBuildJob != nil { + return b.lastBuildJob, nil + } + bld, err := b.getLastBuild() + if err != nil { + return nil, err + } + job, err := b.store.GetProvisionerJobByID(b.ctx, bld.JobID) + if err != nil { + return nil, err + } + b.lastBuildJob = &job + return b.lastBuildJob, nil +} + +// authorize performs build authorization pre-checks using the provided authFunc +func (b *Builder) authorize(authFunc func(action rbac.Action, object rbac.Objecter) bool) error { + // Doing this up front saves a lot of work if the user doesn't have permission. + // This is checked again in the dbauthz layer, but the check is cached + // and will be a noop later. + var action rbac.Action + switch b.trans { + case database.WorkspaceTransitionDelete: + action = rbac.ActionDelete + case database.WorkspaceTransitionStart, database.WorkspaceTransitionStop: + action = rbac.ActionUpdate + default: + return BuildError{http.StatusBadRequest, fmt.Sprintf("Transition %q not supported.", b.trans), xerrors.New("")} + } + if !authFunc(action, b.workspace) { + // We use the same wording as the httpapi to avoid leaking the existence of the workspace + return BuildError{http.StatusNotFound, httpapi.ResourceNotFoundResponse.Message, xerrors.New("")} + } + + template, err := b.getTemplate() + if err != nil { + return BuildError{http.StatusInternalServerError, "failed to fetch template", err} + } + + // If custom state, deny request since user could be corrupting or leaking + // cloud state. + if b.state.explicit != nil || b.state.orphan { + if !authFunc(rbac.ActionUpdate, template.RBACObject()) { + return BuildError{http.StatusForbidden, "Only template managers may provide custom state", xerrors.New("")} + } + } + + if b.logLevel != "" && !authFunc(rbac.ActionUpdate, template) { + return BuildError{ + http.StatusBadRequest, + "Workspace builds with a custom log level are restricted to template authors only.", + xerrors.New(""), + } + } + return nil +} + +func (b *Builder) checkTemplateVersionMatchesTemplate() error { + template, err := b.getTemplate() + if err != nil { + return BuildError{http.StatusInternalServerError, "failed to fetch template", err} + } + templateVersion, err := b.getTemplateVersion() + if xerrors.Is(err, sql.ErrNoRows) { + return BuildError{http.StatusBadRequest, "template version does not exist", err} + } + if err != nil { + return BuildError{http.StatusInternalServerError, "failed to fetch template version", err} + } + if !templateVersion.TemplateID.Valid || templateVersion.TemplateID.UUID != template.ID { + return BuildError{ + http.StatusBadRequest, + "template version doesn't match template", + xerrors.Errorf("templateVersion.TemplateID = %+v, template.ID = %s", + templateVersion.TemplateID, template.ID), + } + } + return nil +} + +func (b *Builder) checkTemplateJobStatus() error { + templateVersion, err := b.getTemplateVersion() + if err != nil { + return BuildError{http.StatusInternalServerError, "failed to fetch template version", err} + } + + templateVersionJob, err := b.getTemplateVersionJob() + if err != nil { + return BuildError{ + http.StatusInternalServerError, "failed to fetch template version job", err, + } + } + + templateVersionJobStatus := conversion.ProvisionerJobStatus(*templateVersionJob) + switch templateVersionJobStatus { + case codersdk.ProvisionerJobPending, codersdk.ProvisionerJobRunning: + return BuildError{ + http.StatusNotAcceptable, + fmt.Sprintf("The provided template version is %s. Wait for it to complete importing!", templateVersionJobStatus), + xerrors.New(""), + } + case codersdk.ProvisionerJobFailed: + return BuildError{ + http.StatusBadRequest, + fmt.Sprintf("The provided template version %q has failed to import: %q. You cannot build workspaces with it!", templateVersion.Name, templateVersionJob.Error.String), + xerrors.New(""), + } + case codersdk.ProvisionerJobCanceled: + return BuildError{ + http.StatusBadRequest, + "The provided template version was canceled during import. You cannot build workspaces with it!", + xerrors.New(""), + } + } + return nil +} + +func (b *Builder) checkRunningBuild() error { + job, err := b.getLastBuildJob() + if xerrors.Is(err, sql.ErrNoRows) { + // no prior build, so it can't be running! + return nil + } + if err != nil { + return BuildError{http.StatusInternalServerError, "failed to fetch prior build", err} + } + if conversion.ProvisionerJobStatus(*job).Active() { + return BuildError{ + http.StatusConflict, + "A workspace build is already active.", + xerrors.New(""), + } + } + return nil +} diff --git a/codersdk/parameters.go b/codersdk/parameters.go index c46a24f478989..e341d6c257964 100644 --- a/codersdk/parameters.go +++ b/codersdk/parameters.go @@ -43,7 +43,6 @@ const ( type ComputedParameter struct { Parameter - SourceValue string `json:"source_value"` SchemaID uuid.UUID `json:"schema_id" format:"uuid"` DefaultSourceValue bool `json:"default_source_value"` } @@ -60,6 +59,7 @@ type Parameter struct { DestinationScheme ParameterDestinationScheme `json:"destination_scheme" table:"destination scheme" validate:"ne=none" enums:"none,environment_variable,provisioner_variable"` CreatedAt time.Time `json:"created_at" table:"created at" format:"date-time"` UpdatedAt time.Time `json:"updated_at" table:"updated at" format:"date-time"` + SourceValue string `json:"source_value"` } type ParameterSchema struct { diff --git a/codersdk/richparameters.go b/codersdk/richparameters.go index b40ecaba112a3..fa1a905bd2d31 100644 --- a/codersdk/richparameters.go +++ b/codersdk/richparameters.go @@ -116,3 +116,63 @@ func validationEnabled(param TemplateVersionParameter) bool { param.Type == "bool" || // boolean type doesn't have any custom validation rules, but the value must be checked (true/false). param.Type == "list(string)" // list(string) type doesn't have special validation, but we need to check if this is a correct list. } + +// ParameterResolver should be populated with legacy workload and rich parameter values from the previous build. It then +// supports queries against a current TemplateVersionParameter to determine whether a new value is required, or a value +// correctly validates. +type ParameterResolver struct { + Legacy []Parameter + Rich []WorkspaceBuildParameter +} + +// ValidateResolve checks the provided value, v, against the parameter, p, and the previous build. If v is nil, it also +// resolves the correct value. It returns the value of the parameter, if valid, and an error if invalid. +func (r *ParameterResolver) ValidateResolve(p TemplateVersionParameter, v *WorkspaceBuildParameter) (value string, err error) { + prevV := r.findLastValue(p) + if !p.Mutable && v != nil && prevV != nil { + return "", xerrors.Errorf("Parameter %q is not mutable, so it can't be updated after creating a workspace.", p.Name) + } + if p.Required && v == nil && prevV == nil { + return "", xerrors.Errorf("Parameter %q is required but not provided", p.Name) + } + // First, the provided value + resolvedValue := v + // Second, previous value + if resolvedValue == nil { + resolvedValue = prevV + } + // Last, default value + if resolvedValue == nil { + resolvedValue = &WorkspaceBuildParameter{ + Name: p.Name, + Value: p.DefaultValue, + } + } + err = ValidateWorkspaceBuildParameter(p, resolvedValue, prevV) + if err != nil { + return "", err + } + return resolvedValue.Value, nil +} + +// findLastValue finds the value from the previous build and returns it, or nil if the parameter had no value in the +// last build. +func (r *ParameterResolver) findLastValue(p TemplateVersionParameter) *WorkspaceBuildParameter { + for _, rp := range r.Rich { + if rp.Name == p.Name { + return &rp + } + } + // For migration purposes, we also support using a legacy variable + if p.LegacyVariableName != "" { + for _, lp := range r.Legacy { + if lp.Name == p.LegacyVariableName { + return &WorkspaceBuildParameter{ + Name: p.Name, + Value: lp.SourceValue, + } + } + } + } + return nil +} From bd2811f85e9989d4c6242f52c971c39107198a65 Mon Sep 17 00:00:00 2001 From: Spike Curtis Date: Tue, 16 May 2023 07:03:41 +0000 Subject: [PATCH 02/10] make gen Signed-off-by: Spike Curtis --- coderd/apidoc/docs.go | 3 +++ coderd/apidoc/swagger.json | 3 +++ docs/api/parameters.md | 3 +++ docs/api/schemas.md | 2 ++ site/src/api/typesGenerated.ts | 8 +++++++- 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 424ebfbab8b40..a0f81be25282c 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -8049,6 +8049,9 @@ const docTemplate = `{ } ] }, + "source_value": { + "type": "string" + }, "updated_at": { "type": "string", "format": "date-time" diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 89d3226f68eeb..e90df6f3f4d8c 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -7195,6 +7195,9 @@ } ] }, + "source_value": { + "type": "string" + }, "updated_at": { "type": "string", "format": "date-time" diff --git a/docs/api/parameters.md b/docs/api/parameters.md index 09a0eb3653913..6a7292a664f9e 100644 --- a/docs/api/parameters.md +++ b/docs/api/parameters.md @@ -42,6 +42,7 @@ curl -X GET http://coder-server:8080/api/v2/parameters/{scope}/{id} \ "scope": "template", "scope_id": "5d3fe357-12dd-4f62-b004-6d1fb3b8454f", "source_scheme": "none", + "source_value": "string", "updated_at": "2019-08-24T14:15:22Z" } ] @@ -67,6 +68,7 @@ Status Code **200** | `» scope` | [codersdk.ParameterScope](schemas.md#codersdkparameterscope) | false | | | | `» scope_id` | string(uuid) | false | | | | `» source_scheme` | [codersdk.ParameterSourceScheme](schemas.md#codersdkparametersourcescheme) | false | | | +| `» source_value` | string | false | | | | `» updated_at` | string(date-time) | false | | | #### Enumerated Values @@ -139,6 +141,7 @@ curl -X POST http://coder-server:8080/api/v2/parameters/{scope}/{id} \ "scope": "template", "scope_id": "5d3fe357-12dd-4f62-b004-6d1fb3b8454f", "source_scheme": "none", + "source_value": "string", "updated_at": "2019-08-24T14:15:22Z" } ``` diff --git a/docs/api/schemas.md b/docs/api/schemas.md index cb66df84adcb5..c1e233edb5ff1 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -3063,6 +3063,7 @@ CreateParameterRequest is a structure used to create a new parameter value for a "scope": "template", "scope_id": "5d3fe357-12dd-4f62-b004-6d1fb3b8454f", "source_scheme": "none", + "source_value": "string", "updated_at": "2019-08-24T14:15:22Z" } ``` @@ -3080,6 +3081,7 @@ Parameter represents a set value for the scope. | `scope` | [codersdk.ParameterScope](#codersdkparameterscope) | false | | | | `scope_id` | string | false | | | | `source_scheme` | [codersdk.ParameterSourceScheme](#codersdkparametersourcescheme) | false | | | +| `source_value` | string | false | | | | `updated_at` | string | false | | | #### Enumerated Values diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index d8ef384a4c406..3f11198874717 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -141,7 +141,6 @@ export interface BuildInfoResponse { // From codersdk/parameters.go export interface ComputedParameter extends Parameter { - readonly source_value: string readonly schema_id: string readonly default_source_value: boolean } @@ -589,6 +588,13 @@ export interface Parameter { readonly destination_scheme: ParameterDestinationScheme readonly created_at: string readonly updated_at: string + readonly source_value: string +} + +// From codersdk/richparameters.go +export interface ParameterResolver { + readonly Legacy: Parameter[] + readonly Rich: WorkspaceBuildParameter[] } // From codersdk/parameters.go From c892e4320faa552be8c5cf322afb786efbb81cce Mon Sep 17 00:00:00 2001 From: Spike Curtis Date: Tue, 16 May 2023 16:53:30 +0000 Subject: [PATCH 03/10] Remove ParameterResolver from typescript Signed-off-by: Spike Curtis --- codersdk/richparameters.go | 1 + site/src/api/typesGenerated.ts | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/codersdk/richparameters.go b/codersdk/richparameters.go index fa1a905bd2d31..4bf3d24edca6c 100644 --- a/codersdk/richparameters.go +++ b/codersdk/richparameters.go @@ -120,6 +120,7 @@ func validationEnabled(param TemplateVersionParameter) bool { // ParameterResolver should be populated with legacy workload and rich parameter values from the previous build. It then // supports queries against a current TemplateVersionParameter to determine whether a new value is required, or a value // correctly validates. +// @typescript-ignore ParameterResolver type ParameterResolver struct { Legacy []Parameter Rich []WorkspaceBuildParameter diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 3f11198874717..948f320febaa9 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -591,12 +591,6 @@ export interface Parameter { readonly source_value: string } -// From codersdk/richparameters.go -export interface ParameterResolver { - readonly Legacy: Parameter[] - readonly Rich: WorkspaceBuildParameter[] -} - // From codersdk/parameters.go export interface ParameterSchema { readonly id: string From 25aec4f7e8b84ddb6671716fa7c1588ab977c9c4 Mon Sep 17 00:00:00 2001 From: Spike Curtis Date: Tue, 16 May 2023 17:31:10 +0000 Subject: [PATCH 04/10] rename conversion -> database/db2sdk Signed-off-by: Spike Curtis --- coderd/conversion/doc.go | 2 -- coderd/conversion/provisionerjob.go | 33 ------------------- .../db2sdk/db2sdk.go} | 29 +++++++++++++++- coderd/prometheusmetrics/prometheusmetrics.go | 4 +-- coderd/provisionerjobs.go | 4 +-- coderd/workspacebuilds.go | 4 +-- coderd/wsbuilder/wsbuilder.go | 12 +++---- 7 files changed, 40 insertions(+), 48 deletions(-) delete mode 100644 coderd/conversion/doc.go delete mode 100644 coderd/conversion/provisionerjob.go rename coderd/{conversion/parameters.go => database/db2sdk/db2sdk.go} (75%) diff --git a/coderd/conversion/doc.go b/coderd/conversion/doc.go deleted file mode 100644 index 3eaaaec79c01f..0000000000000 --- a/coderd/conversion/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package conversion provides common conversion routines from database types to codersdk types -package conversion diff --git a/coderd/conversion/provisionerjob.go b/coderd/conversion/provisionerjob.go deleted file mode 100644 index 684f4afe0cd7a..0000000000000 --- a/coderd/conversion/provisionerjob.go +++ /dev/null @@ -1,33 +0,0 @@ -package conversion - -import ( - "time" - - "github.com/coder/coder/coderd/database" - "github.com/coder/coder/codersdk" -) - -func ProvisionerJobStatus(provisionerJob database.ProvisionerJob) codersdk.ProvisionerJobStatus { - switch { - case provisionerJob.CanceledAt.Valid: - if !provisionerJob.CompletedAt.Valid { - return codersdk.ProvisionerJobCanceling - } - if provisionerJob.Error.String == "" { - return codersdk.ProvisionerJobCanceled - } - return codersdk.ProvisionerJobFailed - case !provisionerJob.StartedAt.Valid: - return codersdk.ProvisionerJobPending - case provisionerJob.CompletedAt.Valid: - if provisionerJob.Error.String == "" { - return codersdk.ProvisionerJobSucceeded - } - return codersdk.ProvisionerJobFailed - case database.Now().Sub(provisionerJob.UpdatedAt) > 30*time.Second: - provisionerJob.Error.String = "Worker failed to update job in time." - return codersdk.ProvisionerJobFailed - default: - return codersdk.ProvisionerJobRunning - } -} diff --git a/coderd/conversion/parameters.go b/coderd/database/db2sdk/db2sdk.go similarity index 75% rename from coderd/conversion/parameters.go rename to coderd/database/db2sdk/db2sdk.go index 594aa36b0fcbe..a2621d954d470 100644 --- a/coderd/conversion/parameters.go +++ b/coderd/database/db2sdk/db2sdk.go @@ -1,7 +1,9 @@ -package conversion +// Package db2sdk provides common conversion routines from database types to codersdk types +package db2sdk import ( "encoding/json" + "time" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/parameter" @@ -85,3 +87,28 @@ func Parameter(parameterValue database.ParameterValue) codersdk.Parameter { SourceValue: parameterValue.SourceValue, } } + +func ProvisionerJobStatus(provisionerJob database.ProvisionerJob) codersdk.ProvisionerJobStatus { + switch { + case provisionerJob.CanceledAt.Valid: + if !provisionerJob.CompletedAt.Valid { + return codersdk.ProvisionerJobCanceling + } + if provisionerJob.Error.String == "" { + return codersdk.ProvisionerJobCanceled + } + return codersdk.ProvisionerJobFailed + case !provisionerJob.StartedAt.Valid: + return codersdk.ProvisionerJobPending + case provisionerJob.CompletedAt.Valid: + if provisionerJob.Error.String == "" { + return codersdk.ProvisionerJobSucceeded + } + return codersdk.ProvisionerJobFailed + case database.Now().Sub(provisionerJob.UpdatedAt) > 30*time.Second: + provisionerJob.Error.String = "Worker failed to update job in time." + return codersdk.ProvisionerJobFailed + default: + return codersdk.ProvisionerJobRunning + } +} diff --git a/coderd/prometheusmetrics/prometheusmetrics.go b/coderd/prometheusmetrics/prometheusmetrics.go index ab4bd087d1e12..01e888e14b514 100644 --- a/coderd/prometheusmetrics/prometheusmetrics.go +++ b/coderd/prometheusmetrics/prometheusmetrics.go @@ -16,8 +16,8 @@ import ( "cdr.dev/slog" - "github.com/coder/coder/coderd/conversion" "github.com/coder/coder/coderd/database" + "github.com/coder/coder/coderd/database/db2sdk" "github.com/coder/coder/coderd/database/dbauthz" "github.com/coder/coder/tailnet" ) @@ -124,7 +124,7 @@ func Workspaces(ctx context.Context, registerer prometheus.Registerer, db databa gauge.Reset() for _, job := range jobs { - status := conversion.ProvisionerJobStatus(job) + status := db2sdk.ProvisionerJobStatus(job) gauge.WithLabelValues(string(status)).Add(1) } } diff --git a/coderd/provisionerjobs.go b/coderd/provisionerjobs.go index 70172010c275a..f92686c0dbf6d 100644 --- a/coderd/provisionerjobs.go +++ b/coderd/provisionerjobs.go @@ -15,8 +15,8 @@ import ( "nhooyr.io/websocket" "cdr.dev/slog" - "github.com/coder/coder/coderd/conversion" "github.com/coder/coder/coderd/database" + "github.com/coder/coder/coderd/database/db2sdk" "github.com/coder/coder/coderd/database/dbauthz" "github.com/coder/coder/coderd/httpapi" "github.com/coder/coder/coderd/rbac" @@ -329,7 +329,7 @@ func convertProvisionerJob(provisionerJob database.ProvisionerJob) codersdk.Prov if provisionerJob.WorkerID.Valid { job.WorkerID = &provisionerJob.WorkerID.UUID } - job.Status = conversion.ProvisionerJobStatus(provisionerJob) + job.Status = db2sdk.ProvisionerJobStatus(provisionerJob) return job } diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index 8718e68276c99..0cd0e10c4fbf8 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -14,8 +14,8 @@ import ( "golang.org/x/exp/slices" "golang.org/x/xerrors" - "github.com/coder/coder/coderd/conversion" "github.com/coder/coder/coderd/database" + "github.com/coder/coder/coderd/database/db2sdk" "github.com/coder/coder/coderd/database/dbauthz" "github.com/coder/coder/coderd/httpapi" "github.com/coder/coder/coderd/httpmw" @@ -540,7 +540,7 @@ func (api *API) workspaceBuildParameters(rw http.ResponseWriter, r *http.Request }) return } - apiParameters := conversion.WorkspaceBuildParameters(parameters) + apiParameters := db2sdk.WorkspaceBuildParameters(parameters) httpapi.Write(ctx, rw, http.StatusOK, apiParameters) } diff --git a/coderd/wsbuilder/wsbuilder.go b/coderd/wsbuilder/wsbuilder.go index 4c4669ee7d5a8..796a72462dae7 100644 --- a/coderd/wsbuilder/wsbuilder.go +++ b/coderd/wsbuilder/wsbuilder.go @@ -14,8 +14,8 @@ import ( "github.com/tabbed/pqtype" "golang.org/x/xerrors" - "github.com/coder/coder/coderd/conversion" "github.com/coder/coder/coderd/database" + "github.com/coder/coder/coderd/database/db2sdk" "github.com/coder/coder/coderd/httpapi" "github.com/coder/coder/coderd/provisionerdserver" "github.com/coder/coder/coderd/rbac" @@ -518,11 +518,11 @@ func (b *Builder) getParameters() (names, values []string, err error) { return nil, nil, BuildError{http.StatusInternalServerError, "failed to fetch last parameter values", err} } resolver := codersdk.ParameterResolver{ - Rich: conversion.WorkspaceBuildParameters(lastBuildParameters), - Legacy: conversion.Parameters(lastParameterValues), + Rich: db2sdk.WorkspaceBuildParameters(lastBuildParameters), + Legacy: db2sdk.Parameters(lastParameterValues), } for _, templateVersionParameter := range templateVersionParameters { - tvp, err := conversion.TemplateVersionParameter(templateVersionParameter) + tvp, err := db2sdk.TemplateVersionParameter(templateVersionParameter) if err != nil { return nil, nil, BuildError{http.StatusInternalServerError, "failed to convert template version parameter", err} } @@ -697,7 +697,7 @@ func (b *Builder) checkTemplateJobStatus() error { } } - templateVersionJobStatus := conversion.ProvisionerJobStatus(*templateVersionJob) + templateVersionJobStatus := db2sdk.ProvisionerJobStatus(*templateVersionJob) switch templateVersionJobStatus { case codersdk.ProvisionerJobPending, codersdk.ProvisionerJobRunning: return BuildError{ @@ -730,7 +730,7 @@ func (b *Builder) checkRunningBuild() error { if err != nil { return BuildError{http.StatusInternalServerError, "failed to fetch prior build", err} } - if conversion.ProvisionerJobStatus(*job).Active() { + if db2sdk.ProvisionerJobStatus(*job).Active() { return BuildError{ http.StatusConflict, "A workspace build is already active.", From 6d69277be7734a89a232db8126c1fb6f895d4d89 Mon Sep 17 00:00:00 2001 From: Spike Curtis Date: Wed, 17 May 2023 06:28:20 +0000 Subject: [PATCH 05/10] tests for db2sdk Signed-off-by: Spike Curtis --- coderd/database/db2sdk/db2sdk.go | 1 - coderd/database/db2sdk/db2sdk_test.go | 191 ++++++++++++++++++++++++++ 2 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 coderd/database/db2sdk/db2sdk_test.go diff --git a/coderd/database/db2sdk/db2sdk.go b/coderd/database/db2sdk/db2sdk.go index a2621d954d470..079b0689c40b2 100644 --- a/coderd/database/db2sdk/db2sdk.go +++ b/coderd/database/db2sdk/db2sdk.go @@ -106,7 +106,6 @@ func ProvisionerJobStatus(provisionerJob database.ProvisionerJob) codersdk.Provi } return codersdk.ProvisionerJobFailed case database.Now().Sub(provisionerJob.UpdatedAt) > 30*time.Second: - provisionerJob.Error.String = "Worker failed to update job in time." return codersdk.ProvisionerJobFailed default: return codersdk.ProvisionerJobRunning diff --git a/coderd/database/db2sdk/db2sdk_test.go b/coderd/database/db2sdk/db2sdk_test.go new file mode 100644 index 0000000000000..cb8a7d28345ae --- /dev/null +++ b/coderd/database/db2sdk/db2sdk_test.go @@ -0,0 +1,191 @@ +package db2sdk_test + +import ( + "crypto/rand" + "database/sql" + "encoding/json" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/coder/coder/coderd/database" + "github.com/coder/coder/coderd/database/db2sdk" + "github.com/coder/coder/codersdk" + "github.com/coder/coder/provisionersdk/proto" +) + +func TestProvisionerJobStatus(t *testing.T) { + t.Parallel() + + cases := []struct { + name string + job database.ProvisionerJob + status codersdk.ProvisionerJobStatus + }{ + { + name: "canceling", + job: database.ProvisionerJob{ + CanceledAt: sql.NullTime{ + Time: database.Now().Add(-time.Minute), + Valid: true, + }, + }, + status: codersdk.ProvisionerJobCanceling, + }, + { + name: "canceled", + job: database.ProvisionerJob{ + CanceledAt: sql.NullTime{ + Time: database.Now().Add(-time.Minute), + Valid: true, + }, + CompletedAt: sql.NullTime{ + Time: database.Now().Add(-30 * time.Second), + Valid: true, + }, + }, + status: codersdk.ProvisionerJobCanceled, + }, + { + name: "canceled_failed", + job: database.ProvisionerJob{ + CanceledAt: sql.NullTime{ + Time: database.Now().Add(-time.Minute), + Valid: true, + }, + CompletedAt: sql.NullTime{ + Time: database.Now().Add(-30 * time.Second), + Valid: true, + }, + Error: sql.NullString{String: "badness", Valid: true}, + }, + status: codersdk.ProvisionerJobFailed, + }, + { + name: "pending", + job: database.ProvisionerJob{}, + status: codersdk.ProvisionerJobPending, + }, + { + name: "succeeded", + job: database.ProvisionerJob{ + StartedAt: sql.NullTime{ + Time: database.Now().Add(-time.Minute), + Valid: true, + }, + CompletedAt: sql.NullTime{ + Time: database.Now().Add(-30 * time.Second), + Valid: true, + }, + }, + status: codersdk.ProvisionerJobSucceeded, + }, + { + name: "completed_failed", + job: database.ProvisionerJob{ + StartedAt: sql.NullTime{ + Time: database.Now().Add(-time.Minute), + Valid: true, + }, + CompletedAt: sql.NullTime{ + Time: database.Now().Add(-30 * time.Second), + Valid: true, + }, + Error: sql.NullString{String: "badness", Valid: true}, + }, + status: codersdk.ProvisionerJobFailed, + }, + { + name: "not_updated", + job: database.ProvisionerJob{ + StartedAt: sql.NullTime{ + Time: database.Now().Add(-time.Minute), + Valid: true, + }, + UpdatedAt: database.Now().Add(-31 * time.Second), + }, + status: codersdk.ProvisionerJobFailed, + }, + { + name: "updated", + job: database.ProvisionerJob{ + StartedAt: sql.NullTime{ + Time: database.Now().Add(-time.Minute), + Valid: true, + }, + UpdatedAt: database.Now(), + }, + status: codersdk.ProvisionerJobRunning, + }, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + actual := db2sdk.ProvisionerJobStatus(tc.job) + require.Equal(t, tc.status, actual) + }) + } +} + +func TestTemplateVersionParameter_OK(t *testing.T) { + t.Parallel() + req := require.New(t) + + // In this test we're just going to cover the fields that have to get parsed. + options := []*proto.RichParameterOption{ + { + Name: "foo", + Description: "bar", + Value: "baz", + Icon: "David Bowie", + }, + } + ob, err := json.Marshal(&options) + req.NoError(err) + + db := database.TemplateVersionParameter{ + Options: json.RawMessage(ob), + Description: "_The Rise and Fall of **Ziggy Stardust** and the Spiders from Mars_", + } + sdk, err := db2sdk.TemplateVersionParameter(db) + req.NoError(err) + req.Len(sdk.Options, 1) + req.Equal("foo", sdk.Options[0].Name) + req.Equal("bar", sdk.Options[0].Description) + req.Equal("baz", sdk.Options[0].Value) + req.Equal("David Bowie", sdk.Options[0].Icon) + req.Equal("The Rise and Fall of Ziggy Stardust and the Spiders from Mars", sdk.DescriptionPlaintext) +} + +func TestTemplateVersionParameter_BadOptions(t *testing.T) { + t.Parallel() + req := require.New(t) + + db := database.TemplateVersionParameter{ + Options: json.RawMessage("not really JSON!"), + Description: "_The Rise and Fall of **Ziggy Stardust** and the Spiders from Mars_", + } + _, err := db2sdk.TemplateVersionParameter(db) + req.Error(err) +} + +func TestTemplateVersionParameter_BadDescription(t *testing.T) { + t.Parallel() + req := require.New(t) + desc := make([]byte, 300) + _, err := rand.Read(desc) + req.NoError(err) + + db := database.TemplateVersionParameter{ + Options: json.RawMessage("[]"), + Description: string(desc), + } + sdk, err := db2sdk.TemplateVersionParameter(db) + // Although the markdown parser can return an error, the way we use it should not, even + // if we feed it garbage data. + req.NoError(err) + req.NotEmpty(sdk.DescriptionPlaintext, "broke the markdown parser with %v", desc) +} From 817c28ee2491ec4c19dcb6c72428c885b4d66697 Mon Sep 17 00:00:00 2001 From: Spike Curtis Date: Wed, 17 May 2023 10:50:52 +0000 Subject: [PATCH 06/10] Tests for ParameterResolver Signed-off-by: Spike Curtis --- codersdk/richparameters_test.go | 174 ++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 codersdk/richparameters_test.go diff --git a/codersdk/richparameters_test.go b/codersdk/richparameters_test.go new file mode 100644 index 0000000000000..77befcc3347f5 --- /dev/null +++ b/codersdk/richparameters_test.go @@ -0,0 +1,174 @@ +package codersdk_test + +import ( + "github.com/coder/coder/codersdk" + "github.com/stretchr/testify/require" + "testing" +) + +func TestParameterResolver_ValidateResolve_New(t *testing.T) { + t.Parallel() + uut := codersdk.ParameterResolver{} + p := codersdk.TemplateVersionParameter{ + Name: "n", + Type: "number", + } + v, err := uut.ValidateResolve(p, &codersdk.WorkspaceBuildParameter{ + Name: "n", + Value: "1", + }) + require.NoError(t, err) + require.Equal(t, "1", v) +} + +func TestParameterResolver_ValidateResolve_Default(t *testing.T) { + t.Parallel() + uut := codersdk.ParameterResolver{} + p := codersdk.TemplateVersionParameter{ + Name: "n", + Type: "number", + DefaultValue: "5", + } + v, err := uut.ValidateResolve(p, nil) + require.NoError(t, err) + require.Equal(t, "5", v) +} + +func TestParameterResolver_ValidateResolve_MissingRequired(t *testing.T) { + t.Parallel() + uut := codersdk.ParameterResolver{} + p := codersdk.TemplateVersionParameter{ + Name: "n", + Type: "number", + Required: true, + } + v, err := uut.ValidateResolve(p, nil) + require.Error(t, err) + require.Equal(t, "", v) +} + +func TestParameterResolver_ValidateResolve_PrevRequired(t *testing.T) { + t.Parallel() + uut := codersdk.ParameterResolver{ + Rich: []codersdk.WorkspaceBuildParameter{{Name: "n", Value: "5"}}, + } + p := codersdk.TemplateVersionParameter{ + Name: "n", + Type: "number", + Required: true, + } + v, err := uut.ValidateResolve(p, nil) + require.NoError(t, err) + require.Equal(t, "5", v) +} + +func TestParameterResolver_ValidateResolve_PrevInvalid(t *testing.T) { + t.Parallel() + uut := codersdk.ParameterResolver{ + Rich: []codersdk.WorkspaceBuildParameter{{Name: "n", Value: "11"}}, + } + p := codersdk.TemplateVersionParameter{ + Name: "n", + Type: "number", + ValidationMax: 10, + ValidationMin: 1, + } + v, err := uut.ValidateResolve(p, nil) + require.Error(t, err) + require.Equal(t, "", v) +} + +func TestParameterResolver_ValidateResolve_DefaultInvalid(t *testing.T) { + // this one arises from an error on the template itself, where the default + // value doesn't pass validation. But, it's good to catch early and error out + // rather than send invalid data to the provisioner + t.Parallel() + uut := codersdk.ParameterResolver{} + p := codersdk.TemplateVersionParameter{ + Name: "n", + Type: "number", + ValidationMax: 10, + ValidationMin: 1, + DefaultValue: "11", + } + v, err := uut.ValidateResolve(p, nil) + require.Error(t, err) + require.Equal(t, "", v) +} + +func TestParameterResolver_ValidateResolve_NewOverridesOld(t *testing.T) { + t.Parallel() + uut := codersdk.ParameterResolver{ + Rich: []codersdk.WorkspaceBuildParameter{{Name: "n", Value: "5"}}, + } + p := codersdk.TemplateVersionParameter{ + Name: "n", + Type: "number", + Required: true, + Mutable: true, + } + v, err := uut.ValidateResolve(p, &codersdk.WorkspaceBuildParameter{ + Name: "n", + Value: "6", + }) + require.NoError(t, err) + require.Equal(t, "6", v) +} + +func TestParameterResolver_ValidateResolve_Immutable(t *testing.T) { + t.Parallel() + uut := codersdk.ParameterResolver{ + Rich: []codersdk.WorkspaceBuildParameter{{Name: "n", Value: "5"}}, + } + p := codersdk.TemplateVersionParameter{ + Name: "n", + Type: "number", + Required: true, + Mutable: false, + } + v, err := uut.ValidateResolve(p, &codersdk.WorkspaceBuildParameter{ + Name: "n", + Value: "6", + }) + require.Error(t, err) + require.Equal(t, "", v) +} + +func TestParameterResolver_ValidateResolve_Legacy(t *testing.T) { + t.Parallel() + uut := codersdk.ParameterResolver{ + Legacy: []codersdk.Parameter{ + {Name: "l", SourceValue: "5"}, + {Name: "n", SourceValue: "6"}, + }, + } + p := codersdk.TemplateVersionParameter{ + Name: "n", + Type: "number", + Required: true, + LegacyVariableName: "l", + } + v, err := uut.ValidateResolve(p, nil) + require.NoError(t, err) + require.Equal(t, "5", v) +} + +func TestParameterResolver_ValidateResolve_PreferRichOverLegacy(t *testing.T) { + t.Parallel() + uut := codersdk.ParameterResolver{ + Rich: []codersdk.WorkspaceBuildParameter{{Name: "n", Value: "7"}}, + Legacy: []codersdk.Parameter{ + {Name: "l", SourceValue: "5"}, + {Name: "n", SourceValue: "6"}, + }, + } + p := codersdk.TemplateVersionParameter{ + Name: "n", + Type: "number", + Required: true, + LegacyVariableName: "l", + } + v, err := uut.ValidateResolve(p, nil) + require.NoError(t, err) + require.Equal(t, "7", v) +} From cee21de97619eddc5eb7efba5dfb7915fd9d0800 Mon Sep 17 00:00:00 2001 From: Spike Curtis Date: Thu, 18 May 2023 11:55:14 +0000 Subject: [PATCH 07/10] wsbuilder tests Signed-off-by: Spike Curtis --- Makefile | 6 + coderd/database/mock/doc.go | 4 + coderd/database/mock/store.go | 3235 ++++++++++++++++++++++++++++ coderd/workspacebuilds_test.go | 355 --- coderd/wsbuilder/wsbuilder.go | 58 +- coderd/wsbuilder/wsbuilder_test.go | 839 ++++++++ dogfood/Dockerfile | 3 +- go.mod | 1 + go.sum | 1 + 9 files changed, 4129 insertions(+), 373 deletions(-) create mode 100644 coderd/database/mock/doc.go create mode 100644 coderd/database/mock/store.go create mode 100644 coderd/wsbuilder/wsbuilder_test.go diff --git a/Makefile b/Makefile index 16f02d9a99c1f..b33c728ffa229 100644 --- a/Makefile +++ b/Makefile @@ -420,6 +420,7 @@ lint/shellcheck: $(SHELL_SRC_FILES) gen: \ coderd/database/dump.sql \ coderd/database/querier.go \ + coderd/database/mock/store.go \ provisionersdk/proto/provisioner.pb.go \ provisionerd/proto/provisionerd.pb.go \ site/src/api/typesGenerated.ts \ @@ -441,6 +442,7 @@ gen/mark-fresh: files="\ coderd/database/dump.sql \ coderd/database/querier.go \ + coderd/database/mock/store.go \ provisionersdk/proto/provisioner.pb.go \ provisionerd/proto/provisionerd.pb.go \ site/src/api/typesGenerated.ts \ @@ -476,6 +478,10 @@ coderd/database/dump.sql: coderd/database/gen/dump/main.go $(wildcard coderd/dat coderd/database/querier.go: coderd/database/sqlc.yaml coderd/database/dump.sql $(wildcard coderd/database/queries/*.sql) coderd/database/gen/enum/main.go ./coderd/database/generate.sh + +coderd/database/mock/store.go: coderd/database/db.go coderd/database/querier.go + go generate ./coderd/database/mock/ + provisionersdk/proto/provisioner.pb.go: provisionersdk/proto/provisioner.proto protoc \ --go_out=. \ diff --git a/coderd/database/mock/doc.go b/coderd/database/mock/doc.go new file mode 100644 index 0000000000000..749f9f23cecb1 --- /dev/null +++ b/coderd/database/mock/doc.go @@ -0,0 +1,4 @@ +// package mock contains a mocked implementation of the database.Store interface for use in tests +package mock + +//go:generate mockgen -destination ./store.go -package mock github.com/coder/coder/coderd/database Store diff --git a/coderd/database/mock/store.go b/coderd/database/mock/store.go new file mode 100644 index 0000000000000..a0c1c180740d6 --- /dev/null +++ b/coderd/database/mock/store.go @@ -0,0 +1,3235 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/coder/coder/coderd/database (interfaces: Store) + +// Package mock is a generated GoMock package. +package mock + +import ( + context "context" + sql "database/sql" + reflect "reflect" + time "time" + + database "github.com/coder/coder/coderd/database" + rbac "github.com/coder/coder/coderd/rbac" + gomock "github.com/golang/mock/gomock" + uuid "github.com/google/uuid" +) + +// MockStore is a mock of Store interface. +type MockStore struct { + ctrl *gomock.Controller + recorder *MockStoreMockRecorder +} + +// MockStoreMockRecorder is the mock recorder for MockStore. +type MockStoreMockRecorder struct { + mock *MockStore +} + +// NewMockStore creates a new mock instance. +func NewMockStore(ctrl *gomock.Controller) *MockStore { + mock := &MockStore{ctrl: ctrl} + mock.recorder = &MockStoreMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockStore) EXPECT() *MockStoreMockRecorder { + return m.recorder +} + +// AcquireLock mocks base method. +func (m *MockStore) AcquireLock(arg0 context.Context, arg1 int64) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AcquireLock", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// AcquireLock indicates an expected call of AcquireLock. +func (mr *MockStoreMockRecorder) AcquireLock(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcquireLock", reflect.TypeOf((*MockStore)(nil).AcquireLock), arg0, arg1) +} + +// AcquireProvisionerJob mocks base method. +func (m *MockStore) AcquireProvisionerJob(arg0 context.Context, arg1 database.AcquireProvisionerJobParams) (database.ProvisionerJob, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AcquireProvisionerJob", arg0, arg1) + ret0, _ := ret[0].(database.ProvisionerJob) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AcquireProvisionerJob indicates an expected call of AcquireProvisionerJob. +func (mr *MockStoreMockRecorder) AcquireProvisionerJob(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcquireProvisionerJob", reflect.TypeOf((*MockStore)(nil).AcquireProvisionerJob), arg0, arg1) +} + +// DeleteAPIKeyByID mocks base method. +func (m *MockStore) DeleteAPIKeyByID(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteAPIKeyByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteAPIKeyByID indicates an expected call of DeleteAPIKeyByID. +func (mr *MockStoreMockRecorder) DeleteAPIKeyByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAPIKeyByID", reflect.TypeOf((*MockStore)(nil).DeleteAPIKeyByID), arg0, arg1) +} + +// DeleteAPIKeysByUserID mocks base method. +func (m *MockStore) DeleteAPIKeysByUserID(arg0 context.Context, arg1 uuid.UUID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteAPIKeysByUserID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteAPIKeysByUserID indicates an expected call of DeleteAPIKeysByUserID. +func (mr *MockStoreMockRecorder) DeleteAPIKeysByUserID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAPIKeysByUserID", reflect.TypeOf((*MockStore)(nil).DeleteAPIKeysByUserID), arg0, arg1) +} + +// DeleteApplicationConnectAPIKeysByUserID mocks base method. +func (m *MockStore) DeleteApplicationConnectAPIKeysByUserID(arg0 context.Context, arg1 uuid.UUID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteApplicationConnectAPIKeysByUserID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteApplicationConnectAPIKeysByUserID indicates an expected call of DeleteApplicationConnectAPIKeysByUserID. +func (mr *MockStoreMockRecorder) DeleteApplicationConnectAPIKeysByUserID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteApplicationConnectAPIKeysByUserID", reflect.TypeOf((*MockStore)(nil).DeleteApplicationConnectAPIKeysByUserID), arg0, arg1) +} + +// DeleteGitSSHKey mocks base method. +func (m *MockStore) DeleteGitSSHKey(arg0 context.Context, arg1 uuid.UUID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteGitSSHKey", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteGitSSHKey indicates an expected call of DeleteGitSSHKey. +func (mr *MockStoreMockRecorder) DeleteGitSSHKey(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteGitSSHKey", reflect.TypeOf((*MockStore)(nil).DeleteGitSSHKey), arg0, arg1) +} + +// DeleteGroupByID mocks base method. +func (m *MockStore) DeleteGroupByID(arg0 context.Context, arg1 uuid.UUID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteGroupByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteGroupByID indicates an expected call of DeleteGroupByID. +func (mr *MockStoreMockRecorder) DeleteGroupByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteGroupByID", reflect.TypeOf((*MockStore)(nil).DeleteGroupByID), arg0, arg1) +} + +// DeleteGroupMemberFromGroup mocks base method. +func (m *MockStore) DeleteGroupMemberFromGroup(arg0 context.Context, arg1 database.DeleteGroupMemberFromGroupParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteGroupMemberFromGroup", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteGroupMemberFromGroup indicates an expected call of DeleteGroupMemberFromGroup. +func (mr *MockStoreMockRecorder) DeleteGroupMemberFromGroup(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteGroupMemberFromGroup", reflect.TypeOf((*MockStore)(nil).DeleteGroupMemberFromGroup), arg0, arg1) +} + +// DeleteGroupMembersByOrgAndUser mocks base method. +func (m *MockStore) DeleteGroupMembersByOrgAndUser(arg0 context.Context, arg1 database.DeleteGroupMembersByOrgAndUserParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteGroupMembersByOrgAndUser", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteGroupMembersByOrgAndUser indicates an expected call of DeleteGroupMembersByOrgAndUser. +func (mr *MockStoreMockRecorder) DeleteGroupMembersByOrgAndUser(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteGroupMembersByOrgAndUser", reflect.TypeOf((*MockStore)(nil).DeleteGroupMembersByOrgAndUser), arg0, arg1) +} + +// DeleteLicense mocks base method. +func (m *MockStore) DeleteLicense(arg0 context.Context, arg1 int32) (int32, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteLicense", arg0, arg1) + ret0, _ := ret[0].(int32) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteLicense indicates an expected call of DeleteLicense. +func (mr *MockStoreMockRecorder) DeleteLicense(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteLicense", reflect.TypeOf((*MockStore)(nil).DeleteLicense), arg0, arg1) +} + +// DeleteOldWorkspaceAgentStartupLogs mocks base method. +func (m *MockStore) DeleteOldWorkspaceAgentStartupLogs(arg0 context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteOldWorkspaceAgentStartupLogs", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteOldWorkspaceAgentStartupLogs indicates an expected call of DeleteOldWorkspaceAgentStartupLogs. +func (mr *MockStoreMockRecorder) DeleteOldWorkspaceAgentStartupLogs(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOldWorkspaceAgentStartupLogs", reflect.TypeOf((*MockStore)(nil).DeleteOldWorkspaceAgentStartupLogs), arg0) +} + +// DeleteOldWorkspaceAgentStats mocks base method. +func (m *MockStore) DeleteOldWorkspaceAgentStats(arg0 context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteOldWorkspaceAgentStats", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteOldWorkspaceAgentStats indicates an expected call of DeleteOldWorkspaceAgentStats. +func (mr *MockStoreMockRecorder) DeleteOldWorkspaceAgentStats(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOldWorkspaceAgentStats", reflect.TypeOf((*MockStore)(nil).DeleteOldWorkspaceAgentStats), arg0) +} + +// DeleteParameterValueByID mocks base method. +func (m *MockStore) DeleteParameterValueByID(arg0 context.Context, arg1 uuid.UUID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteParameterValueByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteParameterValueByID indicates an expected call of DeleteParameterValueByID. +func (mr *MockStoreMockRecorder) DeleteParameterValueByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteParameterValueByID", reflect.TypeOf((*MockStore)(nil).DeleteParameterValueByID), arg0, arg1) +} + +// DeleteReplicasUpdatedBefore mocks base method. +func (m *MockStore) DeleteReplicasUpdatedBefore(arg0 context.Context, arg1 time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteReplicasUpdatedBefore", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteReplicasUpdatedBefore indicates an expected call of DeleteReplicasUpdatedBefore. +func (mr *MockStoreMockRecorder) DeleteReplicasUpdatedBefore(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteReplicasUpdatedBefore", reflect.TypeOf((*MockStore)(nil).DeleteReplicasUpdatedBefore), arg0, arg1) +} + +// GetAPIKeyByID mocks base method. +func (m *MockStore) GetAPIKeyByID(arg0 context.Context, arg1 string) (database.APIKey, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAPIKeyByID", arg0, arg1) + ret0, _ := ret[0].(database.APIKey) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAPIKeyByID indicates an expected call of GetAPIKeyByID. +func (mr *MockStoreMockRecorder) GetAPIKeyByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAPIKeyByID", reflect.TypeOf((*MockStore)(nil).GetAPIKeyByID), arg0, arg1) +} + +// GetAPIKeyByName mocks base method. +func (m *MockStore) GetAPIKeyByName(arg0 context.Context, arg1 database.GetAPIKeyByNameParams) (database.APIKey, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAPIKeyByName", arg0, arg1) + ret0, _ := ret[0].(database.APIKey) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAPIKeyByName indicates an expected call of GetAPIKeyByName. +func (mr *MockStoreMockRecorder) GetAPIKeyByName(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAPIKeyByName", reflect.TypeOf((*MockStore)(nil).GetAPIKeyByName), arg0, arg1) +} + +// GetAPIKeysByLoginType mocks base method. +func (m *MockStore) GetAPIKeysByLoginType(arg0 context.Context, arg1 database.LoginType) ([]database.APIKey, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAPIKeysByLoginType", arg0, arg1) + ret0, _ := ret[0].([]database.APIKey) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAPIKeysByLoginType indicates an expected call of GetAPIKeysByLoginType. +func (mr *MockStoreMockRecorder) GetAPIKeysByLoginType(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAPIKeysByLoginType", reflect.TypeOf((*MockStore)(nil).GetAPIKeysByLoginType), arg0, arg1) +} + +// GetAPIKeysByUserID mocks base method. +func (m *MockStore) GetAPIKeysByUserID(arg0 context.Context, arg1 database.GetAPIKeysByUserIDParams) ([]database.APIKey, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAPIKeysByUserID", arg0, arg1) + ret0, _ := ret[0].([]database.APIKey) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAPIKeysByUserID indicates an expected call of GetAPIKeysByUserID. +func (mr *MockStoreMockRecorder) GetAPIKeysByUserID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAPIKeysByUserID", reflect.TypeOf((*MockStore)(nil).GetAPIKeysByUserID), arg0, arg1) +} + +// GetAPIKeysLastUsedAfter mocks base method. +func (m *MockStore) GetAPIKeysLastUsedAfter(arg0 context.Context, arg1 time.Time) ([]database.APIKey, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAPIKeysLastUsedAfter", arg0, arg1) + ret0, _ := ret[0].([]database.APIKey) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAPIKeysLastUsedAfter indicates an expected call of GetAPIKeysLastUsedAfter. +func (mr *MockStoreMockRecorder) GetAPIKeysLastUsedAfter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAPIKeysLastUsedAfter", reflect.TypeOf((*MockStore)(nil).GetAPIKeysLastUsedAfter), arg0, arg1) +} + +// GetActiveUserCount mocks base method. +func (m *MockStore) GetActiveUserCount(arg0 context.Context) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetActiveUserCount", arg0) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetActiveUserCount indicates an expected call of GetActiveUserCount. +func (mr *MockStoreMockRecorder) GetActiveUserCount(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActiveUserCount", reflect.TypeOf((*MockStore)(nil).GetActiveUserCount), arg0) +} + +// GetAppSecurityKey mocks base method. +func (m *MockStore) GetAppSecurityKey(arg0 context.Context) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAppSecurityKey", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAppSecurityKey indicates an expected call of GetAppSecurityKey. +func (mr *MockStoreMockRecorder) GetAppSecurityKey(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAppSecurityKey", reflect.TypeOf((*MockStore)(nil).GetAppSecurityKey), arg0) +} + +// GetAuditLogsOffset mocks base method. +func (m *MockStore) GetAuditLogsOffset(arg0 context.Context, arg1 database.GetAuditLogsOffsetParams) ([]database.GetAuditLogsOffsetRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAuditLogsOffset", arg0, arg1) + ret0, _ := ret[0].([]database.GetAuditLogsOffsetRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAuditLogsOffset indicates an expected call of GetAuditLogsOffset. +func (mr *MockStoreMockRecorder) GetAuditLogsOffset(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuditLogsOffset", reflect.TypeOf((*MockStore)(nil).GetAuditLogsOffset), arg0, arg1) +} + +// GetAuthorizationUserRoles mocks base method. +func (m *MockStore) GetAuthorizationUserRoles(arg0 context.Context, arg1 uuid.UUID) (database.GetAuthorizationUserRolesRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAuthorizationUserRoles", arg0, arg1) + ret0, _ := ret[0].(database.GetAuthorizationUserRolesRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAuthorizationUserRoles indicates an expected call of GetAuthorizationUserRoles. +func (mr *MockStoreMockRecorder) GetAuthorizationUserRoles(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorizationUserRoles", reflect.TypeOf((*MockStore)(nil).GetAuthorizationUserRoles), arg0, arg1) +} + +// GetAuthorizedTemplates mocks base method. +func (m *MockStore) GetAuthorizedTemplates(arg0 context.Context, arg1 database.GetTemplatesWithFilterParams, arg2 rbac.PreparedAuthorized) ([]database.Template, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAuthorizedTemplates", arg0, arg1, arg2) + ret0, _ := ret[0].([]database.Template) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAuthorizedTemplates indicates an expected call of GetAuthorizedTemplates. +func (mr *MockStoreMockRecorder) GetAuthorizedTemplates(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorizedTemplates", reflect.TypeOf((*MockStore)(nil).GetAuthorizedTemplates), arg0, arg1, arg2) +} + +// GetAuthorizedUserCount mocks base method. +func (m *MockStore) GetAuthorizedUserCount(arg0 context.Context, arg1 database.GetFilteredUserCountParams, arg2 rbac.PreparedAuthorized) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAuthorizedUserCount", arg0, arg1, arg2) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAuthorizedUserCount indicates an expected call of GetAuthorizedUserCount. +func (mr *MockStoreMockRecorder) GetAuthorizedUserCount(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorizedUserCount", reflect.TypeOf((*MockStore)(nil).GetAuthorizedUserCount), arg0, arg1, arg2) +} + +// GetAuthorizedWorkspaces mocks base method. +func (m *MockStore) GetAuthorizedWorkspaces(arg0 context.Context, arg1 database.GetWorkspacesParams, arg2 rbac.PreparedAuthorized) ([]database.GetWorkspacesRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAuthorizedWorkspaces", arg0, arg1, arg2) + ret0, _ := ret[0].([]database.GetWorkspacesRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAuthorizedWorkspaces indicates an expected call of GetAuthorizedWorkspaces. +func (mr *MockStoreMockRecorder) GetAuthorizedWorkspaces(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorizedWorkspaces", reflect.TypeOf((*MockStore)(nil).GetAuthorizedWorkspaces), arg0, arg1, arg2) +} + +// GetDERPMeshKey mocks base method. +func (m *MockStore) GetDERPMeshKey(arg0 context.Context) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDERPMeshKey", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDERPMeshKey indicates an expected call of GetDERPMeshKey. +func (mr *MockStoreMockRecorder) GetDERPMeshKey(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDERPMeshKey", reflect.TypeOf((*MockStore)(nil).GetDERPMeshKey), arg0) +} + +// GetDeploymentDAUs mocks base method. +func (m *MockStore) GetDeploymentDAUs(arg0 context.Context) ([]database.GetDeploymentDAUsRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDeploymentDAUs", arg0) + ret0, _ := ret[0].([]database.GetDeploymentDAUsRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDeploymentDAUs indicates an expected call of GetDeploymentDAUs. +func (mr *MockStoreMockRecorder) GetDeploymentDAUs(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeploymentDAUs", reflect.TypeOf((*MockStore)(nil).GetDeploymentDAUs), arg0) +} + +// GetDeploymentID mocks base method. +func (m *MockStore) GetDeploymentID(arg0 context.Context) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDeploymentID", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDeploymentID indicates an expected call of GetDeploymentID. +func (mr *MockStoreMockRecorder) GetDeploymentID(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeploymentID", reflect.TypeOf((*MockStore)(nil).GetDeploymentID), arg0) +} + +// GetDeploymentWorkspaceAgentStats mocks base method. +func (m *MockStore) GetDeploymentWorkspaceAgentStats(arg0 context.Context, arg1 time.Time) (database.GetDeploymentWorkspaceAgentStatsRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDeploymentWorkspaceAgentStats", arg0, arg1) + ret0, _ := ret[0].(database.GetDeploymentWorkspaceAgentStatsRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDeploymentWorkspaceAgentStats indicates an expected call of GetDeploymentWorkspaceAgentStats. +func (mr *MockStoreMockRecorder) GetDeploymentWorkspaceAgentStats(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeploymentWorkspaceAgentStats", reflect.TypeOf((*MockStore)(nil).GetDeploymentWorkspaceAgentStats), arg0, arg1) +} + +// GetDeploymentWorkspaceStats mocks base method. +func (m *MockStore) GetDeploymentWorkspaceStats(arg0 context.Context) (database.GetDeploymentWorkspaceStatsRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDeploymentWorkspaceStats", arg0) + ret0, _ := ret[0].(database.GetDeploymentWorkspaceStatsRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetDeploymentWorkspaceStats indicates an expected call of GetDeploymentWorkspaceStats. +func (mr *MockStoreMockRecorder) GetDeploymentWorkspaceStats(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeploymentWorkspaceStats", reflect.TypeOf((*MockStore)(nil).GetDeploymentWorkspaceStats), arg0) +} + +// GetFileByHashAndCreator mocks base method. +func (m *MockStore) GetFileByHashAndCreator(arg0 context.Context, arg1 database.GetFileByHashAndCreatorParams) (database.File, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFileByHashAndCreator", arg0, arg1) + ret0, _ := ret[0].(database.File) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetFileByHashAndCreator indicates an expected call of GetFileByHashAndCreator. +func (mr *MockStoreMockRecorder) GetFileByHashAndCreator(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFileByHashAndCreator", reflect.TypeOf((*MockStore)(nil).GetFileByHashAndCreator), arg0, arg1) +} + +// GetFileByID mocks base method. +func (m *MockStore) GetFileByID(arg0 context.Context, arg1 uuid.UUID) (database.File, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFileByID", arg0, arg1) + ret0, _ := ret[0].(database.File) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetFileByID indicates an expected call of GetFileByID. +func (mr *MockStoreMockRecorder) GetFileByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFileByID", reflect.TypeOf((*MockStore)(nil).GetFileByID), arg0, arg1) +} + +// GetFileTemplates mocks base method. +func (m *MockStore) GetFileTemplates(arg0 context.Context, arg1 uuid.UUID) ([]database.GetFileTemplatesRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFileTemplates", arg0, arg1) + ret0, _ := ret[0].([]database.GetFileTemplatesRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetFileTemplates indicates an expected call of GetFileTemplates. +func (mr *MockStoreMockRecorder) GetFileTemplates(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFileTemplates", reflect.TypeOf((*MockStore)(nil).GetFileTemplates), arg0, arg1) +} + +// GetFilteredUserCount mocks base method. +func (m *MockStore) GetFilteredUserCount(arg0 context.Context, arg1 database.GetFilteredUserCountParams) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFilteredUserCount", arg0, arg1) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetFilteredUserCount indicates an expected call of GetFilteredUserCount. +func (mr *MockStoreMockRecorder) GetFilteredUserCount(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFilteredUserCount", reflect.TypeOf((*MockStore)(nil).GetFilteredUserCount), arg0, arg1) +} + +// GetGitAuthLink mocks base method. +func (m *MockStore) GetGitAuthLink(arg0 context.Context, arg1 database.GetGitAuthLinkParams) (database.GitAuthLink, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGitAuthLink", arg0, arg1) + ret0, _ := ret[0].(database.GitAuthLink) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetGitAuthLink indicates an expected call of GetGitAuthLink. +func (mr *MockStoreMockRecorder) GetGitAuthLink(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGitAuthLink", reflect.TypeOf((*MockStore)(nil).GetGitAuthLink), arg0, arg1) +} + +// GetGitSSHKey mocks base method. +func (m *MockStore) GetGitSSHKey(arg0 context.Context, arg1 uuid.UUID) (database.GitSSHKey, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGitSSHKey", arg0, arg1) + ret0, _ := ret[0].(database.GitSSHKey) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetGitSSHKey indicates an expected call of GetGitSSHKey. +func (mr *MockStoreMockRecorder) GetGitSSHKey(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGitSSHKey", reflect.TypeOf((*MockStore)(nil).GetGitSSHKey), arg0, arg1) +} + +// GetGroupByID mocks base method. +func (m *MockStore) GetGroupByID(arg0 context.Context, arg1 uuid.UUID) (database.Group, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroupByID", arg0, arg1) + ret0, _ := ret[0].(database.Group) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetGroupByID indicates an expected call of GetGroupByID. +func (mr *MockStoreMockRecorder) GetGroupByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupByID", reflect.TypeOf((*MockStore)(nil).GetGroupByID), arg0, arg1) +} + +// GetGroupByOrgAndName mocks base method. +func (m *MockStore) GetGroupByOrgAndName(arg0 context.Context, arg1 database.GetGroupByOrgAndNameParams) (database.Group, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroupByOrgAndName", arg0, arg1) + ret0, _ := ret[0].(database.Group) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetGroupByOrgAndName indicates an expected call of GetGroupByOrgAndName. +func (mr *MockStoreMockRecorder) GetGroupByOrgAndName(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupByOrgAndName", reflect.TypeOf((*MockStore)(nil).GetGroupByOrgAndName), arg0, arg1) +} + +// GetGroupMembers mocks base method. +func (m *MockStore) GetGroupMembers(arg0 context.Context, arg1 uuid.UUID) ([]database.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroupMembers", arg0, arg1) + ret0, _ := ret[0].([]database.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetGroupMembers indicates an expected call of GetGroupMembers. +func (mr *MockStoreMockRecorder) GetGroupMembers(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupMembers", reflect.TypeOf((*MockStore)(nil).GetGroupMembers), arg0, arg1) +} + +// GetGroupsByOrganizationID mocks base method. +func (m *MockStore) GetGroupsByOrganizationID(arg0 context.Context, arg1 uuid.UUID) ([]database.Group, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroupsByOrganizationID", arg0, arg1) + ret0, _ := ret[0].([]database.Group) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetGroupsByOrganizationID indicates an expected call of GetGroupsByOrganizationID. +func (mr *MockStoreMockRecorder) GetGroupsByOrganizationID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupsByOrganizationID", reflect.TypeOf((*MockStore)(nil).GetGroupsByOrganizationID), arg0, arg1) +} + +// GetLastUpdateCheck mocks base method. +func (m *MockStore) GetLastUpdateCheck(arg0 context.Context) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLastUpdateCheck", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLastUpdateCheck indicates an expected call of GetLastUpdateCheck. +func (mr *MockStoreMockRecorder) GetLastUpdateCheck(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastUpdateCheck", reflect.TypeOf((*MockStore)(nil).GetLastUpdateCheck), arg0) +} + +// GetLatestWorkspaceBuildByWorkspaceID mocks base method. +func (m *MockStore) GetLatestWorkspaceBuildByWorkspaceID(arg0 context.Context, arg1 uuid.UUID) (database.WorkspaceBuild, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLatestWorkspaceBuildByWorkspaceID", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceBuild) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLatestWorkspaceBuildByWorkspaceID indicates an expected call of GetLatestWorkspaceBuildByWorkspaceID. +func (mr *MockStoreMockRecorder) GetLatestWorkspaceBuildByWorkspaceID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestWorkspaceBuildByWorkspaceID", reflect.TypeOf((*MockStore)(nil).GetLatestWorkspaceBuildByWorkspaceID), arg0, arg1) +} + +// GetLatestWorkspaceBuilds mocks base method. +func (m *MockStore) GetLatestWorkspaceBuilds(arg0 context.Context) ([]database.WorkspaceBuild, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLatestWorkspaceBuilds", arg0) + ret0, _ := ret[0].([]database.WorkspaceBuild) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLatestWorkspaceBuilds indicates an expected call of GetLatestWorkspaceBuilds. +func (mr *MockStoreMockRecorder) GetLatestWorkspaceBuilds(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestWorkspaceBuilds", reflect.TypeOf((*MockStore)(nil).GetLatestWorkspaceBuilds), arg0) +} + +// GetLatestWorkspaceBuildsByWorkspaceIDs mocks base method. +func (m *MockStore) GetLatestWorkspaceBuildsByWorkspaceIDs(arg0 context.Context, arg1 []uuid.UUID) ([]database.WorkspaceBuild, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLatestWorkspaceBuildsByWorkspaceIDs", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceBuild) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLatestWorkspaceBuildsByWorkspaceIDs indicates an expected call of GetLatestWorkspaceBuildsByWorkspaceIDs. +func (mr *MockStoreMockRecorder) GetLatestWorkspaceBuildsByWorkspaceIDs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestWorkspaceBuildsByWorkspaceIDs", reflect.TypeOf((*MockStore)(nil).GetLatestWorkspaceBuildsByWorkspaceIDs), arg0, arg1) +} + +// GetLicenseByID mocks base method. +func (m *MockStore) GetLicenseByID(arg0 context.Context, arg1 int32) (database.License, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLicenseByID", arg0, arg1) + ret0, _ := ret[0].(database.License) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLicenseByID indicates an expected call of GetLicenseByID. +func (mr *MockStoreMockRecorder) GetLicenseByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLicenseByID", reflect.TypeOf((*MockStore)(nil).GetLicenseByID), arg0, arg1) +} + +// GetLicenses mocks base method. +func (m *MockStore) GetLicenses(arg0 context.Context) ([]database.License, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLicenses", arg0) + ret0, _ := ret[0].([]database.License) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLicenses indicates an expected call of GetLicenses. +func (mr *MockStoreMockRecorder) GetLicenses(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLicenses", reflect.TypeOf((*MockStore)(nil).GetLicenses), arg0) +} + +// GetLogoURL mocks base method. +func (m *MockStore) GetLogoURL(arg0 context.Context) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLogoURL", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLogoURL indicates an expected call of GetLogoURL. +func (mr *MockStoreMockRecorder) GetLogoURL(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogoURL", reflect.TypeOf((*MockStore)(nil).GetLogoURL), arg0) +} + +// GetOrganizationByID mocks base method. +func (m *MockStore) GetOrganizationByID(arg0 context.Context, arg1 uuid.UUID) (database.Organization, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetOrganizationByID", arg0, arg1) + ret0, _ := ret[0].(database.Organization) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetOrganizationByID indicates an expected call of GetOrganizationByID. +func (mr *MockStoreMockRecorder) GetOrganizationByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrganizationByID", reflect.TypeOf((*MockStore)(nil).GetOrganizationByID), arg0, arg1) +} + +// GetOrganizationByName mocks base method. +func (m *MockStore) GetOrganizationByName(arg0 context.Context, arg1 string) (database.Organization, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetOrganizationByName", arg0, arg1) + ret0, _ := ret[0].(database.Organization) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetOrganizationByName indicates an expected call of GetOrganizationByName. +func (mr *MockStoreMockRecorder) GetOrganizationByName(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrganizationByName", reflect.TypeOf((*MockStore)(nil).GetOrganizationByName), arg0, arg1) +} + +// GetOrganizationIDsByMemberIDs mocks base method. +func (m *MockStore) GetOrganizationIDsByMemberIDs(arg0 context.Context, arg1 []uuid.UUID) ([]database.GetOrganizationIDsByMemberIDsRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetOrganizationIDsByMemberIDs", arg0, arg1) + ret0, _ := ret[0].([]database.GetOrganizationIDsByMemberIDsRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetOrganizationIDsByMemberIDs indicates an expected call of GetOrganizationIDsByMemberIDs. +func (mr *MockStoreMockRecorder) GetOrganizationIDsByMemberIDs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrganizationIDsByMemberIDs", reflect.TypeOf((*MockStore)(nil).GetOrganizationIDsByMemberIDs), arg0, arg1) +} + +// GetOrganizationMemberByUserID mocks base method. +func (m *MockStore) GetOrganizationMemberByUserID(arg0 context.Context, arg1 database.GetOrganizationMemberByUserIDParams) (database.OrganizationMember, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetOrganizationMemberByUserID", arg0, arg1) + ret0, _ := ret[0].(database.OrganizationMember) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetOrganizationMemberByUserID indicates an expected call of GetOrganizationMemberByUserID. +func (mr *MockStoreMockRecorder) GetOrganizationMemberByUserID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrganizationMemberByUserID", reflect.TypeOf((*MockStore)(nil).GetOrganizationMemberByUserID), arg0, arg1) +} + +// GetOrganizationMembershipsByUserID mocks base method. +func (m *MockStore) GetOrganizationMembershipsByUserID(arg0 context.Context, arg1 uuid.UUID) ([]database.OrganizationMember, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetOrganizationMembershipsByUserID", arg0, arg1) + ret0, _ := ret[0].([]database.OrganizationMember) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetOrganizationMembershipsByUserID indicates an expected call of GetOrganizationMembershipsByUserID. +func (mr *MockStoreMockRecorder) GetOrganizationMembershipsByUserID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrganizationMembershipsByUserID", reflect.TypeOf((*MockStore)(nil).GetOrganizationMembershipsByUserID), arg0, arg1) +} + +// GetOrganizations mocks base method. +func (m *MockStore) GetOrganizations(arg0 context.Context) ([]database.Organization, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetOrganizations", arg0) + ret0, _ := ret[0].([]database.Organization) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetOrganizations indicates an expected call of GetOrganizations. +func (mr *MockStoreMockRecorder) GetOrganizations(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrganizations", reflect.TypeOf((*MockStore)(nil).GetOrganizations), arg0) +} + +// GetOrganizationsByUserID mocks base method. +func (m *MockStore) GetOrganizationsByUserID(arg0 context.Context, arg1 uuid.UUID) ([]database.Organization, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetOrganizationsByUserID", arg0, arg1) + ret0, _ := ret[0].([]database.Organization) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetOrganizationsByUserID indicates an expected call of GetOrganizationsByUserID. +func (mr *MockStoreMockRecorder) GetOrganizationsByUserID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOrganizationsByUserID", reflect.TypeOf((*MockStore)(nil).GetOrganizationsByUserID), arg0, arg1) +} + +// GetParameterSchemasByJobID mocks base method. +func (m *MockStore) GetParameterSchemasByJobID(arg0 context.Context, arg1 uuid.UUID) ([]database.ParameterSchema, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetParameterSchemasByJobID", arg0, arg1) + ret0, _ := ret[0].([]database.ParameterSchema) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetParameterSchemasByJobID indicates an expected call of GetParameterSchemasByJobID. +func (mr *MockStoreMockRecorder) GetParameterSchemasByJobID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParameterSchemasByJobID", reflect.TypeOf((*MockStore)(nil).GetParameterSchemasByJobID), arg0, arg1) +} + +// GetParameterSchemasCreatedAfter mocks base method. +func (m *MockStore) GetParameterSchemasCreatedAfter(arg0 context.Context, arg1 time.Time) ([]database.ParameterSchema, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetParameterSchemasCreatedAfter", arg0, arg1) + ret0, _ := ret[0].([]database.ParameterSchema) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetParameterSchemasCreatedAfter indicates an expected call of GetParameterSchemasCreatedAfter. +func (mr *MockStoreMockRecorder) GetParameterSchemasCreatedAfter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParameterSchemasCreatedAfter", reflect.TypeOf((*MockStore)(nil).GetParameterSchemasCreatedAfter), arg0, arg1) +} + +// GetParameterValueByScopeAndName mocks base method. +func (m *MockStore) GetParameterValueByScopeAndName(arg0 context.Context, arg1 database.GetParameterValueByScopeAndNameParams) (database.ParameterValue, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetParameterValueByScopeAndName", arg0, arg1) + ret0, _ := ret[0].(database.ParameterValue) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetParameterValueByScopeAndName indicates an expected call of GetParameterValueByScopeAndName. +func (mr *MockStoreMockRecorder) GetParameterValueByScopeAndName(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParameterValueByScopeAndName", reflect.TypeOf((*MockStore)(nil).GetParameterValueByScopeAndName), arg0, arg1) +} + +// GetPreviousTemplateVersion mocks base method. +func (m *MockStore) GetPreviousTemplateVersion(arg0 context.Context, arg1 database.GetPreviousTemplateVersionParams) (database.TemplateVersion, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPreviousTemplateVersion", arg0, arg1) + ret0, _ := ret[0].(database.TemplateVersion) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetPreviousTemplateVersion indicates an expected call of GetPreviousTemplateVersion. +func (mr *MockStoreMockRecorder) GetPreviousTemplateVersion(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPreviousTemplateVersion", reflect.TypeOf((*MockStore)(nil).GetPreviousTemplateVersion), arg0, arg1) +} + +// GetProvisionerDaemons mocks base method. +func (m *MockStore) GetProvisionerDaemons(arg0 context.Context) ([]database.ProvisionerDaemon, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetProvisionerDaemons", arg0) + ret0, _ := ret[0].([]database.ProvisionerDaemon) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetProvisionerDaemons indicates an expected call of GetProvisionerDaemons. +func (mr *MockStoreMockRecorder) GetProvisionerDaemons(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProvisionerDaemons", reflect.TypeOf((*MockStore)(nil).GetProvisionerDaemons), arg0) +} + +// GetProvisionerJobByID mocks base method. +func (m *MockStore) GetProvisionerJobByID(arg0 context.Context, arg1 uuid.UUID) (database.ProvisionerJob, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetProvisionerJobByID", arg0, arg1) + ret0, _ := ret[0].(database.ProvisionerJob) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetProvisionerJobByID indicates an expected call of GetProvisionerJobByID. +func (mr *MockStoreMockRecorder) GetProvisionerJobByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProvisionerJobByID", reflect.TypeOf((*MockStore)(nil).GetProvisionerJobByID), arg0, arg1) +} + +// GetProvisionerJobsByIDs mocks base method. +func (m *MockStore) GetProvisionerJobsByIDs(arg0 context.Context, arg1 []uuid.UUID) ([]database.ProvisionerJob, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetProvisionerJobsByIDs", arg0, arg1) + ret0, _ := ret[0].([]database.ProvisionerJob) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetProvisionerJobsByIDs indicates an expected call of GetProvisionerJobsByIDs. +func (mr *MockStoreMockRecorder) GetProvisionerJobsByIDs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProvisionerJobsByIDs", reflect.TypeOf((*MockStore)(nil).GetProvisionerJobsByIDs), arg0, arg1) +} + +// GetProvisionerJobsCreatedAfter mocks base method. +func (m *MockStore) GetProvisionerJobsCreatedAfter(arg0 context.Context, arg1 time.Time) ([]database.ProvisionerJob, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetProvisionerJobsCreatedAfter", arg0, arg1) + ret0, _ := ret[0].([]database.ProvisionerJob) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetProvisionerJobsCreatedAfter indicates an expected call of GetProvisionerJobsCreatedAfter. +func (mr *MockStoreMockRecorder) GetProvisionerJobsCreatedAfter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProvisionerJobsCreatedAfter", reflect.TypeOf((*MockStore)(nil).GetProvisionerJobsCreatedAfter), arg0, arg1) +} + +// GetProvisionerLogsAfterID mocks base method. +func (m *MockStore) GetProvisionerLogsAfterID(arg0 context.Context, arg1 database.GetProvisionerLogsAfterIDParams) ([]database.ProvisionerJobLog, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetProvisionerLogsAfterID", arg0, arg1) + ret0, _ := ret[0].([]database.ProvisionerJobLog) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetProvisionerLogsAfterID indicates an expected call of GetProvisionerLogsAfterID. +func (mr *MockStoreMockRecorder) GetProvisionerLogsAfterID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProvisionerLogsAfterID", reflect.TypeOf((*MockStore)(nil).GetProvisionerLogsAfterID), arg0, arg1) +} + +// GetQuotaAllowanceForUser mocks base method. +func (m *MockStore) GetQuotaAllowanceForUser(arg0 context.Context, arg1 uuid.UUID) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetQuotaAllowanceForUser", arg0, arg1) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetQuotaAllowanceForUser indicates an expected call of GetQuotaAllowanceForUser. +func (mr *MockStoreMockRecorder) GetQuotaAllowanceForUser(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQuotaAllowanceForUser", reflect.TypeOf((*MockStore)(nil).GetQuotaAllowanceForUser), arg0, arg1) +} + +// GetQuotaConsumedForUser mocks base method. +func (m *MockStore) GetQuotaConsumedForUser(arg0 context.Context, arg1 uuid.UUID) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetQuotaConsumedForUser", arg0, arg1) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetQuotaConsumedForUser indicates an expected call of GetQuotaConsumedForUser. +func (mr *MockStoreMockRecorder) GetQuotaConsumedForUser(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetQuotaConsumedForUser", reflect.TypeOf((*MockStore)(nil).GetQuotaConsumedForUser), arg0, arg1) +} + +// GetReplicasUpdatedAfter mocks base method. +func (m *MockStore) GetReplicasUpdatedAfter(arg0 context.Context, arg1 time.Time) ([]database.Replica, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetReplicasUpdatedAfter", arg0, arg1) + ret0, _ := ret[0].([]database.Replica) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetReplicasUpdatedAfter indicates an expected call of GetReplicasUpdatedAfter. +func (mr *MockStoreMockRecorder) GetReplicasUpdatedAfter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReplicasUpdatedAfter", reflect.TypeOf((*MockStore)(nil).GetReplicasUpdatedAfter), arg0, arg1) +} + +// GetServiceBanner mocks base method. +func (m *MockStore) GetServiceBanner(arg0 context.Context) (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetServiceBanner", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetServiceBanner indicates an expected call of GetServiceBanner. +func (mr *MockStoreMockRecorder) GetServiceBanner(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceBanner", reflect.TypeOf((*MockStore)(nil).GetServiceBanner), arg0) +} + +// GetTemplateAverageBuildTime mocks base method. +func (m *MockStore) GetTemplateAverageBuildTime(arg0 context.Context, arg1 database.GetTemplateAverageBuildTimeParams) (database.GetTemplateAverageBuildTimeRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateAverageBuildTime", arg0, arg1) + ret0, _ := ret[0].(database.GetTemplateAverageBuildTimeRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateAverageBuildTime indicates an expected call of GetTemplateAverageBuildTime. +func (mr *MockStoreMockRecorder) GetTemplateAverageBuildTime(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateAverageBuildTime", reflect.TypeOf((*MockStore)(nil).GetTemplateAverageBuildTime), arg0, arg1) +} + +// GetTemplateByID mocks base method. +func (m *MockStore) GetTemplateByID(arg0 context.Context, arg1 uuid.UUID) (database.Template, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateByID", arg0, arg1) + ret0, _ := ret[0].(database.Template) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateByID indicates an expected call of GetTemplateByID. +func (mr *MockStoreMockRecorder) GetTemplateByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateByID", reflect.TypeOf((*MockStore)(nil).GetTemplateByID), arg0, arg1) +} + +// GetTemplateByOrganizationAndName mocks base method. +func (m *MockStore) GetTemplateByOrganizationAndName(arg0 context.Context, arg1 database.GetTemplateByOrganizationAndNameParams) (database.Template, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateByOrganizationAndName", arg0, arg1) + ret0, _ := ret[0].(database.Template) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateByOrganizationAndName indicates an expected call of GetTemplateByOrganizationAndName. +func (mr *MockStoreMockRecorder) GetTemplateByOrganizationAndName(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateByOrganizationAndName", reflect.TypeOf((*MockStore)(nil).GetTemplateByOrganizationAndName), arg0, arg1) +} + +// GetTemplateDAUs mocks base method. +func (m *MockStore) GetTemplateDAUs(arg0 context.Context, arg1 uuid.UUID) ([]database.GetTemplateDAUsRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateDAUs", arg0, arg1) + ret0, _ := ret[0].([]database.GetTemplateDAUsRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateDAUs indicates an expected call of GetTemplateDAUs. +func (mr *MockStoreMockRecorder) GetTemplateDAUs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateDAUs", reflect.TypeOf((*MockStore)(nil).GetTemplateDAUs), arg0, arg1) +} + +// GetTemplateGroupRoles mocks base method. +func (m *MockStore) GetTemplateGroupRoles(arg0 context.Context, arg1 uuid.UUID) ([]database.TemplateGroup, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateGroupRoles", arg0, arg1) + ret0, _ := ret[0].([]database.TemplateGroup) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateGroupRoles indicates an expected call of GetTemplateGroupRoles. +func (mr *MockStoreMockRecorder) GetTemplateGroupRoles(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateGroupRoles", reflect.TypeOf((*MockStore)(nil).GetTemplateGroupRoles), arg0, arg1) +} + +// GetTemplateUserRoles mocks base method. +func (m *MockStore) GetTemplateUserRoles(arg0 context.Context, arg1 uuid.UUID) ([]database.TemplateUser, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateUserRoles", arg0, arg1) + ret0, _ := ret[0].([]database.TemplateUser) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateUserRoles indicates an expected call of GetTemplateUserRoles. +func (mr *MockStoreMockRecorder) GetTemplateUserRoles(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateUserRoles", reflect.TypeOf((*MockStore)(nil).GetTemplateUserRoles), arg0, arg1) +} + +// GetTemplateVersionByID mocks base method. +func (m *MockStore) GetTemplateVersionByID(arg0 context.Context, arg1 uuid.UUID) (database.TemplateVersion, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateVersionByID", arg0, arg1) + ret0, _ := ret[0].(database.TemplateVersion) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateVersionByID indicates an expected call of GetTemplateVersionByID. +func (mr *MockStoreMockRecorder) GetTemplateVersionByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateVersionByID", reflect.TypeOf((*MockStore)(nil).GetTemplateVersionByID), arg0, arg1) +} + +// GetTemplateVersionByJobID mocks base method. +func (m *MockStore) GetTemplateVersionByJobID(arg0 context.Context, arg1 uuid.UUID) (database.TemplateVersion, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateVersionByJobID", arg0, arg1) + ret0, _ := ret[0].(database.TemplateVersion) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateVersionByJobID indicates an expected call of GetTemplateVersionByJobID. +func (mr *MockStoreMockRecorder) GetTemplateVersionByJobID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateVersionByJobID", reflect.TypeOf((*MockStore)(nil).GetTemplateVersionByJobID), arg0, arg1) +} + +// GetTemplateVersionByTemplateIDAndName mocks base method. +func (m *MockStore) GetTemplateVersionByTemplateIDAndName(arg0 context.Context, arg1 database.GetTemplateVersionByTemplateIDAndNameParams) (database.TemplateVersion, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateVersionByTemplateIDAndName", arg0, arg1) + ret0, _ := ret[0].(database.TemplateVersion) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateVersionByTemplateIDAndName indicates an expected call of GetTemplateVersionByTemplateIDAndName. +func (mr *MockStoreMockRecorder) GetTemplateVersionByTemplateIDAndName(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateVersionByTemplateIDAndName", reflect.TypeOf((*MockStore)(nil).GetTemplateVersionByTemplateIDAndName), arg0, arg1) +} + +// GetTemplateVersionParameters mocks base method. +func (m *MockStore) GetTemplateVersionParameters(arg0 context.Context, arg1 uuid.UUID) ([]database.TemplateVersionParameter, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateVersionParameters", arg0, arg1) + ret0, _ := ret[0].([]database.TemplateVersionParameter) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateVersionParameters indicates an expected call of GetTemplateVersionParameters. +func (mr *MockStoreMockRecorder) GetTemplateVersionParameters(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateVersionParameters", reflect.TypeOf((*MockStore)(nil).GetTemplateVersionParameters), arg0, arg1) +} + +// GetTemplateVersionVariables mocks base method. +func (m *MockStore) GetTemplateVersionVariables(arg0 context.Context, arg1 uuid.UUID) ([]database.TemplateVersionVariable, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateVersionVariables", arg0, arg1) + ret0, _ := ret[0].([]database.TemplateVersionVariable) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateVersionVariables indicates an expected call of GetTemplateVersionVariables. +func (mr *MockStoreMockRecorder) GetTemplateVersionVariables(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateVersionVariables", reflect.TypeOf((*MockStore)(nil).GetTemplateVersionVariables), arg0, arg1) +} + +// GetTemplateVersionsByIDs mocks base method. +func (m *MockStore) GetTemplateVersionsByIDs(arg0 context.Context, arg1 []uuid.UUID) ([]database.TemplateVersion, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateVersionsByIDs", arg0, arg1) + ret0, _ := ret[0].([]database.TemplateVersion) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateVersionsByIDs indicates an expected call of GetTemplateVersionsByIDs. +func (mr *MockStoreMockRecorder) GetTemplateVersionsByIDs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateVersionsByIDs", reflect.TypeOf((*MockStore)(nil).GetTemplateVersionsByIDs), arg0, arg1) +} + +// GetTemplateVersionsByTemplateID mocks base method. +func (m *MockStore) GetTemplateVersionsByTemplateID(arg0 context.Context, arg1 database.GetTemplateVersionsByTemplateIDParams) ([]database.TemplateVersion, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateVersionsByTemplateID", arg0, arg1) + ret0, _ := ret[0].([]database.TemplateVersion) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateVersionsByTemplateID indicates an expected call of GetTemplateVersionsByTemplateID. +func (mr *MockStoreMockRecorder) GetTemplateVersionsByTemplateID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateVersionsByTemplateID", reflect.TypeOf((*MockStore)(nil).GetTemplateVersionsByTemplateID), arg0, arg1) +} + +// GetTemplateVersionsCreatedAfter mocks base method. +func (m *MockStore) GetTemplateVersionsCreatedAfter(arg0 context.Context, arg1 time.Time) ([]database.TemplateVersion, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplateVersionsCreatedAfter", arg0, arg1) + ret0, _ := ret[0].([]database.TemplateVersion) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplateVersionsCreatedAfter indicates an expected call of GetTemplateVersionsCreatedAfter. +func (mr *MockStoreMockRecorder) GetTemplateVersionsCreatedAfter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateVersionsCreatedAfter", reflect.TypeOf((*MockStore)(nil).GetTemplateVersionsCreatedAfter), arg0, arg1) +} + +// GetTemplates mocks base method. +func (m *MockStore) GetTemplates(arg0 context.Context) ([]database.Template, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplates", arg0) + ret0, _ := ret[0].([]database.Template) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplates indicates an expected call of GetTemplates. +func (mr *MockStoreMockRecorder) GetTemplates(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplates", reflect.TypeOf((*MockStore)(nil).GetTemplates), arg0) +} + +// GetTemplatesWithFilter mocks base method. +func (m *MockStore) GetTemplatesWithFilter(arg0 context.Context, arg1 database.GetTemplatesWithFilterParams) ([]database.Template, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTemplatesWithFilter", arg0, arg1) + ret0, _ := ret[0].([]database.Template) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplatesWithFilter indicates an expected call of GetTemplatesWithFilter. +func (mr *MockStoreMockRecorder) GetTemplatesWithFilter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplatesWithFilter", reflect.TypeOf((*MockStore)(nil).GetTemplatesWithFilter), arg0, arg1) +} + +// GetUnexpiredLicenses mocks base method. +func (m *MockStore) GetUnexpiredLicenses(arg0 context.Context) ([]database.License, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUnexpiredLicenses", arg0) + ret0, _ := ret[0].([]database.License) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUnexpiredLicenses indicates an expected call of GetUnexpiredLicenses. +func (mr *MockStoreMockRecorder) GetUnexpiredLicenses(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnexpiredLicenses", reflect.TypeOf((*MockStore)(nil).GetUnexpiredLicenses), arg0) +} + +// GetUserByEmailOrUsername mocks base method. +func (m *MockStore) GetUserByEmailOrUsername(arg0 context.Context, arg1 database.GetUserByEmailOrUsernameParams) (database.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserByEmailOrUsername", arg0, arg1) + ret0, _ := ret[0].(database.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserByEmailOrUsername indicates an expected call of GetUserByEmailOrUsername. +func (mr *MockStoreMockRecorder) GetUserByEmailOrUsername(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByEmailOrUsername", reflect.TypeOf((*MockStore)(nil).GetUserByEmailOrUsername), arg0, arg1) +} + +// GetUserByID mocks base method. +func (m *MockStore) GetUserByID(arg0 context.Context, arg1 uuid.UUID) (database.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserByID", arg0, arg1) + ret0, _ := ret[0].(database.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserByID indicates an expected call of GetUserByID. +func (mr *MockStoreMockRecorder) GetUserByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByID", reflect.TypeOf((*MockStore)(nil).GetUserByID), arg0, arg1) +} + +// GetUserCount mocks base method. +func (m *MockStore) GetUserCount(arg0 context.Context) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserCount", arg0) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserCount indicates an expected call of GetUserCount. +func (mr *MockStoreMockRecorder) GetUserCount(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserCount", reflect.TypeOf((*MockStore)(nil).GetUserCount), arg0) +} + +// GetUserLinkByLinkedID mocks base method. +func (m *MockStore) GetUserLinkByLinkedID(arg0 context.Context, arg1 string) (database.UserLink, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserLinkByLinkedID", arg0, arg1) + ret0, _ := ret[0].(database.UserLink) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserLinkByLinkedID indicates an expected call of GetUserLinkByLinkedID. +func (mr *MockStoreMockRecorder) GetUserLinkByLinkedID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserLinkByLinkedID", reflect.TypeOf((*MockStore)(nil).GetUserLinkByLinkedID), arg0, arg1) +} + +// GetUserLinkByUserIDLoginType mocks base method. +func (m *MockStore) GetUserLinkByUserIDLoginType(arg0 context.Context, arg1 database.GetUserLinkByUserIDLoginTypeParams) (database.UserLink, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserLinkByUserIDLoginType", arg0, arg1) + ret0, _ := ret[0].(database.UserLink) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserLinkByUserIDLoginType indicates an expected call of GetUserLinkByUserIDLoginType. +func (mr *MockStoreMockRecorder) GetUserLinkByUserIDLoginType(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserLinkByUserIDLoginType", reflect.TypeOf((*MockStore)(nil).GetUserLinkByUserIDLoginType), arg0, arg1) +} + +// GetUsers mocks base method. +func (m *MockStore) GetUsers(arg0 context.Context, arg1 database.GetUsersParams) ([]database.GetUsersRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUsers", arg0, arg1) + ret0, _ := ret[0].([]database.GetUsersRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUsers indicates an expected call of GetUsers. +func (mr *MockStoreMockRecorder) GetUsers(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUsers", reflect.TypeOf((*MockStore)(nil).GetUsers), arg0, arg1) +} + +// GetUsersByIDs mocks base method. +func (m *MockStore) GetUsersByIDs(arg0 context.Context, arg1 []uuid.UUID) ([]database.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUsersByIDs", arg0, arg1) + ret0, _ := ret[0].([]database.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUsersByIDs indicates an expected call of GetUsersByIDs. +func (mr *MockStoreMockRecorder) GetUsersByIDs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUsersByIDs", reflect.TypeOf((*MockStore)(nil).GetUsersByIDs), arg0, arg1) +} + +// GetWorkspaceAgentByAuthToken mocks base method. +func (m *MockStore) GetWorkspaceAgentByAuthToken(arg0 context.Context, arg1 uuid.UUID) (database.WorkspaceAgent, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceAgentByAuthToken", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceAgent) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceAgentByAuthToken indicates an expected call of GetWorkspaceAgentByAuthToken. +func (mr *MockStoreMockRecorder) GetWorkspaceAgentByAuthToken(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceAgentByAuthToken", reflect.TypeOf((*MockStore)(nil).GetWorkspaceAgentByAuthToken), arg0, arg1) +} + +// GetWorkspaceAgentByID mocks base method. +func (m *MockStore) GetWorkspaceAgentByID(arg0 context.Context, arg1 uuid.UUID) (database.WorkspaceAgent, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceAgentByID", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceAgent) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceAgentByID indicates an expected call of GetWorkspaceAgentByID. +func (mr *MockStoreMockRecorder) GetWorkspaceAgentByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceAgentByID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceAgentByID), arg0, arg1) +} + +// GetWorkspaceAgentByInstanceID mocks base method. +func (m *MockStore) GetWorkspaceAgentByInstanceID(arg0 context.Context, arg1 string) (database.WorkspaceAgent, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceAgentByInstanceID", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceAgent) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceAgentByInstanceID indicates an expected call of GetWorkspaceAgentByInstanceID. +func (mr *MockStoreMockRecorder) GetWorkspaceAgentByInstanceID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceAgentByInstanceID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceAgentByInstanceID), arg0, arg1) +} + +// GetWorkspaceAgentMetadata mocks base method. +func (m *MockStore) GetWorkspaceAgentMetadata(arg0 context.Context, arg1 uuid.UUID) ([]database.WorkspaceAgentMetadatum, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceAgentMetadata", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceAgentMetadatum) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceAgentMetadata indicates an expected call of GetWorkspaceAgentMetadata. +func (mr *MockStoreMockRecorder) GetWorkspaceAgentMetadata(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceAgentMetadata", reflect.TypeOf((*MockStore)(nil).GetWorkspaceAgentMetadata), arg0, arg1) +} + +// GetWorkspaceAgentStartupLogsAfter mocks base method. +func (m *MockStore) GetWorkspaceAgentStartupLogsAfter(arg0 context.Context, arg1 database.GetWorkspaceAgentStartupLogsAfterParams) ([]database.WorkspaceAgentStartupLog, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceAgentStartupLogsAfter", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceAgentStartupLog) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceAgentStartupLogsAfter indicates an expected call of GetWorkspaceAgentStartupLogsAfter. +func (mr *MockStoreMockRecorder) GetWorkspaceAgentStartupLogsAfter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceAgentStartupLogsAfter", reflect.TypeOf((*MockStore)(nil).GetWorkspaceAgentStartupLogsAfter), arg0, arg1) +} + +// GetWorkspaceAgentStats mocks base method. +func (m *MockStore) GetWorkspaceAgentStats(arg0 context.Context, arg1 time.Time) ([]database.GetWorkspaceAgentStatsRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceAgentStats", arg0, arg1) + ret0, _ := ret[0].([]database.GetWorkspaceAgentStatsRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceAgentStats indicates an expected call of GetWorkspaceAgentStats. +func (mr *MockStoreMockRecorder) GetWorkspaceAgentStats(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceAgentStats", reflect.TypeOf((*MockStore)(nil).GetWorkspaceAgentStats), arg0, arg1) +} + +// GetWorkspaceAgentStatsAndLabels mocks base method. +func (m *MockStore) GetWorkspaceAgentStatsAndLabels(arg0 context.Context, arg1 time.Time) ([]database.GetWorkspaceAgentStatsAndLabelsRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceAgentStatsAndLabels", arg0, arg1) + ret0, _ := ret[0].([]database.GetWorkspaceAgentStatsAndLabelsRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceAgentStatsAndLabels indicates an expected call of GetWorkspaceAgentStatsAndLabels. +func (mr *MockStoreMockRecorder) GetWorkspaceAgentStatsAndLabels(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceAgentStatsAndLabels", reflect.TypeOf((*MockStore)(nil).GetWorkspaceAgentStatsAndLabels), arg0, arg1) +} + +// GetWorkspaceAgentsByResourceIDs mocks base method. +func (m *MockStore) GetWorkspaceAgentsByResourceIDs(arg0 context.Context, arg1 []uuid.UUID) ([]database.WorkspaceAgent, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceAgentsByResourceIDs", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceAgent) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceAgentsByResourceIDs indicates an expected call of GetWorkspaceAgentsByResourceIDs. +func (mr *MockStoreMockRecorder) GetWorkspaceAgentsByResourceIDs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceAgentsByResourceIDs", reflect.TypeOf((*MockStore)(nil).GetWorkspaceAgentsByResourceIDs), arg0, arg1) +} + +// GetWorkspaceAgentsCreatedAfter mocks base method. +func (m *MockStore) GetWorkspaceAgentsCreatedAfter(arg0 context.Context, arg1 time.Time) ([]database.WorkspaceAgent, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceAgentsCreatedAfter", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceAgent) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceAgentsCreatedAfter indicates an expected call of GetWorkspaceAgentsCreatedAfter. +func (mr *MockStoreMockRecorder) GetWorkspaceAgentsCreatedAfter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceAgentsCreatedAfter", reflect.TypeOf((*MockStore)(nil).GetWorkspaceAgentsCreatedAfter), arg0, arg1) +} + +// GetWorkspaceAgentsInLatestBuildByWorkspaceID mocks base method. +func (m *MockStore) GetWorkspaceAgentsInLatestBuildByWorkspaceID(arg0 context.Context, arg1 uuid.UUID) ([]database.WorkspaceAgent, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceAgentsInLatestBuildByWorkspaceID", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceAgent) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceAgentsInLatestBuildByWorkspaceID indicates an expected call of GetWorkspaceAgentsInLatestBuildByWorkspaceID. +func (mr *MockStoreMockRecorder) GetWorkspaceAgentsInLatestBuildByWorkspaceID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceAgentsInLatestBuildByWorkspaceID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceAgentsInLatestBuildByWorkspaceID), arg0, arg1) +} + +// GetWorkspaceAppByAgentIDAndSlug mocks base method. +func (m *MockStore) GetWorkspaceAppByAgentIDAndSlug(arg0 context.Context, arg1 database.GetWorkspaceAppByAgentIDAndSlugParams) (database.WorkspaceApp, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceAppByAgentIDAndSlug", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceApp) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceAppByAgentIDAndSlug indicates an expected call of GetWorkspaceAppByAgentIDAndSlug. +func (mr *MockStoreMockRecorder) GetWorkspaceAppByAgentIDAndSlug(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceAppByAgentIDAndSlug", reflect.TypeOf((*MockStore)(nil).GetWorkspaceAppByAgentIDAndSlug), arg0, arg1) +} + +// GetWorkspaceAppsByAgentID mocks base method. +func (m *MockStore) GetWorkspaceAppsByAgentID(arg0 context.Context, arg1 uuid.UUID) ([]database.WorkspaceApp, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceAppsByAgentID", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceApp) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceAppsByAgentID indicates an expected call of GetWorkspaceAppsByAgentID. +func (mr *MockStoreMockRecorder) GetWorkspaceAppsByAgentID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceAppsByAgentID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceAppsByAgentID), arg0, arg1) +} + +// GetWorkspaceAppsByAgentIDs mocks base method. +func (m *MockStore) GetWorkspaceAppsByAgentIDs(arg0 context.Context, arg1 []uuid.UUID) ([]database.WorkspaceApp, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceAppsByAgentIDs", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceApp) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceAppsByAgentIDs indicates an expected call of GetWorkspaceAppsByAgentIDs. +func (mr *MockStoreMockRecorder) GetWorkspaceAppsByAgentIDs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceAppsByAgentIDs", reflect.TypeOf((*MockStore)(nil).GetWorkspaceAppsByAgentIDs), arg0, arg1) +} + +// GetWorkspaceAppsCreatedAfter mocks base method. +func (m *MockStore) GetWorkspaceAppsCreatedAfter(arg0 context.Context, arg1 time.Time) ([]database.WorkspaceApp, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceAppsCreatedAfter", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceApp) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceAppsCreatedAfter indicates an expected call of GetWorkspaceAppsCreatedAfter. +func (mr *MockStoreMockRecorder) GetWorkspaceAppsCreatedAfter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceAppsCreatedAfter", reflect.TypeOf((*MockStore)(nil).GetWorkspaceAppsCreatedAfter), arg0, arg1) +} + +// GetWorkspaceBuildByID mocks base method. +func (m *MockStore) GetWorkspaceBuildByID(arg0 context.Context, arg1 uuid.UUID) (database.WorkspaceBuild, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceBuildByID", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceBuild) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceBuildByID indicates an expected call of GetWorkspaceBuildByID. +func (mr *MockStoreMockRecorder) GetWorkspaceBuildByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceBuildByID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceBuildByID), arg0, arg1) +} + +// GetWorkspaceBuildByJobID mocks base method. +func (m *MockStore) GetWorkspaceBuildByJobID(arg0 context.Context, arg1 uuid.UUID) (database.WorkspaceBuild, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceBuildByJobID", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceBuild) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceBuildByJobID indicates an expected call of GetWorkspaceBuildByJobID. +func (mr *MockStoreMockRecorder) GetWorkspaceBuildByJobID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceBuildByJobID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceBuildByJobID), arg0, arg1) +} + +// GetWorkspaceBuildByWorkspaceIDAndBuildNumber mocks base method. +func (m *MockStore) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(arg0 context.Context, arg1 database.GetWorkspaceBuildByWorkspaceIDAndBuildNumberParams) (database.WorkspaceBuild, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceBuildByWorkspaceIDAndBuildNumber", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceBuild) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceBuildByWorkspaceIDAndBuildNumber indicates an expected call of GetWorkspaceBuildByWorkspaceIDAndBuildNumber. +func (mr *MockStoreMockRecorder) GetWorkspaceBuildByWorkspaceIDAndBuildNumber(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceBuildByWorkspaceIDAndBuildNumber", reflect.TypeOf((*MockStore)(nil).GetWorkspaceBuildByWorkspaceIDAndBuildNumber), arg0, arg1) +} + +// GetWorkspaceBuildParameters mocks base method. +func (m *MockStore) GetWorkspaceBuildParameters(arg0 context.Context, arg1 uuid.UUID) ([]database.WorkspaceBuildParameter, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceBuildParameters", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceBuildParameter) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceBuildParameters indicates an expected call of GetWorkspaceBuildParameters. +func (mr *MockStoreMockRecorder) GetWorkspaceBuildParameters(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceBuildParameters", reflect.TypeOf((*MockStore)(nil).GetWorkspaceBuildParameters), arg0, arg1) +} + +// GetWorkspaceBuildsByWorkspaceID mocks base method. +func (m *MockStore) GetWorkspaceBuildsByWorkspaceID(arg0 context.Context, arg1 database.GetWorkspaceBuildsByWorkspaceIDParams) ([]database.WorkspaceBuild, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceBuildsByWorkspaceID", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceBuild) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceBuildsByWorkspaceID indicates an expected call of GetWorkspaceBuildsByWorkspaceID. +func (mr *MockStoreMockRecorder) GetWorkspaceBuildsByWorkspaceID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceBuildsByWorkspaceID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceBuildsByWorkspaceID), arg0, arg1) +} + +// GetWorkspaceBuildsCreatedAfter mocks base method. +func (m *MockStore) GetWorkspaceBuildsCreatedAfter(arg0 context.Context, arg1 time.Time) ([]database.WorkspaceBuild, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceBuildsCreatedAfter", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceBuild) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceBuildsCreatedAfter indicates an expected call of GetWorkspaceBuildsCreatedAfter. +func (mr *MockStoreMockRecorder) GetWorkspaceBuildsCreatedAfter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceBuildsCreatedAfter", reflect.TypeOf((*MockStore)(nil).GetWorkspaceBuildsCreatedAfter), arg0, arg1) +} + +// GetWorkspaceByAgentID mocks base method. +func (m *MockStore) GetWorkspaceByAgentID(arg0 context.Context, arg1 uuid.UUID) (database.Workspace, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceByAgentID", arg0, arg1) + ret0, _ := ret[0].(database.Workspace) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceByAgentID indicates an expected call of GetWorkspaceByAgentID. +func (mr *MockStoreMockRecorder) GetWorkspaceByAgentID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceByAgentID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceByAgentID), arg0, arg1) +} + +// GetWorkspaceByID mocks base method. +func (m *MockStore) GetWorkspaceByID(arg0 context.Context, arg1 uuid.UUID) (database.Workspace, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceByID", arg0, arg1) + ret0, _ := ret[0].(database.Workspace) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceByID indicates an expected call of GetWorkspaceByID. +func (mr *MockStoreMockRecorder) GetWorkspaceByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceByID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceByID), arg0, arg1) +} + +// GetWorkspaceByOwnerIDAndName mocks base method. +func (m *MockStore) GetWorkspaceByOwnerIDAndName(arg0 context.Context, arg1 database.GetWorkspaceByOwnerIDAndNameParams) (database.Workspace, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceByOwnerIDAndName", arg0, arg1) + ret0, _ := ret[0].(database.Workspace) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceByOwnerIDAndName indicates an expected call of GetWorkspaceByOwnerIDAndName. +func (mr *MockStoreMockRecorder) GetWorkspaceByOwnerIDAndName(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceByOwnerIDAndName", reflect.TypeOf((*MockStore)(nil).GetWorkspaceByOwnerIDAndName), arg0, arg1) +} + +// GetWorkspaceByWorkspaceAppID mocks base method. +func (m *MockStore) GetWorkspaceByWorkspaceAppID(arg0 context.Context, arg1 uuid.UUID) (database.Workspace, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceByWorkspaceAppID", arg0, arg1) + ret0, _ := ret[0].(database.Workspace) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceByWorkspaceAppID indicates an expected call of GetWorkspaceByWorkspaceAppID. +func (mr *MockStoreMockRecorder) GetWorkspaceByWorkspaceAppID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceByWorkspaceAppID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceByWorkspaceAppID), arg0, arg1) +} + +// GetWorkspaceProxies mocks base method. +func (m *MockStore) GetWorkspaceProxies(arg0 context.Context) ([]database.WorkspaceProxy, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceProxies", arg0) + ret0, _ := ret[0].([]database.WorkspaceProxy) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceProxies indicates an expected call of GetWorkspaceProxies. +func (mr *MockStoreMockRecorder) GetWorkspaceProxies(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceProxies", reflect.TypeOf((*MockStore)(nil).GetWorkspaceProxies), arg0) +} + +// GetWorkspaceProxyByHostname mocks base method. +func (m *MockStore) GetWorkspaceProxyByHostname(arg0 context.Context, arg1 database.GetWorkspaceProxyByHostnameParams) (database.WorkspaceProxy, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceProxyByHostname", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceProxy) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceProxyByHostname indicates an expected call of GetWorkspaceProxyByHostname. +func (mr *MockStoreMockRecorder) GetWorkspaceProxyByHostname(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceProxyByHostname", reflect.TypeOf((*MockStore)(nil).GetWorkspaceProxyByHostname), arg0, arg1) +} + +// GetWorkspaceProxyByID mocks base method. +func (m *MockStore) GetWorkspaceProxyByID(arg0 context.Context, arg1 uuid.UUID) (database.WorkspaceProxy, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceProxyByID", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceProxy) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceProxyByID indicates an expected call of GetWorkspaceProxyByID. +func (mr *MockStoreMockRecorder) GetWorkspaceProxyByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceProxyByID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceProxyByID), arg0, arg1) +} + +// GetWorkspaceProxyByName mocks base method. +func (m *MockStore) GetWorkspaceProxyByName(arg0 context.Context, arg1 string) (database.WorkspaceProxy, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceProxyByName", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceProxy) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceProxyByName indicates an expected call of GetWorkspaceProxyByName. +func (mr *MockStoreMockRecorder) GetWorkspaceProxyByName(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceProxyByName", reflect.TypeOf((*MockStore)(nil).GetWorkspaceProxyByName), arg0, arg1) +} + +// GetWorkspaceResourceByID mocks base method. +func (m *MockStore) GetWorkspaceResourceByID(arg0 context.Context, arg1 uuid.UUID) (database.WorkspaceResource, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceResourceByID", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceResource) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceResourceByID indicates an expected call of GetWorkspaceResourceByID. +func (mr *MockStoreMockRecorder) GetWorkspaceResourceByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceResourceByID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceResourceByID), arg0, arg1) +} + +// GetWorkspaceResourceMetadataByResourceIDs mocks base method. +func (m *MockStore) GetWorkspaceResourceMetadataByResourceIDs(arg0 context.Context, arg1 []uuid.UUID) ([]database.WorkspaceResourceMetadatum, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceResourceMetadataByResourceIDs", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceResourceMetadatum) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceResourceMetadataByResourceIDs indicates an expected call of GetWorkspaceResourceMetadataByResourceIDs. +func (mr *MockStoreMockRecorder) GetWorkspaceResourceMetadataByResourceIDs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceResourceMetadataByResourceIDs", reflect.TypeOf((*MockStore)(nil).GetWorkspaceResourceMetadataByResourceIDs), arg0, arg1) +} + +// GetWorkspaceResourceMetadataCreatedAfter mocks base method. +func (m *MockStore) GetWorkspaceResourceMetadataCreatedAfter(arg0 context.Context, arg1 time.Time) ([]database.WorkspaceResourceMetadatum, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceResourceMetadataCreatedAfter", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceResourceMetadatum) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceResourceMetadataCreatedAfter indicates an expected call of GetWorkspaceResourceMetadataCreatedAfter. +func (mr *MockStoreMockRecorder) GetWorkspaceResourceMetadataCreatedAfter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceResourceMetadataCreatedAfter", reflect.TypeOf((*MockStore)(nil).GetWorkspaceResourceMetadataCreatedAfter), arg0, arg1) +} + +// GetWorkspaceResourcesByJobID mocks base method. +func (m *MockStore) GetWorkspaceResourcesByJobID(arg0 context.Context, arg1 uuid.UUID) ([]database.WorkspaceResource, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceResourcesByJobID", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceResource) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceResourcesByJobID indicates an expected call of GetWorkspaceResourcesByJobID. +func (mr *MockStoreMockRecorder) GetWorkspaceResourcesByJobID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceResourcesByJobID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceResourcesByJobID), arg0, arg1) +} + +// GetWorkspaceResourcesByJobIDs mocks base method. +func (m *MockStore) GetWorkspaceResourcesByJobIDs(arg0 context.Context, arg1 []uuid.UUID) ([]database.WorkspaceResource, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceResourcesByJobIDs", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceResource) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceResourcesByJobIDs indicates an expected call of GetWorkspaceResourcesByJobIDs. +func (mr *MockStoreMockRecorder) GetWorkspaceResourcesByJobIDs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceResourcesByJobIDs", reflect.TypeOf((*MockStore)(nil).GetWorkspaceResourcesByJobIDs), arg0, arg1) +} + +// GetWorkspaceResourcesCreatedAfter mocks base method. +func (m *MockStore) GetWorkspaceResourcesCreatedAfter(arg0 context.Context, arg1 time.Time) ([]database.WorkspaceResource, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaceResourcesCreatedAfter", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceResource) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaceResourcesCreatedAfter indicates an expected call of GetWorkspaceResourcesCreatedAfter. +func (mr *MockStoreMockRecorder) GetWorkspaceResourcesCreatedAfter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceResourcesCreatedAfter", reflect.TypeOf((*MockStore)(nil).GetWorkspaceResourcesCreatedAfter), arg0, arg1) +} + +// GetWorkspaces mocks base method. +func (m *MockStore) GetWorkspaces(arg0 context.Context, arg1 database.GetWorkspacesParams) ([]database.GetWorkspacesRow, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspaces", arg0, arg1) + ret0, _ := ret[0].([]database.GetWorkspacesRow) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspaces indicates an expected call of GetWorkspaces. +func (mr *MockStoreMockRecorder) GetWorkspaces(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaces", reflect.TypeOf((*MockStore)(nil).GetWorkspaces), arg0, arg1) +} + +// GetWorkspacesEligibleForAutoStartStop mocks base method. +func (m *MockStore) GetWorkspacesEligibleForAutoStartStop(arg0 context.Context, arg1 time.Time) ([]database.Workspace, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetWorkspacesEligibleForAutoStartStop", arg0, arg1) + ret0, _ := ret[0].([]database.Workspace) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetWorkspacesEligibleForAutoStartStop indicates an expected call of GetWorkspacesEligibleForAutoStartStop. +func (mr *MockStoreMockRecorder) GetWorkspacesEligibleForAutoStartStop(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspacesEligibleForAutoStartStop", reflect.TypeOf((*MockStore)(nil).GetWorkspacesEligibleForAutoStartStop), arg0, arg1) +} + +// InTx mocks base method. +func (m *MockStore) InTx(arg0 func(database.Store) error, arg1 *sql.TxOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InTx", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// InTx indicates an expected call of InTx. +func (mr *MockStoreMockRecorder) InTx(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InTx", reflect.TypeOf((*MockStore)(nil).InTx), arg0, arg1) +} + +// InsertAPIKey mocks base method. +func (m *MockStore) InsertAPIKey(arg0 context.Context, arg1 database.InsertAPIKeyParams) (database.APIKey, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertAPIKey", arg0, arg1) + ret0, _ := ret[0].(database.APIKey) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertAPIKey indicates an expected call of InsertAPIKey. +func (mr *MockStoreMockRecorder) InsertAPIKey(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertAPIKey", reflect.TypeOf((*MockStore)(nil).InsertAPIKey), arg0, arg1) +} + +// InsertAllUsersGroup mocks base method. +func (m *MockStore) InsertAllUsersGroup(arg0 context.Context, arg1 uuid.UUID) (database.Group, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertAllUsersGroup", arg0, arg1) + ret0, _ := ret[0].(database.Group) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertAllUsersGroup indicates an expected call of InsertAllUsersGroup. +func (mr *MockStoreMockRecorder) InsertAllUsersGroup(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertAllUsersGroup", reflect.TypeOf((*MockStore)(nil).InsertAllUsersGroup), arg0, arg1) +} + +// InsertAuditLog mocks base method. +func (m *MockStore) InsertAuditLog(arg0 context.Context, arg1 database.InsertAuditLogParams) (database.AuditLog, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertAuditLog", arg0, arg1) + ret0, _ := ret[0].(database.AuditLog) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertAuditLog indicates an expected call of InsertAuditLog. +func (mr *MockStoreMockRecorder) InsertAuditLog(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertAuditLog", reflect.TypeOf((*MockStore)(nil).InsertAuditLog), arg0, arg1) +} + +// InsertDERPMeshKey mocks base method. +func (m *MockStore) InsertDERPMeshKey(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertDERPMeshKey", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// InsertDERPMeshKey indicates an expected call of InsertDERPMeshKey. +func (mr *MockStoreMockRecorder) InsertDERPMeshKey(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertDERPMeshKey", reflect.TypeOf((*MockStore)(nil).InsertDERPMeshKey), arg0, arg1) +} + +// InsertDeploymentID mocks base method. +func (m *MockStore) InsertDeploymentID(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertDeploymentID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// InsertDeploymentID indicates an expected call of InsertDeploymentID. +func (mr *MockStoreMockRecorder) InsertDeploymentID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertDeploymentID", reflect.TypeOf((*MockStore)(nil).InsertDeploymentID), arg0, arg1) +} + +// InsertFile mocks base method. +func (m *MockStore) InsertFile(arg0 context.Context, arg1 database.InsertFileParams) (database.File, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertFile", arg0, arg1) + ret0, _ := ret[0].(database.File) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertFile indicates an expected call of InsertFile. +func (mr *MockStoreMockRecorder) InsertFile(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertFile", reflect.TypeOf((*MockStore)(nil).InsertFile), arg0, arg1) +} + +// InsertGitAuthLink mocks base method. +func (m *MockStore) InsertGitAuthLink(arg0 context.Context, arg1 database.InsertGitAuthLinkParams) (database.GitAuthLink, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertGitAuthLink", arg0, arg1) + ret0, _ := ret[0].(database.GitAuthLink) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertGitAuthLink indicates an expected call of InsertGitAuthLink. +func (mr *MockStoreMockRecorder) InsertGitAuthLink(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertGitAuthLink", reflect.TypeOf((*MockStore)(nil).InsertGitAuthLink), arg0, arg1) +} + +// InsertGitSSHKey mocks base method. +func (m *MockStore) InsertGitSSHKey(arg0 context.Context, arg1 database.InsertGitSSHKeyParams) (database.GitSSHKey, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertGitSSHKey", arg0, arg1) + ret0, _ := ret[0].(database.GitSSHKey) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertGitSSHKey indicates an expected call of InsertGitSSHKey. +func (mr *MockStoreMockRecorder) InsertGitSSHKey(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertGitSSHKey", reflect.TypeOf((*MockStore)(nil).InsertGitSSHKey), arg0, arg1) +} + +// InsertGroup mocks base method. +func (m *MockStore) InsertGroup(arg0 context.Context, arg1 database.InsertGroupParams) (database.Group, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertGroup", arg0, arg1) + ret0, _ := ret[0].(database.Group) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertGroup indicates an expected call of InsertGroup. +func (mr *MockStoreMockRecorder) InsertGroup(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertGroup", reflect.TypeOf((*MockStore)(nil).InsertGroup), arg0, arg1) +} + +// InsertGroupMember mocks base method. +func (m *MockStore) InsertGroupMember(arg0 context.Context, arg1 database.InsertGroupMemberParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertGroupMember", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// InsertGroupMember indicates an expected call of InsertGroupMember. +func (mr *MockStoreMockRecorder) InsertGroupMember(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertGroupMember", reflect.TypeOf((*MockStore)(nil).InsertGroupMember), arg0, arg1) +} + +// InsertLicense mocks base method. +func (m *MockStore) InsertLicense(arg0 context.Context, arg1 database.InsertLicenseParams) (database.License, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertLicense", arg0, arg1) + ret0, _ := ret[0].(database.License) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertLicense indicates an expected call of InsertLicense. +func (mr *MockStoreMockRecorder) InsertLicense(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertLicense", reflect.TypeOf((*MockStore)(nil).InsertLicense), arg0, arg1) +} + +// InsertOrganization mocks base method. +func (m *MockStore) InsertOrganization(arg0 context.Context, arg1 database.InsertOrganizationParams) (database.Organization, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertOrganization", arg0, arg1) + ret0, _ := ret[0].(database.Organization) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertOrganization indicates an expected call of InsertOrganization. +func (mr *MockStoreMockRecorder) InsertOrganization(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertOrganization", reflect.TypeOf((*MockStore)(nil).InsertOrganization), arg0, arg1) +} + +// InsertOrganizationMember mocks base method. +func (m *MockStore) InsertOrganizationMember(arg0 context.Context, arg1 database.InsertOrganizationMemberParams) (database.OrganizationMember, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertOrganizationMember", arg0, arg1) + ret0, _ := ret[0].(database.OrganizationMember) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertOrganizationMember indicates an expected call of InsertOrganizationMember. +func (mr *MockStoreMockRecorder) InsertOrganizationMember(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertOrganizationMember", reflect.TypeOf((*MockStore)(nil).InsertOrganizationMember), arg0, arg1) +} + +// InsertParameterSchema mocks base method. +func (m *MockStore) InsertParameterSchema(arg0 context.Context, arg1 database.InsertParameterSchemaParams) (database.ParameterSchema, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertParameterSchema", arg0, arg1) + ret0, _ := ret[0].(database.ParameterSchema) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertParameterSchema indicates an expected call of InsertParameterSchema. +func (mr *MockStoreMockRecorder) InsertParameterSchema(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertParameterSchema", reflect.TypeOf((*MockStore)(nil).InsertParameterSchema), arg0, arg1) +} + +// InsertParameterValue mocks base method. +func (m *MockStore) InsertParameterValue(arg0 context.Context, arg1 database.InsertParameterValueParams) (database.ParameterValue, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertParameterValue", arg0, arg1) + ret0, _ := ret[0].(database.ParameterValue) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertParameterValue indicates an expected call of InsertParameterValue. +func (mr *MockStoreMockRecorder) InsertParameterValue(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertParameterValue", reflect.TypeOf((*MockStore)(nil).InsertParameterValue), arg0, arg1) +} + +// InsertProvisionerDaemon mocks base method. +func (m *MockStore) InsertProvisionerDaemon(arg0 context.Context, arg1 database.InsertProvisionerDaemonParams) (database.ProvisionerDaemon, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertProvisionerDaemon", arg0, arg1) + ret0, _ := ret[0].(database.ProvisionerDaemon) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertProvisionerDaemon indicates an expected call of InsertProvisionerDaemon. +func (mr *MockStoreMockRecorder) InsertProvisionerDaemon(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertProvisionerDaemon", reflect.TypeOf((*MockStore)(nil).InsertProvisionerDaemon), arg0, arg1) +} + +// InsertProvisionerJob mocks base method. +func (m *MockStore) InsertProvisionerJob(arg0 context.Context, arg1 database.InsertProvisionerJobParams) (database.ProvisionerJob, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertProvisionerJob", arg0, arg1) + ret0, _ := ret[0].(database.ProvisionerJob) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertProvisionerJob indicates an expected call of InsertProvisionerJob. +func (mr *MockStoreMockRecorder) InsertProvisionerJob(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertProvisionerJob", reflect.TypeOf((*MockStore)(nil).InsertProvisionerJob), arg0, arg1) +} + +// InsertProvisionerJobLogs mocks base method. +func (m *MockStore) InsertProvisionerJobLogs(arg0 context.Context, arg1 database.InsertProvisionerJobLogsParams) ([]database.ProvisionerJobLog, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertProvisionerJobLogs", arg0, arg1) + ret0, _ := ret[0].([]database.ProvisionerJobLog) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertProvisionerJobLogs indicates an expected call of InsertProvisionerJobLogs. +func (mr *MockStoreMockRecorder) InsertProvisionerJobLogs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertProvisionerJobLogs", reflect.TypeOf((*MockStore)(nil).InsertProvisionerJobLogs), arg0, arg1) +} + +// InsertReplica mocks base method. +func (m *MockStore) InsertReplica(arg0 context.Context, arg1 database.InsertReplicaParams) (database.Replica, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertReplica", arg0, arg1) + ret0, _ := ret[0].(database.Replica) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertReplica indicates an expected call of InsertReplica. +func (mr *MockStoreMockRecorder) InsertReplica(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertReplica", reflect.TypeOf((*MockStore)(nil).InsertReplica), arg0, arg1) +} + +// InsertTemplate mocks base method. +func (m *MockStore) InsertTemplate(arg0 context.Context, arg1 database.InsertTemplateParams) (database.Template, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertTemplate", arg0, arg1) + ret0, _ := ret[0].(database.Template) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertTemplate indicates an expected call of InsertTemplate. +func (mr *MockStoreMockRecorder) InsertTemplate(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertTemplate", reflect.TypeOf((*MockStore)(nil).InsertTemplate), arg0, arg1) +} + +// InsertTemplateVersion mocks base method. +func (m *MockStore) InsertTemplateVersion(arg0 context.Context, arg1 database.InsertTemplateVersionParams) (database.TemplateVersion, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertTemplateVersion", arg0, arg1) + ret0, _ := ret[0].(database.TemplateVersion) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertTemplateVersion indicates an expected call of InsertTemplateVersion. +func (mr *MockStoreMockRecorder) InsertTemplateVersion(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertTemplateVersion", reflect.TypeOf((*MockStore)(nil).InsertTemplateVersion), arg0, arg1) +} + +// InsertTemplateVersionParameter mocks base method. +func (m *MockStore) InsertTemplateVersionParameter(arg0 context.Context, arg1 database.InsertTemplateVersionParameterParams) (database.TemplateVersionParameter, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertTemplateVersionParameter", arg0, arg1) + ret0, _ := ret[0].(database.TemplateVersionParameter) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertTemplateVersionParameter indicates an expected call of InsertTemplateVersionParameter. +func (mr *MockStoreMockRecorder) InsertTemplateVersionParameter(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertTemplateVersionParameter", reflect.TypeOf((*MockStore)(nil).InsertTemplateVersionParameter), arg0, arg1) +} + +// InsertTemplateVersionVariable mocks base method. +func (m *MockStore) InsertTemplateVersionVariable(arg0 context.Context, arg1 database.InsertTemplateVersionVariableParams) (database.TemplateVersionVariable, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertTemplateVersionVariable", arg0, arg1) + ret0, _ := ret[0].(database.TemplateVersionVariable) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertTemplateVersionVariable indicates an expected call of InsertTemplateVersionVariable. +func (mr *MockStoreMockRecorder) InsertTemplateVersionVariable(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertTemplateVersionVariable", reflect.TypeOf((*MockStore)(nil).InsertTemplateVersionVariable), arg0, arg1) +} + +// InsertUser mocks base method. +func (m *MockStore) InsertUser(arg0 context.Context, arg1 database.InsertUserParams) (database.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertUser", arg0, arg1) + ret0, _ := ret[0].(database.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertUser indicates an expected call of InsertUser. +func (mr *MockStoreMockRecorder) InsertUser(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertUser", reflect.TypeOf((*MockStore)(nil).InsertUser), arg0, arg1) +} + +// InsertUserGroupsByName mocks base method. +func (m *MockStore) InsertUserGroupsByName(arg0 context.Context, arg1 database.InsertUserGroupsByNameParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertUserGroupsByName", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// InsertUserGroupsByName indicates an expected call of InsertUserGroupsByName. +func (mr *MockStoreMockRecorder) InsertUserGroupsByName(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertUserGroupsByName", reflect.TypeOf((*MockStore)(nil).InsertUserGroupsByName), arg0, arg1) +} + +// InsertUserLink mocks base method. +func (m *MockStore) InsertUserLink(arg0 context.Context, arg1 database.InsertUserLinkParams) (database.UserLink, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertUserLink", arg0, arg1) + ret0, _ := ret[0].(database.UserLink) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertUserLink indicates an expected call of InsertUserLink. +func (mr *MockStoreMockRecorder) InsertUserLink(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertUserLink", reflect.TypeOf((*MockStore)(nil).InsertUserLink), arg0, arg1) +} + +// InsertWorkspace mocks base method. +func (m *MockStore) InsertWorkspace(arg0 context.Context, arg1 database.InsertWorkspaceParams) (database.Workspace, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertWorkspace", arg0, arg1) + ret0, _ := ret[0].(database.Workspace) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertWorkspace indicates an expected call of InsertWorkspace. +func (mr *MockStoreMockRecorder) InsertWorkspace(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspace", reflect.TypeOf((*MockStore)(nil).InsertWorkspace), arg0, arg1) +} + +// InsertWorkspaceAgent mocks base method. +func (m *MockStore) InsertWorkspaceAgent(arg0 context.Context, arg1 database.InsertWorkspaceAgentParams) (database.WorkspaceAgent, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertWorkspaceAgent", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceAgent) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertWorkspaceAgent indicates an expected call of InsertWorkspaceAgent. +func (mr *MockStoreMockRecorder) InsertWorkspaceAgent(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspaceAgent", reflect.TypeOf((*MockStore)(nil).InsertWorkspaceAgent), arg0, arg1) +} + +// InsertWorkspaceAgentMetadata mocks base method. +func (m *MockStore) InsertWorkspaceAgentMetadata(arg0 context.Context, arg1 database.InsertWorkspaceAgentMetadataParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertWorkspaceAgentMetadata", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// InsertWorkspaceAgentMetadata indicates an expected call of InsertWorkspaceAgentMetadata. +func (mr *MockStoreMockRecorder) InsertWorkspaceAgentMetadata(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspaceAgentMetadata", reflect.TypeOf((*MockStore)(nil).InsertWorkspaceAgentMetadata), arg0, arg1) +} + +// InsertWorkspaceAgentStartupLogs mocks base method. +func (m *MockStore) InsertWorkspaceAgentStartupLogs(arg0 context.Context, arg1 database.InsertWorkspaceAgentStartupLogsParams) ([]database.WorkspaceAgentStartupLog, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertWorkspaceAgentStartupLogs", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceAgentStartupLog) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertWorkspaceAgentStartupLogs indicates an expected call of InsertWorkspaceAgentStartupLogs. +func (mr *MockStoreMockRecorder) InsertWorkspaceAgentStartupLogs(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspaceAgentStartupLogs", reflect.TypeOf((*MockStore)(nil).InsertWorkspaceAgentStartupLogs), arg0, arg1) +} + +// InsertWorkspaceAgentStat mocks base method. +func (m *MockStore) InsertWorkspaceAgentStat(arg0 context.Context, arg1 database.InsertWorkspaceAgentStatParams) (database.WorkspaceAgentStat, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertWorkspaceAgentStat", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceAgentStat) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertWorkspaceAgentStat indicates an expected call of InsertWorkspaceAgentStat. +func (mr *MockStoreMockRecorder) InsertWorkspaceAgentStat(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspaceAgentStat", reflect.TypeOf((*MockStore)(nil).InsertWorkspaceAgentStat), arg0, arg1) +} + +// InsertWorkspaceApp mocks base method. +func (m *MockStore) InsertWorkspaceApp(arg0 context.Context, arg1 database.InsertWorkspaceAppParams) (database.WorkspaceApp, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertWorkspaceApp", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceApp) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertWorkspaceApp indicates an expected call of InsertWorkspaceApp. +func (mr *MockStoreMockRecorder) InsertWorkspaceApp(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspaceApp", reflect.TypeOf((*MockStore)(nil).InsertWorkspaceApp), arg0, arg1) +} + +// InsertWorkspaceBuild mocks base method. +func (m *MockStore) InsertWorkspaceBuild(arg0 context.Context, arg1 database.InsertWorkspaceBuildParams) (database.WorkspaceBuild, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertWorkspaceBuild", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceBuild) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertWorkspaceBuild indicates an expected call of InsertWorkspaceBuild. +func (mr *MockStoreMockRecorder) InsertWorkspaceBuild(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspaceBuild", reflect.TypeOf((*MockStore)(nil).InsertWorkspaceBuild), arg0, arg1) +} + +// InsertWorkspaceBuildParameters mocks base method. +func (m *MockStore) InsertWorkspaceBuildParameters(arg0 context.Context, arg1 database.InsertWorkspaceBuildParametersParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertWorkspaceBuildParameters", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// InsertWorkspaceBuildParameters indicates an expected call of InsertWorkspaceBuildParameters. +func (mr *MockStoreMockRecorder) InsertWorkspaceBuildParameters(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspaceBuildParameters", reflect.TypeOf((*MockStore)(nil).InsertWorkspaceBuildParameters), arg0, arg1) +} + +// InsertWorkspaceProxy mocks base method. +func (m *MockStore) InsertWorkspaceProxy(arg0 context.Context, arg1 database.InsertWorkspaceProxyParams) (database.WorkspaceProxy, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertWorkspaceProxy", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceProxy) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertWorkspaceProxy indicates an expected call of InsertWorkspaceProxy. +func (mr *MockStoreMockRecorder) InsertWorkspaceProxy(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspaceProxy", reflect.TypeOf((*MockStore)(nil).InsertWorkspaceProxy), arg0, arg1) +} + +// InsertWorkspaceResource mocks base method. +func (m *MockStore) InsertWorkspaceResource(arg0 context.Context, arg1 database.InsertWorkspaceResourceParams) (database.WorkspaceResource, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertWorkspaceResource", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceResource) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertWorkspaceResource indicates an expected call of InsertWorkspaceResource. +func (mr *MockStoreMockRecorder) InsertWorkspaceResource(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspaceResource", reflect.TypeOf((*MockStore)(nil).InsertWorkspaceResource), arg0, arg1) +} + +// InsertWorkspaceResourceMetadata mocks base method. +func (m *MockStore) InsertWorkspaceResourceMetadata(arg0 context.Context, arg1 database.InsertWorkspaceResourceMetadataParams) ([]database.WorkspaceResourceMetadatum, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertWorkspaceResourceMetadata", arg0, arg1) + ret0, _ := ret[0].([]database.WorkspaceResourceMetadatum) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertWorkspaceResourceMetadata indicates an expected call of InsertWorkspaceResourceMetadata. +func (mr *MockStoreMockRecorder) InsertWorkspaceResourceMetadata(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertWorkspaceResourceMetadata", reflect.TypeOf((*MockStore)(nil).InsertWorkspaceResourceMetadata), arg0, arg1) +} + +// ParameterValue mocks base method. +func (m *MockStore) ParameterValue(arg0 context.Context, arg1 uuid.UUID) (database.ParameterValue, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParameterValue", arg0, arg1) + ret0, _ := ret[0].(database.ParameterValue) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParameterValue indicates an expected call of ParameterValue. +func (mr *MockStoreMockRecorder) ParameterValue(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParameterValue", reflect.TypeOf((*MockStore)(nil).ParameterValue), arg0, arg1) +} + +// ParameterValues mocks base method. +func (m *MockStore) ParameterValues(arg0 context.Context, arg1 database.ParameterValuesParams) ([]database.ParameterValue, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ParameterValues", arg0, arg1) + ret0, _ := ret[0].([]database.ParameterValue) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ParameterValues indicates an expected call of ParameterValues. +func (mr *MockStoreMockRecorder) ParameterValues(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParameterValues", reflect.TypeOf((*MockStore)(nil).ParameterValues), arg0, arg1) +} + +// Ping mocks base method. +func (m *MockStore) Ping(arg0 context.Context) (time.Duration, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Ping", arg0) + ret0, _ := ret[0].(time.Duration) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Ping indicates an expected call of Ping. +func (mr *MockStoreMockRecorder) Ping(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ping", reflect.TypeOf((*MockStore)(nil).Ping), arg0) +} + +// RegisterWorkspaceProxy mocks base method. +func (m *MockStore) RegisterWorkspaceProxy(arg0 context.Context, arg1 database.RegisterWorkspaceProxyParams) (database.WorkspaceProxy, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RegisterWorkspaceProxy", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceProxy) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RegisterWorkspaceProxy indicates an expected call of RegisterWorkspaceProxy. +func (mr *MockStoreMockRecorder) RegisterWorkspaceProxy(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterWorkspaceProxy", reflect.TypeOf((*MockStore)(nil).RegisterWorkspaceProxy), arg0, arg1) +} + +// TryAcquireLock mocks base method. +func (m *MockStore) TryAcquireLock(arg0 context.Context, arg1 int64) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "TryAcquireLock", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// TryAcquireLock indicates an expected call of TryAcquireLock. +func (mr *MockStoreMockRecorder) TryAcquireLock(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TryAcquireLock", reflect.TypeOf((*MockStore)(nil).TryAcquireLock), arg0, arg1) +} + +// UpdateAPIKeyByID mocks base method. +func (m *MockStore) UpdateAPIKeyByID(arg0 context.Context, arg1 database.UpdateAPIKeyByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateAPIKeyByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateAPIKeyByID indicates an expected call of UpdateAPIKeyByID. +func (mr *MockStoreMockRecorder) UpdateAPIKeyByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAPIKeyByID", reflect.TypeOf((*MockStore)(nil).UpdateAPIKeyByID), arg0, arg1) +} + +// UpdateGitAuthLink mocks base method. +func (m *MockStore) UpdateGitAuthLink(arg0 context.Context, arg1 database.UpdateGitAuthLinkParams) (database.GitAuthLink, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateGitAuthLink", arg0, arg1) + ret0, _ := ret[0].(database.GitAuthLink) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateGitAuthLink indicates an expected call of UpdateGitAuthLink. +func (mr *MockStoreMockRecorder) UpdateGitAuthLink(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateGitAuthLink", reflect.TypeOf((*MockStore)(nil).UpdateGitAuthLink), arg0, arg1) +} + +// UpdateGitSSHKey mocks base method. +func (m *MockStore) UpdateGitSSHKey(arg0 context.Context, arg1 database.UpdateGitSSHKeyParams) (database.GitSSHKey, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateGitSSHKey", arg0, arg1) + ret0, _ := ret[0].(database.GitSSHKey) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateGitSSHKey indicates an expected call of UpdateGitSSHKey. +func (mr *MockStoreMockRecorder) UpdateGitSSHKey(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateGitSSHKey", reflect.TypeOf((*MockStore)(nil).UpdateGitSSHKey), arg0, arg1) +} + +// UpdateGroupByID mocks base method. +func (m *MockStore) UpdateGroupByID(arg0 context.Context, arg1 database.UpdateGroupByIDParams) (database.Group, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateGroupByID", arg0, arg1) + ret0, _ := ret[0].(database.Group) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateGroupByID indicates an expected call of UpdateGroupByID. +func (mr *MockStoreMockRecorder) UpdateGroupByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateGroupByID", reflect.TypeOf((*MockStore)(nil).UpdateGroupByID), arg0, arg1) +} + +// UpdateMemberRoles mocks base method. +func (m *MockStore) UpdateMemberRoles(arg0 context.Context, arg1 database.UpdateMemberRolesParams) (database.OrganizationMember, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateMemberRoles", arg0, arg1) + ret0, _ := ret[0].(database.OrganizationMember) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateMemberRoles indicates an expected call of UpdateMemberRoles. +func (mr *MockStoreMockRecorder) UpdateMemberRoles(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateMemberRoles", reflect.TypeOf((*MockStore)(nil).UpdateMemberRoles), arg0, arg1) +} + +// UpdateProvisionerJobByID mocks base method. +func (m *MockStore) UpdateProvisionerJobByID(arg0 context.Context, arg1 database.UpdateProvisionerJobByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateProvisionerJobByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateProvisionerJobByID indicates an expected call of UpdateProvisionerJobByID. +func (mr *MockStoreMockRecorder) UpdateProvisionerJobByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateProvisionerJobByID", reflect.TypeOf((*MockStore)(nil).UpdateProvisionerJobByID), arg0, arg1) +} + +// UpdateProvisionerJobWithCancelByID mocks base method. +func (m *MockStore) UpdateProvisionerJobWithCancelByID(arg0 context.Context, arg1 database.UpdateProvisionerJobWithCancelByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateProvisionerJobWithCancelByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateProvisionerJobWithCancelByID indicates an expected call of UpdateProvisionerJobWithCancelByID. +func (mr *MockStoreMockRecorder) UpdateProvisionerJobWithCancelByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateProvisionerJobWithCancelByID", reflect.TypeOf((*MockStore)(nil).UpdateProvisionerJobWithCancelByID), arg0, arg1) +} + +// UpdateProvisionerJobWithCompleteByID mocks base method. +func (m *MockStore) UpdateProvisionerJobWithCompleteByID(arg0 context.Context, arg1 database.UpdateProvisionerJobWithCompleteByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateProvisionerJobWithCompleteByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateProvisionerJobWithCompleteByID indicates an expected call of UpdateProvisionerJobWithCompleteByID. +func (mr *MockStoreMockRecorder) UpdateProvisionerJobWithCompleteByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateProvisionerJobWithCompleteByID", reflect.TypeOf((*MockStore)(nil).UpdateProvisionerJobWithCompleteByID), arg0, arg1) +} + +// UpdateReplica mocks base method. +func (m *MockStore) UpdateReplica(arg0 context.Context, arg1 database.UpdateReplicaParams) (database.Replica, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateReplica", arg0, arg1) + ret0, _ := ret[0].(database.Replica) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateReplica indicates an expected call of UpdateReplica. +func (mr *MockStoreMockRecorder) UpdateReplica(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateReplica", reflect.TypeOf((*MockStore)(nil).UpdateReplica), arg0, arg1) +} + +// UpdateTemplateACLByID mocks base method. +func (m *MockStore) UpdateTemplateACLByID(arg0 context.Context, arg1 database.UpdateTemplateACLByIDParams) (database.Template, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateTemplateACLByID", arg0, arg1) + ret0, _ := ret[0].(database.Template) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateTemplateACLByID indicates an expected call of UpdateTemplateACLByID. +func (mr *MockStoreMockRecorder) UpdateTemplateACLByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTemplateACLByID", reflect.TypeOf((*MockStore)(nil).UpdateTemplateACLByID), arg0, arg1) +} + +// UpdateTemplateActiveVersionByID mocks base method. +func (m *MockStore) UpdateTemplateActiveVersionByID(arg0 context.Context, arg1 database.UpdateTemplateActiveVersionByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateTemplateActiveVersionByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateTemplateActiveVersionByID indicates an expected call of UpdateTemplateActiveVersionByID. +func (mr *MockStoreMockRecorder) UpdateTemplateActiveVersionByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTemplateActiveVersionByID", reflect.TypeOf((*MockStore)(nil).UpdateTemplateActiveVersionByID), arg0, arg1) +} + +// UpdateTemplateDeletedByID mocks base method. +func (m *MockStore) UpdateTemplateDeletedByID(arg0 context.Context, arg1 database.UpdateTemplateDeletedByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateTemplateDeletedByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateTemplateDeletedByID indicates an expected call of UpdateTemplateDeletedByID. +func (mr *MockStoreMockRecorder) UpdateTemplateDeletedByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTemplateDeletedByID", reflect.TypeOf((*MockStore)(nil).UpdateTemplateDeletedByID), arg0, arg1) +} + +// UpdateTemplateMetaByID mocks base method. +func (m *MockStore) UpdateTemplateMetaByID(arg0 context.Context, arg1 database.UpdateTemplateMetaByIDParams) (database.Template, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateTemplateMetaByID", arg0, arg1) + ret0, _ := ret[0].(database.Template) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateTemplateMetaByID indicates an expected call of UpdateTemplateMetaByID. +func (mr *MockStoreMockRecorder) UpdateTemplateMetaByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTemplateMetaByID", reflect.TypeOf((*MockStore)(nil).UpdateTemplateMetaByID), arg0, arg1) +} + +// UpdateTemplateScheduleByID mocks base method. +func (m *MockStore) UpdateTemplateScheduleByID(arg0 context.Context, arg1 database.UpdateTemplateScheduleByIDParams) (database.Template, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateTemplateScheduleByID", arg0, arg1) + ret0, _ := ret[0].(database.Template) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateTemplateScheduleByID indicates an expected call of UpdateTemplateScheduleByID. +func (mr *MockStoreMockRecorder) UpdateTemplateScheduleByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTemplateScheduleByID", reflect.TypeOf((*MockStore)(nil).UpdateTemplateScheduleByID), arg0, arg1) +} + +// UpdateTemplateVersionByID mocks base method. +func (m *MockStore) UpdateTemplateVersionByID(arg0 context.Context, arg1 database.UpdateTemplateVersionByIDParams) (database.TemplateVersion, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateTemplateVersionByID", arg0, arg1) + ret0, _ := ret[0].(database.TemplateVersion) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateTemplateVersionByID indicates an expected call of UpdateTemplateVersionByID. +func (mr *MockStoreMockRecorder) UpdateTemplateVersionByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTemplateVersionByID", reflect.TypeOf((*MockStore)(nil).UpdateTemplateVersionByID), arg0, arg1) +} + +// UpdateTemplateVersionDescriptionByJobID mocks base method. +func (m *MockStore) UpdateTemplateVersionDescriptionByJobID(arg0 context.Context, arg1 database.UpdateTemplateVersionDescriptionByJobIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateTemplateVersionDescriptionByJobID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateTemplateVersionDescriptionByJobID indicates an expected call of UpdateTemplateVersionDescriptionByJobID. +func (mr *MockStoreMockRecorder) UpdateTemplateVersionDescriptionByJobID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTemplateVersionDescriptionByJobID", reflect.TypeOf((*MockStore)(nil).UpdateTemplateVersionDescriptionByJobID), arg0, arg1) +} + +// UpdateTemplateVersionGitAuthProvidersByJobID mocks base method. +func (m *MockStore) UpdateTemplateVersionGitAuthProvidersByJobID(arg0 context.Context, arg1 database.UpdateTemplateVersionGitAuthProvidersByJobIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateTemplateVersionGitAuthProvidersByJobID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateTemplateVersionGitAuthProvidersByJobID indicates an expected call of UpdateTemplateVersionGitAuthProvidersByJobID. +func (mr *MockStoreMockRecorder) UpdateTemplateVersionGitAuthProvidersByJobID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTemplateVersionGitAuthProvidersByJobID", reflect.TypeOf((*MockStore)(nil).UpdateTemplateVersionGitAuthProvidersByJobID), arg0, arg1) +} + +// UpdateUserDeletedByID mocks base method. +func (m *MockStore) UpdateUserDeletedByID(arg0 context.Context, arg1 database.UpdateUserDeletedByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserDeletedByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateUserDeletedByID indicates an expected call of UpdateUserDeletedByID. +func (mr *MockStoreMockRecorder) UpdateUserDeletedByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserDeletedByID", reflect.TypeOf((*MockStore)(nil).UpdateUserDeletedByID), arg0, arg1) +} + +// UpdateUserHashedPassword mocks base method. +func (m *MockStore) UpdateUserHashedPassword(arg0 context.Context, arg1 database.UpdateUserHashedPasswordParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserHashedPassword", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateUserHashedPassword indicates an expected call of UpdateUserHashedPassword. +func (mr *MockStoreMockRecorder) UpdateUserHashedPassword(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserHashedPassword", reflect.TypeOf((*MockStore)(nil).UpdateUserHashedPassword), arg0, arg1) +} + +// UpdateUserLastSeenAt mocks base method. +func (m *MockStore) UpdateUserLastSeenAt(arg0 context.Context, arg1 database.UpdateUserLastSeenAtParams) (database.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserLastSeenAt", arg0, arg1) + ret0, _ := ret[0].(database.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateUserLastSeenAt indicates an expected call of UpdateUserLastSeenAt. +func (mr *MockStoreMockRecorder) UpdateUserLastSeenAt(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserLastSeenAt", reflect.TypeOf((*MockStore)(nil).UpdateUserLastSeenAt), arg0, arg1) +} + +// UpdateUserLink mocks base method. +func (m *MockStore) UpdateUserLink(arg0 context.Context, arg1 database.UpdateUserLinkParams) (database.UserLink, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserLink", arg0, arg1) + ret0, _ := ret[0].(database.UserLink) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateUserLink indicates an expected call of UpdateUserLink. +func (mr *MockStoreMockRecorder) UpdateUserLink(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserLink", reflect.TypeOf((*MockStore)(nil).UpdateUserLink), arg0, arg1) +} + +// UpdateUserLinkedID mocks base method. +func (m *MockStore) UpdateUserLinkedID(arg0 context.Context, arg1 database.UpdateUserLinkedIDParams) (database.UserLink, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserLinkedID", arg0, arg1) + ret0, _ := ret[0].(database.UserLink) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateUserLinkedID indicates an expected call of UpdateUserLinkedID. +func (mr *MockStoreMockRecorder) UpdateUserLinkedID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserLinkedID", reflect.TypeOf((*MockStore)(nil).UpdateUserLinkedID), arg0, arg1) +} + +// UpdateUserProfile mocks base method. +func (m *MockStore) UpdateUserProfile(arg0 context.Context, arg1 database.UpdateUserProfileParams) (database.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserProfile", arg0, arg1) + ret0, _ := ret[0].(database.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateUserProfile indicates an expected call of UpdateUserProfile. +func (mr *MockStoreMockRecorder) UpdateUserProfile(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserProfile", reflect.TypeOf((*MockStore)(nil).UpdateUserProfile), arg0, arg1) +} + +// UpdateUserRoles mocks base method. +func (m *MockStore) UpdateUserRoles(arg0 context.Context, arg1 database.UpdateUserRolesParams) (database.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserRoles", arg0, arg1) + ret0, _ := ret[0].(database.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateUserRoles indicates an expected call of UpdateUserRoles. +func (mr *MockStoreMockRecorder) UpdateUserRoles(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserRoles", reflect.TypeOf((*MockStore)(nil).UpdateUserRoles), arg0, arg1) +} + +// UpdateUserStatus mocks base method. +func (m *MockStore) UpdateUserStatus(arg0 context.Context, arg1 database.UpdateUserStatusParams) (database.User, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserStatus", arg0, arg1) + ret0, _ := ret[0].(database.User) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateUserStatus indicates an expected call of UpdateUserStatus. +func (mr *MockStoreMockRecorder) UpdateUserStatus(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserStatus", reflect.TypeOf((*MockStore)(nil).UpdateUserStatus), arg0, arg1) +} + +// UpdateWorkspace mocks base method. +func (m *MockStore) UpdateWorkspace(arg0 context.Context, arg1 database.UpdateWorkspaceParams) (database.Workspace, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspace", arg0, arg1) + ret0, _ := ret[0].(database.Workspace) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateWorkspace indicates an expected call of UpdateWorkspace. +func (mr *MockStoreMockRecorder) UpdateWorkspace(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspace", reflect.TypeOf((*MockStore)(nil).UpdateWorkspace), arg0, arg1) +} + +// UpdateWorkspaceAgentConnectionByID mocks base method. +func (m *MockStore) UpdateWorkspaceAgentConnectionByID(arg0 context.Context, arg1 database.UpdateWorkspaceAgentConnectionByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceAgentConnectionByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWorkspaceAgentConnectionByID indicates an expected call of UpdateWorkspaceAgentConnectionByID. +func (mr *MockStoreMockRecorder) UpdateWorkspaceAgentConnectionByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceAgentConnectionByID", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceAgentConnectionByID), arg0, arg1) +} + +// UpdateWorkspaceAgentLifecycleStateByID mocks base method. +func (m *MockStore) UpdateWorkspaceAgentLifecycleStateByID(arg0 context.Context, arg1 database.UpdateWorkspaceAgentLifecycleStateByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceAgentLifecycleStateByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWorkspaceAgentLifecycleStateByID indicates an expected call of UpdateWorkspaceAgentLifecycleStateByID. +func (mr *MockStoreMockRecorder) UpdateWorkspaceAgentLifecycleStateByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceAgentLifecycleStateByID", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceAgentLifecycleStateByID), arg0, arg1) +} + +// UpdateWorkspaceAgentMetadata mocks base method. +func (m *MockStore) UpdateWorkspaceAgentMetadata(arg0 context.Context, arg1 database.UpdateWorkspaceAgentMetadataParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceAgentMetadata", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWorkspaceAgentMetadata indicates an expected call of UpdateWorkspaceAgentMetadata. +func (mr *MockStoreMockRecorder) UpdateWorkspaceAgentMetadata(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceAgentMetadata", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceAgentMetadata), arg0, arg1) +} + +// UpdateWorkspaceAgentStartupByID mocks base method. +func (m *MockStore) UpdateWorkspaceAgentStartupByID(arg0 context.Context, arg1 database.UpdateWorkspaceAgentStartupByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceAgentStartupByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWorkspaceAgentStartupByID indicates an expected call of UpdateWorkspaceAgentStartupByID. +func (mr *MockStoreMockRecorder) UpdateWorkspaceAgentStartupByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceAgentStartupByID", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceAgentStartupByID), arg0, arg1) +} + +// UpdateWorkspaceAgentStartupLogOverflowByID mocks base method. +func (m *MockStore) UpdateWorkspaceAgentStartupLogOverflowByID(arg0 context.Context, arg1 database.UpdateWorkspaceAgentStartupLogOverflowByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceAgentStartupLogOverflowByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWorkspaceAgentStartupLogOverflowByID indicates an expected call of UpdateWorkspaceAgentStartupLogOverflowByID. +func (mr *MockStoreMockRecorder) UpdateWorkspaceAgentStartupLogOverflowByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceAgentStartupLogOverflowByID", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceAgentStartupLogOverflowByID), arg0, arg1) +} + +// UpdateWorkspaceAppHealthByID mocks base method. +func (m *MockStore) UpdateWorkspaceAppHealthByID(arg0 context.Context, arg1 database.UpdateWorkspaceAppHealthByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceAppHealthByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWorkspaceAppHealthByID indicates an expected call of UpdateWorkspaceAppHealthByID. +func (mr *MockStoreMockRecorder) UpdateWorkspaceAppHealthByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceAppHealthByID", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceAppHealthByID), arg0, arg1) +} + +// UpdateWorkspaceAutostart mocks base method. +func (m *MockStore) UpdateWorkspaceAutostart(arg0 context.Context, arg1 database.UpdateWorkspaceAutostartParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceAutostart", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWorkspaceAutostart indicates an expected call of UpdateWorkspaceAutostart. +func (mr *MockStoreMockRecorder) UpdateWorkspaceAutostart(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceAutostart", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceAutostart), arg0, arg1) +} + +// UpdateWorkspaceBuildByID mocks base method. +func (m *MockStore) UpdateWorkspaceBuildByID(arg0 context.Context, arg1 database.UpdateWorkspaceBuildByIDParams) (database.WorkspaceBuild, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceBuildByID", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceBuild) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateWorkspaceBuildByID indicates an expected call of UpdateWorkspaceBuildByID. +func (mr *MockStoreMockRecorder) UpdateWorkspaceBuildByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceBuildByID", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceBuildByID), arg0, arg1) +} + +// UpdateWorkspaceBuildCostByID mocks base method. +func (m *MockStore) UpdateWorkspaceBuildCostByID(arg0 context.Context, arg1 database.UpdateWorkspaceBuildCostByIDParams) (database.WorkspaceBuild, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceBuildCostByID", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceBuild) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateWorkspaceBuildCostByID indicates an expected call of UpdateWorkspaceBuildCostByID. +func (mr *MockStoreMockRecorder) UpdateWorkspaceBuildCostByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceBuildCostByID", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceBuildCostByID), arg0, arg1) +} + +// UpdateWorkspaceDeletedByID mocks base method. +func (m *MockStore) UpdateWorkspaceDeletedByID(arg0 context.Context, arg1 database.UpdateWorkspaceDeletedByIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceDeletedByID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWorkspaceDeletedByID indicates an expected call of UpdateWorkspaceDeletedByID. +func (mr *MockStoreMockRecorder) UpdateWorkspaceDeletedByID(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceDeletedByID", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceDeletedByID), arg0, arg1) +} + +// UpdateWorkspaceLastUsedAt mocks base method. +func (m *MockStore) UpdateWorkspaceLastUsedAt(arg0 context.Context, arg1 database.UpdateWorkspaceLastUsedAtParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceLastUsedAt", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWorkspaceLastUsedAt indicates an expected call of UpdateWorkspaceLastUsedAt. +func (mr *MockStoreMockRecorder) UpdateWorkspaceLastUsedAt(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceLastUsedAt", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceLastUsedAt), arg0, arg1) +} + +// UpdateWorkspaceProxy mocks base method. +func (m *MockStore) UpdateWorkspaceProxy(arg0 context.Context, arg1 database.UpdateWorkspaceProxyParams) (database.WorkspaceProxy, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceProxy", arg0, arg1) + ret0, _ := ret[0].(database.WorkspaceProxy) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateWorkspaceProxy indicates an expected call of UpdateWorkspaceProxy. +func (mr *MockStoreMockRecorder) UpdateWorkspaceProxy(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceProxy", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceProxy), arg0, arg1) +} + +// UpdateWorkspaceProxyDeleted mocks base method. +func (m *MockStore) UpdateWorkspaceProxyDeleted(arg0 context.Context, arg1 database.UpdateWorkspaceProxyDeletedParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceProxyDeleted", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWorkspaceProxyDeleted indicates an expected call of UpdateWorkspaceProxyDeleted. +func (mr *MockStoreMockRecorder) UpdateWorkspaceProxyDeleted(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceProxyDeleted", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceProxyDeleted), arg0, arg1) +} + +// UpdateWorkspaceTTL mocks base method. +func (m *MockStore) UpdateWorkspaceTTL(arg0 context.Context, arg1 database.UpdateWorkspaceTTLParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceTTL", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWorkspaceTTL indicates an expected call of UpdateWorkspaceTTL. +func (mr *MockStoreMockRecorder) UpdateWorkspaceTTL(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceTTL", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceTTL), arg0, arg1) +} + +// UpdateWorkspaceTTLToBeWithinTemplateMax mocks base method. +func (m *MockStore) UpdateWorkspaceTTLToBeWithinTemplateMax(arg0 context.Context, arg1 database.UpdateWorkspaceTTLToBeWithinTemplateMaxParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWorkspaceTTLToBeWithinTemplateMax", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWorkspaceTTLToBeWithinTemplateMax indicates an expected call of UpdateWorkspaceTTLToBeWithinTemplateMax. +func (mr *MockStoreMockRecorder) UpdateWorkspaceTTLToBeWithinTemplateMax(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWorkspaceTTLToBeWithinTemplateMax", reflect.TypeOf((*MockStore)(nil).UpdateWorkspaceTTLToBeWithinTemplateMax), arg0, arg1) +} + +// UpsertAppSecurityKey mocks base method. +func (m *MockStore) UpsertAppSecurityKey(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpsertAppSecurityKey", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpsertAppSecurityKey indicates an expected call of UpsertAppSecurityKey. +func (mr *MockStoreMockRecorder) UpsertAppSecurityKey(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertAppSecurityKey", reflect.TypeOf((*MockStore)(nil).UpsertAppSecurityKey), arg0, arg1) +} + +// UpsertLastUpdateCheck mocks base method. +func (m *MockStore) UpsertLastUpdateCheck(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpsertLastUpdateCheck", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpsertLastUpdateCheck indicates an expected call of UpsertLastUpdateCheck. +func (mr *MockStoreMockRecorder) UpsertLastUpdateCheck(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertLastUpdateCheck", reflect.TypeOf((*MockStore)(nil).UpsertLastUpdateCheck), arg0, arg1) +} + +// UpsertLogoURL mocks base method. +func (m *MockStore) UpsertLogoURL(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpsertLogoURL", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpsertLogoURL indicates an expected call of UpsertLogoURL. +func (mr *MockStoreMockRecorder) UpsertLogoURL(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertLogoURL", reflect.TypeOf((*MockStore)(nil).UpsertLogoURL), arg0, arg1) +} + +// UpsertServiceBanner mocks base method. +func (m *MockStore) UpsertServiceBanner(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpsertServiceBanner", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpsertServiceBanner indicates an expected call of UpsertServiceBanner. +func (mr *MockStoreMockRecorder) UpsertServiceBanner(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertServiceBanner", reflect.TypeOf((*MockStore)(nil).UpsertServiceBanner), arg0, arg1) +} diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index dfc4020465521..c29b759b03f57 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -637,361 +637,6 @@ func TestWorkspaceBuildStatus(t *testing.T) { require.EqualValues(t, codersdk.WorkspaceStatusDeleted, workspace.LatestBuild.Status) } -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 := []codersdk.WorkspaceBuildParameter{ - {Name: firstParameterName, Value: firstParameterValue}, - {Name: secondParameterName, Value: secondParameterValue}, - {Name: immutableParameterName, Value: immutableParameterValue}, - } - - echoResponses := &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Parameters: []*proto.RichParameter{ - {Name: firstParameterName, Description: firstParameterDescription, Mutable: true}, - {Name: secondParameterName, Description: secondParameterDescription, Mutable: true}, - {Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false}, - }, - }, - }, - }, - }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}, - } - - t.Run("UpdateParameterValues", func(t *testing.T) { - t.Parallel() - - client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, echoResponses) - coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { - cwr.RichParameterValues = initialBuildParameters - }) - - workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - require.Equal(t, codersdk.WorkspaceStatusRunning, workspaceBuild.Status) - - // Update build parameters - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - const updatedParameterValue = "3" - nextBuildParameters := []codersdk.WorkspaceBuildParameter{ - {Name: firstParameterName, Value: firstParameterValue}, - {Name: secondParameterName, Value: updatedParameterValue}, - } - nextWorkspaceBuild, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ - Transition: codersdk.WorkspaceTransitionStart, - RichParameterValues: nextBuildParameters, - }) - require.NoError(t, err) - coderdtest.AwaitWorkspaceBuildJob(t, client, nextWorkspaceBuild.ID) - - workspaceBuildParameters, err := client.WorkspaceBuildParameters(ctx, nextWorkspaceBuild.ID) - require.NoError(t, err) - - expected := append(nextBuildParameters, codersdk.WorkspaceBuildParameter{ - Name: immutableParameterName, - Value: immutableParameterValue, - }) - require.ElementsMatch(t, expected, workspaceBuildParameters) - }) - t.Run("UsePreviousParameterValues", func(t *testing.T) { - t.Parallel() - - client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, echoResponses) - coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { - cwr.RichParameterValues = initialBuildParameters - }) - - firstWorkspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - require.Equal(t, codersdk.WorkspaceStatusRunning, firstWorkspaceBuild.Status) - - // Start new workspace build - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - nextWorkspaceBuild, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ - Transition: codersdk.WorkspaceTransitionStart, - }) - require.NoError(t, err) - require.NotEqual(t, firstWorkspaceBuild, nextWorkspaceBuild) - coderdtest.AwaitWorkspaceBuildJob(t, client, nextWorkspaceBuild.ID) - - workspaceBuildParameters, err := client.WorkspaceBuildParameters(ctx, nextWorkspaceBuild.ID) - require.NoError(t, err) - require.ElementsMatch(t, initialBuildParameters, workspaceBuildParameters) - }) - - t.Run("DoNotModifyImmutables", func(t *testing.T) { - t.Parallel() - - client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, echoResponses) - coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { - cwr.RichParameterValues = initialBuildParameters - }) - - workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - require.Equal(t, codersdk.WorkspaceStatusRunning, workspaceBuild.Status) - - // Update build parameters - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - nextBuildParameters := []codersdk.WorkspaceBuildParameter{ - {Name: immutableParameterName, Value: "BAD"}, - } - _, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ - Transition: codersdk.WorkspaceTransitionStart, - RichParameterValues: nextBuildParameters, - }) - require.Error(t, err) - }) - - t.Run("NewImmutableRequiredParameterAdded", func(t *testing.T) { - t.Parallel() - - client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, echoResponses) - coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { - cwr.RichParameterValues = initialBuildParameters - }) - - workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - require.Equal(t, codersdk.WorkspaceStatusRunning, workspaceBuild.Status) - - // Push new template revision - const newImmutableParameterName = "new_immutable_parameter" - const newImmutableParameterDescription = "This is also an immutable parameter" - version2 := coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Parameters: []*proto.RichParameter{ - {Name: firstParameterName, Description: firstParameterDescription, Mutable: true}, - {Name: secondParameterName, Description: secondParameterDescription, Mutable: true}, - {Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false}, - {Name: newImmutableParameterName, Description: newImmutableParameterDescription, Mutable: false, Required: true}, - }, - }, - }, - }, - }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}, - }, template.ID) - coderdtest.AwaitTemplateVersionJob(t, client, version2.ID) - err := client.UpdateActiveTemplateVersion(context.Background(), template.ID, codersdk.UpdateActiveTemplateVersion{ - ID: version2.ID, - }) - require.NoError(t, err) - - // Update build parameters - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - nextBuildParameters := []codersdk.WorkspaceBuildParameter{ - {Name: newImmutableParameterName, Value: "good"}, - } - _, err = client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ - TemplateVersionID: version2.ID, - Transition: codersdk.WorkspaceTransitionStart, - RichParameterValues: nextBuildParameters, - }) - require.NoError(t, err) - }) - - t.Run("NewImmutableOptionalParameterAdded", func(t *testing.T) { - t.Parallel() - - client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, echoResponses) - coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { - cwr.RichParameterValues = initialBuildParameters - }) - - workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - require.Equal(t, codersdk.WorkspaceStatusRunning, workspaceBuild.Status) - - // Push new template revision - const newImmutableParameterName = "new_immutable_parameter" - const newImmutableParameterDescription = "This is also an immutable parameter" - version2 := coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Parameters: []*proto.RichParameter{ - {Name: firstParameterName, Description: firstParameterDescription, Mutable: true}, - {Name: secondParameterName, Description: secondParameterDescription, Mutable: true}, - {Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false}, - {Name: newImmutableParameterName, Description: newImmutableParameterDescription, Mutable: false, DefaultValue: "12345"}, - }, - }, - }, - }, - }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}, - }, template.ID) - coderdtest.AwaitTemplateVersionJob(t, client, version2.ID) - err := client.UpdateActiveTemplateVersion(context.Background(), template.ID, codersdk.UpdateActiveTemplateVersion{ - ID: version2.ID, - }) - require.NoError(t, err) - - // Update build parameters - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - nextBuildParameters := []codersdk.WorkspaceBuildParameter{ - {Name: newImmutableParameterName, Value: "good"}, - } - nextWorkspaceBuild, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ - TemplateVersionID: version2.ID, - Transition: codersdk.WorkspaceTransitionStart, - RichParameterValues: nextBuildParameters, - }) - require.NoError(t, err) - require.NotEqual(t, workspaceBuild, nextWorkspaceBuild) - coderdtest.AwaitWorkspaceBuildJob(t, client, nextWorkspaceBuild.ID) - - workspaceBuildParameters, err := client.WorkspaceBuildParameters(ctx, nextWorkspaceBuild.ID) - require.NoError(t, err) - - expectedNextBuildParameters := append(initialBuildParameters, codersdk.WorkspaceBuildParameter{ - Name: newImmutableParameterName, - Value: "good", - }) - require.ElementsMatch(t, expectedNextBuildParameters, workspaceBuildParameters) - }) - - t.Run("NewImmutableOptionalParameterUsesDefault", func(t *testing.T) { - t.Parallel() - - client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, echoResponses) - coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { - cwr.RichParameterValues = initialBuildParameters - }) - - workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - require.Equal(t, codersdk.WorkspaceStatusRunning, workspaceBuild.Status) - - // Push new template revision - const newImmutableParameterName = "new_immutable_parameter" - const newImmutableParameterDescription = "This is also an immutable parameter" - version2 := coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Parameters: []*proto.RichParameter{ - {Name: firstParameterName, Description: firstParameterDescription, Mutable: true}, - {Name: secondParameterName, Description: secondParameterDescription, Mutable: true}, - {Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false}, - {Name: newImmutableParameterName, Description: newImmutableParameterDescription, Mutable: false, DefaultValue: "12345"}, - }, - }, - }, - }, - }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}, - }, template.ID) - coderdtest.AwaitTemplateVersionJob(t, client, version2.ID) - err := client.UpdateActiveTemplateVersion(context.Background(), template.ID, codersdk.UpdateActiveTemplateVersion{ - ID: version2.ID, - }) - require.NoError(t, err) - - // Update build parameters - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - var nextBuildParameters []codersdk.WorkspaceBuildParameter - nextWorkspaceBuild, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ - TemplateVersionID: version2.ID, - Transition: codersdk.WorkspaceTransitionStart, - RichParameterValues: nextBuildParameters, - }) - require.NoError(t, err) - require.NotEqual(t, workspaceBuild, nextWorkspaceBuild) - coderdtest.AwaitWorkspaceBuildJob(t, client, nextWorkspaceBuild.ID) - - workspaceBuildParameters, err := client.WorkspaceBuildParameters(ctx, nextWorkspaceBuild.ID) - require.NoError(t, err) - - expectedNextBuildParameters := append(initialBuildParameters, codersdk.WorkspaceBuildParameter{ - Name: newImmutableParameterName, - Value: "12345", - }) - require.ElementsMatch(t, expectedNextBuildParameters, workspaceBuildParameters) - }) -} - func TestWorkspaceBuildValidateRichParameters(t *testing.T) { t.Parallel() diff --git a/coderd/wsbuilder/wsbuilder.go b/coderd/wsbuilder/wsbuilder.go index 796a72462dae7..8d554d309fcb0 100644 --- a/coderd/wsbuilder/wsbuilder.go +++ b/coderd/wsbuilder/wsbuilder.go @@ -60,11 +60,33 @@ type Builder struct { lastBuildJob *database.ProvisionerJob } +type Option func(Builder) Builder + +// versionTarget expresses how to determine the template version for the build. +// +// The zero value of this struct means to use the version from the last build. If there is no last build, +// the build will fail. +// +// setting active: true means to use the active version from the template. +// +// setting specific to a non-nil value means to use the provided template version ID. +// +// active and specific are mutually exclusive and setting them both results in undefined behavior. type versionTarget struct { active bool specific *uuid.UUID } +// stateTarget expresses how to determine the provisioner state for the build. +// +// The zero value of this struct means to use state from the last build. If there is no last build, no state is +// provided (i.e. first build on a newly created workspace). +// +// setting orphan: true means not to send any state. This can be used to deleted orphaned workspaces +// +// setting explicit to a non-nil value means to use the provided state +// +// orphan and explicit are mutually exclusive and setting them both results in undefined behavior. type stateTarget struct { orphan bool explicit *[]byte @@ -397,7 +419,7 @@ func (b *Builder) getTemplate() (*database.Template, error) { } t, err := b.store.GetTemplateByID(b.ctx, b.workspace.TemplateID) if err != nil { - return nil, err + return nil, xerrors.Errorf("get template %s: %w", b.workspace.TemplateID, err) } b.template = &t return b.template, nil @@ -409,11 +431,11 @@ func (b *Builder) getTemplateVersionJob() (*database.ProvisionerJob, error) { } v, err := b.getTemplateVersion() if err != nil { - return nil, err + return nil, xerrors.Errorf("get template version so we can get provisioner job: %w", err) } j, err := b.store.GetProvisionerJobByID(b.ctx, v.JobID) if err != nil { - return nil, err + return nil, xerrors.Errorf("get template provisioner job %s: %w", v.JobID, err) } b.templateVersionJob = &j return b.templateVersionJob, err @@ -425,11 +447,11 @@ func (b *Builder) getTemplateVersion() (*database.TemplateVersion, error) { } id, err := b.getTemplateVersionID() if err != nil { - return nil, err + return nil, xerrors.Errorf("get template version ID so we can get version: %w", err) } v, err := b.store.GetTemplateVersionByID(b.ctx, id) if err != nil { - return nil, err + return nil, xerrors.Errorf("get template version %s: %w", id, err) } b.templateVersion = &v return b.templateVersion, err @@ -442,14 +464,14 @@ func (b *Builder) getTemplateVersionID() (uuid.UUID, error) { if b.version.active { t, err := b.getTemplate() if err != nil { - return uuid.Nil, err + return uuid.Nil, xerrors.Errorf("get template so we can get active version: %w", err) } return t.ActiveVersionID, nil } // default is prior version bld, err := b.getLastBuild() if err != nil { - return uuid.Nil, err + return uuid.Nil, xerrors.Errorf("get last build so we can get version: %w", err) } return bld.TemplateVersionID, nil } @@ -464,8 +486,10 @@ func (b *Builder) getLastBuild() (*database.WorkspaceBuild, error) { return nil, *b.lastBuildErr } bld, err := b.store.GetLatestWorkspaceBuildByWorkspaceID(b.ctx, b.workspace.ID) - b.lastBuildErr = &err + if err != nil { + err = xerrors.Errorf("get workspace %s last build: %w", b.workspace.ID, err) + b.lastBuildErr = &err return nil, err } b.lastBuild = &bld @@ -479,7 +503,7 @@ func (b *Builder) getBuildNumber() (int32, error) { return 1, nil } if err != nil { - return 0, err + return 0, xerrors.Errorf("get last build to compute build number: %w", err) } return bld.BuildNumber + 1, nil } @@ -499,7 +523,7 @@ func (b *Builder) getState() ([]byte, error) { return nil, nil } if err != nil { - return nil, err + return nil, xerrors.Errorf("get last build to get state: %w", err) } return bld.ProvisionerState, nil } @@ -562,11 +586,11 @@ func (b *Builder) getLastBuildParameters() ([]database.WorkspaceBuildParameter, return *b.lastBuildParameters, nil } if err != nil { - return nil, err + return nil, xerrors.Errorf("get last build to get parameters: %w", err) } values, err := b.store.GetWorkspaceBuildParameters(b.ctx, bld.ID) if err != nil && !xerrors.Is(err, sql.ErrNoRows) { - return nil, err + return nil, xerrors.Errorf("get last build %s parameters: %w", bld.ID, err) } b.lastBuildParameters = &values return values, nil @@ -578,11 +602,11 @@ func (b *Builder) getTemplateVersionParameters() ([]database.TemplateVersionPara } tvID, err := b.getTemplateVersionID() if err != nil { - return nil, err + return nil, xerrors.Errorf("get template version ID to get parameters: %w", err) } tvp, err := b.store.GetTemplateVersionParameters(b.ctx, tvID) if err != nil && !xerrors.Is(err, sql.ErrNoRows) { - return nil, err + return nil, xerrors.Errorf("get template version %s parameters: %w", tvID, err) } b.templateVersionParameters = &tvp return tvp, nil @@ -597,7 +621,7 @@ func (b *Builder) getLastParameterValues() ([]database.ParameterValue, error) { ScopeIds: []uuid.UUID{b.workspace.ID}, }) if err != nil && !xerrors.Is(err, sql.ErrNoRows) { - return nil, err + return nil, xerrors.Errorf("get workspace %w parameter values: %w", b.workspace.ID, err) } b.lastParameterValues = &pv return pv, nil @@ -609,11 +633,11 @@ func (b *Builder) getLastBuildJob() (*database.ProvisionerJob, error) { } bld, err := b.getLastBuild() if err != nil { - return nil, err + return nil, xerrors.Errorf("get last build to get job: %w", err) } job, err := b.store.GetProvisionerJobByID(b.ctx, bld.JobID) if err != nil { - return nil, err + return nil, xerrors.Errorf("get build provisioner job %s: %w", bld.JobID, err) } b.lastBuildJob = &job return b.lastBuildJob, nil diff --git a/coderd/wsbuilder/wsbuilder_test.go b/coderd/wsbuilder/wsbuilder_test.go new file mode 100644 index 0000000000000..b8e405fcc70b1 --- /dev/null +++ b/coderd/wsbuilder/wsbuilder_test.go @@ -0,0 +1,839 @@ +package wsbuilder_test + +import ( + "context" + "database/sql" + "encoding/json" + "fmt" + "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/dbtype" + "github.com/coder/coder/coderd/database/mock" + "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") + notReplacedParamID = uuid.MustParse("12341234-0000-0000-000e-000000000000") + replacedParamID = uuid.MustParse("12341234-0000-0000-000f-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, + withLegacyParameters(nil), withRichParameters(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, + withLegacyParameters(nil), withRichParameters(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, + withLegacyParameters(nil), withRichParameters(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, + withLegacyParameters(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 TestBuilder_LegacyParams(t *testing.T) { + t.Parallel() + req := require.New(t) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + oldParams := []database.ParameterValue{ + {Name: "not-replaced", SourceValue: "nr", ID: notReplacedParamID}, + {Name: "replaced", SourceValue: "r", ID: replacedParamID}, + } + newParams := []codersdk.CreateParameterRequest{ + {Name: "replaced", SourceValue: "s"}, + {Name: "new", SourceValue: "n"}, + } + + mDB := expectDB(t, + // Inputs + withTemplate, + withActiveVersion(nil), + withLastBuildFound, + withLegacyParameters(oldParams), + withRichParameters(nil), + + // Outputs + expectProvisionerJob(func(job database.InsertProvisionerJobParams) { + }), + expectBuild(func(bld database.InsertWorkspaceBuildParams) { + }), + expectBuildParameters(func(params database.InsertWorkspaceBuildParametersParams) { + }), + expectReplacedParam(replacedParamID, "replaced", "s"), + expectInsertedParam("new", "n"), + ) + + ws := database.Workspace{ID: workspaceID, TemplateID: templateID, OwnerID: userID} + uut := wsbuilder.New(ws, database.WorkspaceTransitionStart).ActiveVersion().LegacyParameterValues(newParams) + _, _, 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, + withLegacyParameters(nil), + withRichParameters(initialBuildParameters), + + // 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, + withLegacyParameters(nil), + withRichParameters(initialBuildParameters), + + // 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("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, + withLegacyParameters(nil), + withRichParameters(initialBuildParameters), + + // 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, + withLegacyParameters(nil), + withRichParameters(initialBuildParameters), + + // 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, + withLegacyParameters(nil), + withRichParameters(initialBuildParameters), + + // 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, + withLegacyParameters(nil), + withRichParameters(initialBuildParameters), + + // 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 *mock.MockStore) + +func expectDB(t *testing.T, opts ...txExpect) *mock.MockStore { + t.Helper() + ctrl := gomock.NewController(t) + mDB := mock.NewMockStore(ctrl) + mTx := mock.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 *mock.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 *mock.MockStore) { + return func(mTx *mock.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 *mock.MockStore) { + return func(mTx *mock.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 *mock.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 *mock.MockStore) { + mTx.EXPECT().GetLatestWorkspaceBuildByWorkspaceID(gomock.Any(), workspaceID). + Times(1). + Return(database.WorkspaceBuild{}, sql.ErrNoRows) +} + +func withLegacyParameters(params []database.ParameterValue) func(mTx *mock.MockStore) { + return func(mTx *mock.MockStore) { + c := mTx.EXPECT().ParameterValues( + gomock.Any(), + database.ParameterValuesParams{ + Scopes: []database.ParameterScope{database.ParameterScopeWorkspace}, + ScopeIds: []uuid.UUID{workspaceID}, + }). + Times(1) + if len(params) > 0 { + c.Return(params, nil) + } else { + c.Return(nil, sql.ErrNoRows) + } + } +} + +func withRichParameters(params []database.WorkspaceBuildParameter) func(mTx *mock.MockStore) { + return func(mTx *mock.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 *mock.MockStore) { + return func(mTx *mock.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 *mock.MockStore) { + return func(mTx *mock.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 *mock.MockStore) { + return func(mTx *mock.MockStore) { + mTx.EXPECT().InsertWorkspaceBuildParameters(gomock.Any(), gomock.Any()). + Times(1). + DoAndReturn( + func(ctx context.Context, params database.InsertWorkspaceBuildParametersParams) error { + assertions(params) + return nil + }, + ) + } +} + +type insertParameterMatcher struct { + name string + value string +} + +func (m insertParameterMatcher) Matches(x interface{}) bool { + p, ok := x.(database.InsertParameterValueParams) + if !ok { + return false + } + if p.Name != m.name { + return false + } + return p.SourceValue == m.value +} + +func (m insertParameterMatcher) String() string { + return fmt.Sprintf("ParameterValue %s=%s", m.name, m.value) +} + +func expectReplacedParam(oldID uuid.UUID, name, newValue string) func(store *mock.MockStore) { + return func(mTx *mock.MockStore) { + del := mTx.EXPECT().DeleteParameterValueByID(gomock.Any(), oldID). + Times(1). + Return(nil) + mTx.EXPECT().InsertParameterValue(gomock.Any(), insertParameterMatcher{name, newValue}). + Times(1). + After(del). + Return(database.ParameterValue{}, nil) + } +} + +func expectInsertedParam(name, newValue string) func(store *mock.MockStore) { + return func(mTx *mock.MockStore) { + mTx.EXPECT().InsertParameterValue(gomock.Any(), insertParameterMatcher{name, newValue}). + Times(1). + Return(database.ParameterValue{}, nil) + } +} diff --git a/dogfood/Dockerfile b/dogfood/Dockerfile index 8e2717405d852..e38ce00e18a8b 100644 --- a/dogfood/Dockerfile +++ b/dogfood/Dockerfile @@ -72,7 +72,8 @@ RUN mkdir --parents "$GOPATH" && \ # yq v4 is used to process yaml files in coder v2. Conflicts with # yq v3 used in v1. go install github.com/mikefarah/yq/v4@v4.30.6 && \ - mv /tmp/bin/yq /tmp/bin/yq4 + mv /tmp/bin/yq /tmp/bin/yq4 && \ + go install github.com/golang/mock/mockgen@v1.6.0 FROM alpine:3.16 as proto WORKDIR /tmp diff --git a/go.mod b/go.mod index fe286caab7d4a..5f49f193268cc 100644 --- a/go.mod +++ b/go.mod @@ -177,6 +177,7 @@ require ( nhooyr.io/websocket v1.8.7 storj.io/drpc v0.0.33-0.20230420154621-9716137f6037 tailscale.com v1.32.2 + github.com/golang/mock v1.6.0 ) require ( diff --git a/go.sum b/go.sum index bf14264e8f8e1..4cdf8eb9e6c7d 100644 --- a/go.sum +++ b/go.sum @@ -766,6 +766,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= From 510a1b03c6d6562050f798856bf37715493e98b1 Mon Sep 17 00:00:00 2001 From: Spike Curtis Date: Mon, 22 May 2023 10:40:28 +0000 Subject: [PATCH 08/10] Move parameter validation tests to richparameters_test.go Signed-off-by: Spike Curtis --- coderd/workspacebuilds_test.go | 204 -------------------------------- coderd/wsbuilder/wsbuilder.go | 1 - codersdk/richparameters_test.go | 154 +++++++++++++++++++++++- 3 files changed, 152 insertions(+), 207 deletions(-) diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index c29b759b03f57..74060213fb549 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -637,210 +637,6 @@ func TestWorkspaceBuildStatus(t *testing.T) { require.EqualValues(t, codersdk.WorkspaceStatusDeleted, workspace.LatestBuild.Status) } -func TestWorkspaceBuildValidateRichParameters(t *testing.T) { - t.Parallel() - - const ( - stringParameterName = "string_parameter" - stringParameterValue = "abc" - - numberParameterName = "number_parameter" - numberParameterValue = "7" - - boolParameterName = "bool_parameter" - boolParameterValue = "true" - - listOfStringsParameterName = "list_of_strings_parameter" - listOfStringsParameterValue = `["a","b","c"]` - ) - - initialBuildParameters := []codersdk.WorkspaceBuildParameter{ - {Name: stringParameterName, Value: stringParameterValue}, - {Name: numberParameterName, Value: numberParameterValue}, - {Name: boolParameterName, Value: boolParameterValue}, - {Name: listOfStringsParameterName, Value: listOfStringsParameterValue}, - } - - prepareEchoResponses := func(richParameters []*proto.RichParameter) *echo.Responses { - return &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Parameters: richParameters, - }, - }, - }, - }, - ProvisionApply: []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }, - }, - } - } - - t.Run("NoValidation", func(t *testing.T) { - t.Parallel() - - richParameters := []*proto.RichParameter{ - {Name: stringParameterName, Type: "string", Mutable: true}, - {Name: numberParameterName, Type: "number", Mutable: true}, - {Name: boolParameterName, Type: "bool", Mutable: true}, - } - - client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(richParameters)) - coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { - cwr.RichParameterValues = initialBuildParameters - }) - - workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - require.Equal(t, codersdk.WorkspaceStatusRunning, workspaceBuild.Status) - - // Update build parameters - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - nextBuildParameters := []codersdk.WorkspaceBuildParameter{ - {Name: numberParameterName, Value: "42"}, - } - nextWorkspaceBuild, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ - Transition: codersdk.WorkspaceTransitionStart, - RichParameterValues: nextBuildParameters, - }) - require.NoError(t, err) - coderdtest.AwaitWorkspaceBuildJob(t, client, nextWorkspaceBuild.ID) - - _, err = client.WorkspaceBuildParameters(ctx, nextWorkspaceBuild.ID) - require.NoError(t, err) - }) - - t.Run("Validation", func(t *testing.T) { - t.Parallel() - - numberRichParameters := []*proto.RichParameter{ - {Name: stringParameterName, Type: "string", Mutable: true}, - {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10}, - {Name: boolParameterName, Type: "bool", Mutable: true}, - } - - monotonicIncreasingNumberRichParameters := []*proto.RichParameter{ - {Name: stringParameterName, Type: "string", Mutable: true}, - {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10, ValidationMonotonic: "increasing"}, - {Name: boolParameterName, Type: "bool", Mutable: true}, - } - - monotonicDecreasingNumberRichParameters := []*proto.RichParameter{ - {Name: stringParameterName, Type: "string", Mutable: true}, - {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10, ValidationMonotonic: "decreasing"}, - {Name: boolParameterName, Type: "bool", Mutable: true}, - } - - stringRichParameters := []*proto.RichParameter{ - {Name: stringParameterName, Type: "string", Mutable: true}, - {Name: numberParameterName, Type: "number", Mutable: true}, - {Name: boolParameterName, Type: "bool", Mutable: true}, - } - - boolRichParameters := []*proto.RichParameter{ - {Name: stringParameterName, Type: "string", Mutable: true}, - {Name: numberParameterName, Type: "number", Mutable: true}, - {Name: boolParameterName, Type: "bool", Mutable: true}, - } - - regexRichParameters := []*proto.RichParameter{ - {Name: stringParameterName, Type: "string", Mutable: true, ValidationRegex: "^[a-z]+$", ValidationError: "this is error"}, - {Name: numberParameterName, Type: "number", Mutable: true}, - {Name: boolParameterName, Type: "bool", Mutable: true}, - } - - listOfStringsRichParameters := []*proto.RichParameter{ - {Name: listOfStringsParameterName, Type: "list(string)", Mutable: true}, - } - - tests := []struct { - parameterName string - value string - valid bool - richParameters []*proto.RichParameter - }{ - {numberParameterName, "2", false, numberRichParameters}, - {numberParameterName, "3", true, numberRichParameters}, - {numberParameterName, "10", true, numberRichParameters}, - {numberParameterName, "11", false, numberRichParameters}, - - {numberParameterName, "6", false, monotonicIncreasingNumberRichParameters}, - {numberParameterName, "7", true, monotonicIncreasingNumberRichParameters}, - {numberParameterName, "8", true, monotonicIncreasingNumberRichParameters}, - - {numberParameterName, "6", true, monotonicDecreasingNumberRichParameters}, - {numberParameterName, "7", true, monotonicDecreasingNumberRichParameters}, - {numberParameterName, "8", false, monotonicDecreasingNumberRichParameters}, - - {stringParameterName, "", true, stringRichParameters}, - {stringParameterName, "foobar", true, stringRichParameters}, - - {stringParameterName, "abcd", true, regexRichParameters}, - {stringParameterName, "abcd1", false, regexRichParameters}, - - {boolParameterName, "true", true, boolRichParameters}, - {boolParameterName, "false", true, boolRichParameters}, - {boolParameterName, "cat", false, boolRichParameters}, - - {listOfStringsParameterName, `[]`, true, listOfStringsRichParameters}, - {listOfStringsParameterName, `["aa"]`, true, listOfStringsRichParameters}, - {listOfStringsParameterName, `["aa]`, false, listOfStringsRichParameters}, - {listOfStringsParameterName, ``, false, listOfStringsRichParameters}, - } - - for _, tc := range tests { - tc := tc - t.Run(tc.parameterName+"-"+tc.value, func(t *testing.T) { - t.Parallel() - - client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) - user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(tc.richParameters)) - coderdtest.AwaitTemplateVersionJob(t, client, version.ID) - - template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) - workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { - cwr.RichParameterValues = initialBuildParameters - }) - - workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) - require.Equal(t, codersdk.WorkspaceStatusRunning, workspaceBuild.Status) - - ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) - defer cancel() - - nextBuildParameters := []codersdk.WorkspaceBuildParameter{ - {Name: tc.parameterName, Value: tc.value}, - } - nextWorkspaceBuild, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ - Transition: codersdk.WorkspaceTransitionStart, - RichParameterValues: nextBuildParameters, - }) - - if tc.valid { - require.NoError(t, err) - coderdtest.AwaitWorkspaceBuildJob(t, client, nextWorkspaceBuild.ID) - } else { - require.Error(t, err) - } - }) - } - }) -} - func TestMigrateLegacyToRichParameters(t *testing.T) { t.Parallel() diff --git a/coderd/wsbuilder/wsbuilder.go b/coderd/wsbuilder/wsbuilder.go index 8d554d309fcb0..e4d2ca9a6b7b3 100644 --- a/coderd/wsbuilder/wsbuilder.go +++ b/coderd/wsbuilder/wsbuilder.go @@ -486,7 +486,6 @@ func (b *Builder) getLastBuild() (*database.WorkspaceBuild, error) { return nil, *b.lastBuildErr } bld, err := b.store.GetLatestWorkspaceBuildByWorkspaceID(b.ctx, b.workspace.ID) - if err != nil { err = xerrors.Errorf("get workspace %s last build: %w", b.workspace.ID, err) b.lastBuildErr = &err diff --git a/codersdk/richparameters_test.go b/codersdk/richparameters_test.go index 77befcc3347f5..fbc7d47748b11 100644 --- a/codersdk/richparameters_test.go +++ b/codersdk/richparameters_test.go @@ -1,9 +1,11 @@ package codersdk_test import ( - "github.com/coder/coder/codersdk" - "github.com/stretchr/testify/require" "testing" + + "github.com/stretchr/testify/require" + + "github.com/coder/coder/codersdk" ) func TestParameterResolver_ValidateResolve_New(t *testing.T) { @@ -172,3 +174,151 @@ func TestParameterResolver_ValidateResolve_PreferRichOverLegacy(t *testing.T) { require.NoError(t, err) require.Equal(t, "7", v) } + +func TestRichParameterValidation(t *testing.T) { + t.Parallel() + + const ( + stringParameterName = "string_parameter" + stringParameterValue = "abc" + + numberParameterName = "number_parameter" + numberParameterValue = "7" + + boolParameterName = "bool_parameter" + boolParameterValue = "true" + + listOfStringsParameterName = "list_of_strings_parameter" + listOfStringsParameterValue = `["a","b","c"]` + ) + + initialBuildParameters := []codersdk.WorkspaceBuildParameter{ + {Name: stringParameterName, Value: stringParameterValue}, + {Name: numberParameterName, Value: numberParameterValue}, + {Name: boolParameterName, Value: boolParameterValue}, + {Name: listOfStringsParameterName, Value: listOfStringsParameterValue}, + } + + t.Run("NoValidation", func(t *testing.T) { + t.Parallel() + + p := codersdk.TemplateVersionParameter{ + Name: numberParameterName, Type: "number", Mutable: true, + } + + uut := codersdk.ParameterResolver{ + Rich: initialBuildParameters, + } + v, err := uut.ValidateResolve(p, &codersdk.WorkspaceBuildParameter{ + Name: numberParameterName, Value: "42", + }) + require.NoError(t, err) + require.Equal(t, v, "42") + }) + + t.Run("Validation", func(t *testing.T) { + t.Parallel() + + numberRichParameters := []codersdk.TemplateVersionParameter{ + {Name: stringParameterName, Type: "string", Mutable: true}, + {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10}, + {Name: boolParameterName, Type: "bool", Mutable: true}, + } + + monotonicIncreasingNumberRichParameters := []codersdk.TemplateVersionParameter{ + {Name: stringParameterName, Type: "string", Mutable: true}, + {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10, ValidationMonotonic: "increasing"}, + {Name: boolParameterName, Type: "bool", Mutable: true}, + } + + monotonicDecreasingNumberRichParameters := []codersdk.TemplateVersionParameter{ + {Name: stringParameterName, Type: "string", Mutable: true}, + {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10, ValidationMonotonic: "decreasing"}, + {Name: boolParameterName, Type: "bool", Mutable: true}, + } + + stringRichParameters := []codersdk.TemplateVersionParameter{ + {Name: stringParameterName, Type: "string", Mutable: true}, + {Name: numberParameterName, Type: "number", Mutable: true}, + {Name: boolParameterName, Type: "bool", Mutable: true}, + } + + boolRichParameters := []codersdk.TemplateVersionParameter{ + {Name: stringParameterName, Type: "string", Mutable: true}, + {Name: numberParameterName, Type: "number", Mutable: true}, + {Name: boolParameterName, Type: "bool", Mutable: true}, + } + + regexRichParameters := []codersdk.TemplateVersionParameter{ + {Name: stringParameterName, Type: "string", Mutable: true, ValidationRegex: "^[a-z]+$", ValidationError: "this is error"}, + {Name: numberParameterName, Type: "number", Mutable: true}, + {Name: boolParameterName, Type: "bool", Mutable: true}, + } + + listOfStringsRichParameters := []codersdk.TemplateVersionParameter{ + {Name: listOfStringsParameterName, Type: "list(string)", Mutable: true}, + } + + tests := []struct { + parameterName string + value string + valid bool + richParameters []codersdk.TemplateVersionParameter + }{ + {numberParameterName, "2", false, numberRichParameters}, + {numberParameterName, "3", true, numberRichParameters}, + {numberParameterName, "10", true, numberRichParameters}, + {numberParameterName, "11", false, numberRichParameters}, + + {numberParameterName, "6", false, monotonicIncreasingNumberRichParameters}, + {numberParameterName, "7", true, monotonicIncreasingNumberRichParameters}, + {numberParameterName, "8", true, monotonicIncreasingNumberRichParameters}, + + {numberParameterName, "6", true, monotonicDecreasingNumberRichParameters}, + {numberParameterName, "7", true, monotonicDecreasingNumberRichParameters}, + {numberParameterName, "8", false, monotonicDecreasingNumberRichParameters}, + + {stringParameterName, "", true, stringRichParameters}, + {stringParameterName, "foobar", true, stringRichParameters}, + + {stringParameterName, "abcd", true, regexRichParameters}, + {stringParameterName, "abcd1", false, regexRichParameters}, + + {boolParameterName, "true", true, boolRichParameters}, + {boolParameterName, "false", true, boolRichParameters}, + {boolParameterName, "cat", false, boolRichParameters}, + + {listOfStringsParameterName, `[]`, true, listOfStringsRichParameters}, + {listOfStringsParameterName, `["aa"]`, true, listOfStringsRichParameters}, + {listOfStringsParameterName, `["aa]`, false, listOfStringsRichParameters}, + {listOfStringsParameterName, ``, false, listOfStringsRichParameters}, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.parameterName+"-"+tc.value, func(t *testing.T) { + t.Parallel() + + uut := codersdk.ParameterResolver{ + Rich: initialBuildParameters, + } + + for _, p := range tc.richParameters { + if p.Name != tc.parameterName { + continue + } + v, err := uut.ValidateResolve(p, &codersdk.WorkspaceBuildParameter{ + Name: tc.parameterName, + Value: tc.value, + }) + if tc.valid { + require.NoError(t, err) + require.Equal(t, tc.value, v) + } else { + require.Error(t, err) + } + } + }) + } + }) +} From acd1243b2bfdcba7a0c22f1bf17d905f91c42efa Mon Sep 17 00:00:00 2001 From: Spike Curtis Date: Tue, 23 May 2023 04:37:26 +0000 Subject: [PATCH 09/10] Fix CI generation; rename mock->dbmock Signed-off-by: Spike Curtis --- .github/workflows/ci.yaml | 2 ++ Makefile | 8 ++--- coderd/database/dbmock/doc.go | 4 +++ coderd/database/{mock => dbmock}/store.go | 4 +-- coderd/database/mock/doc.go | 4 --- coderd/wsbuilder/wsbuilder_test.go | 40 +++++++++++------------ 6 files changed, 32 insertions(+), 30 deletions(-) create mode 100644 coderd/database/dbmock/doc.go rename coderd/database/{mock => dbmock}/store.go (99%) delete mode 100644 coderd/database/mock/doc.go diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9be89e4845024..c2f815b12ebcc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -184,6 +184,8 @@ jobs: run: go install golang.org/x/tools/cmd/goimports@latest - name: Install yq run: go run github.com/mikefarah/yq/v4@v4.30.6 + - name: Install mockgen + run: go install github.com/golang/mock/mockgen@v1.6.0 - name: Install Protoc run: | diff --git a/Makefile b/Makefile index b33c728ffa229..4b6e1d4f22cdc 100644 --- a/Makefile +++ b/Makefile @@ -420,7 +420,7 @@ lint/shellcheck: $(SHELL_SRC_FILES) gen: \ coderd/database/dump.sql \ coderd/database/querier.go \ - coderd/database/mock/store.go \ + coderd/database/dbmock/store.go \ provisionersdk/proto/provisioner.pb.go \ provisionerd/proto/provisionerd.pb.go \ site/src/api/typesGenerated.ts \ @@ -442,7 +442,7 @@ gen/mark-fresh: files="\ coderd/database/dump.sql \ coderd/database/querier.go \ - coderd/database/mock/store.go \ + coderd/database/dbmock/store.go \ provisionersdk/proto/provisioner.pb.go \ provisionerd/proto/provisionerd.pb.go \ site/src/api/typesGenerated.ts \ @@ -479,8 +479,8 @@ coderd/database/querier.go: coderd/database/sqlc.yaml coderd/database/dump.sql $ ./coderd/database/generate.sh -coderd/database/mock/store.go: coderd/database/db.go coderd/database/querier.go - go generate ./coderd/database/mock/ +coderd/database/dbmock/store.go: coderd/database/db.go coderd/database/querier.go + go generate ./coderd/database/dbmock/ provisionersdk/proto/provisioner.pb.go: provisionersdk/proto/provisioner.proto protoc \ diff --git a/coderd/database/dbmock/doc.go b/coderd/database/dbmock/doc.go new file mode 100644 index 0000000000000..1aaeb50463812 --- /dev/null +++ b/coderd/database/dbmock/doc.go @@ -0,0 +1,4 @@ +// package dbmock contains a mocked implementation of the database.Store interface for use in tests +package dbmock + +//go:generate mockgen -destination ./store.go -package dbmock github.com/coder/coder/coderd/database Store diff --git a/coderd/database/mock/store.go b/coderd/database/dbmock/store.go similarity index 99% rename from coderd/database/mock/store.go rename to coderd/database/dbmock/store.go index a0c1c180740d6..5fe83e6f514d6 100644 --- a/coderd/database/mock/store.go +++ b/coderd/database/dbmock/store.go @@ -1,8 +1,8 @@ // Code generated by MockGen. DO NOT EDIT. // Source: github.com/coder/coder/coderd/database (interfaces: Store) -// Package mock is a generated GoMock package. -package mock +// Package dbmock is a generated GoMock package. +package dbmock import ( context "context" diff --git a/coderd/database/mock/doc.go b/coderd/database/mock/doc.go deleted file mode 100644 index 749f9f23cecb1..0000000000000 --- a/coderd/database/mock/doc.go +++ /dev/null @@ -1,4 +0,0 @@ -// package mock contains a mocked implementation of the database.Store interface for use in tests -package mock - -//go:generate mockgen -destination ./store.go -package mock github.com/coder/coder/coderd/database Store diff --git a/coderd/wsbuilder/wsbuilder_test.go b/coderd/wsbuilder/wsbuilder_test.go index b8e405fcc70b1..f1c87a153f86b 100644 --- a/coderd/wsbuilder/wsbuilder_test.go +++ b/coderd/wsbuilder/wsbuilder_test.go @@ -15,8 +15,8 @@ import ( "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/database/mock" "github.com/coder/coder/coderd/provisionerdserver" "github.com/coder/coder/coderd/wsbuilder" "github.com/coder/coder/codersdk" @@ -557,13 +557,13 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { }) } -type txExpect func(mTx *mock.MockStore) +type txExpect func(mTx *dbmock.MockStore) -func expectDB(t *testing.T, opts ...txExpect) *mock.MockStore { +func expectDB(t *testing.T, opts ...txExpect) *dbmock.MockStore { t.Helper() ctrl := gomock.NewController(t) - mDB := mock.NewMockStore(ctrl) - mTx := mock.NewMockStore(ctrl) + 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. @@ -582,7 +582,7 @@ func expectDB(t *testing.T, opts ...txExpect) *mock.MockStore { return mDB } -func withTemplate(mTx *mock.MockStore) { +func withTemplate(mTx *dbmock.MockStore) { mTx.EXPECT().GetTemplateByID(gomock.Any(), templateID). Times(1). Return(database.Template{ @@ -593,8 +593,8 @@ func withTemplate(mTx *mock.MockStore) { }, nil) } -func withActiveVersion(params []database.TemplateVersionParameter) func(mTx *mock.MockStore) { - return func(mTx *mock.MockStore) { +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{ @@ -633,8 +633,8 @@ func withActiveVersion(params []database.TemplateVersionParameter) func(mTx *moc } } -func withInactiveVersion(params []database.TemplateVersionParameter) func(mTx *mock.MockStore) { - return func(mTx *mock.MockStore) { +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{ @@ -673,7 +673,7 @@ func withInactiveVersion(params []database.TemplateVersionParameter) func(mTx *m } } -func withLastBuildFound(mTx *mock.MockStore) { +func withLastBuildFound(mTx *dbmock.MockStore) { mTx.EXPECT().GetLatestWorkspaceBuildByWorkspaceID(gomock.Any(), workspaceID). Times(1). Return(database.WorkspaceBuild{ @@ -704,14 +704,14 @@ func withLastBuildFound(mTx *mock.MockStore) { }, nil) } -func withLastBuildNotFound(mTx *mock.MockStore) { +func withLastBuildNotFound(mTx *dbmock.MockStore) { mTx.EXPECT().GetLatestWorkspaceBuildByWorkspaceID(gomock.Any(), workspaceID). Times(1). Return(database.WorkspaceBuild{}, sql.ErrNoRows) } -func withLegacyParameters(params []database.ParameterValue) func(mTx *mock.MockStore) { - return func(mTx *mock.MockStore) { +func withLegacyParameters(params []database.ParameterValue) func(mTx *dbmock.MockStore) { + return func(mTx *dbmock.MockStore) { c := mTx.EXPECT().ParameterValues( gomock.Any(), database.ParameterValuesParams{ @@ -727,8 +727,8 @@ func withLegacyParameters(params []database.ParameterValue) func(mTx *mock.MockS } } -func withRichParameters(params []database.WorkspaceBuildParameter) func(mTx *mock.MockStore) { - return func(mTx *mock.MockStore) { +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 { @@ -747,8 +747,8 @@ func withRichParameters(params []database.WorkspaceBuildParameter) func(mTx *moc // against it. func expectProvisionerJob( assertions func(job database.InsertProvisionerJobParams), -) func(mTx *mock.MockStore) { - return func(mTx *mock.MockStore) { +) func(mTx *dbmock.MockStore) { + return func(mTx *dbmock.MockStore) { mTx.EXPECT().InsertProvisionerJob(gomock.Any(), gomock.Any()). Times(1). DoAndReturn( @@ -766,8 +766,8 @@ func expectProvisionerJob( // against it. func expectBuild( assertions func(job database.InsertWorkspaceBuildParams), -) func(mTx *mock.MockStore) { - return func(mTx *mock.MockStore) { +) func(mTx *dbmock.MockStore) { + return func(mTx *dbmock.MockStore) { mTx.EXPECT().InsertWorkspaceBuild(gomock.Any(), gomock.Any()). Times(1). DoAndReturn( From 5cb2d2a312ec003c0cd4a40e302f485d6e0eddcb Mon Sep 17 00:00:00 2001 From: Spike Curtis Date: Tue, 23 May 2023 04:40:08 +0000 Subject: [PATCH 10/10] Fix test imports Signed-off-by: Spike Curtis --- coderd/wsbuilder/wsbuilder_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/coderd/wsbuilder/wsbuilder_test.go b/coderd/wsbuilder/wsbuilder_test.go index f1c87a153f86b..afa37fdf2852f 100644 --- a/coderd/wsbuilder/wsbuilder_test.go +++ b/coderd/wsbuilder/wsbuilder_test.go @@ -785,8 +785,8 @@ func expectBuild( // against it. func expectBuildParameters( assertions func(database.InsertWorkspaceBuildParametersParams), -) func(mTx *mock.MockStore) { - return func(mTx *mock.MockStore) { +) func(mTx *dbmock.MockStore) { + return func(mTx *dbmock.MockStore) { mTx.EXPECT().InsertWorkspaceBuildParameters(gomock.Any(), gomock.Any()). Times(1). DoAndReturn( @@ -818,8 +818,8 @@ func (m insertParameterMatcher) String() string { return fmt.Sprintf("ParameterValue %s=%s", m.name, m.value) } -func expectReplacedParam(oldID uuid.UUID, name, newValue string) func(store *mock.MockStore) { - return func(mTx *mock.MockStore) { +func expectReplacedParam(oldID uuid.UUID, name, newValue string) func(store *dbmock.MockStore) { + return func(mTx *dbmock.MockStore) { del := mTx.EXPECT().DeleteParameterValueByID(gomock.Any(), oldID). Times(1). Return(nil) @@ -830,8 +830,8 @@ func expectReplacedParam(oldID uuid.UUID, name, newValue string) func(store *moc } } -func expectInsertedParam(name, newValue string) func(store *mock.MockStore) { - return func(mTx *mock.MockStore) { +func expectInsertedParam(name, newValue string) func(store *dbmock.MockStore) { + return func(mTx *dbmock.MockStore) { mTx.EXPECT().InsertParameterValue(gomock.Any(), insertParameterMatcher{name, newValue}). Times(1). Return(database.ParameterValue{}, nil)