@@ -7,16 +7,18 @@ import (
7
7
"net/http/httptest"
8
8
"net/url"
9
9
"os"
10
+ "strings"
10
11
"testing"
11
12
"time"
12
13
14
+ "github.com/google/uuid"
15
+ "github.com/moby/moby/pkg/namesgenerator"
13
16
"github.com/stretchr/testify/require"
14
17
15
18
"cdr.dev/slog"
16
19
"cdr.dev/slog/sloggers/slogtest"
17
20
"github.com/coder/coder/coderd"
18
21
"github.com/coder/coder/codersdk"
19
- "github.com/coder/coder/cryptorand"
20
22
"github.com/coder/coder/database"
21
23
"github.com/coder/coder/database/databasefake"
22
24
"github.com/coder/coder/database/postgres"
@@ -26,47 +28,49 @@ import (
26
28
"github.com/coder/coder/provisionersdk/proto"
27
29
)
28
30
29
- // Server represents a test instance of coderd.
30
- // The database is intentionally omitted from
31
- // this struct to promote data being exposed via
32
- // the API .
33
- type Server struct {
34
- Client * codersdk. Client
35
- URL * url. URL
36
- }
37
-
38
- // RandomInitialUser generates a random initial user and authenticates
39
- // it with the client on the Server struct.
40
- func ( s * Server ) RandomInitialUser ( t * testing. T ) coderd. CreateInitialUserRequest {
41
- username , err := cryptorand . String ( 12 )
42
- require . NoError ( t , err )
43
- password , err := cryptorand . String ( 12 )
44
- require . NoError ( t , err )
45
- organization , err := cryptorand . String ( 12 )
46
- require . NoError ( t , err )
31
+ // New constructs a new coderd test instance. This returned Server
32
+ // should contain no side-effects.
33
+ func New ( t * testing. T ) * codersdk. Client {
34
+ // This can be hotswapped for a live database instance .
35
+ db := databasefake . New ()
36
+ pubsub := database . NewPubsubInMemory ()
37
+ if os . Getenv ( "DB" ) != "" {
38
+ connectionURL , close , err := postgres . Open ()
39
+ require . NoError ( t , err )
40
+ t . Cleanup ( close )
41
+ sqlDB , err := sql . Open ( "postgres" , connectionURL )
42
+ require . NoError ( t , err )
43
+ t . Cleanup ( func () {
44
+ _ = sqlDB . Close ( )
45
+ } )
46
+ err = database . Migrate ( sqlDB )
47
+ require . NoError ( t , err )
48
+ db = database . New ( sqlDB )
47
49
48
- req := coderd. CreateInitialUserRequest {
49
-
50
- Username : username ,
51
- Password : password ,
52
- Organization : organization ,
50
+ pubsub , err = database . NewPubsub ( context . Background (), sqlDB , connectionURL )
51
+ require . NoError ( t , err )
52
+ t . Cleanup ( func () {
53
+ _ = pubsub . Close ()
54
+ })
53
55
}
54
- _ , err = s .Client .CreateInitialUser (context .Background (), req )
55
- require .NoError (t , err )
56
56
57
- login , err := s .Client .LoginWithPassword (context .Background (), coderd.LoginWithPasswordRequest {
58
-
59
- Password : password ,
57
+ handler := coderd .New (& coderd.Options {
58
+ Logger : slogtest .Make (t , nil ).Leveled (slog .LevelDebug ),
59
+ Database : db ,
60
+ Pubsub : pubsub ,
60
61
})
62
+ srv := httptest .NewServer (handler )
63
+ serverURL , err := url .Parse (srv .URL )
61
64
require .NoError (t , err )
62
- err = s . Client . SetSessionToken ( login . SessionToken )
63
- require . NoError ( t , err )
64
- return req
65
+ t . Cleanup ( srv . Close )
66
+
67
+ return codersdk . New ( serverURL )
65
68
}
66
69
67
- // AddProvisionerd launches a new provisionerd instance with the
68
- // test provisioner registered.
69
- func (s * Server ) AddProvisionerd (t * testing.T ) io.Closer {
70
+ // NewProvisionerDaemon launches a provisionerd instance configured to work
71
+ // well with coderd testing. It registers the "echo" provisioner for
72
+ // quick testing.
73
+ func NewProvisionerDaemon (t * testing.T , client * codersdk.Client ) io.Closer {
70
74
echoClient , echoServer := provisionersdk .TransportPipe ()
71
75
ctx , cancelFunc := context .WithCancel (context .Background ())
72
76
t .Cleanup (func () {
@@ -81,7 +85,7 @@ func (s *Server) AddProvisionerd(t *testing.T) io.Closer {
81
85
require .NoError (t , err )
82
86
}()
83
87
84
- closer := provisionerd .New (s . Client .ProvisionerDaemonClient , & provisionerd.Options {
88
+ closer := provisionerd .New (client .ProvisionerDaemonClient , & provisionerd.Options {
85
89
Logger : slogtest .Make (t , nil ).Named ("provisionerd" ).Leveled (slog .LevelDebug ),
86
90
PollInterval : 50 * time .Millisecond ,
87
91
UpdateInterval : 50 * time .Millisecond ,
@@ -96,44 +100,87 @@ func (s *Server) AddProvisionerd(t *testing.T) io.Closer {
96
100
return closer
97
101
}
98
102
99
- // New constructs a new coderd test instance. This returned Server
100
- // should contain no side-effects.
101
- func New (t * testing.T ) Server {
102
- // This can be hotswapped for a live database instance.
103
- db := databasefake .New ()
104
- pubsub := database .NewPubsubInMemory ()
105
- if os .Getenv ("DB" ) != "" {
106
- connectionURL , close , err := postgres .Open ()
107
- require .NoError (t , err )
108
- t .Cleanup (close )
109
- sqlDB , err := sql .Open ("postgres" , connectionURL )
110
- require .NoError (t , err )
111
- t .Cleanup (func () {
112
- _ = sqlDB .Close ()
113
- })
114
- err = database .Migrate (sqlDB )
115
- require .NoError (t , err )
116
- db = database .New (sqlDB )
103
+ // CreateInitialUser creates a user with preset credentials and authenticates
104
+ // with the passed in codersdk client.
105
+ func CreateInitialUser (t * testing.T , client * codersdk.Client ) coderd.CreateInitialUserRequest {
106
+ req := coderd.CreateInitialUserRequest {
107
+
108
+ Username : "testuser" ,
109
+ Password : "testpass" ,
110
+ Organization : "testorg" ,
111
+ }
112
+ _ , err := client .CreateInitialUser (context .Background (), req )
113
+ require .NoError (t , err )
117
114
118
- pubsub , err = database .NewPubsub (context .Background (), sqlDB , connectionURL )
115
+ login , err := client .LoginWithPassword (context .Background (), coderd.LoginWithPasswordRequest {
116
+ Email : req .Email ,
117
+ Password : req .Password ,
118
+ })
119
+ require .NoError (t , err )
120
+ err = client .SetSessionToken (login .SessionToken )
121
+ require .NoError (t , err )
122
+ return req
123
+ }
124
+
125
+ // CreateProject creates a project with the "echo" provisioner for
126
+ // compatibility with testing. The name assigned is randomly generated.
127
+ func CreateProject (t * testing.T , client * codersdk.Client , organization string ) coderd.Project {
128
+ project , err := client .CreateProject (context .Background (), organization , coderd.CreateProjectRequest {
129
+ Name : randomUsername (),
130
+ Provisioner : database .ProvisionerTypeEcho ,
131
+ })
132
+ require .NoError (t , err )
133
+ return project
134
+ }
135
+
136
+ // CreateProjectVersion creates a project version for the "echo" provisioner
137
+ // for compatibility with testing.
138
+ func CreateProjectVersion (t * testing.T , client * codersdk.Client , organization , project string , responses * echo.Responses ) coderd.ProjectVersion {
139
+ data , err := echo .Tar (responses )
140
+ require .NoError (t , err )
141
+ version , err := client .CreateProjectVersion (context .Background (), organization , project , coderd.CreateProjectVersionRequest {
142
+ StorageMethod : database .ProjectStorageMethodInlineArchive ,
143
+ StorageSource : data ,
144
+ })
145
+ require .NoError (t , err )
146
+ return version
147
+ }
148
+
149
+ // AwaitProjectVersionImported awaits for the project import job to reach completed status.
150
+ func AwaitProjectVersionImported (t * testing.T , client * codersdk.Client , organization , project , version string ) coderd.ProjectVersion {
151
+ var projectVersion coderd.ProjectVersion
152
+ require .Eventually (t , func () bool {
153
+ var err error
154
+ projectVersion , err = client .ProjectVersion (context .Background (), organization , project , version )
119
155
require .NoError (t , err )
120
- t . Cleanup ( func () {
121
- _ = pubsub . Close ( )
122
- })
123
- }
156
+ return projectVersion . Import . Status . Completed ()
157
+ }, 3 * time . Second , 25 * time . Millisecond )
158
+ return projectVersion
159
+ }
124
160
125
- handler := coderd .New (& coderd.Options {
126
- Logger : slogtest .Make (t , nil ).Leveled (slog .LevelDebug ),
127
- Database : db ,
128
- Pubsub : pubsub ,
161
+ // CreateWorkspace creates a workspace for the user and project provided.
162
+ // A random name is generated for it.
163
+ func CreateWorkspace (t * testing.T , client * codersdk.Client , user string , projectID uuid.UUID ) coderd.Workspace {
164
+ workspace , err := client .CreateWorkspace (context .Background (), user , coderd.CreateWorkspaceRequest {
165
+ ProjectID : projectID ,
166
+ Name : randomUsername (),
129
167
})
130
- srv := httptest .NewServer (handler )
131
- serverURL , err := url .Parse (srv .URL )
132
168
require .NoError (t , err )
133
- t .Cleanup (srv .Close )
169
+ return workspace
170
+ }
134
171
135
- return Server {
136
- Client : codersdk .New (serverURL ),
137
- URL : serverURL ,
138
- }
172
+ // AwaitWorkspaceHistoryProvisioned awaits for the workspace provision job to reach completed status.
173
+ func AwaitWorkspaceHistoryProvisioned (t * testing.T , client * codersdk.Client , user , workspace , history string ) coderd.WorkspaceHistory {
174
+ var workspaceHistory coderd.WorkspaceHistory
175
+ require .Eventually (t , func () bool {
176
+ var err error
177
+ workspaceHistory , err = client .WorkspaceHistory (context .Background (), user , workspace , history )
178
+ require .NoError (t , err )
179
+ return workspaceHistory .Provision .Status .Completed ()
180
+ }, 3 * time .Second , 25 * time .Millisecond )
181
+ return workspaceHistory
182
+ }
183
+
184
+ func randomUsername () string {
185
+ return strings .ReplaceAll (namesgenerator .GetRandomName (0 ), "_" , "-" )
139
186
}
0 commit comments