hscontrol: add servertest harness for in-process control plane testing
Add a new hscontrol/servertest package that provides a test harness for exercising the full Headscale control protocol in-process, using Tailscale's controlclient.Direct as the client. The harness consists of: - TestServer: wraps a Headscale instance with an httptest.Server - TestClient: wraps controlclient.Direct with NetworkMap tracking - TestHarness: orchestrates N clients against a single server - Assertion helpers for mesh completeness, visibility, and consistency Export minimal accessor methods on Headscale (HTTPHandler, NoisePublicKey, GetState, SetServerURL, StartBatcher, StartEphemeralGC) so the servertest package can construct a working server from outside the hscontrol package. This enables fast, deterministic tests of connection lifecycle, update propagation, and network weather scenarios without Docker.
This commit is contained in:
parent
82c7efccf8
commit
0288614bdf
5 changed files with 1039 additions and 0 deletions
|
|
@ -16,6 +16,7 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v5"
|
||||
|
|
@ -1069,6 +1070,56 @@ func (h *Headscale) Change(cs ...change.Change) {
|
|||
h.mapBatcher.AddWork(cs...)
|
||||
}
|
||||
|
||||
// HTTPHandler returns an http.Handler for the Headscale control server.
|
||||
// The handler serves the Tailscale control protocol including the /key
|
||||
// endpoint and /ts2021 Noise upgrade path.
|
||||
func (h *Headscale) HTTPHandler() http.Handler {
|
||||
return h.createRouter(grpcRuntime.NewServeMux())
|
||||
}
|
||||
|
||||
// NoisePublicKey returns the server's Noise protocol public key.
|
||||
func (h *Headscale) NoisePublicKey() key.MachinePublic {
|
||||
return h.noisePrivateKey.Public()
|
||||
}
|
||||
|
||||
// GetState returns the server's state manager for programmatic access
|
||||
// to users, nodes, policies, and other server state.
|
||||
func (h *Headscale) GetState() *state.State {
|
||||
return h.state
|
||||
}
|
||||
|
||||
// SetServerURLForTest updates the server URL in the configuration.
|
||||
// This is needed for test servers where the URL is not known until
|
||||
// the HTTP test server starts.
|
||||
// It panics when called outside of tests.
|
||||
func (h *Headscale) SetServerURLForTest(tb testing.TB, url string) {
|
||||
tb.Helper()
|
||||
|
||||
h.cfg.ServerURL = url
|
||||
}
|
||||
|
||||
// StartBatcherForTest initialises and starts the map response batcher.
|
||||
// It registers a cleanup function on tb to stop the batcher.
|
||||
// It panics when called outside of tests.
|
||||
func (h *Headscale) StartBatcherForTest(tb testing.TB) {
|
||||
tb.Helper()
|
||||
|
||||
h.mapBatcher = mapper.NewBatcherAndMapper(h.cfg, h.state)
|
||||
h.mapBatcher.Start()
|
||||
tb.Cleanup(func() { h.mapBatcher.Close() })
|
||||
}
|
||||
|
||||
// StartEphemeralGCForTest starts the ephemeral node garbage collector.
|
||||
// It registers a cleanup function on tb to stop the collector.
|
||||
// It panics when called outside of tests.
|
||||
func (h *Headscale) StartEphemeralGCForTest(tb testing.TB) {
|
||||
tb.Helper()
|
||||
|
||||
go h.ephemeralGC.Start()
|
||||
|
||||
tb.Cleanup(func() { h.ephemeralGC.Close() })
|
||||
}
|
||||
|
||||
// Provide some middleware that can inspect the ACME/autocert https calls
|
||||
// and log when things are failing.
|
||||
type acmeLogger struct {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue