mirror of
https://github.com/juanfont/headscale.git
synced 2026-07-21 10:28:56 +00:00
Replace the gRPC client with the generated HTTP client across every command: locally over the unix socket without auth (matching the previous local gRPC socket), remotely over TLS with a Bearer API key. Output rendering and integration tests move to the HTTP client types; the transport changes, the assertions do not.
72 lines
1.7 KiB
Go
72 lines
1.7 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestDialHeadscaleSocketRetriesUntilPresent proves the CLI socket dialer
|
|
// tolerates a not-yet-created socket (the server-still-starting race) by
|
|
// retrying until it appears, rather than failing immediately like a bare dial.
|
|
func TestDialHeadscaleSocketRetriesUntilPresent(t *testing.T) {
|
|
sock := filepath.Join(t.TempDir(), "headscale.sock")
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
|
defer cancel()
|
|
|
|
type result struct {
|
|
conn net.Conn
|
|
err error
|
|
}
|
|
|
|
done := make(chan result, 1)
|
|
|
|
go func() {
|
|
conn, err := dialHeadscaleSocket(ctx, sock)
|
|
done <- result{conn, err}
|
|
}()
|
|
|
|
// Listen only after the dialer has begun, so its backoff must retry the
|
|
// absent socket and connect once it exists.
|
|
var lc net.ListenConfig
|
|
|
|
ln, err := lc.Listen(ctx, "unix", sock)
|
|
require.NoError(t, err)
|
|
|
|
defer ln.Close()
|
|
|
|
go func() {
|
|
if conn, _ := ln.Accept(); conn != nil {
|
|
conn.Close()
|
|
}
|
|
}()
|
|
|
|
res := <-done
|
|
require.NoError(t, res.err)
|
|
require.NotNil(t, res.conn)
|
|
|
|
res.conn.Close()
|
|
}
|
|
|
|
// TestDialHeadscaleSocketRespectsDeadline proves the retry is bounded by the
|
|
// context: when the socket never appears, the dialer returns an error around the
|
|
// deadline instead of hanging.
|
|
func TestDialHeadscaleSocketRespectsDeadline(t *testing.T) {
|
|
sock := filepath.Join(t.TempDir(), "absent.sock")
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
|
|
defer cancel()
|
|
|
|
start := time.Now()
|
|
|
|
conn, err := dialHeadscaleSocket(ctx, sock)
|
|
require.Error(t, err)
|
|
assert.Nil(t, conn)
|
|
assert.Less(t, time.Since(start), 5*time.Second, "should stop near the deadline, not hang")
|
|
}
|