tstest/integration: expand the tests for tailscale up

Expand the integration tests to cover a wider range of scenarios, including:

*   Before and after a successful initial login
*   Auth URLs and auth keys
*   With and without the `--force-reauth` flag
*   With and without seamless key renewal

These tests expose a race condition when using `--force-reauth` on an
already-logged in device. The command completes too quickly, preventing
the auth URL from being displayed. This issue is identified and will be
fixed in a separate commit.

Updates #17108

Signed-off-by: Alex Chan <alexc@tailscale.com>
This commit is contained in:
Alex Chan
2025-09-15 11:44:00 +01:00
committed by Alex Chan
parent 70400cb75f
commit e0a77cf41a
2 changed files with 193 additions and 45 deletions
+37 -6
View File
@@ -66,6 +66,9 @@ type Server struct {
// belong to the same user.
AllNodesSameUser bool
// DefaultNodeCapabilities overrides the capability map sent to each client.
DefaultNodeCapabilities *tailcfg.NodeCapMap
// ExplicitBaseURL or HTTPTestServer must be set.
ExplicitBaseURL string // e.g. "http://127.0.0.1:1234" with no trailing URL
HTTPTestServer *httptest.Server // if non-nil, used to get BaseURL
@@ -726,6 +729,25 @@ func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey key.
// some follow-ups? For now all are successes.
}
// The in-memory list of nodes, users, and logins is keyed by
// the node key. If the node key changes, update all the data stores
// to use the new node key.
s.mu.Lock()
if _, oldNodeKeyOk := s.nodes[req.OldNodeKey]; oldNodeKeyOk {
if _, newNodeKeyOk := s.nodes[req.NodeKey]; !newNodeKeyOk {
s.nodes[req.OldNodeKey].Key = req.NodeKey
s.nodes[req.NodeKey] = s.nodes[req.OldNodeKey]
s.users[req.NodeKey] = s.users[req.OldNodeKey]
s.logins[req.NodeKey] = s.logins[req.OldNodeKey]
delete(s.nodes, req.OldNodeKey)
delete(s.users, req.OldNodeKey)
delete(s.logins, req.OldNodeKey)
}
}
s.mu.Unlock()
nk := req.NodeKey
user, login := s.getUser(nk)
@@ -745,6 +767,19 @@ func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey key.
v4Prefix,
v6Prefix,
}
var capMap tailcfg.NodeCapMap
if s.DefaultNodeCapabilities != nil {
capMap = *s.DefaultNodeCapabilities
} else {
capMap = tailcfg.NodeCapMap{
tailcfg.CapabilityHTTPS: []tailcfg.RawMessage{},
tailcfg.NodeAttrFunnel: []tailcfg.RawMessage{},
tailcfg.CapabilityFileSharing: []tailcfg.RawMessage{},
tailcfg.CapabilityFunnelPorts + "?ports=8080,443": []tailcfg.RawMessage{},
}
}
node := &tailcfg.Node{
ID: tailcfg.NodeID(nodeID),
StableID: tailcfg.StableNodeID(fmt.Sprintf("TESTCTRL%08x", int(nodeID))),
@@ -757,12 +792,8 @@ func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey key.
Hostinfo: req.Hostinfo.View(),
Name: req.Hostinfo.Hostname,
Cap: req.Version,
Capabilities: []tailcfg.NodeCapability{
tailcfg.CapabilityHTTPS,
tailcfg.NodeAttrFunnel,
tailcfg.CapabilityFileSharing,
tailcfg.CapabilityFunnelPorts + "?ports=8080,443",
},
CapMap: capMap,
Capabilities: slices.Collect(maps.Keys(capMap)),
}
s.nodes[nk] = node
}