headscale/integration/debug_cli_test.go
Kristoffer Dalby 8253d588c6 derp
2025-07-15 14:51:23 +00:00

424 lines
11 KiB
Go

package integration
import (
"encoding/json"
"fmt"
"testing"
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
"github.com/juanfont/headscale/integration/hsic"
"github.com/juanfont/headscale/integration/tsic"
"github.com/stretchr/testify/assert"
)
func TestDebugCommand(t *testing.T) {
IntegrationSkip(t)
spec := ScenarioSpec{
Users: []string{"debug-user"},
}
scenario, err := NewScenario(spec)
assertNoErr(t, err)
defer scenario.ShutdownAssertNoPanics(t)
err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("clidebug"))
assertNoErr(t, err)
headscale, err := scenario.Headscale()
assertNoErr(t, err)
t.Run("test_debug_help", func(t *testing.T) {
// Test debug command help
result, err := headscale.Execute(
[]string{
"headscale",
"debug",
"--help",
},
)
assertNoErr(t, err)
// Help text should contain expected information
assert.Contains(t, result, "debug", "help should mention debug command")
assert.Contains(t, result, "debugging and testing", "help should contain command description")
assert.Contains(t, result, "create-node", "help should mention create-node subcommand")
})
t.Run("test_debug_create_node_help", func(t *testing.T) {
// Test debug create-node command help
result, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--help",
},
)
assertNoErr(t, err)
// Help text should contain expected information
assert.Contains(t, result, "create-node", "help should mention create-node command")
assert.Contains(t, result, "name", "help should mention name flag")
assert.Contains(t, result, "user", "help should mention user flag")
assert.Contains(t, result, "key", "help should mention key flag")
assert.Contains(t, result, "route", "help should mention route flag")
})
}
func TestDebugCreateNodeCommand(t *testing.T) {
IntegrationSkip(t)
spec := ScenarioSpec{
Users: []string{"debug-create-user"},
}
scenario, err := NewScenario(spec)
assertNoErr(t, err)
defer scenario.ShutdownAssertNoPanics(t)
err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("clidebugcreate"))
assertNoErr(t, err)
headscale, err := scenario.Headscale()
assertNoErr(t, err)
// Create a user first
user := spec.Users[0]
_, err = headscale.Execute(
[]string{
"headscale",
"users",
"create",
user,
},
)
assertNoErr(t, err)
t.Run("test_debug_create_node_basic", func(t *testing.T) {
// Test basic debug create-node functionality
nodeName := "debug-test-node"
// Generate a mock registration key (64 hex chars with nodekey prefix)
registrationKey := "nodekey:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
result, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name", nodeName,
"--user", user,
"--key", registrationKey,
},
)
assertNoErr(t, err)
// Should output node creation confirmation
assert.Contains(t, result, "Node created", "should confirm node creation")
assert.Contains(t, result, nodeName, "should mention the created node name")
})
t.Run("test_debug_create_node_with_routes", func(t *testing.T) {
// Test debug create-node with advertised routes
nodeName := "debug-route-node"
registrationKey := "nodekey:abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
result, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name", nodeName,
"--user", user,
"--key", registrationKey,
"--route", "10.0.0.0/24",
"--route", "192.168.1.0/24",
},
)
assertNoErr(t, err)
// Should output node creation confirmation
assert.Contains(t, result, "Node created", "should confirm node creation")
assert.Contains(t, result, nodeName, "should mention the created node name")
})
t.Run("test_debug_create_node_json_output", func(t *testing.T) {
// Test debug create-node with JSON output
nodeName := "debug-json-node"
registrationKey := "nodekey:fedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321"
result, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name", nodeName,
"--user", user,
"--key", registrationKey,
"--output", "json",
},
)
assertNoErr(t, err)
// Should produce valid JSON output
var node v1.Node
err = json.Unmarshal([]byte(result), &node)
assert.NoError(t, err, "debug create-node should produce valid JSON output")
assert.Equal(t, nodeName, node.GetName(), "created node should have correct name")
})
}
func TestDebugCreateNodeCommandValidation(t *testing.T) {
IntegrationSkip(t)
spec := ScenarioSpec{
Users: []string{"debug-validation-user"},
}
scenario, err := NewScenario(spec)
assertNoErr(t, err)
defer scenario.ShutdownAssertNoPanics(t)
err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("clidebugvalidation"))
assertNoErr(t, err)
headscale, err := scenario.Headscale()
assertNoErr(t, err)
// Create a user first
user := spec.Users[0]
_, err = headscale.Execute(
[]string{
"headscale",
"users",
"create",
user,
},
)
assertNoErr(t, err)
t.Run("test_debug_create_node_missing_name", func(t *testing.T) {
// Test debug create-node with missing name flag
registrationKey := "nodekey:1111111111111111111111111111111111111111111111111111111111111111"
_, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--user", user,
"--key", registrationKey,
},
)
// Should fail for missing required name flag
assert.Error(t, err, "should fail for missing name flag")
})
t.Run("test_debug_create_node_missing_user", func(t *testing.T) {
// Test debug create-node with missing user flag
registrationKey := "nodekey:2222222222222222222222222222222222222222222222222222222222222222"
_, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name", "test-node",
"--key", registrationKey,
},
)
// Should fail for missing required user flag
assert.Error(t, err, "should fail for missing user flag")
})
t.Run("test_debug_create_node_missing_key", func(t *testing.T) {
// Test debug create-node with missing key flag
_, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name", "test-node",
"--user", user,
},
)
// Should fail for missing required key flag
assert.Error(t, err, "should fail for missing key flag")
})
t.Run("test_debug_create_node_invalid_key", func(t *testing.T) {
// Test debug create-node with invalid registration key format
_, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name", "test-node",
"--user", user,
"--key", "invalid-key-format",
},
)
// Should fail for invalid key format
assert.Error(t, err, "should fail for invalid key format")
})
t.Run("test_debug_create_node_nonexistent_user", func(t *testing.T) {
// Test debug create-node with non-existent user
registrationKey := "nodekey:3333333333333333333333333333333333333333333333333333333333333333"
_, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name", "test-node",
"--user", "nonexistent-user",
"--key", registrationKey,
},
)
// Should fail for non-existent user
assert.Error(t, err, "should fail for non-existent user")
})
t.Run("test_debug_create_node_duplicate_name", func(t *testing.T) {
// Test debug create-node with duplicate node name
nodeName := "duplicate-node"
registrationKey1 := "nodekey:4444444444444444444444444444444444444444444444444444444444444444"
registrationKey2 := "nodekey:5555555555555555555555555555555555555555555555555555555555555555"
// Create first node
_, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name", nodeName,
"--user", user,
"--key", registrationKey1,
},
)
assertNoErr(t, err)
// Try to create second node with same name
_, err = headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name", nodeName,
"--user", user,
"--key", registrationKey2,
},
)
// Should fail for duplicate node name
assert.Error(t, err, "should fail for duplicate node name")
})
}
func TestDebugCreateNodeCommandEdgeCases(t *testing.T) {
IntegrationSkip(t)
spec := ScenarioSpec{
Users: []string{"debug-edge-user"},
}
scenario, err := NewScenario(spec)
assertNoErr(t, err)
defer scenario.ShutdownAssertNoPanics(t)
err = scenario.CreateHeadscaleEnv([]tsic.Option{}, hsic.WithTestName("clidebugedge"))
assertNoErr(t, err)
headscale, err := scenario.Headscale()
assertNoErr(t, err)
// Create a user first
user := spec.Users[0]
_, err = headscale.Execute(
[]string{
"headscale",
"users",
"create",
user,
},
)
assertNoErr(t, err)
t.Run("test_debug_create_node_invalid_route", func(t *testing.T) {
// Test debug create-node with invalid route format
nodeName := "invalid-route-node"
registrationKey := "nodekey:6666666666666666666666666666666666666666666666666666666666666666"
_, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name", nodeName,
"--user", user,
"--key", registrationKey,
"--route", "invalid-cidr",
},
)
// Should handle invalid route format gracefully
assert.Error(t, err, "should fail for invalid route format")
})
t.Run("test_debug_create_node_empty_route", func(t *testing.T) {
// Test debug create-node with empty route
nodeName := "empty-route-node"
registrationKey := "nodekey:7777777777777777777777777777777777777777777777777777777777777777"
result, err := headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name", nodeName,
"--user", user,
"--key", registrationKey,
"--route", "",
},
)
// Should handle empty route (either succeed or fail gracefully)
if err == nil {
assert.Contains(t, result, "Node created", "should confirm node creation if empty route is allowed")
} else {
assert.Error(t, err, "should fail gracefully for empty route")
}
})
t.Run("test_debug_create_node_very_long_name", func(t *testing.T) {
// Test debug create-node with very long node name
longName := fmt.Sprintf("very-long-node-name-%s", "x")
for i := 0; i < 10; i++ {
longName += "-very-long-segment"
}
registrationKey := "nodekey:8888888888888888888888888888888888888888888888888888888888888888"
_, _ = headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name", longName,
"--user", user,
"--key", registrationKey,
},
)
// Should handle very long names (either succeed or fail gracefully)
assert.NotPanics(t, func() {
headscale.Execute(
[]string{
"headscale",
"debug",
"create-node",
"--name", longName,
"--user", user,
"--key", registrationKey,
},
)
}, "should handle very long node names gracefully")
})
}