Skip to content

Commit a353f98

Browse files
committed
test
1 parent 9d91c42 commit a353f98

File tree

2 files changed

+162
-32
lines changed

2 files changed

+162
-32
lines changed

cli/provisioners_test.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package cli_test
2+
3+
import (
4+
"database/sql"
5+
"encoding/json"
6+
"testing"
7+
"time"
8+
9+
"github.com/google/uuid"
10+
"github.com/stretchr/testify/require"
11+
12+
"github.com/coder/coder/v2/cli/clitest"
13+
"github.com/coder/coder/v2/coderd/coderdtest"
14+
"github.com/coder/coder/v2/coderd/database"
15+
"github.com/coder/coder/v2/coderd/database/dbgen"
16+
"github.com/coder/coder/v2/coderd/database/dbtestutil"
17+
"github.com/coder/coder/v2/codersdk"
18+
)
19+
20+
func TestProvisioners(t *testing.T) {
21+
t.Parallel()
22+
23+
t.Run("List", func(t *testing.T) {
24+
t.Parallel()
25+
26+
db, ps := dbtestutil.NewDB(t, dbtestutil.WithDumpOnFailure())
27+
client, _, coderdAPI := coderdtest.NewWithAPI(t, &coderdtest.Options{
28+
IncludeProvisionerDaemon: true,
29+
Database: db,
30+
Pubsub: ps,
31+
})
32+
owner := coderdtest.CreateFirstUser(t, client)
33+
member, memberUser := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID)
34+
35+
version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, completeWithAgent())
36+
coderdtest.AwaitTemplateVersionJobCompleted(t, client, version.ID)
37+
template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID)
38+
39+
workspace := coderdtest.CreateWorkspace(t, client, template.ID)
40+
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)
41+
42+
// Create a provisioner that's working on a job.
43+
pd1 := dbgen.ProvisionerDaemon(t, coderdAPI.Database, database.ProvisionerDaemon{
44+
Name: "provisioner-1",
45+
CreatedAt: timeParse(t, "2006-01-02", "2024-12-20"),
46+
KeyID: uuid.MustParse(codersdk.ProvisionerKeyIDBuiltIn),
47+
})
48+
w1 := dbgen.Workspace(t, coderdAPI.Database, database.WorkspaceTable{
49+
OwnerID: memberUser.ID,
50+
TemplateID: template.ID,
51+
})
52+
wb1ID := uuid.MustParse("00000000-0000-0000-bbbb-000000000001")
53+
job1 := dbgen.ProvisionerJob(t, db, coderdAPI.Pubsub, database.ProvisionerJob{
54+
ID: uuid.MustParse("00000000-0000-0000-cccc-000000000001"),
55+
WorkerID: uuid.NullUUID{UUID: pd1.ID, Valid: true},
56+
Input: json.RawMessage(`{"workspace_build_id":"` + wb1ID.String() + `"}`),
57+
StartedAt: sql.NullTime{Time: coderdAPI.Clock.Now(), Valid: true},
58+
})
59+
dbgen.WorkspaceBuild(t, coderdAPI.Database, database.WorkspaceBuild{
60+
ID: wb1ID,
61+
JobID: job1.ID,
62+
WorkspaceID: w1.ID,
63+
TemplateVersionID: version.ID,
64+
})
65+
66+
// Create another provisioner that completed a job and is offline.
67+
pd2 := dbgen.ProvisionerDaemon(t, coderdAPI.Database, database.ProvisionerDaemon{
68+
Name: "provisioner-2",
69+
CreatedAt: timeParse(t, "2006-01-02", "2024-12-20"),
70+
LastSeenAt: sql.NullTime{Time: coderdAPI.Clock.Now().Add(-time.Hour), Valid: true},
71+
KeyID: uuid.MustParse(codersdk.ProvisionerKeyIDBuiltIn),
72+
})
73+
w2 := dbgen.Workspace(t, coderdAPI.Database, database.WorkspaceTable{
74+
OwnerID: memberUser.ID,
75+
TemplateID: template.ID,
76+
})
77+
wb2ID := uuid.MustParse("00000000-0000-0000-bbbb-000000000002")
78+
job2 := dbgen.ProvisionerJob(t, db, coderdAPI.Pubsub, database.ProvisionerJob{
79+
ID: uuid.MustParse("00000000-0000-0000-cccc-000000000002"),
80+
WorkerID: uuid.NullUUID{UUID: pd2.ID, Valid: true},
81+
Input: json.RawMessage(`{"workspace_build_id":"` + wb2ID.String() + `"}`),
82+
StartedAt: sql.NullTime{Time: coderdAPI.Clock.Now().Add(-2 * time.Hour), Valid: true},
83+
CompletedAt: sql.NullTime{Time: coderdAPI.Clock.Now().Add(-time.Hour), Valid: true},
84+
})
85+
dbgen.WorkspaceBuild(t, coderdAPI.Database, database.WorkspaceBuild{
86+
ID: wb2ID,
87+
JobID: job2.ID,
88+
WorkspaceID: w2.ID,
89+
TemplateVersionID: version.ID,
90+
})
91+
92+
// Create a provisioner that is idle.
93+
pd3 := dbgen.ProvisionerDaemon(t, coderdAPI.Database, database.ProvisionerDaemon{
94+
Name: "provisioner-3",
95+
CreatedAt: timeParse(t, "2006-01-02", "2024-12-20"),
96+
KeyID: uuid.MustParse(codersdk.ProvisionerKeyIDBuiltIn),
97+
})
98+
_ = pd3
99+
100+
inv, root := clitest.New(t,
101+
"provisioners",
102+
"list",
103+
"--column", "id,created at,last seen at,name,version,api version,tags,status,current job id,previous job id,previous job status,organization",
104+
)
105+
clitest.SetupConfig(t, member, root)
106+
err := inv.Run()
107+
require.NoError(t, err)
108+
109+
// TODO(mafredri): Verify golden output.
110+
})
111+
}
112+
113+
func timeParse(t *testing.T, layout, s string) time.Time {
114+
t.Helper()
115+
tm, err := time.Parse(layout, s)
116+
require.NoError(t, err)
117+
return tm
118+
}

