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:
Kristoffer Dalby
2026-03-16 09:15:46 +00:00
parent 87b8507ac9
commit e5ebe3205a
18 changed files with 209 additions and 236 deletions

View File

@@ -58,6 +58,7 @@ var veryLargeDestination = []policyv2.AliasWithPorts{
func aclScenario(
t *testing.T,
policy *policyv2.Policy,
testName string,
clientsPerUser int,
) *Scenario {
t.Helper()
@@ -81,9 +82,7 @@ func aclScenario(
tsic.WithDockerWorkdir("/"),
},
hsic.WithACLPolicy(policy),
hsic.WithTestName("acl"),
hsic.WithEmbeddedDERPServerOnly(),
hsic.WithTLS(),
hsic.WithTestName(testName),
)
require.NoError(t, err)
@@ -305,6 +304,7 @@ func TestACLHostsInNetMapTable(t *testing.T) {
err = scenario.CreateHeadscaleEnv(
[]tsic.Option{},
hsic.WithTestName("aclnetmap"),
hsic.WithACLPolicy(&testCase.policy),
)
@@ -351,6 +351,7 @@ func TestACLAllowUser80Dst(t *testing.T) {
},
},
},
"acl-allowuser80",
1,
)
defer scenario.ShutdownAssertNoPanics(t)
@@ -414,6 +415,7 @@ func TestACLDenyAllPort80(t *testing.T) {
},
},
},
"acl-denyport80",
4,
)
defer scenario.ShutdownAssertNoPanics(t)
@@ -462,6 +464,7 @@ func TestACLAllowUserDst(t *testing.T) {
},
},
},
"acl-allowuserdst",
2,
)
defer scenario.ShutdownAssertNoPanics(t)
@@ -524,6 +527,7 @@ func TestACLAllowStarDst(t *testing.T) {
},
},
},
"acl-allowstar",
2,
)
defer scenario.ShutdownAssertNoPanics(t)
@@ -591,6 +595,7 @@ func TestACLNamedHostsCanReachBySubnet(t *testing.T) {
},
},
},
"acl-namedsubnet",
3,
)
defer scenario.ShutdownAssertNoPanics(t)
@@ -743,6 +748,7 @@ func TestACLNamedHostsCanReach(t *testing.T) {
t.Run(name, func(t *testing.T) {
scenario := aclScenario(t,
&testCase.policy,
"acl-namedreach",
2,
)
defer scenario.ShutdownAssertNoPanics(t)
@@ -1044,7 +1050,7 @@ func TestACLDevice1CanAccessDevice2(t *testing.T) {
for name, testCase := range tests {
t.Run(name, func(t *testing.T) {
scenario := aclScenario(t, &testCase.policy, 1)
scenario := aclScenario(t, &testCase.policy, "acl-dev1dev2", 1)
defer scenario.ShutdownAssertNoPanics(t)
test1ip := netip.MustParseAddr("100.64.0.1")
@@ -1159,7 +1165,7 @@ func TestPolicyUpdateWhileRunningWithCLIInDatabase(t *testing.T) {
tsic.WithDockerWorkdir("/"),
},
hsic.WithTestName("policyreload"),
hsic.WithPolicyMode(types.PolicyModeDB),
hsic.WithPolicyMode(types.PolicyModeDB), // test updates policy at runtime via CLI
)
require.NoError(t, err)
@@ -1290,6 +1296,7 @@ func TestACLAutogroupMember(t *testing.T) {
},
},
},
"acl-agmember",
2,
)
defer scenario.ShutdownAssertNoPanics(t)
@@ -1383,8 +1390,6 @@ func TestACLAutogroupTagged(t *testing.T) {
headscale, err := scenario.Headscale(
hsic.WithACLPolicy(policy),
hsic.WithTestName("acl-autogroup-tagged"),
hsic.WithEmbeddedDERPServerOnly(),
hsic.WithTLS(),
)
require.NoError(t, err)
@@ -1430,7 +1435,10 @@ func TestACLAutogroupTagged(t *testing.T) {
network = networks[0]
}
// Create the tailscale node with appropriate options
// Create the tailscale node with appropriate options.
// CACert and HeadscaleName are passed explicitly because
// nodes created via CreateTailscaleNode are not part of
// the standard CreateHeadscaleEnv flow.
opts := []tsic.Option{
tsic.WithCACert(headscale.GetCert()),
tsic.WithHeadscaleName(headscale.GetHostname()),
@@ -1698,8 +1706,6 @@ func TestACLAutogroupSelf(t *testing.T) {
},
hsic.WithACLPolicy(policy),
hsic.WithTestName("acl-autogroup-self"),
hsic.WithEmbeddedDERPServerOnly(),
hsic.WithTLS(),
)
require.NoError(t, err)
@@ -1721,7 +1727,10 @@ func TestACLAutogroupSelf(t *testing.T) {
authKey, err := scenario.CreatePreAuthKeyWithTags(routerUser.GetId(), true, false, []string{"tag:router-node"})
require.NoError(t, err)
// Create router node (tags come from the PreAuthKey)
// Create router node (tags come from the PreAuthKey).
// CACert and HeadscaleName are passed explicitly because
// nodes created via tsic.New are not part of the standard
// CreateHeadscaleEnv flow.
routerClient, err := tsic.New(
scenario.Pool(),
"unstable",
@@ -1917,9 +1926,7 @@ func TestACLPolicyPropagationOverTime(t *testing.T) {
tsic.WithDockerWorkdir("/"),
},
hsic.WithTestName("aclpropagation"),
hsic.WithPolicyMode(types.PolicyModeDB),
hsic.WithEmbeddedDERPServerOnly(),
hsic.WithTLS(),
hsic.WithPolicyMode(types.PolicyModeDB), // test updates policy at runtime via CLI
)
require.NoError(t, err)
@@ -2738,8 +2745,6 @@ func TestACLTagPropagation(t *testing.T) {
},
hsic.WithACLPolicy(tt.policy),
hsic.WithTestName("acl-tag-"+tt.name),
hsic.WithEmbeddedDERPServerOnly(),
hsic.WithTLS(),
)
require.NoError(t, err)
@@ -2926,8 +2931,6 @@ func TestACLTagPropagationPortSpecific(t *testing.T) {
},
hsic.WithACLPolicy(policy),
hsic.WithTestName("acl-tag-port-specific"),
hsic.WithEmbeddedDERPServerOnly(),
hsic.WithTLS(),
)
require.NoError(t, err)
@@ -3090,8 +3093,6 @@ func TestACLGroupWithUnknownUser(t *testing.T) {
},
hsic.WithACLPolicy(policy),
hsic.WithTestName("acl-unknown-user"),
hsic.WithEmbeddedDERPServerOnly(),
hsic.WithTLS(),
)
require.NoError(t, err)
@@ -3192,8 +3193,6 @@ func TestACLGroupAfterUserDeletion(t *testing.T) {
},
hsic.WithACLPolicy(policy),
hsic.WithTestName("acl-deleted-user"),
hsic.WithEmbeddedDERPServerOnly(),
hsic.WithTLS(),
hsic.WithPolicyMode(types.PolicyModeDB), // Use DB mode so policy persists after user deletion
)
require.NoError(t, err)
@@ -3386,9 +3385,7 @@ func TestACLGroupDeletionExactReproduction(t *testing.T) {
},
hsic.WithACLPolicy(initialPolicy),
hsic.WithTestName("acl-exact-repro"),
hsic.WithEmbeddedDERPServerOnly(),
hsic.WithTLS(),
hsic.WithPolicyMode(types.PolicyModeDB),
hsic.WithPolicyMode(types.PolicyModeDB), // test updates policy at runtime via CLI
)
require.NoError(t, err)
@@ -3565,9 +3562,7 @@ func TestACLDynamicUnknownUserAddition(t *testing.T) {
},
hsic.WithACLPolicy(validPolicy),
hsic.WithTestName("acl-dynamic-unknown"),
hsic.WithEmbeddedDERPServerOnly(),
hsic.WithTLS(),
hsic.WithPolicyMode(types.PolicyModeDB),
hsic.WithPolicyMode(types.PolicyModeDB), // test updates policy at runtime via CLI
)
require.NoError(t, err)
@@ -3723,9 +3718,7 @@ func TestACLDynamicUnknownUserRemoval(t *testing.T) {
},
hsic.WithACLPolicy(policyWithUnknown),
hsic.WithTestName("acl-unknown-removal"),
hsic.WithEmbeddedDERPServerOnly(),
hsic.WithTLS(),
hsic.WithPolicyMode(types.PolicyModeDB),
hsic.WithPolicyMode(types.PolicyModeDB), // test updates policy at runtime via CLI
)
require.NoError(t, err)