Skip to content

Commit 4e5d30e

Browse files
committed
Wrap HTTP handler replacement in mutex
1 parent 129f5ba commit 4e5d30e

File tree

2 files changed

+66
-53
lines changed

2 files changed

+66
-53
lines changed

coderd/coderdtest/coderdtest.go

Lines changed: 64 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"regexp"
2525
"strconv"
2626
"strings"
27+
"sync"
2728
"testing"
2829
"time"
2930

@@ -127,7 +128,7 @@ func newWithCloser(t *testing.T, options *Options) (*codersdk.Client, io.Closer)
127128
return client, closer
128129
}
129130

130-
func NewOptions(t *testing.T, options *Options) (*httptest.Server, context.CancelFunc, *coderd.Options) {
131+
func NewOptions(t *testing.T, options *Options) (func(http.Handler), context.CancelFunc, *coderd.Options) {
131132
if options == nil {
132133
options = &Options{}
133134
}
@@ -161,7 +162,15 @@ func NewOptions(t *testing.T, options *Options) (*httptest.Server, context.Cance
161162
).WithStatsChannel(options.AutobuildStats)
162163
lifecycleExecutor.Run()
163164

164-
srv := httptest.NewUnstartedServer(nil)
165+
var mutex sync.RWMutex
166+
var handler http.Handler
167+
srv := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
168+
mutex.RLock()
169+
defer mutex.RUnlock()
170+
if handler != nil {
171+
handler.ServeHTTP(w, r)
172+
}
173+
}))
165174
srv.Config.BaseContext = func(_ net.Listener) context.Context {
166175
return ctx
167176
}
@@ -204,55 +213,59 @@ func NewOptions(t *testing.T, options *Options) (*httptest.Server, context.Cance
204213
require.NoError(t, err)
205214
}
206215

207-
return srv, cancelFunc, &coderd.Options{
208-
AgentConnectionUpdateFrequency: 150 * time.Millisecond,
209-
// Force a long disconnection timeout to ensure
210-
// agents are not marked as disconnected during slow tests.
211-
AgentInactiveDisconnectTimeout: testutil.WaitShort,
212-
AccessURL: serverURL,
213-
AppHostname: options.AppHostname,
214-
AppHostnameRegex: appHostnameRegex,
215-
Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
216-
CacheDir: t.TempDir(),
217-
Database: options.Database,
218-
Pubsub: options.Pubsub,
219-
220-
Auditor: options.Auditor,
221-
AWSCertificates: options.AWSCertificates,
222-
AzureCertificates: options.AzureCertificates,
223-
GithubOAuth2Config: options.GithubOAuth2Config,
224-
OIDCConfig: options.OIDCConfig,
225-
GoogleTokenValidator: options.GoogleTokenValidator,
226-
SSHKeygenAlgorithm: options.SSHKeygenAlgorithm,
227-
DERPServer: derpServer,
228-
APIRateLimit: options.APIRateLimit,
229-
Authorizer: options.Authorizer,
230-
Telemetry: telemetry.NewNoop(),
231-
TLSCertificates: options.TLSCertificates,
232-
DERPMap: &tailcfg.DERPMap{
233-
Regions: map[int]*tailcfg.DERPRegion{
234-
1: {
235-
EmbeddedRelay: true,
236-
RegionID: 1,
237-
RegionCode: "coder",
238-
RegionName: "Coder",
239-
Nodes: []*tailcfg.DERPNode{{
240-
Name: "1a",
241-
RegionID: 1,
242-
IPv4: "127.0.0.1",
243-
DERPPort: derpPort,
244-
STUNPort: stunAddr.Port,
245-
InsecureForTests: true,
246-
ForceHTTP: options.TLSCertificates == nil,
247-
}},
216+
return func(h http.Handler) {
217+
mutex.Lock()
218+
handler = h
219+
mutex.Unlock()
220+
}, cancelFunc, &coderd.Options{
221+
AgentConnectionUpdateFrequency: 150 * time.Millisecond,
222+
// Force a long disconnection timeout to ensure
223+
// agents are not marked as disconnected during slow tests.
224+
AgentInactiveDisconnectTimeout: testutil.WaitShort,
225+
AccessURL: serverURL,
226+
AppHostname: options.AppHostname,
227+
AppHostnameRegex: appHostnameRegex,
228+
Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug),
229+
CacheDir: t.TempDir(),
230+
Database: options.Database,
231+
Pubsub: options.Pubsub,
232+
233+
Auditor: options.Auditor,
234+
AWSCertificates: options.AWSCertificates,
235+
AzureCertificates: options.AzureCertificates,
236+
GithubOAuth2Config: options.GithubOAuth2Config,
237+
OIDCConfig: options.OIDCConfig,
238+
GoogleTokenValidator: options.GoogleTokenValidator,
239+
SSHKeygenAlgorithm: options.SSHKeygenAlgorithm,
240+
DERPServer: derpServer,
241+
APIRateLimit: options.APIRateLimit,
242+
Authorizer: options.Authorizer,
243+
Telemetry: telemetry.NewNoop(),
244+
TLSCertificates: options.TLSCertificates,
245+
DERPMap: &tailcfg.DERPMap{
246+
Regions: map[int]*tailcfg.DERPRegion{
247+
1: {
248+
EmbeddedRelay: true,
249+
RegionID: 1,
250+
RegionCode: "coder",
251+
RegionName: "Coder",
252+
Nodes: []*tailcfg.DERPNode{{
253+
Name: "1a",
254+
RegionID: 1,
255+
IPv4: "127.0.0.1",
256+
DERPPort: derpPort,
257+
STUNPort: stunAddr.Port,
258+
InsecureForTests: true,
259+
ForceHTTP: options.TLSCertificates == nil,
260+
}},
261+
},
248262
},
249263
},
250-
},
251-
AutoImportTemplates: options.AutoImportTemplates,
252-
MetricsCacheRefreshInterval: options.MetricsCacheRefreshInterval,
253-
AgentStatsRefreshInterval: options.AgentStatsRefreshInterval,
254-
DeploymentFlags: options.DeploymentFlags,
255-
}
264+
AutoImportTemplates: options.AutoImportTemplates,
265+
MetricsCacheRefreshInterval: options.MetricsCacheRefreshInterval,
266+
AgentStatsRefreshInterval: options.AgentStatsRefreshInterval,
267+
DeploymentFlags: options.DeploymentFlags,
268+
}
256269
}
257270

