mirror of
https://github.com/juanfont/headscale.git
synced 2026-02-07 20:04:00 +01:00
230 lines
6.5 KiB
Go
230 lines
6.5 KiB
Go
package cli
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/spf13/cobra"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
func TestGenerateCommand(t *testing.T) {
|
|
// Test that the generate command exists and shows help
|
|
cmd := &cobra.Command{
|
|
Use: "headscale",
|
|
Short: "headscale - a Tailscale control server",
|
|
}
|
|
|
|
cmd.AddCommand(generateCmd)
|
|
|
|
out := new(bytes.Buffer)
|
|
cmd.SetOut(out)
|
|
cmd.SetErr(out)
|
|
cmd.SetArgs([]string{"generate", "--help"})
|
|
|
|
err := cmd.Execute()
|
|
require.NoError(t, err)
|
|
|
|
outStr := out.String()
|
|
assert.Contains(t, outStr, "Generate commands")
|
|
assert.Contains(t, outStr, "private-key")
|
|
assert.Contains(t, outStr, "Aliases:")
|
|
assert.Contains(t, outStr, "gen")
|
|
}
|
|
|
|
func TestGenerateCommandAlias(t *testing.T) {
|
|
// Test that the "gen" alias works
|
|
cmd := &cobra.Command{
|
|
Use: "headscale",
|
|
Short: "headscale - a Tailscale control server",
|
|
}
|
|
|
|
cmd.AddCommand(generateCmd)
|
|
|
|
out := new(bytes.Buffer)
|
|
cmd.SetOut(out)
|
|
cmd.SetErr(out)
|
|
cmd.SetArgs([]string{"gen", "--help"})
|
|
|
|
err := cmd.Execute()
|
|
require.NoError(t, err)
|
|
|
|
outStr := out.String()
|
|
assert.Contains(t, outStr, "Generate commands")
|
|
}
|
|
|
|
func TestGeneratePrivateKeyCommand(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
args []string
|
|
expectJSON bool
|
|
expectYAML bool
|
|
}{
|
|
{
|
|
name: "default output",
|
|
args: []string{"generate", "private-key"},
|
|
expectJSON: false,
|
|
expectYAML: false,
|
|
},
|
|
{
|
|
name: "json output",
|
|
args: []string{"generate", "private-key", "--output", "json"},
|
|
expectJSON: true,
|
|
expectYAML: false,
|
|
},
|
|
{
|
|
name: "yaml output",
|
|
args: []string{"generate", "private-key", "--output", "yaml"},
|
|
expectJSON: false,
|
|
expectYAML: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Note: This command calls SuccessOutput which exits the process
|
|
// We can't test the actual execution easily without mocking
|
|
// Instead, we test the command structure and that it exists
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "headscale",
|
|
Short: "headscale - a Tailscale control server",
|
|
}
|
|
|
|
cmd.AddCommand(generateCmd)
|
|
cmd.PersistentFlags().StringP("output", "o", "", "Output format")
|
|
|
|
// Test that the command exists and can be found
|
|
privateKeyCmd, _, err := cmd.Find([]string{"generate", "private-key"})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "private-key", privateKeyCmd.Name())
|
|
assert.Equal(t, "Generate a private key for the headscale server", privateKeyCmd.Short)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGeneratePrivateKeyHelp(t *testing.T) {
|
|
cmd := &cobra.Command{
|
|
Use: "headscale",
|
|
Short: "headscale - a Tailscale control server",
|
|
}
|
|
|
|
cmd.AddCommand(generateCmd)
|
|
|
|
out := new(bytes.Buffer)
|
|
cmd.SetOut(out)
|
|
cmd.SetErr(out)
|
|
cmd.SetArgs([]string{"generate", "private-key", "--help"})
|
|
|
|
err := cmd.Execute()
|
|
require.NoError(t, err)
|
|
|
|
outStr := out.String()
|
|
assert.Contains(t, outStr, "Generate a private key for the headscale server")
|
|
assert.Contains(t, outStr, "Usage:")
|
|
}
|
|
|
|
// Test the key generation logic in isolation (without SuccessOutput/ErrorOutput)
|
|
func TestPrivateKeyGeneration(t *testing.T) {
|
|
// We can't easily test the full command because it calls SuccessOutput which exits
|
|
// But we can test that the key generation produces valid output format
|
|
|
|
// This is testing the core logic that would be in the command
|
|
// In a real refactor, we'd extract this to a testable function
|
|
|
|
// For now, we can test that the command structure is correct
|
|
assert.NotNil(t, generatePrivateKeyCmd)
|
|
assert.Equal(t, "private-key", generatePrivateKeyCmd.Use)
|
|
assert.Equal(t, "Generate a private key for the headscale server", generatePrivateKeyCmd.Short)
|
|
assert.NotNil(t, generatePrivateKeyCmd.Run)
|
|
}
|
|
|
|
func TestGenerateCommandStructure(t *testing.T) {
|
|
// Test the command hierarchy
|
|
assert.Equal(t, "generate", generateCmd.Use)
|
|
assert.Equal(t, "Generate commands", generateCmd.Short)
|
|
assert.Contains(t, generateCmd.Aliases, "gen")
|
|
|
|
// Test that private-key is a subcommand
|
|
found := false
|
|
for _, subcmd := range generateCmd.Commands() {
|
|
if subcmd.Name() == "private-key" {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
assert.True(t, found, "private-key should be a subcommand of generate")
|
|
}
|
|
|
|
// Helper function to test output formats (would be used if we refactored the command)
|
|
func validatePrivateKeyOutput(t *testing.T, output string, format string) {
|
|
switch format {
|
|
case "json":
|
|
var result map[string]interface{}
|
|
err := json.Unmarshal([]byte(output), &result)
|
|
require.NoError(t, err, "Output should be valid JSON")
|
|
|
|
privateKey, exists := result["private_key"]
|
|
require.True(t, exists, "JSON should contain private_key field")
|
|
|
|
keyStr, ok := privateKey.(string)
|
|
require.True(t, ok, "private_key should be a string")
|
|
require.NotEmpty(t, keyStr, "private_key should not be empty")
|
|
|
|
// Basic validation that it looks like a machine key
|
|
assert.True(t, strings.HasPrefix(keyStr, "mkey:"), "Machine key should start with mkey:")
|
|
|
|
case "yaml":
|
|
var result map[string]interface{}
|
|
err := yaml.Unmarshal([]byte(output), &result)
|
|
require.NoError(t, err, "Output should be valid YAML")
|
|
|
|
privateKey, exists := result["private_key"]
|
|
require.True(t, exists, "YAML should contain private_key field")
|
|
|
|
keyStr, ok := privateKey.(string)
|
|
require.True(t, ok, "private_key should be a string")
|
|
require.NotEmpty(t, keyStr, "private_key should not be empty")
|
|
|
|
assert.True(t, strings.HasPrefix(keyStr, "mkey:"), "Machine key should start with mkey:")
|
|
|
|
default:
|
|
// Default format should just be the key itself
|
|
assert.True(t, strings.HasPrefix(output, "mkey:"), "Default output should be the machine key")
|
|
assert.NotContains(t, output, "{", "Default output should not contain JSON")
|
|
assert.NotContains(t, output, "private_key:", "Default output should not contain YAML structure")
|
|
}
|
|
}
|
|
|
|
func TestPrivateKeyOutputFormats(t *testing.T) {
|
|
// Test cases for different output formats
|
|
// These test the validation logic we would use after refactoring
|
|
|
|
tests := []struct {
|
|
format string
|
|
sample string
|
|
}{
|
|
{
|
|
format: "json",
|
|
sample: `{"private_key": "mkey:abcd1234567890abcd1234567890abcd1234567890abcd1234567890abcd1234"}`,
|
|
},
|
|
{
|
|
format: "yaml",
|
|
sample: "private_key: mkey:abcd1234567890abcd1234567890abcd1234567890abcd1234567890abcd1234\n",
|
|
},
|
|
{
|
|
format: "",
|
|
sample: "mkey:abcd1234567890abcd1234567890abcd1234567890abcd1234567890abcd1234",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run("format_"+tt.format, func(t *testing.T) {
|
|
validatePrivateKeyOutput(t, tt.sample, tt.format)
|
|
})
|
|
}
|
|
} |