mirror of
https://github.com/juanfont/headscale.git
synced 2025-07-29 12:33:44 +00:00
424 lines
11 KiB
Go
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")
|
|
})
|
|
}
|