nolint:gocyclo // complex HA failover test scenario
(t *testing.T)
| 221 | |
| 222 | //nolint:gocyclo // complex HA failover test scenario |
| 223 | func TestHASubnetRouterFailover(t *testing.T) { |
| 224 | IntegrationSkip(t) |
| 225 | |
| 226 | // HASlowConverge (not HAConverge): tailscale's wgengine sometimes |
| 227 | // keeps routing through the previous primary for ~2 min after |
| 228 | // the netmap update flips PrimaryRoutes server-side. |
| 229 | propagationTime := integrationutil.HASlowConvergeTimeout |
| 230 | |
| 231 | // Helper function to validate primary routes table state |
| 232 | validatePrimaryRoutes := func(t *testing.T, headscale ControlServer, expectedRoutes *types.DebugRoutes, message string) { |
| 233 | t.Helper() |
| 234 | assert.EventuallyWithT(t, func(c *assert.CollectT) { |
| 235 | primaryRoutesState, err := headscale.PrimaryRoutes() |
| 236 | assert.NoError(c, err) |
| 237 | |
| 238 | if diff := cmpdiff.Diff(expectedRoutes, primaryRoutesState, util.PrefixComparer); diff != "" { |
| 239 | t.Log(message) |
| 240 | t.Errorf("validatePrimaryRoutes mismatch (-want +got):\n%s", diff) |
| 241 | } |
| 242 | }, propagationTime, 200*time.Millisecond, "Validating primary routes table") |
| 243 | } |
| 244 | |
| 245 | spec := ScenarioSpec{ |
| 246 | NodesPerUser: 3, |
| 247 | Users: []string{"user1", "user2"}, |
| 248 | Networks: map[string]NetworkSpec{ |
| 249 | "usernet1": {Users: []string{"user1"}}, |
| 250 | "usernet2": {Users: []string{"user2"}}, |
| 251 | }, |
| 252 | ExtraService: map[string][]extraServiceFunc{ |
| 253 | "usernet1": {Webservice}, |
| 254 | }, |
| 255 | // We build the head image with curl and traceroute, so only use |
| 256 | // that for this test. |
| 257 | Versions: []string{"head"}, |
| 258 | } |
| 259 | |
| 260 | scenario, err := NewScenario(spec) |
| 261 | require.NoErrorf(t, err, "failed to create scenario: %s", err) |
| 262 | // defer scenario.ShutdownAssertNoPanics(t) |
| 263 | |
| 264 | err = scenario.CreateHeadscaleEnv( |
| 265 | []tsic.Option{tsic.WithAcceptRoutes()}, |
| 266 | hsic.WithTestName("rt-hafailover"), |
| 267 | ) |
| 268 | requireNoErrHeadscaleEnv(t, err) |
| 269 | |
| 270 | allClients, err := scenario.ListTailscaleClients() |
| 271 | requireNoErrListClients(t, err) |
| 272 | |
| 273 | err = scenario.WaitForTailscaleSync() |
| 274 | requireNoErrSync(t, err) |
| 275 | |
| 276 | headscale, err := scenario.Headscale() |
| 277 | requireNoErrGetHeadscale(t, err) |
| 278 | |
| 279 | prefp, err := scenario.SubnetOfNetwork("usernet1") |
| 280 | require.NoError(t, err) |
nothing calls this directly
no test coverage detected