@@ -17,6 +17,7 @@ import (
17
17
"os/exec"
18
18
"path"
19
19
"path/filepath"
20
+ "regexp"
20
21
"runtime"
21
22
"strings"
22
23
"testing"
@@ -148,8 +149,33 @@ func TestSSH(t *testing.T) {
148
149
t .Run ("StartStoppedWorkspaceConflict" , func (t * testing.T ) {
149
150
t .Parallel ()
150
151
152
+ // Intercept builds to synchronize execution of the SSH command.
153
+ // The purpose here is to make sure all commands try to trigger
154
+ // a start build of the workspace.
155
+ isFirstBuild := true
156
+ buildURL := regexp .MustCompile ("/api/v2/workspaces/.*/builds" )
157
+ buildReq := make (chan struct {})
158
+ buildResume := make (chan struct {})
159
+ buildSyncMW := func (next http.Handler ) http.Handler {
160
+ return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
161
+ if r .Method == http .MethodPost && buildURL .MatchString (r .URL .Path ) {
162
+ if ! isFirstBuild {
163
+ t .Log ("buildSyncMW: blocking build" )
164
+ buildReq <- struct {}{}
165
+ <- buildResume
166
+ t .Log ("buildSyncMW: resuming build" )
167
+ }
168
+ isFirstBuild = false
169
+ }
170
+ next .ServeHTTP (w , r )
171
+ })
172
+ }
173
+
151
174
authToken := uuid .NewString ()
152
- ownerClient := coderdtest .New (t , & coderdtest.Options {IncludeProvisionerDaemon : true })
175
+ ownerClient := coderdtest .New (t , & coderdtest.Options {
176
+ IncludeProvisionerDaemon : true ,
177
+ APIMiddleware : buildSyncMW ,
178
+ })
153
179
owner := coderdtest .CreateFirstUser (t , ownerClient )
154
180
client , _ := coderdtest .CreateAnotherUser (t , ownerClient , owner .OrganizationID , rbac .RoleTemplateAdmin ())
155
181
version := coderdtest .CreateTemplateVersion (t , client , owner .OrganizationID , & echo.Responses {
@@ -165,21 +191,28 @@ func TestSSH(t *testing.T) {
165
191
workspaceBuild := coderdtest .CreateWorkspaceBuild (t , client , workspace , database .WorkspaceTransitionStop )
166
192
coderdtest .AwaitWorkspaceBuildJobCompleted (t , client , workspaceBuild .ID )
167
193
168
- ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitSuperLong )
194
+ ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitMedium )
169
195
defer cancel ()
170
196
171
- ptys := make ( []* ptytest.PTY , 3 )
172
- for i := range ptys {
197
+ var ptys []* ptytest.PTY
198
+ for i := 0 ; i < 3 ; i ++ {
173
199
// SSH to the workspace which should autostart it
174
200
inv , root := clitest .New (t , "ssh" , workspace .Name )
175
201
176
- ptys [i ] = ptytest .New (t ).Attach (inv )
202
+ pty := ptytest .New (t ).Attach (inv )
203
+ ptys = append (ptys , pty )
177
204
clitest .SetupConfig (t , client , root )
178
- clitest . StartWithAssert (t , inv , func (* testing. T , error ) {
179
- // Noop.
205
+ testutil . Go (t , func () {
206
+ _ = inv . WithContext ( ctx ). Run ()
180
207
})
181
208
}
182
209
210
+ for _ , pty := range ptys {
211
+ pty .ExpectMatchContext (ctx , "Workspace was stopped, starting workspace to allow connecting to" )
212
+ testutil .RequireRecvCtx (ctx , t , buildReq )
213
+ }
214
+ close (buildResume )
215
+
183
216
var foundConflict int
184
217
for _ , pty := range ptys {
185
218
// Either allow the command to start the workspace or fail
@@ -191,8 +224,7 @@ func TestSSH(t *testing.T) {
191
224
pty .ExpectMatchContext (ctx , "Waiting for the workspace agent to connect" )
192
225
}
193
226
}
194
- // TODO(mafredri): Remove this if it's racy.
195
- require .Greater (t , foundConflict , 0 , "expected at least one conflict" )
227
+ require .Equal (t , foundConflict , 2 , "expected 2 conflicts" )
196
228
})
197
229
t .Run ("RequireActiveVersion" , func (t * testing.T ) {
198
230
t .Parallel ()
0 commit comments