mirror of
https://github.com/juanfont/headscale.git
synced 2026-02-23 13:50:36 +01:00
377 lines
9.1 KiB
Go
377 lines
9.1 KiB
Go
package cli
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
|
"github.com/spf13/cobra"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestResolveUserByNameOrID(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
identifier string
|
|
users []*v1.User
|
|
expected *v1.User
|
|
expectError bool
|
|
}{
|
|
{
|
|
name: "resolve by ID",
|
|
identifier: "123",
|
|
users: []*v1.User{
|
|
{Id: 123, Name: "testuser", Email: "test@example.com"},
|
|
},
|
|
expected: &v1.User{Id: 123, Name: "testuser", Email: "test@example.com"},
|
|
},
|
|
{
|
|
name: "resolve by name",
|
|
identifier: "testuser",
|
|
users: []*v1.User{
|
|
{Id: 123, Name: "testuser", Email: "test@example.com"},
|
|
},
|
|
expected: &v1.User{Id: 123, Name: "testuser", Email: "test@example.com"},
|
|
},
|
|
{
|
|
name: "resolve by email",
|
|
identifier: "test@example.com",
|
|
users: []*v1.User{
|
|
{Id: 123, Name: "testuser", Email: "test@example.com"},
|
|
},
|
|
expected: &v1.User{Id: 123, Name: "testuser", Email: "test@example.com"},
|
|
},
|
|
{
|
|
name: "not found",
|
|
identifier: "nonexistent",
|
|
users: []*v1.User{},
|
|
expectError: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// We can't easily test the actual resolution without a real client
|
|
// but we can test the logic structure
|
|
assert.NotNil(t, ResolveUserByNameOrID)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestResolveNodeByIdentifier(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
identifier string
|
|
nodes []*v1.Node
|
|
expected *v1.Node
|
|
expectError bool
|
|
}{
|
|
{
|
|
name: "resolve by ID",
|
|
identifier: "123",
|
|
nodes: []*v1.Node{
|
|
{Id: 123, Name: "testnode", GivenName: "test-device", IpAddresses: []string{"192.168.1.1"}},
|
|
},
|
|
expected: &v1.Node{Id: 123, Name: "testnode", GivenName: "test-device", IpAddresses: []string{"192.168.1.1"}},
|
|
},
|
|
{
|
|
name: "resolve by hostname",
|
|
identifier: "testnode",
|
|
nodes: []*v1.Node{
|
|
{Id: 123, Name: "testnode", GivenName: "test-device", IpAddresses: []string{"192.168.1.1"}},
|
|
},
|
|
expected: &v1.Node{Id: 123, Name: "testnode", GivenName: "test-device", IpAddresses: []string{"192.168.1.1"}},
|
|
},
|
|
{
|
|
name: "not found",
|
|
identifier: "nonexistent",
|
|
nodes: []*v1.Node{},
|
|
expectError: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Test that the function exists and has the right signature
|
|
assert.NotNil(t, ResolveNodeByIdentifier)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateRequiredArgs(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
args []string
|
|
minArgs int
|
|
usage string
|
|
expectError bool
|
|
}{
|
|
{
|
|
name: "sufficient args",
|
|
args: []string{"arg1", "arg2"},
|
|
minArgs: 2,
|
|
usage: "command <arg1> <arg2>",
|
|
expectError: false,
|
|
},
|
|
{
|
|
name: "insufficient args",
|
|
args: []string{"arg1"},
|
|
minArgs: 2,
|
|
usage: "command <arg1> <arg2>",
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "no args required",
|
|
args: []string{},
|
|
minArgs: 0,
|
|
usage: "command",
|
|
expectError: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
cmd := &cobra.Command{Use: "test"}
|
|
err := ValidateRequiredArgs(cmd, tt.args, tt.minArgs, tt.usage)
|
|
|
|
if tt.expectError {
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "insufficient arguments")
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateExactArgs(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
args []string
|
|
exactArgs int
|
|
usage string
|
|
expectError bool
|
|
}{
|
|
{
|
|
name: "exact args",
|
|
args: []string{"arg1", "arg2"},
|
|
exactArgs: 2,
|
|
usage: "command <arg1> <arg2>",
|
|
expectError: false,
|
|
},
|
|
{
|
|
name: "too few args",
|
|
args: []string{"arg1"},
|
|
exactArgs: 2,
|
|
usage: "command <arg1> <arg2>",
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "too many args",
|
|
args: []string{"arg1", "arg2", "arg3"},
|
|
exactArgs: 2,
|
|
usage: "command <arg1> <arg2>",
|
|
expectError: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
cmd := &cobra.Command{Use: "test"}
|
|
err := ValidateExactArgs(cmd, tt.args, tt.exactArgs, tt.usage)
|
|
|
|
if tt.expectError {
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "expected")
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestProcessMultipleResources(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
items []string
|
|
processor func(string) error
|
|
continueOnError bool
|
|
expectedErrors int
|
|
}{
|
|
{
|
|
name: "all success",
|
|
items: []string{"item1", "item2", "item3"},
|
|
processor: func(item string) error {
|
|
return nil
|
|
},
|
|
continueOnError: true,
|
|
expectedErrors: 0,
|
|
},
|
|
{
|
|
name: "one error, continue",
|
|
items: []string{"item1", "error", "item3"},
|
|
processor: func(item string) error {
|
|
if item == "error" {
|
|
return errors.New("test error")
|
|
}
|
|
return nil
|
|
},
|
|
continueOnError: true,
|
|
expectedErrors: 1,
|
|
},
|
|
{
|
|
name: "one error, stop",
|
|
items: []string{"item1", "error", "item3"},
|
|
processor: func(item string) error {
|
|
if item == "error" {
|
|
return errors.New("test error")
|
|
}
|
|
return nil
|
|
},
|
|
continueOnError: false,
|
|
expectedErrors: 1,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
errors := ProcessMultipleResources(tt.items, tt.processor, tt.continueOnError)
|
|
assert.Len(t, errors, tt.expectedErrors)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIsValidationError(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
err error
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "insufficient arguments error",
|
|
err: errors.New("insufficient arguments provided"),
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "required flag error",
|
|
err: errors.New("required flag not set"),
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "not found error",
|
|
err: errors.New("not found matching identifier"),
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "ambiguous error",
|
|
err: errors.New("ambiguous identifier"),
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "network error",
|
|
err: errors.New("connection refused"),
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "random error",
|
|
err: errors.New("some other error"),
|
|
expected: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := IsValidationError(tt.err)
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestWrapCommandError(t *testing.T) {
|
|
cmd := &cobra.Command{Use: "test"}
|
|
originalErr := errors.New("original error")
|
|
action := "create user"
|
|
|
|
wrappedErr := WrapCommandError(cmd, originalErr, action)
|
|
|
|
assert.Error(t, wrappedErr)
|
|
assert.Contains(t, wrappedErr.Error(), "failed to create user")
|
|
assert.Contains(t, wrappedErr.Error(), "original error")
|
|
}
|
|
|
|
func TestCommandPatternHelpers(t *testing.T) {
|
|
// Test that the helper functions exist and return valid function types
|
|
|
|
// Mock functions for testing
|
|
listFunc := func(client *ClientWrapper, cmd *cobra.Command) ([]interface{}, error) {
|
|
return []interface{}{}, nil
|
|
}
|
|
|
|
tableSetup := func(tr *TableRenderer) {
|
|
// Mock table setup
|
|
}
|
|
|
|
createFunc := func(client *ClientWrapper, cmd *cobra.Command, args []string) (interface{}, error) {
|
|
return map[string]string{"result": "created"}, nil
|
|
}
|
|
|
|
getFunc := func(client *ClientWrapper, cmd *cobra.Command) (interface{}, error) {
|
|
return map[string]string{"result": "found"}, nil
|
|
}
|
|
|
|
deleteFunc := func(client *ClientWrapper, cmd *cobra.Command) (interface{}, error) {
|
|
return map[string]string{"result": "deleted"}, nil
|
|
}
|
|
|
|
updateFunc := func(client *ClientWrapper, cmd *cobra.Command, args []string) (interface{}, error) {
|
|
return map[string]string{"result": "updated"}, nil
|
|
}
|
|
|
|
// Test helper function creation
|
|
listCmdFunc := StandardListCommand(listFunc, tableSetup)
|
|
assert.NotNil(t, listCmdFunc)
|
|
|
|
createCmdFunc := StandardCreateCommand(createFunc, "Created successfully")
|
|
assert.NotNil(t, createCmdFunc)
|
|
|
|
deleteCmdFunc := StandardDeleteCommand(getFunc, deleteFunc, "resource")
|
|
assert.NotNil(t, deleteCmdFunc)
|
|
|
|
updateCmdFunc := StandardUpdateCommand(updateFunc, "Updated successfully")
|
|
assert.NotNil(t, updateCmdFunc)
|
|
}
|
|
|
|
func TestExecuteListCommand(t *testing.T) {
|
|
// Test that ExecuteListCommand function exists
|
|
assert.NotNil(t, ExecuteListCommand)
|
|
}
|
|
|
|
func TestExecuteCreateCommand(t *testing.T) {
|
|
// Test that ExecuteCreateCommand function exists
|
|
assert.NotNil(t, ExecuteCreateCommand)
|
|
}
|
|
|
|
func TestExecuteGetCommand(t *testing.T) {
|
|
// Test that ExecuteGetCommand function exists
|
|
assert.NotNil(t, ExecuteGetCommand)
|
|
}
|
|
|
|
func TestExecuteUpdateCommand(t *testing.T) {
|
|
// Test that ExecuteUpdateCommand function exists
|
|
assert.NotNil(t, ExecuteUpdateCommand)
|
|
}
|
|
|
|
func TestExecuteDeleteCommand(t *testing.T) {
|
|
// Test that ExecuteDeleteCommand function exists
|
|
assert.NotNil(t, ExecuteDeleteCommand)
|
|
}
|
|
|
|
func TestConfirmAction(t *testing.T) {
|
|
// Test that ConfirmAction function exists
|
|
assert.NotNil(t, ConfirmAction)
|
|
}
|
|
|
|
func TestConfirmDeletion(t *testing.T) {
|
|
// Test that ConfirmDeletion function exists
|
|
assert.NotNil(t, ConfirmDeletion)
|
|
} |