From 7f2a99fec5486b9df4deb672b7a5e164351ce705 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 01:01:30 +0000 Subject: [PATCH 01/16] chore: Rename ProjectHistory to ProjectVersion Version more accurately represents version storage. This forks from the WorkspaceHistory name, but I think it's easier to understand Workspace history. --- coderd/coderd.go | 16 +- coderd/projecthistory.go | 86 ++-- coderd/projecthistory_test.go | 16 +- coderd/projectparameter/projectparameter.go | 52 +-- .../projectparameter/projectparameter_test.go | 18 +- coderd/projects_test.go | 8 +- coderd/provisionerdaemons.go | 34 +- coderd/workspacehistory.go | 30 +- coderd/workspacehistory_test.go | 32 +- coderd/workspacehistorylogs_test.go | 12 +- codersdk/projects.go | 42 +- codersdk/projects_test.go | 12 +- codersdk/workspaces.go | 10 +- codersdk/workspaces_test.go | 2 +- database/databasefake/databasefake.go | 84 ++-- database/dump.sql | 36 +- database/migrations/000002_projects.up.sql | 12 +- database/migrations/000003_workspaces.up.sql | 2 +- database/models.go | 46 +- database/querier.go | 14 +- database/query.sql | 36 +- database/query.sql.go | 420 +++++++++--------- httpmw/projecthistoryparam.go | 32 +- httpmw/projecthistoryparam_test.go | 18 +- provisionerd/proto/provisionerd.pb.go | 24 +- provisionerd/proto/provisionerd.proto | 4 +- provisionerd/provisionerd.go | 4 +- 27 files changed, 551 insertions(+), 551 deletions(-) diff --git a/coderd/coderd.go b/coderd/coderd.go index 0aedb1d0c6847..cd60b044e9d33 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -66,13 +66,13 @@ func New(options *Options) http.Handler { r.Get("/", api.parametersByProject) r.Post("/", api.postParametersByProject) }) - r.Route("/history", func(r chi.Router) { - r.Get("/", api.projectHistoryByOrganization) - r.Post("/", api.postProjectHistoryByOrganization) - r.Route("/{projecthistory}", func(r chi.Router) { - r.Use(httpmw.ExtractProjectHistoryParam(api.Database)) - r.Get("/", api.projectHistoryByOrganizationAndName) - r.Get("/parameters", api.projectHistoryParametersByOrganizationAndName) + r.Route("/versions", func(r chi.Router) { + r.Get("/", api.projectVersionsByOrganization) + r.Post("/", api.postProjectVersionByOrganization) + r.Route("/{projectversion}", func(r chi.Router) { + r.Use(httpmw.ExtractProjectVersionParam(api.Database)) + r.Get("/", api.projectVersionByOrganizationAndName) + r.Get("/parameters", api.projectVersionParametersByOrganizationAndName) }) }) }) @@ -91,7 +91,7 @@ func New(options *Options) http.Handler { r.Route("/{workspace}", func(r chi.Router) { r.Use(httpmw.ExtractWorkspaceParam(options.Database)) r.Get("/", api.workspaceByUser) - r.Route("/history", func(r chi.Router) { + r.Route("/version", func(r chi.Router) { r.Post("/", api.postWorkspaceHistoryByUser) r.Get("/", api.workspaceHistoryByUser) r.Route("/{workspacehistory}", func(r chi.Router) { diff --git a/coderd/projecthistory.go b/coderd/projecthistory.go index 36d4a38f95736..ac1906f2be069 100644 --- a/coderd/projecthistory.go +++ b/coderd/projecthistory.go @@ -20,8 +20,8 @@ import ( "github.com/coder/coder/httpmw" ) -// ProjectHistory is the JSON representation of Coder project version history. -type ProjectHistory struct { +// ProjectVersion represents a single version of a project. +type ProjectVersion struct { ID uuid.UUID `json:"id"` ProjectID uuid.UUID `json:"project_id"` CreatedAt time.Time `json:"created_at"` @@ -31,11 +31,11 @@ type ProjectHistory struct { Import ProvisionerJob `json:"import"` } -// ProjectParameter represents a parameter parsed from project history source on creation. +// ProjectParameter represents a parameter parsed from project version source on creation. type ProjectParameter struct { ID uuid.UUID `json:"id"` CreatedAt time.Time `json:"created_at"` - ProjectHistoryID uuid.UUID `json:"project_history_id"` + ProjectVersionID uuid.UUID `json:"project_version_id"` Name string `json:"name"` Description string `json:"description,omitempty"` DefaultSourceScheme database.ParameterSourceScheme `json:"default_source_scheme,omitempty"` @@ -52,28 +52,28 @@ type ProjectParameter struct { ValidationValueType string `json:"validation_value_type,omitempty"` } -// CreateProjectHistoryRequest enables callers to create a new Project Version. -type CreateProjectHistoryRequest struct { +// CreateProjectVersionRequest enables callers to create a new Project Version. +type CreateProjectVersionRequest struct { StorageMethod database.ProjectStorageMethod `json:"storage_method" validate:"oneof=inline-archive,required"` StorageSource []byte `json:"storage_source" validate:"max=1048576,required"` } -// Lists history for a single project. -func (api *api) projectHistoryByOrganization(rw http.ResponseWriter, r *http.Request) { +// Lists versions for a single project. +func (api *api) projectVersionsByOrganization(rw http.ResponseWriter, r *http.Request) { project := httpmw.ProjectParam(r) - history, err := api.Database.GetProjectHistoryByProjectID(r.Context(), project.ID) + version, err := api.Database.GetProjectVersionByProjectID(r.Context(), project.ID) if errors.Is(err, sql.ErrNoRows) { err = nil } if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ - Message: fmt.Sprintf("get project history: %s", err), + Message: fmt.Sprintf("get project version: %s", err), }) return } - apiHistory := make([]ProjectHistory, 0) - for _, version := range history { + apiVersion := make([]ProjectVersion, 0) + for _, version := range version { job, err := api.Database.GetProvisionerJobByID(r.Context(), version.ImportJobID) if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ @@ -81,16 +81,16 @@ func (api *api) projectHistoryByOrganization(rw http.ResponseWriter, r *http.Req }) return } - apiHistory = append(apiHistory, convertProjectHistory(version, job)) + apiVersion = append(apiVersion, convertProjectVersion(version, job)) } render.Status(r, http.StatusOK) - render.JSON(rw, r, apiHistory) + render.JSON(rw, r, apiVersion) } -// Return a single project history by organization and name. -func (api *api) projectHistoryByOrganizationAndName(rw http.ResponseWriter, r *http.Request) { - projectHistory := httpmw.ProjectHistoryParam(r) - job, err := api.Database.GetProvisionerJobByID(r.Context(), projectHistory.ImportJobID) +// Return a single project version by organization and name. +func (api *api) projectVersionByOrganizationAndName(rw http.ResponseWriter, r *http.Request) { + projectVersion := httpmw.ProjectVersionParam(r) + job, err := api.Database.GetProvisionerJobByID(r.Context(), projectVersion.ImportJobID) if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ Message: fmt.Sprintf("get provisioner job: %s", err), @@ -98,14 +98,14 @@ func (api *api) projectHistoryByOrganizationAndName(rw http.ResponseWriter, r *h return } render.Status(r, http.StatusOK) - render.JSON(rw, r, convertProjectHistory(projectHistory, job)) + render.JSON(rw, r, convertProjectVersion(projectVersion, job)) } // Creates a new version of the project. An import job is queued to parse // the storage method provided. Once completed, the import job will specify // the version as latest. -func (api *api) postProjectHistoryByOrganization(rw http.ResponseWriter, r *http.Request) { - var createProjectVersion CreateProjectHistoryRequest +func (api *api) postProjectVersionByOrganization(rw http.ResponseWriter, r *http.Request) { + var createProjectVersion CreateProjectVersionRequest if !httpapi.Read(rw, r, &createProjectVersion) { return } @@ -131,11 +131,11 @@ func (api *api) postProjectHistoryByOrganization(rw http.ResponseWriter, r *http project := httpmw.ProjectParam(r) var provisionerJob database.ProvisionerJob - var projectHistory database.ProjectHistory + var projectVersion database.ProjectVersion err := api.Database.InTx(func(db database.Store) error { - projectHistoryID := uuid.New() + projectVersionID := uuid.New() input, err := json.Marshal(projectImportJob{ - ProjectHistoryID: projectHistoryID, + ProjectVersionID: projectVersionID, }) if err != nil { return xerrors.Errorf("marshal import job: %w", err) @@ -155,8 +155,8 @@ func (api *api) postProjectHistoryByOrganization(rw http.ResponseWriter, r *http return xerrors.Errorf("insert provisioner job: %w", err) } - projectHistory, err = api.Database.InsertProjectHistory(r.Context(), database.InsertProjectHistoryParams{ - ID: projectHistoryID, + projectVersion, err = api.Database.InsertProjectVersion(r.Context(), database.InsertProjectVersionParams{ + ID: projectVersionID, ProjectID: project.ID, CreatedAt: database.Now(), UpdatedAt: database.Now(), @@ -166,7 +166,7 @@ func (api *api) postProjectHistoryByOrganization(rw http.ResponseWriter, r *http ImportJobID: provisionerJob.ID, }) if err != nil { - return xerrors.Errorf("insert project history: %s", err) + return xerrors.Errorf("insert project version: %s", err) } return nil }) @@ -178,12 +178,12 @@ func (api *api) postProjectHistoryByOrganization(rw http.ResponseWriter, r *http } render.Status(r, http.StatusCreated) - render.JSON(rw, r, convertProjectHistory(projectHistory, provisionerJob)) + render.JSON(rw, r, convertProjectVersion(projectVersion, provisionerJob)) } -func (api *api) projectHistoryParametersByOrganizationAndName(rw http.ResponseWriter, r *http.Request) { - projectHistory := httpmw.ProjectHistoryParam(r) - job, err := api.Database.GetProvisionerJobByID(r.Context(), projectHistory.ImportJobID) +func (api *api) projectVersionParametersByOrganizationAndName(rw http.ResponseWriter, r *http.Request) { + projectVersion := httpmw.ProjectVersionParam(r) + job, err := api.Database.GetProvisionerJobByID(r.Context(), projectVersion.ImportJobID) if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ Message: fmt.Sprintf("get provisioner job: %s", err), @@ -204,7 +204,7 @@ func (api *api) projectHistoryParametersByOrganizationAndName(rw http.ResponseWr return } - parameters, err := api.Database.GetProjectParametersByHistoryID(r.Context(), projectHistory.ID) + parameters, err := api.Database.GetProjectParametersByVersionID(r.Context(), projectVersion.ID) if errors.Is(err, sql.ErrNoRows) { err = nil parameters = []database.ProjectParameter{} @@ -225,14 +225,14 @@ func (api *api) projectHistoryParametersByOrganizationAndName(rw http.ResponseWr render.JSON(rw, r, apiParameters) } -func convertProjectHistory(history database.ProjectHistory, job database.ProvisionerJob) ProjectHistory { - return ProjectHistory{ - ID: history.ID, - ProjectID: history.ProjectID, - CreatedAt: history.CreatedAt, - UpdatedAt: history.UpdatedAt, - Name: history.Name, - StorageMethod: history.StorageMethod, +func convertProjectVersion(version database.ProjectVersion, job database.ProvisionerJob) ProjectVersion { + return ProjectVersion{ + ID: version.ID, + ProjectID: version.ProjectID, + CreatedAt: version.CreatedAt, + UpdatedAt: version.UpdatedAt, + Name: version.Name, + StorageMethod: version.StorageMethod, Import: convertProvisionerJob(job), } } @@ -241,7 +241,7 @@ func convertProjectParameter(parameter database.ProjectParameter) ProjectParamet return ProjectParameter{ ID: parameter.ID, CreatedAt: parameter.CreatedAt, - ProjectHistoryID: parameter.ProjectHistoryID, + ProjectVersionID: parameter.ProjectVersionID, Name: parameter.Name, Description: parameter.Description, DefaultSourceScheme: parameter.DefaultSourceScheme, @@ -259,6 +259,6 @@ func convertProjectParameter(parameter database.ProjectParameter) ProjectParamet } } -func projectHistoryLogsChannel(projectHistoryID uuid.UUID) string { - return fmt.Sprintf("project-history-logs:%s", projectHistoryID) +func projectVersionLogsChannel(projectVersionID uuid.UUID) string { + return fmt.Sprintf("project-version-logs:%s", projectVersionID) } diff --git a/coderd/projecthistory_test.go b/coderd/projecthistory_test.go index a0cf932886835..69d8d011b42d6 100644 --- a/coderd/projecthistory_test.go +++ b/coderd/projecthistory_test.go @@ -15,7 +15,7 @@ import ( "github.com/coder/coder/provisionersdk/proto" ) -func TestProjectHistory(t *testing.T) { +func TestProjectVersion(t *testing.T) { t.Parallel() t.Run("NoHistory", func(t *testing.T) { @@ -27,12 +27,12 @@ func TestProjectHistory(t *testing.T) { Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - versions, err := server.Client.ListProjectHistory(context.Background(), user.Organization, project.Name) + versions, err := server.Client.ProjectVersions(context.Background(), user.Organization, project.Name) require.NoError(t, err) require.Len(t, versions, 0) }) - t.Run("CreateHistory", func(t *testing.T) { + t.Run("CreateVersion", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) user := server.RandomInitialUser(t) @@ -47,16 +47,16 @@ func TestProjectHistory(t *testing.T) { }, }}, nil) require.NoError(t, err) - history, err := server.Client.CreateProjectHistory(context.Background(), user.Organization, project.Name, coderd.CreateProjectHistoryRequest{ + version, err := server.Client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ StorageMethod: database.ProjectStorageMethodInlineArchive, StorageSource: data, }) require.NoError(t, err) - versions, err := server.Client.ListProjectHistory(context.Background(), user.Organization, project.Name) + versions, err := server.Client.ProjectVersions(context.Background(), user.Organization, project.Name) require.NoError(t, err) require.Len(t, versions, 1) - _, err = server.Client.ProjectHistory(context.Background(), user.Organization, project.Name, history.Name) + _, err = server.Client.ProjectVersion(context.Background(), user.Organization, project.Name, version.Name) require.NoError(t, err) }) @@ -78,7 +78,7 @@ func TestProjectHistory(t *testing.T) { require.NoError(t, err) _, err = writer.Write(make([]byte, 1<<21)) require.NoError(t, err) - _, err = server.Client.CreateProjectHistory(context.Background(), user.Organization, project.Name, coderd.CreateProjectHistoryRequest{ + _, err = server.Client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ StorageMethod: database.ProjectStorageMethodInlineArchive, StorageSource: buffer.Bytes(), }) @@ -94,7 +94,7 @@ func TestProjectHistory(t *testing.T) { Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - _, err = server.Client.CreateProjectHistory(context.Background(), user.Organization, project.Name, coderd.CreateProjectHistoryRequest{ + _, err = server.Client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ StorageMethod: database.ProjectStorageMethodInlineArchive, StorageSource: []byte{}, }) diff --git a/coderd/projectparameter/projectparameter.go b/coderd/projectparameter/projectparameter.go index 95975849e0ddf..0ba65eae8f168 100644 --- a/coderd/projectparameter/projectparameter.go +++ b/coderd/projectparameter/projectparameter.go @@ -17,7 +17,7 @@ import ( type Scope struct { OrganizationID string ProjectID uuid.UUID - ProjectHistoryID uuid.UUID + ProjectVersionID uuid.UUID UserID string WorkspaceID uuid.UUID WorkspaceHistoryID uuid.UUID @@ -40,21 +40,21 @@ func Compute(ctx context.Context, db database.Store, scope Scope) ([]Value, erro compute := &compute{ db: db, computedParameterByName: map[string]Value{}, - projectHistoryParametersByName: map[string]database.ProjectParameter{}, + projectVersionParametersByName: map[string]database.ProjectParameter{}, } // All parameters for the project version! - projectHistoryParameters, err := db.GetProjectParametersByHistoryID(ctx, scope.ProjectHistoryID) + projectVersionParameters, err := db.GetProjectParametersByVersionID(ctx, scope.ProjectVersionID) if errors.Is(err, sql.ErrNoRows) { - // This occurs when the project history has defined + // This occurs when the project version has defined // no parameters, so we have nothing to compute! return []Value{}, nil } if err != nil { return nil, xerrors.Errorf("get project parameters: %w", err) } - for _, projectHistoryParameter := range projectHistoryParameters { - compute.projectHistoryParametersByName[projectHistoryParameter.Name] = projectHistoryParameter + for _, projectVersionParameter := range projectVersionParameters { + compute.projectVersionParametersByName[projectVersionParameter.Name] = projectVersionParameter } // Organization parameters come first! @@ -67,33 +67,33 @@ func Compute(ctx context.Context, db database.Store, scope Scope) ([]Value, erro } // Default project parameter values come second! - for _, projectHistoryParameter := range projectHistoryParameters { - if !projectHistoryParameter.DefaultSourceValue.Valid { + for _, projectVersionParameter := range projectVersionParameters { + if !projectVersionParameter.DefaultSourceValue.Valid { continue } - if !projectHistoryParameter.DefaultDestinationValue.Valid { + if !projectVersionParameter.DefaultDestinationValue.Valid { continue } - destinationScheme, err := convertDestinationScheme(projectHistoryParameter.DefaultDestinationScheme) + destinationScheme, err := convertDestinationScheme(projectVersionParameter.DefaultDestinationScheme) if err != nil { - return nil, xerrors.Errorf("convert default destination scheme for project history parameter %q: %w", projectHistoryParameter.Name, err) + return nil, xerrors.Errorf("convert default destination scheme for project version parameter %q: %w", projectVersionParameter.Name, err) } - switch projectHistoryParameter.DefaultSourceScheme { + switch projectVersionParameter.DefaultSourceScheme { case database.ParameterSourceSchemeData: - compute.computedParameterByName[projectHistoryParameter.Name] = Value{ + compute.computedParameterByName[projectVersionParameter.Name] = Value{ Proto: &proto.ParameterValue{ DestinationScheme: destinationScheme, - Name: projectHistoryParameter.DefaultDestinationValue.String, - Value: projectHistoryParameter.DefaultSourceValue.String, + Name: projectVersionParameter.DefaultDestinationValue.String, + Value: projectVersionParameter.DefaultSourceValue.String, }, DefaultValue: true, Scope: database.ParameterScopeProject, ScopeID: scope.ProjectID.String(), } default: - return nil, xerrors.Errorf("unsupported source scheme for project history parameter %q: %q", projectHistoryParameter.Name, string(projectHistoryParameter.DefaultSourceScheme)) + return nil, xerrors.Errorf("unsupported source scheme for project version parameter %q: %q", projectVersionParameter.Name, string(projectVersionParameter.DefaultSourceScheme)) } } @@ -124,13 +124,13 @@ func Compute(ctx context.Context, db database.Store, scope Scope) ([]Value, erro return nil, err } - for _, projectHistoryParameter := range compute.projectHistoryParametersByName { - if _, ok := compute.computedParameterByName[projectHistoryParameter.Name]; ok { + for _, projectVersionParameter := range compute.projectVersionParametersByName { + if _, ok := compute.computedParameterByName[projectVersionParameter.Name]; ok { continue } return nil, NoValueError{ - ParameterID: projectHistoryParameter.ID, - ParameterName: projectHistoryParameter.Name, + ParameterID: projectVersionParameter.ID, + ParameterName: projectVersionParameter.Name, } } @@ -144,7 +144,7 @@ func Compute(ctx context.Context, db database.Store, scope Scope) ([]Value, erro type compute struct { db database.Store computedParameterByName map[string]Value - projectHistoryParametersByName map[string]database.ProjectParameter + projectVersionParametersByName map[string]database.ProjectParameter } // Validates and computes the value for parameters; setting the value on "parameterByName". @@ -158,8 +158,8 @@ func (c *compute) inject(ctx context.Context, scopeParams database.GetParameterV } for _, scopedParameter := range scopedParameters { - projectHistoryParameter, hasProjectHistoryParameter := c.projectHistoryParametersByName[scopedParameter.Name] - if !hasProjectHistoryParameter { + projectVersionParameter, hasProjectVersionParameter := c.projectVersionParametersByName[scopedParameter.Name] + if !hasProjectVersionParameter { // Don't inject parameters that aren't defined by the project. continue } @@ -169,7 +169,7 @@ func (c *compute) inject(ctx context.Context, scopeParams database.GetParameterV // If a parameter already exists, check if this variable can override it. // Injection hierarchy is the responsibility of the caller. This check ensures // project parameters cannot be overridden if already set. - if !projectHistoryParameter.AllowOverrideSource && scopedParameter.Scope != database.ParameterScopeProject { + if !projectVersionParameter.AllowOverrideSource && scopedParameter.Scope != database.ParameterScopeProject { continue } } @@ -181,7 +181,7 @@ func (c *compute) inject(ctx context.Context, scopeParams database.GetParameterV switch scopedParameter.SourceScheme { case database.ParameterSourceSchemeData: - c.computedParameterByName[projectHistoryParameter.Name] = Value{ + c.computedParameterByName[projectVersionParameter.Name] = Value{ Proto: &proto.ParameterValue{ DestinationScheme: destinationScheme, Name: scopedParameter.SourceValue, @@ -189,7 +189,7 @@ func (c *compute) inject(ctx context.Context, scopeParams database.GetParameterV }, } default: - return xerrors.Errorf("unsupported source scheme: %q", string(projectHistoryParameter.DefaultSourceScheme)) + return xerrors.Errorf("unsupported source scheme: %q", string(projectVersionParameter.DefaultSourceScheme)) } } return nil diff --git a/coderd/projectparameter/projectparameter_test.go b/coderd/projectparameter/projectparameter_test.go index 5b562175497e6..1cc2cd80f95ae 100644 --- a/coderd/projectparameter/projectparameter_test.go +++ b/coderd/projectparameter/projectparameter_test.go @@ -21,7 +21,7 @@ func TestCompute(t *testing.T) { return projectparameter.Scope{ OrganizationID: uuid.New().String(), ProjectID: uuid.New(), - ProjectHistoryID: uuid.New(), + ProjectVersionID: uuid.New(), UserID: uuid.NewString(), } } @@ -29,7 +29,7 @@ func TestCompute(t *testing.T) { AllowOverrideSource bool AllowOverrideDestination bool DefaultDestinationScheme database.ParameterDestinationScheme - ProjectHistoryID uuid.UUID + ProjectVersionID uuid.UUID } generateProjectParameter := func(t *testing.T, db database.Store, opts projectParameterOptions) database.ProjectParameter { if opts.DefaultDestinationScheme == "" { @@ -44,7 +44,7 @@ func TestCompute(t *testing.T) { param, err := db.InsertProjectParameter(context.Background(), database.InsertProjectParameterParams{ ID: uuid.New(), Name: name, - ProjectHistoryID: opts.ProjectHistoryID, + ProjectVersionID: opts.ProjectVersionID, DefaultSourceScheme: database.ParameterSourceSchemeData, DefaultSourceValue: sql.NullString{ String: sourceValue, @@ -68,7 +68,7 @@ func TestCompute(t *testing.T) { scope := generateScope() parameter, err := db.InsertProjectParameter(context.Background(), database.InsertProjectParameterParams{ ID: uuid.New(), - ProjectHistoryID: scope.ProjectHistoryID, + ProjectVersionID: scope.ProjectVersionID, Name: "hey", }) require.NoError(t, err) @@ -85,7 +85,7 @@ func TestCompute(t *testing.T) { db := databasefake.New() scope := generateScope() parameter := generateProjectParameter(t, db, projectParameterOptions{ - ProjectHistoryID: scope.ProjectHistoryID, + ProjectVersionID: scope.ProjectVersionID, DefaultDestinationScheme: database.ParameterDestinationSchemeProvisionerVariable, }) values, err := projectparameter.Compute(context.Background(), db, scope) @@ -105,7 +105,7 @@ func TestCompute(t *testing.T) { db := databasefake.New() scope := generateScope() parameter := generateProjectParameter(t, db, projectParameterOptions{ - ProjectHistoryID: scope.ProjectHistoryID, + ProjectVersionID: scope.ProjectVersionID, }) _, err := db.InsertParameterValue(context.Background(), database.InsertParameterValueParams{ ID: uuid.New(), @@ -131,7 +131,7 @@ func TestCompute(t *testing.T) { db := databasefake.New() scope := generateScope() parameter := generateProjectParameter(t, db, projectParameterOptions{ - ProjectHistoryID: scope.ProjectHistoryID, + ProjectVersionID: scope.ProjectVersionID, }) value, err := db.InsertParameterValue(context.Background(), database.InsertParameterValueParams{ ID: uuid.New(), @@ -157,7 +157,7 @@ func TestCompute(t *testing.T) { db := databasefake.New() scope := generateScope() parameter := generateProjectParameter(t, db, projectParameterOptions{ - ProjectHistoryID: scope.ProjectHistoryID, + ProjectVersionID: scope.ProjectVersionID, }) _, err := db.InsertParameterValue(context.Background(), database.InsertParameterValueParams{ ID: uuid.New(), @@ -183,7 +183,7 @@ func TestCompute(t *testing.T) { scope := generateScope() parameter := generateProjectParameter(t, db, projectParameterOptions{ AllowOverrideSource: true, - ProjectHistoryID: scope.ProjectHistoryID, + ProjectVersionID: scope.ProjectVersionID, }) _, err := db.InsertParameterValue(context.Background(), database.InsertParameterValueParams{ ID: uuid.New(), diff --git a/coderd/projects_test.go b/coderd/projects_test.go index 14ed1af4f03b1..b5bbc03766522 100644 --- a/coderd/projects_test.go +++ b/coderd/projects_test.go @@ -148,17 +148,17 @@ func TestProjects(t *testing.T) { }, }}, nil) require.NoError(t, err) - history, err := server.Client.CreateProjectHistory(context.Background(), user.Organization, project.Name, coderd.CreateProjectHistoryRequest{ + version, err := server.Client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ StorageMethod: database.ProjectStorageMethodInlineArchive, StorageSource: data, }) require.NoError(t, err) require.Eventually(t, func() bool { - projectHistory, err := server.Client.ProjectHistory(context.Background(), user.Organization, project.Name, history.Name) + projectVersion, err := server.Client.ProjectVersion(context.Background(), user.Organization, project.Name, version.Name) require.NoError(t, err) - return projectHistory.Import.Status.Completed() + return projectVersion.Import.Status.Completed() }, 15*time.Second, 10*time.Millisecond) - params, err := server.Client.ProjectHistoryParameters(context.Background(), user.Organization, project.Name, history.Name) + params, err := server.Client.ProjectVersionParameters(context.Background(), user.Organization, project.Name, version.Name) require.NoError(t, err) require.Len(t, params, 1) require.Equal(t, "example", params[0].Name) diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index 445f9ed1710ac..69886a6848a40 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -106,7 +106,7 @@ type workspaceProvisionJob struct { // The input for a "project_import" job. type projectImportJob struct { - ProjectHistoryID uuid.UUID `json:"project_history_id"` + ProjectVersionID uuid.UUID `json:"project_version_id"` } // Implementation of the provisioner daemon protobuf server. @@ -182,7 +182,7 @@ func (server *provisionerdServer) AcquireJob(ctx context.Context, _ *proto.Empty ProjectName: project.Name, UserName: user.Username, } - var projectHistory database.ProjectHistory + var projectVersion database.ProjectVersion switch job.Type { case database.ProvisionerJobTypeWorkspaceProvision: var input workspaceProvisionJob @@ -198,16 +198,16 @@ func (server *provisionerdServer) AcquireJob(ctx context.Context, _ *proto.Empty if err != nil { return nil, failJob(fmt.Sprintf("get workspace: %s", err)) } - projectHistory, err = server.Database.GetProjectHistoryByID(ctx, workspaceHistory.ProjectHistoryID) + projectVersion, err = server.Database.GetProjectVersionByID(ctx, workspaceHistory.ProjectVersionID) if err != nil { - return nil, failJob(fmt.Sprintf("get project history: %s", err)) + return nil, failJob(fmt.Sprintf("get project version: %s", err)) } // Compute parameters for the workspace to consume. parameters, err := projectparameter.Compute(ctx, server.Database, projectparameter.Scope{ OrganizationID: organization.ID, ProjectID: project.ID, - ProjectHistoryID: projectHistory.ID, + ProjectVersionID: projectVersion.ID, UserID: user.ID, WorkspaceID: workspace.ID, WorkspaceHistoryID: workspaceHistory.ID, @@ -249,23 +249,23 @@ func (server *provisionerdServer) AcquireJob(ctx context.Context, _ *proto.Empty if err != nil { return nil, failJob(fmt.Sprintf("unmarshal job input %q: %s", job.Input, err)) } - projectHistory, err = server.Database.GetProjectHistoryByID(ctx, input.ProjectHistoryID) + projectVersion, err = server.Database.GetProjectVersionByID(ctx, input.ProjectVersionID) if err != nil { - return nil, failJob(fmt.Sprintf("get project history: %s", err)) + return nil, failJob(fmt.Sprintf("get project version: %s", err)) } protoJob.Type = &proto.AcquiredJob_ProjectImport_{ ProjectImport: &proto.AcquiredJob_ProjectImport{ - ProjectHistoryId: projectHistory.ID.String(), - ProjectHistoryName: projectHistory.Name, + ProjectVersionId: projectVersion.ID.String(), + ProjectVersionName: projectVersion.Name, }, } } - switch projectHistory.StorageMethod { + switch projectVersion.StorageMethod { case database.ProjectStorageMethodInlineArchive: - protoJob.ProjectSourceArchive = projectHistory.StorageSource + protoJob.ProjectSourceArchive = projectVersion.StorageSource default: - return nil, failJob(fmt.Sprintf("unsupported storage source: %q", projectHistory.StorageMethod)) + return nil, failJob(fmt.Sprintf("unsupported storage source: %q", projectVersion.StorageMethod)) } return protoJob, err @@ -309,8 +309,8 @@ func (server *provisionerdServer) UpdateJob(stream proto.DRPCProvisionerDaemon_U if err != nil { return xerrors.Errorf("unmarshal job input %q: %s", job.Input, err) } - insertParams := database.InsertProjectHistoryLogsParams{ - ProjectHistoryID: input.ProjectHistoryID, + insertParams := database.InsertProjectVersionLogsParams{ + ProjectVersionID: input.ProjectVersionID, } for _, log := range update.ProjectImportLogs { logLevel, err := convertLogLevel(log.Level) @@ -327,7 +327,7 @@ func (server *provisionerdServer) UpdateJob(stream proto.DRPCProvisionerDaemon_U insertParams.Source = append(insertParams.Source, logSource) insertParams.Output = append(insertParams.Output, log.Output) } - logs, err := server.Database.InsertProjectHistoryLogs(stream.Context(), insertParams) + logs, err := server.Database.InsertProjectVersionLogs(stream.Context(), insertParams) if err != nil { return xerrors.Errorf("insert project logs: %w", err) } @@ -335,7 +335,7 @@ func (server *provisionerdServer) UpdateJob(stream proto.DRPCProvisionerDaemon_U if err != nil { return xerrors.Errorf("marshal project log: %w", err) } - err = server.Pubsub.Publish(projectHistoryLogsChannel(input.ProjectHistoryID), data) + err = server.Pubsub.Publish(projectVersionLogsChannel(input.ProjectVersionID), data) if err != nil { return xerrors.Errorf("publish history log: %w", err) } @@ -442,7 +442,7 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr projectParameter := database.InsertProjectParameterParams{ ID: uuid.New(), CreatedAt: database.Now(), - ProjectHistoryID: input.ProjectHistoryID, + ProjectVersionID: input.ProjectVersionID, Name: protoParameter.Name, Description: protoParameter.Description, RedisplayValue: protoParameter.RedisplayValue, diff --git a/coderd/workspacehistory.go b/coderd/workspacehistory.go index 59ba0ed9e7905..8ebdee7df1702 100644 --- a/coderd/workspacehistory.go +++ b/coderd/workspacehistory.go @@ -25,7 +25,7 @@ type WorkspaceHistory struct { CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` WorkspaceID uuid.UUID `json:"workspace_id"` - ProjectHistoryID uuid.UUID `json:"project_history_id"` + ProjectVersionID uuid.UUID `json:"project_version_id"` BeforeID uuid.UUID `json:"before_id"` AfterID uuid.UUID `json:"after_id"` Name string `json:"name"` @@ -36,7 +36,7 @@ type WorkspaceHistory struct { // CreateWorkspaceHistoryRequest provides options to update the latest workspace history. type CreateWorkspaceHistoryRequest struct { - ProjectHistoryID uuid.UUID `json:"project_history_id" validate:"required"` + ProjectVersionID uuid.UUID `json:"project_version_id" validate:"required"` Transition database.WorkspaceTransition `json:"transition" validate:"oneof=create start stop delete,required"` } @@ -47,12 +47,12 @@ func (api *api) postWorkspaceHistoryByUser(rw http.ResponseWriter, r *http.Reque } user := httpmw.UserParam(r) workspace := httpmw.WorkspaceParam(r) - projectHistory, err := api.Database.GetProjectHistoryByID(r.Context(), createBuild.ProjectHistoryID) + projectVersion, err := api.Database.GetProjectVersionByID(r.Context(), createBuild.ProjectVersionID) if errors.Is(err, sql.ErrNoRows) { httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ - Message: "project history not found", + Message: "project version not found", Errors: []httpapi.Error{{ - Field: "project_history_id", + Field: "project_version_id", Code: "exists", }}, }) @@ -60,36 +60,36 @@ func (api *api) postWorkspaceHistoryByUser(rw http.ResponseWriter, r *http.Reque } if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ - Message: fmt.Sprintf("get project history: %s", err), + Message: fmt.Sprintf("get project version: %s", err), }) return } - projectHistoryJob, err := api.Database.GetProvisionerJobByID(r.Context(), projectHistory.ImportJobID) + projectVersionJob, err := api.Database.GetProvisionerJobByID(r.Context(), projectVersion.ImportJobID) if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ Message: fmt.Sprintf("get provisioner job: %s", err), }) return } - projectHistoryJobStatus := convertProvisionerJob(projectHistoryJob).Status - switch projectHistoryJobStatus { + projectVersionJobStatus := convertProvisionerJob(projectVersionJob).Status + switch projectVersionJobStatus { case ProvisionerJobStatusPending, ProvisionerJobStatusRunning: httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{ - Message: fmt.Sprintf("The provided project history is %s. Wait for it to complete importing!", projectHistoryJobStatus), + Message: fmt.Sprintf("The provided project version is %s. Wait for it to complete importing!", projectVersionJobStatus), }) return case ProvisionerJobStatusFailed: httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ - Message: fmt.Sprintf("The provided project history %q has failed to import. You cannot create workspaces using it!", projectHistory.Name), + Message: fmt.Sprintf("The provided project version %q has failed to import. You cannot create workspaces using it!", projectVersion.Name), }) return case ProvisionerJobStatusCancelled: httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{ - Message: "The provided project history was canceled during import. You cannot create workspaces using it!", + Message: "The provided project version was canceled during import. You cannot create workspaces using it!", }) } - project, err := api.Database.GetProjectByID(r.Context(), projectHistory.ProjectID) + project, err := api.Database.GetProjectByID(r.Context(), projectVersion.ProjectID) if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ Message: fmt.Sprintf("get project: %s", err), @@ -154,7 +154,7 @@ func (api *api) postWorkspaceHistoryByUser(rw http.ResponseWriter, r *http.Reque CreatedAt: database.Now(), UpdatedAt: database.Now(), WorkspaceID: workspace.ID, - ProjectHistoryID: projectHistory.ID, + ProjectVersionID: projectVersion.ID, BeforeID: priorHistoryID, Name: namesgenerator.GetRandomName(1), Initiator: user.ID, @@ -246,7 +246,7 @@ func convertWorkspaceHistory(workspaceHistory database.WorkspaceHistory, provisi CreatedAt: workspaceHistory.CreatedAt, UpdatedAt: workspaceHistory.UpdatedAt, WorkspaceID: workspaceHistory.WorkspaceID, - ProjectHistoryID: workspaceHistory.ProjectHistoryID, + ProjectVersionID: workspaceHistory.ProjectVersionID, BeforeID: workspaceHistory.BeforeID.UUID, AfterID: workspaceHistory.AfterID.UUID, Name: workspaceHistory.Name, diff --git a/coderd/workspacehistory_test.go b/coderd/workspacehistory_test.go index d65e82fd10ecb..484269892ad3f 100644 --- a/coderd/workspacehistory_test.go +++ b/coderd/workspacehistory_test.go @@ -32,19 +32,19 @@ func TestWorkspaceHistory(t *testing.T) { return project, workspace } - setupProjectHistory := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest, project coderd.Project, data []byte) coderd.ProjectHistory { - projectHistory, err := client.CreateProjectHistory(context.Background(), user.Organization, project.Name, coderd.CreateProjectHistoryRequest{ + setupProjectVersion := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest, project coderd.Project, data []byte) coderd.ProjectVersion { + projectVersion, err := client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ StorageMethod: database.ProjectStorageMethodInlineArchive, StorageSource: data, }) require.NoError(t, err) require.Eventually(t, func() bool { - hist, err := client.ProjectHistory(context.Background(), user.Organization, project.Name, projectHistory.Name) + version, err := client.ProjectVersion(context.Background(), user.Organization, project.Name, projectVersion.Name) require.NoError(t, err) - t.Logf("Import status: %s\n", hist.Import.Status) - return hist.Import.Status.Completed() + t.Logf("Import status: %s\n", version.Import.Status) + return version.Import.Status.Completed() }, 15*time.Second, 50*time.Millisecond) - return projectHistory + return projectVersion } t.Run("AllHistory", func(t *testing.T) { @@ -58,9 +58,9 @@ func TestWorkspaceHistory(t *testing.T) { require.Len(t, history, 0) data, err := echo.Tar(echo.ParseComplete, echo.ProvisionComplete) require.NoError(t, err) - projectVersion := setupProjectHistory(t, server.Client, user, project, data) + projectVersion := setupProjectVersion(t, server.Client, user, project, data) _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectHistoryID: projectVersion.ID, + ProjectVersionID: projectVersion.ID, Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) @@ -79,9 +79,9 @@ func TestWorkspaceHistory(t *testing.T) { require.Error(t, err) data, err := echo.Tar(echo.ParseComplete, echo.ProvisionComplete) require.NoError(t, err) - projectHistory := setupProjectHistory(t, server.Client, user, project, data) + projectVersion := setupProjectVersion(t, server.Client, user, project, data) _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectHistoryID: projectHistory.ID, + ProjectVersionID: projectVersion.ID, Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) @@ -97,9 +97,9 @@ func TestWorkspaceHistory(t *testing.T) { project, workspace := setupProjectAndWorkspace(t, server.Client, user) data, err := echo.Tar(echo.ParseComplete, echo.ProvisionComplete) require.NoError(t, err) - projectHistory := setupProjectHistory(t, server.Client, user, project, data) + projectVersion := setupProjectVersion(t, server.Client, user, project, data) _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectHistoryID: projectHistory.ID, + ProjectVersionID: projectVersion.ID, Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) @@ -122,16 +122,16 @@ func TestWorkspaceHistory(t *testing.T) { project, workspace := setupProjectAndWorkspace(t, server.Client, user) data, err := echo.Tar(echo.ParseComplete, echo.ProvisionComplete) require.NoError(t, err) - projectHistory := setupProjectHistory(t, server.Client, user, project, data) + projectVersion := setupProjectVersion(t, server.Client, user, project, data) _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectHistoryID: projectHistory.ID, + ProjectVersionID: projectVersion.ID, Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectHistoryID: projectHistory.ID, + ProjectVersionID: projectVersion.ID, Transition: database.WorkspaceTransitionCreate, }) require.Error(t, err) @@ -145,7 +145,7 @@ func TestWorkspaceHistory(t *testing.T) { _, workspace := setupProjectAndWorkspace(t, server.Client, user) _, err := server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectHistoryID: uuid.New(), + ProjectVersionID: uuid.New(), Transition: database.WorkspaceTransitionCreate, }) require.Error(t, err) diff --git a/coderd/workspacehistorylogs_test.go b/coderd/workspacehistorylogs_test.go index 9e9dd06fbd6db..f507001beb4d5 100644 --- a/coderd/workspacehistorylogs_test.go +++ b/coderd/workspacehistorylogs_test.go @@ -32,18 +32,18 @@ func TestWorkspaceHistoryLogs(t *testing.T) { return project, workspace } - setupProjectHistory := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest, project coderd.Project, data []byte) coderd.ProjectHistory { - projectHistory, err := client.CreateProjectHistory(context.Background(), user.Organization, project.Name, coderd.CreateProjectHistoryRequest{ + setupProjectVersion := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest, project coderd.Project, data []byte) coderd.ProjectVersion { + projectVersion, err := client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ StorageMethod: database.ProjectStorageMethodInlineArchive, StorageSource: data, }) require.NoError(t, err) require.Eventually(t, func() bool { - hist, err := client.ProjectHistory(context.Background(), user.Organization, project.Name, projectHistory.Name) + hist, err := client.ProjectVersion(context.Background(), user.Organization, project.Name, projectVersion.Name) require.NoError(t, err) return hist.Import.Status.Completed() }, 15*time.Second, 50*time.Millisecond) - return projectHistory + return projectVersion } server := coderdtest.New(t) @@ -62,10 +62,10 @@ func TestWorkspaceHistoryLogs(t *testing.T) { }, }}) require.NoError(t, err) - projectHistory := setupProjectHistory(t, server.Client, user, project, data) + projectVersion := setupProjectVersion(t, server.Client, user, project, data) workspaceHistory, err := server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectHistoryID: projectHistory.ID, + ProjectVersionID: projectVersion.ID, Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) diff --git a/codersdk/projects.go b/codersdk/projects.go index 7b43e5d604170..e3805ba3c4d71 100644 --- a/codersdk/projects.go +++ b/codersdk/projects.go @@ -57,9 +57,9 @@ func (c *Client) CreateProject(ctx context.Context, organization string, request return project, json.NewDecoder(res.Body).Decode(&project) } -// ListProjectHistory lists history for a project. -func (c *Client) ListProjectHistory(ctx context.Context, organization, project string) ([]coderd.ProjectHistory, error) { - res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/projects/%s/%s/history", organization, project), nil) +// ProjectVersions lists versions of a project. +func (c *Client) ProjectVersions(ctx context.Context, organization, project string) ([]coderd.ProjectVersion, error) { + res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/projects/%s/%s/versions", organization, project), nil) if err != nil { return nil, err } @@ -67,41 +67,41 @@ func (c *Client) ListProjectHistory(ctx context.Context, organization, project s if res.StatusCode != http.StatusOK { return nil, readBodyAsError(res) } - var projectHistory []coderd.ProjectHistory - return projectHistory, json.NewDecoder(res.Body).Decode(&projectHistory) + var projectVersion []coderd.ProjectVersion + return projectVersion, json.NewDecoder(res.Body).Decode(&projectVersion) } -// ProjectHistory returns project history by name. -func (c *Client) ProjectHistory(ctx context.Context, organization, project, history string) (coderd.ProjectHistory, error) { - res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/projects/%s/%s/history/%s", organization, project, history), nil) +// ProjectVersion returns project version by name. +func (c *Client) ProjectVersion(ctx context.Context, organization, project, version string) (coderd.ProjectVersion, error) { + res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/projects/%s/%s/versions/%s", organization, project, version), nil) if err != nil { - return coderd.ProjectHistory{}, err + return coderd.ProjectVersion{}, err } defer res.Body.Close() if res.StatusCode != http.StatusOK { - return coderd.ProjectHistory{}, readBodyAsError(res) + return coderd.ProjectVersion{}, readBodyAsError(res) } - var projectHistory coderd.ProjectHistory - return projectHistory, json.NewDecoder(res.Body).Decode(&projectHistory) + var projectVersion coderd.ProjectVersion + return projectVersion, json.NewDecoder(res.Body).Decode(&projectVersion) } -// CreateProjectHistory inserts a new version for the project. -func (c *Client) CreateProjectHistory(ctx context.Context, organization, project string, request coderd.CreateProjectHistoryRequest) (coderd.ProjectHistory, error) { - res, err := c.request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/projects/%s/%s/history", organization, project), request) +// CreateProjectVersion inserts a new version for the project. +func (c *Client) CreateProjectVersion(ctx context.Context, organization, project string, request coderd.CreateProjectVersionRequest) (coderd.ProjectVersion, error) { + res, err := c.request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/projects/%s/%s/versions", organization, project), request) if err != nil { - return coderd.ProjectHistory{}, err + return coderd.ProjectVersion{}, err } defer res.Body.Close() if res.StatusCode != http.StatusCreated { - return coderd.ProjectHistory{}, readBodyAsError(res) + return coderd.ProjectVersion{}, readBodyAsError(res) } - var projectVersion coderd.ProjectHistory + var projectVersion coderd.ProjectVersion return projectVersion, json.NewDecoder(res.Body).Decode(&projectVersion) } -// ProjectHistoryParameters returns project parameters for history by name. -func (c *Client) ProjectHistoryParameters(ctx context.Context, organization, project, history string) ([]coderd.ProjectParameter, error) { - res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/projects/%s/%s/history/%s/parameters", organization, project, history), nil) +// ProjectVersionParameters returns project parameters for a version by name. +func (c *Client) ProjectVersionParameters(ctx context.Context, organization, project, version string) ([]coderd.ProjectParameter, error) { + res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/projects/%s/%s/versions/%s/parameters", organization, project, version), nil) if err != nil { return nil, err } diff --git a/codersdk/projects_test.go b/codersdk/projects_test.go index 0645438c249f9..957a759b3e062 100644 --- a/codersdk/projects_test.go +++ b/codersdk/projects_test.go @@ -74,7 +74,7 @@ func TestProjects(t *testing.T) { t.Run("UnauthenticatedHistory", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _, err := server.Client.ListProjectHistory(context.Background(), "org", "project") + _, err := server.Client.ProjectVersions(context.Background(), "org", "project") require.Error(t, err) }) @@ -87,14 +87,14 @@ func TestProjects(t *testing.T) { Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - _, err = server.Client.ListProjectHistory(context.Background(), user.Organization, project.Name) + _, err = server.Client.ProjectVersions(context.Background(), user.Organization, project.Name) require.NoError(t, err) }) t.Run("CreateHistoryUnauthenticated", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _, err := server.Client.CreateProjectHistory(context.Background(), "org", "project", coderd.CreateProjectHistoryRequest{ + _, err := server.Client.CreateProjectVersion(context.Background(), "org", "project", coderd.CreateProjectVersionRequest{ StorageMethod: database.ProjectStorageMethodInlineArchive, StorageSource: []byte{}, }) @@ -119,13 +119,13 @@ func TestProjects(t *testing.T) { require.NoError(t, err) _, err = writer.Write(make([]byte, 1<<10)) require.NoError(t, err) - history, err := server.Client.CreateProjectHistory(context.Background(), user.Organization, project.Name, coderd.CreateProjectHistoryRequest{ + version, err := server.Client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ StorageMethod: database.ProjectStorageMethodInlineArchive, StorageSource: buffer.Bytes(), }) require.NoError(t, err) - _, err = server.Client.ProjectHistory(context.Background(), user.Organization, project.Name, history.Name) + _, err = server.Client.ProjectVersion(context.Background(), user.Organization, project.Name, version.Name) require.NoError(t, err) }) @@ -168,7 +168,7 @@ func TestProjects(t *testing.T) { t.Parallel() server := coderdtest.New(t) user := server.RandomInitialUser(t) - _, err := server.Client.ProjectHistoryParameters(context.Background(), user.Organization, "nothing", "nope") + _, err := server.Client.ProjectVersionParameters(context.Background(), user.Organization, "nothing", "nope") require.Error(t, err) }) } diff --git a/codersdk/workspaces.go b/codersdk/workspaces.go index 79878bf407570..d6ddf14f7b082 100644 --- a/codersdk/workspaces.go +++ b/codersdk/workspaces.go @@ -68,7 +68,7 @@ func (c *Client) ListWorkspaceHistory(ctx context.Context, owner, workspace stri if owner == "" { owner = "me" } - res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/%s/history", owner, workspace), nil) + res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/%s/version", owner, workspace), nil) if err != nil { return nil, err } @@ -89,7 +89,7 @@ func (c *Client) WorkspaceHistory(ctx context.Context, owner, workspace, history if history == "" { history = "latest" } - res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/%s/history/%s", owner, workspace, history), nil) + res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/%s/version/%s", owner, workspace, history), nil) if err != nil { return coderd.WorkspaceHistory{}, err } @@ -123,7 +123,7 @@ func (c *Client) CreateWorkspaceHistory(ctx context.Context, owner, workspace st if owner == "" { owner = "me" } - res, err := c.request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/workspaces/%s/%s/history", owner, workspace), request) + res, err := c.request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/workspaces/%s/%s/version", owner, workspace), request) if err != nil { return coderd.WorkspaceHistory{}, err } @@ -153,7 +153,7 @@ func (c *Client) WorkspaceHistoryLogsBetween(ctx context.Context, owner, workspa if !before.IsZero() { values["before"] = []string{strconv.FormatInt(before.UTC().UnixMilli(), 10)} } - res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/%s/history/%s/logs?%s", owner, workspace, history, values.Encode()), nil) + res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/%s/version/%s/logs?%s", owner, workspace, history, values.Encode()), nil) if err != nil { return nil, err } @@ -177,7 +177,7 @@ func (c *Client) FollowWorkspaceHistoryLogsAfter(ctx context.Context, owner, wor owner = "me" } - res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/%s/history/%s/logs?follow%s", owner, workspace, history, afterQuery), nil) + res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/%s/version/%s/logs?follow%s", owner, workspace, history, afterQuery), nil) if err != nil { return nil, err } diff --git a/codersdk/workspaces_test.go b/codersdk/workspaces_test.go index b030b3741450f..21e0d5bcaa1a6 100644 --- a/codersdk/workspaces_test.go +++ b/codersdk/workspaces_test.go @@ -161,7 +161,7 @@ func TestWorkspaces(t *testing.T) { }) require.NoError(t, err) _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectHistoryID: uuid.New(), + ProjectVersionID: uuid.New(), Transition: database.WorkspaceTransitionCreate, }) require.Error(t, err) diff --git a/database/databasefake/databasefake.go b/database/databasefake/databasefake.go index 36a8671c64f3a..2ee1bf965e878 100644 --- a/database/databasefake/databasefake.go +++ b/database/databasefake/databasefake.go @@ -21,8 +21,8 @@ func New() database.Store { parameterValue: make([]database.ParameterValue, 0), project: make([]database.Project, 0), - projectHistory: make([]database.ProjectHistory, 0), - projectHistoryLog: make([]database.ProjectHistoryLog, 0), + projectVersion: make([]database.ProjectVersion, 0), + projectVersionLog: make([]database.ProjectVersionLog, 0), projectParameter: make([]database.ProjectParameter, 0), provisionerDaemons: make([]database.ProvisionerDaemon, 0), provisionerJobs: make([]database.ProvisionerJob, 0), @@ -47,8 +47,8 @@ type fakeQuerier struct { // New tables parameterValue []database.ParameterValue project []database.Project - projectHistory []database.ProjectHistory - projectHistoryLog []database.ProjectHistoryLog + projectVersion []database.ProjectVersion + projectVersionLog []database.ProjectVersionLog projectParameter []database.ProjectParameter provisionerDaemons []database.ProvisionerDaemon provisionerJobs []database.ProvisionerJob @@ -410,55 +410,55 @@ func (q *fakeQuerier) GetProjectByOrganizationAndName(_ context.Context, arg dat return database.Project{}, sql.ErrNoRows } -func (q *fakeQuerier) GetProjectHistoryByProjectID(_ context.Context, projectID uuid.UUID) ([]database.ProjectHistory, error) { +func (q *fakeQuerier) GetProjectVersionByProjectID(_ context.Context, projectID uuid.UUID) ([]database.ProjectVersion, error) { q.mutex.Lock() defer q.mutex.Unlock() - history := make([]database.ProjectHistory, 0) - for _, projectHistory := range q.projectHistory { - if projectHistory.ProjectID.String() != projectID.String() { + version := make([]database.ProjectVersion, 0) + for _, projectVersion := range q.projectVersion { + if projectVersion.ProjectID.String() != projectID.String() { continue } - history = append(history, projectHistory) + version = append(version, projectVersion) } - if len(history) == 0 { + if len(version) == 0 { return nil, sql.ErrNoRows } - return history, nil + return version, nil } -func (q *fakeQuerier) GetProjectHistoryByProjectIDAndName(_ context.Context, arg database.GetProjectHistoryByProjectIDAndNameParams) (database.ProjectHistory, error) { +func (q *fakeQuerier) GetProjectVersionByProjectIDAndName(_ context.Context, arg database.GetProjectVersionByProjectIDAndNameParams) (database.ProjectVersion, error) { q.mutex.Lock() defer q.mutex.Unlock() - for _, projectHistory := range q.projectHistory { - if projectHistory.ProjectID.String() != arg.ProjectID.String() { + for _, projectVersion := range q.projectVersion { + if projectVersion.ProjectID.String() != arg.ProjectID.String() { continue } - if !strings.EqualFold(projectHistory.Name, arg.Name) { + if !strings.EqualFold(projectVersion.Name, arg.Name) { continue } - return projectHistory, nil + return projectVersion, nil } - return database.ProjectHistory{}, sql.ErrNoRows + return database.ProjectVersion{}, sql.ErrNoRows } -func (q *fakeQuerier) GetProjectHistoryLogsByIDBetween(_ context.Context, arg database.GetProjectHistoryLogsByIDBetweenParams) ([]database.ProjectHistoryLog, error) { +func (q *fakeQuerier) GetProjectVersionLogsByIDBetween(_ context.Context, arg database.GetProjectVersionLogsByIDBetweenParams) ([]database.ProjectVersionLog, error) { q.mutex.Lock() defer q.mutex.Unlock() - logs := make([]database.ProjectHistoryLog, 0) - for _, projectHistoryLog := range q.projectHistoryLog { - if projectHistoryLog.ProjectHistoryID.String() != arg.ProjectHistoryID.String() { + logs := make([]database.ProjectVersionLog, 0) + for _, projectVersionLog := range q.projectVersionLog { + if projectVersionLog.ProjectVersionID.String() != arg.ProjectVersionID.String() { continue } - if projectHistoryLog.CreatedAt.After(arg.CreatedBefore) { + if projectVersionLog.CreatedAt.After(arg.CreatedBefore) { continue } - if projectHistoryLog.CreatedAt.Before(arg.CreatedAfter) { + if projectVersionLog.CreatedAt.Before(arg.CreatedAfter) { continue } - logs = append(logs, projectHistoryLog) + logs = append(logs, projectVersionLog) } if len(logs) == 0 { return nil, sql.ErrNoRows @@ -466,26 +466,26 @@ func (q *fakeQuerier) GetProjectHistoryLogsByIDBetween(_ context.Context, arg da return logs, nil } -func (q *fakeQuerier) GetProjectHistoryByID(_ context.Context, projectHistoryID uuid.UUID) (database.ProjectHistory, error) { +func (q *fakeQuerier) GetProjectVersionByID(_ context.Context, projectVersionID uuid.UUID) (database.ProjectVersion, error) { q.mutex.Lock() defer q.mutex.Unlock() - for _, projectHistory := range q.projectHistory { - if projectHistory.ID.String() != projectHistoryID.String() { + for _, projectVersion := range q.projectVersion { + if projectVersion.ID.String() != projectVersionID.String() { continue } - return projectHistory, nil + return projectVersion, nil } - return database.ProjectHistory{}, sql.ErrNoRows + return database.ProjectVersion{}, sql.ErrNoRows } -func (q *fakeQuerier) GetProjectParametersByHistoryID(_ context.Context, projectHistoryID uuid.UUID) ([]database.ProjectParameter, error) { +func (q *fakeQuerier) GetProjectParametersByVersionID(_ context.Context, projectVersionID uuid.UUID) ([]database.ProjectParameter, error) { q.mutex.Lock() defer q.mutex.Unlock() parameters := make([]database.ProjectParameter, 0) for _, projectParameter := range q.projectParameter { - if projectParameter.ProjectHistoryID.String() != projectHistoryID.String() { + if projectParameter.ProjectVersionID.String() != projectVersionID.String() { continue } parameters = append(parameters, projectParameter) @@ -660,12 +660,12 @@ func (q *fakeQuerier) InsertProject(_ context.Context, arg database.InsertProjec return project, nil } -func (q *fakeQuerier) InsertProjectHistory(_ context.Context, arg database.InsertProjectHistoryParams) (database.ProjectHistory, error) { +func (q *fakeQuerier) InsertProjectVersion(_ context.Context, arg database.InsertProjectVersionParams) (database.ProjectVersion, error) { q.mutex.Lock() defer q.mutex.Unlock() //nolint:gosimple - history := database.ProjectHistory{ + version := database.ProjectVersion{ ID: arg.ID, ProjectID: arg.ProjectID, CreatedAt: arg.CreatedAt, @@ -676,18 +676,18 @@ func (q *fakeQuerier) InsertProjectHistory(_ context.Context, arg database.Inser StorageSource: arg.StorageSource, ImportJobID: arg.ImportJobID, } - q.projectHistory = append(q.projectHistory, history) - return history, nil + q.projectVersion = append(q.projectVersion, version) + return version, nil } -func (q *fakeQuerier) InsertProjectHistoryLogs(_ context.Context, arg database.InsertProjectHistoryLogsParams) ([]database.ProjectHistoryLog, error) { +func (q *fakeQuerier) InsertProjectVersionLogs(_ context.Context, arg database.InsertProjectVersionLogsParams) ([]database.ProjectVersionLog, error) { q.mutex.Lock() defer q.mutex.Unlock() - logs := make([]database.ProjectHistoryLog, 0) + logs := make([]database.ProjectVersionLog, 0) for index, output := range arg.Output { - logs = append(logs, database.ProjectHistoryLog{ - ProjectHistoryID: arg.ProjectHistoryID, + logs = append(logs, database.ProjectVersionLog{ + ProjectVersionID: arg.ProjectVersionID, ID: arg.ID[index], CreatedAt: arg.CreatedAt[index], Source: arg.Source[index], @@ -695,7 +695,7 @@ func (q *fakeQuerier) InsertProjectHistoryLogs(_ context.Context, arg database.I Output: output, }) } - q.projectHistoryLog = append(q.projectHistoryLog, logs...) + q.projectVersionLog = append(q.projectVersionLog, logs...) return logs, nil } @@ -707,7 +707,7 @@ func (q *fakeQuerier) InsertProjectParameter(_ context.Context, arg database.Ins param := database.ProjectParameter{ ID: arg.ID, CreatedAt: arg.CreatedAt, - ProjectHistoryID: arg.ProjectHistoryID, + ProjectVersionID: arg.ProjectVersionID, Name: arg.Name, Description: arg.Description, DefaultSourceScheme: arg.DefaultSourceScheme, @@ -821,7 +821,7 @@ func (q *fakeQuerier) InsertWorkspaceHistory(_ context.Context, arg database.Ins UpdatedAt: arg.UpdatedAt, WorkspaceID: arg.WorkspaceID, Name: arg.Name, - ProjectHistoryID: arg.ProjectHistoryID, + ProjectVersionID: arg.ProjectVersionID, BeforeID: arg.BeforeID, Transition: arg.Transition, Initiator: arg.Initiator, diff --git a/database/dump.sql b/database/dump.sql index 7f174528af7b2..9da449f498079 100644 --- a/database/dump.sql +++ b/database/dump.sql @@ -137,7 +137,7 @@ CREATE TABLE project ( active_version_id uuid ); -CREATE TABLE project_history ( +CREATE TABLE project_version ( id uuid NOT NULL, project_id uuid NOT NULL, created_at timestamp with time zone NOT NULL, @@ -149,9 +149,9 @@ CREATE TABLE project_history ( import_job_id uuid NOT NULL ); -CREATE TABLE project_history_log ( +CREATE TABLE project_version_log ( id uuid NOT NULL, - project_history_id uuid NOT NULL, + project_version_id uuid NOT NULL, created_at timestamp with time zone NOT NULL, source log_source NOT NULL, level log_level NOT NULL, @@ -161,7 +161,7 @@ CREATE TABLE project_history_log ( CREATE TABLE project_parameter ( id uuid NOT NULL, created_at timestamp with time zone NOT NULL, - project_history_id uuid NOT NULL, + project_version_id uuid NOT NULL, name character varying(64) NOT NULL, description character varying(8192) DEFAULT ''::character varying NOT NULL, default_source_scheme parameter_source_scheme, @@ -247,7 +247,7 @@ CREATE TABLE workspace_history ( created_at timestamp with time zone NOT NULL, updated_at timestamp with time zone NOT NULL, workspace_id uuid NOT NULL, - project_history_id uuid NOT NULL, + project_version_id uuid NOT NULL, name character varying(64) NOT NULL, before_id uuid, after_id uuid, @@ -282,14 +282,14 @@ ALTER TABLE ONLY parameter_value ALTER TABLE ONLY parameter_value ADD CONSTRAINT parameter_value_name_scope_scope_id_key UNIQUE (name, scope, scope_id); -ALTER TABLE ONLY project_history - ADD CONSTRAINT project_history_id_key UNIQUE (id); +ALTER TABLE ONLY project_version + ADD CONSTRAINT project_version_id_key UNIQUE (id); -ALTER TABLE ONLY project_history_log - ADD CONSTRAINT project_history_log_id_key UNIQUE (id); +ALTER TABLE ONLY project_version_log + ADD CONSTRAINT project_version_log_id_key UNIQUE (id); -ALTER TABLE ONLY project_history - ADD CONSTRAINT project_history_project_id_name_key UNIQUE (project_id, name); +ALTER TABLE ONLY project_version + ADD CONSTRAINT project_version_project_id_name_key UNIQUE (project_id, name); ALTER TABLE ONLY project ADD CONSTRAINT project_id_key UNIQUE (id); @@ -301,7 +301,7 @@ ALTER TABLE ONLY project_parameter ADD CONSTRAINT project_parameter_id_key UNIQUE (id); ALTER TABLE ONLY project_parameter - ADD CONSTRAINT project_parameter_project_history_id_name_key UNIQUE (project_history_id, name); + ADD CONSTRAINT project_parameter_project_version_id_name_key UNIQUE (project_version_id, name); ALTER TABLE ONLY provisioner_daemon ADD CONSTRAINT provisioner_daemon_id_key UNIQUE (id); @@ -339,14 +339,14 @@ ALTER TABLE ONLY workspace_resource ALTER TABLE ONLY workspace_resource ADD CONSTRAINT workspace_resource_workspace_history_id_name_key UNIQUE (workspace_history_id, name); -ALTER TABLE ONLY project_history_log - ADD CONSTRAINT project_history_log_project_history_id_fkey FOREIGN KEY (project_history_id) REFERENCES project_history(id) ON DELETE CASCADE; +ALTER TABLE ONLY project_version_log + ADD CONSTRAINT project_version_log_project_version_id_fkey FOREIGN KEY (project_version_id) REFERENCES project_version(id) ON DELETE CASCADE; -ALTER TABLE ONLY project_history - ADD CONSTRAINT project_history_project_id_fkey FOREIGN KEY (project_id) REFERENCES project(id); +ALTER TABLE ONLY project_version + ADD CONSTRAINT project_version_project_id_fkey FOREIGN KEY (project_id) REFERENCES project(id); ALTER TABLE ONLY project_parameter - ADD CONSTRAINT project_parameter_project_history_id_fkey FOREIGN KEY (project_history_id) REFERENCES project_history(id) ON DELETE CASCADE; + ADD CONSTRAINT project_parameter_project_version_id_fkey FOREIGN KEY (project_version_id) REFERENCES project_version(id) ON DELETE CASCADE; ALTER TABLE ONLY provisioner_job ADD CONSTRAINT provisioner_job_project_id_fkey FOREIGN KEY (project_id) REFERENCES project(id) ON DELETE CASCADE; @@ -358,7 +358,7 @@ ALTER TABLE ONLY workspace_history_log ADD CONSTRAINT workspace_history_log_workspace_history_id_fkey FOREIGN KEY (workspace_history_id) REFERENCES workspace_history(id) ON DELETE CASCADE; ALTER TABLE ONLY workspace_history - ADD CONSTRAINT workspace_history_project_history_id_fkey FOREIGN KEY (project_history_id) REFERENCES project_history(id) ON DELETE CASCADE; + ADD CONSTRAINT workspace_history_project_version_id_fkey FOREIGN KEY (project_version_id) REFERENCES project_version(id) ON DELETE CASCADE; ALTER TABLE ONLY workspace_history ADD CONSTRAINT workspace_history_workspace_id_fkey FOREIGN KEY (workspace_id) REFERENCES workspace(id) ON DELETE CASCADE; diff --git a/database/migrations/000002_projects.up.sql b/database/migrations/000002_projects.up.sql index 0149ec8033f39..c33f2f1e725b8 100644 --- a/database/migrations/000002_projects.up.sql +++ b/database/migrations/000002_projects.up.sql @@ -20,10 +20,10 @@ CREATE TABLE project ( CREATE TYPE project_storage_method AS ENUM ('inline-archive'); --- Project Versions store Project history. When a Project Version is imported, +-- Project Versions store historical project data. When a Project Version is imported, -- an "import" job is queued to parse parameters. A Project Version -- can only be used if the import job succeeds. -CREATE TABLE project_history ( +CREATE TABLE project_version ( id uuid NOT NULL UNIQUE, -- This should be indexed. project_id uuid NOT NULL REFERENCES project (id), @@ -66,7 +66,7 @@ CREATE TYPE parameter_destination_scheme AS ENUM('none', 'environment_variable', CREATE TABLE project_parameter ( id uuid NOT NULL UNIQUE, created_at timestamptz NOT NULL, - project_history_id uuid NOT NULL REFERENCES project_history(id) ON DELETE CASCADE, + project_version_id uuid NOT NULL REFERENCES project_version(id) ON DELETE CASCADE, name varchar(64) NOT NULL, -- 8KB limit description varchar(8192) NOT NULL DEFAULT '', @@ -88,7 +88,7 @@ CREATE TABLE project_parameter ( validation_condition varchar(512) NOT NULL, validation_type_system parameter_type_system NOT NULL, validation_value_type varchar(64) NOT NULL, - UNIQUE(project_history_id, name) + UNIQUE(project_version_id, name) ); CREATE TYPE log_level AS ENUM ( @@ -104,9 +104,9 @@ CREATE TYPE log_source AS ENUM ( 'provisioner' ); -CREATE TABLE project_history_log ( +CREATE TABLE project_version_log ( id uuid NOT NULL UNIQUE, - project_history_id uuid NOT NULL REFERENCES project_history (id) ON DELETE CASCADE, + project_version_id uuid NOT NULL REFERENCES project_version (id) ON DELETE CASCADE, created_at timestamptz NOT NULL, source log_source NOT NULL, level log_level NOT NULL, diff --git a/database/migrations/000003_workspaces.up.sql b/database/migrations/000003_workspaces.up.sql index fcc0b8fc3f77b..fe7bfe6ea2822 100644 --- a/database/migrations/000003_workspaces.up.sql +++ b/database/migrations/000003_workspaces.up.sql @@ -21,7 +21,7 @@ CREATE TABLE workspace_history ( created_at timestamptz NOT NULL, updated_at timestamptz NOT NULL, workspace_id uuid NOT NULL REFERENCES workspace (id) ON DELETE CASCADE, - project_history_id uuid NOT NULL REFERENCES project_history (id) ON DELETE CASCADE, + project_version_id uuid NOT NULL REFERENCES project_version (id) ON DELETE CASCADE, name varchar(64) NOT NULL, before_id uuid, after_id uuid, diff --git a/database/models.go b/database/models.go index f0c0458e5cd58..72e7007e176c5 100644 --- a/database/models.go +++ b/database/models.go @@ -316,31 +316,10 @@ type Project struct { ActiveVersionID uuid.NullUUID `db:"active_version_id" json:"active_version_id"` } -type ProjectHistory struct { - ID uuid.UUID `db:"id" json:"id"` - ProjectID uuid.UUID `db:"project_id" json:"project_id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` - Name string `db:"name" json:"name"` - Description string `db:"description" json:"description"` - StorageMethod ProjectStorageMethod `db:"storage_method" json:"storage_method"` - StorageSource []byte `db:"storage_source" json:"storage_source"` - ImportJobID uuid.UUID `db:"import_job_id" json:"import_job_id"` -} - -type ProjectHistoryLog struct { - ID uuid.UUID `db:"id" json:"id"` - ProjectHistoryID uuid.UUID `db:"project_history_id" json:"project_history_id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - Source LogSource `db:"source" json:"source"` - Level LogLevel `db:"level" json:"level"` - Output string `db:"output" json:"output"` -} - type ProjectParameter struct { ID uuid.UUID `db:"id" json:"id"` CreatedAt time.Time `db:"created_at" json:"created_at"` - ProjectHistoryID uuid.UUID `db:"project_history_id" json:"project_history_id"` + ProjectVersionID uuid.UUID `db:"project_version_id" json:"project_version_id"` Name string `db:"name" json:"name"` Description string `db:"description" json:"description"` DefaultSourceScheme ParameterSourceScheme `db:"default_source_scheme" json:"default_source_scheme"` @@ -357,6 +336,27 @@ type ProjectParameter struct { ValidationValueType string `db:"validation_value_type" json:"validation_value_type"` } +type ProjectVersion struct { + ID uuid.UUID `db:"id" json:"id"` + ProjectID uuid.UUID `db:"project_id" json:"project_id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + Name string `db:"name" json:"name"` + Description string `db:"description" json:"description"` + StorageMethod ProjectStorageMethod `db:"storage_method" json:"storage_method"` + StorageSource []byte `db:"storage_source" json:"storage_source"` + ImportJobID uuid.UUID `db:"import_job_id" json:"import_job_id"` +} + +type ProjectVersionLog struct { + ID uuid.UUID `db:"id" json:"id"` + ProjectVersionID uuid.UUID `db:"project_version_id" json:"project_version_id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + Source LogSource `db:"source" json:"source"` + Level LogLevel `db:"level" json:"level"` + Output string `db:"output" json:"output"` +} + type ProvisionerDaemon struct { ID uuid.UUID `db:"id" json:"id"` CreatedAt time.Time `db:"created_at" json:"created_at"` @@ -426,7 +426,7 @@ type WorkspaceHistory struct { CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` WorkspaceID uuid.UUID `db:"workspace_id" json:"workspace_id"` - ProjectHistoryID uuid.UUID `db:"project_history_id" json:"project_history_id"` + ProjectVersionID uuid.UUID `db:"project_version_id" json:"project_version_id"` Name string `db:"name" json:"name"` BeforeID uuid.NullUUID `db:"before_id" json:"before_id"` AfterID uuid.NullUUID `db:"after_id" json:"after_id"` diff --git a/database/querier.go b/database/querier.go index 49793672fa9e1..20c859cbe3f67 100644 --- a/database/querier.go +++ b/database/querier.go @@ -18,11 +18,11 @@ type querier interface { GetParameterValuesByScope(ctx context.Context, arg GetParameterValuesByScopeParams) ([]ParameterValue, error) GetProjectByID(ctx context.Context, id uuid.UUID) (Project, error) GetProjectByOrganizationAndName(ctx context.Context, arg GetProjectByOrganizationAndNameParams) (Project, error) - GetProjectHistoryByID(ctx context.Context, id uuid.UUID) (ProjectHistory, error) - GetProjectHistoryByProjectID(ctx context.Context, projectID uuid.UUID) ([]ProjectHistory, error) - GetProjectHistoryByProjectIDAndName(ctx context.Context, arg GetProjectHistoryByProjectIDAndNameParams) (ProjectHistory, error) - GetProjectHistoryLogsByIDBetween(ctx context.Context, arg GetProjectHistoryLogsByIDBetweenParams) ([]ProjectHistoryLog, error) - GetProjectParametersByHistoryID(ctx context.Context, projectHistoryID uuid.UUID) ([]ProjectParameter, error) + GetProjectParametersByVersionID(ctx context.Context, projectVersionID uuid.UUID) ([]ProjectParameter, error) + GetProjectVersionByID(ctx context.Context, id uuid.UUID) (ProjectVersion, error) + GetProjectVersionByProjectID(ctx context.Context, projectID uuid.UUID) ([]ProjectVersion, error) + GetProjectVersionByProjectIDAndName(ctx context.Context, arg GetProjectVersionByProjectIDAndNameParams) (ProjectVersion, error) + GetProjectVersionLogsByIDBetween(ctx context.Context, arg GetProjectVersionLogsByIDBetweenParams) ([]ProjectVersionLog, error) GetProjectsByOrganizationIDs(ctx context.Context, ids []string) ([]Project, error) GetProvisionerDaemonByID(ctx context.Context, id uuid.UUID) (ProvisionerDaemon, error) GetProvisionerDaemons(ctx context.Context) ([]ProvisionerDaemon, error) @@ -46,9 +46,9 @@ type querier interface { InsertOrganizationMember(ctx context.Context, arg InsertOrganizationMemberParams) (OrganizationMember, error) InsertParameterValue(ctx context.Context, arg InsertParameterValueParams) (ParameterValue, error) InsertProject(ctx context.Context, arg InsertProjectParams) (Project, error) - InsertProjectHistory(ctx context.Context, arg InsertProjectHistoryParams) (ProjectHistory, error) - InsertProjectHistoryLogs(ctx context.Context, arg InsertProjectHistoryLogsParams) ([]ProjectHistoryLog, error) InsertProjectParameter(ctx context.Context, arg InsertProjectParameterParams) (ProjectParameter, error) + InsertProjectVersion(ctx context.Context, arg InsertProjectVersionParams) (ProjectVersion, error) + InsertProjectVersionLogs(ctx context.Context, arg InsertProjectVersionLogsParams) ([]ProjectVersionLog, error) InsertProvisionerDaemon(ctx context.Context, arg InsertProvisionerDaemonParams) (ProvisionerDaemon, error) InsertProvisionerJob(ctx context.Context, arg InsertProvisionerJobParams) (ProvisionerJob, error) InsertUser(ctx context.Context, arg InsertUserParams) (User, error) diff --git a/database/query.sql b/database/query.sql index 93943326f7f15..3a9889c299453 100644 --- a/database/query.sql +++ b/database/query.sql @@ -155,46 +155,46 @@ FROM WHERE organization_id = ANY(@ids :: text [ ]); --- name: GetProjectParametersByHistoryID :many +-- name: GetProjectParametersByVersionID :many SELECT * FROM project_parameter WHERE - project_history_id = $1; + project_version_id = $1; --- name: GetProjectHistoryByProjectID :many +-- name: GetProjectVersionByProjectID :many SELECT * FROM - project_history + project_version WHERE project_id = $1; --- name: GetProjectHistoryByProjectIDAndName :one +-- name: GetProjectVersionByProjectIDAndName :one SELECT * FROM - project_history + project_version WHERE project_id = $1 AND name = $2; --- name: GetProjectHistoryByID :one +-- name: GetProjectVersionByID :one SELECT * FROM - project_history + project_version WHERE id = $1; --- name: GetProjectHistoryLogsByIDBetween :many +-- name: GetProjectVersionLogsByIDBetween :many SELECT * FROM - project_history_log + project_version_log WHERE - project_history_id = @project_history_id + project_version_id = @project_version_id AND ( created_at >= @created_after OR created_at <= @created_before @@ -414,9 +414,9 @@ INSERT INTO VALUES ($1, $2, $3, $4, $5, $6) RETURNING *; --- name: InsertProjectHistory :one +-- name: InsertProjectVersion :one INSERT INTO - project_history ( + project_version ( id, project_id, created_at, @@ -430,11 +430,11 @@ INSERT INTO VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING *; --- name: InsertProjectHistoryLogs :many +-- name: InsertProjectVersionLogs :many INSERT INTO - project_history_log + project_version_log SELECT - @project_history_id :: uuid AS project_history_id, + @project_version_id :: uuid AS project_version_id, unnest(@id :: uuid [ ]) AS id, unnest(@created_at :: timestamptz [ ]) AS created_at, unnest(@source :: log_source [ ]) as source, @@ -446,7 +446,7 @@ INSERT INTO project_parameter ( id, created_at, - project_history_id, + project_version_id, name, description, default_source_scheme, @@ -553,7 +553,7 @@ INSERT INTO created_at, updated_at, workspace_id, - project_history_id, + project_version_id, before_id, name, transition, diff --git a/database/query.sql.go b/database/query.sql.go index 0da3e8cfba63e..363c5a3aae896 100644 --- a/database/query.sql.go +++ b/database/query.sql.go @@ -350,18 +350,68 @@ func (q *sqlQuerier) GetProjectByOrganizationAndName(ctx context.Context, arg Ge return i, err } -const getProjectHistoryByID = `-- name: GetProjectHistoryByID :one +const getProjectParametersByVersionID = `-- name: GetProjectParametersByVersionID :many +SELECT + id, created_at, project_version_id, name, description, default_source_scheme, default_source_value, allow_override_source, default_destination_scheme, default_destination_value, allow_override_destination, default_refresh, redisplay_value, validation_error, validation_condition, validation_type_system, validation_value_type +FROM + project_parameter +WHERE + project_version_id = $1 +` + +func (q *sqlQuerier) GetProjectParametersByVersionID(ctx context.Context, projectVersionID uuid.UUID) ([]ProjectParameter, error) { + rows, err := q.db.QueryContext(ctx, getProjectParametersByVersionID, projectVersionID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ProjectParameter + for rows.Next() { + var i ProjectParameter + if err := rows.Scan( + &i.ID, + &i.CreatedAt, + &i.ProjectVersionID, + &i.Name, + &i.Description, + &i.DefaultSourceScheme, + &i.DefaultSourceValue, + &i.AllowOverrideSource, + &i.DefaultDestinationScheme, + &i.DefaultDestinationValue, + &i.AllowOverrideDestination, + &i.DefaultRefresh, + &i.RedisplayValue, + &i.ValidationError, + &i.ValidationCondition, + &i.ValidationTypeSystem, + &i.ValidationValueType, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getProjectVersionByID = `-- name: GetProjectVersionByID :one SELECT id, project_id, created_at, updated_at, name, description, storage_method, storage_source, import_job_id FROM - project_history + project_version WHERE id = $1 ` -func (q *sqlQuerier) GetProjectHistoryByID(ctx context.Context, id uuid.UUID) (ProjectHistory, error) { - row := q.db.QueryRowContext(ctx, getProjectHistoryByID, id) - var i ProjectHistory +func (q *sqlQuerier) GetProjectVersionByID(ctx context.Context, id uuid.UUID) (ProjectVersion, error) { + row := q.db.QueryRowContext(ctx, getProjectVersionByID, id) + var i ProjectVersion err := row.Scan( &i.ID, &i.ProjectID, @@ -376,24 +426,24 @@ func (q *sqlQuerier) GetProjectHistoryByID(ctx context.Context, id uuid.UUID) (P return i, err } -const getProjectHistoryByProjectID = `-- name: GetProjectHistoryByProjectID :many +const getProjectVersionByProjectID = `-- name: GetProjectVersionByProjectID :many SELECT id, project_id, created_at, updated_at, name, description, storage_method, storage_source, import_job_id FROM - project_history + project_version WHERE project_id = $1 ` -func (q *sqlQuerier) GetProjectHistoryByProjectID(ctx context.Context, projectID uuid.UUID) ([]ProjectHistory, error) { - rows, err := q.db.QueryContext(ctx, getProjectHistoryByProjectID, projectID) +func (q *sqlQuerier) GetProjectVersionByProjectID(ctx context.Context, projectID uuid.UUID) ([]ProjectVersion, error) { + rows, err := q.db.QueryContext(ctx, getProjectVersionByProjectID, projectID) if err != nil { return nil, err } defer rows.Close() - var items []ProjectHistory + var items []ProjectVersion for rows.Next() { - var i ProjectHistory + var i ProjectVersion if err := rows.Scan( &i.ID, &i.ProjectID, @@ -418,24 +468,24 @@ func (q *sqlQuerier) GetProjectHistoryByProjectID(ctx context.Context, projectID return items, nil } -const getProjectHistoryByProjectIDAndName = `-- name: GetProjectHistoryByProjectIDAndName :one +const getProjectVersionByProjectIDAndName = `-- name: GetProjectVersionByProjectIDAndName :one SELECT id, project_id, created_at, updated_at, name, description, storage_method, storage_source, import_job_id FROM - project_history + project_version WHERE project_id = $1 AND name = $2 ` -type GetProjectHistoryByProjectIDAndNameParams struct { +type GetProjectVersionByProjectIDAndNameParams struct { ProjectID uuid.UUID `db:"project_id" json:"project_id"` Name string `db:"name" json:"name"` } -func (q *sqlQuerier) GetProjectHistoryByProjectIDAndName(ctx context.Context, arg GetProjectHistoryByProjectIDAndNameParams) (ProjectHistory, error) { - row := q.db.QueryRowContext(ctx, getProjectHistoryByProjectIDAndName, arg.ProjectID, arg.Name) - var i ProjectHistory +func (q *sqlQuerier) GetProjectVersionByProjectIDAndName(ctx context.Context, arg GetProjectVersionByProjectIDAndNameParams) (ProjectVersion, error) { + row := q.db.QueryRowContext(ctx, getProjectVersionByProjectIDAndName, arg.ProjectID, arg.Name) + var i ProjectVersion err := row.Scan( &i.ID, &i.ProjectID, @@ -450,13 +500,13 @@ func (q *sqlQuerier) GetProjectHistoryByProjectIDAndName(ctx context.Context, ar return i, err } -const getProjectHistoryLogsByIDBetween = `-- name: GetProjectHistoryLogsByIDBetween :many +const getProjectVersionLogsByIDBetween = `-- name: GetProjectVersionLogsByIDBetween :many SELECT - id, project_history_id, created_at, source, level, output + id, project_version_id, created_at, source, level, output FROM - project_history_log + project_version_log WHERE - project_history_id = $1 + project_version_id = $1 AND ( created_at >= $2 OR created_at <= $3 @@ -465,24 +515,24 @@ ORDER BY created_at ` -type GetProjectHistoryLogsByIDBetweenParams struct { - ProjectHistoryID uuid.UUID `db:"project_history_id" json:"project_history_id"` +type GetProjectVersionLogsByIDBetweenParams struct { + ProjectVersionID uuid.UUID `db:"project_version_id" json:"project_version_id"` CreatedAfter time.Time `db:"created_after" json:"created_after"` CreatedBefore time.Time `db:"created_before" json:"created_before"` } -func (q *sqlQuerier) GetProjectHistoryLogsByIDBetween(ctx context.Context, arg GetProjectHistoryLogsByIDBetweenParams) ([]ProjectHistoryLog, error) { - rows, err := q.db.QueryContext(ctx, getProjectHistoryLogsByIDBetween, arg.ProjectHistoryID, arg.CreatedAfter, arg.CreatedBefore) +func (q *sqlQuerier) GetProjectVersionLogsByIDBetween(ctx context.Context, arg GetProjectVersionLogsByIDBetweenParams) ([]ProjectVersionLog, error) { + rows, err := q.db.QueryContext(ctx, getProjectVersionLogsByIDBetween, arg.ProjectVersionID, arg.CreatedAfter, arg.CreatedBefore) if err != nil { return nil, err } defer rows.Close() - var items []ProjectHistoryLog + var items []ProjectVersionLog for rows.Next() { - var i ProjectHistoryLog + var i ProjectVersionLog if err := rows.Scan( &i.ID, - &i.ProjectHistoryID, + &i.ProjectVersionID, &i.CreatedAt, &i.Source, &i.Level, @@ -501,56 +551,6 @@ func (q *sqlQuerier) GetProjectHistoryLogsByIDBetween(ctx context.Context, arg G return items, nil } -const getProjectParametersByHistoryID = `-- name: GetProjectParametersByHistoryID :many -SELECT - id, created_at, project_history_id, name, description, default_source_scheme, default_source_value, allow_override_source, default_destination_scheme, default_destination_value, allow_override_destination, default_refresh, redisplay_value, validation_error, validation_condition, validation_type_system, validation_value_type -FROM - project_parameter -WHERE - project_history_id = $1 -` - -func (q *sqlQuerier) GetProjectParametersByHistoryID(ctx context.Context, projectHistoryID uuid.UUID) ([]ProjectParameter, error) { - rows, err := q.db.QueryContext(ctx, getProjectParametersByHistoryID, projectHistoryID) - if err != nil { - return nil, err - } - defer rows.Close() - var items []ProjectParameter - for rows.Next() { - var i ProjectParameter - if err := rows.Scan( - &i.ID, - &i.CreatedAt, - &i.ProjectHistoryID, - &i.Name, - &i.Description, - &i.DefaultSourceScheme, - &i.DefaultSourceValue, - &i.AllowOverrideSource, - &i.DefaultDestinationScheme, - &i.DefaultDestinationValue, - &i.AllowOverrideDestination, - &i.DefaultRefresh, - &i.RedisplayValue, - &i.ValidationError, - &i.ValidationCondition, - &i.ValidationTypeSystem, - &i.ValidationValueType, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - const getProjectsByOrganizationIDs = `-- name: GetProjectsByOrganizationIDs :many SELECT id, created_at, updated_at, organization_id, name, provisioner, active_version_id @@ -870,7 +870,7 @@ func (q *sqlQuerier) GetWorkspaceByUserIDAndName(ctx context.Context, arg GetWor const getWorkspaceHistoryByID = `-- name: GetWorkspaceHistoryByID :one SELECT - id, created_at, updated_at, workspace_id, project_history_id, name, before_id, after_id, transition, initiator, provisioner_state, provision_job_id + id, created_at, updated_at, workspace_id, project_version_id, name, before_id, after_id, transition, initiator, provisioner_state, provision_job_id FROM workspace_history WHERE @@ -887,7 +887,7 @@ func (q *sqlQuerier) GetWorkspaceHistoryByID(ctx context.Context, id uuid.UUID) &i.CreatedAt, &i.UpdatedAt, &i.WorkspaceID, - &i.ProjectHistoryID, + &i.ProjectVersionID, &i.Name, &i.BeforeID, &i.AfterID, @@ -901,7 +901,7 @@ func (q *sqlQuerier) GetWorkspaceHistoryByID(ctx context.Context, id uuid.UUID) const getWorkspaceHistoryByWorkspaceID = `-- name: GetWorkspaceHistoryByWorkspaceID :many SELECT - id, created_at, updated_at, workspace_id, project_history_id, name, before_id, after_id, transition, initiator, provisioner_state, provision_job_id + id, created_at, updated_at, workspace_id, project_version_id, name, before_id, after_id, transition, initiator, provisioner_state, provision_job_id FROM workspace_history WHERE @@ -922,7 +922,7 @@ func (q *sqlQuerier) GetWorkspaceHistoryByWorkspaceID(ctx context.Context, works &i.CreatedAt, &i.UpdatedAt, &i.WorkspaceID, - &i.ProjectHistoryID, + &i.ProjectVersionID, &i.Name, &i.BeforeID, &i.AfterID, @@ -946,7 +946,7 @@ func (q *sqlQuerier) GetWorkspaceHistoryByWorkspaceID(ctx context.Context, works const getWorkspaceHistoryByWorkspaceIDAndName = `-- name: GetWorkspaceHistoryByWorkspaceIDAndName :one SELECT - id, created_at, updated_at, workspace_id, project_history_id, name, before_id, after_id, transition, initiator, provisioner_state, provision_job_id + id, created_at, updated_at, workspace_id, project_version_id, name, before_id, after_id, transition, initiator, provisioner_state, provision_job_id FROM workspace_history WHERE @@ -967,7 +967,7 @@ func (q *sqlQuerier) GetWorkspaceHistoryByWorkspaceIDAndName(ctx context.Context &i.CreatedAt, &i.UpdatedAt, &i.WorkspaceID, - &i.ProjectHistoryID, + &i.ProjectVersionID, &i.Name, &i.BeforeID, &i.AfterID, @@ -981,7 +981,7 @@ func (q *sqlQuerier) GetWorkspaceHistoryByWorkspaceIDAndName(ctx context.Context const getWorkspaceHistoryByWorkspaceIDWithoutAfter = `-- name: GetWorkspaceHistoryByWorkspaceIDWithoutAfter :one SELECT - id, created_at, updated_at, workspace_id, project_history_id, name, before_id, after_id, transition, initiator, provisioner_state, provision_job_id + id, created_at, updated_at, workspace_id, project_version_id, name, before_id, after_id, transition, initiator, provisioner_state, provision_job_id FROM workspace_history WHERE @@ -999,7 +999,7 @@ func (q *sqlQuerier) GetWorkspaceHistoryByWorkspaceIDWithoutAfter(ctx context.Co &i.CreatedAt, &i.UpdatedAt, &i.WorkspaceID, - &i.ProjectHistoryID, + &i.ProjectVersionID, &i.Name, &i.BeforeID, &i.AfterID, @@ -1466,126 +1466,12 @@ func (q *sqlQuerier) InsertProject(ctx context.Context, arg InsertProjectParams) return i, err } -const insertProjectHistory = `-- name: InsertProjectHistory :one -INSERT INTO - project_history ( - id, - project_id, - created_at, - updated_at, - name, - description, - storage_method, - storage_source, - import_job_id - ) -VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id, project_id, created_at, updated_at, name, description, storage_method, storage_source, import_job_id -` - -type InsertProjectHistoryParams struct { - ID uuid.UUID `db:"id" json:"id"` - ProjectID uuid.UUID `db:"project_id" json:"project_id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` - Name string `db:"name" json:"name"` - Description string `db:"description" json:"description"` - StorageMethod ProjectStorageMethod `db:"storage_method" json:"storage_method"` - StorageSource []byte `db:"storage_source" json:"storage_source"` - ImportJobID uuid.UUID `db:"import_job_id" json:"import_job_id"` -} - -func (q *sqlQuerier) InsertProjectHistory(ctx context.Context, arg InsertProjectHistoryParams) (ProjectHistory, error) { - row := q.db.QueryRowContext(ctx, insertProjectHistory, - arg.ID, - arg.ProjectID, - arg.CreatedAt, - arg.UpdatedAt, - arg.Name, - arg.Description, - arg.StorageMethod, - arg.StorageSource, - arg.ImportJobID, - ) - var i ProjectHistory - err := row.Scan( - &i.ID, - &i.ProjectID, - &i.CreatedAt, - &i.UpdatedAt, - &i.Name, - &i.Description, - &i.StorageMethod, - &i.StorageSource, - &i.ImportJobID, - ) - return i, err -} - -const insertProjectHistoryLogs = `-- name: InsertProjectHistoryLogs :many -INSERT INTO - project_history_log -SELECT - $1 :: uuid AS project_history_id, - unnest($2 :: uuid [ ]) AS id, - unnest($3 :: timestamptz [ ]) AS created_at, - unnest($4 :: log_source [ ]) as source, - unnest($5 :: log_level [ ]) as level, - unnest($6 :: varchar(1024) [ ]) as output RETURNING id, project_history_id, created_at, source, level, output -` - -type InsertProjectHistoryLogsParams struct { - ProjectHistoryID uuid.UUID `db:"project_history_id" json:"project_history_id"` - ID []uuid.UUID `db:"id" json:"id"` - CreatedAt []time.Time `db:"created_at" json:"created_at"` - Source []LogSource `db:"source" json:"source"` - Level []LogLevel `db:"level" json:"level"` - Output []string `db:"output" json:"output"` -} - -func (q *sqlQuerier) InsertProjectHistoryLogs(ctx context.Context, arg InsertProjectHistoryLogsParams) ([]ProjectHistoryLog, error) { - rows, err := q.db.QueryContext(ctx, insertProjectHistoryLogs, - arg.ProjectHistoryID, - pq.Array(arg.ID), - pq.Array(arg.CreatedAt), - pq.Array(arg.Source), - pq.Array(arg.Level), - pq.Array(arg.Output), - ) - if err != nil { - return nil, err - } - defer rows.Close() - var items []ProjectHistoryLog - for rows.Next() { - var i ProjectHistoryLog - if err := rows.Scan( - &i.ID, - &i.ProjectHistoryID, - &i.CreatedAt, - &i.Source, - &i.Level, - &i.Output, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - const insertProjectParameter = `-- name: InsertProjectParameter :one INSERT INTO project_parameter ( id, created_at, - project_history_id, + project_version_id, name, description, default_source_scheme, @@ -1620,13 +1506,13 @@ VALUES $15, $16, $17 - ) RETURNING id, created_at, project_history_id, name, description, default_source_scheme, default_source_value, allow_override_source, default_destination_scheme, default_destination_value, allow_override_destination, default_refresh, redisplay_value, validation_error, validation_condition, validation_type_system, validation_value_type + ) RETURNING id, created_at, project_version_id, name, description, default_source_scheme, default_source_value, allow_override_source, default_destination_scheme, default_destination_value, allow_override_destination, default_refresh, redisplay_value, validation_error, validation_condition, validation_type_system, validation_value_type ` type InsertProjectParameterParams struct { ID uuid.UUID `db:"id" json:"id"` CreatedAt time.Time `db:"created_at" json:"created_at"` - ProjectHistoryID uuid.UUID `db:"project_history_id" json:"project_history_id"` + ProjectVersionID uuid.UUID `db:"project_version_id" json:"project_version_id"` Name string `db:"name" json:"name"` Description string `db:"description" json:"description"` DefaultSourceScheme ParameterSourceScheme `db:"default_source_scheme" json:"default_source_scheme"` @@ -1647,7 +1533,7 @@ func (q *sqlQuerier) InsertProjectParameter(ctx context.Context, arg InsertProje row := q.db.QueryRowContext(ctx, insertProjectParameter, arg.ID, arg.CreatedAt, - arg.ProjectHistoryID, + arg.ProjectVersionID, arg.Name, arg.Description, arg.DefaultSourceScheme, @@ -1667,7 +1553,7 @@ func (q *sqlQuerier) InsertProjectParameter(ctx context.Context, arg InsertProje err := row.Scan( &i.ID, &i.CreatedAt, - &i.ProjectHistoryID, + &i.ProjectVersionID, &i.Name, &i.Description, &i.DefaultSourceScheme, @@ -1686,6 +1572,120 @@ func (q *sqlQuerier) InsertProjectParameter(ctx context.Context, arg InsertProje return i, err } +const insertProjectVersion = `-- name: InsertProjectVersion :one +INSERT INTO + project_version ( + id, + project_id, + created_at, + updated_at, + name, + description, + storage_method, + storage_source, + import_job_id + ) +VALUES + ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id, project_id, created_at, updated_at, name, description, storage_method, storage_source, import_job_id +` + +type InsertProjectVersionParams struct { + ID uuid.UUID `db:"id" json:"id"` + ProjectID uuid.UUID `db:"project_id" json:"project_id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` + Name string `db:"name" json:"name"` + Description string `db:"description" json:"description"` + StorageMethod ProjectStorageMethod `db:"storage_method" json:"storage_method"` + StorageSource []byte `db:"storage_source" json:"storage_source"` + ImportJobID uuid.UUID `db:"import_job_id" json:"import_job_id"` +} + +func (q *sqlQuerier) InsertProjectVersion(ctx context.Context, arg InsertProjectVersionParams) (ProjectVersion, error) { + row := q.db.QueryRowContext(ctx, insertProjectVersion, + arg.ID, + arg.ProjectID, + arg.CreatedAt, + arg.UpdatedAt, + arg.Name, + arg.Description, + arg.StorageMethod, + arg.StorageSource, + arg.ImportJobID, + ) + var i ProjectVersion + err := row.Scan( + &i.ID, + &i.ProjectID, + &i.CreatedAt, + &i.UpdatedAt, + &i.Name, + &i.Description, + &i.StorageMethod, + &i.StorageSource, + &i.ImportJobID, + ) + return i, err +} + +const insertProjectVersionLogs = `-- name: InsertProjectVersionLogs :many +INSERT INTO + project_version_log +SELECT + $1 :: uuid AS project_version_id, + unnest($2 :: uuid [ ]) AS id, + unnest($3 :: timestamptz [ ]) AS created_at, + unnest($4 :: log_source [ ]) as source, + unnest($5 :: log_level [ ]) as level, + unnest($6 :: varchar(1024) [ ]) as output RETURNING id, project_version_id, created_at, source, level, output +` + +type InsertProjectVersionLogsParams struct { + ProjectVersionID uuid.UUID `db:"project_version_id" json:"project_version_id"` + ID []uuid.UUID `db:"id" json:"id"` + CreatedAt []time.Time `db:"created_at" json:"created_at"` + Source []LogSource `db:"source" json:"source"` + Level []LogLevel `db:"level" json:"level"` + Output []string `db:"output" json:"output"` +} + +func (q *sqlQuerier) InsertProjectVersionLogs(ctx context.Context, arg InsertProjectVersionLogsParams) ([]ProjectVersionLog, error) { + rows, err := q.db.QueryContext(ctx, insertProjectVersionLogs, + arg.ProjectVersionID, + pq.Array(arg.ID), + pq.Array(arg.CreatedAt), + pq.Array(arg.Source), + pq.Array(arg.Level), + pq.Array(arg.Output), + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ProjectVersionLog + for rows.Next() { + var i ProjectVersionLog + if err := rows.Scan( + &i.ID, + &i.ProjectVersionID, + &i.CreatedAt, + &i.Source, + &i.Level, + &i.Output, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const insertProvisionerDaemon = `-- name: InsertProvisionerDaemon :one INSERT INTO provisioner_daemon (id, created_at, name, provisioners) @@ -1934,7 +1934,7 @@ INSERT INTO created_at, updated_at, workspace_id, - project_history_id, + project_version_id, before_id, name, transition, @@ -1943,7 +1943,7 @@ INSERT INTO provisioner_state ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING id, created_at, updated_at, workspace_id, project_history_id, name, before_id, after_id, transition, initiator, provisioner_state, provision_job_id + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING id, created_at, updated_at, workspace_id, project_version_id, name, before_id, after_id, transition, initiator, provisioner_state, provision_job_id ` type InsertWorkspaceHistoryParams struct { @@ -1951,7 +1951,7 @@ type InsertWorkspaceHistoryParams struct { CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` WorkspaceID uuid.UUID `db:"workspace_id" json:"workspace_id"` - ProjectHistoryID uuid.UUID `db:"project_history_id" json:"project_history_id"` + ProjectVersionID uuid.UUID `db:"project_version_id" json:"project_version_id"` BeforeID uuid.NullUUID `db:"before_id" json:"before_id"` Name string `db:"name" json:"name"` Transition WorkspaceTransition `db:"transition" json:"transition"` @@ -1966,7 +1966,7 @@ func (q *sqlQuerier) InsertWorkspaceHistory(ctx context.Context, arg InsertWorks arg.CreatedAt, arg.UpdatedAt, arg.WorkspaceID, - arg.ProjectHistoryID, + arg.ProjectVersionID, arg.BeforeID, arg.Name, arg.Transition, @@ -1980,7 +1980,7 @@ func (q *sqlQuerier) InsertWorkspaceHistory(ctx context.Context, arg InsertWorks &i.CreatedAt, &i.UpdatedAt, &i.WorkspaceID, - &i.ProjectHistoryID, + &i.ProjectVersionID, &i.Name, &i.BeforeID, &i.AfterID, diff --git a/httpmw/projecthistoryparam.go b/httpmw/projecthistoryparam.go index 07f6a0e9010b5..21deceff87825 100644 --- a/httpmw/projecthistoryparam.go +++ b/httpmw/projecthistoryparam.go @@ -13,47 +13,47 @@ import ( "github.com/coder/coder/httpapi" ) -type projectHistoryParamContextKey struct{} +type projectVersionParamContextKey struct{} -// ProjectHistoryParam returns the project history from the ExtractProjectHistoryParam handler. -func ProjectHistoryParam(r *http.Request) database.ProjectHistory { - projectHistory, ok := r.Context().Value(projectHistoryParamContextKey{}).(database.ProjectHistory) +// ProjectVersionParam returns the project version from the ExtractProjectVersionParam handler. +func ProjectVersionParam(r *http.Request) database.ProjectVersion { + projectVersion, ok := r.Context().Value(projectVersionParamContextKey{}).(database.ProjectVersion) if !ok { - panic("developer error: project history param middleware not provided") + panic("developer error: project version param middleware not provided") } - return projectHistory + return projectVersion } -// ExtractProjectHistoryParam grabs project history from the "projecthistory" URL parameter. -func ExtractProjectHistoryParam(db database.Store) func(http.Handler) http.Handler { +// ExtractProjectVersionParam grabs project version from the "projectversion" URL parameter. +func ExtractProjectVersionParam(db database.Store) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { project := ProjectParam(r) - projectHistoryName := chi.URLParam(r, "projecthistory") - if projectHistoryName == "" { + projectVersionName := chi.URLParam(r, "projectversion") + if projectVersionName == "" { httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ - Message: "project history name must be provided", + Message: "project version name must be provided", }) return } - projectHistory, err := db.GetProjectHistoryByProjectIDAndName(r.Context(), database.GetProjectHistoryByProjectIDAndNameParams{ + projectVersion, err := db.GetProjectVersionByProjectIDAndName(r.Context(), database.GetProjectVersionByProjectIDAndNameParams{ ProjectID: project.ID, - Name: projectHistoryName, + Name: projectVersionName, }) if errors.Is(err, sql.ErrNoRows) { httpapi.Write(rw, http.StatusNotFound, httpapi.Response{ - Message: fmt.Sprintf("project history %q does not exist", projectHistoryName), + Message: fmt.Sprintf("project version %q does not exist", projectVersionName), }) return } if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ - Message: fmt.Sprintf("get project history: %s", err.Error()), + Message: fmt.Sprintf("get project version: %s", err.Error()), }) return } - ctx := context.WithValue(r.Context(), projectHistoryParamContextKey{}, projectHistory) + ctx := context.WithValue(r.Context(), projectVersionParamContextKey{}, projectVersion) next.ServeHTTP(rw, r.WithContext(ctx)) }) } diff --git a/httpmw/projecthistoryparam_test.go b/httpmw/projecthistoryparam_test.go index dbac93517637a..b5054a58231b8 100644 --- a/httpmw/projecthistoryparam_test.go +++ b/httpmw/projecthistoryparam_test.go @@ -19,7 +19,7 @@ import ( "github.com/coder/coder/httpmw" ) -func TestProjectHistoryParam(t *testing.T) { +func TestProjectVersionParam(t *testing.T) { t.Parallel() setupAuthentication := func(db database.Store) (*http.Request, database.Project) { @@ -94,7 +94,7 @@ func TestProjectHistoryParam(t *testing.T) { httpmw.ExtractAPIKey(db, nil), httpmw.ExtractOrganizationParam(db), httpmw.ExtractProjectParam(db), - httpmw.ExtractProjectHistoryParam(db), + httpmw.ExtractProjectVersionParam(db), ) rtr.Get("/", nil) r, _ := setupAuthentication(db) @@ -114,12 +114,12 @@ func TestProjectHistoryParam(t *testing.T) { httpmw.ExtractAPIKey(db, nil), httpmw.ExtractOrganizationParam(db), httpmw.ExtractProjectParam(db), - httpmw.ExtractProjectHistoryParam(db), + httpmw.ExtractProjectVersionParam(db), ) rtr.Get("/", nil) r, _ := setupAuthentication(db) - chi.RouteContext(r.Context()).URLParams.Add("projecthistory", "nothin") + chi.RouteContext(r.Context()).URLParams.Add("projectversion", "nothin") rw := httptest.NewRecorder() rtr.ServeHTTP(rw, r) @@ -128,7 +128,7 @@ func TestProjectHistoryParam(t *testing.T) { require.Equal(t, http.StatusNotFound, res.StatusCode) }) - t.Run("ProjectHistory", func(t *testing.T) { + t.Run("ProjectVersion", func(t *testing.T) { t.Parallel() db := databasefake.New() rtr := chi.NewRouter() @@ -136,21 +136,21 @@ func TestProjectHistoryParam(t *testing.T) { httpmw.ExtractAPIKey(db, nil), httpmw.ExtractOrganizationParam(db), httpmw.ExtractProjectParam(db), - httpmw.ExtractProjectHistoryParam(db), + httpmw.ExtractProjectVersionParam(db), ) rtr.Get("/", func(rw http.ResponseWriter, r *http.Request) { - _ = httpmw.ProjectHistoryParam(r) + _ = httpmw.ProjectVersionParam(r) rw.WriteHeader(http.StatusOK) }) r, project := setupAuthentication(db) - projectHistory, err := db.InsertProjectHistory(context.Background(), database.InsertProjectHistoryParams{ + projectVersion, err := db.InsertProjectVersion(context.Background(), database.InsertProjectVersionParams{ ID: uuid.New(), ProjectID: project.ID, Name: "moo", }) require.NoError(t, err) - chi.RouteContext(r.Context()).URLParams.Add("projecthistory", projectHistory.Name) + chi.RouteContext(r.Context()).URLParams.Add("projectversion", projectVersion.Name) rw := httptest.NewRecorder() rtr.ServeHTTP(rw, r) diff --git a/provisionerd/proto/provisionerd.pb.go b/provisionerd/proto/provisionerd.pb.go index 0f1723b09b4e4..c7b59d6f6fcdc 100644 --- a/provisionerd/proto/provisionerd.pb.go +++ b/provisionerd/proto/provisionerd.pb.go @@ -602,8 +602,8 @@ type AcquiredJob_ProjectImport struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ProjectHistoryId string `protobuf:"bytes,1,opt,name=project_history_id,json=projectHistoryId,proto3" json:"project_history_id,omitempty"` - ProjectHistoryName string `protobuf:"bytes,2,opt,name=project_history_name,json=projectHistoryName,proto3" json:"project_history_name,omitempty"` + ProjectVersionId string `protobuf:"bytes,1,opt,name=project_version_id,json=projectVersionId,proto3" json:"project_version_id,omitempty"` + ProjectVersionName string `protobuf:"bytes,2,opt,name=project_version_name,json=projectVersionName,proto3" json:"project_version_name,omitempty"` } func (x *AcquiredJob_ProjectImport) Reset() { @@ -638,16 +638,16 @@ func (*AcquiredJob_ProjectImport) Descriptor() ([]byte, []int) { return file_provisionerd_proto_provisionerd_proto_rawDescGZIP(), []int{1, 1} } -func (x *AcquiredJob_ProjectImport) GetProjectHistoryId() string { +func (x *AcquiredJob_ProjectImport) GetProjectVersionId() string { if x != nil { - return x.ProjectHistoryId + return x.ProjectVersionId } return "" } -func (x *AcquiredJob_ProjectImport) GetProjectHistoryName() string { +func (x *AcquiredJob_ProjectImport) GetProjectVersionName() string { if x != nil { - return x.ProjectHistoryName + return x.ProjectVersionName } return "" } @@ -805,12 +805,12 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x6f, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x70, - 0x6f, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x68, - 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x10, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x49, - 0x64, 0x12, 0x30, 0x0a, 0x14, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x68, 0x69, 0x73, - 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x12, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4e, + 0x6f, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x10, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x30, 0x0a, 0x14, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x12, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3b, 0x0a, 0x0c, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, diff --git a/provisionerd/proto/provisionerd.proto b/provisionerd/proto/provisionerd.proto index 836d2d5f49a3a..accb69e99f542 100644 --- a/provisionerd/proto/provisionerd.proto +++ b/provisionerd/proto/provisionerd.proto @@ -18,8 +18,8 @@ message AcquiredJob { bytes state = 4; } message ProjectImport { - string project_history_id = 1; - string project_history_name = 2; + string project_version_id = 1; + string project_version_name = 2; } string job_id = 1; int64 created_at = 2; diff --git a/provisionerd/provisionerd.go b/provisionerd/provisionerd.go index f751847b6afe3..2eff81620b87c 100644 --- a/provisionerd/provisionerd.go +++ b/provisionerd/provisionerd.go @@ -318,7 +318,7 @@ func (p *provisionerDaemon) runJob(ctx context.Context, job *proto.AcquiredJob) switch jobType := job.Type.(type) { case *proto.AcquiredJob_ProjectImport_: p.opts.Logger.Debug(context.Background(), "acquired job is project import", - slog.F("project_history_name", jobType.ProjectImport.ProjectHistoryName), + slog.F("project_version_name", jobType.ProjectImport.ProjectVersionName), ) p.runProjectImport(ctx, provisioner, job) @@ -362,7 +362,7 @@ func (p *provisionerDaemon) runProjectImport(ctx context.Context, provisioner sd p.opts.Logger.Debug(context.Background(), "parse job logged", slog.F("level", msgType.Log.Level), slog.F("output", msgType.Log.Output), - slog.F("project_history_id", job.GetProjectImport().ProjectHistoryId), + slog.F("project_version_id", job.GetProjectImport().ProjectVersionId), ) err = p.updateStream.Send(&proto.JobUpdate{ From 7c46342543ba80b67a841f4bba26adab0ce2859c Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 01:02:51 +0000 Subject: [PATCH 02/16] Rename files --- coderd/{projecthistory.go => projectversion.go} | 0 coderd/{projecthistory_test.go => projectversion_test.go} | 0 httpmw/{projecthistoryparam.go => projectversionparam.go} | 0 .../{projecthistoryparam_test.go => projectversionparam_test.go} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename coderd/{projecthistory.go => projectversion.go} (100%) rename coderd/{projecthistory_test.go => projectversion_test.go} (100%) rename httpmw/{projecthistoryparam.go => projectversionparam.go} (100%) rename httpmw/{projecthistoryparam_test.go => projectversionparam_test.go} (100%) diff --git a/coderd/projecthistory.go b/coderd/projectversion.go similarity index 100% rename from coderd/projecthistory.go rename to coderd/projectversion.go diff --git a/coderd/projecthistory_test.go b/coderd/projectversion_test.go similarity index 100% rename from coderd/projecthistory_test.go rename to coderd/projectversion_test.go diff --git a/httpmw/projecthistoryparam.go b/httpmw/projectversionparam.go similarity index 100% rename from httpmw/projecthistoryparam.go rename to httpmw/projectversionparam.go diff --git a/httpmw/projecthistoryparam_test.go b/httpmw/projectversionparam_test.go similarity index 100% rename from httpmw/projecthistoryparam_test.go rename to httpmw/projectversionparam_test.go From 9e04a0ec43102bee56cb55c2bd14a6377147ef9d Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 04:03:43 +0000 Subject: [PATCH 03/16] Standardize tests a bit more --- coderd/coderdtest/coderdtest.go | 153 ++++++++++++++++----------- coderd/coderdtest/coderdtest_test.go | 4 +- coderd/projects.go | 26 ----- coderd/projects_test.go | 146 +++++++++---------------- coderd/projectversion.go | 18 +--- coderd/projectversion_test.go | 146 ++++++++++++++----------- coderd/provisionerdaemons_test.go | 2 +- coderd/users_test.go | 14 +-- coderd/workspacehistory_test.go | 28 ++--- coderd/workspacehistorylogs_test.go | 26 ++--- coderd/workspaces.go | 26 +++++ coderd/workspaces_test.go | 18 ++-- codersdk/client.go | 6 +- codersdk/projects_test.go | 16 +-- codersdk/users_test.go | 8 +- codersdk/workspaces_test.go | 12 +-- go.mod | 1 + go.sum | 2 + provisioner/echo/serve.go | 24 ++++- provisioner/echo/serve_test.go | 4 +- 20 files changed, 359 insertions(+), 321 deletions(-) diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 86a50fabd0d28..c23502c40a255 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -7,16 +7,17 @@ import ( "net/http/httptest" "net/url" "os" + "strings" "testing" "time" + "github.com/moby/moby/pkg/namesgenerator" "github.com/stretchr/testify/require" "cdr.dev/slog" "cdr.dev/slog/sloggers/slogtest" "github.com/coder/coder/coderd" "github.com/coder/coder/codersdk" - "github.com/coder/coder/cryptorand" "github.com/coder/coder/database" "github.com/coder/coder/database/databasefake" "github.com/coder/coder/database/postgres" @@ -26,6 +27,48 @@ import ( "github.com/coder/coder/provisionersdk/proto" ) +// New constructs a new coderd test instance. This returned Server +// should contain no side-effects. +func New(t *testing.T) Server { + // This can be hotswapped for a live database instance. + db := databasefake.New() + pubsub := database.NewPubsubInMemory() + if os.Getenv("DB") != "" { + connectionURL, close, err := postgres.Open() + require.NoError(t, err) + t.Cleanup(close) + sqlDB, err := sql.Open("postgres", connectionURL) + require.NoError(t, err) + t.Cleanup(func() { + _ = sqlDB.Close() + }) + err = database.Migrate(sqlDB) + require.NoError(t, err) + db = database.New(sqlDB) + + pubsub, err = database.NewPubsub(context.Background(), sqlDB, connectionURL) + require.NoError(t, err) + t.Cleanup(func() { + _ = pubsub.Close() + }) + } + + handler := coderd.New(&coderd.Options{ + Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug), + Database: db, + Pubsub: pubsub, + }) + srv := httptest.NewServer(handler) + serverURL, err := url.Parse(srv.URL) + require.NoError(t, err) + t.Cleanup(srv.Close) + + return Server{ + Client: codersdk.New(serverURL), + URL: serverURL, + } +} + // Server represents a test instance of coderd. // The database is intentionally omitted from // this struct to promote data being exposed via @@ -35,38 +78,32 @@ type Server struct { URL *url.URL } -// RandomInitialUser generates a random initial user and authenticates -// it with the client on the Server struct. -func (s *Server) RandomInitialUser(t *testing.T) coderd.CreateInitialUserRequest { - username, err := cryptorand.String(12) - require.NoError(t, err) - password, err := cryptorand.String(12) - require.NoError(t, err) - organization, err := cryptorand.String(12) - require.NoError(t, err) - +// NewInitialUser creates a user with preset credentials and authenticates +// with the passed in codersdk client. +func NewInitialUser(t *testing.T, client *codersdk.Client) coderd.CreateInitialUserRequest { req := coderd.CreateInitialUserRequest{ Email: "testuser@coder.com", - Username: username, - Password: password, - Organization: organization, + Username: "testuser", + Password: "testpass", + Organization: "testorg", } - _, err = s.Client.CreateInitialUser(context.Background(), req) + _, err := client.CreateInitialUser(context.Background(), req) require.NoError(t, err) - login, err := s.Client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ - Email: "testuser@coder.com", - Password: password, + login, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ + Email: req.Email, + Password: req.Password, }) require.NoError(t, err) - err = s.Client.SetSessionToken(login.SessionToken) + err = client.SetSessionToken(login.SessionToken) require.NoError(t, err) return req } -// AddProvisionerd launches a new provisionerd instance with the -// test provisioner registered. -func (s *Server) AddProvisionerd(t *testing.T) io.Closer { +// NewProvisionerDaemon launches a provisionerd instance configured to work +// well with coderd testing. It registers the "echo" provisioner for +// quick testing. +func NewProvisionerDaemon(t *testing.T, client *codersdk.Client) io.Closer { echoClient, echoServer := provisionersdk.TransportPipe() ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(func() { @@ -81,7 +118,7 @@ func (s *Server) AddProvisionerd(t *testing.T) io.Closer { require.NoError(t, err) }() - closer := provisionerd.New(s.Client.ProvisionerDaemonClient, &provisionerd.Options{ + closer := provisionerd.New(client.ProvisionerDaemonClient, &provisionerd.Options{ Logger: slogtest.Make(t, nil).Named("provisionerd").Leveled(slog.LevelDebug), PollInterval: 50 * time.Millisecond, UpdateInterval: 50 * time.Millisecond, @@ -96,44 +133,42 @@ func (s *Server) AddProvisionerd(t *testing.T) io.Closer { return closer } -// New constructs a new coderd test instance. This returned Server -// should contain no side-effects. -func New(t *testing.T) Server { - // This can be hotswapped for a live database instance. - db := databasefake.New() - pubsub := database.NewPubsubInMemory() - if os.Getenv("DB") != "" { - connectionURL, close, err := postgres.Open() - require.NoError(t, err) - t.Cleanup(close) - sqlDB, err := sql.Open("postgres", connectionURL) - require.NoError(t, err) - t.Cleanup(func() { - _ = sqlDB.Close() - }) - err = database.Migrate(sqlDB) - require.NoError(t, err) - db = database.New(sqlDB) - - pubsub, err = database.NewPubsub(context.Background(), sqlDB, connectionURL) - require.NoError(t, err) - t.Cleanup(func() { - _ = pubsub.Close() - }) - } +// NewProject creates a project with the "echo" provisioner for +// compatibility with testing. The name assigned is randomly generated. +func NewProject(t *testing.T, client *codersdk.Client, organization string) coderd.Project { + project, err := client.CreateProject(context.Background(), organization, coderd.CreateProjectRequest{ + Name: randomUsername(), + Provisioner: database.ProvisionerTypeEcho, + }) + require.NoError(t, err) + return project +} - handler := coderd.New(&coderd.Options{ - Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug), - Database: db, - Pubsub: pubsub, +// NewProjectVersion creates a project version for the "echo" provisioner +// for compatibility with testing. +func NewProjectVersion(t *testing.T, client *codersdk.Client, organization, project string, responses *echo.Responses) coderd.ProjectVersion { + data, err := echo.Tar(responses) + require.NoError(t, err) + version, err := client.CreateProjectVersion(context.Background(), organization, project, coderd.CreateProjectVersionRequest{ + StorageMethod: database.ProjectStorageMethodInlineArchive, + StorageSource: data, }) - srv := httptest.NewServer(handler) - serverURL, err := url.Parse(srv.URL) require.NoError(t, err) - t.Cleanup(srv.Close) + return version +} - return Server{ - Client: codersdk.New(serverURL), - URL: serverURL, - } +// AwaitProjectVersionImported awaits for the project import job to reach completed status. +func AwaitProjectVersionImported(t *testing.T, client *codersdk.Client, organization, project, version string) coderd.ProjectVersion { + var projectVersion coderd.ProjectVersion + require.Eventually(t, func() bool { + var err error + projectVersion, err = client.ProjectVersion(context.Background(), organization, project, version) + require.NoError(t, err) + return projectVersion.Import.Status.Completed() + }, 3*time.Second, 50*time.Millisecond) + return projectVersion +} + +func randomUsername() string { + return strings.ReplaceAll(namesgenerator.GetRandomName(0), "_", "-") } diff --git a/coderd/coderdtest/coderdtest_test.go b/coderd/coderdtest/coderdtest_test.go index b7312f96864fc..0de99796172f4 100644 --- a/coderd/coderdtest/coderdtest_test.go +++ b/coderd/coderdtest/coderdtest_test.go @@ -15,6 +15,6 @@ func TestMain(m *testing.M) { func TestNew(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _ = server.RandomInitialUser(t) - _ = server.AddProvisionerd(t) + _ = coderdtest.NewInitialUser(t, server.Client) + _ = coderdtest.NewProvisionerDaemon(t, server.Client) } diff --git a/coderd/projects.go b/coderd/projects.go index 991d20f0e79cf..f03f0d43caaab 100644 --- a/coderd/projects.go +++ b/coderd/projects.go @@ -124,32 +124,6 @@ func (*api) projectByOrganization(rw http.ResponseWriter, r *http.Request) { render.JSON(rw, r, project) } -// Returns all workspaces for a specific project. -func (api *api) workspacesByProject(rw http.ResponseWriter, r *http.Request) { - apiKey := httpmw.APIKey(r) - project := httpmw.ProjectParam(r) - workspaces, err := api.Database.GetWorkspacesByProjectAndUserID(r.Context(), database.GetWorkspacesByProjectAndUserIDParams{ - OwnerID: apiKey.UserID, - ProjectID: project.ID, - }) - if errors.Is(err, sql.ErrNoRows) { - err = nil - } - if err != nil { - httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ - Message: fmt.Sprintf("get workspaces: %s", err), - }) - return - } - - apiWorkspaces := make([]Workspace, 0, len(workspaces)) - for _, workspace := range workspaces { - apiWorkspaces = append(apiWorkspaces, convertWorkspace(workspace)) - } - render.Status(r, http.StatusOK) - render.JSON(rw, r, apiWorkspaces) -} - // Creates parameters for a project. // This should validate the calling user has permissions! func (api *api) postParametersByProject(rw http.ResponseWriter, r *http.Request) { diff --git a/coderd/projects_test.go b/coderd/projects_test.go index b5bbc03766522..887f19c45de14 100644 --- a/coderd/projects_test.go +++ b/coderd/projects_test.go @@ -3,123 +3,104 @@ package coderd_test import ( "context" "testing" - "time" "github.com/stretchr/testify/require" "github.com/coder/coder/coderd" "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/database" - "github.com/coder/coder/provisioner/echo" - "github.com/coder/coder/provisionersdk/proto" ) func TestProjects(t *testing.T) { t.Parallel() - t.Run("Create", func(t *testing.T) { + t.Run("ListEmpty", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - _, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "someproject", - Provisioner: database.ProvisionerTypeEcho, - }) + _ = coderdtest.NewInitialUser(t, server.Client) + projects, err := server.Client.Projects(context.Background(), "") require.NoError(t, err) + require.NotNil(t, projects) + require.Len(t, projects, 0) }) - t.Run("AlreadyExists", func(t *testing.T) { + t.Run("List", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - _, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "someproject", - Provisioner: database.ProvisionerTypeEcho, - }) + user := coderdtest.NewInitialUser(t, server.Client) + _ = coderdtest.NewProject(t, server.Client, user.Organization) + projects, err := server.Client.Projects(context.Background(), "") require.NoError(t, err) - _, err = server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "someproject", - Provisioner: database.ProvisionerTypeEcho, - }) - require.Error(t, err) + require.Len(t, projects, 1) }) +} +func TestProjectsByOrganization(t *testing.T) { + t.Parallel() t.Run("ListEmpty", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _ = server.RandomInitialUser(t) - projects, err := server.Client.Projects(context.Background(), "") + user := coderdtest.NewInitialUser(t, server.Client) + projects, err := server.Client.Projects(context.Background(), user.Organization) require.NoError(t, err) + require.NotNil(t, projects) require.Len(t, projects, 0) }) t.Run("List", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - _, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "someproject", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - // Ensure global query works. + user := coderdtest.NewInitialUser(t, server.Client) + _ = coderdtest.NewProject(t, server.Client, user.Organization) projects, err := server.Client.Projects(context.Background(), "") require.NoError(t, err) require.Len(t, projects, 1) - - // Ensure specified query works. - projects, err = server.Client.Projects(context.Background(), user.Organization) - require.NoError(t, err) - require.Len(t, projects, 1) }) +} - t.Run("ListEmpty", func(t *testing.T) { +func TestPostProjectsByOrganization(t *testing.T) { + t.Parallel() + t.Run("Create", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - - projects, err := server.Client.Projects(context.Background(), user.Organization) - require.NoError(t, err) - require.Len(t, projects, 0) + user := coderdtest.NewInitialUser(t, server.Client) + _ = coderdtest.NewProject(t, server.Client, user.Organization) }) - t.Run("Single", func(t *testing.T) { + t.Run("AlreadyExists", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "someproject", + user := coderdtest.NewInitialUser(t, server.Client) + project := coderdtest.NewProject(t, server.Client, user.Organization) + _, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + Name: project.Name, Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - _, err = server.Client.Project(context.Background(), user.Organization, project.Name) - require.NoError(t, err) }) +} - t.Run("Parameters", func(t *testing.T) { +func TestProjectByOrganization(t *testing.T) { + t.Parallel() + t.Run("Get", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "someproject", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - _, err = server.Client.ProjectParameters(context.Background(), user.Organization, project.Name) + user := coderdtest.NewInitialUser(t, server.Client) + project := coderdtest.NewProject(t, server.Client, user.Organization) + _, err := server.Client.Project(context.Background(), user.Organization, project.Name) require.NoError(t, err) }) +} - t.Run("CreateParameter", func(t *testing.T) { +func TestPostParametersByProject(t *testing.T) { + t.Parallel() + t.Run("Create", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "someproject", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - _, err = server.Client.CreateProjectParameter(context.Background(), user.Organization, project.Name, coderd.CreateParameterValueRequest{ - Name: "hi", + user := coderdtest.NewInitialUser(t, server.Client) + project := coderdtest.NewProject(t, server.Client, user.Organization) + _, err := server.Client.CreateProjectParameter(context.Background(), user.Organization, project.Name, coderd.CreateParameterValueRequest{ + Name: "somename", SourceValue: "tomato", SourceScheme: database.ParameterSourceSchemeData, DestinationScheme: database.ParameterDestinationSchemeEnvironmentVariable, @@ -127,40 +108,17 @@ func TestProjects(t *testing.T) { }) require.NoError(t, err) }) +} - t.Run("Import", func(t *testing.T) { +func TestParametersByProject(t *testing.T) { + t.Parallel() + t.Run("List", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - _ = server.AddProvisionerd(t) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "someproject", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - data, err := echo.Tar([]*proto.Parse_Response{{ - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{ - ParameterSchemas: []*proto.ParameterSchema{{ - Name: "example", - }}, - }, - }, - }}, nil) - require.NoError(t, err) - version, err := server.Client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ - StorageMethod: database.ProjectStorageMethodInlineArchive, - StorageSource: data, - }) - require.NoError(t, err) - require.Eventually(t, func() bool { - projectVersion, err := server.Client.ProjectVersion(context.Background(), user.Organization, project.Name, version.Name) - require.NoError(t, err) - return projectVersion.Import.Status.Completed() - }, 15*time.Second, 10*time.Millisecond) - params, err := server.Client.ProjectVersionParameters(context.Background(), user.Organization, project.Name, version.Name) + user := coderdtest.NewInitialUser(t, server.Client) + project := coderdtest.NewProject(t, server.Client, user.Organization) + params, err := server.Client.ProjectParameters(context.Background(), user.Organization, project.Name) require.NoError(t, err) - require.Len(t, params, 1) - require.Equal(t, "example", params[0].Name) + require.NotNil(t, params) }) } diff --git a/coderd/projectversion.go b/coderd/projectversion.go index ac1906f2be069..1f045e1c09101 100644 --- a/coderd/projectversion.go +++ b/coderd/projectversion.go @@ -110,19 +110,11 @@ func (api *api) postProjectVersionByOrganization(rw http.ResponseWriter, r *http return } - switch createProjectVersion.StorageMethod { - case database.ProjectStorageMethodInlineArchive: - tarReader := tar.NewReader(bytes.NewReader(createProjectVersion.StorageSource)) - _, err := tarReader.Next() - if err != nil { - httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ - Message: "the archive must be a tar", - }) - return - } - default: + tarReader := tar.NewReader(bytes.NewReader(createProjectVersion.StorageSource)) + _, err := tarReader.Next() + if err != nil { httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ - Message: fmt.Sprintf("unsupported storage method %s", createProjectVersion.StorageMethod), + Message: "the archive must be a tar", }) return } @@ -132,7 +124,7 @@ func (api *api) postProjectVersionByOrganization(rw http.ResponseWriter, r *http var provisionerJob database.ProvisionerJob var projectVersion database.ProjectVersion - err := api.Database.InTx(func(db database.Store) error { + err = api.Database.InTx(func(db database.Store) error { projectVersionID := uuid.New() input, err := json.Marshal(projectImportJob{ ProjectVersionID: projectVersionID, diff --git a/coderd/projectversion_test.go b/coderd/projectversion_test.go index 69d8d011b42d6..705d6db28e73d 100644 --- a/coderd/projectversion_test.go +++ b/coderd/projectversion_test.go @@ -1,103 +1,129 @@ package coderd_test import ( - "archive/tar" - "bytes" "context" + "net/http" "testing" "github.com/stretchr/testify/require" "github.com/coder/coder/coderd" "github.com/coder/coder/coderd/coderdtest" + "github.com/coder/coder/codersdk" "github.com/coder/coder/database" "github.com/coder/coder/provisioner/echo" "github.com/coder/coder/provisionersdk/proto" ) -func TestProjectVersion(t *testing.T) { +func TestProjectVersionsByOrganization(t *testing.T) { t.Parallel() - - t.Run("NoHistory", func(t *testing.T) { + t.Run("ListEmpty", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "someproject", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) + user := coderdtest.NewInitialUser(t, server.Client) + project := coderdtest.NewProject(t, server.Client, user.Organization) versions, err := server.Client.ProjectVersions(context.Background(), user.Organization, project.Name) require.NoError(t, err) + require.NotNil(t, versions) require.Len(t, versions, 0) }) - t.Run("CreateVersion", func(t *testing.T) { + t.Run("List", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "someproject", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - data, err := echo.Tar([]*proto.Parse_Response{{ - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{}, - }, - }}, nil) - require.NoError(t, err) - version, err := server.Client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ - StorageMethod: database.ProjectStorageMethodInlineArchive, - StorageSource: data, - }) - require.NoError(t, err) + user := coderdtest.NewInitialUser(t, server.Client) + project := coderdtest.NewProject(t, server.Client, user.Organization) + _ = coderdtest.NewProjectVersion(t, server.Client, user.Organization, project.Name, nil) versions, err := server.Client.ProjectVersions(context.Background(), user.Organization, project.Name) require.NoError(t, err) require.Len(t, versions, 1) + }) +} - _, err = server.Client.ProjectVersion(context.Background(), user.Organization, project.Name, version.Name) - require.NoError(t, err) +func TestProjectVersionByOrganizationAndName(t *testing.T) { + t.Parallel() + t.Run("Get", func(t *testing.T) { + t.Parallel() + server := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, server.Client) + project := coderdtest.NewProject(t, server.Client, user.Organization) + version := coderdtest.NewProjectVersion(t, server.Client, user.Organization, project.Name, nil) + require.Equal(t, version.Import.Status, coderd.ProvisionerJobStatusPending) }) +} - t.Run("CreateHistoryArchiveTooBig", func(t *testing.T) { +func TestPostProjectVersionByOrganization(t *testing.T) { + t.Parallel() + t.Run("Create", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "someproject", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - var buffer bytes.Buffer - writer := tar.NewWriter(&buffer) - err = writer.WriteHeader(&tar.Header{ - Name: "file", - Size: 1 << 21, - }) - require.NoError(t, err) - _, err = writer.Write(make([]byte, 1<<21)) - require.NoError(t, err) - _, err = server.Client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ - StorageMethod: database.ProjectStorageMethodInlineArchive, - StorageSource: buffer.Bytes(), + user := coderdtest.NewInitialUser(t, server.Client) + project := coderdtest.NewProject(t, server.Client, user.Organization) + _ = coderdtest.NewProjectVersion(t, server.Client, user.Organization, project.Name, nil) + }) + + t.Run("InvalidStorage", func(t *testing.T) { + t.Parallel() + server := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, server.Client) + project := coderdtest.NewProject(t, server.Client, user.Organization) + _, err := server.Client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ + StorageMethod: database.ProjectStorageMethod("invalid"), + StorageSource: []byte{}, }) require.Error(t, err) }) +} - t.Run("CreateHistoryInvalidArchive", func(t *testing.T) { +func TestProjectVersionParametersByOrganizationAndName(t *testing.T) { + t.Parallel() + t.Run("NotImported", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "someproject", - Provisioner: database.ProvisionerTypeEcho, + user := coderdtest.NewInitialUser(t, server.Client) + project := coderdtest.NewProject(t, server.Client, user.Organization) + version := coderdtest.NewProjectVersion(t, server.Client, user.Organization, project.Name, nil) + _, err := server.Client.ProjectVersionParameters(context.Background(), user.Organization, project.Name, version.Name) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusPreconditionRequired, apiErr.StatusCode()) + }) + + t.Run("FailedImport", func(t *testing.T) { + t.Parallel() + server := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, server.Client) + _ = coderdtest.NewProvisionerDaemon(t, server.Client) + project := coderdtest.NewProject(t, server.Client, user.Organization) + version := coderdtest.NewProjectVersion(t, server.Client, user.Organization, project.Name, &echo.Responses{ + Provision: []*proto.Provision_Response{{}}, }) - require.NoError(t, err) - _, err = server.Client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ - StorageMethod: database.ProjectStorageMethodInlineArchive, - StorageSource: []byte{}, + coderdtest.AwaitProjectVersionImported(t, server.Client, user.Organization, project.Name, version.Name) + _, err := server.Client.ProjectVersionParameters(context.Background(), user.Organization, project.Name, version.Name) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode()) + }) + t.Run("List", func(t *testing.T) { + t.Parallel() + server := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, server.Client) + _ = coderdtest.NewProvisionerDaemon(t, server.Client) + project := coderdtest.NewProject(t, server.Client, user.Organization) + version := coderdtest.NewProjectVersion(t, server.Client, user.Organization, project.Name, &echo.Responses{ + Parse: []*proto.Parse_Response{{ + Type: &proto.Parse_Response_Complete{ + Complete: &proto.Parse_Complete{ + ParameterSchemas: []*proto.ParameterSchema{{ + Name: "example", + }}, + }, + }, + }}, }) - require.Error(t, err) + coderdtest.AwaitProjectVersionImported(t, server.Client, user.Organization, project.Name, version.Name) + params, err := server.Client.ProjectVersionParameters(context.Background(), user.Organization, project.Name, version.Name) + require.NoError(t, err) + require.Len(t, params, 1) }) } diff --git a/coderd/provisionerdaemons_test.go b/coderd/provisionerdaemons_test.go index 5cba701d5a34e..757d4f3ced7f9 100644 --- a/coderd/provisionerdaemons_test.go +++ b/coderd/provisionerdaemons_test.go @@ -16,7 +16,7 @@ func TestProvisionerDaemons(t *testing.T) { t.Run("Register", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _ = server.AddProvisionerd(t) + _ = coderdtest.NewProvisionerDaemon(t, server.Client) require.Eventually(t, func() bool { daemons, err := server.Client.ProvisionerDaemons(context.Background()) require.NoError(t, err) diff --git a/coderd/users_test.go b/coderd/users_test.go index 11b533b0f7bd8..9974f8c9cc9a9 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -18,7 +18,7 @@ func TestUsers(t *testing.T) { t.Run("Authenticated", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _ = server.RandomInitialUser(t) + _ = coderdtest.NewInitialUser(t, server.Client) _, err := server.Client.User(context.Background(), "") require.NoError(t, err) }) @@ -26,7 +26,7 @@ func TestUsers(t *testing.T) { t.Run("CreateMultipleInitial", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _ = server.RandomInitialUser(t) + _ = coderdtest.NewInitialUser(t, server.Client) _, err := server.Client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{ Email: "dummy@coder.com", Organization: "bananas", @@ -39,7 +39,7 @@ func TestUsers(t *testing.T) { t.Run("Login", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) _, err := server.Client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ Email: user.Email, Password: user.Password, @@ -60,7 +60,7 @@ func TestUsers(t *testing.T) { t.Run("LoginBadPassword", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) _, err := server.Client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ Email: user.Email, Password: "bananas", @@ -71,7 +71,7 @@ func TestUsers(t *testing.T) { t.Run("ListOrganizations", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _ = server.RandomInitialUser(t) + _ = coderdtest.NewInitialUser(t, server.Client) orgs, err := server.Client.UserOrganizations(context.Background(), "") require.NoError(t, err) require.Len(t, orgs, 1) @@ -80,7 +80,7 @@ func TestUsers(t *testing.T) { t.Run("CreateUser", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _ = server.RandomInitialUser(t) + _ = coderdtest.NewInitialUser(t, server.Client) _, err := server.Client.CreateUser(context.Background(), coderd.CreateUserRequest{ Email: "wow@ok.io", Username: "tomato", @@ -92,7 +92,7 @@ func TestUsers(t *testing.T) { t.Run("CreateUserConflict", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) _, err := server.Client.CreateUser(context.Background(), coderd.CreateUserRequest{ Email: "wow@ok.io", Username: user.Username, diff --git a/coderd/workspacehistory_test.go b/coderd/workspacehistory_test.go index 484269892ad3f..49a7830f95913 100644 --- a/coderd/workspacehistory_test.go +++ b/coderd/workspacehistory_test.go @@ -50,13 +50,13 @@ func TestWorkspaceHistory(t *testing.T) { t.Run("AllHistory", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - _ = server.AddProvisionerd(t) + user := coderdtest.NewInitialUser(t, server.Client) + _ = coderdtest.NewProvisionerDaemon(t, server.Client) project, workspace := setupProjectAndWorkspace(t, server.Client, user) history, err := server.Client.ListWorkspaceHistory(context.Background(), "", workspace.Name) require.NoError(t, err) require.Len(t, history, 0) - data, err := echo.Tar(echo.ParseComplete, echo.ProvisionComplete) + data, err := echo.Tar(nil) require.NoError(t, err) projectVersion := setupProjectVersion(t, server.Client, user, project, data) _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ @@ -72,12 +72,12 @@ func TestWorkspaceHistory(t *testing.T) { t.Run("LatestHistory", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - _ = server.AddProvisionerd(t) + user := coderdtest.NewInitialUser(t, server.Client) + _ = coderdtest.NewProvisionerDaemon(t, server.Client) project, workspace := setupProjectAndWorkspace(t, server.Client, user) _, err := server.Client.WorkspaceHistory(context.Background(), "", workspace.Name, "") require.Error(t, err) - data, err := echo.Tar(echo.ParseComplete, echo.ProvisionComplete) + data, err := echo.Tar(nil) require.NoError(t, err) projectVersion := setupProjectVersion(t, server.Client, user, project, data) _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ @@ -92,10 +92,10 @@ func TestWorkspaceHistory(t *testing.T) { t.Run("CreateHistory", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - _ = server.AddProvisionerd(t) + user := coderdtest.NewInitialUser(t, server.Client) + _ = coderdtest.NewProvisionerDaemon(t, server.Client) project, workspace := setupProjectAndWorkspace(t, server.Client, user) - data, err := echo.Tar(echo.ParseComplete, echo.ProvisionComplete) + data, err := echo.Tar(nil) require.NoError(t, err) projectVersion := setupProjectVersion(t, server.Client, user, project, data) _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ @@ -117,10 +117,10 @@ func TestWorkspaceHistory(t *testing.T) { t.Run("CreateHistoryAlreadyInProgress", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - _ = server.AddProvisionerd(t) + user := coderdtest.NewInitialUser(t, server.Client) + _ = coderdtest.NewProvisionerDaemon(t, server.Client) project, workspace := setupProjectAndWorkspace(t, server.Client, user) - data, err := echo.Tar(echo.ParseComplete, echo.ProvisionComplete) + data, err := echo.Tar(nil) require.NoError(t, err) projectVersion := setupProjectVersion(t, server.Client, user, project, data) @@ -140,8 +140,8 @@ func TestWorkspaceHistory(t *testing.T) { t.Run("CreateHistoryInvalidProjectVersion", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) - _ = server.AddProvisionerd(t) + user := coderdtest.NewInitialUser(t, server.Client) + _ = coderdtest.NewProvisionerDaemon(t, server.Client) _, workspace := setupProjectAndWorkspace(t, server.Client, user) _, err := server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ diff --git a/coderd/workspacehistorylogs_test.go b/coderd/workspacehistorylogs_test.go index f507001beb4d5..9719e483a47ff 100644 --- a/coderd/workspacehistorylogs_test.go +++ b/coderd/workspacehistorylogs_test.go @@ -47,20 +47,22 @@ func TestWorkspaceHistoryLogs(t *testing.T) { } server := coderdtest.New(t) - user := server.RandomInitialUser(t) - _ = server.AddProvisionerd(t) + user := coderdtest.NewInitialUser(t, server.Client) + _ = coderdtest.NewProvisionerDaemon(t, server.Client) project, workspace := setupProjectAndWorkspace(t, server.Client, user) - data, err := echo.Tar(echo.ParseComplete, []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Log{ - Log: &proto.Log{ - Output: "test", + data, err := echo.Tar(&echo.Responses{ + echo.ParseComplete, []*proto.Provision_Response{{ + Type: &proto.Provision_Response_Log{ + Log: &proto.Log{ + Output: "test", + }, }, - }, - }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}) + }, { + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{}, + }, + }}, + }) require.NoError(t, err) projectVersion := setupProjectVersion(t, server.Client, user, project, data) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 01ef9870cecd4..22c10d7cc546b 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -145,6 +145,32 @@ func (*api) workspaceByUser(rw http.ResponseWriter, r *http.Request) { render.JSON(rw, r, convertWorkspace(workspace)) } +// Returns all workspaces for a specific project. +func (api *api) workspacesByProject(rw http.ResponseWriter, r *http.Request) { + apiKey := httpmw.APIKey(r) + project := httpmw.ProjectParam(r) + workspaces, err := api.Database.GetWorkspacesByProjectAndUserID(r.Context(), database.GetWorkspacesByProjectAndUserIDParams{ + OwnerID: apiKey.UserID, + ProjectID: project.ID, + }) + if errors.Is(err, sql.ErrNoRows) { + err = nil + } + if err != nil { + httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ + Message: fmt.Sprintf("get workspaces: %s", err), + }) + return + } + + apiWorkspaces := make([]Workspace, 0, len(workspaces)) + for _, workspace := range workspaces { + apiWorkspaces = append(apiWorkspaces, convertWorkspace(workspace)) + } + render.Status(r, http.StatusOK) + render.JSON(rw, r, apiWorkspaces) +} + // Converts the internal workspace representation to a public external-facing model. func convertWorkspace(workspace database.Workspace) Workspace { return Workspace(workspace) diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 2ee817899ca64..991009bda341c 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -19,7 +19,7 @@ func TestWorkspaces(t *testing.T) { t.Run("ListNone", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _ = server.RandomInitialUser(t) + _ = coderdtest.NewInitialUser(t, server.Client) workspaces, err := server.Client.WorkspacesByUser(context.Background(), "") require.NoError(t, err) require.Len(t, workspaces, 0) @@ -42,7 +42,7 @@ func TestWorkspaces(t *testing.T) { t.Run("List", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) _, _ = setupProjectAndWorkspace(t, server.Client, user) workspaces, err := server.Client.WorkspacesByUser(context.Background(), "") require.NoError(t, err) @@ -52,7 +52,7 @@ func TestWorkspaces(t *testing.T) { t.Run("ListNoneForProject", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "banana", Provisioner: database.ProvisionerTypeEcho, @@ -66,7 +66,7 @@ func TestWorkspaces(t *testing.T) { t.Run("ListForProject", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) project, _ := setupProjectAndWorkspace(t, server.Client, user) workspaces, err := server.Client.WorkspacesByProject(context.Background(), user.Organization, project.Name) require.NoError(t, err) @@ -76,7 +76,7 @@ func TestWorkspaces(t *testing.T) { t.Run("CreateInvalidInput", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "banana", Provisioner: database.ProvisionerTypeEcho, @@ -92,7 +92,7 @@ func TestWorkspaces(t *testing.T) { t.Run("CreateInvalidProject", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _ = server.RandomInitialUser(t) + _ = coderdtest.NewInitialUser(t, server.Client) _, err := server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ ProjectID: uuid.New(), Name: "moo", @@ -103,7 +103,7 @@ func TestWorkspaces(t *testing.T) { t.Run("CreateNotInProjectOrganization", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - initial := server.RandomInitialUser(t) + initial := coderdtest.NewInitialUser(t, server.Client) project, err := server.Client.CreateProject(context.Background(), initial.Organization, coderd.CreateProjectRequest{ Name: "banana", Provisioner: database.ProvisionerTypeEcho, @@ -132,7 +132,7 @@ func TestWorkspaces(t *testing.T) { t.Run("CreateAlreadyExists", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) project, workspace := setupProjectAndWorkspace(t, server.Client, user) _, err := server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ Name: workspace.Name, @@ -144,7 +144,7 @@ func TestWorkspaces(t *testing.T) { t.Run("Single", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) _, workspace := setupProjectAndWorkspace(t, server.Client, user) _, err := server.Client.Workspace(context.Background(), "", workspace.Name) require.NoError(t, err) diff --git a/codersdk/client.go b/codersdk/client.go index b4931a91e8b91..1e688fa7fae6a 100644 --- a/codersdk/client.go +++ b/codersdk/client.go @@ -112,5 +112,9 @@ func (e *Error) StatusCode() int { } func (e *Error) Error() string { - return fmt.Sprintf("status code %d: %s", e.statusCode, e.Message) + msg := fmt.Sprintf("status code %d: %s", e.statusCode, e.Message) + for _, err := range e.Errors { + msg += fmt.Sprintf("\n\t%s: %s", err.Field, err.Code) + } + return msg } diff --git a/codersdk/projects_test.go b/codersdk/projects_test.go index 957a759b3e062..cdd87f2bde350 100644 --- a/codersdk/projects_test.go +++ b/codersdk/projects_test.go @@ -26,7 +26,7 @@ func TestProjects(t *testing.T) { t.Run("List", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) _, err := server.Client.Projects(context.Background(), "") require.NoError(t, err) _, err = server.Client.Projects(context.Background(), user.Organization) @@ -43,7 +43,7 @@ func TestProjects(t *testing.T) { t.Run("Create", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) _, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", Provisioner: database.ProvisionerTypeEcho, @@ -61,7 +61,7 @@ func TestProjects(t *testing.T) { t.Run("Single", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) _, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", Provisioner: database.ProvisionerTypeEcho, @@ -81,7 +81,7 @@ func TestProjects(t *testing.T) { t.Run("History", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", Provisioner: database.ProvisionerTypeEcho, @@ -104,7 +104,7 @@ func TestProjects(t *testing.T) { t.Run("CreateHistory", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", Provisioner: database.ProvisionerTypeEcho, @@ -132,7 +132,7 @@ func TestProjects(t *testing.T) { t.Run("Parameters", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", Provisioner: database.ProvisionerTypeEcho, @@ -147,7 +147,7 @@ func TestProjects(t *testing.T) { t.Run("CreateParameter", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", Provisioner: database.ProvisionerTypeEcho, @@ -167,7 +167,7 @@ func TestProjects(t *testing.T) { t.Run("HistoryParametersError", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) _, err := server.Client.ProjectVersionParameters(context.Background(), user.Organization, "nothing", "nope") require.Error(t, err) }) diff --git a/codersdk/users_test.go b/codersdk/users_test.go index 26f1e7d3fd646..33ef6c09e12e5 100644 --- a/codersdk/users_test.go +++ b/codersdk/users_test.go @@ -34,7 +34,7 @@ func TestUsers(t *testing.T) { t.Run("User", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _ = server.RandomInitialUser(t) + _ = coderdtest.NewInitialUser(t, server.Client) _, err := server.Client.User(context.Background(), "") require.NoError(t, err) }) @@ -42,7 +42,7 @@ func TestUsers(t *testing.T) { t.Run("UserOrganizations", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _ = server.RandomInitialUser(t) + _ = coderdtest.NewInitialUser(t, server.Client) orgs, err := server.Client.UserOrganizations(context.Background(), "") require.NoError(t, err) require.Len(t, orgs, 1) @@ -51,7 +51,7 @@ func TestUsers(t *testing.T) { t.Run("LogoutIsSuccessful", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _ = server.RandomInitialUser(t) + _ = coderdtest.NewInitialUser(t, server.Client) err := server.Client.Logout(context.Background()) require.NoError(t, err) }) @@ -59,7 +59,7 @@ func TestUsers(t *testing.T) { t.Run("CreateMultiple", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - _ = server.RandomInitialUser(t) + _ = coderdtest.NewInitialUser(t, server.Client) _, err := server.Client.CreateUser(context.Background(), coderd.CreateUserRequest{ Email: "wow@ok.io", Username: "example", diff --git a/codersdk/workspaces_test.go b/codersdk/workspaces_test.go index 21e0d5bcaa1a6..4f781e9f794bd 100644 --- a/codersdk/workspaces_test.go +++ b/codersdk/workspaces_test.go @@ -31,7 +31,7 @@ func TestWorkspaces(t *testing.T) { t.Run("ListByUser", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, @@ -49,7 +49,7 @@ func TestWorkspaces(t *testing.T) { t.Run("ListByProject", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, @@ -81,7 +81,7 @@ func TestWorkspaces(t *testing.T) { t.Run("Single", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, @@ -106,7 +106,7 @@ func TestWorkspaces(t *testing.T) { t.Run("History", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, @@ -131,7 +131,7 @@ func TestWorkspaces(t *testing.T) { t.Run("LatestHistory", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, @@ -149,7 +149,7 @@ func TestWorkspaces(t *testing.T) { t.Run("CreateHistory", func(t *testing.T) { t.Parallel() server := coderdtest.New(t) - user := server.RandomInitialUser(t) + user := coderdtest.NewInitialUser(t, server.Client) project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, diff --git a/go.mod b/go.mod index 7b2557fa99db8..328e0bf127178 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/pion/logging v0.2.2 github.com/pion/transport v0.13.0 github.com/pion/webrtc/v3 v3.1.21 + github.com/quasilyte/go-ruleguard/dsl v0.3.16 github.com/spf13/cobra v1.3.0 github.com/stretchr/testify v1.7.0 github.com/unrolled/secure v1.0.9 diff --git a/go.sum b/go.sum index a05e8a7a74e34..c2b41be6dcec0 100644 --- a/go.sum +++ b/go.sum @@ -1087,6 +1087,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/quasilyte/go-ruleguard/dsl v0.3.16 h1:yJtIpd4oyNS+/c/gKqxNwoGO9+lPOsy1A4BzKjJRcrI= +github.com/quasilyte/go-ruleguard/dsl v0.3.16/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= diff --git a/provisioner/echo/serve.go b/provisioner/echo/serve.go index 12172b6c5864e..ac7c2ea3e39b0 100644 --- a/provisioner/echo/serve.go +++ b/provisioner/echo/serve.go @@ -4,6 +4,7 @@ import ( "archive/tar" "bytes" "context" + "errors" "fmt" "os" "path/filepath" @@ -48,6 +49,10 @@ func (*echo) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_Pa path := filepath.Join(request.Directory, fmt.Sprintf("%d.parse.protobuf", index)) _, err := os.Stat(path) if err != nil { + if index == 0 { + // Error if nothing is around to enable failed states. + return errors.New("no state") + } break } data, err := os.ReadFile(path) @@ -73,6 +78,10 @@ func (*echo) Provision(request *proto.Provision_Request, stream proto.DRPCProvis path := filepath.Join(request.Directory, fmt.Sprintf("%d.provision.protobuf", index)) _, err := os.Stat(path) if err != nil { + if index == 0 { + // Error if nothing is around to enable failed states. + return errors.New("no state") + } break } data, err := os.ReadFile(path) @@ -92,11 +101,20 @@ func (*echo) Provision(request *proto.Provision_Request, stream proto.DRPCProvis return nil } +type Responses struct { + Parse []*proto.Parse_Response + Provision []*proto.Provision_Response +} + // Tar returns a tar archive of responses to provisioner operations. -func Tar(parseResponses []*proto.Parse_Response, provisionResponses []*proto.Provision_Response) ([]byte, error) { +func Tar(responses *Responses) ([]byte, error) { + if responses == nil { + responses = &Responses{ParseComplete, ProvisionComplete} + } + var buffer bytes.Buffer writer := tar.NewWriter(&buffer) - for index, response := range parseResponses { + for index, response := range responses.Parse { data, err := protobuf.Marshal(response) if err != nil { return nil, err @@ -113,7 +131,7 @@ func Tar(parseResponses []*proto.Parse_Response, provisionResponses []*proto.Pro return nil, err } } - for index, response := range provisionResponses { + for index, response := range responses.Provision { data, err := protobuf.Marshal(response) if err != nil { return nil, err diff --git a/provisioner/echo/serve_test.go b/provisioner/echo/serve_test.go index ce8a1e078bad1..48ca00e11d94d 100644 --- a/provisioner/echo/serve_test.go +++ b/provisioner/echo/serve_test.go @@ -53,7 +53,7 @@ func TestEcho(t *testing.T) { }, }, }} - data, err := echo.Tar(responses, nil) + data, err := echo.Tar(&echo.Responses{responses, nil}) require.NoError(t, err) client, err := api.Parse(ctx, &proto.Parse_Request{ Directory: unpackTar(t, data), @@ -86,7 +86,7 @@ func TestEcho(t *testing.T) { }, }, }} - data, err := echo.Tar(nil, responses) + data, err := echo.Tar(&echo.Responses{nil, responses}) require.NoError(t, err) client, err := api.Provision(ctx, &proto.Provision_Request{ Directory: unpackTar(t, data), From 9cd8b436f2d03f6be4ea8c05f0fc70e82df5d5a7 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 07:03:56 +0000 Subject: [PATCH 04/16] Remove Server struct from coderdtest --- .golangci.yml | 4 ++ coderd/coderdtest/coderdtest.go | 19 ++++-- coderd/coderdtest/coderdtest_test.go | 6 +- coderd/projects.go | 2 + coderd/projects_test.go | 72 ++++++++++++----------- coderd/projectversion_test.go | 80 ++++++++++++------------- coderd/provisionerdaemons.go | 20 +------ coderd/provisionerdaemons_test.go | 6 +- coderd/users_test.go | 50 ++++++++-------- coderd/workspacehistory_test.go | 88 +++++++++++++++++----------- coderd/workspacehistorylogs_test.go | 18 +++--- coderd/workspaces_test.go | 74 +++++++++++------------ codersdk/client.go | 9 +-- codersdk/projects_test.go | 82 +++++++++++++------------- codersdk/provisioners.go | 2 +- codersdk/users_test.go | 32 +++++----- codersdk/workspaces_test.go | 84 +++++++++++++------------- provisioner/echo/serve.go | 5 +- rules.go | 23 ++++++++ 19 files changed, 361 insertions(+), 315 deletions(-) create mode 100644 rules.go diff --git a/.golangci.yml b/.golangci.yml index abad144557b76..c85be43163feb 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -100,6 +100,10 @@ linters-settings: # - whyNoLint # - wrapperFunc # - yodaStyleExpr + settings: + ruleguard: + failOn: all + rules: rules.go goimports: local-prefixes: coder.com,cdr.dev,go.coder.com,github.com/cdr,github.com/coder diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index c23502c40a255..3ed3ef29add93 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -11,6 +11,7 @@ import ( "testing" "time" + "github.com/google/uuid" "github.com/moby/moby/pkg/namesgenerator" "github.com/stretchr/testify/require" @@ -29,7 +30,7 @@ import ( // New constructs a new coderd test instance. This returned Server // should contain no side-effects. -func New(t *testing.T) Server { +func New(t *testing.T) *codersdk.Client { // This can be hotswapped for a live database instance. db := databasefake.New() pubsub := database.NewPubsubInMemory() @@ -63,10 +64,7 @@ func New(t *testing.T) Server { require.NoError(t, err) t.Cleanup(srv.Close) - return Server{ - Client: codersdk.New(serverURL), - URL: serverURL, - } + return codersdk.New(serverURL) } // Server represents a test instance of coderd. @@ -169,6 +167,17 @@ func AwaitProjectVersionImported(t *testing.T, client *codersdk.Client, organiza return projectVersion } +// NewWorkspace creates a workspace for the user and project provided. +// A random name is generated for it. +func NewWorkspace(t *testing.T, client *codersdk.Client, user string, projectID uuid.UUID) coderd.Workspace { + workspace, err := client.CreateWorkspace(context.Background(), user, coderd.CreateWorkspaceRequest{ + ProjectID: projectID, + Name: randomUsername(), + }) + require.NoError(t, err) + return workspace +} + func randomUsername() string { return strings.ReplaceAll(namesgenerator.GetRandomName(0), "_", "-") } diff --git a/coderd/coderdtest/coderdtest_test.go b/coderd/coderdtest/coderdtest_test.go index 0de99796172f4..c7c6fac010fa1 100644 --- a/coderd/coderdtest/coderdtest_test.go +++ b/coderd/coderdtest/coderdtest_test.go @@ -14,7 +14,7 @@ func TestMain(m *testing.M) { func TestNew(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, server.Client) - _ = coderdtest.NewProvisionerDaemon(t, server.Client) + client := coderdtest.New(t) + _ = coderdtest.NewInitialUser(t, client) + _ = coderdtest.NewProvisionerDaemon(t, client) } diff --git a/coderd/projects.go b/coderd/projects.go index f03f0d43caaab..d140468feb291 100644 --- a/coderd/projects.go +++ b/coderd/projects.go @@ -42,6 +42,7 @@ func (api *api) projects(rw http.ResponseWriter, r *http.Request) { projects, err := api.Database.GetProjectsByOrganizationIDs(r.Context(), organizationIDs) if errors.Is(err, sql.ErrNoRows) { err = nil + projects = []database.Project{} } if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ @@ -59,6 +60,7 @@ func (api *api) projectsByOrganization(rw http.ResponseWriter, r *http.Request) projects, err := api.Database.GetProjectsByOrganizationIDs(r.Context(), []string{organization.ID}) if errors.Is(err, sql.ErrNoRows) { err = nil + projects = []database.Project{} } if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ diff --git a/coderd/projects_test.go b/coderd/projects_test.go index 887f19c45de14..83a7f91b641f5 100644 --- a/coderd/projects_test.go +++ b/coderd/projects_test.go @@ -2,12 +2,14 @@ package coderd_test import ( "context" + "net/http" "testing" "github.com/stretchr/testify/require" "github.com/coder/coder/coderd" "github.com/coder/coder/coderd/coderdtest" + "github.com/coder/coder/codersdk" "github.com/coder/coder/database" ) @@ -16,9 +18,9 @@ func TestProjects(t *testing.T) { t.Run("ListEmpty", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, server.Client) - projects, err := server.Client.Projects(context.Background(), "") + client := coderdtest.New(t) + _ = coderdtest.NewInitialUser(t, client) + projects, err := client.Projects(context.Background(), "") require.NoError(t, err) require.NotNil(t, projects) require.Len(t, projects, 0) @@ -26,10 +28,10 @@ func TestProjects(t *testing.T) { t.Run("List", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _ = coderdtest.NewProject(t, server.Client, user.Organization) - projects, err := server.Client.Projects(context.Background(), "") + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _ = coderdtest.NewProject(t, client, user.Organization) + projects, err := client.Projects(context.Background(), "") require.NoError(t, err) require.Len(t, projects, 1) }) @@ -39,9 +41,9 @@ func TestProjectsByOrganization(t *testing.T) { t.Parallel() t.Run("ListEmpty", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - projects, err := server.Client.Projects(context.Background(), user.Organization) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + projects, err := client.Projects(context.Background(), user.Organization) require.NoError(t, err) require.NotNil(t, projects) require.Len(t, projects, 0) @@ -49,10 +51,10 @@ func TestProjectsByOrganization(t *testing.T) { t.Run("List", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _ = coderdtest.NewProject(t, server.Client, user.Organization) - projects, err := server.Client.Projects(context.Background(), "") + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _ = coderdtest.NewProject(t, client, user.Organization) + projects, err := client.Projects(context.Background(), "") require.NoError(t, err) require.Len(t, projects, 1) }) @@ -62,21 +64,23 @@ func TestPostProjectsByOrganization(t *testing.T) { t.Parallel() t.Run("Create", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _ = coderdtest.NewProject(t, server.Client, user.Organization) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _ = coderdtest.NewProject(t, client, user.Organization) }) t.Run("AlreadyExists", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project := coderdtest.NewProject(t, server.Client, user.Organization) - _, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project := coderdtest.NewProject(t, client, user.Organization) + _, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: project.Name, Provisioner: database.ProvisionerTypeEcho, }) - require.NoError(t, err) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusConflict, apiErr.StatusCode()) }) } @@ -84,10 +88,10 @@ func TestProjectByOrganization(t *testing.T) { t.Parallel() t.Run("Get", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project := coderdtest.NewProject(t, server.Client, user.Organization) - _, err := server.Client.Project(context.Background(), user.Organization, project.Name) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project := coderdtest.NewProject(t, client, user.Organization) + _, err := client.Project(context.Background(), user.Organization, project.Name) require.NoError(t, err) }) } @@ -96,10 +100,10 @@ func TestPostParametersByProject(t *testing.T) { t.Parallel() t.Run("Create", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project := coderdtest.NewProject(t, server.Client, user.Organization) - _, err := server.Client.CreateProjectParameter(context.Background(), user.Organization, project.Name, coderd.CreateParameterValueRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project := coderdtest.NewProject(t, client, user.Organization) + _, err := client.CreateProjectParameter(context.Background(), user.Organization, project.Name, coderd.CreateParameterValueRequest{ Name: "somename", SourceValue: "tomato", SourceScheme: database.ParameterSourceSchemeData, @@ -114,10 +118,10 @@ func TestParametersByProject(t *testing.T) { t.Parallel() t.Run("List", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project := coderdtest.NewProject(t, server.Client, user.Organization) - params, err := server.Client.ProjectParameters(context.Background(), user.Organization, project.Name) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project := coderdtest.NewProject(t, client, user.Organization) + params, err := client.ProjectParameters(context.Background(), user.Organization, project.Name) require.NoError(t, err) require.NotNil(t, params) }) diff --git a/coderd/projectversion_test.go b/coderd/projectversion_test.go index 705d6db28e73d..c03263f0f7972 100644 --- a/coderd/projectversion_test.go +++ b/coderd/projectversion_test.go @@ -19,10 +19,10 @@ func TestProjectVersionsByOrganization(t *testing.T) { t.Parallel() t.Run("ListEmpty", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project := coderdtest.NewProject(t, server.Client, user.Organization) - versions, err := server.Client.ProjectVersions(context.Background(), user.Organization, project.Name) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project := coderdtest.NewProject(t, client, user.Organization) + versions, err := client.ProjectVersions(context.Background(), user.Organization, project.Name) require.NoError(t, err) require.NotNil(t, versions) require.Len(t, versions, 0) @@ -30,11 +30,11 @@ func TestProjectVersionsByOrganization(t *testing.T) { t.Run("List", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project := coderdtest.NewProject(t, server.Client, user.Organization) - _ = coderdtest.NewProjectVersion(t, server.Client, user.Organization, project.Name, nil) - versions, err := server.Client.ProjectVersions(context.Background(), user.Organization, project.Name) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project := coderdtest.NewProject(t, client, user.Organization) + _ = coderdtest.NewProjectVersion(t, client, user.Organization, project.Name, nil) + versions, err := client.ProjectVersions(context.Background(), user.Organization, project.Name) require.NoError(t, err) require.Len(t, versions, 1) }) @@ -44,10 +44,10 @@ func TestProjectVersionByOrganizationAndName(t *testing.T) { t.Parallel() t.Run("Get", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project := coderdtest.NewProject(t, server.Client, user.Organization) - version := coderdtest.NewProjectVersion(t, server.Client, user.Organization, project.Name, nil) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project := coderdtest.NewProject(t, client, user.Organization) + version := coderdtest.NewProjectVersion(t, client, user.Organization, project.Name, nil) require.Equal(t, version.Import.Status, coderd.ProvisionerJobStatusPending) }) } @@ -56,18 +56,18 @@ func TestPostProjectVersionByOrganization(t *testing.T) { t.Parallel() t.Run("Create", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project := coderdtest.NewProject(t, server.Client, user.Organization) - _ = coderdtest.NewProjectVersion(t, server.Client, user.Organization, project.Name, nil) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project := coderdtest.NewProject(t, client, user.Organization) + _ = coderdtest.NewProjectVersion(t, client, user.Organization, project.Name, nil) }) t.Run("InvalidStorage", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project := coderdtest.NewProject(t, server.Client, user.Organization) - _, err := server.Client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project := coderdtest.NewProject(t, client, user.Organization) + _, err := client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ StorageMethod: database.ProjectStorageMethod("invalid"), StorageSource: []byte{}, }) @@ -79,11 +79,11 @@ func TestProjectVersionParametersByOrganizationAndName(t *testing.T) { t.Parallel() t.Run("NotImported", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project := coderdtest.NewProject(t, server.Client, user.Organization) - version := coderdtest.NewProjectVersion(t, server.Client, user.Organization, project.Name, nil) - _, err := server.Client.ProjectVersionParameters(context.Background(), user.Organization, project.Name, version.Name) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project := coderdtest.NewProject(t, client, user.Organization) + version := coderdtest.NewProjectVersion(t, client, user.Organization, project.Name, nil) + _, err := client.ProjectVersionParameters(context.Background(), user.Organization, project.Name, version.Name) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) require.Equal(t, http.StatusPreconditionRequired, apiErr.StatusCode()) @@ -91,26 +91,26 @@ func TestProjectVersionParametersByOrganizationAndName(t *testing.T) { t.Run("FailedImport", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _ = coderdtest.NewProvisionerDaemon(t, server.Client) - project := coderdtest.NewProject(t, server.Client, user.Organization) - version := coderdtest.NewProjectVersion(t, server.Client, user.Organization, project.Name, &echo.Responses{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _ = coderdtest.NewProvisionerDaemon(t, client) + project := coderdtest.NewProject(t, client, user.Organization) + version := coderdtest.NewProjectVersion(t, client, user.Organization, project.Name, &echo.Responses{ Provision: []*proto.Provision_Response{{}}, }) - coderdtest.AwaitProjectVersionImported(t, server.Client, user.Organization, project.Name, version.Name) - _, err := server.Client.ProjectVersionParameters(context.Background(), user.Organization, project.Name, version.Name) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + _, err := client.ProjectVersionParameters(context.Background(), user.Organization, project.Name, version.Name) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode()) }) t.Run("List", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _ = coderdtest.NewProvisionerDaemon(t, server.Client) - project := coderdtest.NewProject(t, server.Client, user.Organization) - version := coderdtest.NewProjectVersion(t, server.Client, user.Organization, project.Name, &echo.Responses{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _ = coderdtest.NewProvisionerDaemon(t, client) + project := coderdtest.NewProject(t, client, user.Organization) + version := coderdtest.NewProjectVersion(t, client, user.Organization, project.Name, &echo.Responses{ Parse: []*proto.Parse_Response{{ Type: &proto.Parse_Response_Complete{ Complete: &proto.Parse_Complete{ @@ -121,8 +121,8 @@ func TestProjectVersionParametersByOrganizationAndName(t *testing.T) { }, }}, }) - coderdtest.AwaitProjectVersionImported(t, server.Client, user.Organization, project.Name, version.Name) - params, err := server.Client.ProjectVersionParameters(context.Background(), user.Organization, project.Name, version.Name) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + params, err := client.ProjectVersionParameters(context.Background(), user.Organization, project.Name, version.Name) require.NoError(t, err) require.Len(t, params, 1) }) diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index 69886a6848a40..29d369a46d188 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -221,25 +221,11 @@ func (server *provisionerdServer) AcquireJob(ctx context.Context, _ *proto.Empty protoParameters = append(protoParameters, parameter.Proto) } - provisionerState := []byte{} - // If workspace history exists before this entry, use that state. - // We can't use the before state everytime, because if a job fails - // for some random reason, the workspace shouldn't be reset. - // - // Maybe we should make state global on a workspace? - if workspaceHistory.BeforeID.Valid { - beforeHistory, err := server.Database.GetWorkspaceHistoryByID(ctx, workspaceHistory.BeforeID.UUID) - if err != nil { - return nil, failJob(fmt.Sprintf("get workspace history: %s", err)) - } - provisionerState = beforeHistory.ProvisionerState - } - protoJob.Type = &proto.AcquiredJob_WorkspaceProvision_{ WorkspaceProvision: &proto.AcquiredJob_WorkspaceProvision{ WorkspaceHistoryId: workspaceHistory.ID.String(), WorkspaceName: workspace.Name, - State: provisionerState, + State: workspaceHistory.ProvisionerState, ParameterValues: protoParameters, }, } @@ -286,10 +272,10 @@ func (server *provisionerdServer) UpdateJob(stream proto.DRPCProvisionerDaemon_U return xerrors.Errorf("get job: %w", err) } if !job.WorkerID.Valid { - return errors.New("job isn't running yet") + return xerrors.New("job isn't running yet") } if job.WorkerID.UUID.String() != server.ID.String() { - return errors.New("you don't own this job") + return xerrors.New("you don't own this job") } err = server.Database.UpdateProvisionerJobByID(stream.Context(), database.UpdateProvisionerJobByIDParams{ diff --git a/coderd/provisionerdaemons_test.go b/coderd/provisionerdaemons_test.go index 757d4f3ced7f9..eb5809c65f27b 100644 --- a/coderd/provisionerdaemons_test.go +++ b/coderd/provisionerdaemons_test.go @@ -15,10 +15,10 @@ func TestProvisionerDaemons(t *testing.T) { t.Run("Register", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _ = coderdtest.NewProvisionerDaemon(t, server.Client) + client := coderdtest.New(t) + _ = coderdtest.NewProvisionerDaemon(t, client) require.Eventually(t, func() bool { - daemons, err := server.Client.ProvisionerDaemons(context.Background()) + daemons, err := client.ProvisionerDaemons(context.Background()) require.NoError(t, err) return len(daemons) > 0 }, time.Second, 10*time.Millisecond) diff --git a/coderd/users_test.go b/coderd/users_test.go index 9974f8c9cc9a9..04219ee66a1f1 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -17,17 +17,17 @@ func TestUsers(t *testing.T) { t.Run("Authenticated", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, server.Client) - _, err := server.Client.User(context.Background(), "") + client := coderdtest.New(t) + _ = coderdtest.NewInitialUser(t, client) + _, err := client.User(context.Background(), "") require.NoError(t, err) }) t.Run("CreateMultipleInitial", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, server.Client) - _, err := server.Client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{ + client := coderdtest.New(t) + _ = coderdtest.NewInitialUser(t, client) + _, err := client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{ Email: "dummy@coder.com", Organization: "bananas", Username: "fake", @@ -38,9 +38,9 @@ func TestUsers(t *testing.T) { t.Run("Login", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _, err := server.Client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ Email: user.Email, Password: user.Password, }) @@ -49,8 +49,8 @@ func TestUsers(t *testing.T) { t.Run("LoginInvalidUser", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _, err := server.Client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ + client := coderdtest.New(t) + _, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ Email: "hello@io.io", Password: "wowie", }) @@ -59,9 +59,9 @@ func TestUsers(t *testing.T) { t.Run("LoginBadPassword", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _, err := server.Client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ Email: user.Email, Password: "bananas", }) @@ -70,18 +70,18 @@ func TestUsers(t *testing.T) { t.Run("ListOrganizations", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, server.Client) - orgs, err := server.Client.UserOrganizations(context.Background(), "") + client := coderdtest.New(t) + _ = coderdtest.NewInitialUser(t, client) + orgs, err := client.UserOrganizations(context.Background(), "") require.NoError(t, err) require.Len(t, orgs, 1) }) t.Run("CreateUser", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, server.Client) - _, err := server.Client.CreateUser(context.Background(), coderd.CreateUserRequest{ + client := coderdtest.New(t) + _ = coderdtest.NewInitialUser(t, client) + _, err := client.CreateUser(context.Background(), coderd.CreateUserRequest{ Email: "wow@ok.io", Username: "tomato", Password: "bananas", @@ -91,9 +91,9 @@ func TestUsers(t *testing.T) { t.Run("CreateUserConflict", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _, err := server.Client.CreateUser(context.Background(), coderd.CreateUserRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _, err := client.CreateUser(context.Background(), coderd.CreateUserRequest{ Email: "wow@ok.io", Username: user.Username, Password: "bananas", @@ -108,8 +108,8 @@ func TestLogout(t *testing.T) { t.Run("LogoutShouldClearCookie", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - fullURL, err := server.URL.Parse("/api/v2/logout") + client := coderdtest.New(t) + fullURL, err := client.URL.Parse("/api/v2/logout") require.NoError(t, err, "Server URL should parse successfully") req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, fullURL.String(), nil) diff --git a/coderd/workspacehistory_test.go b/coderd/workspacehistory_test.go index 49a7830f95913..44e27d6bdb6bd 100644 --- a/coderd/workspacehistory_test.go +++ b/coderd/workspacehistory_test.go @@ -15,6 +15,24 @@ import ( "github.com/coder/coder/provisioner/echo" ) +func TestPostWorkspaceHistoryByUser(t *testing.T) { + t.Run("NoVersion", func(t *testing.T) { + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project := coderdtest.NewProject(t, client, user.Organization) + workspace := coderdtest.NewWorkspace(t, client, "me", project.ID) + _, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: uuid.New(), + Transition: database.WorkspaceTransitionCreate, + }) + require.Error(t, err) + }) + + t.Run("Create", func(t *testing.T) { + + }) +} + func TestWorkspaceHistory(t *testing.T) { t.Parallel() @@ -49,56 +67,56 @@ func TestWorkspaceHistory(t *testing.T) { t.Run("AllHistory", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _ = coderdtest.NewProvisionerDaemon(t, server.Client) - project, workspace := setupProjectAndWorkspace(t, server.Client, user) - history, err := server.Client.ListWorkspaceHistory(context.Background(), "", workspace.Name) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _ = coderdtest.NewProvisionerDaemon(t, client) + project, workspace := setupProjectAndWorkspace(t, client, user) + history, err := client.ListWorkspaceHistory(context.Background(), "", workspace.Name) require.NoError(t, err) require.Len(t, history, 0) data, err := echo.Tar(nil) require.NoError(t, err) - projectVersion := setupProjectVersion(t, server.Client, user, project, data) - _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + projectVersion := setupProjectVersion(t, client, user, project, data) + _, err = client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ ProjectVersionID: projectVersion.ID, Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) - history, err = server.Client.ListWorkspaceHistory(context.Background(), "", workspace.Name) + history, err = client.ListWorkspaceHistory(context.Background(), "", workspace.Name) require.NoError(t, err) require.Len(t, history, 1) }) t.Run("LatestHistory", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _ = coderdtest.NewProvisionerDaemon(t, server.Client) - project, workspace := setupProjectAndWorkspace(t, server.Client, user) - _, err := server.Client.WorkspaceHistory(context.Background(), "", workspace.Name, "") + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _ = coderdtest.NewProvisionerDaemon(t, client) + project, workspace := setupProjectAndWorkspace(t, client, user) + _, err := client.WorkspaceHistory(context.Background(), "", workspace.Name, "") require.Error(t, err) data, err := echo.Tar(nil) require.NoError(t, err) - projectVersion := setupProjectVersion(t, server.Client, user, project, data) - _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + projectVersion := setupProjectVersion(t, client, user, project, data) + _, err = client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ ProjectVersionID: projectVersion.ID, Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) - _, err = server.Client.WorkspaceHistory(context.Background(), "", workspace.Name, "") + _, err = client.WorkspaceHistory(context.Background(), "", workspace.Name, "") require.NoError(t, err) }) t.Run("CreateHistory", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _ = coderdtest.NewProvisionerDaemon(t, server.Client) - project, workspace := setupProjectAndWorkspace(t, server.Client, user) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _ = coderdtest.NewProvisionerDaemon(t, client) + project, workspace := setupProjectAndWorkspace(t, client, user) data, err := echo.Tar(nil) require.NoError(t, err) - projectVersion := setupProjectVersion(t, server.Client, user, project, data) - _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + projectVersion := setupProjectVersion(t, client, user, project, data) + _, err = client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ ProjectVersionID: projectVersion.ID, Transition: database.WorkspaceTransitionCreate, }) @@ -106,7 +124,7 @@ func TestWorkspaceHistory(t *testing.T) { var workspaceHistory coderd.WorkspaceHistory require.Eventually(t, func() bool { - workspaceHistory, err = server.Client.WorkspaceHistory(context.Background(), "", workspace.Name, "") + workspaceHistory, err = client.WorkspaceHistory(context.Background(), "", workspace.Name, "") require.NoError(t, err) return workspaceHistory.Provision.Status.Completed() }, 15*time.Second, 50*time.Millisecond) @@ -116,21 +134,21 @@ func TestWorkspaceHistory(t *testing.T) { t.Run("CreateHistoryAlreadyInProgress", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _ = coderdtest.NewProvisionerDaemon(t, server.Client) - project, workspace := setupProjectAndWorkspace(t, server.Client, user) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _ = coderdtest.NewProvisionerDaemon(t, client) + project, workspace := setupProjectAndWorkspace(t, client, user) data, err := echo.Tar(nil) require.NoError(t, err) - projectVersion := setupProjectVersion(t, server.Client, user, project, data) + projectVersion := setupProjectVersion(t, client, user, project, data) - _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + _, err = client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ ProjectVersionID: projectVersion.ID, Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) - _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + _, err = client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ ProjectVersionID: projectVersion.ID, Transition: database.WorkspaceTransitionCreate, }) @@ -139,12 +157,12 @@ func TestWorkspaceHistory(t *testing.T) { t.Run("CreateHistoryInvalidProjectVersion", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _ = coderdtest.NewProvisionerDaemon(t, server.Client) - _, workspace := setupProjectAndWorkspace(t, server.Client, user) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _ = coderdtest.NewProvisionerDaemon(t, client) + _, workspace := setupProjectAndWorkspace(t, client, user) - _, err := server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + _, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ ProjectVersionID: uuid.New(), Transition: database.WorkspaceTransitionCreate, }) diff --git a/coderd/workspacehistorylogs_test.go b/coderd/workspacehistorylogs_test.go index 9719e483a47ff..1d615ae1be246 100644 --- a/coderd/workspacehistorylogs_test.go +++ b/coderd/workspacehistorylogs_test.go @@ -46,10 +46,10 @@ func TestWorkspaceHistoryLogs(t *testing.T) { return projectVersion } - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _ = coderdtest.NewProvisionerDaemon(t, server.Client) - project, workspace := setupProjectAndWorkspace(t, server.Client, user) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _ = coderdtest.NewProvisionerDaemon(t, client) + project, workspace := setupProjectAndWorkspace(t, client, user) data, err := echo.Tar(&echo.Responses{ echo.ParseComplete, []*proto.Provision_Response{{ Type: &proto.Provision_Response_Log{ @@ -64,16 +64,16 @@ func TestWorkspaceHistoryLogs(t *testing.T) { }}, }) require.NoError(t, err) - projectVersion := setupProjectVersion(t, server.Client, user, project, data) + projectVersion := setupProjectVersion(t, client, user, project, data) - workspaceHistory, err := server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + workspaceHistory, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ ProjectVersionID: projectVersion.ID, Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) now := database.Now() - logChan, err := server.Client.FollowWorkspaceHistoryLogsAfter(context.Background(), "", workspace.Name, workspaceHistory.Name, now) + logChan, err := client.FollowWorkspaceHistoryLogsAfter(context.Background(), "", workspace.Name, workspaceHistory.Name, now) require.NoError(t, err) for { @@ -87,14 +87,14 @@ func TestWorkspaceHistoryLogs(t *testing.T) { t.Run("ReturnAll", func(t *testing.T) { t.Parallel() - _, err := server.Client.WorkspaceHistoryLogs(context.Background(), "", workspace.Name, workspaceHistory.Name) + _, err := client.WorkspaceHistoryLogs(context.Background(), "", workspace.Name, workspaceHistory.Name) require.NoError(t, err) }) t.Run("Between", func(t *testing.T) { t.Parallel() - _, err := server.Client.WorkspaceHistoryLogsBetween(context.Background(), "", workspace.Name, workspaceHistory.Name, time.Time{}, database.Now()) + _, err := client.WorkspaceHistoryLogsBetween(context.Background(), "", workspace.Name, workspaceHistory.Name, time.Time{}, database.Now()) require.NoError(t, err) }) } diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 991009bda341c..cf1e45ce5293d 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -18,9 +18,9 @@ func TestWorkspaces(t *testing.T) { t.Run("ListNone", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, server.Client) - workspaces, err := server.Client.WorkspacesByUser(context.Background(), "") + client := coderdtest.New(t) + _ = coderdtest.NewInitialUser(t, client) + workspaces, err := client.WorkspacesByUser(context.Background(), "") require.NoError(t, err) require.Len(t, workspaces, 0) }) @@ -41,48 +41,48 @@ func TestWorkspaces(t *testing.T) { t.Run("List", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _, _ = setupProjectAndWorkspace(t, server.Client, user) - workspaces, err := server.Client.WorkspacesByUser(context.Background(), "") + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _, _ = setupProjectAndWorkspace(t, client, user) + workspaces, err := client.WorkspacesByUser(context.Background(), "") require.NoError(t, err) require.Len(t, workspaces, 1) }) t.Run("ListNoneForProject", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "banana", Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - workspaces, err := server.Client.WorkspacesByProject(context.Background(), user.Organization, project.Name) + workspaces, err := client.WorkspacesByProject(context.Background(), user.Organization, project.Name) require.NoError(t, err) require.Len(t, workspaces, 0) }) t.Run("ListForProject", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project, _ := setupProjectAndWorkspace(t, server.Client, user) - workspaces, err := server.Client.WorkspacesByProject(context.Background(), user.Organization, project.Name) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project, _ := setupProjectAndWorkspace(t, client, user) + workspaces, err := client.WorkspacesByProject(context.Background(), user.Organization, project.Name) require.NoError(t, err) require.Len(t, workspaces, 1) }) t.Run("CreateInvalidInput", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "banana", Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - _, err = server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ + _, err = client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ ProjectID: project.ID, Name: "$$$", }) @@ -91,9 +91,9 @@ func TestWorkspaces(t *testing.T) { t.Run("CreateInvalidProject", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, server.Client) - _, err := server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ + client := coderdtest.New(t) + _ = coderdtest.NewInitialUser(t, client) + _, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ ProjectID: uuid.New(), Name: "moo", }) @@ -102,27 +102,27 @@ func TestWorkspaces(t *testing.T) { t.Run("CreateNotInProjectOrganization", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - initial := coderdtest.NewInitialUser(t, server.Client) - project, err := server.Client.CreateProject(context.Background(), initial.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + initial := coderdtest.NewInitialUser(t, client) + project, err := client.CreateProject(context.Background(), initial.Organization, coderd.CreateProjectRequest{ Name: "banana", Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - _, err = server.Client.CreateUser(context.Background(), coderd.CreateUserRequest{ + _, err = client.CreateUser(context.Background(), coderd.CreateUserRequest{ Email: "hello@ok.io", Username: "example", Password: "password", }) require.NoError(t, err) - token, err := server.Client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ + token, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ Email: "hello@ok.io", Password: "password", }) require.NoError(t, err) - err = server.Client.SetSessionToken(token.SessionToken) + err = client.SetSessionToken(token.SessionToken) require.NoError(t, err) - _, err = server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ + _, err = client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ ProjectID: project.ID, Name: "moo", }) @@ -131,10 +131,10 @@ func TestWorkspaces(t *testing.T) { t.Run("CreateAlreadyExists", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project, workspace := setupProjectAndWorkspace(t, server.Client, user) - _, err := server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project, workspace := setupProjectAndWorkspace(t, client, user) + _, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ Name: workspace.Name, ProjectID: project.ID, }) @@ -143,10 +143,10 @@ func TestWorkspaces(t *testing.T) { t.Run("Single", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _, workspace := setupProjectAndWorkspace(t, server.Client, user) - _, err := server.Client.Workspace(context.Background(), "", workspace.Name) + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _, workspace := setupProjectAndWorkspace(t, client, user) + _, err := client.Workspace(context.Background(), "", workspace.Name) require.NoError(t, err) }) } diff --git a/codersdk/client.go b/codersdk/client.go index 1e688fa7fae6a..e5684f669c809 100644 --- a/codersdk/client.go +++ b/codersdk/client.go @@ -20,14 +20,15 @@ import ( // New creates a Coder client for the provided URL. func New(serverURL *url.URL) *Client { return &Client{ - url: serverURL, + URL: serverURL, httpClient: &http.Client{}, } } // Client is an HTTP caller for methods to the Coder API. type Client struct { - url *url.URL + URL *url.URL + httpClient *http.Client } @@ -40,7 +41,7 @@ func (c *Client) SetSessionToken(token string) error { return err } } - c.httpClient.Jar.SetCookies(c.url, []*http.Cookie{{ + c.httpClient.Jar.SetCookies(c.URL, []*http.Cookie{{ Name: httpmw.AuthCookie, Value: token, }}) @@ -50,7 +51,7 @@ func (c *Client) SetSessionToken(token string) error { // request performs an HTTP request with the body provided. // The caller is responsible for closing the response body. func (c *Client) request(ctx context.Context, method, path string, body interface{}) (*http.Response, error) { - serverURL, err := c.url.Parse(path) + serverURL, err := c.URL.Parse(path) if err != nil { return nil, xerrors.Errorf("parse url: %w", err) } diff --git a/codersdk/projects_test.go b/codersdk/projects_test.go index cdd87f2bde350..9961cca6bf392 100644 --- a/codersdk/projects_test.go +++ b/codersdk/projects_test.go @@ -18,33 +18,33 @@ func TestProjects(t *testing.T) { t.Run("UnauthenticatedList", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _, err := server.Client.Projects(context.Background(), "") + client := coderdtest.New(t) + _, err := client.Projects(context.Background(), "") require.Error(t, err) }) t.Run("List", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _, err := server.Client.Projects(context.Background(), "") + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _, err := client.Projects(context.Background(), "") require.NoError(t, err) - _, err = server.Client.Projects(context.Background(), user.Organization) + _, err = client.Projects(context.Background(), user.Organization) require.NoError(t, err) }) t.Run("UnauthenticatedCreate", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _, err := server.Client.CreateProject(context.Background(), "", coderd.CreateProjectRequest{}) + client := coderdtest.New(t) + _, err := client.CreateProject(context.Background(), "", coderd.CreateProjectRequest{}) require.Error(t, err) }) t.Run("Create", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", Provisioner: database.ProvisionerTypeEcho, }) @@ -53,48 +53,48 @@ func TestProjects(t *testing.T) { t.Run("UnauthenticatedSingle", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _, err := server.Client.Project(context.Background(), "wow", "example") + client := coderdtest.New(t) + _, err := client.Project(context.Background(), "wow", "example") require.Error(t, err) }) t.Run("Single", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - _, err = server.Client.Project(context.Background(), user.Organization, "bananas") + _, err = client.Project(context.Background(), user.Organization, "bananas") require.NoError(t, err) }) t.Run("UnauthenticatedHistory", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _, err := server.Client.ProjectVersions(context.Background(), "org", "project") + client := coderdtest.New(t) + _, err := client.ProjectVersions(context.Background(), "org", "project") require.Error(t, err) }) t.Run("History", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - _, err = server.Client.ProjectVersions(context.Background(), user.Organization, project.Name) + _, err = client.ProjectVersions(context.Background(), user.Organization, project.Name) require.NoError(t, err) }) t.Run("CreateHistoryUnauthenticated", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _, err := server.Client.CreateProjectVersion(context.Background(), "org", "project", coderd.CreateProjectVersionRequest{ + client := coderdtest.New(t) + _, err := client.CreateProjectVersion(context.Background(), "org", "project", coderd.CreateProjectVersionRequest{ StorageMethod: database.ProjectStorageMethodInlineArchive, StorageSource: []byte{}, }) @@ -103,9 +103,9 @@ func TestProjects(t *testing.T) { t.Run("CreateHistory", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", Provisioner: database.ProvisionerTypeEcho, }) @@ -119,26 +119,26 @@ func TestProjects(t *testing.T) { require.NoError(t, err) _, err = writer.Write(make([]byte, 1<<10)) require.NoError(t, err) - version, err := server.Client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ + version, err := client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ StorageMethod: database.ProjectStorageMethodInlineArchive, StorageSource: buffer.Bytes(), }) require.NoError(t, err) - _, err = server.Client.ProjectVersion(context.Background(), user.Organization, project.Name, version.Name) + _, err = client.ProjectVersion(context.Background(), user.Organization, project.Name, version.Name) require.NoError(t, err) }) t.Run("Parameters", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - params, err := server.Client.ProjectParameters(context.Background(), user.Organization, project.Name) + params, err := client.ProjectParameters(context.Background(), user.Organization, project.Name) require.NoError(t, err) require.NotNil(t, params) require.Len(t, params, 0) @@ -146,14 +146,14 @@ func TestProjects(t *testing.T) { t.Run("CreateParameter", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - param, err := server.Client.CreateProjectParameter(context.Background(), user.Organization, project.Name, coderd.CreateParameterValueRequest{ + param, err := client.CreateProjectParameter(context.Background(), user.Organization, project.Name, coderd.CreateParameterValueRequest{ Name: "hi", SourceValue: "tomato", SourceScheme: database.ParameterSourceSchemeData, @@ -166,9 +166,9 @@ func TestProjects(t *testing.T) { t.Run("HistoryParametersError", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - _, err := server.Client.ProjectVersionParameters(context.Background(), user.Organization, "nothing", "nope") + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + _, err := client.ProjectVersionParameters(context.Background(), user.Organization, "nothing", "nope") require.Error(t, err) }) } diff --git a/codersdk/provisioners.go b/codersdk/provisioners.go index cfc908a7d39b3..3ebfaa148fdf4 100644 --- a/codersdk/provisioners.go +++ b/codersdk/provisioners.go @@ -29,7 +29,7 @@ func (c *Client) ProvisionerDaemons(ctx context.Context) ([]coderd.ProvisionerDa // ProvisionerDaemonClient returns the gRPC service for a provisioner daemon implementation. func (c *Client) ProvisionerDaemonClient(ctx context.Context) (proto.DRPCProvisionerDaemonClient, error) { - serverURL, err := c.url.Parse("/api/v2/provisioners/daemons/serve") + serverURL, err := c.URL.Parse("/api/v2/provisioners/daemons/serve") if err != nil { return nil, xerrors.Errorf("parse url: %w", err) } diff --git a/codersdk/users_test.go b/codersdk/users_test.go index 33ef6c09e12e5..0704e0ab51618 100644 --- a/codersdk/users_test.go +++ b/codersdk/users_test.go @@ -14,8 +14,8 @@ func TestUsers(t *testing.T) { t.Parallel() t.Run("CreateInitial", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _, err := server.Client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{ + client := coderdtest.New(t) + _, err := client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{ Email: "wowie@coder.com", Organization: "somethin", Username: "tester", @@ -26,41 +26,41 @@ func TestUsers(t *testing.T) { t.Run("NoUser", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _, err := server.Client.User(context.Background(), "") + client := coderdtest.New(t) + _, err := client.User(context.Background(), "") require.Error(t, err) }) t.Run("User", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, server.Client) - _, err := server.Client.User(context.Background(), "") + client := coderdtest.New(t) + _ = coderdtest.NewInitialUser(t, client) + _, err := client.User(context.Background(), "") require.NoError(t, err) }) t.Run("UserOrganizations", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, server.Client) - orgs, err := server.Client.UserOrganizations(context.Background(), "") + client := coderdtest.New(t) + _ = coderdtest.NewInitialUser(t, client) + orgs, err := client.UserOrganizations(context.Background(), "") require.NoError(t, err) require.Len(t, orgs, 1) }) t.Run("LogoutIsSuccessful", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, server.Client) - err := server.Client.Logout(context.Background()) + client := coderdtest.New(t) + _ = coderdtest.NewInitialUser(t, client) + err := client.Logout(context.Background()) require.NoError(t, err) }) t.Run("CreateMultiple", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, server.Client) - _, err := server.Client.CreateUser(context.Background(), coderd.CreateUserRequest{ + client := coderdtest.New(t) + _ = coderdtest.NewInitialUser(t, client) + _, err := client.CreateUser(context.Background(), coderd.CreateUserRequest{ Email: "wow@ok.io", Username: "example", Password: "tomato", diff --git a/codersdk/workspaces_test.go b/codersdk/workspaces_test.go index 4f781e9f794bd..67712a275ea4a 100644 --- a/codersdk/workspaces_test.go +++ b/codersdk/workspaces_test.go @@ -16,151 +16,151 @@ func TestWorkspaces(t *testing.T) { t.Parallel() t.Run("ListError", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _, err := server.Client.WorkspacesByUser(context.Background(), "") + client := coderdtest.New(t) + _, err := client.WorkspacesByUser(context.Background(), "") require.Error(t, err) }) t.Run("ListNoOwner", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _, err := server.Client.WorkspacesByUser(context.Background(), "") + client := coderdtest.New(t) + _, err := client.WorkspacesByUser(context.Background(), "") require.Error(t, err) }) t.Run("ListByUser", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - _, err = server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ + _, err = client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ Name: "wow", ProjectID: project.ID, }) require.NoError(t, err) - _, err = server.Client.WorkspacesByUser(context.Background(), "me") + _, err = client.WorkspacesByUser(context.Background(), "me") require.NoError(t, err) }) t.Run("ListByProject", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - _, err = server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ + _, err = client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ Name: "wow", ProjectID: project.ID, }) require.NoError(t, err) - _, err = server.Client.WorkspacesByProject(context.Background(), user.Organization, project.Name) + _, err = client.WorkspacesByProject(context.Background(), user.Organization, project.Name) require.NoError(t, err) }) t.Run("ListByProjectError", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _, err := server.Client.WorkspacesByProject(context.Background(), "", "") + client := coderdtest.New(t) + _, err := client.WorkspacesByProject(context.Background(), "", "") require.Error(t, err) }) t.Run("CreateError", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _, err := server.Client.CreateWorkspace(context.Background(), "no", coderd.CreateWorkspaceRequest{}) + client := coderdtest.New(t) + _, err := client.CreateWorkspace(context.Background(), "no", coderd.CreateWorkspaceRequest{}) require.Error(t, err) }) t.Run("Single", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - workspace, err := server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ + workspace, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ Name: "wow", ProjectID: project.ID, }) require.NoError(t, err) - _, err = server.Client.Workspace(context.Background(), "", workspace.Name) + _, err = client.Workspace(context.Background(), "", workspace.Name) require.NoError(t, err) }) t.Run("SingleError", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _, err := server.Client.Workspace(context.Background(), "", "blob") + client := coderdtest.New(t) + _, err := client.Workspace(context.Background(), "", "blob") require.Error(t, err) }) t.Run("History", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - workspace, err := server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ + workspace, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ Name: "wow", ProjectID: project.ID, }) require.NoError(t, err) - _, err = server.Client.ListWorkspaceHistory(context.Background(), "", workspace.Name) + _, err = client.ListWorkspaceHistory(context.Background(), "", workspace.Name) require.NoError(t, err) }) t.Run("HistoryError", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - _, err := server.Client.ListWorkspaceHistory(context.Background(), "", "blob") + client := coderdtest.New(t) + _, err := client.ListWorkspaceHistory(context.Background(), "", "blob") require.Error(t, err) }) t.Run("LatestHistory", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - workspace, err := server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ + workspace, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ Name: "wow", ProjectID: project.ID, }) require.NoError(t, err) - _, err = server.Client.WorkspaceHistory(context.Background(), "", workspace.Name, "") + _, err = client.WorkspaceHistory(context.Background(), "", workspace.Name, "") require.Error(t, err) }) t.Run("CreateHistory", func(t *testing.T) { t.Parallel() - server := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, server.Client) - project, err := server.Client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ + client := coderdtest.New(t) + user := coderdtest.NewInitialUser(t, client) + project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, }) require.NoError(t, err) - workspace, err := server.Client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ + workspace, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ Name: "wow", ProjectID: project.ID, }) require.NoError(t, err) - _, err = server.Client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + _, err = client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ ProjectVersionID: uuid.New(), Transition: database.WorkspaceTransitionCreate, }) diff --git a/provisioner/echo/serve.go b/provisioner/echo/serve.go index ac7c2ea3e39b0..8dc48b96cf28f 100644 --- a/provisioner/echo/serve.go +++ b/provisioner/echo/serve.go @@ -4,7 +4,6 @@ import ( "archive/tar" "bytes" "context" - "errors" "fmt" "os" "path/filepath" @@ -51,7 +50,7 @@ func (*echo) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_Pa if err != nil { if index == 0 { // Error if nothing is around to enable failed states. - return errors.New("no state") + return xerrors.New("no state") } break } @@ -80,7 +79,7 @@ func (*echo) Provision(request *proto.Provision_Request, stream proto.DRPCProvis if err != nil { if index == 0 { // Error if nothing is around to enable failed states. - return errors.New("no state") + return xerrors.New("no state") } break } diff --git a/rules.go b/rules.go new file mode 100644 index 0000000000000..d8b7db0844720 --- /dev/null +++ b/rules.go @@ -0,0 +1,23 @@ +package gorules + +import ( + "github.com/quasilyte/go-ruleguard/dsl" +) + +// Use xerrors everywhere! It provides additional stacktrace info! +//nolint:unused,deadcode,varnamelen +func xerrors(m dsl.Matcher) { + m.Import("errors") + m.Import("fmt") + m.Import("golang.org/x/xerrors") + + m.Match("fmt.Errorf($*args)"). + Suggest("xerrors.New($args)") + + m.Match("fmt.Errorf($*args)"). + Suggest("xerrors.Errorf($args)") + + m.Match("errors.New($msg)"). + Where(m["msg"].Type.Is("string")). + Suggest("xerrors.New($msg)") +} From be3e6ac696d5438a00d58f9f132c7dc008bb8289 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 08:01:22 +0000 Subject: [PATCH 05/16] Improve test coverage for workspace history --- coderd/coderdtest/coderdtest.go | 81 +++++----- coderd/coderdtest/coderdtest_test.go | 2 +- coderd/projects_test.go | 32 ++-- coderd/projectversion_test.go | 44 +++--- coderd/provisioners.go | 2 +- coderd/users.go | 4 + coderd/users_test.go | 135 ++++++++++------ coderd/workspacehistory.go | 23 +-- coderd/workspacehistory_test.go | 220 +++++++++++++-------------- coderd/workspacehistorylogs_test.go | 2 +- coderd/workspaces_test.go | 18 +-- codersdk/projects_test.go | 16 +- codersdk/users_test.go | 8 +- codersdk/workspaces_test.go | 12 +- 14 files changed, 322 insertions(+), 277 deletions(-) diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 3ed3ef29add93..38fb0ab9738a2 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -3,6 +3,7 @@ package coderdtest import ( "context" "database/sql" + "fmt" "io" "net/http/httptest" "net/url" @@ -67,37 +68,6 @@ func New(t *testing.T) *codersdk.Client { return codersdk.New(serverURL) } -// Server represents a test instance of coderd. -// The database is intentionally omitted from -// this struct to promote data being exposed via -// the API. -type Server struct { - Client *codersdk.Client - URL *url.URL -} - -// NewInitialUser creates a user with preset credentials and authenticates -// with the passed in codersdk client. -func NewInitialUser(t *testing.T, client *codersdk.Client) coderd.CreateInitialUserRequest { - req := coderd.CreateInitialUserRequest{ - Email: "testuser@coder.com", - Username: "testuser", - Password: "testpass", - Organization: "testorg", - } - _, err := client.CreateInitialUser(context.Background(), req) - require.NoError(t, err) - - login, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ - Email: req.Email, - Password: req.Password, - }) - require.NoError(t, err) - err = client.SetSessionToken(login.SessionToken) - require.NoError(t, err) - return req -} - // NewProvisionerDaemon launches a provisionerd instance configured to work // well with coderd testing. It registers the "echo" provisioner for // quick testing. @@ -131,9 +101,31 @@ func NewProvisionerDaemon(t *testing.T, client *codersdk.Client) io.Closer { return closer } -// NewProject creates a project with the "echo" provisioner for +// CreateInitialUser creates a user with preset credentials and authenticates +// with the passed in codersdk client. +func CreateInitialUser(t *testing.T, client *codersdk.Client) coderd.CreateInitialUserRequest { + req := coderd.CreateInitialUserRequest{ + Email: "testuser@coder.com", + Username: "testuser", + Password: "testpass", + Organization: "testorg", + } + _, err := client.CreateInitialUser(context.Background(), req) + require.NoError(t, err) + + login, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ + Email: req.Email, + Password: req.Password, + }) + require.NoError(t, err) + err = client.SetSessionToken(login.SessionToken) + require.NoError(t, err) + return req +} + +// CreateProject creates a project with the "echo" provisioner for // compatibility with testing. The name assigned is randomly generated. -func NewProject(t *testing.T, client *codersdk.Client, organization string) coderd.Project { +func CreateProject(t *testing.T, client *codersdk.Client, organization string) coderd.Project { project, err := client.CreateProject(context.Background(), organization, coderd.CreateProjectRequest{ Name: randomUsername(), Provisioner: database.ProvisionerTypeEcho, @@ -142,9 +134,9 @@ func NewProject(t *testing.T, client *codersdk.Client, organization string) code return project } -// NewProjectVersion creates a project version for the "echo" provisioner +// CreateProjectVersion creates a project version for the "echo" provisioner // for compatibility with testing. -func NewProjectVersion(t *testing.T, client *codersdk.Client, organization, project string, responses *echo.Responses) coderd.ProjectVersion { +func CreateProjectVersion(t *testing.T, client *codersdk.Client, organization, project string, responses *echo.Responses) coderd.ProjectVersion { data, err := echo.Tar(responses) require.NoError(t, err) version, err := client.CreateProjectVersion(context.Background(), organization, project, coderd.CreateProjectVersionRequest{ @@ -162,14 +154,15 @@ func AwaitProjectVersionImported(t *testing.T, client *codersdk.Client, organiza var err error projectVersion, err = client.ProjectVersion(context.Background(), organization, project, version) require.NoError(t, err) + fmt.Printf("GOT: %s\n", projectVersion.Import.Status) return projectVersion.Import.Status.Completed() - }, 3*time.Second, 50*time.Millisecond) + }, 3*time.Second, 25*time.Millisecond) return projectVersion } -// NewWorkspace creates a workspace for the user and project provided. +// CreateWorkspace creates a workspace for the user and project provided. // A random name is generated for it. -func NewWorkspace(t *testing.T, client *codersdk.Client, user string, projectID uuid.UUID) coderd.Workspace { +func CreateWorkspace(t *testing.T, client *codersdk.Client, user string, projectID uuid.UUID) coderd.Workspace { workspace, err := client.CreateWorkspace(context.Background(), user, coderd.CreateWorkspaceRequest{ ProjectID: projectID, Name: randomUsername(), @@ -178,6 +171,18 @@ func NewWorkspace(t *testing.T, client *codersdk.Client, user string, projectID return workspace } +// AwaitWorkspaceHistoryProvisioned awaits for the workspace provision job to reach completed status. +func AwaitWorkspaceHistoryProvisioned(t *testing.T, client *codersdk.Client, user, workspace, history string) coderd.WorkspaceHistory { + var workspaceHistory coderd.WorkspaceHistory + require.Eventually(t, func() bool { + var err error + workspaceHistory, err = client.WorkspaceHistory(context.Background(), user, workspace, history) + require.NoError(t, err) + return workspaceHistory.Provision.Status.Completed() + }, 3*time.Second, 25*time.Millisecond) + return workspaceHistory +} + func randomUsername() string { return strings.ReplaceAll(namesgenerator.GetRandomName(0), "_", "-") } diff --git a/coderd/coderdtest/coderdtest_test.go b/coderd/coderdtest/coderdtest_test.go index c7c6fac010fa1..f880c8fc3a984 100644 --- a/coderd/coderdtest/coderdtest_test.go +++ b/coderd/coderdtest/coderdtest_test.go @@ -15,6 +15,6 @@ func TestMain(m *testing.M) { func TestNew(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, client) + _ = coderdtest.CreateInitialUser(t, client) _ = coderdtest.NewProvisionerDaemon(t, client) } diff --git a/coderd/projects_test.go b/coderd/projects_test.go index 83a7f91b641f5..7f68182f95d26 100644 --- a/coderd/projects_test.go +++ b/coderd/projects_test.go @@ -19,7 +19,7 @@ func TestProjects(t *testing.T) { t.Run("ListEmpty", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, client) + _ = coderdtest.CreateInitialUser(t, client) projects, err := client.Projects(context.Background(), "") require.NoError(t, err) require.NotNil(t, projects) @@ -29,8 +29,8 @@ func TestProjects(t *testing.T) { t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - _ = coderdtest.NewProject(t, client, user.Organization) + user := coderdtest.CreateInitialUser(t, client) + _ = coderdtest.CreateProject(t, client, user.Organization) projects, err := client.Projects(context.Background(), "") require.NoError(t, err) require.Len(t, projects, 1) @@ -42,7 +42,7 @@ func TestProjectsByOrganization(t *testing.T) { t.Run("ListEmpty", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) projects, err := client.Projects(context.Background(), user.Organization) require.NoError(t, err) require.NotNil(t, projects) @@ -52,8 +52,8 @@ func TestProjectsByOrganization(t *testing.T) { t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - _ = coderdtest.NewProject(t, client, user.Organization) + user := coderdtest.CreateInitialUser(t, client) + _ = coderdtest.CreateProject(t, client, user.Organization) projects, err := client.Projects(context.Background(), "") require.NoError(t, err) require.Len(t, projects, 1) @@ -65,15 +65,15 @@ func TestPostProjectsByOrganization(t *testing.T) { t.Run("Create", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - _ = coderdtest.NewProject(t, client, user.Organization) + user := coderdtest.CreateInitialUser(t, client) + _ = coderdtest.CreateProject(t, client, user.Organization) }) t.Run("AlreadyExists", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - project := coderdtest.NewProject(t, client, user.Organization) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) _, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: project.Name, Provisioner: database.ProvisionerTypeEcho, @@ -89,8 +89,8 @@ func TestProjectByOrganization(t *testing.T) { t.Run("Get", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - project := coderdtest.NewProject(t, client, user.Organization) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) _, err := client.Project(context.Background(), user.Organization, project.Name) require.NoError(t, err) }) @@ -101,8 +101,8 @@ func TestPostParametersByProject(t *testing.T) { t.Run("Create", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - project := coderdtest.NewProject(t, client, user.Organization) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) _, err := client.CreateProjectParameter(context.Background(), user.Organization, project.Name, coderd.CreateParameterValueRequest{ Name: "somename", SourceValue: "tomato", @@ -119,8 +119,8 @@ func TestParametersByProject(t *testing.T) { t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - project := coderdtest.NewProject(t, client, user.Organization) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) params, err := client.ProjectParameters(context.Background(), user.Organization, project.Name) require.NoError(t, err) require.NotNil(t, params) diff --git a/coderd/projectversion_test.go b/coderd/projectversion_test.go index c03263f0f7972..50fe0e4fd0227 100644 --- a/coderd/projectversion_test.go +++ b/coderd/projectversion_test.go @@ -20,8 +20,8 @@ func TestProjectVersionsByOrganization(t *testing.T) { t.Run("ListEmpty", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - project := coderdtest.NewProject(t, client, user.Organization) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) versions, err := client.ProjectVersions(context.Background(), user.Organization, project.Name) require.NoError(t, err) require.NotNil(t, versions) @@ -31,9 +31,9 @@ func TestProjectVersionsByOrganization(t *testing.T) { t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - project := coderdtest.NewProject(t, client, user.Organization) - _ = coderdtest.NewProjectVersion(t, client, user.Organization, project.Name, nil) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + _ = coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) versions, err := client.ProjectVersions(context.Background(), user.Organization, project.Name) require.NoError(t, err) require.Len(t, versions, 1) @@ -45,9 +45,9 @@ func TestProjectVersionByOrganizationAndName(t *testing.T) { t.Run("Get", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - project := coderdtest.NewProject(t, client, user.Organization) - version := coderdtest.NewProjectVersion(t, client, user.Organization, project.Name, nil) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) require.Equal(t, version.Import.Status, coderd.ProvisionerJobStatusPending) }) } @@ -57,16 +57,16 @@ func TestPostProjectVersionByOrganization(t *testing.T) { t.Run("Create", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - project := coderdtest.NewProject(t, client, user.Organization) - _ = coderdtest.NewProjectVersion(t, client, user.Organization, project.Name, nil) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + _ = coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) }) t.Run("InvalidStorage", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - project := coderdtest.NewProject(t, client, user.Organization) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) _, err := client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ StorageMethod: database.ProjectStorageMethod("invalid"), StorageSource: []byte{}, @@ -80,9 +80,9 @@ func TestProjectVersionParametersByOrganizationAndName(t *testing.T) { t.Run("NotImported", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - project := coderdtest.NewProject(t, client, user.Organization) - version := coderdtest.NewProjectVersion(t, client, user.Organization, project.Name, nil) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) _, err := client.ProjectVersionParameters(context.Background(), user.Organization, project.Name, version.Name) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) @@ -92,10 +92,10 @@ func TestProjectVersionParametersByOrganizationAndName(t *testing.T) { t.Run("FailedImport", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) _ = coderdtest.NewProvisionerDaemon(t, client) - project := coderdtest.NewProject(t, client, user.Organization) - version := coderdtest.NewProjectVersion(t, client, user.Organization, project.Name, &echo.Responses{ + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, &echo.Responses{ Provision: []*proto.Provision_Response{{}}, }) coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) @@ -107,10 +107,10 @@ func TestProjectVersionParametersByOrganizationAndName(t *testing.T) { t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) _ = coderdtest.NewProvisionerDaemon(t, client) - project := coderdtest.NewProject(t, client, user.Organization) - version := coderdtest.NewProjectVersion(t, client, user.Organization, project.Name, &echo.Responses{ + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, &echo.Responses{ Parse: []*proto.Parse_Response{{ Type: &proto.Parse_Response_Complete{ Complete: &proto.Parse_Complete{ diff --git a/coderd/provisioners.go b/coderd/provisioners.go index 959e69b565801..f2cd46eb4b763 100644 --- a/coderd/provisioners.go +++ b/coderd/provisioners.go @@ -70,7 +70,7 @@ func convertProvisionerJob(provisionerJob database.ProvisionerJob) ProvisionerJo job.Status = ProvisionerJobStatusRunning } - if job.Error != "" { + if !provisionerJob.CancelledAt.Valid && job.Error != "" { job.Status = ProvisionerJobStatusFailed } diff --git a/coderd/users.go b/coderd/users.go index 8aafc1f1bd9e0..0644a78d01aff 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -195,6 +195,10 @@ func (api *api) organizationsByUser(rw http.ResponseWriter, r *http.Request) { user := httpmw.UserParam(r) organizations, err := api.Database.GetOrganizationsByUserID(r.Context(), user.ID) + if errors.Is(err, sql.ErrNoRows) { + err = nil + organizations = []database.Organization{} + } if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ Message: fmt.Sprintf("get organizations: %s", err.Error()), diff --git a/coderd/users_test.go b/coderd/users_test.go index 04219ee66a1f1..0aafb0bc09cb1 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -9,103 +9,138 @@ import ( "github.com/coder/coder/coderd" "github.com/coder/coder/coderd/coderdtest" + "github.com/coder/coder/codersdk" "github.com/coder/coder/httpmw" ) -func TestUsers(t *testing.T) { +func TestPostUser(t *testing.T) { t.Parallel() - - t.Run("Authenticated", func(t *testing.T) { + t.Run("BadRequest", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, client) - _, err := client.User(context.Background(), "") - require.NoError(t, err) + _, err := client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{}) + require.Error(t, err) }) - t.Run("CreateMultipleInitial", func(t *testing.T) { + t.Run("AlreadyExists", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, client) + _ = coderdtest.CreateInitialUser(t, client) _, err := client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{ - Email: "dummy@coder.com", - Organization: "bananas", - Username: "fake", + Email: "some@email.com", + Username: "exampleuser", Password: "password", + Organization: "someorg", }) - require.Error(t, err) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusConflict, apiErr.StatusCode()) }) - t.Run("Login", func(t *testing.T) { + t.Run("Create", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - _, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ - Email: user.Email, - Password: user.Password, - }) - require.NoError(t, err) + _ = coderdtest.CreateInitialUser(t, client) }) +} - t.Run("LoginInvalidUser", func(t *testing.T) { +func TestPostUsers(t *testing.T) { + t.Run("BadRequest", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ - Email: "hello@io.io", - Password: "wowie", - }) + _, err := client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{}) require.Error(t, err) }) - t.Run("LoginBadPassword", func(t *testing.T) { + t.Run("Conflicting", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - _, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ - Email: user.Email, - Password: "bananas", + user := coderdtest.CreateInitialUser(t, client) + _, err := client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{ + Email: user.Email, + Username: user.Username, + Password: "password", + Organization: "someorg", }) - require.Error(t, err) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusConflict, apiErr.StatusCode()) }) - t.Run("ListOrganizations", func(t *testing.T) { + t.Run("Create", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, client) - orgs, err := client.UserOrganizations(context.Background(), "") + _ = coderdtest.CreateInitialUser(t, client) + _, err := client.CreateUser(context.Background(), coderd.CreateUserRequest{ + Email: "another@user.org", + Username: "someone-else", + Password: "testing", + }) require.NoError(t, err) - require.Len(t, orgs, 1) }) +} - t.Run("CreateUser", func(t *testing.T) { +func TestUserByName(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + _ = coderdtest.CreateInitialUser(t, client) + _, err := client.User(context.Background(), "") + require.NoError(t, err) +} + +func TestOrganizationsByUser(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + _ = coderdtest.CreateInitialUser(t, client) + orgs, err := client.UserOrganizations(context.Background(), "") + require.NoError(t, err) + require.NotNil(t, orgs) + require.Len(t, orgs, 1) +} + +func TestPostLogin(t *testing.T) { + t.Parallel() + t.Run("InvalidUser", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, client) - _, err := client.CreateUser(context.Background(), coderd.CreateUserRequest{ - Email: "wow@ok.io", - Username: "tomato", - Password: "bananas", + _, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ + Email: "my@email.org", + Password: "password", }) - require.NoError(t, err) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusUnauthorized, apiErr.StatusCode()) }) - t.Run("CreateUserConflict", func(t *testing.T) { + t.Run("BadPassword", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - _, err := client.CreateUser(context.Background(), coderd.CreateUserRequest{ - Email: "wow@ok.io", - Username: user.Username, - Password: "bananas", + user := coderdtest.CreateInitialUser(t, client) + _, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ + Email: user.Email, + Password: "badpass", }) - require.Error(t, err) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusUnauthorized, apiErr.StatusCode()) + }) + + t.Run("Success", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + user := coderdtest.CreateInitialUser(t, client) + _, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ + Email: user.Email, + Password: user.Password, + }) + require.NoError(t, err) }) } -func TestLogout(t *testing.T) { +func TestPostLogout(t *testing.T) { t.Parallel() - t.Run("LogoutShouldClearCookie", func(t *testing.T) { + t.Run("ClearCookie", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) diff --git a/coderd/workspacehistory.go b/coderd/workspacehistory.go index 8ebdee7df1702..d8f4354f6cdb7 100644 --- a/coderd/workspacehistory.go +++ b/coderd/workspacehistory.go @@ -74,12 +74,12 @@ func (api *api) postWorkspaceHistoryByUser(rw http.ResponseWriter, r *http.Reque projectVersionJobStatus := convertProvisionerJob(projectVersionJob).Status switch projectVersionJobStatus { case ProvisionerJobStatusPending, ProvisionerJobStatusRunning: - httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{ + httpapi.Write(rw, http.StatusNotAcceptable, httpapi.Response{ Message: fmt.Sprintf("The provided project version is %s. Wait for it to complete importing!", projectVersionJobStatus), }) return case ProvisionerJobStatusFailed: - httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ + httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{ Message: fmt.Sprintf("The provided project version %q has failed to import. You cannot create workspaces using it!", projectVersion.Name), }) return @@ -87,6 +87,7 @@ func (api *api) postWorkspaceHistoryByUser(rw http.ResponseWriter, r *http.Reque httpapi.Write(rw, http.StatusPreconditionFailed, httpapi.Response{ Message: "The provided project version was canceled during import. You cannot create workspaces using it!", }) + return } project, err := api.Database.GetProjectByID(r.Context(), projectVersion.ProjectID) @@ -102,7 +103,7 @@ func (api *api) postWorkspaceHistoryByUser(rw http.ResponseWriter, r *http.Reque priorHistory, err := api.Database.GetWorkspaceHistoryByWorkspaceIDWithoutAfter(r.Context(), workspace.ID) if err == nil { priorJob, err := api.Database.GetProvisionerJobByID(r.Context(), priorHistory.ProvisionJobID) - if err == nil && convertProvisionerJob(priorJob).Status.Completed() { + if err == nil && !convertProvisionerJob(priorJob).Status.Completed() { httpapi.Write(rw, http.StatusConflict, httpapi.Response{ Message: "a workspace build is already active", }) @@ -113,8 +114,7 @@ func (api *api) postWorkspaceHistoryByUser(rw http.ResponseWriter, r *http.Reque UUID: priorHistory.ID, Valid: true, } - } - if !errors.Is(err, sql.ErrNoRows) { + } else if !errors.Is(err, sql.ErrNoRows) { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ Message: fmt.Sprintf("get prior workspace history: %s", err), }) @@ -168,8 +168,9 @@ func (api *api) postWorkspaceHistoryByUser(rw http.ResponseWriter, r *http.Reque if priorHistoryID.Valid { // Update the prior history entries "after" column. err = db.UpdateWorkspaceHistoryByID(r.Context(), database.UpdateWorkspaceHistoryByIDParams{ - ID: priorHistory.ID, - UpdatedAt: database.Now(), + ID: priorHistory.ID, + ProvisionerState: priorHistory.ProvisionerState, + UpdatedAt: database.Now(), AfterID: uuid.NullUUID{ UUID: workspaceHistory.ID, Valid: true, @@ -178,6 +179,7 @@ func (api *api) postWorkspaceHistoryByUser(rw http.ResponseWriter, r *http.Reque if err != nil { return xerrors.Errorf("update prior workspace history: %w", err) } + fmt.Printf("Updated %s to %s\n", priorHistory.ID, workspaceHistory.ID) } return nil @@ -197,9 +199,10 @@ func (api *api) postWorkspaceHistoryByUser(rw http.ResponseWriter, r *http.Reque func (api *api) workspaceHistoryByUser(rw http.ResponseWriter, r *http.Request) { workspace := httpmw.WorkspaceParam(r) - histories, err := api.Database.GetWorkspaceHistoryByWorkspaceID(r.Context(), workspace.ID) + history, err := api.Database.GetWorkspaceHistoryByWorkspaceID(r.Context(), workspace.ID) if errors.Is(err, sql.ErrNoRows) { err = nil + history = []database.WorkspaceHistory{} } if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ @@ -208,8 +211,8 @@ func (api *api) workspaceHistoryByUser(rw http.ResponseWriter, r *http.Request) return } - apiHistory := make([]WorkspaceHistory, 0, len(histories)) - for _, history := range histories { + apiHistory := make([]WorkspaceHistory, 0, len(history)) + for _, history := range history { job, err := api.Database.GetProvisionerJobByID(r.Context(), history.ProvisionJobID) if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ diff --git a/coderd/workspacehistory_test.go b/coderd/workspacehistory_test.go index 44e27d6bdb6bd..8e1e7a9fb3b2b 100644 --- a/coderd/workspacehistory_test.go +++ b/coderd/workspacehistory_test.go @@ -2,8 +2,8 @@ package coderd_test import ( "context" + "net/http" "testing" - "time" "github.com/google/uuid" "github.com/stretchr/testify/require" @@ -13,159 +13,157 @@ import ( "github.com/coder/coder/codersdk" "github.com/coder/coder/database" "github.com/coder/coder/provisioner/echo" + "github.com/coder/coder/provisionersdk/proto" ) func TestPostWorkspaceHistoryByUser(t *testing.T) { - t.Run("NoVersion", func(t *testing.T) { + t.Run("NoProjectVersion", func(t *testing.T) { client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - project := coderdtest.NewProject(t, client, user.Organization) - workspace := coderdtest.NewWorkspace(t, client, "me", project.ID) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) _, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ ProjectVersionID: uuid.New(), Transition: database.WorkspaceTransitionCreate, }) - require.Error(t, err) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusBadRequest, apiErr.StatusCode()) }) - t.Run("Create", func(t *testing.T) { - - }) -} - -func TestWorkspaceHistory(t *testing.T) { - t.Parallel() - - setupProjectAndWorkspace := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest) (coderd.Project, coderd.Workspace) { - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "banana", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - workspace, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "example", - ProjectID: project.ID, + t.Run("ProjectVersionImporting", func(t *testing.T) { + client := coderdtest.New(t) + coderdtest.NewProvisionerDaemon(t, client) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, &echo.Responses{ + Provision: []*proto.Provision_Response{{}}, }) - require.NoError(t, err) - return project, workspace - } - - setupProjectVersion := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest, project coderd.Project, data []byte) coderd.ProjectVersion { - projectVersion, err := client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ - StorageMethod: database.ProjectStorageMethodInlineArchive, - StorageSource: data, + _, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, + Transition: database.WorkspaceTransitionCreate, }) - require.NoError(t, err) - require.Eventually(t, func() bool { - version, err := client.ProjectVersion(context.Background(), user.Organization, project.Name, projectVersion.Name) - require.NoError(t, err) - t.Logf("Import status: %s\n", version.Import.Status) - return version.Import.Status.Completed() - }, 15*time.Second, 50*time.Millisecond) - return projectVersion - } + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusNotAcceptable, apiErr.StatusCode()) + }) - t.Run("AllHistory", func(t *testing.T) { - t.Parallel() + t.Run("ProjectVersionFailedImport", func(t *testing.T) { client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - _ = coderdtest.NewProvisionerDaemon(t, client) - project, workspace := setupProjectAndWorkspace(t, client, user) - history, err := client.ListWorkspaceHistory(context.Background(), "", workspace.Name) - require.NoError(t, err) - require.Len(t, history, 0) - data, err := echo.Tar(nil) - require.NoError(t, err) - projectVersion := setupProjectVersion(t, client, user, project, data) - _, err = client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectVersionID: projectVersion.ID, + coderdtest.NewProvisionerDaemon(t, client) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, &echo.Responses{ + Provision: []*proto.Provision_Response{{}}, + }) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) + _, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, Transition: database.WorkspaceTransitionCreate, }) - require.NoError(t, err) - history, err = client.ListWorkspaceHistory(context.Background(), "", workspace.Name) - require.NoError(t, err) - require.Len(t, history, 1) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusPreconditionFailed, apiErr.StatusCode()) }) - t.Run("LatestHistory", func(t *testing.T) { - t.Parallel() + t.Run("AlreadyActive", func(t *testing.T) { client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - _ = coderdtest.NewProvisionerDaemon(t, client) - project, workspace := setupProjectAndWorkspace(t, client, user) - _, err := client.WorkspaceHistory(context.Background(), "", workspace.Name, "") - require.Error(t, err) - data, err := echo.Tar(nil) + coderdtest.NewProvisionerDaemon(t, client) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) + _, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, + Transition: database.WorkspaceTransitionCreate, + }) require.NoError(t, err) - projectVersion := setupProjectVersion(t, client, user, project, data) _, err = client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectVersionID: projectVersion.ID, + ProjectVersionID: version.ID, Transition: database.WorkspaceTransitionCreate, }) - require.NoError(t, err) - _, err = client.WorkspaceHistory(context.Background(), "", workspace.Name, "") - require.NoError(t, err) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusConflict, apiErr.StatusCode()) }) - t.Run("CreateHistory", func(t *testing.T) { - t.Parallel() + t.Run("UpdatePriorAfterField", func(t *testing.T) { client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - _ = coderdtest.NewProvisionerDaemon(t, client) - project, workspace := setupProjectAndWorkspace(t, client, user) - data, err := echo.Tar(nil) + coderdtest.NewProvisionerDaemon(t, client) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) + firstHistory, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, + Transition: database.WorkspaceTransitionCreate, + }) require.NoError(t, err) - projectVersion := setupProjectVersion(t, client, user, project, data) - _, err = client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectVersionID: projectVersion.ID, + coderdtest.AwaitWorkspaceHistoryProvisioned(t, client, "me", workspace.Name, firstHistory.Name) + secondHistory, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) + require.Equal(t, firstHistory.ID.String(), secondHistory.BeforeID.String()) - var workspaceHistory coderd.WorkspaceHistory - require.Eventually(t, func() bool { - workspaceHistory, err = client.WorkspaceHistory(context.Background(), "", workspace.Name, "") - require.NoError(t, err) - return workspaceHistory.Provision.Status.Completed() - }, 15*time.Second, 50*time.Millisecond) - require.Equal(t, "", workspaceHistory.Provision.Error) - require.Equal(t, coderd.ProvisionerJobStatusSucceeded, workspaceHistory.Provision.Status) + firstHistory, err = client.WorkspaceHistory(context.Background(), "", workspace.Name, firstHistory.Name) + require.NoError(t, err) + require.Equal(t, secondHistory.ID.String(), firstHistory.AfterID.String()) }) +} - t.Run("CreateHistoryAlreadyInProgress", func(t *testing.T) { - t.Parallel() +func TestWorkspaceHistoryByUser(t *testing.T) { + t.Run("ListEmpty", func(t *testing.T) { client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - _ = coderdtest.NewProvisionerDaemon(t, client) - project, workspace := setupProjectAndWorkspace(t, client, user) - data, err := echo.Tar(nil) + coderdtest.NewProvisionerDaemon(t, client) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) + history, err := client.ListWorkspaceHistory(context.Background(), "me", workspace.Name) require.NoError(t, err) - projectVersion := setupProjectVersion(t, client, user, project, data) + require.NotNil(t, history) + require.Len(t, history, 0) + }) - _, err = client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectVersionID: projectVersion.ID, + t.Run("List", func(t *testing.T) { + client := coderdtest.New(t) + coderdtest.NewProvisionerDaemon(t, client) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) + _, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) - - _, err = client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectVersionID: projectVersion.ID, - Transition: database.WorkspaceTransitionCreate, - }) - require.Error(t, err) + history, err := client.ListWorkspaceHistory(context.Background(), "me", workspace.Name) + require.NotNil(t, history) + require.Len(t, history, 1) }) +} - t.Run("CreateHistoryInvalidProjectVersion", func(t *testing.T) { - t.Parallel() +func TestWorkspaceHistoryByName(t *testing.T) { + t.Run("Get", func(t *testing.T) { client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) - _ = coderdtest.NewProvisionerDaemon(t, client) - _, workspace := setupProjectAndWorkspace(t, client, user) - - _, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectVersionID: uuid.New(), + coderdtest.NewProvisionerDaemon(t, client) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) + history, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, Transition: database.WorkspaceTransitionCreate, }) - require.Error(t, err) + require.NoError(t, err) + _, err = client.WorkspaceHistory(context.Background(), "me", workspace.Name, history.Name) + require.NoError(t, err) }) } diff --git a/coderd/workspacehistorylogs_test.go b/coderd/workspacehistorylogs_test.go index 1d615ae1be246..3c792a930591e 100644 --- a/coderd/workspacehistorylogs_test.go +++ b/coderd/workspacehistorylogs_test.go @@ -47,7 +47,7 @@ func TestWorkspaceHistoryLogs(t *testing.T) { } client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) _ = coderdtest.NewProvisionerDaemon(t, client) project, workspace := setupProjectAndWorkspace(t, client, user) data, err := echo.Tar(&echo.Responses{ diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index cf1e45ce5293d..e6260695db3fe 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -19,7 +19,7 @@ func TestWorkspaces(t *testing.T) { t.Run("ListNone", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, client) + _ = coderdtest.CreateInitialUser(t, client) workspaces, err := client.WorkspacesByUser(context.Background(), "") require.NoError(t, err) require.Len(t, workspaces, 0) @@ -42,7 +42,7 @@ func TestWorkspaces(t *testing.T) { t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) _, _ = setupProjectAndWorkspace(t, client, user) workspaces, err := client.WorkspacesByUser(context.Background(), "") require.NoError(t, err) @@ -52,7 +52,7 @@ func TestWorkspaces(t *testing.T) { t.Run("ListNoneForProject", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "banana", Provisioner: database.ProvisionerTypeEcho, @@ -66,7 +66,7 @@ func TestWorkspaces(t *testing.T) { t.Run("ListForProject", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) project, _ := setupProjectAndWorkspace(t, client, user) workspaces, err := client.WorkspacesByProject(context.Background(), user.Organization, project.Name) require.NoError(t, err) @@ -76,7 +76,7 @@ func TestWorkspaces(t *testing.T) { t.Run("CreateInvalidInput", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "banana", Provisioner: database.ProvisionerTypeEcho, @@ -92,7 +92,7 @@ func TestWorkspaces(t *testing.T) { t.Run("CreateInvalidProject", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, client) + _ = coderdtest.CreateInitialUser(t, client) _, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ ProjectID: uuid.New(), Name: "moo", @@ -103,7 +103,7 @@ func TestWorkspaces(t *testing.T) { t.Run("CreateNotInProjectOrganization", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - initial := coderdtest.NewInitialUser(t, client) + initial := coderdtest.CreateInitialUser(t, client) project, err := client.CreateProject(context.Background(), initial.Organization, coderd.CreateProjectRequest{ Name: "banana", Provisioner: database.ProvisionerTypeEcho, @@ -132,7 +132,7 @@ func TestWorkspaces(t *testing.T) { t.Run("CreateAlreadyExists", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) project, workspace := setupProjectAndWorkspace(t, client, user) _, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ Name: workspace.Name, @@ -144,7 +144,7 @@ func TestWorkspaces(t *testing.T) { t.Run("Single", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) _, workspace := setupProjectAndWorkspace(t, client, user) _, err := client.Workspace(context.Background(), "", workspace.Name) require.NoError(t, err) diff --git a/codersdk/projects_test.go b/codersdk/projects_test.go index 9961cca6bf392..b860e60470c40 100644 --- a/codersdk/projects_test.go +++ b/codersdk/projects_test.go @@ -26,7 +26,7 @@ func TestProjects(t *testing.T) { t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) _, err := client.Projects(context.Background(), "") require.NoError(t, err) _, err = client.Projects(context.Background(), user.Organization) @@ -43,7 +43,7 @@ func TestProjects(t *testing.T) { t.Run("Create", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) _, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", Provisioner: database.ProvisionerTypeEcho, @@ -61,7 +61,7 @@ func TestProjects(t *testing.T) { t.Run("Single", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) _, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", Provisioner: database.ProvisionerTypeEcho, @@ -81,7 +81,7 @@ func TestProjects(t *testing.T) { t.Run("History", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", Provisioner: database.ProvisionerTypeEcho, @@ -104,7 +104,7 @@ func TestProjects(t *testing.T) { t.Run("CreateHistory", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "bananas", Provisioner: database.ProvisionerTypeEcho, @@ -132,7 +132,7 @@ func TestProjects(t *testing.T) { t.Run("Parameters", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", Provisioner: database.ProvisionerTypeEcho, @@ -147,7 +147,7 @@ func TestProjects(t *testing.T) { t.Run("CreateParameter", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "someproject", Provisioner: database.ProvisionerTypeEcho, @@ -167,7 +167,7 @@ func TestProjects(t *testing.T) { t.Run("HistoryParametersError", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) _, err := client.ProjectVersionParameters(context.Background(), user.Organization, "nothing", "nope") require.Error(t, err) }) diff --git a/codersdk/users_test.go b/codersdk/users_test.go index 0704e0ab51618..ada436af9dc8e 100644 --- a/codersdk/users_test.go +++ b/codersdk/users_test.go @@ -34,7 +34,7 @@ func TestUsers(t *testing.T) { t.Run("User", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, client) + _ = coderdtest.CreateInitialUser(t, client) _, err := client.User(context.Background(), "") require.NoError(t, err) }) @@ -42,7 +42,7 @@ func TestUsers(t *testing.T) { t.Run("UserOrganizations", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, client) + _ = coderdtest.CreateInitialUser(t, client) orgs, err := client.UserOrganizations(context.Background(), "") require.NoError(t, err) require.Len(t, orgs, 1) @@ -51,7 +51,7 @@ func TestUsers(t *testing.T) { t.Run("LogoutIsSuccessful", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, client) + _ = coderdtest.CreateInitialUser(t, client) err := client.Logout(context.Background()) require.NoError(t, err) }) @@ -59,7 +59,7 @@ func TestUsers(t *testing.T) { t.Run("CreateMultiple", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.NewInitialUser(t, client) + _ = coderdtest.CreateInitialUser(t, client) _, err := client.CreateUser(context.Background(), coderd.CreateUserRequest{ Email: "wow@ok.io", Username: "example", diff --git a/codersdk/workspaces_test.go b/codersdk/workspaces_test.go index 67712a275ea4a..36de9cbe8a6a3 100644 --- a/codersdk/workspaces_test.go +++ b/codersdk/workspaces_test.go @@ -31,7 +31,7 @@ func TestWorkspaces(t *testing.T) { t.Run("ListByUser", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, @@ -49,7 +49,7 @@ func TestWorkspaces(t *testing.T) { t.Run("ListByProject", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, @@ -81,7 +81,7 @@ func TestWorkspaces(t *testing.T) { t.Run("Single", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, @@ -106,7 +106,7 @@ func TestWorkspaces(t *testing.T) { t.Run("History", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, @@ -131,7 +131,7 @@ func TestWorkspaces(t *testing.T) { t.Run("LatestHistory", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, @@ -149,7 +149,7 @@ func TestWorkspaces(t *testing.T) { t.Run("CreateHistory", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.NewInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ Name: "tomato", Provisioner: database.ProvisionerTypeEcho, From ab4dcb140bf75aa34aaf8933db403479f6172682 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 08:09:30 +0000 Subject: [PATCH 06/16] Fix linting errors --- coderd/users_test.go | 1 + coderd/workspacehistory.go | 1 - coderd/workspacehistory_test.go | 39 ++++++++++++++++++----------- coderd/workspacehistorylogs_test.go | 3 ++- 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/coderd/users_test.go b/coderd/users_test.go index 0aafb0bc09cb1..b3f36b3dd0914 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -45,6 +45,7 @@ func TestPostUser(t *testing.T) { } func TestPostUsers(t *testing.T) { + t.Parallel() t.Run("BadRequest", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) diff --git a/coderd/workspacehistory.go b/coderd/workspacehistory.go index d8f4354f6cdb7..dae2a4d157436 100644 --- a/coderd/workspacehistory.go +++ b/coderd/workspacehistory.go @@ -179,7 +179,6 @@ func (api *api) postWorkspaceHistoryByUser(rw http.ResponseWriter, r *http.Reque if err != nil { return xerrors.Errorf("update prior workspace history: %w", err) } - fmt.Printf("Updated %s to %s\n", priorHistory.ID, workspaceHistory.ID) } return nil diff --git a/coderd/workspacehistory_test.go b/coderd/workspacehistory_test.go index 8e1e7a9fb3b2b..49c4adda58f0e 100644 --- a/coderd/workspacehistory_test.go +++ b/coderd/workspacehistory_test.go @@ -17,7 +17,9 @@ import ( ) func TestPostWorkspaceHistoryByUser(t *testing.T) { + t.Parallel() t.Run("NoProjectVersion", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) project := coderdtest.CreateProject(t, client, user.Organization) @@ -32,6 +34,7 @@ func TestPostWorkspaceHistoryByUser(t *testing.T) { }) t.Run("ProjectVersionImporting", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t) coderdtest.NewProvisionerDaemon(t, client) user := coderdtest.CreateInitialUser(t, client) @@ -50,6 +53,7 @@ func TestPostWorkspaceHistoryByUser(t *testing.T) { }) t.Run("ProjectVersionFailedImport", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t) coderdtest.NewProvisionerDaemon(t, client) user := coderdtest.CreateInitialUser(t, client) @@ -69,6 +73,7 @@ func TestPostWorkspaceHistoryByUser(t *testing.T) { }) t.Run("AlreadyActive", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t) coderdtest.NewProvisionerDaemon(t, client) user := coderdtest.CreateInitialUser(t, client) @@ -91,6 +96,7 @@ func TestPostWorkspaceHistoryByUser(t *testing.T) { }) t.Run("UpdatePriorAfterField", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t) coderdtest.NewProvisionerDaemon(t, client) user := coderdtest.CreateInitialUser(t, client) @@ -118,7 +124,9 @@ func TestPostWorkspaceHistoryByUser(t *testing.T) { } func TestWorkspaceHistoryByUser(t *testing.T) { + t.Parallel() t.Run("ListEmpty", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t) coderdtest.NewProvisionerDaemon(t, client) user := coderdtest.CreateInitialUser(t, client) @@ -131,6 +139,7 @@ func TestWorkspaceHistoryByUser(t *testing.T) { }) t.Run("List", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t) coderdtest.NewProvisionerDaemon(t, client) user := coderdtest.CreateInitialUser(t, client) @@ -144,26 +153,26 @@ func TestWorkspaceHistoryByUser(t *testing.T) { }) require.NoError(t, err) history, err := client.ListWorkspaceHistory(context.Background(), "me", workspace.Name) + require.NoError(t, err) require.NotNil(t, history) require.Len(t, history, 1) }) } func TestWorkspaceHistoryByName(t *testing.T) { - t.Run("Get", func(t *testing.T) { - client := coderdtest.New(t) - coderdtest.NewProvisionerDaemon(t, client) - user := coderdtest.CreateInitialUser(t, client) - project := coderdtest.CreateProject(t, client, user.Organization) - version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) - coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) - workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) - history, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectVersionID: version.ID, - Transition: database.WorkspaceTransitionCreate, - }) - require.NoError(t, err) - _, err = client.WorkspaceHistory(context.Background(), "me", workspace.Name, history.Name) - require.NoError(t, err) + t.Parallel() + client := coderdtest.New(t) + coderdtest.NewProvisionerDaemon(t, client) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) + history, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, + Transition: database.WorkspaceTransitionCreate, }) + require.NoError(t, err) + _, err = client.WorkspaceHistory(context.Background(), "me", workspace.Name, history.Name) + require.NoError(t, err) } diff --git a/coderd/workspacehistorylogs_test.go b/coderd/workspacehistorylogs_test.go index 3c792a930591e..d1875ac963d60 100644 --- a/coderd/workspacehistorylogs_test.go +++ b/coderd/workspacehistorylogs_test.go @@ -51,7 +51,8 @@ func TestWorkspaceHistoryLogs(t *testing.T) { _ = coderdtest.NewProvisionerDaemon(t, client) project, workspace := setupProjectAndWorkspace(t, client, user) data, err := echo.Tar(&echo.Responses{ - echo.ParseComplete, []*proto.Provision_Response{{ + Parse: echo.ParseComplete, + Provision: []*proto.Provision_Response{{ Type: &proto.Provision_Response_Log{ Log: &proto.Log{ Output: "test", From 57efae22337182e8a82d16afafa83da42580b0fe Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 08:34:07 +0000 Subject: [PATCH 07/16] Fix coderd test leak --- coderd/coderdtest/coderdtest.go | 2 -- coderd/coderdtest/coderdtest_test.go | 20 ++++++++++++++++++-- coderd/provisionerdaemons.go | 5 ++++- codersdk/provisioners.go | 5 ++++- provisioner/echo/serve.go | 6 ++++-- 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 38fb0ab9738a2..430ed0c66a283 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -3,7 +3,6 @@ package coderdtest import ( "context" "database/sql" - "fmt" "io" "net/http/httptest" "net/url" @@ -154,7 +153,6 @@ func AwaitProjectVersionImported(t *testing.T, client *codersdk.Client, organiza var err error projectVersion, err = client.ProjectVersion(context.Background(), organization, project, version) require.NoError(t, err) - fmt.Printf("GOT: %s\n", projectVersion.Import.Status) return projectVersion.Import.Status.Completed() }, 3*time.Second, 25*time.Millisecond) return projectVersion diff --git a/coderd/coderdtest/coderdtest_test.go b/coderd/coderdtest/coderdtest_test.go index f880c8fc3a984..ca0e1d9a8a04f 100644 --- a/coderd/coderdtest/coderdtest_test.go +++ b/coderd/coderdtest/coderdtest_test.go @@ -1,11 +1,16 @@ package coderdtest_test import ( + "context" "testing" "go.uber.org/goleak" + "github.com/stretchr/testify/require" + + "github.com/coder/coder/coderd" "github.com/coder/coder/coderd/coderdtest" + "github.com/coder/coder/database" ) func TestMain(m *testing.M) { @@ -15,6 +20,17 @@ func TestMain(m *testing.M) { func TestNew(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.CreateInitialUser(t, client) - _ = coderdtest.NewProvisionerDaemon(t, client) + user := coderdtest.CreateInitialUser(t, client) + closer := coderdtest.NewProvisionerDaemon(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) + history, err := client.CreateWorkspaceHistory(context.Background(), "me", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, + Transition: database.WorkspaceTransitionCreate, + }) + require.NoError(t, err) + coderdtest.AwaitWorkspaceHistoryProvisioned(t, client, "me", workspace.Name, history.Name) + closer.Close() } diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index 29d369a46d188..db7474af8508e 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "fmt" + "io" "net/http" "reflect" "time" @@ -75,7 +76,9 @@ func (api *api) provisionerDaemonsServe(rw http.ResponseWriter, r *http.Request) // Multiplexes the incoming connection using yamux. // This allows multiple function calls to occur over // the same connection. - session, err := yamux.Server(websocket.NetConn(r.Context(), conn, websocket.MessageBinary), nil) + config := yamux.DefaultConfig() + config.LogOutput = io.Discard + session, err := yamux.Server(websocket.NetConn(r.Context(), conn, websocket.MessageBinary), config) if err != nil { _ = conn.Close(websocket.StatusInternalError, fmt.Sprintf("multiplex server: %s", err)) return diff --git a/codersdk/provisioners.go b/codersdk/provisioners.go index 3ebfaa148fdf4..e0ebf5f56f1c9 100644 --- a/codersdk/provisioners.go +++ b/codersdk/provisioners.go @@ -3,6 +3,7 @@ package codersdk import ( "context" "encoding/json" + "io" "net/http" "github.com/hashicorp/yamux" @@ -42,7 +43,9 @@ func (c *Client) ProvisionerDaemonClient(ctx context.Context) (proto.DRPCProvisi } return nil, readBodyAsError(res) } - session, err := yamux.Client(websocket.NetConn(context.Background(), conn, websocket.MessageBinary), nil) + config := yamux.DefaultConfig() + config.LogOutput = io.Discard + session, err := yamux.Client(websocket.NetConn(ctx, conn, websocket.MessageBinary), config) if err != nil { return nil, xerrors.Errorf("multiplex client: %w", err) } diff --git a/provisioner/echo/serve.go b/provisioner/echo/serve.go index 8dc48b96cf28f..a0bb57dad1e82 100644 --- a/provisioner/echo/serve.go +++ b/provisioner/echo/serve.go @@ -68,7 +68,8 @@ func (*echo) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_Pa return err } } - return nil + <-stream.Context().Done() + return stream.Context().Err() } // Provision reads requests from the provided directory to stream responses. @@ -97,7 +98,8 @@ func (*echo) Provision(request *proto.Provision_Request, stream proto.DRPCProvis return err } } - return nil + <-stream.Context().Done() + return stream.Context().Err() } type Responses struct { From 9fa815ce21232e1f634ce5c2e1440a1f2621a5ea Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 08:34:07 +0000 Subject: [PATCH 08/16] Fix coderd test leak --- coderd/coderdtest/coderdtest.go | 2 -- coderd/coderdtest/coderdtest_test.go | 20 ++++++++++++++++++-- coderd/provisionerdaemons.go | 5 ++++- codersdk/provisioners.go | 5 ++++- peer/conn_test.go | 4 ++-- provisioner/echo/serve.go | 6 ++++-- provisionerd/provisionerd_test.go | 4 ++-- 7 files changed, 34 insertions(+), 12 deletions(-) diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 38fb0ab9738a2..430ed0c66a283 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -3,7 +3,6 @@ package coderdtest import ( "context" "database/sql" - "fmt" "io" "net/http/httptest" "net/url" @@ -154,7 +153,6 @@ func AwaitProjectVersionImported(t *testing.T, client *codersdk.Client, organiza var err error projectVersion, err = client.ProjectVersion(context.Background(), organization, project, version) require.NoError(t, err) - fmt.Printf("GOT: %s\n", projectVersion.Import.Status) return projectVersion.Import.Status.Completed() }, 3*time.Second, 25*time.Millisecond) return projectVersion diff --git a/coderd/coderdtest/coderdtest_test.go b/coderd/coderdtest/coderdtest_test.go index f880c8fc3a984..ca0e1d9a8a04f 100644 --- a/coderd/coderdtest/coderdtest_test.go +++ b/coderd/coderdtest/coderdtest_test.go @@ -1,11 +1,16 @@ package coderdtest_test import ( + "context" "testing" "go.uber.org/goleak" + "github.com/stretchr/testify/require" + + "github.com/coder/coder/coderd" "github.com/coder/coder/coderd/coderdtest" + "github.com/coder/coder/database" ) func TestMain(m *testing.M) { @@ -15,6 +20,17 @@ func TestMain(m *testing.M) { func TestNew(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.CreateInitialUser(t, client) - _ = coderdtest.NewProvisionerDaemon(t, client) + user := coderdtest.CreateInitialUser(t, client) + closer := coderdtest.NewProvisionerDaemon(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) + history, err := client.CreateWorkspaceHistory(context.Background(), "me", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, + Transition: database.WorkspaceTransitionCreate, + }) + require.NoError(t, err) + coderdtest.AwaitWorkspaceHistoryProvisioned(t, client, "me", workspace.Name, history.Name) + closer.Close() } diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index 29d369a46d188..db7474af8508e 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "fmt" + "io" "net/http" "reflect" "time" @@ -75,7 +76,9 @@ func (api *api) provisionerDaemonsServe(rw http.ResponseWriter, r *http.Request) // Multiplexes the incoming connection using yamux. // This allows multiple function calls to occur over // the same connection. - session, err := yamux.Server(websocket.NetConn(r.Context(), conn, websocket.MessageBinary), nil) + config := yamux.DefaultConfig() + config.LogOutput = io.Discard + session, err := yamux.Server(websocket.NetConn(r.Context(), conn, websocket.MessageBinary), config) if err != nil { _ = conn.Close(websocket.StatusInternalError, fmt.Sprintf("multiplex server: %s", err)) return diff --git a/codersdk/provisioners.go b/codersdk/provisioners.go index 3ebfaa148fdf4..e0ebf5f56f1c9 100644 --- a/codersdk/provisioners.go +++ b/codersdk/provisioners.go @@ -3,6 +3,7 @@ package codersdk import ( "context" "encoding/json" + "io" "net/http" "github.com/hashicorp/yamux" @@ -42,7 +43,9 @@ func (c *Client) ProvisionerDaemonClient(ctx context.Context) (proto.DRPCProvisi } return nil, readBodyAsError(res) } - session, err := yamux.Client(websocket.NetConn(context.Background(), conn, websocket.MessageBinary), nil) + config := yamux.DefaultConfig() + config.LogOutput = io.Discard + session, err := yamux.Client(websocket.NetConn(ctx, conn, websocket.MessageBinary), config) if err != nil { return nil, xerrors.Errorf("multiplex client: %w", err) } diff --git a/peer/conn_test.go b/peer/conn_test.go index c55bb56b06614..519e5f3b743db 100644 --- a/peer/conn_test.go +++ b/peer/conn_test.go @@ -2,7 +2,6 @@ package peer_test import ( "context" - "errors" "io" "net" "net/http" @@ -17,6 +16,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/goleak" + "golang.org/x/xerrors" "cdr.dev/slog" "cdr.dev/slog/sloggers/slogtest" @@ -231,7 +231,7 @@ func TestConn(t *testing.T) { t.Parallel() conn, err := peer.Client([]webrtc.ICEServer{}, nil) require.NoError(t, err) - expectedErr := errors.New("wow") + expectedErr := xerrors.New("wow") _ = conn.CloseWithError(expectedErr) _, err = conn.Dial(context.Background(), "", nil) require.ErrorIs(t, err, expectedErr) diff --git a/provisioner/echo/serve.go b/provisioner/echo/serve.go index 8dc48b96cf28f..a0bb57dad1e82 100644 --- a/provisioner/echo/serve.go +++ b/provisioner/echo/serve.go @@ -68,7 +68,8 @@ func (*echo) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_Pa return err } } - return nil + <-stream.Context().Done() + return stream.Context().Err() } // Provision reads requests from the provided directory to stream responses. @@ -97,7 +98,8 @@ func (*echo) Provision(request *proto.Provision_Request, stream proto.DRPCProvis return err } } - return nil + <-stream.Context().Done() + return stream.Context().Err() } type Responses struct { diff --git a/provisionerd/provisionerd_test.go b/provisionerd/provisionerd_test.go index 376bfd1eaadb1..5a32b6fb2030e 100644 --- a/provisionerd/provisionerd_test.go +++ b/provisionerd/provisionerd_test.go @@ -4,7 +4,6 @@ import ( "archive/tar" "bytes" "context" - "errors" "io" "os" "path/filepath" @@ -15,6 +14,7 @@ import ( "github.com/stretchr/testify/require" "go.uber.org/atomic" "go.uber.org/goleak" + "golang.org/x/xerrors" "storj.io/drpc/drpcmux" "storj.io/drpc/drpcserver" @@ -52,7 +52,7 @@ func TestProvisionerd(t *testing.T) { completeChan := make(chan struct{}) closer := createProvisionerd(t, func(ctx context.Context) (proto.DRPCProvisionerDaemonClient, error) { defer close(completeChan) - return nil, errors.New("an error") + return nil, xerrors.New("an error") }, provisionerd.Provisioners{}) <-completeChan require.NoError(t, closer.Close()) From c50cee0ed662919622d754f338c06e9be8346d5b Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 18:39:31 +0000 Subject: [PATCH 09/16] Improve workspace history logs --- coderd/workspacehistorylogs.go | 12 +- coderd/workspacehistorylogs_test.go | 169 +++++++++++++++++----------- 2 files changed, 109 insertions(+), 72 deletions(-) diff --git a/coderd/workspacehistorylogs.go b/coderd/workspacehistorylogs.go index ecf8e1fda9d2b..029167c0a7572 100644 --- a/coderd/workspacehistorylogs.go +++ b/coderd/workspacehistorylogs.go @@ -87,7 +87,6 @@ func (api *api) workspaceHistoryLogsByName(rw http.ResponseWriter, r *http.Reque }) if errors.Is(err, sql.ErrNoRows) { err = nil - logs = []database.WorkspaceHistoryLog{} } if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ @@ -95,6 +94,9 @@ func (api *api) workspaceHistoryLogsByName(rw http.ResponseWriter, r *http.Reque }) return } + if logs == nil { + logs = []database.WorkspaceHistoryLog{} + } render.Status(r, http.StatusOK) render.JSON(rw, r, logs) return @@ -113,12 +115,8 @@ func (api *api) workspaceHistoryLogsByName(rw http.ResponseWriter, r *http.Reque select { case bufferedLogs <- log: default: - // This is a case that shouldn't happen, but totally could. - // There's no way to stream data from the database, so we'll - // need to maintain some level of internal buffer. - // - // If this overflows users could miss logs when streaming. - // We warn to make sure we know when it happens! + // If this overflows users could miss logs streaming. This can happen + // if a database request takes a long amount of time, and we get a lot of logs. api.Logger.Warn(r.Context(), "workspace history log overflowing channel") } } diff --git a/coderd/workspacehistorylogs_test.go b/coderd/workspacehistorylogs_test.go index d1875ac963d60..1e95a0f506cc1 100644 --- a/coderd/workspacehistorylogs_test.go +++ b/coderd/workspacehistorylogs_test.go @@ -9,93 +9,132 @@ import ( "github.com/coder/coder/coderd" "github.com/coder/coder/coderd/coderdtest" - "github.com/coder/coder/codersdk" "github.com/coder/coder/database" "github.com/coder/coder/provisioner/echo" "github.com/coder/coder/provisionersdk/proto" ) -func TestWorkspaceHistoryLogs(t *testing.T) { +func TestWorkspaceHistoryLogsByName(t *testing.T) { t.Parallel() - - setupProjectAndWorkspace := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest) (coderd.Project, coderd.Workspace) { - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "banana", - Provisioner: database.ProvisionerTypeEcho, + t.Run("List", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + user := coderdtest.CreateInitialUser(t, client) + coderdtest.NewProvisionerDaemon(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, &echo.Responses{ + Parse: echo.ParseComplete, + Provision: []*proto.Provision_Response{{ + Type: &proto.Provision_Response_Log{ + Log: &proto.Log{ + Level: proto.LogLevel_INFO, + Output: "log-output", + }, + }, + }, { + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{}, + }, + }}, }) - require.NoError(t, err) - workspace, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "example", - ProjectID: project.ID, + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) + history, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, + Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) - return project, workspace - } - setupProjectVersion := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest, project coderd.Project, data []byte) coderd.ProjectVersion { - projectVersion, err := client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ - StorageMethod: database.ProjectStorageMethodInlineArchive, - StorageSource: data, - }) + // Successfully return empty logs before the job starts! + logs, err := client.WorkspaceHistoryLogs(context.Background(), "", workspace.Name, history.Name) require.NoError(t, err) - require.Eventually(t, func() bool { - hist, err := client.ProjectVersion(context.Background(), user.Organization, project.Name, projectVersion.Name) - require.NoError(t, err) - return hist.Import.Status.Completed() - }, 15*time.Second, 50*time.Millisecond) - return projectVersion - } + require.NotNil(t, logs) + require.Len(t, logs, 0) - client := coderdtest.New(t) - user := coderdtest.CreateInitialUser(t, client) - _ = coderdtest.NewProvisionerDaemon(t, client) - project, workspace := setupProjectAndWorkspace(t, client, user) - data, err := echo.Tar(&echo.Responses{ - Parse: echo.ParseComplete, - Provision: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Log{ - Log: &proto.Log{ - Output: "test", - }, - }, - }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}, - }) - require.NoError(t, err) - projectVersion := setupProjectVersion(t, client, user, project, data) + coderdtest.AwaitWorkspaceHistoryProvisioned(t, client, "", workspace.Name, history.Name) - workspaceHistory, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectVersionID: projectVersion.ID, - Transition: database.WorkspaceTransitionCreate, + // Return the log after completion! + logs, err = client.WorkspaceHistoryLogs(context.Background(), "", workspace.Name, history.Name) + require.NoError(t, err) + require.NotNil(t, logs) + require.Len(t, logs, 1) }) - require.NoError(t, err) - - now := database.Now() - logChan, err := client.FollowWorkspaceHistoryLogsAfter(context.Background(), "", workspace.Name, workspaceHistory.Name, now) - require.NoError(t, err) - - for { - log, more := <-logChan - if !more { - break - } - t.Logf("Output: %s", log.Output) - } - t.Run("ReturnAll", func(t *testing.T) { + t.Run("StreamAfterComplete", func(t *testing.T) { t.Parallel() + client := coderdtest.New(t) + user := coderdtest.CreateInitialUser(t, client) + coderdtest.NewProvisionerDaemon(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, &echo.Responses{ + Parse: echo.ParseComplete, + Provision: []*proto.Provision_Response{{ + Type: &proto.Provision_Response_Log{ + Log: &proto.Log{ + Level: proto.LogLevel_INFO, + Output: "log-output", + }, + }, + }, { + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{}, + }, + }}, + }) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) + before := time.Now().UTC() + history, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, + Transition: database.WorkspaceTransitionCreate, + }) + require.NoError(t, err) + coderdtest.AwaitWorkspaceHistoryProvisioned(t, client, "", workspace.Name, history.Name) - _, err := client.WorkspaceHistoryLogs(context.Background(), "", workspace.Name, workspaceHistory.Name) + logs, err := client.FollowWorkspaceHistoryLogsAfter(context.Background(), "", workspace.Name, history.Name, before) require.NoError(t, err) + log := <-logs + require.Equal(t, "log-output", log.Output) + // Make sure the channel automatically closes! + _, ok := <-logs + require.False(t, ok) }) - t.Run("Between", func(t *testing.T) { + t.Run("StreamWhileRunning", func(t *testing.T) { t.Parallel() + client := coderdtest.New(t) + user := coderdtest.CreateInitialUser(t, client) + coderdtest.NewProvisionerDaemon(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, &echo.Responses{ + Parse: echo.ParseComplete, + Provision: []*proto.Provision_Response{{ + Type: &proto.Provision_Response_Log{ + Log: &proto.Log{ + Level: proto.LogLevel_INFO, + Output: "log-output", + }, + }, + }, { + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{}, + }, + }}, + }) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) + history, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, + Transition: database.WorkspaceTransitionCreate, + }) + require.NoError(t, err) - _, err := client.WorkspaceHistoryLogsBetween(context.Background(), "", workspace.Name, workspaceHistory.Name, time.Time{}, database.Now()) + logs, err := client.FollowWorkspaceHistoryLogsAfter(context.Background(), "", workspace.Name, history.Name, time.Time{}) require.NoError(t, err) + log := <-logs + require.Equal(t, "log-output", log.Output) + // Make sure the channel automatically closes! + _, ok := <-logs + require.False(t, ok) }) } From e202b2d3a5927fb7376936797fec96de0ff20704 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 20:11:28 +0000 Subject: [PATCH 10/16] Standardize test structure for codersdk --- coderd/coderd.go | 1 - coderd/provisionerdaemons.go | 5 +- coderd/provisionerdaemons_test.go | 22 +-- coderd/workspaces.go | 2 +- coderd/workspaces_test.go | 155 ++++++++++---------- codersdk/projects_test.go | 189 ++++++++++++++----------- codersdk/provisioners_test.go | 42 ++++++ codersdk/users_test.go | 93 ++++++++---- codersdk/workspaces.go | 2 +- codersdk/workspaces_test.go | 228 +++++++++++++++++++----------- 10 files changed, 451 insertions(+), 288 deletions(-) create mode 100644 codersdk/provisioners_test.go diff --git a/coderd/coderd.go b/coderd/coderd.go index cd60b044e9d33..abce77ce2a10e 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -86,7 +86,6 @@ func New(options *Options) http.Handler { r.Get("/", api.workspaces) r.Route("/{user}", func(r chi.Router) { r.Use(httpmw.ExtractUserParam(options.Database)) - r.Get("/", api.workspaces) r.Post("/", api.postWorkspaceByUser) r.Route("/{workspace}", func(r chi.Router) { r.Use(httpmw.ExtractWorkspaceParam(options.Database)) diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index db7474af8508e..00880074af473 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -36,7 +36,6 @@ func (api *api) provisionerDaemons(rw http.ResponseWriter, r *http.Request) { daemons, err := api.Database.GetProvisionerDaemons(r.Context()) if errors.Is(err, sql.ErrNoRows) { err = nil - daemons = []database.ProvisionerDaemon{} } if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ @@ -44,7 +43,9 @@ func (api *api) provisionerDaemons(rw http.ResponseWriter, r *http.Request) { }) return } - + if daemons == nil { + daemons = []database.ProvisionerDaemon{} + } render.Status(r, http.StatusOK) render.JSON(rw, r, daemons) } diff --git a/coderd/provisionerdaemons_test.go b/coderd/provisionerdaemons_test.go index eb5809c65f27b..f37923aa00a30 100644 --- a/coderd/provisionerdaemons_test.go +++ b/coderd/provisionerdaemons_test.go @@ -11,16 +11,18 @@ import ( ) func TestProvisionerDaemons(t *testing.T) { + // Tests for properly processing specific job + // types should be placed in their respective + // resource location. + // + // eg. project import is a project-related job t.Parallel() - t.Run("Register", func(t *testing.T) { - t.Parallel() - client := coderdtest.New(t) - _ = coderdtest.NewProvisionerDaemon(t, client) - require.Eventually(t, func() bool { - daemons, err := client.ProvisionerDaemons(context.Background()) - require.NoError(t, err) - return len(daemons) > 0 - }, time.Second, 10*time.Millisecond) - }) + client := coderdtest.New(t) + _ = coderdtest.NewProvisionerDaemon(t, client) + require.Eventually(t, func() bool { + daemons, err := client.ProvisionerDaemons(context.Background()) + require.NoError(t, err) + return len(daemons) > 0 + }, time.Second, 25*time.Millisecond) } diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 22c10d7cc546b..733741512baea 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -137,7 +137,7 @@ func (api *api) postWorkspaceByUser(rw http.ResponseWriter, r *http.Request) { render.JSON(rw, r, convertWorkspace(workspace)) } -// Returns a single singleWorkspace. +// Returns a single single workspace. func (*api) workspaceByUser(rw http.ResponseWriter, r *http.Request) { workspace := httpmw.WorkspaceParam(r) diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index e6260695db3fe..bc170a92ab4b8 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -2,6 +2,7 @@ package coderd_test import ( "context" + "net/http" "testing" "github.com/google/uuid" @@ -10,143 +11,135 @@ import ( "github.com/coder/coder/coderd" "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/codersdk" - "github.com/coder/coder/database" ) func TestWorkspaces(t *testing.T) { t.Parallel() - t.Run("ListNone", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) _ = coderdtest.CreateInitialUser(t, client) - workspaces, err := client.WorkspacesByUser(context.Background(), "") + workspaces, err := client.Workspaces(context.Background(), "") require.NoError(t, err) + require.NotNil(t, workspaces) require.Len(t, workspaces, 0) }) - setupProjectAndWorkspace := func(t *testing.T, client *codersdk.Client, user coderd.CreateInitialUserRequest) (coderd.Project, coderd.Workspace) { - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "banana", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - workspace, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "example", - ProjectID: project.ID, - }) - require.NoError(t, err) - return project, workspace - } - t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - _, _ = setupProjectAndWorkspace(t, client, user) - workspaces, err := client.WorkspacesByUser(context.Background(), "") + project := coderdtest.CreateProject(t, client, user.Organization) + _ = coderdtest.CreateWorkspace(t, client, "", project.ID) + workspaces, err := client.Workspaces(context.Background(), "") require.NoError(t, err) require.Len(t, workspaces, 1) }) +} - t.Run("ListNoneForProject", func(t *testing.T) { +func TestPostWorkspaceByUser(t *testing.T) { + t.Parallel() + t.Run("InvalidProject", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.CreateInitialUser(t, client) - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "banana", - Provisioner: database.ProvisionerTypeEcho, + _ = coderdtest.CreateInitialUser(t, client) + _, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ + ProjectID: uuid.New(), + Name: "workspace", }) - require.NoError(t, err) - workspaces, err := client.WorkspacesByProject(context.Background(), user.Organization, project.Name) - require.NoError(t, err) - require.Len(t, workspaces, 0) + require.Error(t, err) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusBadRequest, apiErr.StatusCode()) }) - t.Run("ListForProject", func(t *testing.T) { + t.Run("NoProjectAccess", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - project, _ := setupProjectAndWorkspace(t, client, user) - workspaces, err := client.WorkspacesByProject(context.Background(), user.Organization, project.Name) - require.NoError(t, err) - require.Len(t, workspaces, 1) - }) + project := coderdtest.CreateProject(t, client, user.Organization) - t.Run("CreateInvalidInput", func(t *testing.T) { - t.Parallel() - client := coderdtest.New(t) - user := coderdtest.CreateInitialUser(t, client) - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "banana", - Provisioner: database.ProvisionerTypeEcho, + anotherUser := coderd.CreateUserRequest{ + Email: "another@user.org", + Username: "someuser", + Password: "somepass", + } + _, err := client.CreateUser(context.Background(), anotherUser) + require.NoError(t, err) + token, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ + Email: anotherUser.Email, + Password: anotherUser.Password, }) require.NoError(t, err) + err = client.SetSessionToken(token.SessionToken) + require.NoError(t, err) + _, err = client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ ProjectID: project.ID, - Name: "$$$", + Name: "workspace", }) require.Error(t, err) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusUnauthorized, apiErr.StatusCode()) }) - t.Run("CreateInvalidProject", func(t *testing.T) { + t.Run("AlreadyExists", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.CreateInitialUser(t, client) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + workspace := coderdtest.CreateWorkspace(t, client, "", project.ID) _, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - ProjectID: uuid.New(), - Name: "moo", + ProjectID: project.ID, + Name: workspace.Name, }) require.Error(t, err) + var apiErr *codersdk.Error + require.ErrorAs(t, err, &apiErr) + require.Equal(t, http.StatusConflict, apiErr.StatusCode()) }) - t.Run("CreateNotInProjectOrganization", func(t *testing.T) { + t.Run("Create", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - initial := coderdtest.CreateInitialUser(t, client) - project, err := client.CreateProject(context.Background(), initial.Organization, coderd.CreateProjectRequest{ - Name: "banana", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - _, err = client.CreateUser(context.Background(), coderd.CreateUserRequest{ - Email: "hello@ok.io", - Username: "example", - Password: "password", - }) - require.NoError(t, err) - token, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ - Email: "hello@ok.io", - Password: "password", - }) - require.NoError(t, err) - err = client.SetSessionToken(token.SessionToken) - require.NoError(t, err) - _, err = client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - ProjectID: project.ID, - Name: "moo", - }) - require.Error(t, err) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + _ = coderdtest.CreateWorkspace(t, client, "", project.ID) }) +} + +func TestWorkspaceByUser(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + workspace := coderdtest.CreateWorkspace(t, client, "", project.ID) + _, err := client.Workspace(context.Background(), "", workspace.Name) + require.NoError(t, err) +} - t.Run("CreateAlreadyExists", func(t *testing.T) { +func TestWorkspacesByProject(t *testing.T) { + t.Parallel() + t.Run("ListEmpty", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - project, workspace := setupProjectAndWorkspace(t, client, user) - _, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: workspace.Name, - ProjectID: project.ID, - }) - require.Error(t, err) + project := coderdtest.CreateProject(t, client, user.Organization) + workspaces, err := client.WorkspacesByProject(context.Background(), user.Organization, project.Name) + require.NoError(t, err) + require.NotNil(t, workspaces) }) - t.Run("Single", func(t *testing.T) { + t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - _, workspace := setupProjectAndWorkspace(t, client, user) - _, err := client.Workspace(context.Background(), "", workspace.Name) + project := coderdtest.CreateProject(t, client, user.Organization) + _ = coderdtest.CreateWorkspace(t, client, "", project.ID) + workspaces, err := client.WorkspacesByProject(context.Background(), user.Organization, project.Name) require.NoError(t, err) + require.NotNil(t, workspaces) + require.Len(t, workspaces, 1) }) } diff --git a/codersdk/projects_test.go b/codersdk/projects_test.go index b860e60470c40..bf072657c97bd 100644 --- a/codersdk/projects_test.go +++ b/codersdk/projects_test.go @@ -1,8 +1,6 @@ package codersdk_test import ( - "archive/tar" - "bytes" "context" "testing" @@ -15,8 +13,7 @@ import ( func TestProjects(t *testing.T) { t.Parallel() - - t.Run("UnauthenticatedList", func(t *testing.T) { + t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) _, err := client.Projects(context.Background(), "") @@ -26,149 +23,173 @@ func TestProjects(t *testing.T) { t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.CreateInitialUser(t, client) + _ = coderdtest.CreateInitialUser(t, client) _, err := client.Projects(context.Background(), "") require.NoError(t, err) - _, err = client.Projects(context.Background(), user.Organization) - require.NoError(t, err) }) +} - t.Run("UnauthenticatedCreate", func(t *testing.T) { +func TestProject(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _, err := client.CreateProject(context.Background(), "", coderd.CreateProjectRequest{}) + _, err := client.Project(context.Background(), "", "") require.Error(t, err) }) - t.Run("Create", func(t *testing.T) { + t.Run("Get", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - _, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "bananas", + project := coderdtest.CreateProject(t, client, user.Organization) + _, err := client.Project(context.Background(), user.Organization, project.Name) + require.NoError(t, err) + }) +} + +func TestCreateProject(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + _, err := client.CreateProject(context.Background(), "org", coderd.CreateProjectRequest{ + Name: "something", Provisioner: database.ProvisionerTypeEcho, }) - require.NoError(t, err) + require.Error(t, err) + }) + + t.Run("Create", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + user := coderdtest.CreateInitialUser(t, client) + _ = coderdtest.CreateProject(t, client, user.Organization) }) +} - t.Run("UnauthenticatedSingle", func(t *testing.T) { +func TestProjectVersions(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _, err := client.Project(context.Background(), "wow", "example") + _, err := client.ProjectVersions(context.Background(), "some", "project") require.Error(t, err) }) - t.Run("Single", func(t *testing.T) { + t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - _, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "bananas", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - _, err = client.Project(context.Background(), user.Organization, "bananas") + project := coderdtest.CreateProject(t, client, user.Organization) + + _, err := client.ProjectVersions(context.Background(), user.Organization, project.Name) require.NoError(t, err) }) +} - t.Run("UnauthenticatedHistory", func(t *testing.T) { +func TestProjectVersion(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _, err := client.ProjectVersions(context.Background(), "org", "project") + _, err := client.ProjectVersion(context.Background(), "some", "project", "version") require.Error(t, err) }) - t.Run("History", func(t *testing.T) { + t.Run("Get", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "bananas", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - _, err = client.ProjectVersions(context.Background(), user.Organization, project.Name) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) + _, err := client.ProjectVersion(context.Background(), user.Organization, project.Name, version.Name) require.NoError(t, err) }) +} - t.Run("CreateHistoryUnauthenticated", func(t *testing.T) { +func TestCreateProjectVersion(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _, err := client.CreateProjectVersion(context.Background(), "org", "project", coderd.CreateProjectVersionRequest{ - StorageMethod: database.ProjectStorageMethodInlineArchive, - StorageSource: []byte{}, - }) + _, err := client.CreateProjectVersion(context.Background(), "some", "project", coderd.CreateProjectVersionRequest{}) require.Error(t, err) }) - t.Run("CreateHistory", func(t *testing.T) { + t.Run("Create", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "bananas", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - var buffer bytes.Buffer - writer := tar.NewWriter(&buffer) - err = writer.WriteHeader(&tar.Header{ - Name: "file", - Size: 1 << 10, - }) - require.NoError(t, err) - _, err = writer.Write(make([]byte, 1<<10)) - require.NoError(t, err) - version, err := client.CreateProjectVersion(context.Background(), user.Organization, project.Name, coderd.CreateProjectVersionRequest{ - StorageMethod: database.ProjectStorageMethodInlineArchive, - StorageSource: buffer.Bytes(), - }) - require.NoError(t, err) + project := coderdtest.CreateProject(t, client, user.Organization) + _ = coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) + }) +} - _, err = client.ProjectVersion(context.Background(), user.Organization, project.Name, version.Name) - require.NoError(t, err) +func TestProjectVersionParameters(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + _, err := client.ProjectVersionParameters(context.Background(), "some", "project", "version") + require.Error(t, err) }) - t.Run("Parameters", func(t *testing.T) { + t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "someproject", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - params, err := client.ProjectParameters(context.Background(), user.Organization, project.Name) + coderdtest.NewProvisionerDaemon(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + _, err := client.ProjectVersionParameters(context.Background(), user.Organization, project.Name, version.Name) require.NoError(t, err) - require.NotNil(t, params) - require.Len(t, params, 0) }) +} - t.Run("CreateParameter", func(t *testing.T) { +func TestProjectParameters(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + _, err := client.ProjectParameters(context.Background(), "some", "project") + require.Error(t, err) + }) + + t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "someproject", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - param, err := client.CreateProjectParameter(context.Background(), user.Organization, project.Name, coderd.CreateParameterValueRequest{ - Name: "hi", - SourceValue: "tomato", - SourceScheme: database.ParameterSourceSchemeData, - DestinationScheme: database.ParameterDestinationSchemeEnvironmentVariable, - DestinationValue: "moo", - }) + coderdtest.NewProvisionerDaemon(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + _, err := client.ProjectParameters(context.Background(), user.Organization, project.Name) require.NoError(t, err) - require.Equal(t, "hi", param.Name) }) +} - t.Run("HistoryParametersError", func(t *testing.T) { +func TestCreateProjectParameter(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - user := coderdtest.CreateInitialUser(t, client) - _, err := client.ProjectVersionParameters(context.Background(), user.Organization, "nothing", "nope") + _, err := client.CreateProjectParameter(context.Background(), "some", "project", coderd.CreateParameterValueRequest{}) require.Error(t, err) }) + + t.Run("Create", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + user := coderdtest.CreateInitialUser(t, client) + coderdtest.NewProvisionerDaemon(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + _, err := client.CreateProjectParameter(context.Background(), user.Organization, project.Name, coderd.CreateParameterValueRequest{ + Name: "example", + SourceValue: "source-value", + SourceScheme: database.ParameterSourceSchemeData, + DestinationScheme: database.ParameterDestinationSchemeEnvironmentVariable, + DestinationValue: "destination-value", + }) + require.NoError(t, err) + }) } diff --git a/codersdk/provisioners_test.go b/codersdk/provisioners_test.go new file mode 100644 index 0000000000000..e373a921c29a2 --- /dev/null +++ b/codersdk/provisioners_test.go @@ -0,0 +1,42 @@ +package codersdk_test + +import ( + "context" + "testing" + + "github.com/coder/coder/coderd/coderdtest" + "github.com/coder/coder/provisionerd/proto" + "github.com/stretchr/testify/require" +) + +func TestProvisionerDaemons(t *testing.T) { + t.Parallel() + t.Run("Get", func(t *testing.T) { + client := coderdtest.New(t) + _, err := client.ProvisionerDaemons(context.Background()) + require.NoError(t, err) + }) +} + +func TestProvisionerDaemonClient(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { + client := coderdtest.New(t) + ctx, cancelFunc := context.WithCancel(context.Background()) + daemon, err := client.ProvisionerDaemonClient(ctx) + require.NoError(t, err) + cancelFunc() + _, err = daemon.AcquireJob(context.Background(), &proto.Empty{}) + require.Error(t, err) + }) + + t.Run("Connect", func(t *testing.T) { + client := coderdtest.New(t) + ctx, cancelFunc := context.WithCancel(context.Background()) + defer cancelFunc() + daemon, err := client.ProvisionerDaemonClient(ctx) + require.NoError(t, err) + _, err = daemon.AcquireJob(ctx, &proto.Empty{}) + require.NoError(t, err) + }) +} diff --git a/codersdk/users_test.go b/codersdk/users_test.go index ada436af9dc8e..d24b955a0c0cd 100644 --- a/codersdk/users_test.go +++ b/codersdk/users_test.go @@ -10,61 +10,100 @@ import ( "github.com/coder/coder/coderd/coderdtest" ) -func TestUsers(t *testing.T) { +func TestCreateInitialUser(t *testing.T) { t.Parallel() - t.Run("CreateInitial", func(t *testing.T) { + t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _, err := client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{ - Email: "wowie@coder.com", - Organization: "somethin", - Username: "tester", - Password: "moo", - }) - require.NoError(t, err) + _, err := client.CreateInitialUser(context.Background(), coderd.CreateInitialUserRequest{}) + require.Error(t, err) }) - t.Run("NoUser", func(t *testing.T) { + t.Run("Create", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _, err := client.User(context.Background(), "") + _ = coderdtest.CreateInitialUser(t, client) + }) +} + +func TestCreateUser(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + _, err := client.CreateUser(context.Background(), coderd.CreateUserRequest{}) require.Error(t, err) }) - t.Run("User", func(t *testing.T) { + t.Run("Create", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) _ = coderdtest.CreateInitialUser(t, client) - _, err := client.User(context.Background(), "") + _, err := client.CreateUser(context.Background(), coderd.CreateUserRequest{ + Email: "example@coder.com", + Username: "something", + Password: "password", + }) require.NoError(t, err) }) +} - t.Run("UserOrganizations", func(t *testing.T) { +func TestLoginWithPassword(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _ = coderdtest.CreateInitialUser(t, client) - orgs, err := client.UserOrganizations(context.Background(), "") - require.NoError(t, err) - require.Len(t, orgs, 1) + _, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{}) + require.Error(t, err) }) - t.Run("LogoutIsSuccessful", func(t *testing.T) { + t.Run("Success", func(t *testing.T) { t.Parallel() + client := coderdtest.New(t) + user := coderdtest.CreateInitialUser(t, client) + _, err := client.LoginWithPassword(context.Background(), coderd.LoginWithPasswordRequest{ + Email: user.Email, + Password: user.Password, + }) + require.NoError(t, err) + }) +} + +func TestLogout(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + err := client.Logout(context.Background()) + require.NoError(t, err) +} + +func TestUser(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { + client := coderdtest.New(t) + _, err := client.User(context.Background(), "") + require.Error(t, err) + }) + + t.Run("Get", func(t *testing.T) { client := coderdtest.New(t) _ = coderdtest.CreateInitialUser(t, client) - err := client.Logout(context.Background()) + _, err := client.User(context.Background(), "") require.NoError(t, err) }) +} - t.Run("CreateMultiple", func(t *testing.T) { - t.Parallel() +func TestUserOrganizations(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { + client := coderdtest.New(t) + _, err := client.UserOrganizations(context.Background(), "") + require.Error(t, err) + }) + + t.Run("List", func(t *testing.T) { client := coderdtest.New(t) _ = coderdtest.CreateInitialUser(t, client) - _, err := client.CreateUser(context.Background(), coderd.CreateUserRequest{ - Email: "wow@ok.io", - Username: "example", - Password: "tomato", - }) + _, err := client.UserOrganizations(context.Background(), "") require.NoError(t, err) }) } diff --git a/codersdk/workspaces.go b/codersdk/workspaces.go index d6ddf14f7b082..82c2ce2853c0f 100644 --- a/codersdk/workspaces.go +++ b/codersdk/workspaces.go @@ -15,7 +15,7 @@ import ( // Workspaces returns all workspaces the authenticated session has access to. // If owner is specified, all workspaces for an organization will be returned. // If owner is empty, all workspaces the caller has access to will be returned. -func (c *Client) WorkspacesByUser(ctx context.Context, user string) ([]coderd.Workspace, error) { +func (c *Client) Workspaces(ctx context.Context, user string) ([]coderd.Workspace, error) { route := "/api/v2/workspaces" if user != "" { route += fmt.Sprintf("/%s", user) diff --git a/codersdk/workspaces_test.go b/codersdk/workspaces_test.go index 36de9cbe8a6a3..5ca82e4fbf4f4 100644 --- a/codersdk/workspaces_test.go +++ b/codersdk/workspaces_test.go @@ -3,167 +3,233 @@ package codersdk_test import ( "context" "testing" + "time" - "github.com/google/uuid" "github.com/stretchr/testify/require" "github.com/coder/coder/coderd" "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/database" + "github.com/coder/coder/provisioner/echo" + "github.com/coder/coder/provisionersdk/proto" ) func TestWorkspaces(t *testing.T) { t.Parallel() - t.Run("ListError", func(t *testing.T) { + t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _, err := client.WorkspacesByUser(context.Background(), "") + _, err := client.Workspaces(context.Background(), "") require.Error(t, err) }) - t.Run("ListNoOwner", func(t *testing.T) { + t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _, err := client.WorkspacesByUser(context.Background(), "") + _ = coderdtest.CreateInitialUser(t, client) + _, err := client.Workspaces(context.Background(), "") + require.NoError(t, err) + }) +} + +func TestWorkspacesByProject(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + _, err := client.WorkspacesByProject(context.Background(), "", "") require.Error(t, err) }) - t.Run("ListByUser", func(t *testing.T) { + t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "tomato", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - _, err = client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "wow", - ProjectID: project.ID, - }) - require.NoError(t, err) - _, err = client.WorkspacesByUser(context.Background(), "me") + project := coderdtest.CreateProject(t, client, user.Organization) + _, err := client.WorkspacesByProject(context.Background(), user.Organization, project.Name) require.NoError(t, err) }) +} + +func TestWorkspace(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + _, err := client.Workspace(context.Background(), "", "") + require.Error(t, err) + }) - t.Run("ListByProject", func(t *testing.T) { + t.Run("Get", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "tomato", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - _, err = client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "wow", - ProjectID: project.ID, - }) - require.NoError(t, err) - _, err = client.WorkspacesByProject(context.Background(), user.Organization, project.Name) + project := coderdtest.CreateProject(t, client, user.Organization) + workspace := coderdtest.CreateWorkspace(t, client, "", project.ID) + _, err := client.Workspace(context.Background(), "", workspace.Name) require.NoError(t, err) }) +} - t.Run("ListByProjectError", func(t *testing.T) { +func TestListWorkspaceHistory(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _, err := client.WorkspacesByProject(context.Background(), "", "") + _, err := client.ListWorkspaceHistory(context.Background(), "", "") require.Error(t, err) }) - t.Run("CreateError", func(t *testing.T) { + t.Run("List", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + workspace := coderdtest.CreateWorkspace(t, client, "", project.ID) + _, err := client.ListWorkspaceHistory(context.Background(), "", workspace.Name) + require.NoError(t, err) + }) +} + +func TestWorkspaceHistory(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _, err := client.CreateWorkspace(context.Background(), "no", coderd.CreateWorkspaceRequest{}) + _, err := client.WorkspaceHistory(context.Background(), "", "", "") require.Error(t, err) }) - t.Run("Single", func(t *testing.T) { + t.Run("Get", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "tomato", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - workspace, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "wow", - ProjectID: project.ID, + _ = coderdtest.NewProvisionerDaemon(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "", project.ID) + _, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, + Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) - _, err = client.Workspace(context.Background(), "", workspace.Name) - require.NoError(t, err) }) +} - t.Run("SingleError", func(t *testing.T) { +func TestCreateWorkspace(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _, err := client.Workspace(context.Background(), "", "blob") + _, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{}) require.Error(t, err) }) - t.Run("History", func(t *testing.T) { + t.Run("Get", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "tomato", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - workspace, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "wow", - ProjectID: project.ID, + project := coderdtest.CreateProject(t, client, user.Organization) + _ = coderdtest.CreateWorkspace(t, client, "", project.ID) + }) +} + +func TestCreateWorkspaceHistory(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + _, err := client.CreateWorkspaceHistory(context.Background(), "", "", coderd.CreateWorkspaceHistoryRequest{}) + require.Error(t, err) + }) + + t.Run("Create", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + user := coderdtest.CreateInitialUser(t, client) + _ = coderdtest.NewProvisionerDaemon(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "", project.ID) + _, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, + Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) - _, err = client.ListWorkspaceHistory(context.Background(), "", workspace.Name) - require.NoError(t, err) }) +} - t.Run("HistoryError", func(t *testing.T) { +func TestWorkspaceHistoryLogs(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) - _, err := client.ListWorkspaceHistory(context.Background(), "", "blob") + _, err := client.WorkspaceHistoryLogs(context.Background(), "", "", "") require.Error(t, err) }) - t.Run("LatestHistory", func(t *testing.T) { + t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "tomato", - Provisioner: database.ProvisionerTypeEcho, + _ = coderdtest.NewProvisionerDaemon(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, nil) + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "", project.ID) + history, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, + Transition: database.WorkspaceTransitionCreate, }) require.NoError(t, err) - workspace, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "wow", - ProjectID: project.ID, - }) + _, err = client.WorkspaceHistoryLogs(context.Background(), "", workspace.Name, history.Name) require.NoError(t, err) - _, err = client.WorkspaceHistory(context.Background(), "", workspace.Name, "") + }) +} + +func TestFollowWorkspaceHistoryLogsAfter(t *testing.T) { + t.Parallel() + t.Run("Error", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + _, err := client.FollowWorkspaceHistoryLogsAfter(context.Background(), "", "", "", time.Time{}) require.Error(t, err) }) - t.Run("CreateHistory", func(t *testing.T) { + t.Run("Stream", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) - project, err := client.CreateProject(context.Background(), user.Organization, coderd.CreateProjectRequest{ - Name: "tomato", - Provisioner: database.ProvisionerTypeEcho, - }) - require.NoError(t, err) - workspace, err := client.CreateWorkspace(context.Background(), "", coderd.CreateWorkspaceRequest{ - Name: "wow", - ProjectID: project.ID, + _ = coderdtest.NewProvisionerDaemon(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, &echo.Responses{ + Parse: echo.ParseComplete, + Provision: []*proto.Provision_Response{{ + Type: &proto.Provision_Response_Log{ + Log: &proto.Log{ + Output: "hello", + }, + }, + }, { + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{}, + }, + }}, }) - require.NoError(t, err) - _, err = client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectVersionID: uuid.New(), + coderdtest.AwaitProjectVersionImported(t, client, user.Organization, project.Name, version.Name) + workspace := coderdtest.CreateWorkspace(t, client, "", project.ID) + history, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ + ProjectVersionID: version.ID, Transition: database.WorkspaceTransitionCreate, }) - require.Error(t, err) + require.NoError(t, err) + logs, err := client.FollowWorkspaceHistoryLogsAfter(context.Background(), "", workspace.Name, history.Name, time.Time{}) + require.NoError(t, err) + _, ok := <-logs + require.True(t, ok) + _, ok = <-logs + require.False(t, ok) }) } From ca31d901f7dfb55cc49531256bf8870e4074153a Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 20:17:31 +0000 Subject: [PATCH 11/16] Fix linting errors --- codersdk/provisioners_test.go | 6 +++++- codersdk/users_test.go | 4 ++++ provisionerd/provisionerd.go | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/codersdk/provisioners_test.go b/codersdk/provisioners_test.go index e373a921c29a2..9bb4528ebec1e 100644 --- a/codersdk/provisioners_test.go +++ b/codersdk/provisioners_test.go @@ -4,14 +4,16 @@ import ( "context" "testing" + "github.com/stretchr/testify/require" + "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/provisionerd/proto" - "github.com/stretchr/testify/require" ) func TestProvisionerDaemons(t *testing.T) { t.Parallel() t.Run("Get", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t) _, err := client.ProvisionerDaemons(context.Background()) require.NoError(t, err) @@ -21,6 +23,7 @@ func TestProvisionerDaemons(t *testing.T) { func TestProvisionerDaemonClient(t *testing.T) { t.Parallel() t.Run("Error", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t) ctx, cancelFunc := context.WithCancel(context.Background()) daemon, err := client.ProvisionerDaemonClient(ctx) @@ -31,6 +34,7 @@ func TestProvisionerDaemonClient(t *testing.T) { }) t.Run("Connect", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t) ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() diff --git a/codersdk/users_test.go b/codersdk/users_test.go index d24b955a0c0cd..3425c9204f3ca 100644 --- a/codersdk/users_test.go +++ b/codersdk/users_test.go @@ -79,12 +79,14 @@ func TestLogout(t *testing.T) { func TestUser(t *testing.T) { t.Parallel() t.Run("Error", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t) _, err := client.User(context.Background(), "") require.Error(t, err) }) t.Run("Get", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t) _ = coderdtest.CreateInitialUser(t, client) _, err := client.User(context.Background(), "") @@ -95,12 +97,14 @@ func TestUser(t *testing.T) { func TestUserOrganizations(t *testing.T) { t.Parallel() t.Run("Error", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t) _, err := client.UserOrganizations(context.Background(), "") require.Error(t, err) }) t.Run("List", func(t *testing.T) { + t.Parallel() client := coderdtest.New(t) _ = coderdtest.CreateInitialUser(t, client) _, err := client.UserOrganizations(context.Background(), "") diff --git a/provisionerd/provisionerd.go b/provisionerd/provisionerd.go index b0e8d7c198de5..315c746848b99 100644 --- a/provisionerd/provisionerd.go +++ b/provisionerd/provisionerd.go @@ -488,7 +488,7 @@ func (p *provisionerDaemon) cancelActiveJobf(format string, args ...interface{}) return } if p.jobCancelled.Load() { - p.opts.Logger.Warn(context.Background(), "job has already been cancelled", slog.F("error_messsage", errMsg)) + p.opts.Logger.Warn(context.Background(), "job has already been canceled", slog.F("error_messsage", errMsg)) return } p.jobCancelled.Store(true) From 673c59d87e9637f4ff5eb01d5027b6541e4227c4 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 20:28:18 +0000 Subject: [PATCH 12/16] Fix WebSocket compression --- coderd/provisionerdaemons.go | 2 +- codersdk/provisioners.go | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index 00880074af473..f6d616383ab1a 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -53,7 +53,7 @@ func (api *api) provisionerDaemons(rw http.ResponseWriter, r *http.Request) { // Serves the provisioner daemon protobuf API over a WebSocket. func (api *api) provisionerDaemonsServe(rw http.ResponseWriter, r *http.Request) { conn, err := websocket.Accept(rw, r, &websocket.AcceptOptions{ - // Need to disable compression to avoid a data-race + // Need to disable compression to avoid a data-race. CompressionMode: websocket.CompressionDisabled, }) if err != nil { diff --git a/codersdk/provisioners.go b/codersdk/provisioners.go index e0ebf5f56f1c9..5f96271a4218d 100644 --- a/codersdk/provisioners.go +++ b/codersdk/provisioners.go @@ -36,6 +36,8 @@ func (c *Client) ProvisionerDaemonClient(ctx context.Context) (proto.DRPCProvisi } conn, res, err := websocket.Dial(ctx, serverURL.String(), &websocket.DialOptions{ HTTPClient: c.httpClient, + // Need to disable compression to avoid a data-race. + CompressionMode: websocket.CompressionDisabled, }) if err != nil { if res == nil { From aad577f1104b9f21f87fecafc401042721806d5f Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 14:47:10 -0600 Subject: [PATCH 13/16] Update coderd/workspaces.go Co-authored-by: Bryan --- coderd/workspaces.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 733741512baea..4ea1ba2706202 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -137,7 +137,7 @@ func (api *api) postWorkspaceByUser(rw http.ResponseWriter, r *http.Request) { render.JSON(rw, r, convertWorkspace(workspace)) } -// Returns a single single workspace. +// Returns a single workspace. func (*api) workspaceByUser(rw http.ResponseWriter, r *http.Request) { workspace := httpmw.WorkspaceParam(r) From 6c39920b0495d203064eae5b17ed7efca573455b Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 20:55:59 +0000 Subject: [PATCH 14/16] Add test for listing project parameters --- coderd/coderd_test.go | 11 +++++++++++ coderd/projects_test.go | 19 +++++++++++++++++++ codersdk/client.go | 8 +++++--- provisioner/echo/serve_test.go | 8 ++++++-- provisionersdk/serve_test.go | 1 + rules.go | 10 +++++++--- 6 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 coderd/coderd_test.go diff --git a/coderd/coderd_test.go b/coderd/coderd_test.go new file mode 100644 index 0000000000000..ef360326b1d8e --- /dev/null +++ b/coderd/coderd_test.go @@ -0,0 +1,11 @@ +package coderd_test + +import ( + "testing" + + "go.uber.org/goleak" +) + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} diff --git a/coderd/projects_test.go b/coderd/projects_test.go index 7f68182f95d26..5788f66647543 100644 --- a/coderd/projects_test.go +++ b/coderd/projects_test.go @@ -116,13 +116,32 @@ func TestPostParametersByProject(t *testing.T) { func TestParametersByProject(t *testing.T) { t.Parallel() + t.Run("ListEmpty", func(t *testing.T) { + t.Parallel() + client := coderdtest.New(t) + user := coderdtest.CreateInitialUser(t, client) + project := coderdtest.CreateProject(t, client, user.Organization) + params, err := client.ProjectParameters(context.Background(), user.Organization, project.Name) + require.NoError(t, err) + require.NotNil(t, params) + }) + t.Run("List", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) user := coderdtest.CreateInitialUser(t, client) project := coderdtest.CreateProject(t, client, user.Organization) + _, err := client.CreateProjectParameter(context.Background(), user.Organization, project.Name, coderd.CreateParameterValueRequest{ + Name: "example", + SourceValue: "source-value", + SourceScheme: database.ParameterSourceSchemeData, + DestinationScheme: database.ParameterDestinationSchemeEnvironmentVariable, + DestinationValue: "destination-value", + }) + require.NoError(t, err) params, err := client.ProjectParameters(context.Background(), user.Organization, project.Name) require.NoError(t, err) require.NotNil(t, params) + require.Len(t, params, 1) }) } diff --git a/codersdk/client.go b/codersdk/client.go index e5684f669c809..4bd5a111cb949 100644 --- a/codersdk/client.go +++ b/codersdk/client.go @@ -10,6 +10,7 @@ import ( "net/http" "net/http/cookiejar" "net/url" + "strings" "golang.org/x/xerrors" @@ -113,9 +114,10 @@ func (e *Error) StatusCode() int { } func (e *Error) Error() string { - msg := fmt.Sprintf("status code %d: %s", e.statusCode, e.Message) + var builder strings.Builder + _, _ = fmt.Fprintf(&builder, "status code %d: %s", e.statusCode, e.Message) for _, err := range e.Errors { - msg += fmt.Sprintf("\n\t%s: %s", err.Field, err.Code) + _, _ = fmt.Fprintf(&builder, "\n\t%s: %s", err.Field, err.Code) } - return msg + return builder.String() } diff --git a/provisioner/echo/serve_test.go b/provisioner/echo/serve_test.go index 48ca00e11d94d..adf8cced81a90 100644 --- a/provisioner/echo/serve_test.go +++ b/provisioner/echo/serve_test.go @@ -53,7 +53,9 @@ func TestEcho(t *testing.T) { }, }, }} - data, err := echo.Tar(&echo.Responses{responses, nil}) + data, err := echo.Tar(&echo.Responses{ + Parse: responses, + }) require.NoError(t, err) client, err := api.Parse(ctx, &proto.Parse_Request{ Directory: unpackTar(t, data), @@ -86,7 +88,9 @@ func TestEcho(t *testing.T) { }, }, }} - data, err := echo.Tar(&echo.Responses{nil, responses}) + data, err := echo.Tar(&echo.Responses{ + Provision: responses, + }) require.NoError(t, err) client, err := api.Provision(ctx, &proto.Provision_Request{ Directory: unpackTar(t, data), diff --git a/provisionersdk/serve_test.go b/provisionersdk/serve_test.go index cf2dd7517df82..601fdc7ea11df 100644 --- a/provisionersdk/serve_test.go +++ b/provisionersdk/serve_test.go @@ -39,6 +39,7 @@ func TestProvisionerSDK(t *testing.T) { _, err = stream.Recv() require.Equal(t, drpcerr.Unimplemented, int(drpcerr.Code(err))) }) + t.Run("ServeClosedPipe", func(t *testing.T) { t.Parallel() client, server := provisionersdk.TransportPipe() diff --git a/rules.go b/rules.go index d8b7db0844720..7a95c89e016ed 100644 --- a/rules.go +++ b/rules.go @@ -10,14 +10,18 @@ func xerrors(m dsl.Matcher) { m.Import("errors") m.Import("fmt") m.Import("golang.org/x/xerrors") + msg := "Use xerrors to provide additional stacktrace information!" m.Match("fmt.Errorf($*args)"). - Suggest("xerrors.New($args)") + Suggest("xerrors.New($args)"). + Report(msg) m.Match("fmt.Errorf($*args)"). - Suggest("xerrors.Errorf($args)") + Suggest("xerrors.Errorf($args)"). + Report(msg) m.Match("errors.New($msg)"). Where(m["msg"].Type.Is("string")). - Suggest("xerrors.New($msg)") + Suggest("xerrors.New($msg)"). + Report(msg) } From a4d17d0dbd295a2a407f4b740c9dbef94ce73b79 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 21:35:25 +0000 Subject: [PATCH 15/16] Cache npm dependencies with setup node --- .github/workflows/coder.yaml | 6 ++++-- coderd/workspacehistory_test.go | 20 -------------------- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/.github/workflows/coder.yaml b/.github/workflows/coder.yaml index 8b29a3861f871..dc477222695b4 100644 --- a/.github/workflows/coder.yaml +++ b/.github/workflows/coder.yaml @@ -165,18 +165,20 @@ jobs: -covermode=atomic -coverprofile="gotests.coverage" -timeout=3m -count=1 -race -parallel=2 - - uses: actions/setup-node@v2 + - name: Setup Node for DataDog CLI + uses: actions/setup-node@v2 if: always() && github.actor != 'dependabot[bot]' with: node-version: "14" - - name: Cache DataDog CI + - name: Cache DataDog CLI if: always() && github.actor != 'dependabot[bot]' uses: actions/cache@v2 with: path: | ~/.npm %LocalAppData%\npm-cache + C:\npm key: datadogci- restore-keys: datadogci- diff --git a/coderd/workspacehistory_test.go b/coderd/workspacehistory_test.go index 794da40a7ab18..b7ef8855264fb 100644 --- a/coderd/workspacehistory_test.go +++ b/coderd/workspacehistory_test.go @@ -34,26 +34,6 @@ func TestPostWorkspaceHistoryByUser(t *testing.T) { require.Equal(t, http.StatusBadRequest, apiErr.StatusCode()) }) - t.Run("ProjectVersionImporting", func(t *testing.T) { - t.Parallel() - client := coderdtest.New(t) - user := coderdtest.CreateInitialUser(t, client) - coderdtest.NewProvisionerDaemon(t, client) - project := coderdtest.CreateProject(t, client, user.Organization) - workspace := coderdtest.CreateWorkspace(t, client, "me", project.ID) - version := coderdtest.CreateProjectVersion(t, client, user.Organization, project.Name, &echo.Responses{ - Provision: []*proto.Provision_Response{{}}, - }) - _, err := client.CreateWorkspaceHistory(context.Background(), "", workspace.Name, coderd.CreateWorkspaceHistoryRequest{ - ProjectVersionID: version.ID, - Transition: database.WorkspaceTransitionCreate, - }) - require.Error(t, err) - var apiErr *codersdk.Error - require.ErrorAs(t, err, &apiErr) - require.Equal(t, http.StatusNotAcceptable, apiErr.StatusCode()) - }) - t.Run("ProjectVersionFailedImport", func(t *testing.T) { t.Parallel() client := coderdtest.New(t) From a8a05316cd2248c9d8e70622124b821a154a72b0 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 5 Feb 2022 23:10:08 +0000 Subject: [PATCH 16/16] Remove windows npm cache key --- .github/workflows/coder.yaml | 1 - provisionerd/provisionerd.go | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/coder.yaml b/.github/workflows/coder.yaml index dc477222695b4..22c7583290147 100644 --- a/.github/workflows/coder.yaml +++ b/.github/workflows/coder.yaml @@ -178,7 +178,6 @@ jobs: path: | ~/.npm %LocalAppData%\npm-cache - C:\npm key: datadogci- restore-keys: datadogci- diff --git a/provisionerd/provisionerd.go b/provisionerd/provisionerd.go index 315c746848b99..78f8c40f4c374 100644 --- a/provisionerd/provisionerd.go +++ b/provisionerd/provisionerd.go @@ -484,6 +484,9 @@ func (p *provisionerDaemon) cancelActiveJobf(format string, args ...interface{}) defer p.jobMutex.Unlock() errMsg := fmt.Sprintf(format, args...) if !p.isRunningJob() { + if p.isClosed() { + return + } p.opts.Logger.Info(context.Background(), "skipping job cancel; none running", slog.F("error_message", errMsg)) return }