@@ -170,6 +170,55 @@ func TestCoder(t *testing.T) {
170170 require .ErrorIs (t , err , context .DeadlineExceeded )
171171 <- handlerDone
172172 })
173+
174+ // In this test, we validate that a 401 error on the initial connect
175+ // results in a retry. When envbuilder initially attempts to connect
176+ // using the Coder agent token, the workspace build may not yet have
177+ // completed.
178+ t .Run ("V2Retry" , func (t * testing.T ) {
179+ t .Parallel ()
180+ ctx , cancel := context .WithTimeout (context .Background (), 10 * time .Second )
181+ defer cancel ()
182+
183+ token := uuid .NewString ()
184+ done := make (chan struct {})
185+ handlerSend := make (chan int )
186+ handler := func (w http.ResponseWriter , r * http.Request ) {
187+ t .Logf ("test handler: %s" , r .URL .Path )
188+ if r .URL .Path == "/api/v2/buildinfo" {
189+ w .Header ().Set ("Content-Type" , "application/json" )
190+ _ , _ = w .Write ([]byte (`{"version": "v2.9.0"}` ))
191+ return
192+ }
193+ code := <- handlerSend
194+ t .Logf ("test handler response: %d" , code )
195+ w .WriteHeader (code )
196+ }
197+ srv := httptest .NewServer (http .HandlerFunc (handler ))
198+ defer srv .Close ()
199+
200+ u , err := url .Parse (srv .URL )
201+ require .NoError (t , err )
202+ var connectError error
203+ go func () {
204+ defer close (handlerSend )
205+ defer close (done )
206+ _ , _ , connectError = Coder (ctx , u , token )
207+ }()
208+
209+ // Initial: unauthorized
210+ handlerSend <- http .StatusUnauthorized
211+ // 2nd try: still unauthorized
212+ handlerSend <- http .StatusUnauthorized
213+ // 3rd try: authorized
214+ handlerSend <- http .StatusOK
215+
216+ cancel ()
217+
218+ <- done
219+ require .ErrorContains (t , connectError , "failed to WebSocket dial" )
220+ require .ErrorIs (t , connectError , context .Canceled )
221+ })
173222}
174223
175224type fakeLogDest struct {
0 commit comments