258271
// NewWithAPI constructs an in-memory API instance and returns a client to talk to it.
@@ -262,10 +275,10 @@ func NewWithAPI(t *testing.T, options *Options) (*codersdk.Client, io.Closer, *c
262275
if options == nil {
263276
options = &Options{}
264277
}
265-
srv, cancelFunc, newOptions := NewOptions(t, options)
278+
setHandler, cancelFunc, newOptions := NewOptions(t, options)
266279
// We set the handler after server creation for the access URL.
267280
coderAPI := coderd.New(newOptions)
268-
srv.Config.Handler = coderAPI.RootHandler
281+
setHandler(coderAPI.APIHandler)
269282
var provisionerCloser io.Closer = nopcloser{}
270283
if options.IncludeProvisionerDaemon {
271284
provisionerCloser = NewProvisionerDaemon(t, coderAPI)

enterprise/coderd/coderdenttest/coderdenttest.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func NewWithAPI(t *testing.T, options *Options) (*codersdk.Client, io.Closer, *c
6262
if options.Options == nil {
6363
options.Options = &coderdtest.Options{}
6464
}
65-
srv, cancelFunc, oop := coderdtest.NewOptions(t, options.Options)
65+
setHandler, cancelFunc, oop := coderdtest.NewOptions(t, options.Options)
6666
coderAPI, err := coderd.New(context.Background(), &coderd.Options{
6767
RBAC: true,
6868
AuditLogging: options.AuditLogging,
@@ -76,7 +76,7 @@ func NewWithAPI(t *testing.T, options *Options) (*codersdk.Client, io.Closer, *c
7676
Keys: Keys,
7777
})
7878
assert.NoError(t, err)
79-
srv.Config.Handler = coderAPI.AGPL.RootHandler
79+
setHandler(coderAPI.AGPL.RootHandler)
8080
var provisionerCloser io.Closer = nopcloser{}
8181
if options.IncludeProvisionerDaemon {
8282
provisionerCloser = coderdtest.NewProvisionerDaemon(t, coderAPI.AGPL)

0 commit comments

Comments
 (0)