mirror of
https://github.com/juanfont/headscale.git
synced 2025-08-01 19:44:31 -04:00
319 lines
8.4 KiB
Go
319 lines
8.4 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/spf13/cobra"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestClientWrapper_NewClient(t *testing.T) {
|
|
// This test validates the ClientWrapper structure without requiring actual gRPC connection
|
|
// since newHeadscaleCLIWithConfig would require a running headscale server
|
|
|
|
// Test that NewClient function exists and has the right signature
|
|
// We can't actually call it without a server, but we can test the structure
|
|
wrapper := &ClientWrapper{
|
|
ctx: context.Background(),
|
|
client: nil, // Would be set by actual connection
|
|
conn: nil, // Would be set by actual connection
|
|
cancel: func() {}, // Mock cancel function
|
|
}
|
|
|
|
// Verify wrapper structure
|
|
assert.NotNil(t, wrapper.ctx)
|
|
assert.NotNil(t, wrapper.cancel)
|
|
}
|
|
|
|
func TestClientWrapper_Close(t *testing.T) {
|
|
// Test the Close method with mock values
|
|
cancelCalled := false
|
|
mockCancel := func() {
|
|
cancelCalled = true
|
|
}
|
|
|
|
wrapper := &ClientWrapper{
|
|
ctx: context.Background(),
|
|
client: nil,
|
|
conn: nil, // In real usage would be *grpc.ClientConn
|
|
cancel: mockCancel,
|
|
}
|
|
|
|
// Call Close
|
|
wrapper.Close()
|
|
|
|
// Verify cancel was called
|
|
assert.True(t, cancelCalled)
|
|
}
|
|
|
|
func TestExecuteWithClient(t *testing.T) {
|
|
// Test ExecuteWithClient function structure
|
|
// Note: We cannot actually test ExecuteWithClient as it calls newHeadscaleCLIWithConfig()
|
|
// which requires a running headscale server. Instead we test that the function exists
|
|
// and has the correct signature.
|
|
|
|
cmd := &cobra.Command{Use: "test"}
|
|
AddOutputFlag(cmd)
|
|
|
|
// Verify the function exists and has the correct signature
|
|
assert.NotNil(t, ExecuteWithClient)
|
|
|
|
// We can't actually call ExecuteWithClient without a server since it would panic
|
|
// when trying to connect to headscale. This is expected behavior.
|
|
}
|
|
|
|
func TestClientWrapper_ExecuteWithErrorHandling(t *testing.T) {
|
|
// Test the ExecuteWithErrorHandling method structure
|
|
// Note: We can't actually test ExecuteWithErrorHandling without a real gRPC client
|
|
// since it expects a v1.HeadscaleServiceClient, but we can test the method exists
|
|
|
|
wrapper := &ClientWrapper{
|
|
ctx: context.Background(),
|
|
client: nil, // Mock client
|
|
conn: nil,
|
|
cancel: func() {},
|
|
}
|
|
|
|
// Verify the method exists
|
|
assert.NotNil(t, wrapper.ExecuteWithErrorHandling)
|
|
}
|
|
|
|
func TestClientWrapper_NodeOperations(t *testing.T) {
|
|
// Test that all node operation methods exist with correct signatures
|
|
cmd := &cobra.Command{Use: "test"}
|
|
AddOutputFlag(cmd)
|
|
|
|
wrapper := &ClientWrapper{
|
|
ctx: context.Background(),
|
|
client: nil,
|
|
conn: nil,
|
|
cancel: func() {},
|
|
}
|
|
|
|
// Test ListNodes method exists
|
|
assert.NotNil(t, wrapper.ListNodes)
|
|
|
|
// Test RegisterNode method exists
|
|
assert.NotNil(t, wrapper.RegisterNode)
|
|
|
|
// Test DeleteNode method exists
|
|
assert.NotNil(t, wrapper.DeleteNode)
|
|
|
|
// Test ExpireNode method exists
|
|
assert.NotNil(t, wrapper.ExpireNode)
|
|
|
|
// Test RenameNode method exists
|
|
assert.NotNil(t, wrapper.RenameNode)
|
|
|
|
// Test MoveNode method exists
|
|
assert.NotNil(t, wrapper.MoveNode)
|
|
|
|
// Test GetNode method exists
|
|
assert.NotNil(t, wrapper.GetNode)
|
|
|
|
// Test SetTags method exists
|
|
assert.NotNil(t, wrapper.SetTags)
|
|
|
|
// Test SetApprovedRoutes method exists
|
|
assert.NotNil(t, wrapper.SetApprovedRoutes)
|
|
|
|
// Test BackfillNodeIPs method exists
|
|
assert.NotNil(t, wrapper.BackfillNodeIPs)
|
|
}
|
|
|
|
func TestClientWrapper_UserOperations(t *testing.T) {
|
|
// Test that all user operation methods exist with correct signatures
|
|
wrapper := &ClientWrapper{
|
|
ctx: context.Background(),
|
|
client: nil,
|
|
conn: nil,
|
|
cancel: func() {},
|
|
}
|
|
|
|
// Test ListUsers method exists
|
|
assert.NotNil(t, wrapper.ListUsers)
|
|
|
|
// Test CreateUser method exists
|
|
assert.NotNil(t, wrapper.CreateUser)
|
|
|
|
// Test RenameUser method exists
|
|
assert.NotNil(t, wrapper.RenameUser)
|
|
|
|
// Test DeleteUser method exists
|
|
assert.NotNil(t, wrapper.DeleteUser)
|
|
}
|
|
|
|
func TestClientWrapper_ApiKeyOperations(t *testing.T) {
|
|
// Test that all API key operation methods exist with correct signatures
|
|
wrapper := &ClientWrapper{
|
|
ctx: context.Background(),
|
|
client: nil,
|
|
conn: nil,
|
|
cancel: func() {},
|
|
}
|
|
|
|
// Test ListApiKeys method exists
|
|
assert.NotNil(t, wrapper.ListApiKeys)
|
|
|
|
// Test CreateApiKey method exists
|
|
assert.NotNil(t, wrapper.CreateApiKey)
|
|
|
|
// Test ExpireApiKey method exists
|
|
assert.NotNil(t, wrapper.ExpireApiKey)
|
|
|
|
// Test DeleteApiKey method exists
|
|
assert.NotNil(t, wrapper.DeleteApiKey)
|
|
}
|
|
|
|
func TestClientWrapper_PreAuthKeyOperations(t *testing.T) {
|
|
// Test that all preauth key operation methods exist with correct signatures
|
|
wrapper := &ClientWrapper{
|
|
ctx: context.Background(),
|
|
client: nil,
|
|
conn: nil,
|
|
cancel: func() {},
|
|
}
|
|
|
|
// Test ListPreAuthKeys method exists
|
|
assert.NotNil(t, wrapper.ListPreAuthKeys)
|
|
|
|
// Test CreatePreAuthKey method exists
|
|
assert.NotNil(t, wrapper.CreatePreAuthKey)
|
|
|
|
// Test ExpirePreAuthKey method exists
|
|
assert.NotNil(t, wrapper.ExpirePreAuthKey)
|
|
}
|
|
|
|
func TestClientWrapper_PolicyOperations(t *testing.T) {
|
|
// Test that all policy operation methods exist with correct signatures
|
|
wrapper := &ClientWrapper{
|
|
ctx: context.Background(),
|
|
client: nil,
|
|
conn: nil,
|
|
cancel: func() {},
|
|
}
|
|
|
|
// Test GetPolicy method exists
|
|
assert.NotNil(t, wrapper.GetPolicy)
|
|
|
|
// Test SetPolicy method exists
|
|
assert.NotNil(t, wrapper.SetPolicy)
|
|
}
|
|
|
|
func TestClientWrapper_DebugOperations(t *testing.T) {
|
|
// Test that all debug operation methods exist with correct signatures
|
|
wrapper := &ClientWrapper{
|
|
ctx: context.Background(),
|
|
client: nil,
|
|
conn: nil,
|
|
cancel: func() {},
|
|
}
|
|
|
|
// Test DebugCreateNode method exists
|
|
assert.NotNil(t, wrapper.DebugCreateNode)
|
|
}
|
|
|
|
func TestClientWrapper_AllMethodsUseContext(t *testing.T) {
|
|
// Verify that ClientWrapper maintains context properly
|
|
testCtx := context.WithValue(context.Background(), "test", "value")
|
|
|
|
wrapper := &ClientWrapper{
|
|
ctx: testCtx,
|
|
client: nil,
|
|
conn: nil,
|
|
cancel: func() {},
|
|
}
|
|
|
|
// The context should be preserved
|
|
assert.Equal(t, testCtx, wrapper.ctx)
|
|
assert.Equal(t, "value", wrapper.ctx.Value("test"))
|
|
}
|
|
|
|
func TestErrorHandling_Integration(t *testing.T) {
|
|
// Test error handling integration with flag infrastructure
|
|
cmd := &cobra.Command{Use: "test"}
|
|
AddOutputFlag(cmd)
|
|
|
|
// Set output format
|
|
err := cmd.Flags().Set("output", "json")
|
|
require.NoError(t, err)
|
|
|
|
// Test that GetOutputFormat works correctly for error handling
|
|
outputFormat := GetOutputFormat(cmd)
|
|
assert.Equal(t, "json", outputFormat)
|
|
|
|
// Verify that the integration between client infrastructure and flag infrastructure
|
|
// works by testing that GetOutputFormat can be used for error formatting
|
|
// (actual ExecuteWithClient testing requires a running server)
|
|
assert.Equal(t, "json", GetOutputFormat(cmd))
|
|
}
|
|
|
|
func TestClientInfrastructure_ComprehensiveCoverage(t *testing.T) {
|
|
// Test that we have comprehensive coverage of all gRPC methods
|
|
// This ensures we haven't missed any gRPC operations in our wrapper
|
|
|
|
wrapper := &ClientWrapper{}
|
|
|
|
// Node operations (10 methods)
|
|
nodeOps := []interface{}{
|
|
wrapper.ListNodes,
|
|
wrapper.RegisterNode,
|
|
wrapper.DeleteNode,
|
|
wrapper.ExpireNode,
|
|
wrapper.RenameNode,
|
|
wrapper.MoveNode,
|
|
wrapper.GetNode,
|
|
wrapper.SetTags,
|
|
wrapper.SetApprovedRoutes,
|
|
wrapper.BackfillNodeIPs,
|
|
}
|
|
|
|
// User operations (4 methods)
|
|
userOps := []interface{}{
|
|
wrapper.ListUsers,
|
|
wrapper.CreateUser,
|
|
wrapper.RenameUser,
|
|
wrapper.DeleteUser,
|
|
}
|
|
|
|
// API key operations (4 methods)
|
|
apiKeyOps := []interface{}{
|
|
wrapper.ListApiKeys,
|
|
wrapper.CreateApiKey,
|
|
wrapper.ExpireApiKey,
|
|
wrapper.DeleteApiKey,
|
|
}
|
|
|
|
// PreAuth key operations (3 methods)
|
|
preAuthOps := []interface{}{
|
|
wrapper.ListPreAuthKeys,
|
|
wrapper.CreatePreAuthKey,
|
|
wrapper.ExpirePreAuthKey,
|
|
}
|
|
|
|
// Policy operations (2 methods)
|
|
policyOps := []interface{}{
|
|
wrapper.GetPolicy,
|
|
wrapper.SetPolicy,
|
|
}
|
|
|
|
// Debug operations (1 method)
|
|
debugOps := []interface{}{
|
|
wrapper.DebugCreateNode,
|
|
}
|
|
|
|
// Verify all operation arrays have methods
|
|
allOps := [][]interface{}{nodeOps, userOps, apiKeyOps, preAuthOps, policyOps, debugOps}
|
|
|
|
for i, ops := range allOps {
|
|
for j, op := range ops {
|
|
assert.NotNil(t, op, "Operation %d in category %d should not be nil", j, i)
|
|
}
|
|
}
|
|
|
|
// Total should be 24 gRPC wrapper methods
|
|
totalMethods := len(nodeOps) + len(userOps) + len(apiKeyOps) + len(preAuthOps) + len(policyOps) + len(debugOps)
|
|
assert.Equal(t, 24, totalMethods, "Should have exactly 24 gRPC operation wrapper methods")
|
|
} |