diff --git a/coderd/coderdtest/authorize.go b/coderd/coderdtest/authorize.go index c10f954140ea5..af52f7fc70f53 100644 --- a/coderd/coderdtest/authorize.go +++ b/coderd/coderdtest/authorize.go @@ -358,6 +358,7 @@ func (s *PreparedRecorder) CompileToSQL(ctx context.Context, cfg regosql.Convert // Meaning 'FakeAuthorizer' by default will never return "unauthorized". type FakeAuthorizer struct { ConditionalReturn func(context.Context, rbac.Subject, policy.Action, rbac.Object) error + sqlFilter string } var _ rbac.Authorizer = (*FakeAuthorizer)(nil) @@ -370,6 +371,12 @@ func (d *FakeAuthorizer) AlwaysReturn(err error) *FakeAuthorizer { return d } +// OverrideSQLFilter sets the SQL filter that will always be returned by CompileToSQL. +func (d *FakeAuthorizer) OverrideSQLFilter(filter string) *FakeAuthorizer { + d.sqlFilter = filter + return d +} + func (d *FakeAuthorizer) Authorize(ctx context.Context, subject rbac.Subject, action policy.Action, object rbac.Object) error { if d.ConditionalReturn != nil { return d.ConditionalReturn(ctx, subject, action, object) @@ -400,10 +407,12 @@ func (f *fakePreparedAuthorizer) Authorize(ctx context.Context, object rbac.Obje return f.Original.Authorize(ctx, f.Subject, f.Action, object) } -// CompileToSQL returns a compiled version of the authorizer that will work for -// in memory databases. This fake version will not work against a SQL database. -func (*fakePreparedAuthorizer) CompileToSQL(_ context.Context, _ regosql.ConvertConfig) (string, error) { - return "not a valid sql string", nil +func (f *fakePreparedAuthorizer) CompileToSQL(_ context.Context, _ regosql.ConvertConfig) (string, error) { + if f.Original.sqlFilter != "" { + return f.Original.sqlFilter, nil + } + // By default, allow all SQL queries. + return "TRUE", nil } // Random rbac helper funcs diff --git a/coderd/coderdtest/authorize_test.go b/coderd/coderdtest/authorize_test.go index 5cdcd26869cf3..75f9a5d843481 100644 --- a/coderd/coderdtest/authorize_test.go +++ b/coderd/coderdtest/authorize_test.go @@ -44,7 +44,7 @@ func TestAuthzRecorder(t *testing.T) { require.NoError(t, rec.AllAsserted(), "all assertions should have been made") }) - t.Run("Authorize&Prepared", func(t *testing.T) { + t.Run("Authorize_Prepared", func(t *testing.T) { t.Parallel() rec := &coderdtest.RecordingAuthorizer{ diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index f64dbcc166591..0a35667ed0178 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -8,6 +8,7 @@ import ( "fmt" "strings" "sync/atomic" + "testing" "time" "github.com/google/uuid" @@ -1366,6 +1367,13 @@ func (q *querier) DeleteWorkspaceAgentPortSharesByTemplate(ctx context.Context, return q.db.DeleteWorkspaceAgentPortSharesByTemplate(ctx, templateID) } +func (q *querier) DisableForeignKeysAndTriggers(ctx context.Context) error { + if !testing.Testing() { + return xerrors.Errorf("DisableForeignKeysAndTriggers is only allowed in tests") + } + return q.db.DisableForeignKeysAndTriggers(ctx) +} + func (q *querier) EnqueueNotificationMessage(ctx context.Context, arg database.EnqueueNotificationMessageParams) error { if err := q.authorizeContext(ctx, policy.ActionCreate, rbac.ResourceNotificationMessage); err != nil { return err diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 48adbdb576201..93e9a4318d1ed 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -4,18 +4,22 @@ import ( "context" "database/sql" "encoding/json" + "fmt" + "net" "reflect" "strings" "testing" "time" "github.com/google/uuid" + "github.com/sqlc-dev/pqtype" "github.com/stretchr/testify/require" "golang.org/x/xerrors" "cdr.dev/slog" "github.com/coder/coder/v2/coderd/database/db2sdk" + "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/notifications" "github.com/coder/coder/v2/coderd/rbac/policy" "github.com/coder/coder/v2/codersdk" @@ -24,7 +28,7 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/database/dbgen" - "github.com/coder/coder/v2/coderd/database/dbmem" + "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/database/dbtime" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/coderd/util/slice" @@ -70,7 +74,8 @@ func TestAsNoActor(t *testing.T) { func TestPing(t *testing.T) { t.Parallel() - q := dbauthz.New(dbmem.New(), &coderdtest.RecordingAuthorizer{}, slog.Make(), coderdtest.AccessControlStorePointer()) + db, _ := dbtestutil.NewDB(t) + q := dbauthz.New(db, &coderdtest.RecordingAuthorizer{}, slog.Make(), coderdtest.AccessControlStorePointer()) _, err := q.Ping(context.Background()) require.NoError(t, err, "must not error") } @@ -79,7 +84,7 @@ func TestPing(t *testing.T) { func TestInTX(t *testing.T) { t.Parallel() - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) q := dbauthz.New(db, &coderdtest.RecordingAuthorizer{ Wrapped: (&coderdtest.FakeAuthorizer{}).AlwaysReturn(xerrors.New("custom error")), }, slog.Make(), coderdtest.AccessControlStorePointer()) @@ -89,8 +94,17 @@ func TestInTX(t *testing.T) { Groups: []string{}, Scope: rbac.ScopeAll, } - - w := dbgen.Workspace(t, db, database.WorkspaceTable{}) + u := dbgen.User(t, db, database.User{}) + o := dbgen.Organization(t, db, database.Organization{}) + tpl := dbgen.Template(t, db, database.Template{ + CreatedBy: u.ID, + OrganizationID: o.ID, + }) + w := dbgen.Workspace(t, db, database.WorkspaceTable{ + OwnerID: u.ID, + TemplateID: tpl.ID, + OrganizationID: o.ID, + }) ctx := dbauthz.As(context.Background(), actor) err := q.InTx(func(tx database.Store) error { // The inner tx should use the parent's authz @@ -107,15 +121,24 @@ func TestNew(t *testing.T) { t.Parallel() var ( - db = dbmem.New() - exp = dbgen.Workspace(t, db, database.WorkspaceTable{}) - rec = &coderdtest.RecordingAuthorizer{ + db, _ = dbtestutil.NewDB(t) + rec = &coderdtest.RecordingAuthorizer{ Wrapped: &coderdtest.FakeAuthorizer{}, } subj = rbac.Subject{} ctx = dbauthz.As(context.Background(), rbac.Subject{}) ) - + u := dbgen.User(t, db, database.User{}) + org := dbgen.Organization(t, db, database.Organization{}) + tpl := dbgen.Template(t, db, database.Template{ + OrganizationID: org.ID, + CreatedBy: u.ID, + }) + exp := dbgen.Workspace(t, db, database.WorkspaceTable{ + OwnerID: u.ID, + OrganizationID: org.ID, + TemplateID: tpl.ID, + }) // Double wrap should not cause an actual double wrap. So only 1 rbac call // should be made. az := dbauthz.New(db, rec, slog.Make(), coderdtest.AccessControlStorePointer()) @@ -134,7 +157,8 @@ func TestNew(t *testing.T) { // as only the first db call will be made. But it is better than nothing. func TestDBAuthzRecursive(t *testing.T) { t.Parallel() - q := dbauthz.New(dbmem.New(), &coderdtest.RecordingAuthorizer{ + db, _ := dbtestutil.NewDB(t) + q := dbauthz.New(db, &coderdtest.RecordingAuthorizer{ Wrapped: &coderdtest.FakeAuthorizer{}, }, slog.Make(), coderdtest.AccessControlStorePointer()) actor := rbac.Subject{ @@ -173,16 +197,29 @@ func must[T any](value T, err error) T { return value } +func defaultIPAddress() pqtype.Inet { + return pqtype.Inet{ + IPNet: net.IPNet{ + IP: net.IPv4(127, 0, 0, 1), + Mask: net.IPv4Mask(255, 255, 255, 255), + }, + Valid: true, + } +} + func (s *MethodTestSuite) TestAPIKey() { s.Run("DeleteAPIKeyByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) key, _ := dbgen.APIKey(s.T(), db, database.APIKey{}) check.Args(key.ID).Asserts(key, policy.ActionDelete).Returns() })) s.Run("GetAPIKeyByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) key, _ := dbgen.APIKey(s.T(), db, database.APIKey{}) check.Args(key.ID).Asserts(key, policy.ActionRead).Returns(key) })) s.Run("GetAPIKeyByName", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) key, _ := dbgen.APIKey(s.T(), db, database.APIKey{ TokenName: "marge-cat", LoginType: database.LoginTypeToken, @@ -193,6 +230,7 @@ func (s *MethodTestSuite) TestAPIKey() { }).Asserts(key, policy.ActionRead).Returns(key) })) s.Run("GetAPIKeysByLoginType", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) a, _ := dbgen.APIKey(s.T(), db, database.APIKey{LoginType: database.LoginTypePassword}) b, _ := dbgen.APIKey(s.T(), db, database.APIKey{LoginType: database.LoginTypePassword}) _, _ = dbgen.APIKey(s.T(), db, database.APIKey{LoginType: database.LoginTypeGithub}) @@ -201,18 +239,19 @@ func (s *MethodTestSuite) TestAPIKey() { Returns(slice.New(a, b)) })) s.Run("GetAPIKeysByUserID", s.Subtest(func(db database.Store, check *expects) { - idAB := uuid.New() - idC := uuid.New() + u1 := dbgen.User(s.T(), db, database.User{}) + u2 := dbgen.User(s.T(), db, database.User{}) - keyA, _ := dbgen.APIKey(s.T(), db, database.APIKey{UserID: idAB, LoginType: database.LoginTypeToken}) - keyB, _ := dbgen.APIKey(s.T(), db, database.APIKey{UserID: idAB, LoginType: database.LoginTypeToken}) - _, _ = dbgen.APIKey(s.T(), db, database.APIKey{UserID: idC, LoginType: database.LoginTypeToken}) + keyA, _ := dbgen.APIKey(s.T(), db, database.APIKey{UserID: u1.ID, LoginType: database.LoginTypeToken, TokenName: "key-a"}) + keyB, _ := dbgen.APIKey(s.T(), db, database.APIKey{UserID: u1.ID, LoginType: database.LoginTypeToken, TokenName: "key-b"}) + _, _ = dbgen.APIKey(s.T(), db, database.APIKey{UserID: u2.ID, LoginType: database.LoginTypeToken}) - check.Args(database.GetAPIKeysByUserIDParams{LoginType: database.LoginTypeToken, UserID: idAB}). + check.Args(database.GetAPIKeysByUserIDParams{LoginType: database.LoginTypeToken, UserID: u1.ID}). Asserts(keyA, policy.ActionRead, keyB, policy.ActionRead). Returns(slice.New(keyA, keyB)) })) s.Run("GetAPIKeysLastUsedAfter", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) a, _ := dbgen.APIKey(s.T(), db, database.APIKey{LastUsed: time.Now().Add(time.Hour)}) b, _ := dbgen.APIKey(s.T(), db, database.APIKey{LastUsed: time.Now().Add(time.Hour)}) _, _ = dbgen.APIKey(s.T(), db, database.APIKey{LastUsed: time.Now().Add(-time.Hour)}) @@ -222,19 +261,26 @@ func (s *MethodTestSuite) TestAPIKey() { })) s.Run("InsertAPIKey", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) + check.Args(database.InsertAPIKeyParams{ UserID: u.ID, LoginType: database.LoginTypePassword, Scope: database.APIKeyScopeAll, + IPAddress: defaultIPAddress(), }).Asserts(rbac.ResourceApiKey.WithOwner(u.ID.String()), policy.ActionCreate) })) s.Run("UpdateAPIKeyByID", s.Subtest(func(db database.Store, check *expects) { - a, _ := dbgen.APIKey(s.T(), db, database.APIKey{}) + u := dbgen.User(s.T(), db, database.User{}) + a, _ := dbgen.APIKey(s.T(), db, database.APIKey{UserID: u.ID, IPAddress: defaultIPAddress()}) check.Args(database.UpdateAPIKeyByIDParams{ - ID: a.ID, + ID: a.ID, + IPAddress: defaultIPAddress(), + LastUsed: time.Now(), + ExpiresAt: time.Now().Add(time.Hour), }).Asserts(a, policy.ActionUpdate).Returns() })) s.Run("DeleteApplicationConnectAPIKeysByUserID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) a, _ := dbgen.APIKey(s.T(), db, database.APIKey{ Scope: database.APIKeyScopeApplicationConnect, }) @@ -261,8 +307,10 @@ func (s *MethodTestSuite) TestAPIKey() { func (s *MethodTestSuite) TestAuditLogs() { s.Run("InsertAuditLog", s.Subtest(func(db database.Store, check *expects) { check.Args(database.InsertAuditLogParams{ - ResourceType: database.ResourceTypeOrganization, - Action: database.AuditActionCreate, + ResourceType: database.ResourceTypeOrganization, + Action: database.AuditActionCreate, + Diff: json.RawMessage("{}"), + AdditionalFields: json.RawMessage("{}"), }).Asserts(rbac.ResourceAuditLog, policy.ActionCreate) })) s.Run("GetAuditLogsOffset", s.Subtest(func(db database.Store, check *expects) { @@ -270,9 +318,10 @@ func (s *MethodTestSuite) TestAuditLogs() { _ = dbgen.AuditLog(s.T(), db, database.AuditLog{}) check.Args(database.GetAuditLogsOffsetParams{ LimitOpt: 10, - }).Asserts(rbac.ResourceAuditLog, policy.ActionRead) + }).Asserts(rbac.ResourceAuditLog, policy.ActionRead).WithNotAuthorized("nil") })) s.Run("GetAuthorizedAuditLogsOffset", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) _ = dbgen.AuditLog(s.T(), db, database.AuditLog{}) _ = dbgen.AuditLog(s.T(), db, database.AuditLog{}) check.Args(database.GetAuditLogsOffsetParams{ @@ -303,10 +352,12 @@ func (s *MethodTestSuite) TestFile() { func (s *MethodTestSuite) TestGroup() { s.Run("DeleteGroupByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) g := dbgen.Group(s.T(), db, database.Group{}) check.Args(g.ID).Asserts(g, policy.ActionDelete).Returns() })) s.Run("DeleteGroupMemberFromGroup", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) g := dbgen.Group(s.T(), db, database.Group{}) u := dbgen.User(s.T(), db, database.User{}) m := dbgen.GroupMember(s.T(), db, database.GroupMemberTable{ @@ -319,10 +370,12 @@ func (s *MethodTestSuite) TestGroup() { }).Asserts(g, policy.ActionUpdate).Returns() })) s.Run("GetGroupByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) g := dbgen.Group(s.T(), db, database.Group{}) check.Args(g.ID).Asserts(g, policy.ActionRead).Returns(g) })) s.Run("GetGroupByOrgAndName", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) g := dbgen.Group(s.T(), db, database.Group{}) check.Args(database.GetGroupByOrgAndNameParams{ OrganizationID: g.OrganizationID, @@ -330,28 +383,33 @@ func (s *MethodTestSuite) TestGroup() { }).Asserts(g, policy.ActionRead).Returns(g) })) s.Run("GetGroupMembersByGroupID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) g := dbgen.Group(s.T(), db, database.Group{}) u := dbgen.User(s.T(), db, database.User{}) gm := dbgen.GroupMember(s.T(), db, database.GroupMemberTable{GroupID: g.ID, UserID: u.ID}) check.Args(g.ID).Asserts(gm, policy.ActionRead) })) s.Run("GetGroupMembersCountByGroupID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) g := dbgen.Group(s.T(), db, database.Group{}) check.Args(g.ID).Asserts(g, policy.ActionRead) })) s.Run("GetGroupMembers", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) g := dbgen.Group(s.T(), db, database.Group{}) u := dbgen.User(s.T(), db, database.User{}) dbgen.GroupMember(s.T(), db, database.GroupMemberTable{GroupID: g.ID, UserID: u.ID}) check.Asserts(rbac.ResourceSystem, policy.ActionRead) })) s.Run("System/GetGroups", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) _ = dbgen.Group(s.T(), db, database.Group{}) check.Args(database.GetGroupsParams{}). Asserts(rbac.ResourceSystem, policy.ActionRead) })) s.Run("GetGroups", s.Subtest(func(db database.Store, check *expects) { - g := dbgen.Group(s.T(), db, database.Group{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + g := dbgen.Group(s.T(), db, database.Group{OrganizationID: o.ID}) u := dbgen.User(s.T(), db, database.User{}) gm := dbgen.GroupMember(s.T(), db, database.GroupMemberTable{GroupID: g.ID, UserID: u.ID}) check.Args(database.GetGroupsParams{ @@ -373,6 +431,7 @@ func (s *MethodTestSuite) TestGroup() { }).Asserts(rbac.ResourceGroup.InOrg(o.ID), policy.ActionCreate) })) s.Run("InsertGroupMember", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) g := dbgen.Group(s.T(), db, database.Group{}) check.Args(database.InsertGroupMemberParams{ UserID: uuid.New(), @@ -384,7 +443,6 @@ func (s *MethodTestSuite) TestGroup() { u1 := dbgen.User(s.T(), db, database.User{}) g1 := dbgen.Group(s.T(), db, database.Group{OrganizationID: o.ID}) g2 := dbgen.Group(s.T(), db, database.Group{OrganizationID: o.ID}) - _ = dbgen.GroupMember(s.T(), db, database.GroupMemberTable{GroupID: g1.ID, UserID: u1.ID}) check.Args(database.InsertUserGroupsByNameParams{ OrganizationID: o.ID, UserID: u1.ID, @@ -396,11 +454,16 @@ func (s *MethodTestSuite) TestGroup() { u1 := dbgen.User(s.T(), db, database.User{}) g1 := dbgen.Group(s.T(), db, database.Group{OrganizationID: o.ID}) g2 := dbgen.Group(s.T(), db, database.Group{OrganizationID: o.ID}) + g3 := dbgen.Group(s.T(), db, database.Group{OrganizationID: o.ID}) _ = dbgen.GroupMember(s.T(), db, database.GroupMemberTable{GroupID: g1.ID, UserID: u1.ID}) + returns := slice.New(g2.ID, g3.ID) + if !dbtestutil.WillUsePostgres() { + returns = slice.New(g1.ID, g2.ID, g3.ID) + } check.Args(database.InsertUserGroupsByIDParams{ UserID: u1.ID, - GroupIds: slice.New(g1.ID, g2.ID), - }).Asserts(rbac.ResourceSystem, policy.ActionUpdate).Returns(slice.New(g1.ID, g2.ID)) + GroupIds: slice.New(g1.ID, g2.ID, g3.ID), + }).Asserts(rbac.ResourceSystem, policy.ActionUpdate).Returns(returns) })) s.Run("RemoveUserFromAllGroups", s.Subtest(func(db database.Store, check *expects) { o := dbgen.Organization(s.T(), db, database.Organization{}) @@ -424,6 +487,7 @@ func (s *MethodTestSuite) TestGroup() { }).Asserts(rbac.ResourceSystem, policy.ActionUpdate).Returns(slice.New(g1.ID, g2.ID)) })) s.Run("UpdateGroupByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) g := dbgen.Group(s.T(), db, database.Group{}) check.Args(database.UpdateGroupByIDParams{ ID: g.ID, @@ -433,6 +497,7 @@ func (s *MethodTestSuite) TestGroup() { func (s *MethodTestSuite) TestProvisionerJob() { s.Run("ArchiveUnusedTemplateVersions", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeTemplateVersionImport, Error: sql.NullString{ @@ -453,6 +518,7 @@ func (s *MethodTestSuite) TestProvisionerJob() { }).Asserts(v.RBACObject(tpl), policy.ActionUpdate) })) s.Run("UnarchiveTemplateVersion", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeTemplateVersionImport, }) @@ -468,14 +534,35 @@ func (s *MethodTestSuite) TestProvisionerJob() { }).Asserts(v.RBACObject(tpl), policy.ActionUpdate) })) s.Run("Build/GetProvisionerJobByID", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + OwnerID: u.ID, + OrganizationID: o.ID, + TemplateID: tpl.ID, + }) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeWorkspaceBuild, }) - _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{JobID: j.ID, WorkspaceID: w.ID}) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + JobID: j.ID, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) check.Args(j.ID).Asserts(w, policy.ActionRead).Returns(j) })) s.Run("TemplateVersion/GetProvisionerJobByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeTemplateVersionImport, }) @@ -487,6 +574,7 @@ func (s *MethodTestSuite) TestProvisionerJob() { check.Args(j.ID).Asserts(v.RBACObject(tpl), policy.ActionRead).Returns(j) })) s.Run("TemplateVersionDryRun/GetProvisionerJobByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) tpl := dbgen.Template(s.T(), db, database.Template{}) v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, @@ -500,24 +588,59 @@ func (s *MethodTestSuite) TestProvisionerJob() { check.Args(j.ID).Asserts(v.RBACObject(tpl), policy.ActionRead).Returns(j) })) s.Run("Build/UpdateProvisionerJobWithCancelByID", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{AllowUserCancelWorkspaceJobs: true}) - w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{TemplateID: tpl.ID}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + AllowUserCancelWorkspaceJobs: true, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeWorkspaceBuild, }) - _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{JobID: j.ID, WorkspaceID: w.ID}) + _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) check.Args(database.UpdateProvisionerJobWithCancelByIDParams{ID: j.ID}).Asserts(w, policy.ActionUpdate).Returns() })) s.Run("BuildFalseCancel/UpdateProvisionerJobWithCancelByID", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{AllowUserCancelWorkspaceJobs: false}) - w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{TemplateID: tpl.ID}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + AllowUserCancelWorkspaceJobs: false, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{TemplateID: tpl.ID, OrganizationID: o.ID, OwnerID: u.ID}) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeWorkspaceBuild, }) - _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{JobID: j.ID, WorkspaceID: w.ID}) + _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) check.Args(database.UpdateProvisionerJobWithCancelByIDParams{ID: j.ID}).Asserts(w, policy.ActionUpdate).Returns() })) s.Run("TemplateVersion/UpdateProvisionerJobWithCancelByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeTemplateVersionImport, }) @@ -530,6 +653,7 @@ func (s *MethodTestSuite) TestProvisionerJob() { Asserts(v.RBACObject(tpl), []policy.Action{policy.ActionRead, policy.ActionUpdate}).Returns() })) s.Run("TemplateVersionNoTemplate/UpdateProvisionerJobWithCancelByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeTemplateVersionImport, }) @@ -541,6 +665,7 @@ func (s *MethodTestSuite) TestProvisionerJob() { Asserts(v.RBACObjectNoTemplate(), []policy.Action{policy.ActionRead, policy.ActionUpdate}).Returns() })) s.Run("TemplateVersionDryRun/UpdateProvisionerJobWithCancelByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) tpl := dbgen.Template(s.T(), db, database.Template{}) v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, @@ -560,11 +685,30 @@ func (s *MethodTestSuite) TestProvisionerJob() { check.Args([]uuid.UUID{a.ID, b.ID}).Asserts().Returns(slice.New(a, b)) })) s.Run("GetProvisionerLogsAfterID", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + OrganizationID: o.ID, + OwnerID: u.ID, + TemplateID: tpl.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeWorkspaceBuild, }) - _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{JobID: j.ID, WorkspaceID: w.ID}) + _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) check.Args(database.GetProvisionerLogsAfterIDParams{ JobID: j.ID, }).Asserts(w, policy.ActionRead).Returns([]database.ProvisionerJobLog{}) @@ -605,7 +749,8 @@ func (s *MethodTestSuite) TestLicense() { check.Args(l.ID).Asserts(l, policy.ActionDelete) })) s.Run("GetDeploymentID", s.Subtest(func(db database.Store, check *expects) { - check.Args().Asserts().Returns("") + db.InsertDeploymentID(context.Background(), "value") + check.Args().Asserts().Returns("value") })) s.Run("GetDefaultProxyConfig", s.Subtest(func(db database.Store, check *expects) { check.Args().Asserts().Returns(database.GetDefaultProxyConfigRow{ @@ -675,10 +820,12 @@ func (s *MethodTestSuite) TestOrganization() { s.Run("GetOrganizationIDsByMemberIDs", s.Subtest(func(db database.Store, check *expects) { oa := dbgen.Organization(s.T(), db, database.Organization{}) ob := dbgen.Organization(s.T(), db, database.Organization{}) - ma := dbgen.OrganizationMember(s.T(), db, database.OrganizationMember{OrganizationID: oa.ID}) - mb := dbgen.OrganizationMember(s.T(), db, database.OrganizationMember{OrganizationID: ob.ID}) + ua := dbgen.User(s.T(), db, database.User{}) + ub := dbgen.User(s.T(), db, database.User{}) + ma := dbgen.OrganizationMember(s.T(), db, database.OrganizationMember{OrganizationID: oa.ID, UserID: ua.ID}) + mb := dbgen.OrganizationMember(s.T(), db, database.OrganizationMember{OrganizationID: ob.ID, UserID: ub.ID}) check.Args([]uuid.UUID{ma.UserID, mb.UserID}). - Asserts(rbac.ResourceUserObject(ma.UserID), policy.ActionRead, rbac.ResourceUserObject(mb.UserID), policy.ActionRead) + Asserts(rbac.ResourceUserObject(ma.UserID), policy.ActionRead, rbac.ResourceUserObject(mb.UserID), policy.ActionRead).OutOfOrder() })) s.Run("GetOrganizations", s.Subtest(func(db database.Store, check *expects) { def, _ := db.GetDefaultOrganization(context.Background()) @@ -717,6 +864,11 @@ func (s *MethodTestSuite) TestOrganization() { u := dbgen.User(s.T(), db, database.User{}) member := dbgen.OrganizationMember(s.T(), db, database.OrganizationMember{UserID: u.ID, OrganizationID: o.ID}) + cancelledErr := "fetch object: context canceled" + if !dbtestutil.WillUsePostgres() { + cancelledErr = sql.ErrNoRows.Error() + } + check.Args(database.DeleteOrganizationMemberParams{ OrganizationID: o.ID, UserID: u.ID, @@ -724,10 +876,9 @@ func (s *MethodTestSuite) TestOrganization() { // Reads the org member before it tries to delete it member, policy.ActionRead, member, policy.ActionDelete). - // SQL Filter returns a 404 WithNotAuthorized("no rows"). - WithCancelled("no rows"). - Errors(sql.ErrNoRows) + WithCancelled(cancelledErr). + ErrorsWithInMemDB(sql.ErrNoRows) })) s.Run("UpdateOrganization", s.Subtest(func(db database.Store, check *expects) { o := dbgen.Organization(s.T(), db, database.Organization{ @@ -773,13 +924,18 @@ func (s *MethodTestSuite) TestOrganization() { out := mem out.Roles = []string{} + cancelledErr := "fetch object: context canceled" + if !dbtestutil.WillUsePostgres() { + cancelledErr = sql.ErrNoRows.Error() + } + check.Args(database.UpdateMemberRolesParams{ GrantedRoles: []string{}, UserID: u.ID, OrgID: o.ID, }). WithNotAuthorized(sql.ErrNoRows.Error()). - WithCancelled(sql.ErrNoRows.Error()). + WithCancelled(cancelledErr). Asserts( mem, policy.ActionRead, rbac.ResourceAssignOrgRole.InOrg(o.ID), policy.ActionAssign, // org-mem @@ -832,10 +988,12 @@ func (s *MethodTestSuite) TestTemplate() { s.Run("GetPreviousTemplateVersion", s.Subtest(func(db database.Store, check *expects) { tvid := uuid.New() now := time.Now() + u := dbgen.User(s.T(), db, database.User{}) o1 := dbgen.Organization(s.T(), db, database.Organization{}) t1 := dbgen.Template(s.T(), db, database.Template{ OrganizationID: o1.ID, ActiveVersionID: tvid, + CreatedBy: u.ID, }) _ = dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ CreatedAt: now.Add(-time.Hour), @@ -843,12 +1001,14 @@ func (s *MethodTestSuite) TestTemplate() { Name: t1.Name, OrganizationID: o1.ID, TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, + CreatedBy: u.ID, }) b := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ CreatedAt: now.Add(-2 * time.Hour), - Name: t1.Name, + Name: t1.Name + "b", OrganizationID: o1.ID, TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, + CreatedBy: u.ID, }) check.Args(database.GetPreviousTemplateVersionParams{ Name: t1.Name, @@ -857,10 +1017,12 @@ func (s *MethodTestSuite) TestTemplate() { }).Asserts(t1, policy.ActionRead).Returns(b) })) s.Run("GetTemplateByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) check.Args(t1.ID).Asserts(t1, policy.ActionRead).Returns(t1) })) s.Run("GetTemplateByOrganizationAndName", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) o1 := dbgen.Organization(s.T(), db, database.Organization{}) t1 := dbgen.Template(s.T(), db, database.Template{ OrganizationID: o1.ID, @@ -871,6 +1033,7 @@ func (s *MethodTestSuite) TestTemplate() { }).Asserts(t1, policy.ActionRead).Returns(t1) })) s.Run("GetTemplateVersionByJobID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, @@ -878,6 +1041,7 @@ func (s *MethodTestSuite) TestTemplate() { check.Args(tv.JobID).Asserts(t1, policy.ActionRead).Returns(tv) })) s.Run("GetTemplateVersionByTemplateIDAndName", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, @@ -888,6 +1052,7 @@ func (s *MethodTestSuite) TestTemplate() { }).Asserts(t1, policy.ActionRead).Returns(tv) })) s.Run("GetTemplateVersionParameters", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, @@ -895,6 +1060,7 @@ func (s *MethodTestSuite) TestTemplate() { check.Args(tv.ID).Asserts(t1, policy.ActionRead).Returns([]database.TemplateVersionParameter{}) })) s.Run("GetTemplateVersionVariables", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, @@ -905,6 +1071,7 @@ func (s *MethodTestSuite) TestTemplate() { check.Args(tv.ID).Asserts(t1, policy.ActionRead).Returns([]database.TemplateVersionVariable{tvv1}) })) s.Run("GetTemplateVersionWorkspaceTags", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, @@ -915,14 +1082,17 @@ func (s *MethodTestSuite) TestTemplate() { check.Args(tv.ID).Asserts(t1, policy.ActionRead).Returns([]database.TemplateVersionWorkspaceTag{wt1}) })) s.Run("GetTemplateGroupRoles", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) check.Args(t1.ID).Asserts(t1, policy.ActionUpdate) })) s.Run("GetTemplateUserRoles", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) check.Args(t1.ID).Asserts(t1, policy.ActionUpdate) })) s.Run("GetTemplateVersionByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, @@ -930,6 +1100,7 @@ func (s *MethodTestSuite) TestTemplate() { check.Args(tv.ID).Asserts(t1, policy.ActionRead).Returns(tv) })) s.Run("GetTemplateVersionsByTemplateID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) a := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, @@ -943,6 +1114,7 @@ func (s *MethodTestSuite) TestTemplate() { Returns(slice.New(a, b)) })) s.Run("GetTemplateVersionsCreatedAfter", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) now := time.Now() t1 := dbgen.Template(s.T(), db, database.Template{}) _ = dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ @@ -956,12 +1128,18 @@ func (s *MethodTestSuite) TestTemplate() { check.Args(now.Add(-time.Hour)).Asserts(rbac.ResourceTemplate.All(), policy.ActionRead) })) s.Run("GetTemplatesWithFilter", s.Subtest(func(db database.Store, check *expects) { - a := dbgen.Template(s.T(), db, database.Template{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + u := dbgen.User(s.T(), db, database.User{}) + a := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) // No asserts because SQLFilter. check.Args(database.GetTemplatesWithFilterParams{}). Asserts().Returns(slice.New(a)) })) s.Run("GetAuthorizedTemplates", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) a := dbgen.Template(s.T(), db, database.Template{}) // No asserts because SQLFilter. check.Args(database.GetTemplatesWithFilterParams{}, emptyPreparedAuthorized{}). @@ -969,6 +1147,7 @@ func (s *MethodTestSuite) TestTemplate() { Returns(slice.New(a)) })) s.Run("InsertTemplate", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) orgID := uuid.New() check.Args(database.InsertTemplateParams{ Provisioner: "echo", @@ -977,6 +1156,7 @@ func (s *MethodTestSuite) TestTemplate() { }).Asserts(rbac.ResourceTemplate.InOrg(orgID), policy.ActionCreate) })) s.Run("InsertTemplateVersion", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) check.Args(database.InsertTemplateVersionParams{ TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, @@ -984,46 +1164,54 @@ func (s *MethodTestSuite) TestTemplate() { }).Asserts(t1, policy.ActionRead, t1, policy.ActionCreate) })) s.Run("SoftDeleteTemplateByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) check.Args(t1.ID).Asserts(t1, policy.ActionDelete) })) s.Run("UpdateTemplateACLByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) check.Args(database.UpdateTemplateACLByIDParams{ ID: t1.ID, }).Asserts(t1, policy.ActionCreate) })) s.Run("UpdateTemplateAccessControlByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) check.Args(database.UpdateTemplateAccessControlByIDParams{ ID: t1.ID, }).Asserts(t1, policy.ActionUpdate) })) s.Run("UpdateTemplateScheduleByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) check.Args(database.UpdateTemplateScheduleByIDParams{ ID: t1.ID, }).Asserts(t1, policy.ActionUpdate) })) s.Run("UpdateTemplateWorkspacesLastUsedAt", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) check.Args(database.UpdateTemplateWorkspacesLastUsedAtParams{ TemplateID: t1.ID, }).Asserts(t1, policy.ActionUpdate) })) s.Run("UpdateWorkspacesDormantDeletingAtByTemplateID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) check.Args(database.UpdateWorkspacesDormantDeletingAtByTemplateIDParams{ TemplateID: t1.ID, }).Asserts(t1, policy.ActionUpdate) })) s.Run("UpdateWorkspacesTTLByTemplateID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) check.Args(database.UpdateWorkspacesTTLByTemplateIDParams{ TemplateID: t1.ID, }).Asserts(t1, policy.ActionUpdate) })) s.Run("UpdateTemplateActiveVersionByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{ ActiveVersionID: uuid.New(), }) @@ -1037,6 +1225,7 @@ func (s *MethodTestSuite) TestTemplate() { }).Asserts(t1, policy.ActionUpdate).Returns() })) s.Run("UpdateTemplateDeletedByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) check.Args(database.UpdateTemplateDeletedByIDParams{ ID: t1.ID, @@ -1044,6 +1233,7 @@ func (s *MethodTestSuite) TestTemplate() { }).Asserts(t1, policy.ActionDelete).Returns() })) s.Run("UpdateTemplateMetaByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) check.Args(database.UpdateTemplateMetaByIDParams{ ID: t1.ID, @@ -1051,6 +1241,7 @@ func (s *MethodTestSuite) TestTemplate() { }).Asserts(t1, policy.ActionUpdate) })) s.Run("UpdateTemplateVersionByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, @@ -1063,6 +1254,7 @@ func (s *MethodTestSuite) TestTemplate() { }).Asserts(t1, policy.ActionUpdate) })) s.Run("UpdateTemplateVersionDescriptionByJobID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) jobID := uuid.New() t1 := dbgen.Template(s.T(), db, database.Template{}) _ = dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ @@ -1076,13 +1268,21 @@ func (s *MethodTestSuite) TestTemplate() { })) s.Run("UpdateTemplateVersionExternalAuthProvidersByJobID", s.Subtest(func(db database.Store, check *expects) { jobID := uuid.New() - t1 := dbgen.Template(s.T(), db, database.Template{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + t1 := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) _ = dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ - TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, - JobID: jobID, + TemplateID: uuid.NullUUID{UUID: t1.ID, Valid: true}, + CreatedBy: u.ID, + OrganizationID: o.ID, + JobID: jobID, }) check.Args(database.UpdateTemplateVersionExternalAuthProvidersByJobIDParams{ - JobID: jobID, + JobID: jobID, + ExternalAuthProviders: json.RawMessage("{}"), }).Asserts(t1, policy.ActionUpdate).Returns() })) s.Run("GetTemplateInsights", s.Subtest(func(db database.Store, check *expects) { @@ -1092,13 +1292,19 @@ func (s *MethodTestSuite) TestTemplate() { check.Args(database.GetUserLatencyInsightsParams{}).Asserts(rbac.ResourceTemplate, policy.ActionViewInsights) })) s.Run("GetUserActivityInsights", s.Subtest(func(db database.Store, check *expects) { - check.Args(database.GetUserActivityInsightsParams{}).Asserts(rbac.ResourceTemplate, policy.ActionViewInsights).Errors(sql.ErrNoRows) + check.Args(database.GetUserActivityInsightsParams{}).Asserts(rbac.ResourceTemplate, policy.ActionViewInsights). + ErrorsWithInMemDB(sql.ErrNoRows). + Returns([]database.GetUserActivityInsightsRow{}) })) s.Run("GetTemplateParameterInsights", s.Subtest(func(db database.Store, check *expects) { check.Args(database.GetTemplateParameterInsightsParams{}).Asserts(rbac.ResourceTemplate, policy.ActionViewInsights) })) s.Run("GetTemplateInsightsByInterval", s.Subtest(func(db database.Store, check *expects) { - check.Args(database.GetTemplateInsightsByIntervalParams{}).Asserts(rbac.ResourceTemplate, policy.ActionViewInsights) + check.Args(database.GetTemplateInsightsByIntervalParams{ + IntervalDays: 7, + StartTime: dbtime.Now().Add(-time.Hour * 24 * 7), + EndTime: dbtime.Now(), + }).Asserts(rbac.ResourceTemplate, policy.ActionViewInsights) })) s.Run("GetTemplateInsightsByTemplate", s.Subtest(func(db database.Store, check *expects) { check.Args(database.GetTemplateInsightsByTemplateParams{}).Asserts(rbac.ResourceTemplate, policy.ActionViewInsights) @@ -1110,7 +1316,9 @@ func (s *MethodTestSuite) TestTemplate() { check.Args(database.GetTemplateAppInsightsByTemplateParams{}).Asserts(rbac.ResourceTemplate, policy.ActionViewInsights) })) s.Run("GetTemplateUsageStats", s.Subtest(func(db database.Store, check *expects) { - check.Args(database.GetTemplateUsageStatsParams{}).Asserts(rbac.ResourceTemplate, policy.ActionViewInsights).Errors(sql.ErrNoRows) + check.Args(database.GetTemplateUsageStatsParams{}).Asserts(rbac.ResourceTemplate, policy.ActionViewInsights). + ErrorsWithInMemDB(sql.ErrNoRows). + Returns([]database.TemplateUsageStat{}) })) s.Run("UpsertTemplateUsageStats", s.Subtest(func(db database.Store, check *expects) { check.Asserts(rbac.ResourceSystem, policy.ActionUpdate) @@ -1119,6 +1327,7 @@ func (s *MethodTestSuite) TestTemplate() { func (s *MethodTestSuite) TestUser() { s.Run("GetAuthorizedUsers", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) dbgen.User(s.T(), db, database.User{}) // No asserts because SQLFilter. check.Args(database.GetUsersParams{}, emptyPreparedAuthorized{}). @@ -1161,6 +1370,7 @@ func (s *MethodTestSuite) TestUser() { Returns(slice.New(a, b)) })) s.Run("GetUsers", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) dbgen.User(s.T(), db, database.User{Username: "GetUsers-a-user"}) dbgen.User(s.T(), db, database.User{Username: "GetUsers-b-user"}) check.Args(database.GetUsersParams{}). @@ -1171,6 +1381,7 @@ func (s *MethodTestSuite) TestUser() { check.Args(database.InsertUserParams{ ID: uuid.New(), LoginType: database.LoginTypePassword, + RBACRoles: []string{}, }).Asserts(rbac.ResourceAssignRole, policy.ActionAssign, rbac.ResourceUser, policy.ActionCreate) })) s.Run("InsertUserLink", s.Subtest(func(db database.Store, check *expects) { @@ -1199,7 +1410,9 @@ func (s *MethodTestSuite) TestUser() { s.Run("UpdateUserHashedOneTimePasscode", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) check.Args(database.UpdateUserHashedOneTimePasscodeParams{ - ID: u.ID, + ID: u.ID, + HashedOneTimePasscode: []byte{}, + OneTimePasscodeExpiresAt: sql.NullTime{Time: u.CreatedAt, Valid: true}, }).Asserts(rbac.ResourceSystem, policy.ActionUpdate).Returns() })) s.Run("UpdateUserQuietHoursSchedule", s.Subtest(func(db database.Store, check *expects) { @@ -1254,10 +1467,12 @@ func (s *MethodTestSuite) TestUser() { }).Asserts(u, policy.ActionUpdate).Returns(u) })) s.Run("DeleteGitSSHKey", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) key := dbgen.GitSSHKey(s.T(), db, database.GitSSHKey{}) check.Args(key.UserID).Asserts(rbac.ResourceUserObject(key.UserID), policy.ActionUpdatePersonal).Returns() })) s.Run("GetGitSSHKey", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) key := dbgen.GitSSHKey(s.T(), db, database.GitSSHKey{}) check.Args(key.UserID).Asserts(rbac.ResourceUserObject(key.UserID), policy.ActionReadPersonal).Returns(key) })) @@ -1268,6 +1483,7 @@ func (s *MethodTestSuite) TestUser() { }).Asserts(u, policy.ActionUpdatePersonal) })) s.Run("UpdateGitSSHKey", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) key := dbgen.GitSSHKey(s.T(), db, database.GitSSHKey{}) check.Args(database.UpdateGitSSHKeyParams{ UserID: key.UserID, @@ -1310,6 +1526,7 @@ func (s *MethodTestSuite) TestUser() { }).Asserts(rbac.ResourceUserObject(link.UserID), policy.ActionUpdatePersonal).Returns(link) })) s.Run("UpdateUserLink", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) link := dbgen.UserLink(s.T(), db, database.UserLink{}) check.Args(database.UpdateUserLinkParams{ OAuthAccessToken: link.OAuthAccessToken, @@ -1367,6 +1584,7 @@ func (s *MethodTestSuite) TestUser() { rbac.ResourceAssignRole, policy.ActionDelete) })) s.Run("Blank/UpdateCustomRole", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) customRole := dbgen.CustomRole(s.T(), db, database.CustomRole{}) // Blank is no perms in the role check.Args(database.UpdateCustomRoleParams{ @@ -1375,7 +1593,7 @@ func (s *MethodTestSuite) TestUser() { SitePermissions: nil, OrgPermissions: nil, UserPermissions: nil, - }).Asserts(rbac.ResourceAssignRole, policy.ActionUpdate) + }).Asserts(rbac.ResourceAssignRole, policy.ActionUpdate).ErrorsWithPG(sql.ErrNoRows) })) s.Run("SitePermissions/UpdateCustomRole", s.Subtest(func(db database.Store, check *expects) { customRole := dbgen.CustomRole(s.T(), db, database.CustomRole{ @@ -1406,7 +1624,7 @@ func (s *MethodTestSuite) TestUser() { rbac.ResourceTemplate, policy.ActionViewInsights, rbac.ResourceWorkspace.WithOwner(testActorID.String()), policy.ActionRead, - ) + ).ErrorsWithPG(sql.ErrNoRows) })) s.Run("OrgPermissions/UpdateCustomRole", s.Subtest(func(db database.Store, check *expects) { orgID := uuid.New() @@ -1494,22 +1712,29 @@ func (s *MethodTestSuite) TestUser() { func (s *MethodTestSuite) TestWorkspace() { s.Run("GetWorkspaceByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + OwnerID: u.ID, + OrganizationID: o.ID, + TemplateID: tpl.ID, + }) check.Args(ws.ID).Asserts(ws, policy.ActionRead) })) - s.Run("GetWorkspaces", s.Subtest(func(db database.Store, check *expects) { - _ = dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - _ = dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + s.Run("GetWorkspaces", s.Subtest(func(_ database.Store, check *expects) { // No asserts here because SQLFilter. check.Args(database.GetWorkspacesParams{}).Asserts() })) - s.Run("GetAuthorizedWorkspaces", s.Subtest(func(db database.Store, check *expects) { - _ = dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - _ = dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + s.Run("GetAuthorizedWorkspaces", s.Subtest(func(_ database.Store, check *expects) { // No asserts here because SQLFilter. check.Args(database.GetWorkspacesParams{}, emptyPreparedAuthorized{}).Asserts() })) s.Run("GetWorkspacesAndAgentsByOwnerID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) _ = dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: build.JobID, Type: database.ProvisionerJobTypeWorkspaceBuild}) @@ -1519,6 +1744,7 @@ func (s *MethodTestSuite) TestWorkspace() { check.Args(ws.OwnerID).Asserts() })) s.Run("GetAuthorizedWorkspacesAndAgentsByOwnerID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) _ = dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: build.JobID, Type: database.ProvisionerJobTypeWorkspaceBuild}) @@ -1528,37 +1754,116 @@ func (s *MethodTestSuite) TestWorkspace() { check.Args(ws.OwnerID, emptyPreparedAuthorized{}).Asserts() })) s.Run("GetLatestWorkspaceBuildByWorkspaceID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID}) - check.Args(ws.ID).Asserts(ws, policy.ActionRead).Returns(b) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) + check.Args(w.ID).Asserts(w, policy.ActionRead).Returns(b) })) s.Run("GetWorkspaceAgentByID", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: tpl.ID, + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, }) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) - res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) + res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: b.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) - check.Args(agt.ID).Asserts(ws, policy.ActionRead).Returns(agt) + check.Args(agt.ID).Asserts(w, policy.ActionRead).Returns(agt) })) s.Run("GetWorkspaceAgentLifecycleStateByID", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: tpl.ID, + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, }) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) - res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) + res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: b.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) - check.Args(agt.ID).Asserts(ws, policy.ActionRead) + check.Args(agt.ID).Asserts(w, policy.ActionRead) })) s.Run("GetWorkspaceAgentMetadata", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: tpl.ID, + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, }) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) - res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) + res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: b.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) _ = db.InsertWorkspaceAgentMetadata(context.Background(), database.InsertWorkspaceAgentMetadataParams{ WorkspaceAgentID: agt.ID, @@ -1568,77 +1873,191 @@ func (s *MethodTestSuite) TestWorkspace() { check.Args(database.GetWorkspaceAgentMetadataParams{ WorkspaceAgentID: agt.ID, Keys: []string{"test"}, - }).Asserts(ws, policy.ActionRead) + }).Asserts(w, policy.ActionRead) })) s.Run("GetWorkspaceAgentByInstanceID", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: tpl.ID, + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, }) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) - res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) + res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: b.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) - check.Args(agt.AuthInstanceID.String).Asserts(ws, policy.ActionRead).Returns(agt) + check.Args(agt.AuthInstanceID.String).Asserts(w, policy.ActionRead).Returns(agt) })) s.Run("UpdateWorkspaceAgentLifecycleStateByID", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: tpl.ID, + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, }) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) - res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) + res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: b.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) check.Args(database.UpdateWorkspaceAgentLifecycleStateByIDParams{ ID: agt.ID, LifecycleState: database.WorkspaceAgentLifecycleStateCreated, - }).Asserts(ws, policy.ActionUpdate).Returns() + }).Asserts(w, policy.ActionUpdate).Returns() })) s.Run("UpdateWorkspaceAgentMetadata", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: tpl.ID, + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, }) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) - res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) + res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: b.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) check.Args(database.UpdateWorkspaceAgentMetadataParams{ WorkspaceAgentID: agt.ID, - }).Asserts(ws, policy.ActionUpdate).Returns() + }).Asserts(w, policy.ActionUpdate).Returns() })) s.Run("UpdateWorkspaceAgentLogOverflowByID", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: tpl.ID, + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, }) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) - res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) - agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) - check.Args(database.UpdateWorkspaceAgentLogOverflowByIDParams{ - ID: agt.ID, + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) + res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: b.JobID}) + agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) + check.Args(database.UpdateWorkspaceAgentLogOverflowByIDParams{ + ID: agt.ID, LogsOverflowed: true, - }).Asserts(ws, policy.ActionUpdate).Returns() + }).Asserts(w, policy.ActionUpdate).Returns() })) s.Run("UpdateWorkspaceAgentStartupByID", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: tpl.ID, + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, }) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) - res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) + res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: b.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) check.Args(database.UpdateWorkspaceAgentStartupByIDParams{ ID: agt.ID, Subsystems: []database.WorkspaceAgentSubsystem{ database.WorkspaceAgentSubsystemEnvbox, }, - }).Asserts(ws, policy.ActionUpdate).Returns() + }).Asserts(w, policy.ActionUpdate).Returns() })) s.Run("GetWorkspaceAgentLogsAfter", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: tpl.ID, + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: ws.ID, + TemplateVersionID: tv.ID, }) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) check.Args(database.GetWorkspaceAgentLogsAfterParams{ @@ -1646,11 +2065,30 @@ func (s *MethodTestSuite) TestWorkspace() { }).Asserts(ws, policy.ActionRead).Returns([]database.WorkspaceAgentLog{}) })) s.Run("GetWorkspaceAppByAgentIDAndSlug", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: tpl.ID, + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: ws.ID, + TemplateVersionID: tv.ID, }) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) app := dbgen.WorkspaceApp(s.T(), db, database.WorkspaceApp{AgentID: agt.ID}) @@ -1661,11 +2099,30 @@ func (s *MethodTestSuite) TestWorkspace() { }).Asserts(ws, policy.ActionRead).Returns(app) })) s.Run("GetWorkspaceAppsByAgentID", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: tpl.ID, + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: ws.ID, + TemplateVersionID: tv.ID, }) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) a := dbgen.WorkspaceApp(s.T(), db, database.WorkspaceApp{AgentID: agt.ID}) @@ -1674,58 +2131,234 @@ func (s *MethodTestSuite) TestWorkspace() { check.Args(agt.ID).Asserts(ws, policy.ActionRead).Returns(slice.New(a, b)) })) s.Run("GetWorkspaceBuildByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: ws.ID, + TemplateVersionID: tv.ID, + }) check.Args(build.ID).Asserts(ws, policy.ActionRead).Returns(build) })) s.Run("GetWorkspaceBuildByJobID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: ws.ID, + TemplateVersionID: tv.ID, + }) check.Args(build.JobID).Asserts(ws, policy.ActionRead).Returns(build) })) s.Run("GetWorkspaceBuildByWorkspaceIDAndBuildNumber", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, BuildNumber: 10}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: ws.ID, + TemplateVersionID: tv.ID, + BuildNumber: 10, + }) check.Args(database.GetWorkspaceBuildByWorkspaceIDAndBuildNumberParams{ WorkspaceID: ws.ID, BuildNumber: build.BuildNumber, }).Asserts(ws, policy.ActionRead).Returns(build) })) s.Run("GetWorkspaceBuildParameters", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: ws.ID, + TemplateVersionID: tv.ID, + }) check.Args(build.ID).Asserts(ws, policy.ActionRead). Returns([]database.WorkspaceBuildParameter{}) })) s.Run("GetWorkspaceBuildsByWorkspaceID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, BuildNumber: 1}) - _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, BuildNumber: 2}) - _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, BuildNumber: 3}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j1 := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j1.ID, + WorkspaceID: ws.ID, + TemplateVersionID: tv.ID, + BuildNumber: 1, + }) + j2 := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j2.ID, + WorkspaceID: ws.ID, + TemplateVersionID: tv.ID, + BuildNumber: 2, + }) + j3 := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j3.ID, + WorkspaceID: ws.ID, + TemplateVersionID: tv.ID, + BuildNumber: 3, + }) check.Args(database.GetWorkspaceBuildsByWorkspaceIDParams{WorkspaceID: ws.ID}).Asserts(ws, policy.ActionRead) // ordering })) s.Run("GetWorkspaceByAgentID", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: tpl.ID, + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: ws.ID, + TemplateVersionID: tv.ID, }) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) check.Args(agt.ID).Asserts(ws, policy.ActionRead) })) s.Run("GetWorkspaceAgentsInLatestBuildByWorkspaceID", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: tpl.ID, + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: ws.ID, + TemplateVersionID: tv.ID, }) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) check.Args(ws.ID).Asserts(ws, policy.ActionRead) })) s.Run("GetWorkspaceByOwnerIDAndName", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) check.Args(database.GetWorkspaceByOwnerIDAndNameParams{ OwnerID: ws.OwnerID, Deleted: ws.Deleted, @@ -1733,58 +2366,157 @@ func (s *MethodTestSuite) TestWorkspace() { }).Asserts(ws, policy.ActionRead) })) s.Run("GetWorkspaceResourceByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) - _ = dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: build.JobID, Type: database.ProvisionerJobTypeWorkspaceBuild}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: ws.ID, + TemplateVersionID: tv.ID, + }) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) check.Args(res.ID).Asserts(ws, policy.ActionRead).Returns(res) })) s.Run("Build/GetWorkspaceResourcesByJobID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) - job := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: build.JobID, Type: database.ProvisionerJobTypeWorkspaceBuild}) - check.Args(job.ID).Asserts(ws, policy.ActionRead).Returns([]database.WorkspaceResource{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: ws.ID, + TemplateVersionID: tv.ID, + }) + check.Args(build.JobID).Asserts(ws, policy.ActionRead).Returns([]database.WorkspaceResource{}) })) s.Run("Template/GetWorkspaceResourcesByJobID", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) - v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, JobID: uuid.New()}) - job := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: v.JobID, Type: database.ProvisionerJobTypeTemplateVersionImport}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + JobID: uuid.New(), + }) + job := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + ID: v.JobID, + Type: database.ProvisionerJobTypeTemplateVersionImport, + }) check.Args(job.ID).Asserts(v.RBACObject(tpl), []policy.Action{policy.ActionRead, policy.ActionRead}).Returns([]database.WorkspaceResource{}) })) s.Run("InsertWorkspace", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) check.Args(database.InsertWorkspaceParams{ ID: uuid.New(), OwnerID: u.ID, OrganizationID: o.ID, AutomaticUpdates: database.AutomaticUpdatesNever, + TemplateID: tpl.ID, }).Asserts(rbac.ResourceWorkspace.WithOwner(u.ID.String()).InOrg(o.ID), policy.ActionCreate) })) s.Run("Start/InsertWorkspaceBuild", s.Subtest(func(db database.Store, check *expects) { - t := dbgen.Template(s.T(), db, database.Template{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + t := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: t.ID, + TemplateID: t.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + pj := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + OrganizationID: o.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: t.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, }) check.Args(database.InsertWorkspaceBuildParams{ - WorkspaceID: w.ID, - Transition: database.WorkspaceTransitionStart, - Reason: database.BuildReasonInitiator, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + Transition: database.WorkspaceTransitionStart, + Reason: database.BuildReasonInitiator, + JobID: pj.ID, }).Asserts(w, policy.ActionWorkspaceStart) })) s.Run("Stop/InsertWorkspaceBuild", s.Subtest(func(db database.Store, check *expects) { - t := dbgen.Template(s.T(), db, database.Template{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + t := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: t.ID, + TemplateID: t.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: t.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + pj := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + OrganizationID: o.ID, }) check.Args(database.InsertWorkspaceBuildParams{ - WorkspaceID: w.ID, - Transition: database.WorkspaceTransitionStop, - Reason: database.BuildReasonInitiator, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + Transition: database.WorkspaceTransitionStop, + Reason: database.BuildReasonInitiator, + JobID: pj.ID, }).Asserts(w, policy.ActionWorkspaceStop) })) s.Run("Start/RequireActiveVersion/VersionMismatch/InsertWorkspaceBuild", s.Subtest(func(db database.Store, check *expects) { - t := dbgen.Template(s.T(), db, database.Template{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + t := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) ctx := testutil.Context(s.T(), testutil.WaitShort) err := db.UpdateTemplateAccessControlByID(ctx, database.UpdateTemplateAccessControlByIDParams{ ID: t.ID, @@ -1792,24 +2524,39 @@ func (s *MethodTestSuite) TestWorkspace() { }) require.NoError(s.T(), err) v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ - TemplateID: uuid.NullUUID{UUID: t.ID}, + TemplateID: uuid.NullUUID{UUID: t.ID}, + OrganizationID: o.ID, + CreatedBy: u.ID, }) w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: t.ID, + TemplateID: t.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + pj := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + OrganizationID: o.ID, }) check.Args(database.InsertWorkspaceBuildParams{ WorkspaceID: w.ID, Transition: database.WorkspaceTransitionStart, Reason: database.BuildReasonInitiator, TemplateVersionID: v.ID, + JobID: pj.ID, }).Asserts( w, policy.ActionWorkspaceStart, t, policy.ActionUpdate, ) })) s.Run("Start/RequireActiveVersion/VersionsMatch/InsertWorkspaceBuild", s.Subtest(func(db database.Store, check *expects) { - v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) t := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, ActiveVersionID: v.ID, }) @@ -1821,7 +2568,12 @@ func (s *MethodTestSuite) TestWorkspace() { require.NoError(s.T(), err) w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: t.ID, + TemplateID: t.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + pj := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + OrganizationID: o.ID, }) // Assert that we do not check for template update permissions // if versions match. @@ -1830,21 +2582,64 @@ func (s *MethodTestSuite) TestWorkspace() { Transition: database.WorkspaceTransitionStart, Reason: database.BuildReasonInitiator, TemplateVersionID: v.ID, + JobID: pj.ID, }).Asserts( w, policy.ActionWorkspaceStart, ) })) s.Run("Delete/InsertWorkspaceBuild", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + pj := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + OrganizationID: o.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) check.Args(database.InsertWorkspaceBuildParams{ - WorkspaceID: w.ID, - Transition: database.WorkspaceTransitionDelete, - Reason: database.BuildReasonInitiator, + WorkspaceID: w.ID, + Transition: database.WorkspaceTransitionDelete, + Reason: database.BuildReasonInitiator, + TemplateVersionID: tv.ID, + JobID: pj.ID, }).Asserts(w, policy.ActionDelete) })) s.Run("InsertWorkspaceBuildParameters", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: w.ID}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) check.Args(database.InsertWorkspaceBuildParametersParams{ WorkspaceBuildID: b.ID, Name: []string{"foo", "bar"}, @@ -1852,7 +2647,17 @@ func (s *MethodTestSuite) TestWorkspace() { }).Asserts(w, policy.ActionUpdate) })) s.Run("UpdateWorkspace", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) expected := w expected.Name = "" check.Args(database.UpdateWorkspaceParams{ @@ -1860,64 +2665,180 @@ func (s *MethodTestSuite) TestWorkspace() { }).Asserts(w, policy.ActionUpdate).Returns(expected) })) s.Run("UpdateWorkspaceDormantDeletingAt", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) check.Args(database.UpdateWorkspaceDormantDeletingAtParams{ ID: w.ID, }).Asserts(w, policy.ActionUpdate) })) s.Run("UpdateWorkspaceAutomaticUpdates", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) check.Args(database.UpdateWorkspaceAutomaticUpdatesParams{ ID: w.ID, AutomaticUpdates: database.AutomaticUpdatesAlways, }).Asserts(w, policy.ActionUpdate) })) s.Run("UpdateWorkspaceAppHealthByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) - res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) + res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: b.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) app := dbgen.WorkspaceApp(s.T(), db, database.WorkspaceApp{AgentID: agt.ID}) check.Args(database.UpdateWorkspaceAppHealthByIDParams{ ID: app.ID, Health: database.WorkspaceAppHealthDisabled, - }).Asserts(ws, policy.ActionUpdate).Returns() + }).Asserts(w, policy.ActionUpdate).Returns() })) s.Run("UpdateWorkspaceAutostart", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) check.Args(database.UpdateWorkspaceAutostartParams{ - ID: ws.ID, - }).Asserts(ws, policy.ActionUpdate).Returns() + ID: w.ID, + }).Asserts(w, policy.ActionUpdate).Returns() })) s.Run("UpdateWorkspaceBuildDeadlineByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) check.Args(database.UpdateWorkspaceBuildDeadlineByIDParams{ - ID: build.ID, - UpdatedAt: build.UpdatedAt, - Deadline: build.Deadline, - }).Asserts(ws, policy.ActionUpdate) + ID: b.ID, + UpdatedAt: b.UpdatedAt, + Deadline: b.Deadline, + }).Asserts(w, policy.ActionUpdate) })) s.Run("SoftDeleteWorkspaceByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - ws.Deleted = true - check.Args(ws.ID).Asserts(ws, policy.ActionDelete).Returns() + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + w.Deleted = true + check.Args(w.ID).Asserts(w, policy.ActionDelete).Returns() })) s.Run("UpdateWorkspaceDeletedByID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{Deleted: true}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + Deleted: true, + }) check.Args(database.UpdateWorkspaceDeletedByIDParams{ - ID: ws.ID, + ID: w.ID, Deleted: true, - }).Asserts(ws, policy.ActionDelete).Returns() + }).Asserts(w, policy.ActionDelete).Returns() })) s.Run("UpdateWorkspaceLastUsedAt", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) check.Args(database.UpdateWorkspaceLastUsedAtParams{ - ID: ws.ID, - }).Asserts(ws, policy.ActionUpdate).Returns() + ID: w.ID, + }).Asserts(w, policy.ActionUpdate).Returns() })) s.Run("UpdateWorkspaceNextStartAt", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) check.Args(database.UpdateWorkspaceNextStartAtParams{ ID: ws.ID, NextStartAt: sql.NullTime{Valid: true, Time: dbtime.Now()}, @@ -1930,50 +2851,144 @@ func (s *MethodTestSuite) TestWorkspace() { }).Asserts(rbac.ResourceWorkspace.All(), policy.ActionUpdate) })) s.Run("BatchUpdateWorkspaceLastUsedAt", s.Subtest(func(db database.Store, check *expects) { - ws1 := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - ws2 := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w1 := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + w2 := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) check.Args(database.BatchUpdateWorkspaceLastUsedAtParams{ - IDs: []uuid.UUID{ws1.ID, ws2.ID}, + IDs: []uuid.UUID{w1.ID, w2.ID}, }).Asserts(rbac.ResourceWorkspace.All(), policy.ActionUpdate).Returns() })) s.Run("UpdateWorkspaceTTL", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) check.Args(database.UpdateWorkspaceTTLParams{ - ID: ws.ID, - }).Asserts(ws, policy.ActionUpdate).Returns() + ID: w.ID, + }).Asserts(w, policy.ActionUpdate).Returns() })) s.Run("GetWorkspaceByWorkspaceAppID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) - res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) + res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: b.JobID}) agt := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ResourceID: res.ID}) app := dbgen.WorkspaceApp(s.T(), db, database.WorkspaceApp{AgentID: agt.ID}) - check.Args(app.ID).Asserts(ws, policy.ActionRead) + check.Args(app.ID).Asserts(w, policy.ActionRead) })) s.Run("ActivityBumpWorkspace", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) - dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: build.JobID, Type: database.ProvisionerJobTypeWorkspaceBuild}) + u := dbgen.User(s.T(), db, database.User{}) + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + Type: database.ProvisionerJobTypeWorkspaceBuild, + }) + _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + JobID: j.ID, + WorkspaceID: w.ID, + TemplateVersionID: tv.ID, + }) check.Args(database.ActivityBumpWorkspaceParams{ - WorkspaceID: ws.ID, - }).Asserts(ws, policy.ActionUpdate).Returns() + WorkspaceID: w.ID, + }).Asserts(w, policy.ActionUpdate).Returns() })) s.Run("FavoriteWorkspace", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID}) - check.Args(ws.ID).Asserts(ws, policy.ActionUpdate).Returns() + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + check.Args(w.ID).Asserts(w, policy.ActionUpdate).Returns() })) s.Run("UnfavoriteWorkspace", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID}) - check.Args(ws.ID).Asserts(ws, policy.ActionUpdate).Returns() + o := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: o.ID, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + TemplateID: tpl.ID, + OrganizationID: o.ID, + OwnerID: u.ID, + }) + check.Args(w.ID).Asserts(w, policy.ActionUpdate).Returns() })) } func (s *MethodTestSuite) TestWorkspacePortSharing() { s.Run("UpsertWorkspaceAgentPortShare", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID}) + org := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: org.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + OwnerID: u.ID, + OrganizationID: org.ID, + TemplateID: tpl.ID, + }) ps := dbgen.WorkspaceAgentPortShare(s.T(), db, database.WorkspaceAgentPortShare{WorkspaceID: ws.ID}) //nolint:gosimple // casting is not a simplification check.Args(database.UpsertWorkspaceAgentPortShareParams{ @@ -1986,7 +3001,16 @@ func (s *MethodTestSuite) TestWorkspacePortSharing() { })) s.Run("GetWorkspaceAgentPortShare", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID}) + org := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: org.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + OwnerID: u.ID, + OrganizationID: org.ID, + TemplateID: tpl.ID, + }) ps := dbgen.WorkspaceAgentPortShare(s.T(), db, database.WorkspaceAgentPortShare{WorkspaceID: ws.ID}) check.Args(database.GetWorkspaceAgentPortShareParams{ WorkspaceID: ps.WorkspaceID, @@ -1996,13 +3020,31 @@ func (s *MethodTestSuite) TestWorkspacePortSharing() { })) s.Run("ListWorkspaceAgentPortShares", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID}) + org := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: org.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + OwnerID: u.ID, + OrganizationID: org.ID, + TemplateID: tpl.ID, + }) ps := dbgen.WorkspaceAgentPortShare(s.T(), db, database.WorkspaceAgentPortShare{WorkspaceID: ws.ID}) check.Args(ws.ID).Asserts(ws, policy.ActionRead).Returns([]database.WorkspaceAgentPortShare{ps}) })) s.Run("DeleteWorkspaceAgentPortShare", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID}) + org := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: org.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + OwnerID: u.ID, + OrganizationID: org.ID, + TemplateID: tpl.ID, + }) ps := dbgen.WorkspaceAgentPortShare(s.T(), db, database.WorkspaceAgentPortShare{WorkspaceID: ws.ID}) check.Args(database.DeleteWorkspaceAgentPortShareParams{ WorkspaceID: ps.WorkspaceID, @@ -2012,17 +3054,33 @@ func (s *MethodTestSuite) TestWorkspacePortSharing() { })) s.Run("DeleteWorkspaceAgentPortSharesByTemplate", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - t := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID, TemplateID: t.ID}) + org := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: org.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + OwnerID: u.ID, + OrganizationID: org.ID, + TemplateID: tpl.ID, + }) _ = dbgen.WorkspaceAgentPortShare(s.T(), db, database.WorkspaceAgentPortShare{WorkspaceID: ws.ID}) - check.Args(t.ID).Asserts(t, policy.ActionUpdate).Returns() + check.Args(tpl.ID).Asserts(tpl, policy.ActionUpdate).Returns() })) s.Run("ReduceWorkspaceAgentShareLevelToAuthenticatedByTemplate", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - t := dbgen.Template(s.T(), db, database.Template{}) - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID, TemplateID: t.ID}) + org := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: org.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + OwnerID: u.ID, + OrganizationID: org.ID, + TemplateID: tpl.ID, + }) _ = dbgen.WorkspaceAgentPortShare(s.T(), db, database.WorkspaceAgentPortShare{WorkspaceID: ws.ID}) - check.Args(t.ID).Asserts(t, policy.ActionUpdate).Returns() + check.Args(tpl.ID).Asserts(tpl, policy.ActionUpdate).Returns() })) } @@ -2031,7 +3089,7 @@ func (s *MethodTestSuite) TestProvisionerKeys() { org := dbgen.Organization(s.T(), db, database.Organization{}) pk := database.ProvisionerKey{ ID: uuid.New(), - CreatedAt: time.Now(), + CreatedAt: dbtestutil.NowInDefaultTimezone(), OrganizationID: org.ID, Name: strings.ToLower(coderdtest.RandomName(s.T())), HashedSecret: []byte(coderdtest.RandomName(s.T())), @@ -2072,6 +3130,7 @@ func (s *MethodTestSuite) TestProvisionerKeys() { CreatedAt: pk.CreatedAt, OrganizationID: pk.OrganizationID, Name: pk.Name, + HashedSecret: pk.HashedSecret, }, } check.Args(org.ID).Asserts(pk, policy.ActionRead).Returns(pks) @@ -2085,6 +3144,7 @@ func (s *MethodTestSuite) TestProvisionerKeys() { CreatedAt: pk.CreatedAt, OrganizationID: pk.OrganizationID, Name: pk.Name, + HashedSecret: pk.HashedSecret, }, } check.Args(org.ID).Asserts(pk, policy.ActionRead).Returns(pks) @@ -2098,7 +3158,9 @@ func (s *MethodTestSuite) TestProvisionerKeys() { func (s *MethodTestSuite) TestExtraMethods() { s.Run("GetProvisionerDaemons", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) d, err := db.UpsertProvisionerDaemon(context.Background(), database.UpsertProvisionerDaemonParams{ + Provisioners: []database.ProvisionerType{}, Tags: database.StringMap(map[string]string{ provisionersdk.TagScope: provisionersdk.ScopeOrganization, }), @@ -2107,9 +3169,11 @@ func (s *MethodTestSuite) TestExtraMethods() { check.Args().Asserts(d, policy.ActionRead) })) s.Run("GetProvisionerDaemonsByOrganization", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) org := dbgen.Organization(s.T(), db, database.Organization{}) d, err := db.UpsertProvisionerDaemon(context.Background(), database.UpsertProvisionerDaemonParams{ OrganizationID: org.ID, + Provisioners: []database.ProvisionerType{}, Tags: database.StringMap(map[string]string{ provisionersdk.TagScope: provisionersdk.ScopeOrganization, }), @@ -2120,6 +3184,7 @@ func (s *MethodTestSuite) TestExtraMethods() { check.Args(database.GetProvisionerDaemonsByOrganizationParams{OrganizationID: org.ID}).Asserts(d, policy.ActionRead).Returns(ds) })) s.Run("GetEligibleProvisionerDaemonsByProvisionerJobIDs", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) org := dbgen.Organization(s.T(), db, database.Organization{}) tags := database.StringMap(map[string]string{ provisionersdk.TagScope: provisionersdk.ScopeOrganization, @@ -2130,6 +3195,7 @@ func (s *MethodTestSuite) TestExtraMethods() { Tags: tags, Provisioner: database.ProvisionerTypeEcho, StorageMethod: database.ProvisionerStorageMethodFile, + Input: json.RawMessage("{}"), }) s.NoError(err, "insert provisioner job") d, err := db.UpsertProvisionerDaemon(context.Background(), database.UpsertProvisionerDaemonParams{ @@ -2143,7 +3209,9 @@ func (s *MethodTestSuite) TestExtraMethods() { check.Args(uuid.UUIDs{j.ID}).Asserts(d, policy.ActionRead).Returns(ds) })) s.Run("DeleteOldProvisionerDaemons", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) _, err := db.UpsertProvisionerDaemon(context.Background(), database.UpsertProvisionerDaemonParams{ + Provisioners: []database.ProvisionerType{}, Tags: database.StringMap(map[string]string{ provisionersdk.TagScope: provisionersdk.ScopeOrganization, }), @@ -2152,7 +3220,9 @@ func (s *MethodTestSuite) TestExtraMethods() { check.Args().Asserts(rbac.ResourceSystem, policy.ActionDelete) })) s.Run("UpdateProvisionerDaemonLastSeenAt", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) d, err := db.UpsertProvisionerDaemon(context.Background(), database.UpsertProvisionerDaemonParams{ + Provisioners: []database.ProvisionerType{}, Tags: database.StringMap(map[string]string{ provisionersdk.TagScope: provisionersdk.ScopeOrganization, }), @@ -2165,145 +3235,151 @@ func (s *MethodTestSuite) TestExtraMethods() { })) } -// All functions in this method test suite are not implemented in dbmem, but -// we still want to assert RBAC checks. func (s *MethodTestSuite) TestTailnetFunctions() { - s.Run("CleanTailnetCoordinators", s.Subtest(func(db database.Store, check *expects) { + s.Run("CleanTailnetCoordinators", s.Subtest(func(_ database.Store, check *expects) { check.Args(). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("CleanTailnetLostPeers", s.Subtest(func(db database.Store, check *expects) { + s.Run("CleanTailnetLostPeers", s.Subtest(func(_ database.Store, check *expects) { check.Args(). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("CleanTailnetTunnels", s.Subtest(func(db database.Store, check *expects) { + s.Run("CleanTailnetTunnels", s.Subtest(func(_ database.Store, check *expects) { check.Args(). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("DeleteAllTailnetClientSubscriptions", s.Subtest(func(db database.Store, check *expects) { + s.Run("DeleteAllTailnetClientSubscriptions", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.DeleteAllTailnetClientSubscriptionsParams{}). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("DeleteAllTailnetTunnels", s.Subtest(func(db database.Store, check *expects) { + s.Run("DeleteAllTailnetTunnels", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.DeleteAllTailnetTunnelsParams{}). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("DeleteCoordinator", s.Subtest(func(db database.Store, check *expects) { + s.Run("DeleteCoordinator", s.Subtest(func(_ database.Store, check *expects) { check.Args(uuid.New()). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("DeleteTailnetAgent", s.Subtest(func(db database.Store, check *expects) { + s.Run("DeleteTailnetAgent", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.DeleteTailnetAgentParams{}). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate). - Errors(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate).Errors(sql.ErrNoRows). + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("DeleteTailnetClient", s.Subtest(func(db database.Store, check *expects) { + s.Run("DeleteTailnetClient", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.DeleteTailnetClientParams{}). - Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - Errors(dbmem.ErrUnimplemented) + Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete).Errors(sql.ErrNoRows). + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("DeleteTailnetClientSubscription", s.Subtest(func(db database.Store, check *expects) { + s.Run("DeleteTailnetClientSubscription", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.DeleteTailnetClientSubscriptionParams{}). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("DeleteTailnetPeer", s.Subtest(func(db database.Store, check *expects) { + s.Run("DeleteTailnetPeer", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.DeleteTailnetPeerParams{}). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented). + ErrorsWithPG(sql.ErrNoRows) })) - s.Run("DeleteTailnetTunnel", s.Subtest(func(db database.Store, check *expects) { + s.Run("DeleteTailnetTunnel", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.DeleteTailnetTunnelParams{}). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionDelete). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented). + ErrorsWithPG(sql.ErrNoRows) })) - s.Run("GetAllTailnetAgents", s.Subtest(func(db database.Store, check *expects) { + s.Run("GetAllTailnetAgents", s.Subtest(func(_ database.Store, check *expects) { check.Args(). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("GetTailnetAgents", s.Subtest(func(db database.Store, check *expects) { + s.Run("GetTailnetAgents", s.Subtest(func(_ database.Store, check *expects) { check.Args(uuid.New()). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("GetTailnetClientsForAgent", s.Subtest(func(db database.Store, check *expects) { + s.Run("GetTailnetClientsForAgent", s.Subtest(func(_ database.Store, check *expects) { check.Args(uuid.New()). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("GetTailnetPeers", s.Subtest(func(db database.Store, check *expects) { + s.Run("GetTailnetPeers", s.Subtest(func(_ database.Store, check *expects) { check.Args(uuid.New()). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("GetTailnetTunnelPeerBindings", s.Subtest(func(db database.Store, check *expects) { + s.Run("GetTailnetTunnelPeerBindings", s.Subtest(func(_ database.Store, check *expects) { check.Args(uuid.New()). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("GetTailnetTunnelPeerIDs", s.Subtest(func(db database.Store, check *expects) { + s.Run("GetTailnetTunnelPeerIDs", s.Subtest(func(_ database.Store, check *expects) { check.Args(uuid.New()). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("GetAllTailnetCoordinators", s.Subtest(func(db database.Store, check *expects) { + s.Run("GetAllTailnetCoordinators", s.Subtest(func(_ database.Store, check *expects) { check.Args(). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("GetAllTailnetPeers", s.Subtest(func(db database.Store, check *expects) { + s.Run("GetAllTailnetPeers", s.Subtest(func(_ database.Store, check *expects) { check.Args(). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("GetAllTailnetTunnels", s.Subtest(func(db database.Store, check *expects) { + s.Run("GetAllTailnetTunnels", s.Subtest(func(_ database.Store, check *expects) { check.Args(). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionRead). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) s.Run("UpsertTailnetAgent", s.Subtest(func(db database.Store, check *expects) { - check.Args(database.UpsertTailnetAgentParams{}). + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) + check.Args(database.UpsertTailnetAgentParams{Node: json.RawMessage("{}")}). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) s.Run("UpsertTailnetClient", s.Subtest(func(db database.Store, check *expects) { - check.Args(database.UpsertTailnetClientParams{}). + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) + check.Args(database.UpsertTailnetClientParams{Node: json.RawMessage("{}")}). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) s.Run("UpsertTailnetClientSubscription", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.UpsertTailnetClientSubscriptionParams{}). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("UpsertTailnetCoordinator", s.Subtest(func(db database.Store, check *expects) { + s.Run("UpsertTailnetCoordinator", s.Subtest(func(_ database.Store, check *expects) { check.Args(uuid.New()). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) s.Run("UpsertTailnetPeer", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.UpsertTailnetPeerParams{ Status: database.TailnetStatusOk, }). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionCreate). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) s.Run("UpsertTailnetTunnel", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.UpsertTailnetTunnelParams{}). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionCreate). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) - s.Run("UpdateTailnetPeerStatusByCoordinator", s.Subtest(func(_ database.Store, check *expects) { - check.Args(database.UpdateTailnetPeerStatusByCoordinatorParams{}). + s.Run("UpdateTailnetPeerStatusByCoordinator", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) + check.Args(database.UpdateTailnetPeerStatusByCoordinatorParams{Status: database.TailnetStatusOk}). Asserts(rbac.ResourceTailnetCoordinator, policy.ActionUpdate). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) } @@ -2395,6 +3471,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { }).Asserts(rbac.ResourceSystem, policy.ActionUpdate).Returns(l) })) s.Run("GetLatestWorkspaceBuildsByWorkspaceIDs", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID}) check.Args([]uuid.UUID{ws.ID}).Asserts(rbac.ResourceSystem, policy.ActionRead).Returns(slice.New(b)) @@ -2403,10 +3480,12 @@ func (s *MethodTestSuite) TestSystemFunctions() { check.Args(database.UpsertDefaultProxyParams{}).Asserts(rbac.ResourceSystem, policy.ActionUpdate).Returns() })) s.Run("GetUserLinkByLinkedID", s.Subtest(func(db database.Store, check *expects) { - l := dbgen.UserLink(s.T(), db, database.UserLink{}) + u := dbgen.User(s.T(), db, database.User{}) + l := dbgen.UserLink(s.T(), db, database.UserLink{UserID: u.ID}) check.Args(l.LinkedID).Asserts(rbac.ResourceSystem, policy.ActionRead).Returns(l) })) s.Run("GetUserLinkByUserIDLoginType", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) l := dbgen.UserLink(s.T(), db, database.UserLink{}) check.Args(database.GetUserLinkByUserIDLoginTypeParams{ UserID: l.UserID, @@ -2414,6 +3493,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { }).Asserts(rbac.ResourceSystem, policy.ActionRead).Returns(l) })) s.Run("GetLatestWorkspaceBuilds", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{}) dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{}) check.Args().Asserts(rbac.ResourceSystem, policy.ActionRead) @@ -2465,10 +3545,12 @@ func (s *MethodTestSuite) TestSystemFunctions() { check.Args().Asserts(rbac.ResourceSystem, policy.ActionRead).Returns(int64(0)) })) s.Run("GetTemplates", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) _ = dbgen.Template(s.T(), db, database.Template{}) check.Args().Asserts(rbac.ResourceSystem, policy.ActionRead) })) s.Run("UpdateWorkspaceBuildCostByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{}) o := b o.DailyCost = 10 @@ -2478,6 +3560,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { }).Asserts(rbac.ResourceSystem, policy.ActionUpdate) })) s.Run("UpdateWorkspaceBuildProvisionerStateByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) check.Args(database.UpdateWorkspaceBuildProvisionerStateByIDParams{ @@ -2494,22 +3577,27 @@ func (s *MethodTestSuite) TestSystemFunctions() { check.Args().Asserts(rbac.ResourceSystem, policy.ActionRead) })) s.Run("GetWorkspaceBuildsCreatedAfter", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) _ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{CreatedAt: time.Now().Add(-time.Hour)}) check.Args(time.Now()).Asserts(rbac.ResourceSystem, policy.ActionRead) })) s.Run("GetWorkspaceAgentsCreatedAfter", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) _ = dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{CreatedAt: time.Now().Add(-time.Hour)}) check.Args(time.Now()).Asserts(rbac.ResourceSystem, policy.ActionRead) })) s.Run("GetWorkspaceAppsCreatedAfter", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) _ = dbgen.WorkspaceApp(s.T(), db, database.WorkspaceApp{CreatedAt: time.Now().Add(-time.Hour), OpenIn: database.WorkspaceAppOpenInSlimWindow}) check.Args(time.Now()).Asserts(rbac.ResourceSystem, policy.ActionRead) })) s.Run("GetWorkspaceResourcesCreatedAfter", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) _ = dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{CreatedAt: time.Now().Add(-time.Hour)}) check.Args(time.Now()).Asserts(rbac.ResourceSystem, policy.ActionRead) })) s.Run("GetWorkspaceResourceMetadataCreatedAfter", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) _ = dbgen.WorkspaceResourceMetadatums(s.T(), db, database.WorkspaceResourceMetadatum{}) check.Args(time.Now()).Asserts(rbac.ResourceSystem, policy.ActionRead) })) @@ -2522,6 +3610,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { check.Args(time.Now()).Asserts( /*rbac.ResourceSystem, policy.ActionRead*/ ) })) s.Run("GetTemplateVersionsByIDs", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) t1 := dbgen.Template(s.T(), db, database.Template{}) t2 := dbgen.Template(s.T(), db, database.Template{}) tv1 := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ @@ -2538,15 +3627,19 @@ func (s *MethodTestSuite) TestSystemFunctions() { Returns(slice.New(tv1, tv2, tv3)) })) s.Run("GetParameterSchemasByJobID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) tpl := dbgen.Template(s.T(), db, database.Template{}) tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, }) job := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: tv.JobID}) check.Args(job.ID). - Asserts(tpl, policy.ActionRead).Errors(sql.ErrNoRows) + Asserts(tpl, policy.ActionRead). + ErrorsWithInMemDB(sql.ErrNoRows). + Returns([]database.ParameterSchema{}) })) s.Run("GetWorkspaceAppsByAgentIDs", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) aWs := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) aBuild := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: aWs.ID, JobID: uuid.New()}) aRes := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: aBuild.JobID}) @@ -2564,6 +3657,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { Returns([]database.WorkspaceApp{a, b}) })) s.Run("GetWorkspaceResourcesByJobIDs", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) tpl := dbgen.Template(s.T(), db, database.Template{}) v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, JobID: uuid.New()}) tJob := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: v.JobID, Type: database.ProvisionerJobTypeTemplateVersionImport}) @@ -2576,6 +3670,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { Returns([]database.WorkspaceResource{}) })) s.Run("GetWorkspaceResourceMetadataByResourceIDs", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) _ = dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ID: build.JobID, Type: database.ProvisionerJobTypeWorkspaceBuild}) @@ -2585,6 +3680,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { Asserts(rbac.ResourceSystem, policy.ActionRead) })) s.Run("GetWorkspaceAgentsByResourceIDs", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) @@ -2602,11 +3698,13 @@ func (s *MethodTestSuite) TestSystemFunctions() { Returns(slice.New(a, b)) })) s.Run("InsertWorkspaceAgent", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.InsertWorkspaceAgentParams{ ID: uuid.New(), }).Asserts(rbac.ResourceSystem, policy.ActionCreate) })) s.Run("InsertWorkspaceApp", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.InsertWorkspaceAppParams{ ID: uuid.New(), Health: database.WorkspaceAppHealthDisabled, @@ -2620,6 +3718,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { }).Asserts(rbac.ResourceSystem, policy.ActionCreate) })) s.Run("UpdateWorkspaceAgentConnectionByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) build := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: uuid.New()}) res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: build.JobID}) @@ -2632,9 +3731,14 @@ func (s *MethodTestSuite) TestSystemFunctions() { // TODO: we need to create a ProvisionerJob resource j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ StartedAt: sql.NullTime{Valid: false}, + UpdatedAt: time.Now(), }) - check.Args(database.AcquireProvisionerJobParams{OrganizationID: j.OrganizationID, Types: []database.ProvisionerType{j.Provisioner}, ProvisionerTags: must(json.Marshal(j.Tags))}). - Asserts( /*rbac.ResourceSystem, policy.ActionUpdate*/ ) + check.Args(database.AcquireProvisionerJobParams{ + StartedAt: sql.NullTime{Valid: true, Time: time.Now()}, + OrganizationID: j.OrganizationID, + Types: []database.ProvisionerType{j.Provisioner}, + ProvisionerTags: must(json.Marshal(j.Tags)), + }).Asserts( /*rbac.ResourceSystem, policy.ActionUpdate*/ ) })) s.Run("UpdateProvisionerJobWithCompleteByID", s.Subtest(func(db database.Store, check *expects) { // TODO: we need to create a ProvisionerJob resource @@ -2652,12 +3756,14 @@ func (s *MethodTestSuite) TestSystemFunctions() { }).Asserts( /*rbac.ResourceSystem, policy.ActionUpdate*/ ) })) s.Run("InsertProvisionerJob", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) // TODO: we need to create a ProvisionerJob resource check.Args(database.InsertProvisionerJobParams{ ID: uuid.New(), Provisioner: database.ProvisionerTypeEcho, StorageMethod: database.ProvisionerStorageMethodFile, Type: database.ProvisionerJobTypeWorkspaceBuild, + Input: json.RawMessage("{}"), }).Asserts( /*rbac.ResourceSystem, policy.ActionCreate*/ ) })) s.Run("InsertProvisionerJobLogs", s.Subtest(func(db database.Store, check *expects) { @@ -2675,16 +3781,19 @@ func (s *MethodTestSuite) TestSystemFunctions() { }).Asserts( /*rbac.ResourceSystem, policy.ActionCreate*/ ) })) s.Run("UpsertProvisionerDaemon", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) org := dbgen.Organization(s.T(), db, database.Organization{}) pd := rbac.ResourceProvisionerDaemon.InOrg(org.ID) check.Args(database.UpsertProvisionerDaemonParams{ OrganizationID: org.ID, + Provisioners: []database.ProvisionerType{}, Tags: database.StringMap(map[string]string{ provisionersdk.TagScope: provisionersdk.ScopeOrganization, }), }).Asserts(pd, policy.ActionCreate) check.Args(database.UpsertProvisionerDaemonParams{ OrganizationID: org.ID, + Provisioners: []database.ProvisionerType{}, Tags: database.StringMap(map[string]string{ provisionersdk.TagScope: provisionersdk.ScopeUser, provisionersdk.TagOwner: "11111111-1111-1111-1111-111111111111", @@ -2692,15 +3801,17 @@ func (s *MethodTestSuite) TestSystemFunctions() { }).Asserts(pd.WithOwner("11111111-1111-1111-1111-111111111111"), policy.ActionCreate) })) s.Run("InsertTemplateVersionParameter", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) v := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{}) check.Args(database.InsertTemplateVersionParameterParams{ TemplateVersionID: v.ID, + Options: json.RawMessage("{}"), }).Asserts(rbac.ResourceSystem, policy.ActionCreate) })) s.Run("InsertWorkspaceResource", s.Subtest(func(db database.Store, check *expects) { - r := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{}) + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.InsertWorkspaceResourceParams{ - ID: r.ID, + ID: uuid.New(), Transition: database.WorkspaceTransitionStart, }).Asserts(rbac.ResourceSystem, policy.ActionCreate) })) @@ -2714,6 +3825,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { check.Args(database.InsertWorkspaceAppStatsParams{}).Asserts(rbac.ResourceSystem, policy.ActionCreate) })) s.Run("InsertWorkspaceAgentScriptTimings", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.InsertWorkspaceAgentScriptTimingsParams{ ScriptID: uuid.New(), Stage: database.WorkspaceAgentScriptTimingStageStart, @@ -2724,6 +3836,7 @@ func (s *MethodTestSuite) TestSystemFunctions() { check.Args(database.InsertWorkspaceAgentScriptsParams{}).Asserts(rbac.ResourceSystem, policy.ActionCreate) })) s.Run("InsertWorkspaceAgentMetadata", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.InsertWorkspaceAgentMetadataParams{}).Asserts(rbac.ResourceSystem, policy.ActionCreate) })) s.Run("InsertWorkspaceAgentLogs", s.Subtest(func(db database.Store, check *expects) { @@ -2736,13 +3849,16 @@ func (s *MethodTestSuite) TestSystemFunctions() { check.Args(database.GetTemplateDAUsParams{}).Asserts(rbac.ResourceSystem, policy.ActionRead) })) s.Run("GetActiveWorkspaceBuildsByTemplateID", s.Subtest(func(db database.Store, check *expects) { - check.Args(uuid.New()).Asserts(rbac.ResourceSystem, policy.ActionRead).Errors(sql.ErrNoRows) + check.Args(uuid.New()). + Asserts(rbac.ResourceSystem, policy.ActionRead). + ErrorsWithInMemDB(sql.ErrNoRows). + Returns([]database.WorkspaceBuild{}) })) s.Run("GetDeploymentDAUs", s.Subtest(func(db database.Store, check *expects) { check.Args(int32(0)).Asserts(rbac.ResourceSystem, policy.ActionRead) })) s.Run("GetAppSecurityKey", s.Subtest(func(db database.Store, check *expects) { - check.Args().Asserts(rbac.ResourceSystem, policy.ActionRead) + check.Args().Asserts(rbac.ResourceSystem, policy.ActionRead).ErrorsWithPG(sql.ErrNoRows) })) s.Run("UpsertAppSecurityKey", s.Subtest(func(db database.Store, check *expects) { check.Args("foo").Asserts(rbac.ResourceSystem, policy.ActionUpdate) @@ -2836,13 +3952,17 @@ func (s *MethodTestSuite) TestSystemFunctions() { check.Args(time.Time{}).Asserts() })) s.Run("InsertTemplateVersionVariable", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.InsertTemplateVersionVariableParams{}).Asserts(rbac.ResourceSystem, policy.ActionCreate) })) s.Run("InsertTemplateVersionWorkspaceTag", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) check.Args(database.InsertTemplateVersionWorkspaceTagParams{}).Asserts(rbac.ResourceSystem, policy.ActionCreate) })) s.Run("UpdateInactiveUsersToDormant", s.Subtest(func(db database.Store, check *expects) { - check.Args(database.UpdateInactiveUsersToDormantParams{}).Asserts(rbac.ResourceSystem, policy.ActionCreate).Errors(sql.ErrNoRows) + check.Args(database.UpdateInactiveUsersToDormantParams{}).Asserts(rbac.ResourceSystem, policy.ActionCreate). + ErrorsWithInMemDB(sql.ErrNoRows). + Returns([]database.UpdateInactiveUsersToDormantRow{}) })) s.Run("GetWorkspaceUniqueOwnerCountByTemplateIDs", s.Subtest(func(db database.Store, check *expects) { check.Args([]uuid.UUID{uuid.New()}).Asserts(rbac.ResourceSystem, policy.ActionRead) @@ -2866,8 +3986,24 @@ func (s *MethodTestSuite) TestSystemFunctions() { check.Args(uuid.New()).Asserts(rbac.ResourceSystem, policy.ActionRead) })) s.Run("GetJFrogXrayScanByWorkspaceAndAgentID", s.Subtest(func(db database.Store, check *expects) { - ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) - agent := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{}) + u := dbgen.User(s.T(), db, database.User{}) + org := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: org.ID, + CreatedBy: u.ID, + }) + ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + OwnerID: u.ID, + OrganizationID: org.ID, + TemplateID: tpl.ID, + }) + pj := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{}) + res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{ + JobID: pj.ID, + }) + agent := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ + ResourceID: res.ID, + }) err := db.UpsertJFrogXrayScanByWorkspaceAndAgentID(context.Background(), database.UpsertJFrogXrayScanByWorkspaceAndAgentIDParams{ AgentID: agent.ID, @@ -2894,13 +4030,27 @@ func (s *MethodTestSuite) TestSystemFunctions() { }).Asserts(ws, policy.ActionRead).Returns(expect) })) s.Run("UpsertJFrogXrayScanByWorkspaceAndAgentID", s.Subtest(func(db database.Store, check *expects) { - tpl := dbgen.Template(s.T(), db, database.Template{}) + u := dbgen.User(s.T(), db, database.User{}) + org := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: org.ID, + CreatedBy: u.ID, + }) ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ - TemplateID: tpl.ID, + OwnerID: u.ID, + OrganizationID: org.ID, + TemplateID: tpl.ID, + }) + pj := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{}) + res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{ + JobID: pj.ID, + }) + agent := dbgen.WorkspaceAgent(s.T(), db, database.WorkspaceAgent{ + ResourceID: res.ID, }) check.Args(database.UpsertJFrogXrayScanByWorkspaceAndAgentIDParams{ WorkspaceID: ws.ID, - AgentID: uuid.New(), + AgentID: agent.ID, }).Asserts(tpl, policy.ActionCreate) })) s.Run("DeleteRuntimeConfig", s.Subtest(func(db database.Store, check *expects) { @@ -2942,15 +4092,31 @@ func (s *MethodTestSuite) TestSystemFunctions() { }).Asserts(rbac.ResourceSystem, policy.ActionCreate) })) s.Run("GetProvisionerJobTimingsByJobID", s.Subtest(func(db database.Store, check *expects) { - w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) + u := dbgen.User(s.T(), db, database.User{}) + org := dbgen.Organization(s.T(), db, database.Organization{}) + tpl := dbgen.Template(s.T(), db, database.Template{ + OrganizationID: org.ID, + CreatedBy: u.ID, + }) + tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + OrganizationID: org.ID, + TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true}, + CreatedBy: u.ID, + }) + w := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + OwnerID: u.ID, + OrganizationID: org.ID, + TemplateID: tpl.ID, + }) j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeWorkspaceBuild, }) - b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{JobID: j.ID, WorkspaceID: w.ID}) + b := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{JobID: j.ID, WorkspaceID: w.ID, TemplateVersionID: tv.ID}) t := dbgen.ProvisionerJobTimings(s.T(), db, b, 2) check.Args(j.ID).Asserts(w, policy.ActionRead).Returns(t) })) s.Run("GetWorkspaceAgentScriptTimingsByBuildID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) workspace := dbgen.Workspace(s.T(), db, database.WorkspaceTable{}) job := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeWorkspaceBuild, @@ -2983,6 +4149,9 @@ func (s *MethodTestSuite) TestSystemFunctions() { } check.Args(build.ID).Asserts(rbac.ResourceSystem, policy.ActionRead).Returns(rows) })) + s.Run("DisableForeignKeysAndTriggers", s.Subtest(func(db database.Store, check *expects) { + check.Args().Asserts() + })) s.Run("InsertWorkspaceModule", s.Subtest(func(db database.Store, check *expects) { j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ Type: database.ProvisionerJobTypeWorkspaceBuild, @@ -3014,7 +4183,9 @@ func (s *MethodTestSuite) TestNotifications() { s.Run("DeleteOldNotificationMessages", s.Subtest(func(_ database.Store, check *expects) { check.Args().Asserts(rbac.ResourceNotificationMessage, policy.ActionDelete) })) - s.Run("EnqueueNotificationMessage", s.Subtest(func(_ database.Store, check *expects) { + s.Run("EnqueueNotificationMessage", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) + // TODO: update this test once we have a specific role for notifications check.Args(database.EnqueueNotificationMessageParams{ Method: database.NotificationMethodWebhook, Payload: []byte("{}"), @@ -3022,7 +4193,9 @@ func (s *MethodTestSuite) TestNotifications() { })) s.Run("FetchNewMessageMetadata", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) - check.Args(database.FetchNewMessageMetadataParams{UserID: u.ID}).Asserts(rbac.ResourceNotificationMessage, policy.ActionRead) + check.Args(database.FetchNewMessageMetadataParams{UserID: u.ID}). + Asserts(rbac.ResourceNotificationMessage, policy.ActionRead). + ErrorsWithPG(sql.ErrNoRows) })) s.Run("GetNotificationMessagesByStatus", s.Subtest(func(_ database.Store, check *expects) { check.Args(database.GetNotificationMessagesByStatusParams{ @@ -3033,15 +4206,16 @@ func (s *MethodTestSuite) TestNotifications() { // Notification templates s.Run("GetNotificationTemplateByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) user := dbgen.User(s.T(), db, database.User{}) check.Args(user.ID).Asserts(rbac.ResourceNotificationTemplate, policy.ActionRead). - Errors(dbmem.ErrUnimplemented) + ErrorsWithPG(sql.ErrNoRows). + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) s.Run("GetNotificationTemplatesByKind", s.Subtest(func(db database.Store, check *expects) { check.Args(database.NotificationTemplateKindSystem). Asserts(). - Errors(dbmem.ErrUnimplemented) - + ErrorsWithInMemDB(dbmem.ErrUnimplemented) // TODO(dannyk): add support for other database.NotificationTemplateKind types once implemented. })) s.Run("UpdateNotificationTemplateMethodByID", s.Subtest(func(db database.Store, check *expects) { @@ -3049,7 +4223,7 @@ func (s *MethodTestSuite) TestNotifications() { Method: database.NullNotificationMethod{NotificationMethod: database.NotificationMethodWebhook, Valid: true}, ID: notifications.TemplateWorkspaceDormant, }).Asserts(rbac.ResourceNotificationTemplate, policy.ActionUpdate). - Errors(dbmem.ErrUnimplemented) + ErrorsWithInMemDB(dbmem.ErrUnimplemented) })) // Notification preferences @@ -3081,12 +4255,23 @@ func (s *MethodTestSuite) TestOAuth2ProviderApps() { check.Args(app.ID).Asserts(rbac.ResourceOauth2App, policy.ActionRead).Returns(app) })) s.Run("GetOAuth2ProviderAppsByUserID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) user := dbgen.User(s.T(), db, database.User{}) key, _ := dbgen.APIKey(s.T(), db, database.APIKey{ UserID: user.ID, }) - app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{}) - _ = dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{}) + createdAt := dbtestutil.NowInDefaultTimezone() + if !dbtestutil.WillUsePostgres() { + createdAt = time.Time{} + } + app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{ + CreatedAt: createdAt, + UpdatedAt: createdAt, + }) + _ = dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{ + CreatedAt: createdAt, + UpdatedAt: createdAt, + }) secret := dbgen.OAuth2ProviderAppSecret(s.T(), db, database.OAuth2ProviderAppSecret{ AppID: app.ID, }) @@ -3094,6 +4279,7 @@ func (s *MethodTestSuite) TestOAuth2ProviderApps() { _ = dbgen.OAuth2ProviderAppToken(s.T(), db, database.OAuth2ProviderAppToken{ AppSecretID: secret.ID, APIKeyID: key.ID, + HashPrefix: []byte(fmt.Sprintf("%d", i)), }) } check.Args(user.ID).Asserts(rbac.ResourceOauth2AppCodeToken.WithOwner(user.ID.String()), policy.ActionRead).Returns([]database.GetOAuth2ProviderAppsByUserIDRow{ @@ -3103,6 +4289,8 @@ func (s *MethodTestSuite) TestOAuth2ProviderApps() { CallbackURL: app.CallbackURL, Icon: app.Icon, Name: app.Name, + CreatedAt: createdAt, + UpdatedAt: createdAt, }, TokenCount: 5, }, @@ -3112,9 +4300,10 @@ func (s *MethodTestSuite) TestOAuth2ProviderApps() { check.Args(database.InsertOAuth2ProviderAppParams{}).Asserts(rbac.ResourceOauth2App, policy.ActionCreate) })) s.Run("UpdateOAuth2ProviderAppByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{}) app.Name = "my-new-name" - app.UpdatedAt = time.Now() + app.UpdatedAt = dbtestutil.NowInDefaultTimezone() check.Args(database.UpdateOAuth2ProviderAppByIDParams{ ID: app.ID, Name: app.Name, @@ -3130,19 +4319,23 @@ func (s *MethodTestSuite) TestOAuth2ProviderApps() { func (s *MethodTestSuite) TestOAuth2ProviderAppSecrets() { s.Run("GetOAuth2ProviderAppSecretsByAppID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) app1 := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{}) app2 := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{}) secrets := []database.OAuth2ProviderAppSecret{ dbgen.OAuth2ProviderAppSecret(s.T(), db, database.OAuth2ProviderAppSecret{ - AppID: app1.ID, - CreatedAt: time.Now().Add(-time.Hour), // For ordering. + AppID: app1.ID, + CreatedAt: time.Now().Add(-time.Hour), // For ordering. + SecretPrefix: []byte("1"), }), dbgen.OAuth2ProviderAppSecret(s.T(), db, database.OAuth2ProviderAppSecret{ - AppID: app1.ID, + AppID: app1.ID, + SecretPrefix: []byte("2"), }), } _ = dbgen.OAuth2ProviderAppSecret(s.T(), db, database.OAuth2ProviderAppSecret{ - AppID: app2.ID, + AppID: app2.ID, + SecretPrefix: []byte("3"), }) check.Args(app1.ID).Asserts(rbac.ResourceOauth2AppSecret, policy.ActionRead).Returns(secrets) })) @@ -3167,11 +4360,12 @@ func (s *MethodTestSuite) TestOAuth2ProviderAppSecrets() { }).Asserts(rbac.ResourceOauth2AppSecret, policy.ActionCreate) })) s.Run("UpdateOAuth2ProviderAppSecretByID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{}) secret := dbgen.OAuth2ProviderAppSecret(s.T(), db, database.OAuth2ProviderAppSecret{ AppID: app.ID, }) - secret.LastUsedAt = sql.NullTime{Time: time.Now(), Valid: true} + secret.LastUsedAt = sql.NullTime{Time: dbtestutil.NowInDefaultTimezone(), Valid: true} check.Args(database.UpdateOAuth2ProviderAppSecretByIDParams{ ID: secret.ID, LastUsedAt: secret.LastUsedAt, @@ -3223,12 +4417,14 @@ func (s *MethodTestSuite) TestOAuth2ProviderAppCodes() { check.Args(code.ID).Asserts(code, policy.ActionDelete) })) s.Run("DeleteOAuth2ProviderAppCodesByAppAndUserID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) user := dbgen.User(s.T(), db, database.User{}) app := dbgen.OAuth2ProviderApp(s.T(), db, database.OAuth2ProviderApp{}) for i := 0; i < 5; i++ { _ = dbgen.OAuth2ProviderAppCode(s.T(), db, database.OAuth2ProviderAppCode{ - AppID: app.ID, - UserID: user.ID, + AppID: app.ID, + UserID: user.ID, + SecretPrefix: []byte(fmt.Sprintf("%d", i)), }) } check.Args(database.DeleteOAuth2ProviderAppCodesByAppAndUserIDParams{ @@ -3269,6 +4465,7 @@ func (s *MethodTestSuite) TestOAuth2ProviderAppTokens() { check.Args(token.HashPrefix).Asserts(rbac.ResourceOauth2AppCodeToken.WithOwner(user.ID.String()), policy.ActionRead) })) s.Run("DeleteOAuth2ProviderAppTokensByAppAndUserID", s.Subtest(func(db database.Store, check *expects) { + dbtestutil.DisableForeignKeysAndTriggers(s.T(), db) user := dbgen.User(s.T(), db, database.User{}) key, _ := dbgen.APIKey(s.T(), db, database.APIKey{ UserID: user.ID, @@ -3281,6 +4478,7 @@ func (s *MethodTestSuite) TestOAuth2ProviderAppTokens() { _ = dbgen.OAuth2ProviderAppToken(s.T(), db, database.OAuth2ProviderAppToken{ AppSecretID: secret.ID, APIKeyID: key.ID, + HashPrefix: []byte(fmt.Sprintf("%d", i)), }) } check.Args(database.DeleteOAuth2ProviderAppTokensByAppAndUserIDParams{ diff --git a/coderd/database/dbauthz/groupsauth_test.go b/coderd/database/dbauthz/groupsauth_test.go index a72c4db3af38a..04d816629ac65 100644 --- a/coderd/database/dbauthz/groupsauth_test.go +++ b/coderd/database/dbauthz/groupsauth_test.go @@ -13,7 +13,6 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/database/dbgen" - "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/rbac" ) @@ -22,13 +21,9 @@ import ( func TestGroupsAuth(t *testing.T) { t.Parallel() - if dbtestutil.WillUsePostgres() { - t.Skip("this test would take too long to run on postgres") - } - authz := rbac.NewAuthorizer(prometheus.NewRegistry()) - - db := dbauthz.New(dbmem.New(), authz, slogtest.Make(t, &slogtest.Options{ + store, _ := dbtestutil.NewDB(t) + db := dbauthz.New(store, authz, slogtest.Make(t, &slogtest.Options{ IgnoreErrors: true, }), coderdtest.AccessControlStorePointer()) diff --git a/coderd/database/dbauthz/setup_test.go b/coderd/database/dbauthz/setup_test.go index 52e8dd42fea9c..fc01e39330d7d 100644 --- a/coderd/database/dbauthz/setup_test.go +++ b/coderd/database/dbauthz/setup_test.go @@ -22,8 +22,8 @@ import ( "github.com/coder/coder/v2/coderd/coderdtest" "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbauthz" - "github.com/coder/coder/v2/coderd/database/dbmem" "github.com/coder/coder/v2/coderd/database/dbmock" + "github.com/coder/coder/v2/coderd/database/dbtestutil" "github.com/coder/coder/v2/coderd/rbac" "github.com/coder/coder/v2/coderd/rbac/regosql" "github.com/coder/coder/v2/coderd/util/slice" @@ -114,7 +114,7 @@ func (s *MethodTestSuite) Subtest(testCaseF func(db database.Store, check *expec methodName := names[len(names)-1] s.methodAccounting[methodName]++ - db := dbmem.New() + db, _ := dbtestutil.NewDB(t) fakeAuthorizer := &coderdtest.FakeAuthorizer{} rec := &coderdtest.RecordingAuthorizer{ Wrapped: fakeAuthorizer, @@ -217,7 +217,11 @@ func (s *MethodTestSuite) Subtest(testCaseF func(db database.Store, check *expec } } - rec.AssertActor(s.T(), actor, pairs...) + if testCase.outOfOrder { + rec.AssertOutOfOrder(s.T(), actor, pairs...) + } else { + rec.AssertActor(s.T(), actor, pairs...) + } s.NoError(rec.AllAsserted(), "all rbac calls must be asserted") }) } @@ -236,6 +240,8 @@ func (s *MethodTestSuite) NoActorErrorTest(callMethod func(ctx context.Context) func (s *MethodTestSuite) NotAuthorizedErrorTest(ctx context.Context, az *coderdtest.FakeAuthorizer, testCase expects, callMethod func(ctx context.Context) ([]reflect.Value, error)) { s.Run("NotAuthorized", func() { az.AlwaysReturn(rbac.ForbiddenWithInternal(xerrors.New("Always fail authz"), rbac.Subject{}, "", rbac.Object{}, nil)) + // Override the SQL filter to always fail. + az.OverrideSQLFilter("FALSE") // If we have assertions, that means the method should FAIL // if RBAC will disallow the request. The returned error should @@ -328,6 +334,14 @@ type expects struct { notAuthorizedExpect string cancelledCtxExpect string successAuthorizer func(ctx context.Context, subject rbac.Subject, action policy.Action, obj rbac.Object) error + outOfOrder bool +} + +// OutOfOrder is optional. It controls whether the assertions should be +// asserted in order. +func (m *expects) OutOfOrder() *expects { + m.outOfOrder = true + return m } // Asserts is required. Asserts the RBAC authorize calls that should be made. @@ -358,6 +372,24 @@ func (m *expects) Errors(err error) *expects { return m } +// ErrorsWithPG is optional. If it is never called, it will not be asserted. +// It will only be asserted if the test is running with a Postgres database. +func (m *expects) ErrorsWithPG(err error) *expects { + if dbtestutil.WillUsePostgres() { + return m.Errors(err) + } + return m +} + +// ErrorsWithInMemDB is optional. If it is never called, it will not be asserted. +// It will only be asserted if the test is running with an in-memory database. +func (m *expects) ErrorsWithInMemDB(err error) *expects { + if !dbtestutil.WillUsePostgres() { + return m.Errors(err) + } + return m +} + func (m *expects) FailSystemObjectChecks() *expects { return m.WithSuccessAuthorizer(func(ctx context.Context, subject rbac.Subject, action policy.Action, obj rbac.Object) error { if obj.Type == rbac.ResourceSystem.Type { diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 2895fd15ad49c..d3b7b3fb35f5f 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -2206,6 +2206,11 @@ func (q *FakeQuerier) DeleteWorkspaceAgentPortSharesByTemplate(_ context.Context return nil } +func (*FakeQuerier) DisableForeignKeysAndTriggers(_ context.Context) error { + // This is a no-op in the in-memory database. + return nil +} + func (q *FakeQuerier) EnqueueNotificationMessage(_ context.Context, arg database.EnqueueNotificationMessageParams) error { err := validateDatabaseType(arg) if err != nil { diff --git a/coderd/database/dbmetrics/querymetrics.go b/coderd/database/dbmetrics/querymetrics.go index 645357d6f095e..5df5c547a20d6 100644 --- a/coderd/database/dbmetrics/querymetrics.go +++ b/coderd/database/dbmetrics/querymetrics.go @@ -413,6 +413,13 @@ func (m queryMetricsStore) DeleteWorkspaceAgentPortSharesByTemplate(ctx context. return r0 } +func (m queryMetricsStore) DisableForeignKeysAndTriggers(ctx context.Context) error { + start := time.Now() + r0 := m.s.DisableForeignKeysAndTriggers(ctx) + m.queryLatencies.WithLabelValues("DisableForeignKeysAndTriggers").Observe(time.Since(start).Seconds()) + return r0 +} + func (m queryMetricsStore) EnqueueNotificationMessage(ctx context.Context, arg database.EnqueueNotificationMessageParams) error { start := time.Now() r0 := m.s.EnqueueNotificationMessage(ctx, arg) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 73a0e6d60af55..6b552fe5060ff 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -728,6 +728,20 @@ func (mr *MockStoreMockRecorder) DeleteWorkspaceAgentPortSharesByTemplate(arg0, return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteWorkspaceAgentPortSharesByTemplate", reflect.TypeOf((*MockStore)(nil).DeleteWorkspaceAgentPortSharesByTemplate), arg0, arg1) } +// DisableForeignKeysAndTriggers mocks base method. +func (m *MockStore) DisableForeignKeysAndTriggers(arg0 context.Context) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DisableForeignKeysAndTriggers", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// DisableForeignKeysAndTriggers indicates an expected call of DisableForeignKeysAndTriggers. +func (mr *MockStoreMockRecorder) DisableForeignKeysAndTriggers(arg0 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisableForeignKeysAndTriggers", reflect.TypeOf((*MockStore)(nil).DisableForeignKeysAndTriggers), arg0) +} + // EnqueueNotificationMessage mocks base method. func (m *MockStore) EnqueueNotificationMessage(arg0 context.Context, arg1 database.EnqueueNotificationMessageParams) error { m.ctrl.T.Helper() diff --git a/coderd/database/dbtestutil/db.go b/coderd/database/dbtestutil/db.go index b752d7c4c3a97..c76be1ed52a9d 100644 --- a/coderd/database/dbtestutil/db.go +++ b/coderd/database/dbtestutil/db.go @@ -87,6 +87,18 @@ func NewDBWithSQLDB(t testing.TB, opts ...Option) (database.Store, pubsub.Pubsub return db, ps, sqlDB } +var DefaultTimezone = "Canada/Newfoundland" + +// NowInDefaultTimezone returns the current time rounded to the nearest microsecond in the default timezone +// used by postgres in tests. Useful for object equality checks. +func NowInDefaultTimezone() time.Time { + loc, err := time.LoadLocation(DefaultTimezone) + if err != nil { + panic(err) + } + return time.Now().In(loc).Round(time.Microsecond) +} + func NewDB(t testing.TB, opts ...Option) (database.Store, pubsub.Pubsub) { t.Helper() @@ -115,7 +127,7 @@ func NewDB(t testing.TB, opts ...Option) (database.Store, pubsub.Pubsub) { // - It has a non-UTC offset // - It has a fractional hour UTC offset // - It includes a daylight savings time component - o.fixedTimezone = "Canada/Newfoundland" + o.fixedTimezone = DefaultTimezone } dbName := dbNameFromConnectionURL(t, connectionURL) setDBTimezone(t, connectionURL, dbName, o.fixedTimezone) @@ -318,3 +330,15 @@ func normalizeDump(schema []byte) []byte { return schema } + +// Deprecated: disable foreign keys was created to aid in migrating off +// of the test-only in-memory database. Do not use this in new code. +func DisableForeignKeysAndTriggers(t *testing.T, db database.Store) { + err := db.DisableForeignKeysAndTriggers(context.Background()) + if t != nil { + require.NoError(t, err) + } + if err != nil { + panic(err) + } +} diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 2128315ce6dad..620cc14b3fd26 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -106,6 +106,10 @@ type sqlcQuerier interface { DeleteTailnetTunnel(ctx context.Context, arg DeleteTailnetTunnelParams) (DeleteTailnetTunnelRow, error) DeleteWorkspaceAgentPortShare(ctx context.Context, arg DeleteWorkspaceAgentPortShareParams) error DeleteWorkspaceAgentPortSharesByTemplate(ctx context.Context, templateID uuid.UUID) error + // Disable foreign keys and triggers for all tables. + // Deprecated: disable foreign keys was created to aid in migrating off + // of the test-only in-memory database. Do not use this in new code. + DisableForeignKeysAndTriggers(ctx context.Context) error EnqueueNotificationMessage(ctx context.Context, arg EnqueueNotificationMessageParams) error FavoriteWorkspace(ctx context.Context, id uuid.UUID) error // This is used to build up the notification_message's JSON payload. diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 78b1609ca4bfd..8fbb7c0b5be6c 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -9796,6 +9796,33 @@ func (q *sqlQuerier) InsertTemplateVersionWorkspaceTag(ctx context.Context, arg return i, err } +const disableForeignKeysAndTriggers = `-- name: DisableForeignKeysAndTriggers :exec +DO $$ +DECLARE + table_record record; +BEGIN + FOR table_record IN + SELECT table_schema, table_name + FROM information_schema.tables + WHERE table_schema NOT IN ('pg_catalog', 'information_schema') + AND table_type = 'BASE TABLE' + LOOP + EXECUTE format('ALTER TABLE %I.%I DISABLE TRIGGER ALL', + table_record.table_schema, + table_record.table_name); + END LOOP; +END; +$$ +` + +// Disable foreign keys and triggers for all tables. +// Deprecated: disable foreign keys was created to aid in migrating off +// of the test-only in-memory database. Do not use this in new code. +func (q *sqlQuerier) DisableForeignKeysAndTriggers(ctx context.Context) error { + _, err := q.db.ExecContext(ctx, disableForeignKeysAndTriggers) + return err +} + const getUserLinkByLinkedID = `-- name: GetUserLinkByLinkedID :one SELECT user_links.user_id, user_links.login_type, user_links.linked_id, user_links.oauth_access_token, user_links.oauth_refresh_token, user_links.oauth_expiry, user_links.oauth_access_token_key_id, user_links.oauth_refresh_token_key_id, user_links.claims diff --git a/coderd/database/queries/testadmin.sql b/coderd/database/queries/testadmin.sql new file mode 100644 index 0000000000000..77d39ce52768c --- /dev/null +++ b/coderd/database/queries/testadmin.sql @@ -0,0 +1,20 @@ +-- name: DisableForeignKeysAndTriggers :exec +-- Disable foreign keys and triggers for all tables. +-- Deprecated: disable foreign keys was created to aid in migrating off +-- of the test-only in-memory database. Do not use this in new code. +DO $$ +DECLARE + table_record record; +BEGIN + FOR table_record IN + SELECT table_schema, table_name + FROM information_schema.tables + WHERE table_schema NOT IN ('pg_catalog', 'information_schema') + AND table_type = 'BASE TABLE' + LOOP + EXECUTE format('ALTER TABLE %I.%I DISABLE TRIGGER ALL', + table_record.table_schema, + table_record.table_name); + END LOOP; +END; +$$;