mirror of
https://github.com/juanfont/headscale.git
synced 2026-04-11 03:27:20 +02:00
integration: standardize test infrastructure options
Make embedded DERP server and TLS the default configuration for all integration tests, replacing the per-test opt-in model that led to inconsistent and flaky test behavior. Infrastructure changes: - DefaultConfigEnv() includes embedded DERP server settings - New() auto-generates a proper CA + server TLS certificate pair - CA cert is installed into container trust stores and returned by GetCert() so clients and internal tools (curl) trust the server - CreateCertificate() now returns (caCert, cert, key) instead of discarding the CA certificate - Add WithPublicDERP() and WithoutTLS() opt-out options - Remove WithTLS(), WithEmbeddedDERPServerOnly(), and WithDERPAsIP() since all their behavior is now the default or unnecessary Test cleanup: - Remove all redundant WithTLS/WithEmbeddedDERPServerOnly/WithDERPAsIP calls from test files - Give every test a unique WithTestName by parameterizing aclScenario, sshScenario, and derpServerScenario helpers - Add WithTestName to tests that were missing it - Document all non-standard options with inline comments explaining why each is needed Updates #3139
This commit is contained in:
@@ -28,11 +28,24 @@ func DefaultConfigEnv() map[string]string {
|
||||
"HEADSCALE_PRIVATE_KEY_PATH": "/tmp/private.key",
|
||||
"HEADSCALE_NOISE_PRIVATE_KEY_PATH": "/tmp/noise_private.key",
|
||||
"HEADSCALE_METRICS_LISTEN_ADDR": "0.0.0.0:9090",
|
||||
"HEADSCALE_DERP_URLS": "https://controlplane.tailscale.com/derpmap/default",
|
||||
"HEADSCALE_DERP_AUTO_UPDATE_ENABLED": "false",
|
||||
"HEADSCALE_DERP_UPDATE_FREQUENCY": "1m",
|
||||
"HEADSCALE_DEBUG_PORT": "40000",
|
||||
|
||||
// Embedded DERP is the default for test isolation.
|
||||
// Tests should not depend on external DERP infrastructure.
|
||||
// Use WithPublicDERP() to opt out for tests that explicitly
|
||||
// need public DERP relays.
|
||||
"HEADSCALE_DERP_URLS": "",
|
||||
"HEADSCALE_DERP_AUTO_UPDATE_ENABLED": "false",
|
||||
"HEADSCALE_DERP_UPDATE_FREQUENCY": "1m",
|
||||
"HEADSCALE_DERP_SERVER_ENABLED": "true",
|
||||
"HEADSCALE_DERP_SERVER_REGION_ID": "999",
|
||||
"HEADSCALE_DERP_SERVER_REGION_CODE": "headscale",
|
||||
"HEADSCALE_DERP_SERVER_REGION_NAME": "Headscale Embedded DERP",
|
||||
"HEADSCALE_DERP_SERVER_STUN_LISTEN_ADDR": "0.0.0.0:3478",
|
||||
"HEADSCALE_DERP_SERVER_PRIVATE_KEY_PATH": "/tmp/derp.key",
|
||||
"DERP_DEBUG_LOGS": "true",
|
||||
"DERP_PROBER_DEBUG_LOGS": "true",
|
||||
|
||||
// a bunch of tests (ACL/Policy) rely on predictable IP alloc,
|
||||
// so ensure the sequential alloc is used by default.
|
||||
"HEADSCALE_PREFIXES_ALLOCATION": string(types.IPAllocationStrategySequential),
|
||||
|
||||
@@ -82,8 +82,10 @@ type HeadscaleInContainer struct {
|
||||
hostPortBindings map[string][]string
|
||||
aclPolicy *policyv2.Policy
|
||||
env map[string]string
|
||||
tlsCACert []byte
|
||||
tlsCert []byte
|
||||
tlsKey []byte
|
||||
noTLS bool
|
||||
filesInContainer []fileInContainer
|
||||
postgres bool
|
||||
policyMode types.PolicyMode
|
||||
@@ -115,24 +117,24 @@ func WithCACert(cert []byte) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithTLS creates certificates and enables HTTPS.
|
||||
func WithTLS() Option {
|
||||
// WithoutTLS disables the default TLS configuration.
|
||||
// Most tests should not need this. Use only for tests that
|
||||
// explicitly need to test non-TLS behavior.
|
||||
func WithoutTLS() Option {
|
||||
return func(hsic *HeadscaleInContainer) {
|
||||
cert, key, err := integrationutil.CreateCertificate(hsic.hostname)
|
||||
if err != nil {
|
||||
log.Fatalf("creating certificates for headscale test: %s", err)
|
||||
}
|
||||
|
||||
hsic.tlsCert = cert
|
||||
hsic.tlsKey = key
|
||||
hsic.noTLS = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithCustomTLS uses the given certificates for the Headscale instance.
|
||||
func WithCustomTLS(cert, key []byte) Option {
|
||||
// The caCert is installed into the container's trust store and returned
|
||||
// by GetCert() so that clients can trust this server.
|
||||
func WithCustomTLS(caCert, cert, key []byte) Option {
|
||||
return func(hsic *HeadscaleInContainer) {
|
||||
hsic.tlsCACert = caCert
|
||||
hsic.tlsCert = cert
|
||||
hsic.tlsKey = key
|
||||
hsic.caCerts = append(hsic.caCerts, caCert)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,25 +218,20 @@ func WithIPAllocationStrategy(strategy types.IPAllocationStrategy) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithEmbeddedDERPServerOnly configures Headscale to start
|
||||
// and only use the embedded DERP server.
|
||||
// It requires WithTLS and WithHostnameAsServerURL to be
|
||||
// set.
|
||||
//
|
||||
//nolint:goconst // env var values like "true" and "headscale" are clearer inline
|
||||
func WithEmbeddedDERPServerOnly() Option {
|
||||
// WithPublicDERP disables the embedded DERP server and restores
|
||||
// the default public DERP relay configuration. Use this for tests
|
||||
// that explicitly need to test public DERP behavior.
|
||||
func WithPublicDERP() Option {
|
||||
return func(hsic *HeadscaleInContainer) {
|
||||
hsic.env["HEADSCALE_DERP_URLS"] = ""
|
||||
hsic.env["HEADSCALE_DERP_SERVER_ENABLED"] = "true"
|
||||
hsic.env["HEADSCALE_DERP_SERVER_REGION_ID"] = "999"
|
||||
hsic.env["HEADSCALE_DERP_SERVER_REGION_CODE"] = "headscale"
|
||||
hsic.env["HEADSCALE_DERP_SERVER_REGION_NAME"] = "Headscale Embedded DERP"
|
||||
hsic.env["HEADSCALE_DERP_SERVER_STUN_LISTEN_ADDR"] = "0.0.0.0:3478"
|
||||
hsic.env["HEADSCALE_DERP_SERVER_PRIVATE_KEY_PATH"] = "/tmp/derp.key"
|
||||
|
||||
// Envknob for enabling DERP debug logs
|
||||
hsic.env["DERP_DEBUG_LOGS"] = "true"
|
||||
hsic.env["DERP_PROBER_DEBUG_LOGS"] = "true"
|
||||
hsic.env["HEADSCALE_DERP_URLS"] = "https://controlplane.tailscale.com/derpmap/default"
|
||||
hsic.env["HEADSCALE_DERP_SERVER_ENABLED"] = "false"
|
||||
delete(hsic.env, "HEADSCALE_DERP_SERVER_REGION_ID")
|
||||
delete(hsic.env, "HEADSCALE_DERP_SERVER_REGION_CODE")
|
||||
delete(hsic.env, "HEADSCALE_DERP_SERVER_REGION_NAME")
|
||||
delete(hsic.env, "HEADSCALE_DERP_SERVER_STUN_LISTEN_ADDR")
|
||||
delete(hsic.env, "HEADSCALE_DERP_SERVER_PRIVATE_KEY_PATH")
|
||||
delete(hsic.env, "DERP_DEBUG_LOGS")
|
||||
delete(hsic.env, "DERP_PROBER_DEBUG_LOGS")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,14 +279,6 @@ func WithTimezone(timezone string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithDERPAsIP enables using IP address instead of hostname for DERP server.
|
||||
// This is useful for integration tests where DNS resolution may be unreliable.
|
||||
func WithDERPAsIP() Option {
|
||||
return func(hsic *HeadscaleInContainer) {
|
||||
hsic.env["HEADSCALE_DEBUG_DERP_USE_IP"] = "1"
|
||||
}
|
||||
}
|
||||
|
||||
// buildEntrypoint builds the container entrypoint command based on configuration.
|
||||
// It constructs proper wait conditions instead of fixed sleeps:
|
||||
// 1. Wait for network to be ready
|
||||
@@ -367,6 +356,26 @@ func New(
|
||||
opt(hsic)
|
||||
}
|
||||
|
||||
// TLS is enabled by default for all integration tests.
|
||||
// Generate a self-signed certificate if TLS was not explicitly
|
||||
// disabled via WithoutTLS() and no custom cert was provided
|
||||
// via WithCustomTLS().
|
||||
if !hsic.noTLS && len(hsic.tlsCert) == 0 {
|
||||
caCert, cert, key, err := integrationutil.CreateCertificate(hsic.hostname)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating default TLS certificates: %w", err)
|
||||
}
|
||||
|
||||
hsic.tlsCACert = caCert
|
||||
hsic.tlsCert = cert
|
||||
hsic.tlsKey = key
|
||||
|
||||
// Install the CA cert into the headscale container's trust
|
||||
// store so that tools like curl trust the server's own
|
||||
// certificate.
|
||||
hsic.caCerts = append(hsic.caCerts, caCert)
|
||||
}
|
||||
|
||||
log.Println("NAME: ", hsic.hostname)
|
||||
|
||||
portProto := fmt.Sprintf("%d/tcp", hsic.port)
|
||||
@@ -1030,9 +1039,10 @@ func (t *HeadscaleInContainer) getEndpoint(useIP bool) string {
|
||||
return "http://" + hostEndpoint
|
||||
}
|
||||
|
||||
// GetCert returns the public certificate of the HeadscaleInContainer.
|
||||
// GetCert returns the CA certificate that clients should trust to
|
||||
// verify this server's TLS certificate.
|
||||
func (t *HeadscaleInContainer) GetCert() []byte {
|
||||
return t.tlsCert
|
||||
return t.tlsCACert
|
||||
}
|
||||
|
||||
// GetHostname returns the hostname of the HeadscaleInContainer.
|
||||
|
||||
Reference in New Issue
Block a user