mirror of
https://github.com/juanfont/headscale.git
synced 2026-05-23 18:48:42 +09:00
integration: replace ad-hoc test timeouts with named constants
Categorised timeouts in integrationutil/timeouts.go remove the drift opportunity between same-purpose budgets repeated across the suite. The auth, cli, dns, derp, ssh, and tags tests are swept; acl, route, and general tests follow in later commits alongside their other ergonomic fixes.
This commit is contained in:
@@ -88,7 +88,7 @@ func TestAuthKeyLogoutAndReloginSameUser(t *testing.T) {
|
||||
for _, node := range listNodes {
|
||||
assertLastSeenSetWithCollect(c, node)
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for expected node list before logout")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for expected node list before logout")
|
||||
|
||||
nodeCountBeforeLogout = len(listNodes)
|
||||
t.Logf("node count before logout: %d", nodeCountBeforeLogout)
|
||||
@@ -115,7 +115,7 @@ func TestAuthKeyLogoutAndReloginSameUser(t *testing.T) {
|
||||
listNodes, err = headscale.ListNodes()
|
||||
assert.NoError(ct, err, "Failed to list nodes after logout")
|
||||
assert.Len(ct, listNodes, nodeCountBeforeLogout, "Node count should match before logout count - expected %d nodes, got %d", nodeCountBeforeLogout, len(listNodes))
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second, "validating node persistence after logout (nodes should remain in database)")
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second, "validating node persistence after logout (nodes should remain in database)")
|
||||
|
||||
for _, node := range listNodes {
|
||||
assertLastSeenSet(t, node)
|
||||
@@ -153,7 +153,7 @@ func TestAuthKeyLogoutAndReloginSameUser(t *testing.T) {
|
||||
listNodes, err = headscale.ListNodes()
|
||||
assert.NoError(ct, err, "Failed to list nodes after relogin")
|
||||
assert.Len(ct, listNodes, nodeCountBeforeLogout, "Node count should remain unchanged after relogin - expected %d nodes, got %d", nodeCountBeforeLogout, len(listNodes))
|
||||
}, integrationutil.ScaledTimeout(60*time.Second), 2*time.Second, "validating node count stability after same-user auth key relogin")
|
||||
}, integrationutil.HAConvergeTimeout, 2*time.Second, "validating node count stability after same-user auth key relogin")
|
||||
|
||||
for _, node := range listNodes {
|
||||
assertLastSeenSet(t, node)
|
||||
@@ -210,7 +210,7 @@ func TestAuthKeyLogoutAndReloginSameUser(t *testing.T) {
|
||||
for _, node := range listNodes {
|
||||
assertLastSeenSetWithCollect(c, node)
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for node list after relogin")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for node list after relogin")
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -266,7 +266,7 @@ func TestAuthKeyLogoutAndReloginNewUser(t *testing.T) {
|
||||
listNodes, err = headscale.ListNodes()
|
||||
assert.NoError(c, err)
|
||||
assert.Len(c, listNodes, len(allClients))
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for expected node list before logout")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for expected node list before logout")
|
||||
|
||||
nodeCountBeforeLogout = len(listNodes)
|
||||
t.Logf("node count before logout: %d", nodeCountBeforeLogout)
|
||||
@@ -313,7 +313,7 @@ func TestAuthKeyLogoutAndReloginNewUser(t *testing.T) {
|
||||
user1Nodes, err = headscale.ListNodes("user1")
|
||||
assert.NoError(ct, err, "Failed to list nodes for user1 after relogin")
|
||||
assert.Len(ct, user1Nodes, len(allClients), "User1 should have all %d clients after relogin, got %d nodes", len(allClients), len(user1Nodes))
|
||||
}, integrationutil.ScaledTimeout(60*time.Second), 2*time.Second, "validating user1 has all client nodes after auth key relogin")
|
||||
}, integrationutil.HAConvergeTimeout, 2*time.Second, "validating user1 has all client nodes after auth key relogin")
|
||||
|
||||
// Collect expected node IDs for user1 after relogin
|
||||
expectedUser1Nodes := make([]types.NodeID, 0, len(user1Nodes))
|
||||
@@ -337,7 +337,7 @@ func TestAuthKeyLogoutAndReloginNewUser(t *testing.T) {
|
||||
user2Nodes, err = headscale.ListNodes("user2")
|
||||
assert.NoError(ct, err, "Failed to list nodes for user2 after user1 relogin")
|
||||
assert.Len(ct, user2Nodes, len(allClients)/2, "User2 should still have %d clients after user1 relogin, got %d nodes", len(allClients)/2, len(user2Nodes))
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second, "validating user2 nodes persist after user1 relogin (should not be affected)")
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second, "validating user2 nodes persist after user1 relogin (should not be affected)")
|
||||
|
||||
t.Logf("Validating client login states after user switch at %s", time.Now().Format(TimestampFormat))
|
||||
|
||||
@@ -346,7 +346,7 @@ func TestAuthKeyLogoutAndReloginNewUser(t *testing.T) {
|
||||
status, err := client.Status()
|
||||
assert.NoError(ct, err, "Failed to get status for client %s", client.Hostname())
|
||||
assert.Equal(ct, "user1@test.no", status.User[status.Self.UserID].LoginName, "Client %s should be logged in as user1 after user switch, got %s", client.Hostname(), status.User[status.Self.UserID].LoginName)
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second, "validating %s is logged in as user1 after auth key user switch", client.Hostname())
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second, "validating %s is logged in as user1 after auth key user switch", client.Hostname())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,7 +412,7 @@ func TestAuthKeyLogoutAndReloginSameUserExpiredKey(t *testing.T) {
|
||||
listNodes, err = headscale.ListNodes()
|
||||
assert.NoError(c, err)
|
||||
assert.Len(c, listNodes, len(allClients))
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for expected node list before logout")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for expected node list before logout")
|
||||
|
||||
nodeCountBeforeLogout = len(listNodes)
|
||||
t.Logf("node count before logout: %d", nodeCountBeforeLogout)
|
||||
@@ -527,7 +527,7 @@ func TestAuthKeyDeleteKey(t *testing.T) {
|
||||
user1Nodes, err = headscale.ListNodes("user1")
|
||||
assert.NoError(c, err)
|
||||
assert.Len(c, user1Nodes, 1)
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for node to be registered")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for node to be registered")
|
||||
|
||||
nodeID := user1Nodes[0].GetId()
|
||||
nodeName := user1Nodes[0].GetName()
|
||||
@@ -554,7 +554,7 @@ func TestAuthKeyDeleteKey(t *testing.T) {
|
||||
status, err := client.Status()
|
||||
assert.NoError(c, err)
|
||||
assert.Equal(c, "Stopped", status.BackendState)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "client should be stopped")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "client should be stopped")
|
||||
|
||||
err = client.Up()
|
||||
require.NoError(t, err)
|
||||
@@ -659,7 +659,7 @@ func TestAuthKeyLogoutAndReloginRoutesPreserved(t *testing.T) {
|
||||
assert.Contains(c, initialNode.GetSubnetRoutes(), advertiseRoute,
|
||||
"Subnet routes should contain %s", advertiseRoute)
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "initial route should be serving")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "initial route should be serving")
|
||||
|
||||
require.NotNil(t, initialNode, "Initial node should be found")
|
||||
initialNodeID := initialNode.GetId()
|
||||
@@ -677,7 +677,7 @@ func TestAuthKeyLogoutAndReloginRoutesPreserved(t *testing.T) {
|
||||
status, err := client.Status()
|
||||
assert.NoError(ct, err)
|
||||
assert.Equal(ct, "NeedsLogin", status.BackendState, "Expected NeedsLogin state after logout")
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "waiting for logout to complete")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "waiting for logout to complete")
|
||||
|
||||
t.Logf("Logout completed, node should still exist in database")
|
||||
|
||||
@@ -686,7 +686,7 @@ func TestAuthKeyLogoutAndReloginRoutesPreserved(t *testing.T) {
|
||||
nodes, err := headscale.ListNodes()
|
||||
assert.NoError(c, err)
|
||||
assert.Len(c, nodes, 1, "Node should persist in database after logout")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "node should persist after logout")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "node should persist after logout")
|
||||
|
||||
// Step 3: Re-authenticate with the SAME user (using auth key)
|
||||
t.Logf("Step 3: Re-authenticating with same user at %s", time.Now().Format(TimestampFormat))
|
||||
@@ -707,7 +707,7 @@ func TestAuthKeyLogoutAndReloginRoutesPreserved(t *testing.T) {
|
||||
status, err := client.Status()
|
||||
assert.NoError(ct, err)
|
||||
assert.Equal(ct, "Running", status.BackendState, "Expected Running state after relogin")
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "waiting for relogin to complete")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "waiting for relogin to complete")
|
||||
|
||||
t.Logf("Re-authentication completed at %s", time.Now().Format(TimestampFormat))
|
||||
|
||||
@@ -741,7 +741,7 @@ func TestAuthKeyLogoutAndReloginRoutesPreserved(t *testing.T) {
|
||||
assert.Equal(c, initialNodeID, node.GetId(),
|
||||
"Node ID should be preserved after same-user relogin")
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond,
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll,
|
||||
"BUG #2896: routes should remain SERVING after logout/relogin with same user")
|
||||
|
||||
t.Logf("Test completed - verifying issue #2896 fix")
|
||||
|
||||
@@ -526,7 +526,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
if diff := cmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
||||
ct.Errorf("User validation failed after first login - unexpected users: %s", diff)
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "validating user1 creation after initial OIDC login")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "validating user1 creation after initial OIDC login")
|
||||
|
||||
t.Logf("Validating initial node creation at %s", time.Now().Format(TimestampFormat))
|
||||
|
||||
@@ -538,7 +538,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
listNodes, err = headscale.ListNodes()
|
||||
assert.NoError(ct, err, "Failed to list nodes during initial validation")
|
||||
assert.Len(ct, listNodes, 1, "Expected exactly 1 node after first login, got %d", len(listNodes))
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "validating initial node creation for user1 after OIDC login")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "validating initial node creation for user1 after OIDC login")
|
||||
|
||||
// Collect expected node IDs for validation after user1 initial login
|
||||
expectedNodes := make([]types.NodeID, 0, 1)
|
||||
@@ -553,7 +553,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
|
||||
nodeID, err = strconv.ParseUint(string(status.Self.ID), 10, 64)
|
||||
assert.NoError(ct, err, "Failed to parse node ID from status")
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "waiting for node ID to be populated in status after initial login")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "waiting for node ID to be populated in status after initial login")
|
||||
|
||||
expectedNodes = append(expectedNodes, types.NodeID(nodeID))
|
||||
|
||||
@@ -579,7 +579,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
status, err := ts.Status()
|
||||
assert.NoError(ct, err, "Failed to get client status during logout validation")
|
||||
assert.Equal(ct, "NeedsLogin", status.BackendState, "Expected NeedsLogin state after logout, got %s", status.BackendState)
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "waiting for user1 logout to complete before user2 login")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "waiting for user1 logout to complete before user2 login")
|
||||
|
||||
u, err = ts.LoginWithURL(headscale.GetEndpoint())
|
||||
require.NoError(t, err)
|
||||
@@ -617,7 +617,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
if diff := cmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
||||
ct.Errorf("User validation failed after user2 login - expected both user1 and user2: %s", diff)
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "validating both user1 and user2 exist after second OIDC login")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "validating both user1 and user2 exist after second OIDC login")
|
||||
|
||||
var listNodesAfterNewUserLogin []*v1.Node
|
||||
// First, wait for the new node to be created
|
||||
@@ -627,7 +627,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
assert.NoError(ct, err, "Failed to list nodes after user2 login")
|
||||
// We might temporarily have more than 2 nodes during cleanup, so check for at least 2
|
||||
assert.GreaterOrEqual(ct, len(listNodesAfterNewUserLogin), 2, "Should have at least 2 nodes after user2 login, got %d (may include temporary nodes during cleanup)", len(listNodesAfterNewUserLogin))
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "waiting for user2 node creation (allowing temporary extra nodes during cleanup)")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "waiting for user2 node creation (allowing temporary extra nodes during cleanup)")
|
||||
|
||||
// Then wait for cleanup to stabilize at exactly 2 nodes
|
||||
t.Logf("Waiting for node cleanup stabilization at %s", time.Now().Format(TimestampFormat))
|
||||
@@ -644,7 +644,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
assert.Equal(ct, listNodesAfterNewUserLogin[0].GetMachineKey(), listNodesAfterNewUserLogin[1].GetMachineKey(), "Both nodes should share the same machine key")
|
||||
assert.NotEqual(ct, listNodesAfterNewUserLogin[0].GetNodeKey(), listNodesAfterNewUserLogin[1].GetNodeKey(), "Node keys should be different between user1 and user2 nodes")
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(90*time.Second), 2*time.Second, "waiting for node count stabilization at exactly 2 nodes after user2 login")
|
||||
}, integrationutil.PolicyPropagationTimeout, 2*time.Second, "waiting for node count stabilization at exactly 2 nodes after user2 login")
|
||||
|
||||
// Security validation: Only user2's node should be active after user switch
|
||||
var activeUser2NodeID types.NodeID
|
||||
@@ -674,7 +674,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
} else {
|
||||
assert.Fail(c, "User2 node not found in nodestore")
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(60*time.Second), 2*time.Second, "validating only user2 node is online after user switch")
|
||||
}, integrationutil.HAConvergeTimeout, 2*time.Second, "validating only user2 node is online after user switch")
|
||||
|
||||
// Before logging out user2, validate we have exactly 2 nodes and both are stable
|
||||
t.Logf("Pre-logout validation: checking node stability at %s", time.Now().Format(TimestampFormat))
|
||||
@@ -689,7 +689,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
assert.NotEmpty(ct, node.GetMachineKey(), "Node %d should have a valid machine key before logout", i)
|
||||
t.Logf("Pre-logout node %d: User=%s, MachineKey=%s", i, node.GetUser().GetName(), node.GetMachineKey()[:16]+"...")
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(60*time.Second), 2*time.Second, "validating stable node count and integrity before user2 logout")
|
||||
}, integrationutil.HAConvergeTimeout, 2*time.Second, "validating stable node count and integrity before user2 logout")
|
||||
|
||||
// Log out user2, and log into user1, no new node should be created,
|
||||
// the node should now "become" node1 again
|
||||
@@ -715,7 +715,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
status, err := ts.Status()
|
||||
assert.NoError(ct, err, "Failed to get client status during user2 logout validation")
|
||||
assert.Equal(ct, "NeedsLogin", status.BackendState, "Expected NeedsLogin state after user2 logout, got %s", status.BackendState)
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "waiting for user2 logout to complete before user1 relogin")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "waiting for user2 logout to complete before user1 relogin")
|
||||
|
||||
// Before logging back in, ensure we still have exactly 2 nodes
|
||||
// Note: We skip validateLogoutComplete here since it expects all nodes to be offline,
|
||||
@@ -734,7 +734,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
assert.NotEmpty(ct, node.GetMachineKey(), "Node %d should still have a valid machine key after user2 logout", i)
|
||||
t.Logf("Post-logout node %d: User=%s, MachineKey=%s", i, node.GetUser().GetName(), node.GetMachineKey()[:16]+"...")
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(60*time.Second), 2*time.Second, "validating node persistence and integrity after user2 logout")
|
||||
}, integrationutil.HAConvergeTimeout, 2*time.Second, "validating node persistence and integrity after user2 logout")
|
||||
|
||||
// We do not actually "change" the user here, it is done by logging in again
|
||||
// as the OIDC mock server is kind of like a stack, and the next user is
|
||||
@@ -750,7 +750,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
status, err := ts.Status()
|
||||
assert.NoError(ct, err, "Failed to get client status during user1 relogin validation")
|
||||
assert.Equal(ct, "Running", status.BackendState, "Expected Running state after user1 relogin, got %s", status.BackendState)
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "waiting for user1 relogin to complete (final login)")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "waiting for user1 relogin to complete (final login)")
|
||||
|
||||
t.Logf("Logged back in")
|
||||
t.Log("timestamp: " + time.Now().Format(TimestampFormat) + "\n")
|
||||
@@ -785,7 +785,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
if diff := cmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
||||
ct.Errorf("Final user validation failed - both users should persist after relogin cycle: %s", diff)
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "validating user persistence after complete relogin cycle (user1->user2->user1)")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "validating user persistence after complete relogin cycle (user1->user2->user1)")
|
||||
|
||||
var listNodesAfterLoggingBackIn []*v1.Node
|
||||
// Wait for login to complete and nodes to stabilize
|
||||
@@ -826,7 +826,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
assert.NotEqual(ct, listNodesAfterLoggingBackIn[0].GetNodeKey(), listNodesAfterLoggingBackIn[1].GetNodeKey(), "Final nodes should have different node keys for different users")
|
||||
|
||||
t.Logf("Final validation complete - node counts and key relationships verified at %s", time.Now().Format(TimestampFormat))
|
||||
}, integrationutil.ScaledTimeout(60*time.Second), 2*time.Second, "validating final node state after complete user1->user2->user1 relogin cycle with detailed key validation")
|
||||
}, integrationutil.HAConvergeTimeout, 2*time.Second, "validating final node state after complete user1->user2->user1 relogin cycle with detailed key validation")
|
||||
|
||||
// Security validation: Only user1's node should be active after relogin
|
||||
var activeUser1NodeID types.NodeID
|
||||
@@ -856,7 +856,7 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||
} else {
|
||||
assert.Fail(c, "User1 node not found in nodestore after relogin")
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(60*time.Second), 2*time.Second, "validating only user1 node is online after final relogin")
|
||||
}, integrationutil.HAConvergeTimeout, 2*time.Second, "validating only user1 node is online after final relogin")
|
||||
}
|
||||
|
||||
// TestOIDCFollowUpUrl validates the follow-up login flow
|
||||
@@ -933,7 +933,7 @@ func TestOIDCFollowUpUrl(t *testing.T) {
|
||||
assert.NoError(c, err)
|
||||
|
||||
assert.NotEqual(c, u.String(), st.AuthURL, "AuthURL should change")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for registration cache to expire and status to reflect NeedsLogin")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for registration cache to expire and status to reflect NeedsLogin")
|
||||
|
||||
_, err = doLoginURL(ts.Hostname(), newUrl)
|
||||
require.NoError(t, err)
|
||||
@@ -971,7 +971,7 @@ func TestOIDCFollowUpUrl(t *testing.T) {
|
||||
listNodes, err := headscale.ListNodes()
|
||||
assert.NoError(c, err)
|
||||
assert.Len(c, listNodes, 1)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for expected node list after OIDC login")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for expected node list after OIDC login")
|
||||
}
|
||||
|
||||
// TestOIDCMultipleOpenedLoginUrls tests the scenario:
|
||||
@@ -1081,7 +1081,7 @@ func TestOIDCMultipleOpenedLoginUrls(t *testing.T) {
|
||||
listNodes, err := headscale.ListNodes()
|
||||
assert.NoError(c, err)
|
||||
assert.Len(c, listNodes, 1)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for expected node list after OIDC login",
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for expected node list after OIDC login",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1176,7 +1176,7 @@ func TestOIDCReloginSameNodeSameUser(t *testing.T) {
|
||||
if diff := cmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
||||
ct.Errorf("User validation failed after first login - unexpected users: %s", diff)
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "validating user1 creation after initial OIDC login")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "validating user1 creation after initial OIDC login")
|
||||
|
||||
t.Logf("Validating initial node creation at %s", time.Now().Format(TimestampFormat))
|
||||
|
||||
@@ -1188,7 +1188,7 @@ func TestOIDCReloginSameNodeSameUser(t *testing.T) {
|
||||
initialNodes, err = headscale.ListNodes()
|
||||
assert.NoError(ct, err, "Failed to list nodes during initial validation")
|
||||
assert.Len(ct, initialNodes, 1, "Expected exactly 1 node after first login, got %d", len(initialNodes))
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "validating initial node creation for user1 after OIDC login")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "validating initial node creation for user1 after OIDC login")
|
||||
|
||||
// Collect expected node IDs for validation after user1 initial login
|
||||
expectedNodes := make([]types.NodeID, 0, 1)
|
||||
@@ -1203,7 +1203,7 @@ func TestOIDCReloginSameNodeSameUser(t *testing.T) {
|
||||
|
||||
nodeID, err = strconv.ParseUint(string(status.Self.ID), 10, 64)
|
||||
assert.NoError(ct, err, "Failed to parse node ID from status")
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "waiting for node ID to be populated in status after initial login")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "waiting for node ID to be populated in status after initial login")
|
||||
|
||||
expectedNodes = append(expectedNodes, types.NodeID(nodeID))
|
||||
|
||||
@@ -1232,7 +1232,7 @@ func TestOIDCReloginSameNodeSameUser(t *testing.T) {
|
||||
status, err := ts.Status()
|
||||
assert.NoError(ct, err, "Failed to get client status during logout validation")
|
||||
assert.Equal(ct, "NeedsLogin", status.BackendState, "Expected NeedsLogin state after logout, got %s", status.BackendState)
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "waiting for user1 logout to complete before same-user relogin")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "waiting for user1 logout to complete before same-user relogin")
|
||||
|
||||
// Validate node persistence during logout (node should remain in DB)
|
||||
t.Logf("Validating node persistence during logout at %s", time.Now().Format(TimestampFormat))
|
||||
@@ -1240,7 +1240,7 @@ func TestOIDCReloginSameNodeSameUser(t *testing.T) {
|
||||
listNodes, err := headscale.ListNodes()
|
||||
assert.NoError(ct, err, "Failed to list nodes during logout validation")
|
||||
assert.Len(ct, listNodes, 1, "Should still have exactly 1 node during logout (node should persist in DB), got %d", len(listNodes))
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "validating node persistence in database during same-user logout")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "validating node persistence in database during same-user logout")
|
||||
|
||||
// Login again as the same user (user1)
|
||||
u, err = ts.LoginWithURL(headscale.GetEndpoint())
|
||||
@@ -1254,7 +1254,7 @@ func TestOIDCReloginSameNodeSameUser(t *testing.T) {
|
||||
status, err := ts.Status()
|
||||
assert.NoError(ct, err, "Failed to get client status during relogin validation")
|
||||
assert.Equal(ct, "Running", status.BackendState, "Expected Running state after user1 relogin, got %s", status.BackendState)
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "waiting for user1 relogin to complete (same user)")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "waiting for user1 relogin to complete (same user)")
|
||||
|
||||
t.Logf("Final validation: checking user persistence after same-user relogin at %s", time.Now().Format(TimestampFormat))
|
||||
assert.EventuallyWithT(t, func(ct *assert.CollectT) {
|
||||
@@ -1279,7 +1279,7 @@ func TestOIDCReloginSameNodeSameUser(t *testing.T) {
|
||||
if diff := cmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
||||
ct.Errorf("Final user validation failed - user1 should persist after same-user relogin: %s", diff)
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "validating user1 persistence after same-user OIDC relogin cycle")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "validating user1 persistence after same-user OIDC relogin cycle")
|
||||
|
||||
var finalNodes []*v1.Node
|
||||
|
||||
@@ -1302,7 +1302,7 @@ func TestOIDCReloginSameNodeSameUser(t *testing.T) {
|
||||
assert.NotEqual(ct, initialNodeKey, finalNode.GetNodeKey(), "Node key should be regenerated after logout/relogin even for same user")
|
||||
|
||||
t.Logf("Final validation complete - same user relogin key relationships verified at %s", time.Now().Format(TimestampFormat))
|
||||
}, integrationutil.ScaledTimeout(60*time.Second), 2*time.Second, "validating final node state after same-user OIDC relogin cycle with key preservation validation")
|
||||
}, integrationutil.HAConvergeTimeout, 2*time.Second, "validating final node state after same-user OIDC relogin cycle with key preservation validation")
|
||||
|
||||
// Security validation: user1's node should be active after relogin
|
||||
activeUser1NodeID := types.NodeID(finalNodes[0].GetId())
|
||||
@@ -1322,7 +1322,7 @@ func TestOIDCReloginSameNodeSameUser(t *testing.T) {
|
||||
} else {
|
||||
assert.Fail(c, "User1 node not found in nodestore after same-user relogin")
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(60*time.Second), 2*time.Second, "validating user1 node is online after same-user OIDC relogin")
|
||||
}, integrationutil.HAConvergeTimeout, 2*time.Second, "validating user1 node is online after same-user OIDC relogin")
|
||||
}
|
||||
|
||||
// TestOIDCExpiryAfterRestart validates that node expiry is preserved
|
||||
@@ -1398,7 +1398,7 @@ func TestOIDCExpiryAfterRestart(t *testing.T) {
|
||||
initialExpiry = expiryTime
|
||||
t.Logf("Initial expiry set to: %v (expires in %v)", expiryTime, time.Until(expiryTime))
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "validating initial expiry after OIDC login")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "validating initial expiry after OIDC login")
|
||||
|
||||
// Now restart the tailscaled container
|
||||
t.Logf("Restarting tailscaled container at %s", time.Now().Format(TimestampFormat))
|
||||
@@ -1420,7 +1420,7 @@ func TestOIDCExpiryAfterRestart(t *testing.T) {
|
||||
}
|
||||
|
||||
assert.Equal(ct, "Running", status.BackendState)
|
||||
}, integrationutil.ScaledTimeout(60*time.Second), 2*time.Second, "waiting for tailscale to reconnect after restart")
|
||||
}, integrationutil.HAConvergeTimeout, 2*time.Second, "waiting for tailscale to reconnect after restart")
|
||||
|
||||
// THE CRITICAL TEST: Verify expiry is still set correctly after restart
|
||||
t.Logf("Validating expiry preservation after restart at %s", time.Now().Format(TimestampFormat))
|
||||
@@ -1448,7 +1448,7 @@ func TestOIDCExpiryAfterRestart(t *testing.T) {
|
||||
t.Logf("SUCCESS: Expiry preserved after restart: %v (expires in %v)",
|
||||
expiryTime, time.Until(expiryTime))
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "validating expiry preservation after restart")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "validating expiry preservation after restart")
|
||||
}
|
||||
|
||||
// TestOIDCACLPolicyOnJoin validates that ACL policies are correctly applied
|
||||
@@ -1570,7 +1570,7 @@ func TestOIDCACLPolicyOnJoin(t *testing.T) {
|
||||
gatewayNodeID = gatewayNode.GetId()
|
||||
assert.Len(ct, gatewayNode.GetAvailableRoutes(), 1)
|
||||
assert.Contains(ct, gatewayNode.GetAvailableRoutes(), advertiseRoute)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "route advertisement should propagate to headscale")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "route advertisement should propagate to headscale")
|
||||
|
||||
// Approve the advertised route
|
||||
_, err = headscale.ApproveRoutes(
|
||||
@@ -1588,7 +1588,7 @@ func TestOIDCACLPolicyOnJoin(t *testing.T) {
|
||||
gatewayNode := nodes[0]
|
||||
assert.Len(ct, gatewayNode.GetApprovedRoutes(), 1)
|
||||
assert.Contains(ct, gatewayNode.GetApprovedRoutes(), advertiseRoute)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "route approval should propagate to headscale")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "route approval should propagate to headscale")
|
||||
|
||||
// NOW create the OIDC user by having them join
|
||||
// This is where issue #2888 manifests - the new OIDC node should immediately
|
||||
@@ -1658,7 +1658,7 @@ func TestOIDCACLPolicyOnJoin(t *testing.T) {
|
||||
t.Logf("Gateway peer AllowedIPs: %v", allowedIPs)
|
||||
}
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(15*time.Second), 500*time.Millisecond,
|
||||
}, integrationutil.ScaledTimeout(15*time.Second), integrationutil.SlowPoll,
|
||||
"OIDC user should immediately see gateway's advertised route without client restart (issue #2888)")
|
||||
|
||||
// Verify that the Gateway node sees the OIDC node's advertised route (AutoApproveRoutes check)
|
||||
@@ -1690,7 +1690,7 @@ func TestOIDCACLPolicyOnJoin(t *testing.T) {
|
||||
"Gateway user should immediately see OIDC's advertised route %s in PrimaryRoutes", oidcAdvertiseRoute)
|
||||
}
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(15*time.Second), 500*time.Millisecond,
|
||||
}, integrationutil.ScaledTimeout(15*time.Second), integrationutil.SlowPoll,
|
||||
"Gateway user should immediately see OIDC's advertised route (AutoApproveRoutes check)")
|
||||
|
||||
// Additional validation: Verify nodes in headscale match expectations
|
||||
@@ -1738,7 +1738,7 @@ func TestOIDCACLPolicyOnJoin(t *testing.T) {
|
||||
assert.Equal(ct, "oidcuser", oidcUserFound.GetName())
|
||||
assert.Equal(ct, "oidcuser@headscale.net", oidcUserFound.GetEmail())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "headscale should have correct users and nodes")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "headscale should have correct users and nodes")
|
||||
|
||||
t.Logf("Test completed successfully - issue #2888 fix validated")
|
||||
}
|
||||
@@ -1829,7 +1829,7 @@ func TestOIDCReloginSameUserRoutesPreserved(t *testing.T) {
|
||||
status, err := ts.Status()
|
||||
assert.NoError(ct, err)
|
||||
assert.Equal(ct, "Running", status.BackendState)
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "waiting for initial login to complete")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "waiting for initial login to complete")
|
||||
|
||||
// Step 1: Verify initial route is advertised, approved, and SERVING
|
||||
t.Logf("Step 1: Verifying initial route is advertised, approved, and SERVING at %s", time.Now().Format(TimestampFormat))
|
||||
@@ -1853,7 +1853,7 @@ func TestOIDCReloginSameUserRoutesPreserved(t *testing.T) {
|
||||
assert.Contains(c, initialNode.GetSubnetRoutes(), advertiseRoute,
|
||||
"Subnet routes should contain %s", advertiseRoute)
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "initial route should be serving")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "initial route should be serving")
|
||||
|
||||
require.NotNil(t, initialNode, "Initial node should be found")
|
||||
initialNodeID := initialNode.GetId()
|
||||
@@ -1871,7 +1871,7 @@ func TestOIDCReloginSameUserRoutesPreserved(t *testing.T) {
|
||||
status, err := ts.Status()
|
||||
assert.NoError(ct, err)
|
||||
assert.Equal(ct, "NeedsLogin", status.BackendState, "Expected NeedsLogin state after logout")
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "waiting for logout to complete")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "waiting for logout to complete")
|
||||
|
||||
t.Logf("Logout completed, node should still exist in database")
|
||||
|
||||
@@ -1880,7 +1880,7 @@ func TestOIDCReloginSameUserRoutesPreserved(t *testing.T) {
|
||||
nodes, err := headscale.ListNodes()
|
||||
assert.NoError(c, err)
|
||||
assert.Len(c, nodes, 1, "Node should persist in database after logout")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "node should persist after logout")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "node should persist after logout")
|
||||
|
||||
// Step 3: Re-authenticate via OIDC as the same user
|
||||
t.Logf("Step 3: Re-authenticating with same user via OIDC at %s", time.Now().Format(TimestampFormat))
|
||||
@@ -1896,7 +1896,7 @@ func TestOIDCReloginSameUserRoutesPreserved(t *testing.T) {
|
||||
status, err := ts.Status()
|
||||
assert.NoError(ct, err)
|
||||
assert.Equal(ct, "Running", status.BackendState, "Expected Running state after relogin")
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 1*time.Second, "waiting for relogin to complete")
|
||||
}, integrationutil.StatusReadyTimeout, 1*time.Second, "waiting for relogin to complete")
|
||||
|
||||
t.Logf("Re-authentication completed at %s", time.Now().Format(TimestampFormat))
|
||||
|
||||
@@ -1930,7 +1930,7 @@ func TestOIDCReloginSameUserRoutesPreserved(t *testing.T) {
|
||||
assert.Equal(c, initialNodeID, node.GetId(),
|
||||
"Node ID should be preserved after same-user relogin")
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond,
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll,
|
||||
"BUG #2896: routes should remain SERVING after OIDC logout/relogin with same user")
|
||||
|
||||
t.Logf("Test completed - verifying issue #2896 fix for OIDC")
|
||||
|
||||
@@ -107,7 +107,7 @@ func TestAuthWebFlowLogoutAndReloginSameUser(t *testing.T) {
|
||||
listNodes, err = headscale.ListNodes()
|
||||
assert.NoError(ct, err, "Failed to list nodes after web authentication")
|
||||
assert.Len(ct, listNodes, len(allClients), "Expected %d nodes after web auth, got %d", len(allClients), len(listNodes))
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second, "validating node count matches client count after web authentication")
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second, "validating node count matches client count after web authentication")
|
||||
|
||||
nodeCountBeforeLogout := len(listNodes)
|
||||
t.Logf("node count before logout: %d", nodeCountBeforeLogout)
|
||||
@@ -154,7 +154,7 @@ func TestAuthWebFlowLogoutAndReloginSameUser(t *testing.T) {
|
||||
listNodes, err = headscale.ListNodes()
|
||||
assert.NoError(ct, err, "Failed to list nodes after web flow logout")
|
||||
assert.Len(ct, listNodes, nodeCountBeforeLogout, "Node count should remain unchanged after logout - expected %d nodes, got %d", nodeCountBeforeLogout, len(listNodes))
|
||||
}, integrationutil.ScaledTimeout(60*time.Second), 2*time.Second, "validating node persistence in database after web flow logout")
|
||||
}, integrationutil.HAConvergeTimeout, 2*time.Second, "validating node persistence in database after web flow logout")
|
||||
t.Logf("node count first login: %d, after relogin: %d", nodeCountBeforeLogout, len(listNodes))
|
||||
|
||||
// Validate connection state after relogin
|
||||
@@ -265,7 +265,7 @@ func TestAuthWebFlowLogoutAndReloginNewUser(t *testing.T) {
|
||||
listNodes, err = headscale.ListNodes()
|
||||
assert.NoError(ct, err, "Failed to list nodes after initial web authentication")
|
||||
assert.Len(ct, listNodes, len(allClients), "Expected %d nodes after web auth, got %d", len(allClients), len(listNodes))
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second, "validating node count matches client count after initial web authentication")
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second, "validating node count matches client count after initial web authentication")
|
||||
|
||||
nodeCountBeforeLogout := len(listNodes)
|
||||
t.Logf("node count before logout: %d", nodeCountBeforeLogout)
|
||||
@@ -325,7 +325,7 @@ func TestAuthWebFlowLogoutAndReloginNewUser(t *testing.T) {
|
||||
user1Nodes, err = headscale.ListNodes("user1")
|
||||
assert.NoError(ct, err, "Failed to list nodes for user1 after web flow relogin")
|
||||
assert.Len(ct, user1Nodes, len(allClients), "User1 should have all %d clients after web flow relogin, got %d nodes", len(allClients), len(user1Nodes))
|
||||
}, integrationutil.ScaledTimeout(60*time.Second), 2*time.Second, "validating user1 has all client nodes after web flow user switch relogin")
|
||||
}, integrationutil.HAConvergeTimeout, 2*time.Second, "validating user1 has all client nodes after web flow user switch relogin")
|
||||
|
||||
// Collect expected node IDs for user1 after relogin
|
||||
expectedUser1Nodes := make([]types.NodeID, 0, len(user1Nodes))
|
||||
@@ -347,7 +347,7 @@ func TestAuthWebFlowLogoutAndReloginNewUser(t *testing.T) {
|
||||
user2Nodes, err = headscale.ListNodes("user2")
|
||||
assert.NoError(ct, err, "Failed to list nodes for user2 after CLI registration to user1")
|
||||
assert.Len(ct, user2Nodes, len(allClients)/2, "User2 should still have %d old nodes (likely expired) after CLI registration to user1, got %d nodes", len(allClients)/2, len(user2Nodes))
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second, "validating user2 old nodes remain in database after CLI registration to user1")
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second, "validating user2 old nodes remain in database after CLI registration to user1")
|
||||
|
||||
t.Logf("Validating client login states after web flow user switch at %s", time.Now().Format(TimestampFormat))
|
||||
|
||||
@@ -356,7 +356,7 @@ func TestAuthWebFlowLogoutAndReloginNewUser(t *testing.T) {
|
||||
status, err := client.Status()
|
||||
assert.NoError(ct, err, "Failed to get status for client %s", client.Hostname())
|
||||
assert.Equal(ct, "user1@test.no", status.User[status.Self.UserID].LoginName, "Client %s should be logged in as user1 after web flow user switch, got %s", client.Hostname(), status.User[status.Self.UserID].LoginName)
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second, "validating %s is logged in as user1 after web flow user switch", client.Hostname())
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second, "validating %s is logged in as user1 after web flow user switch", client.Hostname())
|
||||
}
|
||||
|
||||
// Test connectivity after user switch
|
||||
|
||||
@@ -147,7 +147,7 @@ func TestUserCommand(t *testing.T) {
|
||||
&listByUsername,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for user list by username")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for user list by username")
|
||||
|
||||
slices.SortFunc(listByUsername, sortWithID)
|
||||
|
||||
@@ -178,7 +178,7 @@ func TestUserCommand(t *testing.T) {
|
||||
&listByID,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for user list by ID")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for user list by ID")
|
||||
|
||||
slices.SortFunc(listByID, sortWithID)
|
||||
|
||||
@@ -264,7 +264,7 @@ func TestUserCommand(t *testing.T) {
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
assert.Empty(c, listAfterNameDelete)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for user list after name delete")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for user list after name delete")
|
||||
}
|
||||
|
||||
func TestPreAuthKeyCommand(t *testing.T) {
|
||||
@@ -315,7 +315,7 @@ func TestPreAuthKeyCommand(t *testing.T) {
|
||||
&preAuthKey,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for preauth key creation")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for preauth key creation")
|
||||
|
||||
keys[index] = &preAuthKey
|
||||
}
|
||||
@@ -337,7 +337,7 @@ func TestPreAuthKeyCommand(t *testing.T) {
|
||||
&listedPreAuthKeys,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for preauth keys list")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for preauth keys list")
|
||||
|
||||
// There is one key created by "scenario.CreateHeadscaleEnv"
|
||||
assert.Len(t, listedPreAuthKeys, 4)
|
||||
@@ -413,7 +413,7 @@ func TestPreAuthKeyCommand(t *testing.T) {
|
||||
&listedPreAuthKeysAfterExpire,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for preauth keys list after expire")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for preauth keys list after expire")
|
||||
|
||||
assert.True(t, listedPreAuthKeysAfterExpire[1].GetExpiration().AsTime().Before(time.Now()))
|
||||
assert.True(t, listedPreAuthKeysAfterExpire[2].GetExpiration().AsTime().After(time.Now()))
|
||||
@@ -457,7 +457,7 @@ func TestPreAuthKeyCommandWithoutExpiry(t *testing.T) {
|
||||
&preAuthKey,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for preauth key creation without expiry")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for preauth key creation without expiry")
|
||||
|
||||
var listedPreAuthKeys []v1.PreAuthKey
|
||||
|
||||
@@ -474,7 +474,7 @@ func TestPreAuthKeyCommandWithoutExpiry(t *testing.T) {
|
||||
&listedPreAuthKeys,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for preauth keys list")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for preauth keys list")
|
||||
|
||||
// There is one key created by "scenario.CreateHeadscaleEnv"
|
||||
assert.Len(t, listedPreAuthKeys, 2)
|
||||
@@ -523,7 +523,7 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
|
||||
&preAuthReusableKey,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for reusable preauth key creation")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for reusable preauth key creation")
|
||||
|
||||
var preAuthEphemeralKey v1.PreAuthKey
|
||||
|
||||
@@ -543,7 +543,7 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
|
||||
&preAuthEphemeralKey,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for ephemeral preauth key creation")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for ephemeral preauth key creation")
|
||||
|
||||
assert.True(t, preAuthEphemeralKey.GetEphemeral())
|
||||
assert.False(t, preAuthEphemeralKey.GetReusable())
|
||||
@@ -563,7 +563,7 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
|
||||
&listedPreAuthKeys,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for preauth keys list after reusable/ephemeral creation")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for preauth keys list after reusable/ephemeral creation")
|
||||
|
||||
// There is one key created by "scenario.CreateHeadscaleEnv"
|
||||
assert.Len(t, listedPreAuthKeys, 3)
|
||||
@@ -621,7 +621,7 @@ func TestPreAuthKeyCorrectUserLoggedInCommand(t *testing.T) {
|
||||
&user2Key,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for user2 preauth key creation")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for user2 preauth key creation")
|
||||
|
||||
var listNodes []*v1.Node
|
||||
|
||||
@@ -653,7 +653,7 @@ func TestPreAuthKeyCorrectUserLoggedInCommand(t *testing.T) {
|
||||
assert.NoError(ct, err)
|
||||
assert.NotContains(ct, []string{"Starting", "Running"}, status.BackendState,
|
||||
"Expected node to be logged out, backend state: %s", status.BackendState)
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second)
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second)
|
||||
|
||||
err = client.Login(headscale.GetEndpoint(), user2Key.GetKey())
|
||||
require.NoError(t, err)
|
||||
@@ -665,7 +665,7 @@ func TestPreAuthKeyCorrectUserLoggedInCommand(t *testing.T) {
|
||||
// With tags-as-identity model, tagged nodes show as TaggedDevices user (2147455555)
|
||||
// The PreAuthKey was created with tags, so the node is tagged
|
||||
assert.Equal(ct, "userid:2147455555", status.Self.UserID.String(), "Expected node to be logged in as tagged-devices user")
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second)
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second)
|
||||
|
||||
assert.EventuallyWithT(t, func(ct *assert.CollectT) {
|
||||
var err error
|
||||
@@ -730,7 +730,7 @@ func TestTaggedNodesCLIOutput(t *testing.T) {
|
||||
&user2Key,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for user2 tagged preauth key creation")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for user2 tagged preauth key creation")
|
||||
|
||||
allClients, err := scenario.ListTailscaleClients()
|
||||
requireNoErrListClients(t, err)
|
||||
@@ -751,7 +751,7 @@ func TestTaggedNodesCLIOutput(t *testing.T) {
|
||||
assert.NoError(ct, err)
|
||||
assert.NotContains(ct, []string{"Starting", "Running"}, status.BackendState,
|
||||
"Expected node to be logged out, backend state: %s", status.BackendState)
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second)
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second)
|
||||
|
||||
// Log in with the tagged PreAuthKey (from user2, with tags)
|
||||
err = client.Login(headscale.GetEndpoint(), user2Key.GetKey())
|
||||
@@ -763,7 +763,7 @@ func TestTaggedNodesCLIOutput(t *testing.T) {
|
||||
assert.Equal(ct, "Running", status.BackendState, "Expected node to be logged in, backend state: %s", status.BackendState)
|
||||
// With tags-as-identity model, tagged nodes show as TaggedDevices user (2147455555)
|
||||
assert.Equal(ct, "userid:2147455555", status.Self.UserID.String(), "Expected node to be logged in as tagged-devices user")
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second)
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second)
|
||||
|
||||
// Wait for the second node to appear
|
||||
var listNodes []*v1.Node
|
||||
@@ -850,7 +850,7 @@ func TestApiKeyCommand(t *testing.T) {
|
||||
&listedAPIKeys,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for API keys list")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for API keys list")
|
||||
|
||||
assert.Len(t, listedAPIKeys, 5)
|
||||
|
||||
@@ -925,7 +925,7 @@ func TestApiKeyCommand(t *testing.T) {
|
||||
&listedAfterExpireAPIKeys,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for API keys list after expire")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for API keys list after expire")
|
||||
|
||||
for index := range listedAfterExpireAPIKeys {
|
||||
if _, ok := expiredPrefixes[listedAfterExpireAPIKeys[index].GetPrefix()]; ok {
|
||||
@@ -967,7 +967,7 @@ func TestApiKeyCommand(t *testing.T) {
|
||||
&listedAPIKeysAfterDelete,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for API keys list after delete")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for API keys list after delete")
|
||||
|
||||
assert.Len(t, listedAPIKeysAfterDelete, 4)
|
||||
|
||||
@@ -996,7 +996,7 @@ func TestApiKeyCommand(t *testing.T) {
|
||||
&listedAPIKeysAfterExpireByID,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for API keys list after expire by ID")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for API keys list after expire by ID")
|
||||
|
||||
// Verify the key was expired
|
||||
for idx := range listedAPIKeysAfterExpireByID {
|
||||
@@ -1032,7 +1032,7 @@ func TestApiKeyCommand(t *testing.T) {
|
||||
&listedAPIKeysAfterDeleteByID,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for API keys list after delete by ID")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for API keys list after delete by ID")
|
||||
|
||||
assert.Len(t, listedAPIKeysAfterDeleteByID, 3)
|
||||
|
||||
@@ -1109,7 +1109,7 @@ func TestNodeCommand(t *testing.T) {
|
||||
&node,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for node registration")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for node registration")
|
||||
|
||||
nodes[index] = &node
|
||||
}
|
||||
@@ -1194,7 +1194,7 @@ func TestNodeCommand(t *testing.T) {
|
||||
&node,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for other-user node registration")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for other-user node registration")
|
||||
|
||||
otherUserMachines[index] = &node
|
||||
}
|
||||
@@ -1219,7 +1219,7 @@ func TestNodeCommand(t *testing.T) {
|
||||
&listAllWithotherUser,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for nodes list after adding other-user nodes")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for nodes list after adding other-user nodes")
|
||||
|
||||
// All nodes, nodes + otherUser
|
||||
assert.Len(t, listAllWithotherUser, 7)
|
||||
@@ -1248,7 +1248,7 @@ func TestNodeCommand(t *testing.T) {
|
||||
&listOnlyotherUserMachineUser,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for nodes list filtered by other-user")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for nodes list filtered by other-user")
|
||||
|
||||
assert.Len(t, listOnlyotherUserMachineUser, 2)
|
||||
|
||||
@@ -1368,7 +1368,7 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||
&node,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for node-expire-user node registration")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for node-expire-user node registration")
|
||||
|
||||
nodes[index] = &node
|
||||
}
|
||||
@@ -1390,7 +1390,7 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||
&listAll,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for nodes list in expire test")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for nodes list in expire test")
|
||||
|
||||
assert.Len(t, listAll, 5)
|
||||
|
||||
@@ -1429,7 +1429,7 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||
&listAllAfterExpiry,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for nodes list after expiry")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for nodes list after expiry")
|
||||
|
||||
assert.Len(t, listAllAfterExpiry, 5)
|
||||
|
||||
@@ -1506,7 +1506,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||
&node,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for node-rename-command node registration")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for node-rename-command node registration")
|
||||
|
||||
nodes[index] = &node
|
||||
}
|
||||
@@ -1528,7 +1528,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||
&listAll,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for nodes list in rename test")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for nodes list in rename test")
|
||||
|
||||
assert.Len(t, listAll, 5)
|
||||
|
||||
@@ -1569,7 +1569,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||
&listAllAfterRename,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for nodes list after rename")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for nodes list after rename")
|
||||
|
||||
assert.Len(t, listAllAfterRename, 5)
|
||||
|
||||
@@ -1607,7 +1607,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||
&listAllAfterRenameAttempt,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for nodes list after failed rename attempt")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for nodes list after failed rename attempt")
|
||||
|
||||
assert.Len(t, listAllAfterRenameAttempt, 5)
|
||||
|
||||
@@ -1696,7 +1696,7 @@ func TestPolicyCommand(t *testing.T) {
|
||||
&output,
|
||||
)
|
||||
assert.NoError(c, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond, "Waiting for policy get command")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll, "Waiting for policy get command")
|
||||
|
||||
assert.Len(t, output.TagOwners, 1)
|
||||
assert.Len(t, output.ACLs, 1)
|
||||
|
||||
@@ -67,7 +67,7 @@ func TestResolveMagicDNS(t *testing.T) {
|
||||
for _, ip := range ips {
|
||||
assert.Contains(ct, result, ip.String(), "IP %s should be found in DNS resolution result from %s to %s", ip.String(), client.Hostname(), peer.Hostname())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second)
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ func derpServerScenario(
|
||||
assert.NotContains(ct, health, "could not connect to the 'Headscale Embedded DERP' relay server.",
|
||||
"Client %s should be connected to Headscale Embedded DERP", client.Hostname())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second)
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second)
|
||||
}
|
||||
|
||||
success := pingDerpAllHelper(t, allClients, allHostnames)
|
||||
@@ -174,7 +174,7 @@ func derpServerScenario(
|
||||
assert.NotContains(ct, health, "could not connect to the 'Headscale Embedded DERP' relay server.",
|
||||
"Client %s should be connected to Headscale Embedded DERP after first run", client.Hostname())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second)
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second)
|
||||
}
|
||||
|
||||
t.Logf("Run 1: %d successful pings out of %d", success, len(allClients)*len(allHostnames))
|
||||
@@ -200,7 +200,7 @@ func derpServerScenario(
|
||||
assert.NotContains(ct, health, "could not connect to the 'Headscale Embedded DERP' relay server.",
|
||||
"Client %s should be connected to Headscale Embedded DERP after second run", client.Hostname())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 2*time.Second)
|
||||
}, integrationutil.StatusReadyTimeout, 2*time.Second)
|
||||
}
|
||||
|
||||
t.Logf("Run2: %d successful pings out of %d", success, len(allClients)*len(allHostnames))
|
||||
|
||||
40
integration/integrationutil/timeouts.go
Normal file
40
integration/integrationutil/timeouts.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package integrationutil
|
||||
|
||||
import "time"
|
||||
|
||||
// CI-scaled convergence budgets. ScaledTimeout doubles each on CI.
|
||||
var (
|
||||
// HAConvergeTimeout: routes / ACL / policy propagation to reach
|
||||
// every node and show up in status, traceroute, or curl.
|
||||
HAConvergeTimeout = ScaledTimeout(60 * time.Second)
|
||||
|
||||
// HASlowConvergeTimeout: multi-step failover sequences that need
|
||||
// at least one HA prober cycle plus a data-plane settle.
|
||||
HASlowConvergeTimeout = ScaledTimeout(120 * time.Second)
|
||||
|
||||
// PolicyPropagationTimeout: post-SetPolicy filter rules and peer
|
||||
// reachability to reflect the change. Sized for wgengine's
|
||||
// rule-reload lag on contended CI runners (~2 min observed).
|
||||
PolicyPropagationTimeout = ScaledTimeout(180 * time.Second)
|
||||
|
||||
// AuthFlowTimeout: OIDC / web-auth / preauth-key flows to reach
|
||||
// Running.
|
||||
AuthFlowTimeout = ScaledTimeout(30 * time.Second)
|
||||
|
||||
// StatusReadyTimeout: post-event read to reflect the event
|
||||
// (created node visible in list, set tags visible on node).
|
||||
StatusReadyTimeout = ScaledTimeout(30 * time.Second)
|
||||
)
|
||||
|
||||
// Polling intervals for EventuallyWithT.
|
||||
const (
|
||||
// FastPoll: in-process reads (HA state, route table snapshots).
|
||||
FastPoll = 200 * time.Millisecond
|
||||
|
||||
// SlowPoll: cross-container reads (tailscale status, curl,
|
||||
// headscale API) where each tick pays a docker exec round-trip.
|
||||
SlowPoll = 500 * time.Millisecond
|
||||
|
||||
// PingPoll: gap between full ping-matrix sweeps.
|
||||
PingPoll = 2 * time.Second
|
||||
)
|
||||
@@ -471,7 +471,7 @@ func doSSHWithRetryAsUser(
|
||||
|
||||
// For all other errors, assert no error to trigger retry
|
||||
assert.NoError(ct, err)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 200*time.Millisecond)
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.FastPoll)
|
||||
} else {
|
||||
// For failure cases, just execute once
|
||||
result, stderr, err = client.Execute(command)
|
||||
@@ -701,7 +701,7 @@ func findSSHCheckAuthID(t *testing.T, headscale ControlServer) string {
|
||||
}
|
||||
|
||||
assert.NotEmpty(c, authID, "auth-id not found in headscale logs")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "waiting for SSH check auth-id in headscale logs")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "waiting for SSH check auth-id in headscale logs")
|
||||
|
||||
return authID
|
||||
}
|
||||
@@ -810,7 +810,7 @@ func findNewSSHCheckAuthID(
|
||||
}
|
||||
|
||||
assert.NotEmpty(c, authID, "new auth-id not found in headscale logs")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "waiting for new SSH check auth-id")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "waiting for new SSH check auth-id")
|
||||
|
||||
return authID
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ func TestTagsAuthKeyWithTagRequestDifferentTag(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
t.Logf("Node registered with tags: %v (expected rejection)", nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "checking node state")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "checking node state")
|
||||
|
||||
t.Fail()
|
||||
}
|
||||
@@ -252,7 +252,7 @@ func TestTagsAuthKeyWithTagNoAdvertiseFlag(t *testing.T) {
|
||||
t.Logf("Node registered with tags: %v", node.GetTags())
|
||||
assertNodeHasTagsWithCollect(c, node, []string{"tag:valid-owned"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "verifying node inherited tags from auth key")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "verifying node inherited tags from auth key")
|
||||
|
||||
t.Logf("Test 2.2 completed - node inherited tags from auth key")
|
||||
}
|
||||
@@ -320,7 +320,7 @@ func TestTagsAuthKeyWithTagCannotAddViaCLI(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for initial registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for initial registration")
|
||||
|
||||
t.Logf("Node registered with tag:valid-owned, now attempting to add tag:second via CLI")
|
||||
|
||||
@@ -353,7 +353,7 @@ func TestTagsAuthKeyWithTagCannotAddViaCLI(t *testing.T) {
|
||||
assert.Fail(c, "Tags should not have changed")
|
||||
}
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "verifying tags unchanged")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "verifying tags unchanged")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,7 +416,7 @@ func TestTagsAuthKeyWithTagCannotChangeViaCLI(t *testing.T) {
|
||||
nodes, err := headscale.ListNodes()
|
||||
assert.NoError(c, err)
|
||||
assert.Len(c, nodes, 1)
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for initial registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for initial registration")
|
||||
|
||||
t.Logf("Node registered, now attempting to change to different tag via CLI")
|
||||
|
||||
@@ -448,7 +448,7 @@ func TestTagsAuthKeyWithTagCannotChangeViaCLI(t *testing.T) {
|
||||
assert.Fail(c, "Tags should not have changed")
|
||||
}
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "verifying tags unchanged")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "verifying tags unchanged")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,7 +519,7 @@ func TestTagsAuthKeyWithTagAdminOverrideReauthPreserves(t *testing.T) {
|
||||
nodeID = nodes[0].GetId()
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for initial registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for initial registration")
|
||||
|
||||
t.Logf("Step 1 complete: Node %d registered with tag:valid-owned", nodeID)
|
||||
|
||||
@@ -536,12 +536,12 @@ func TestTagsAuthKeyWithTagAdminOverrideReauthPreserves(t *testing.T) {
|
||||
t.Logf("After admin assignment, server tags are: %v", nodes[0].GetTags())
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:second"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "verifying admin tag assignment on server")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "verifying admin tag assignment on server")
|
||||
|
||||
// Verify admin assignment propagated to node's self view (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:second"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "verifying admin tag assignment propagated to node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "verifying admin tag assignment propagated to node self")
|
||||
|
||||
t.Logf("Step 2 complete: Admin assigned tag:second (verified on both server and node self)")
|
||||
|
||||
@@ -569,12 +569,12 @@ func TestTagsAuthKeyWithTagAdminOverrideReauthPreserves(t *testing.T) {
|
||||
// Expected: admin-assigned tags are preserved through reauth
|
||||
assertNodeHasTagsWithCollect(c, node, []string{"tag:second"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "admin tags should be preserved after reauth on server")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "admin tags should be preserved after reauth on server")
|
||||
|
||||
// Verify admin tags are preserved in node's self view after reauth (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:second"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "admin tags should be preserved after reauth in node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "admin tags should be preserved after reauth in node self")
|
||||
|
||||
t.Logf("Test 2.5 PASS: Admin tags preserved through reauth (admin decisions are authoritative)")
|
||||
}
|
||||
@@ -645,7 +645,7 @@ func TestTagsAuthKeyWithTagCLICannotModifyAdminTags(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
nodeID = nodes[0].GetId()
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for initial registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for initial registration")
|
||||
|
||||
// Step 2: Admin assigns multiple tags via headscale CLI
|
||||
err = headscale.SetNodeTags(nodeID, []string{"tag:valid-owned", "tag:second"})
|
||||
@@ -659,12 +659,12 @@ func TestTagsAuthKeyWithTagCLICannotModifyAdminTags(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned", "tag:second"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "verifying admin tag assignment on server")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "verifying admin tag assignment on server")
|
||||
|
||||
// Verify admin assignment propagated to node's self view (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:valid-owned", "tag:second"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "verifying admin tag assignment propagated to node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "verifying admin tag assignment propagated to node self")
|
||||
|
||||
t.Logf("Admin assigned both tags, now attempting to reduce via CLI")
|
||||
|
||||
@@ -691,12 +691,12 @@ func TestTagsAuthKeyWithTagCLICannotModifyAdminTags(t *testing.T) {
|
||||
// Expected: tags should remain unchanged (admin wins)
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned", "tag:second"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "admin tags should be preserved after CLI attempt on server")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "admin tags should be preserved after CLI attempt on server")
|
||||
|
||||
// Verify admin tags are preserved in node's self view (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:valid-owned", "tag:second"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "admin tags should be preserved after CLI attempt in node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "admin tags should be preserved after CLI attempt in node self")
|
||||
|
||||
t.Logf("Test 2.6 PASS: Admin tags preserved - CLI cannot modify admin-assigned tags")
|
||||
}
|
||||
@@ -770,7 +770,7 @@ func TestTagsAuthKeyWithoutTagCannotRequestTags(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
t.Logf("Node registered with tags: %v (expected rejection)", nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "checking node state")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "checking node state")
|
||||
|
||||
t.Fail()
|
||||
}
|
||||
@@ -837,7 +837,7 @@ func TestTagsAuthKeyWithoutTagRegisterNoTags(t *testing.T) {
|
||||
t.Logf("Node registered with tags: %v", nodes[0].GetTags())
|
||||
assertNodeHasNoTagsWithCollect(c, nodes[0])
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "verifying node has no tags")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "verifying node has no tags")
|
||||
|
||||
t.Logf("Test 3.2 completed - node registered without tags")
|
||||
}
|
||||
@@ -905,7 +905,7 @@ func TestTagsAuthKeyWithoutTagCannotAddViaCLI(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
assertNodeHasNoTagsWithCollect(c, nodes[0])
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for initial registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for initial registration")
|
||||
|
||||
t.Logf("Node registered without tags, attempting to add via CLI")
|
||||
|
||||
@@ -936,7 +936,7 @@ func TestTagsAuthKeyWithoutTagCannotAddViaCLI(t *testing.T) {
|
||||
assert.Fail(c, "Tags should not have changed")
|
||||
}
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "verifying tags unchanged")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "verifying tags unchanged")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1007,7 +1007,7 @@ func TestTagsAuthKeyWithoutTagCLINoOpAfterAdminWithReset(t *testing.T) {
|
||||
nodeID = nodes[0].GetId()
|
||||
assertNodeHasNoTagsWithCollect(c, nodes[0])
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for initial registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for initial registration")
|
||||
|
||||
// Step 2: Admin assigns tags
|
||||
err = headscale.SetNodeTags(nodeID, []string{"tag:valid-owned"})
|
||||
@@ -1021,12 +1021,12 @@ func TestTagsAuthKeyWithoutTagCLINoOpAfterAdminWithReset(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "verifying admin tag assignment on server")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "verifying admin tag assignment on server")
|
||||
|
||||
// Verify admin assignment propagated to node's self view (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:valid-owned"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "verifying admin tag assignment propagated to node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "verifying admin tag assignment propagated to node self")
|
||||
|
||||
t.Logf("Admin assigned tag, now running CLI with --reset")
|
||||
|
||||
@@ -1050,12 +1050,12 @@ func TestTagsAuthKeyWithoutTagCLINoOpAfterAdminWithReset(t *testing.T) {
|
||||
t.Logf("After --reset, server tags are: %v", nodes[0].GetTags())
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "admin tags should be preserved after --reset on server")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "admin tags should be preserved after --reset on server")
|
||||
|
||||
// Verify admin tags are preserved in node's self view after --reset (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:valid-owned"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "admin tags should be preserved after --reset in node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "admin tags should be preserved after --reset in node self")
|
||||
|
||||
t.Logf("Test 3.4 PASS: Admin tags preserved after --reset")
|
||||
}
|
||||
@@ -1126,7 +1126,7 @@ func TestTagsAuthKeyWithoutTagCLINoOpAfterAdminWithEmptyAdvertise(t *testing.T)
|
||||
if len(nodes) == 1 {
|
||||
nodeID = nodes[0].GetId()
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for initial registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for initial registration")
|
||||
|
||||
// Step 2: Admin assigns tags
|
||||
err = headscale.SetNodeTags(nodeID, []string{"tag:valid-owned"})
|
||||
@@ -1140,12 +1140,12 @@ func TestTagsAuthKeyWithoutTagCLINoOpAfterAdminWithEmptyAdvertise(t *testing.T)
|
||||
if len(nodes) == 1 {
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "verifying admin tag assignment on server")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "verifying admin tag assignment on server")
|
||||
|
||||
// Verify admin assignment propagated to node's self view (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:valid-owned"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "verifying admin tag assignment propagated to node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "verifying admin tag assignment propagated to node self")
|
||||
|
||||
t.Logf("Admin assigned tag, now running CLI with empty --advertise-tags")
|
||||
|
||||
@@ -1169,12 +1169,12 @@ func TestTagsAuthKeyWithoutTagCLINoOpAfterAdminWithEmptyAdvertise(t *testing.T)
|
||||
t.Logf("After empty --advertise-tags, server tags are: %v", nodes[0].GetTags())
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "admin tags should be preserved after empty --advertise-tags on server")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "admin tags should be preserved after empty --advertise-tags on server")
|
||||
|
||||
// Verify admin tags are preserved in node's self view after empty --advertise-tags (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:valid-owned"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "admin tags should be preserved after empty --advertise-tags in node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "admin tags should be preserved after empty --advertise-tags in node self")
|
||||
|
||||
t.Logf("Test 3.5 PASS: Admin tags preserved after empty --advertise-tags")
|
||||
}
|
||||
@@ -1245,7 +1245,7 @@ func TestTagsAuthKeyWithoutTagCLICannotReduceAdminMultiTag(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
nodeID = nodes[0].GetId()
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for initial registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for initial registration")
|
||||
|
||||
// Step 2: Admin assigns multiple tags
|
||||
err = headscale.SetNodeTags(nodeID, []string{"tag:valid-owned", "tag:second"})
|
||||
@@ -1259,12 +1259,12 @@ func TestTagsAuthKeyWithoutTagCLICannotReduceAdminMultiTag(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned", "tag:second"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "verifying admin tag assignment on server")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "verifying admin tag assignment on server")
|
||||
|
||||
// Verify admin assignment propagated to node's self view (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:valid-owned", "tag:second"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "verifying admin tag assignment propagated to node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "verifying admin tag assignment propagated to node self")
|
||||
|
||||
t.Logf("Admin assigned both tags, now attempting to reduce via CLI")
|
||||
|
||||
@@ -1288,12 +1288,12 @@ func TestTagsAuthKeyWithoutTagCLICannotReduceAdminMultiTag(t *testing.T) {
|
||||
t.Logf("After CLI reduce attempt, server tags are: %v", nodes[0].GetTags())
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned", "tag:second"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "admin tags should be preserved after CLI reduce attempt on server")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "admin tags should be preserved after CLI reduce attempt on server")
|
||||
|
||||
// Verify admin tags are preserved in node's self view after CLI reduce attempt (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:valid-owned", "tag:second"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "admin tags should be preserved after CLI reduce attempt in node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "admin tags should be preserved after CLI reduce attempt in node self")
|
||||
|
||||
t.Logf("Test 3.6 PASS: Admin tags preserved - CLI cannot reduce admin-assigned multi-tag set")
|
||||
}
|
||||
@@ -1369,7 +1369,7 @@ func TestTagsUserLoginOwnedTagAtRegistration(t *testing.T) {
|
||||
t.Logf("Node registered with tags: %v", nodes[0].GetTags())
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "verifying node has advertised tag")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "verifying node has advertised tag")
|
||||
|
||||
t.Logf("Test 1.1 completed - web auth with owned tag succeeded")
|
||||
}
|
||||
@@ -1442,7 +1442,7 @@ func TestTagsUserLoginNonExistentTagAtRegistration(t *testing.T) {
|
||||
"Non-existent tag should not be applied to node")
|
||||
t.Logf("Test 1.2: Node registered with tags: %v (non-existent tag correctly rejected)", nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "checking node registration result")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "checking node registration result")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1510,7 +1510,7 @@ func TestTagsUserLoginUnownedTagAtRegistration(t *testing.T) {
|
||||
"Unowned tag should not be applied to node (tag:valid-unowned is owned by other-user)")
|
||||
t.Logf("Test 1.3: Node registered with tags: %v (unowned tag correctly rejected)", nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "checking node registration result")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "checking node registration result")
|
||||
}
|
||||
|
||||
// TestTagsUserLoginAddTagViaCLIReauth tests that a user can add tags via CLI reauthentication.
|
||||
@@ -1574,7 +1574,7 @@ func TestTagsUserLoginAddTagViaCLIReauth(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
t.Logf("Initial tags: %v", nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "checking initial tags")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "checking initial tags")
|
||||
|
||||
// Step 2: Try to add second tag via CLI
|
||||
t.Logf("Attempting to add second tag via CLI reauth")
|
||||
@@ -1601,7 +1601,7 @@ func TestTagsUserLoginAddTagViaCLIReauth(t *testing.T) {
|
||||
t.Logf("Test 1.4: Tags are %v (may require manual reauth completion)", nodes[0].GetTags())
|
||||
}
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "checking tags after CLI")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "checking tags after CLI")
|
||||
}
|
||||
|
||||
// TestTagsUserLoginRemoveTagViaCLIReauth tests that a user can remove tags via CLI reauthentication.
|
||||
@@ -1665,7 +1665,7 @@ func TestTagsUserLoginRemoveTagViaCLIReauth(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
t.Logf("Initial tags: %v", nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "checking initial tags")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "checking initial tags")
|
||||
|
||||
// Step 2: Try to remove second tag via CLI
|
||||
t.Logf("Attempting to remove tag via CLI reauth")
|
||||
@@ -1690,7 +1690,7 @@ func TestTagsUserLoginRemoveTagViaCLIReauth(t *testing.T) {
|
||||
t.Logf("Test 1.5 PASS: Only one tag after removal")
|
||||
}
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "checking tags after CLI")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "checking tags after CLI")
|
||||
}
|
||||
|
||||
// TestTagsUserLoginCLINoOpAfterAdminAssignment tests that CLI advertise-tags becomes
|
||||
@@ -1760,7 +1760,7 @@ func TestTagsUserLoginCLINoOpAfterAdminAssignment(t *testing.T) {
|
||||
nodeID = nodes[0].GetId()
|
||||
t.Logf("Step 1: Node %d registered with tags: %v", nodeID, nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for initial registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for initial registration")
|
||||
|
||||
// Step 2: Admin assigns different tag
|
||||
err = headscale.SetNodeTags(nodeID, []string{"tag:second"})
|
||||
@@ -1775,12 +1775,12 @@ func TestTagsUserLoginCLINoOpAfterAdminAssignment(t *testing.T) {
|
||||
t.Logf("Step 2: After admin assignment, server tags: %v", nodes[0].GetTags())
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:second"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "verifying admin assignment on server")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "verifying admin assignment on server")
|
||||
|
||||
// Verify admin assignment propagated to node's self view (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:second"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "verifying admin assignment propagated to node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "verifying admin assignment propagated to node self")
|
||||
|
||||
// Step 3: Try to change tags via CLI
|
||||
command := []string{
|
||||
@@ -1801,12 +1801,12 @@ func TestTagsUserLoginCLINoOpAfterAdminAssignment(t *testing.T) {
|
||||
t.Logf("Step 3: After CLI, server tags are: %v", nodes[0].GetTags())
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:second"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "admin tags should be preserved - CLI advertise-tags should be no-op on server")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "admin tags should be preserved - CLI advertise-tags should be no-op on server")
|
||||
|
||||
// Verify admin tags are preserved in node's self view after CLI attempt (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:second"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "admin tags should be preserved - CLI advertise-tags should be no-op in node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "admin tags should be preserved - CLI advertise-tags should be no-op in node self")
|
||||
|
||||
t.Logf("Test 1.6 PASS: Admin tags preserved (CLI was no-op)")
|
||||
}
|
||||
@@ -1876,7 +1876,7 @@ func TestTagsUserLoginCLICannotRemoveAdminTags(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
nodeID = nodes[0].GetId()
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for initial registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for initial registration")
|
||||
|
||||
// Step 2: Admin assigns both tags
|
||||
err = headscale.SetNodeTags(nodeID, []string{"tag:valid-owned", "tag:second"})
|
||||
@@ -1891,12 +1891,12 @@ func TestTagsUserLoginCLICannotRemoveAdminTags(t *testing.T) {
|
||||
t.Logf("After admin assignment, server tags: %v", nodes[0].GetTags())
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned", "tag:second"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "verifying admin assignment on server")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "verifying admin assignment on server")
|
||||
|
||||
// Verify admin assignment propagated to node's self view (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:valid-owned", "tag:second"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "verifying admin assignment propagated to node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "verifying admin assignment propagated to node self")
|
||||
|
||||
// Step 3: Try to reduce tags via CLI
|
||||
command := []string{
|
||||
@@ -1917,12 +1917,12 @@ func TestTagsUserLoginCLICannotRemoveAdminTags(t *testing.T) {
|
||||
t.Logf("Test 1.7: After CLI, server tags are: %v", nodes[0].GetTags())
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned", "tag:second"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "admin tags should be preserved - CLI cannot remove them on server")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "admin tags should be preserved - CLI cannot remove them on server")
|
||||
|
||||
// Verify admin tags are preserved in node's self view after CLI attempt (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:valid-owned", "tag:second"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "admin tags should be preserved - CLI cannot remove them in node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "admin tags should be preserved - CLI cannot remove them in node self")
|
||||
|
||||
t.Logf("Test 1.7 PASS: Admin tags preserved (CLI cannot remove)")
|
||||
}
|
||||
@@ -1995,7 +1995,7 @@ func TestTagsAuthKeyWithTagRequestNonExistentTag(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
t.Logf("Node registered with tags: %v (expected rejection)", nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "checking node state")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "checking node state")
|
||||
|
||||
t.Fail()
|
||||
}
|
||||
@@ -2065,7 +2065,7 @@ func TestTagsAuthKeyWithTagRequestUnownedTag(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
t.Logf("Node registered with tags: %v (expected rejection)", nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "checking node state")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "checking node state")
|
||||
|
||||
t.Fail()
|
||||
}
|
||||
@@ -2139,7 +2139,7 @@ func TestTagsAuthKeyWithoutTagRequestNonExistentTag(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
t.Logf("Node registered with tags: %v (expected rejection)", nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "checking node state")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "checking node state")
|
||||
|
||||
t.Fail()
|
||||
}
|
||||
@@ -2209,7 +2209,7 @@ func TestTagsAuthKeyWithoutTagRequestUnownedTag(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
t.Logf("Node registered with tags: %v (expected rejection)", nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "checking node state")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "checking node state")
|
||||
|
||||
t.Fail()
|
||||
}
|
||||
@@ -2281,7 +2281,7 @@ func TestTagsAdminAPICannotSetNonExistentTag(t *testing.T) {
|
||||
nodeID = nodes[0].GetId()
|
||||
t.Logf("Node %d registered with tags: %v", nodeID, nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for registration")
|
||||
|
||||
// Try to set a non-existent tag via admin API - should fail
|
||||
err = headscale.SetNodeTags(nodeID, []string{"tag:nonexistent"})
|
||||
@@ -2353,7 +2353,7 @@ func TestTagsAdminAPICanSetUnownedTag(t *testing.T) {
|
||||
nodeID = nodes[0].GetId()
|
||||
t.Logf("Node %d registered with tags: %v", nodeID, nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for registration")
|
||||
|
||||
// Admin sets an "unowned" tag - should SUCCEED because admin has full authority
|
||||
// (tag:valid-unowned is owned by other-user, but admin can assign it)
|
||||
@@ -2369,12 +2369,12 @@ func TestTagsAdminAPICanSetUnownedTag(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-unowned"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "verifying unowned tag was applied on server")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "verifying unowned tag was applied on server")
|
||||
|
||||
// Verify the tag was propagated to node's self view (issue #2978)
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:valid-unowned"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "verifying unowned tag propagated to node self")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "verifying unowned tag propagated to node self")
|
||||
|
||||
t.Logf("Test 4.2 PASS: Admin API correctly allowed setting unowned tag")
|
||||
}
|
||||
@@ -2441,7 +2441,7 @@ func TestTagsAdminAPICannotRemoveAllTags(t *testing.T) {
|
||||
nodeID = nodes[0].GetId()
|
||||
t.Logf("Node %d registered with tags: %v", nodeID, nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for registration")
|
||||
|
||||
// Try to remove all tags - should fail
|
||||
err = headscale.SetNodeTags(nodeID, []string{})
|
||||
@@ -2458,7 +2458,7 @@ func TestTagsAdminAPICannotRemoveAllTags(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "verifying original tags preserved")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "verifying original tags preserved")
|
||||
}
|
||||
|
||||
// assertNetmapSelfHasTagsWithCollect asserts that the client's netmap self node has expected tags.
|
||||
@@ -2563,12 +2563,12 @@ func TestTagsIssue2978ReproTagReplacement(t *testing.T) {
|
||||
nodeID = nodes[0].GetId()
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for initial registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for initial registration")
|
||||
|
||||
// Verify client initially sees tag:valid-owned
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:valid-owned"})
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "client should see initial tag")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "client should see initial tag")
|
||||
|
||||
t.Logf("Step 1: Node %d registered via web auth with --advertise-tags=tag:valid-owned, client sees it", nodeID)
|
||||
|
||||
@@ -2588,7 +2588,7 @@ func TestTagsIssue2978ReproTagReplacement(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:second"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "server should show tag:second after first call")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "server should show tag:second after first call")
|
||||
|
||||
t.Log("Step 2a: Server shows tag:second after first call")
|
||||
|
||||
@@ -2638,11 +2638,11 @@ func TestTagsIssue2978ReproTagReplacement(t *testing.T) {
|
||||
t.Log("Step 3a: Verifying client self view updates after SECOND call")
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:second"})
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "client status.Self should update to tag:second after SECOND call")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "client status.Self should update to tag:second after SECOND call")
|
||||
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNetmapSelfHasTagsWithCollect(c, client, []string{"tag:second"})
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "client netmap.SelfNode should update to tag:second after SECOND call")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "client netmap.SelfNode should update to tag:second after SECOND call")
|
||||
|
||||
t.Log("Step 3b: Client self view updated to tag:second after SECOND call")
|
||||
|
||||
@@ -2660,7 +2660,7 @@ func TestTagsIssue2978ReproTagReplacement(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-unowned"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "server should show tag:valid-unowned")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "server should show tag:valid-unowned")
|
||||
|
||||
t.Log("Step 4a: Server shows tag:valid-unowned after first call")
|
||||
|
||||
@@ -2692,11 +2692,11 @@ func TestTagsIssue2978ReproTagReplacement(t *testing.T) {
|
||||
t.Log("Step 5a: Verifying client self view updates after SECOND call")
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNodeSelfHasTagsWithCollect(c, client, []string{"tag:valid-unowned"})
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "client status.Self should update to tag:valid-unowned after SECOND call")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "client status.Self should update to tag:valid-unowned after SECOND call")
|
||||
|
||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
||||
assertNetmapSelfHasTagsWithCollect(c, client, []string{"tag:valid-unowned"})
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "client netmap.SelfNode should update to tag:valid-unowned after SECOND call")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "client netmap.SelfNode should update to tag:valid-unowned after SECOND call")
|
||||
|
||||
t.Log("Test complete - see logs for bug reproduction details")
|
||||
}
|
||||
@@ -2763,7 +2763,7 @@ func TestTagsAdminAPICannotSetInvalidFormat(t *testing.T) {
|
||||
nodeID = nodes[0].GetId()
|
||||
t.Logf("Node %d registered with tags: %v", nodeID, nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "waiting for registration")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "waiting for registration")
|
||||
|
||||
// Try to set a tag without the "tag:" prefix - should fail
|
||||
err = headscale.SetNodeTags(nodeID, []string{"invalid-no-prefix"})
|
||||
@@ -2780,7 +2780,7 @@ func TestTagsAdminAPICannotSetInvalidFormat(t *testing.T) {
|
||||
if len(nodes) == 1 {
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), 500*time.Millisecond, "verifying original tags preserved")
|
||||
}, integrationutil.ScaledTimeout(10*time.Second), integrationutil.SlowPoll, "verifying original tags preserved")
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -2871,7 +2871,7 @@ func TestTagsUserLoginReauthWithEmptyTagsRemovesAllTags(t *testing.T) {
|
||||
// Verify node has the expected tags
|
||||
assertNodeHasTagsWithCollect(c, node, []string{"tag:valid-owned", "tag:second"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "checking initial tags")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "checking initial tags")
|
||||
|
||||
// Step 2: Reauth with empty tags to remove all tags
|
||||
t.Logf("Step 2: Reauthenticating with empty tag list to untag device (%s)", tc.name)
|
||||
@@ -2947,7 +2947,7 @@ func TestTagsUserLoginReauthWithEmptyTagsRemovesAllTags(t *testing.T) {
|
||||
tc.name, tagTestUser, node.GetTags(), node.GetUser().GetName())
|
||||
}
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(60*time.Second), 1*time.Second, "verifying tags removed and ownership returned")
|
||||
}, integrationutil.HAConvergeTimeout, 1*time.Second, "verifying tags removed and ownership returned")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3020,7 +3020,7 @@ func TestTagsAuthKeyWithoutUserInheritsTags(t *testing.T) {
|
||||
t.Logf("Node registered with tags: %v", node.GetTags())
|
||||
assertNodeHasTagsWithCollect(c, node, []string{"tag:valid-owned"})
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "verifying node inherited tags from auth key")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "verifying node inherited tags from auth key")
|
||||
|
||||
t.Logf("Test 5.1 PASS: Node inherited tags from tags-only auth key")
|
||||
}
|
||||
@@ -3158,7 +3158,7 @@ func TestTagsAuthKeyConvertToUserViaCLIRegister(t *testing.T) {
|
||||
assertNodeHasTagsWithCollect(c, nodes[0], []string{"tag:valid-owned"})
|
||||
t.Logf("Initial state - Node ID: %d, Tags: %v", nodes[0].GetId(), nodes[0].GetTags())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(30*time.Second), 500*time.Millisecond, "node should be tagged initially")
|
||||
}, integrationutil.StatusReadyTimeout, integrationutil.SlowPoll, "node should be tagged initially")
|
||||
|
||||
// Step 2: Force reauth with empty tags (triggers web auth flow)
|
||||
command := []string{
|
||||
@@ -3201,5 +3201,5 @@ func TestTagsAuthKeyConvertToUserViaCLIRegister(t *testing.T) {
|
||||
t.Logf("After conversion - Node ID: %d, Tags: %v, User: %s",
|
||||
nodes[0].GetId(), nodes[0].GetTags(), nodes[0].GetUser().GetName())
|
||||
}
|
||||
}, integrationutil.ScaledTimeout(60*time.Second), 1*time.Second, "node should be user-owned after conversion via CLI register")
|
||||
}, integrationutil.HAConvergeTimeout, 1*time.Second, "node should be user-owned after conversion via CLI register")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user