coderd/database/dbgen/dbgen.go

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -248,12 +248,18 @@ func WorkspaceAgentScriptTiming(t testing.TB, db database.Store, orig database.W
248248
func Workspace(t testing.TB, db database.Store, orig database.WorkspaceTable) database.WorkspaceTable {
249249
t.Helper()
250250

251+
var defOrgID uuid.UUID
252+
if orig.OrganizationID == uuid.Nil {
253+
defOrg, _ := db.GetDefaultOrganization(genCtx)
254+
defOrgID = defOrg.ID
255+
}
256+
251257
workspace, err := db.InsertWorkspace(genCtx, database.InsertWorkspaceParams{
252258
ID: takeFirst(orig.ID, uuid.New()),
253259
OwnerID: takeFirst(orig.OwnerID, uuid.New()),
254260
CreatedAt: takeFirst(orig.CreatedAt, dbtime.Now()),
255261
UpdatedAt: takeFirst(orig.UpdatedAt, dbtime.Now()),
256-
OrganizationID: takeFirst(orig.OrganizationID, uuid.New()),
262+
OrganizationID: takeFirst(orig.OrganizationID, defOrgID, uuid.New()),
257263
TemplateID: takeFirst(orig.TemplateID, uuid.New()),
258264
LastUsedAt: takeFirst(orig.LastUsedAt, dbtime.Now()),
259265
Name: takeFirst(orig.Name, testutil.GetRandomName(t)),
@@ -505,9 +511,27 @@ func GroupMember(t testing.TB, db database.Store, member database.GroupMemberTab
505511

506512
// ProvisionerDaemon creates a provisioner daemon as far as the database is concerned. It does not run a provisioner daemon.
507513
// If no key is provided, it will create one.
508-
func ProvisionerDaemon(t testing.TB, db database.Store, daemon database.ProvisionerDaemon) database.ProvisionerDaemon {
514+
func ProvisionerDaemon(t testing.TB, db database.Store, orig database.ProvisionerDaemon) database.ProvisionerDaemon {
509515
t.Helper()
510516

517+
var defOrgID uuid.UUID
518+
if orig.OrganizationID == uuid.Nil {
519+
defOrg, _ := db.GetDefaultOrganization(genCtx)
520+
defOrgID = defOrg.ID
521+
}
522+
523+
daemon := database.UpsertProvisionerDaemonParams{
524+
Name: takeFirst(orig.Name, testutil.GetRandomName(t)),
525+
OrganizationID: takeFirst(orig.OrganizationID, defOrgID, uuid.New()),
526+
CreatedAt: takeFirst(orig.CreatedAt, dbtime.Now()),
527+
Provisioners: takeFirstSlice(orig.Provisioners, []database.ProvisionerType{database.ProvisionerTypeEcho}),
528+
Tags: takeFirstMap(orig.Tags, database.StringMap{"owner": "", "scope": "organization"}),
529+
KeyID: takeFirst(orig.KeyID, uuid.Nil),
530+
LastSeenAt: takeFirst(orig.LastSeenAt, sql.NullTime{Time: dbtime.Now(), Valid: true}),
531+
Version: takeFirst(orig.Version, "v0.0.0"),
532+
APIVersion: takeFirst(orig.APIVersion, "1.1"),
533+
}
534+
511535
if daemon.KeyID == uuid.Nil {
512536
key, err := db.InsertProvisionerKey(genCtx, database.InsertProvisionerKeyParams{
513537
ID: uuid.New(),
@@ -521,24 +545,7 @@ func ProvisionerDaemon(t testing.TB, db database.Store, daemon database.Provisio
521545
daemon.KeyID = key.ID
522546
}
523547

524-
if daemon.CreatedAt.IsZero() {
525-
daemon.CreatedAt = dbtime.Now()
526-
}
527-
if daemon.Name == "" {
528-
daemon.Name = "test-daemon"
529-
}
530-
531-
d, err := db.UpsertProvisionerDaemon(genCtx, database.UpsertProvisionerDaemonParams{
532-
Name: daemon.Name,
533-
OrganizationID: daemon.OrganizationID,
534-
CreatedAt: daemon.CreatedAt,
535-
Provisioners: daemon.Provisioners,
536-
Tags: daemon.Tags,
537-
KeyID: daemon.KeyID,
538-
LastSeenAt: daemon.LastSeenAt,
539-
Version: daemon.Version,
540-
APIVersion: daemon.APIVersion,
541-
})
548+
d, err := db.UpsertProvisionerDaemon(genCtx, daemon)
542549
require.NoError(t, err)
543550
return d
544551
}
@@ -556,12 +563,10 @@ func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig data
556563

557564
jobID := takeFirst(orig.ID, uuid.New())
558565
// Always set some tags to prevent Acquire from grabbing jobs it should not.
559-
if !orig.StartedAt.Time.IsZero() {
560-
if orig.Tags == nil {
561-
orig.Tags = make(database.StringMap)
562-
}
566+
tags := takeFirstMap(orig.Tags, database.StringMap{"owner": "", "scope": "organization"})
567+
if orig.Tags == nil && !orig.StartedAt.Time.IsZero() {
563568
// Make sure when we acquire the job, we only get this one.
564-
orig.Tags[jobID.String()] = "true"
569+
tags[jobID.String()] = "true"
565570
}
566571

567572
job, err := db.InsertProvisionerJob(genCtx, database.InsertProvisionerJobParams{
@@ -575,7 +580,7 @@ func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig data
575580
FileID: takeFirst(orig.FileID, uuid.New()),
576581
Type: takeFirst(orig.Type, database.ProvisionerJobTypeWorkspaceBuild),
577582
Input: takeFirstSlice(orig.Input, []byte("{}")),
578-
Tags: orig.Tags,
583+
Tags: tags,
579584
TraceMetadata: pqtype.NullRawMessage{},
580585
})
581586
require.NoError(t, err, "insert job")
@@ -587,17 +592,18 @@ func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig data
587592
job, err = db.AcquireProvisionerJob(genCtx, database.AcquireProvisionerJobParams{
588593
StartedAt: orig.StartedAt,
589594
OrganizationID: job.OrganizationID,
590-
Types: []database.ProvisionerType{database.ProvisionerTypeEcho},
591-
ProvisionerTags: must(json.Marshal(orig.Tags)),
592-
WorkerID: uuid.NullUUID{},
595+
Types: []database.ProvisionerType{job.Provisioner},
596+
ProvisionerTags: must(json.Marshal(tags)),
597+
WorkerID: takeFirst(orig.WorkerID, uuid.NullUUID{}),
593598
})
594599
require.NoError(t, err)
595600
// There is no easy way to make sure we acquire the correct job.
596601
require.Equal(t, jobID, job.ID, "acquired incorrect job")
602+
fmt.Printf("%#v\n", job)
597603
}
598604

599605
if !orig.CompletedAt.Time.IsZero() || orig.Error.String != "" {
600-
err := db.UpdateProvisionerJobWithCompleteByID(genCtx, database.UpdateProvisionerJobWithCompleteByIDParams{
606+
err = db.UpdateProvisionerJobWithCompleteByID(genCtx, database.UpdateProvisionerJobWithCompleteByIDParams{
601607
ID: jobID,
602608
UpdatedAt: job.UpdatedAt,
603609
CompletedAt: orig.CompletedAt,
@@ -607,7 +613,7 @@ func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig data
607613
require.NoError(t, err)
608614
}
609615
if !orig.CanceledAt.Time.IsZero() {
610-
err := db.UpdateProvisionerJobWithCancelByID(genCtx, database.UpdateProvisionerJobWithCancelByIDParams{
616+
err = db.UpdateProvisionerJobWithCancelByID(genCtx, database.UpdateProvisionerJobWithCancelByIDParams{
611617
ID: jobID,
612618
CanceledAt: orig.CanceledAt,
613619
CompletedAt: orig.CompletedAt,
@@ -616,7 +622,7 @@ func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig data
616622
}
617623

618624
job, err = db.GetProvisionerJobByID(genCtx, jobID)
619-
require.NoError(t, err)
625+
require.NoError(t, err, "get job: %s", jobID.String())
620626

621627
return job
622628
}
@@ -1108,6 +1114,12 @@ func takeFirstSlice[T any](values ...[]T) []T {
11081114
})
11091115
}
11101116

1117+
func takeFirstMap[T, E comparable](values ...map[T]E) map[T]E {
1118+
return takeFirstF(values, func(v map[T]E) bool {
1119+
return v != nil
1120+
})
1121+
}
1122+
11111123
// takeFirstF takes the first value that returns true
11121124
func takeFirstF[Value any](values []Value, take func(v Value) bool) Value {
11131125
for _, v := range values {

0 commit comments

Comments
 (0)