@@ -18,6 +18,7 @@ import (
18
18
"github.com/stretchr/testify/assert"
19
19
"github.com/stretchr/testify/require"
20
20
"go.opentelemetry.io/otel/trace"
21
+ "golang.org/x/xerrors"
21
22
"tailscale.com/tailcfg"
22
23
23
24
"github.com/coder/coder/v2/agent"
@@ -56,8 +57,7 @@ func TestServerTailnet_AgentConn_NoSTUN(t *testing.T) {
56
57
defer cancel ()
57
58
58
59
// Connect through the ServerTailnet
59
- agents , serverTailnet := setupServerTailnetAgent (t , 1 ,
60
- tailnettest .DisableSTUN , tailnettest .DERPIsEmbedded )
60
+ agents , serverTailnet := setupServerTailnetAgent (t , 1 , withDERPAndStunOptions (tailnettest .DisableSTUN , tailnettest .DERPIsEmbedded ))
61
61
a := agents [0 ]
62
62
63
63
conn , release , err := serverTailnet .AgentConn (ctx , a .id )
@@ -340,7 +340,7 @@ func TestServerTailnet_ReverseProxy(t *testing.T) {
340
340
ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitLong )
341
341
defer cancel ()
342
342
343
- agents , serverTailnet := setupServerTailnetAgent (t , 1 , tailnettest .DisableSTUN )
343
+ agents , serverTailnet := setupServerTailnetAgent (t , 1 , withDERPAndStunOptions ( tailnettest .DisableSTUN ) )
344
344
a := agents [0 ]
345
345
346
346
require .True (t , serverTailnet .Conn ().GetBlockEndpoints (), "expected BlockEndpoints to be set" )
@@ -365,6 +365,43 @@ func TestServerTailnet_ReverseProxy(t *testing.T) {
365
365
})
366
366
}
367
367
368
+ func TestServerTailnet_Healthcheck (t * testing.T ) {
369
+ t .Parallel ()
370
+
371
+ // Verifies that a non-nil healthcheck which returns a non-error response behaves as expected.
372
+ t .Run ("Passing" , func (t * testing.T ) {
373
+ t .Parallel ()
374
+
375
+ ctx := testutil .Context (t , testutil .WaitMedium )
376
+ fn := func (ctx context.Context ) error { return nil }
377
+
378
+ agents , serverTailnet := setupServerTailnetAgent (t , 1 , withHealthcheckFn (fn ))
379
+
380
+ a := agents [0 ]
381
+ conn , release , err := serverTailnet .AgentConn (ctx , a .id )
382
+ t .Cleanup (release )
383
+ require .NoError (t , err )
384
+ assert .True (t , conn .AwaitReachable (ctx ))
385
+ })
386
+
387
+ // If the healthcheck fails, we have no insight into this at this level.
388
+ // The dial against the control plane is retried, so we wait for the context to timeout as an indication that the
389
+ // healthcheck is performing as expected.
390
+ t .Run ("Failing" , func (t * testing.T ) {
391
+ t .Parallel ()
392
+
393
+ ctx := testutil .Context (t , testutil .WaitMedium )
394
+ fn := func (ctx context.Context ) error { return xerrors .Errorf ("oops, db gone" ) }
395
+
396
+ agents , serverTailnet := setupServerTailnetAgent (t , 1 , withHealthcheckFn (fn ))
397
+
398
+ a := agents [0 ]
399
+ _ , release , err := serverTailnet .AgentConn (ctx , a .id )
400
+ require .Nil (t , release )
401
+ require .ErrorContains (t , err , "agent is unreachable" )
402
+ })
403
+ }
404
+
368
405
type wrappedListener struct {
369
406
net.Listener
370
407
dials int32
@@ -389,9 +426,36 @@ type agentWithID struct {
389
426
agent.Agent
390
427
}
391
428
392
- func setupServerTailnetAgent (t * testing.T , agentNum int , opts ... tailnettest.DERPAndStunOption ) ([]agentWithID , * coderd.ServerTailnet ) {
429
+ type serverOption struct {
430
+ HealthcheckFn func (ctx context.Context ) error
431
+ DERPAndStunOptions []tailnettest.DERPAndStunOption
432
+ }
433
+
434
+ func withHealthcheckFn (fn func (ctx context.Context ) error ) serverOption {
435
+ return serverOption {
436
+ HealthcheckFn : fn ,
437
+ }
438
+ }
439
+
440
+ func withDERPAndStunOptions (opts ... tailnettest.DERPAndStunOption ) serverOption {
441
+ return serverOption {
442
+ DERPAndStunOptions : opts ,
443
+ }
444
+ }
445
+
446
+ func setupServerTailnetAgent (t * testing.T , agentNum int , opts ... serverOption ) ([]agentWithID , * coderd.ServerTailnet ) {
393
447
logger := testutil .Logger (t )
394
- derpMap , derpServer := tailnettest .RunDERPAndSTUN (t , opts ... )
448
+
449
+ var healthcheckFn func (ctx context.Context ) error
450
+ var derpAndStunOptions []tailnettest.DERPAndStunOption
451
+ for _ , opt := range opts {
452
+ derpAndStunOptions = append (derpAndStunOptions , opt .DERPAndStunOptions ... )
453
+ if opt .HealthcheckFn != nil {
454
+ healthcheckFn = opt .HealthcheckFn
455
+ }
456
+ }
457
+
458
+ derpMap , derpServer := tailnettest .RunDERPAndSTUN (t , derpAndStunOptions ... )
395
459
396
460
coord := tailnet .NewCoordinator (logger )
397
461
t .Cleanup (func () {
@@ -431,10 +495,11 @@ func setupServerTailnetAgent(t *testing.T, agentNum int, opts ...tailnettest.DER
431
495
}
432
496
433
497
dialer := & coderd.InmemTailnetDialer {
434
- CoordPtr : & coordPtr ,
435
- DERPFn : func () * tailcfg.DERPMap { return derpMap },
436
- Logger : logger ,
437
- ClientID : uuid.UUID {5 },
498
+ CoordPtr : & coordPtr ,
499
+ DERPFn : func () * tailcfg.DERPMap { return derpMap },
500
+ Logger : logger ,
501
+ ClientID : uuid.UUID {5 },
502
+ DatabaseHealthcheckFn : healthcheckFn ,
438
503
}
439
504
serverTailnet , err := coderd .NewServerTailnet (
440
505
context .Background (),
0 commit comments