1
1
package cli_test
2
2
3
3
import (
4
+ "bytes"
5
+ "context"
4
6
"database/sql"
5
7
"encoding/json"
8
+ "fmt"
9
+ "slices"
6
10
"testing"
7
11
"time"
8
12
9
13
"github.com/google/uuid"
10
14
"github.com/stretchr/testify/require"
11
15
12
16
"github.com/coder/coder/v2/cli/clitest"
17
+ "github.com/coder/coder/v2/coderd"
13
18
"github.com/coder/coder/v2/coderd/coderdtest"
14
19
"github.com/coder/coder/v2/coderd/database"
20
+ "github.com/coder/coder/v2/coderd/database/dbauthz"
15
21
"github.com/coder/coder/v2/coderd/database/dbgen"
16
22
"github.com/coder/coder/v2/coderd/database/dbtestutil"
23
+ "github.com/coder/coder/v2/coderd/database/dbtime"
17
24
"github.com/coder/coder/v2/codersdk"
18
25
)
19
26
20
- func TestProvisioners (t * testing.T ) {
27
+ func TestProvisioners_Golden (t * testing.T ) {
21
28
t .Parallel ()
22
29
23
- db , ps := dbtestutil .NewDB (t , dbtestutil .WithDumpOnFailure ())
30
+ // Replace UUIDs with predictable values for golden files.
31
+ replace := make (map [string ]string )
32
+ updateReplaceUUIDs := func (coderdAPI * coderd.API ) {
33
+ //nolint:gocritic // This is a test.
34
+ systemCtx := dbauthz .AsSystemRestricted (context .Background ())
35
+ provisioners , err := coderdAPI .Database .GetProvisionerDaemons (systemCtx )
36
+ require .NoError (t , err )
37
+ slices .SortFunc (provisioners , func (a , b database.ProvisionerDaemon ) int {
38
+ return a .CreatedAt .Compare (b .CreatedAt )
39
+ })
40
+ pIdx := 0
41
+ for _ , p := range provisioners {
42
+ if _ , ok := replace [p .ID .String ()]; ! ok {
43
+ replace [p .ID .String ()] = fmt .Sprintf ("00000000-0000-0000-aaaa-%012d" , pIdx )
44
+ pIdx ++
45
+ }
46
+ }
47
+ jobs , err := coderdAPI .Database .GetProvisionerJobsCreatedAfter (systemCtx , time.Time {})
48
+ require .NoError (t , err )
49
+ slices .SortFunc (jobs , func (a , b database.ProvisionerJob ) int {
50
+ return a .CreatedAt .Compare (b .CreatedAt )
51
+ })
52
+ jIdx := 0
53
+ for _ , j := range jobs {
54
+ if _ , ok := replace [j .ID .String ()]; ! ok {
55
+ replace [j .ID .String ()] = fmt .Sprintf ("00000000-0000-0000-bbbb-%012d" , jIdx )
56
+ jIdx ++
57
+ }
58
+ }
59
+ }
60
+
61
+ db , ps := dbtestutil .NewDB (t ,
62
+ dbtestutil .WithDumpOnFailure (),
63
+ //nolint:gocritic // Use UTC for consistent timestamp length in golden files.
64
+ dbtestutil .WithTimezone ("UTC" ),
65
+ )
24
66
client , _ , coderdAPI := coderdtest .NewWithAPI (t , & coderdtest.Options {
25
67
IncludeProvisionerDaemon : false ,
26
68
Database : db ,
@@ -36,27 +78,32 @@ func TestProvisioners(t *testing.T) {
36
78
coderdtest .AwaitTemplateVersionJobCompleted (t , client , version .ID )
37
79
template := coderdtest .CreateTemplate (t , client , owner .OrganizationID , version .ID )
38
80
81
+ time .Sleep (1500 * time .Millisecond ) // Ensure the workspace build job has a different timestamp for sorting.
39
82
workspace := coderdtest .CreateWorkspace (t , client , template .ID )
40
83
coderdtest .AwaitWorkspaceBuildJobCompleted (t , client , workspace .LatestBuild .ID )
41
84
42
- // Stop the provisioner so it doesn't grab jobs.
85
+ // Stop the provisioner so it doesn't grab any more jobs.
43
86
firstProvisioner .Close ()
44
87
88
+ // Sanitize the UUIDs for the initial resources.
89
+ replace [version .ID .String ()] = "00000000-0000-0000-cccc-000000000000"
90
+ replace [workspace .LatestBuild .ID .String ()] = "00000000-0000-0000-dddd-000000000000"
91
+
45
92
// Create a provisioner that's working on a job.
46
93
pd1 := dbgen .ProvisionerDaemon (t , coderdAPI .Database , database.ProvisionerDaemon {
47
94
Name : "provisioner-1" ,
48
- CreatedAt : timeParse ( t , "2006-01-02" , "2024-12-20" ),
95
+ CreatedAt : dbtime . Now (). Add ( 1 * time . Second ),
49
96
KeyID : uuid .MustParse (codersdk .ProvisionerKeyIDBuiltIn ),
50
97
})
51
98
w1 := dbgen .Workspace (t , coderdAPI .Database , database.WorkspaceTable {
52
99
OwnerID : memberUser .ID ,
53
100
TemplateID : template .ID ,
54
101
})
55
- wb1ID := uuid .MustParse ("00000000-0000-0000-bbbb -000000000001" )
102
+ wb1ID := uuid .MustParse ("00000000-0000-0000-dddd -000000000001" )
56
103
job1 := dbgen .ProvisionerJob (t , db , coderdAPI .Pubsub , database.ProvisionerJob {
57
- ID : uuid .MustParse ("00000000-0000-0000-cccc-000000000001" ),
58
104
WorkerID : uuid.NullUUID {UUID : pd1 .ID , Valid : true },
59
105
Input : json .RawMessage (`{"workspace_build_id":"` + wb1ID .String () + `"}` ),
106
+ CreatedAt : dbtime .Now ().Add (2 * time .Second ),
60
107
StartedAt : sql.NullTime {Time : coderdAPI .Clock .Now (), Valid : true },
61
108
Tags : database.StringMap {"owner" : "" , "scope" : "organization" },
62
109
})
@@ -67,22 +114,22 @@ func TestProvisioners(t *testing.T) {
67
114
TemplateVersionID : version .ID ,
68
115
})
69
116
70
- // Create another provisioner that completed a job and is offline.
117
+ // Create a provisioner that completed a job previously and is offline.
71
118
pd2 := dbgen .ProvisionerDaemon (t , coderdAPI .Database , database.ProvisionerDaemon {
72
119
Name : "provisioner-2" ,
73
- CreatedAt : timeParse ( t , "2006-01-02" , "2024-12-20" ),
120
+ CreatedAt : dbtime . Now (). Add ( 2 * time . Second ),
74
121
LastSeenAt : sql.NullTime {Time : coderdAPI .Clock .Now ().Add (- time .Hour ), Valid : true },
75
122
KeyID : uuid .MustParse (codersdk .ProvisionerKeyIDBuiltIn ),
76
123
})
77
124
w2 := dbgen .Workspace (t , coderdAPI .Database , database.WorkspaceTable {
78
125
OwnerID : memberUser .ID ,
79
126
TemplateID : template .ID ,
80
127
})
81
- wb2ID := uuid .MustParse ("00000000-0000-0000-bbbb -000000000002" )
128
+ wb2ID := uuid .MustParse ("00000000-0000-0000-dddd -000000000002" )
82
129
job2 := dbgen .ProvisionerJob (t , db , coderdAPI .Pubsub , database.ProvisionerJob {
83
- ID : uuid .MustParse ("00000000-0000-0000-cccc-000000000002" ),
84
130
WorkerID : uuid.NullUUID {UUID : pd2 .ID , Valid : true },
85
131
Input : json .RawMessage (`{"workspace_build_id":"` + wb2ID .String () + `"}` ),
132
+ CreatedAt : dbtime .Now ().Add (3 * time .Second ),
86
133
StartedAt : sql.NullTime {Time : coderdAPI .Clock .Now ().Add (- 2 * time .Hour ), Valid : true },
87
134
CompletedAt : sql.NullTime {Time : coderdAPI .Clock .Now ().Add (- time .Hour ), Valid : true },
88
135
Tags : database.StringMap {"owner" : "" , "scope" : "organization" },
@@ -99,11 +146,11 @@ func TestProvisioners(t *testing.T) {
99
146
OwnerID : memberUser .ID ,
100
147
TemplateID : template .ID ,
101
148
})
102
- wb3ID := uuid .MustParse ("00000000-0000-0000-bbbb -000000000003" )
149
+ wb3ID := uuid .MustParse ("00000000-0000-0000-dddd -000000000003" )
103
150
job3 := dbgen .ProvisionerJob (t , db , coderdAPI .Pubsub , database.ProvisionerJob {
104
- ID : uuid . MustParse ( "00000000-0000-0000-cccc-000000000003" ),
105
- Input : json . RawMessage ( `{"workspace_build_id":"` + wb3ID . String () + `"}` ),
106
- Tags : database.StringMap {"owner" : "" , "scope" : "organization" },
151
+ Input : json . RawMessage ( `{"workspace_build_id":"` + wb3ID . String () + `"}` ),
152
+ CreatedAt : dbtime . Now (). Add ( 4 * time . Second ),
153
+ Tags : database.StringMap {"owner" : "" , "scope" : "organization" },
107
154
})
108
155
dbgen .WorkspaceBuild (t , coderdAPI .Database , database.WorkspaceBuild {
109
156
ID : wb3ID ,
@@ -113,48 +160,50 @@ func TestProvisioners(t *testing.T) {
113
160
})
114
161
115
162
// Create a provisioner that is idle.
116
- pd3 : = dbgen .ProvisionerDaemon (t , coderdAPI .Database , database.ProvisionerDaemon {
163
+ _ = dbgen .ProvisionerDaemon (t , coderdAPI .Database , database.ProvisionerDaemon {
117
164
Name : "provisioner-3" ,
118
- CreatedAt : timeParse ( t , "2006-01-02" , "2024-12-20" ),
165
+ CreatedAt : dbtime . Now (). Add ( 3 * time . Second ),
119
166
KeyID : uuid .MustParse (codersdk .ProvisionerKeyIDBuiltIn ),
120
167
})
121
- _ = pd3
168
+
169
+ updateReplaceUUIDs (coderdAPI )
170
+
171
+ for id , replaceID := range replace {
172
+ t .Logf ("replace[%q] = %q" , id , replaceID )
173
+ }
122
174
123
175
t .Run ("list" , func (t * testing.T ) {
124
176
t .Parallel ()
125
177
178
+ var got bytes.Buffer
126
179
inv , root := clitest .New (t ,
127
180
"provisioners" ,
128
181
"list" ,
129
182
"--column" , "id,created at,last seen at,name,version,api version,tags,status,current job id,previous job id,previous job status,organization" ,
130
183
)
184
+ inv .Stdout = & got
131
185
clitest .SetupConfig (t , member , root )
132
186
err := inv .Run ()
133
187
require .NoError (t , err )
134
188
135
- // TODO(mafredri): Verify golden output.
189
+ clitest . TestGoldenFile ( t , t . Name (), got . Bytes (), replace )
136
190
})
137
191
138
192
t .Run ("jobs list" , func (t * testing.T ) {
139
193
t .Parallel ()
140
194
195
+ var got bytes.Buffer
141
196
inv , root := clitest .New (t ,
142
197
"provisioners" ,
143
198
"jobs" ,
144
199
"list" ,
145
200
"--column" , "id,created at,status,worker id,tags,template version id,workspace build id,type,available workers,organization,queue" ,
146
201
)
202
+ inv .Stdout = & got
147
203
clitest .SetupConfig (t , member , root )
148
204
err := inv .Run ()
149
205
require .NoError (t , err )
150
206
151
- // TODO(mafredri): Verify golden output.
207
+ clitest . TestGoldenFile ( t , t . Name (), got . Bytes (), replace )
152
208
})
153
209
}
154
-
155
- func timeParse (t * testing.T , layout , s string ) time.Time {
156
- t .Helper ()
157
- tm , err := time .Parse (layout , s )
158
- require .NoError (t , err )
159
- return tm
160
- }
0 commit comments