Documentation
¶
Overview ¶
Package testutil provides testing utilities for daemon functionality. It enables dual-mode testing where commands can be tested both with a running daemon and in direct mode (no daemon).
Index ¶
- Constants
- func AwaitUnixSocket(t *testing.T, socketPath string)
- func IsDaemonMode() bool
- func NewTestClient() *daemon.Client
- func RequireDaemon(t *testing.T)
- func RequireNoDaemon(t *testing.T)
- func RunDualMode(t *testing.T, tests []DualModeTest)
- func StartTestDaemon(t *testing.T, tmpDir string) (cleanup func())
- func TestDaemonConfig(tmpDir string) *daemon.Config
- func WaitForDaemon(t *testing.T, timeout time.Duration) error
- type DualModeTest
- type Fault
- type FaultConfig
- type MockDaemondeprecated
- func (m *MockDaemon) CallCount(msgType string) int
- func (m *MockDaemon) GetCalls() []RPCCall
- func (m *MockDaemon) ResetCalls()
- func (m *MockDaemon) Start(t *testing.T)
- func (m *MockDaemon) Stop()
- func (m *MockDaemon) WithResponse(msgType string, response any) *MockDaemon
- func (m *MockDaemon) WithStatus(status *daemon.StatusData) *MockDaemon
- func (m *MockDaemon) WithSyncError(err error) *MockDaemon
- type MockService
- func (m *MockService) Activity()
- func (m *MockService) Checkout(payload daemon.CheckoutPayload, progress *daemon.ProgressWriter) (*daemon.CheckoutResult, error)
- func (m *MockService) CodeIndex(payload daemon.CodeIndexPayload, progress *daemon.ProgressWriter) (*daemon.CodeIndexResult, error)
- func (m *MockService) CodeStatus() *daemon.CodeDBStats
- func (m *MockService) Doctor() *daemon.DoctorResponse
- func (m *MockService) Friction(payload daemon.FrictionPayload)
- func (m *MockService) GetErrors() []daemon.StoredError
- func (m *MockService) Heartbeat(callerID string, payload json.RawMessage)
- func (m *MockService) Instances() []daemon.InstanceInfo
- func (m *MockService) MarkErrors(ids []string)
- func (m *MockService) PauseMurmuring(agentID string)
- func (m *MockService) PublishMurmur(payload daemon.MurmurPayload)
- func (m *MockService) ResumeMurmuring(agentID string)
- func (m *MockService) SessionFinalize(payload daemon.SessionFinalizeIPCPayload)
- func (m *MockService) SessionWatchStart(payload daemon.SessionWatchStartPayload)
- func (m *MockService) SessionWatchStop(payload daemon.SessionWatchStopPayload)
- func (m *MockService) Sessions() []daemon.AgentSession
- func (m *MockService) Status() *daemon.StatusData
- func (m *MockService) Stop()
- func (m *MockService) Sync() error
- func (m *MockService) SyncHistory() []daemon.SyncEvent
- func (m *MockService) SyncWithProgress(progress *daemon.ProgressWriter) error
- func (m *MockService) TeamSync(progress *daemon.ProgressWriter) error
- func (m *MockService) Telemetry(payload json.RawMessage)
- func (m *MockService) TriggerGC() *daemon.TriggerGCResponse
- func (m *MockService) WhisperHistory(agentID string, before time.Time, limit int) (*daemon.WhisperHistoryResponse, error)
- func (m *MockService) Whispers(agentID string, attention whisperstore.Attention, topics []string) ([]whisperstore.WhisperEntry, error)
- type Mode
- type OxFaultConfig
- type OxFaultDaemon
- func NewCorruptDaemon(t *testing.T) *OxFaultDaemon
- func NewCrashingDaemon(t *testing.T) *OxFaultDaemon
- func NewFaultDaemon(t *testing.T, config FaultConfig) *OxFaultDaemon
- func NewFlakyDaemon(t *testing.T, dropEveryN int) *OxFaultDaemon
- func NewHealthyFaultDaemon(t *testing.T) *OxFaultDaemon
- func NewHungDaemon(t *testing.T) *OxFaultDaemon
- func NewOxCorruptDaemon(t *testing.T) *OxFaultDaemon
- func NewOxCrashingDaemon(t *testing.T) *OxFaultDaemon
- func NewOxFaultDaemon(t *testing.T, config OxFaultConfig) *OxFaultDaemon
- func NewOxFlakyDaemon(t *testing.T, dropEveryN int) *OxFaultDaemon
- func NewOxHealthyFaultDaemon(t *testing.T) *OxFaultDaemon
- func NewOxHungDaemon(t *testing.T) *OxFaultDaemon
- func NewOxSlowDaemon(t *testing.T, delay time.Duration) *OxFaultDaemon
- func NewSlowDaemon(t *testing.T, delay time.Duration) *OxFaultDaemon
- type RPCCall
- type TestEnvironment
Examples ¶
Constants ¶
const ( FaultNone = faultdaemon.FaultNone FaultHangOnAccept = faultdaemon.FaultHangOnAccept FaultHangBeforeResponse = faultdaemon.FaultHangBeforeResponse FaultSlowResponse = faultdaemon.FaultSlowResponse FaultCorruptResponse = faultdaemon.FaultCorruptResponse FaultPartialResponse = faultdaemon.FaultPartialResponse FaultCloseImmediately = faultdaemon.FaultCloseImmediately FaultCloseAfterRead = faultdaemon.FaultCloseAfterRead FaultDropConnection = faultdaemon.FaultDropConnection FaultPanicInHandler = faultdaemon.FaultPanicInHandler FaultDeadlock = faultdaemon.FaultDeadlock FaultMultipleResponses = faultdaemon.FaultMultipleResponses FaultResponseWithoutNewline = faultdaemon.FaultResponseWithoutNewline FaultChunkedResponse = faultdaemon.FaultChunkedResponse FaultSlowAccept = faultdaemon.FaultSlowAccept FaultRefuseAfterAccept = faultdaemon.FaultRefuseAfterAccept FaultVerySlowResponse = faultdaemon.FaultVerySlowResponse FaultResponseTooLarge = faultdaemon.FaultResponseTooLarge FaultInvalidJSON = faultdaemon.FaultInvalidJSON FaultEmbeddedNewlines = faultdaemon.FaultEmbeddedNewlines FaultWriteHalfThenHang = faultdaemon.FaultWriteHalfThenHang )
Fault constant aliases
Variables ¶
This section is empty.
Functions ¶
func AwaitUnixSocket ¶ added in v0.6.1
AwaitUnixSocket polls until a unix socket accepts connections. Completes immediately when the socket is ready (typically <5ms), times out with a clear message if it never becomes available.
func IsDaemonMode ¶
func IsDaemonMode() bool
IsDaemonMode returns true if we're running in daemon mode. Useful for tests that need to behave differently based on daemon availability.
func NewTestClient ¶
NewTestClient creates a daemon client with test-appropriate timeout. Uses 500ms (vs 50ms production default) for test stability under load.
func RequireDaemon ¶
RequireDaemon skips the test if no daemon is running.
func RequireNoDaemon ¶
RequireNoDaemon skips the test if a daemon is running.
func RunDualMode ¶
func RunDualMode(t *testing.T, tests []DualModeTest)
RunDualMode executes tests in both daemon and direct modes. Each test runs twice: once with a daemon and once without. Note: Tests do not run in parallel because daemon mode requires modifying environment variables, which conflicts with t.Parallel().
func StartTestDaemon ¶
StartTestDaemon starts a real daemon in a temp directory for testing. Returns a cleanup function that must be called to stop the daemon.
Usage:
cleanup := StartTestDaemon(t, tmpDir) defer cleanup() // ... run tests that interact with daemon ...
func TestDaemonConfig ¶
TestDaemonConfig returns a daemon config suitable for testing.
Types ¶
type DualModeTest ¶
type DualModeTest struct {
// Name is the test name (will have mode suffix appended).
Name string
// Test is the test function. Mode indicates whether the daemon is running.
// Test should use mode to determine how to execute the command.
Test func(t *testing.T, mode Mode)
// SkipDaemon skips daemon mode test if true.
SkipDaemon bool
// SkipDirect skips direct mode test if true.
SkipDirect bool
}
DualModeTest defines a test that should work in both daemon and direct modes. This ensures commands function correctly regardless of daemon availability.
Example ¶
ExampleDualModeTest demonstrates how to use DualModeTest.
// define tests that work in both modes
tests := []DualModeTest{
{
Name: "command_works_with_and_without_daemon",
Test: func(t *testing.T, mode Mode) {
// your command logic here
// use mode to check which mode we're in
if mode == ModeDaemon {
// daemon-specific assertions
} else {
// direct mode assertions
}
},
},
}
// run in a test function:
// RunDualMode(t, tests)
_ = tests
type FaultConfig ¶
type FaultConfig struct {
// Fault is the failure mode to inject.
Fault Fault
// SlowResponseDelay is the delay for slow response faults.
SlowResponseDelay time.Duration
// DropEveryN drops every Nth connection for drop connection fault.
DropEveryN int
// FaultOnMessageType restricts the fault to a specific message type.
// Other message types respond normally.
FaultOnMessageType string
// StatusResponse overrides the daemon's status response.
StatusResponse *daemon.StatusData
// DoctorResponse overrides the daemon's doctor response.
DoctorResponse *daemon.DoctorResponse
// CheckoutResponse overrides the daemon's checkout response.
CheckoutResponse *daemon.CheckoutResult
// SyncError is the error to return for sync requests.
SyncError error
}
FaultConfig is the backward-compatible config struct for tests. It mirrors the old API where fields were at the top level.
type MockDaemon
deprecated
type MockDaemon struct {
// Responses maps message types to their responses.
// Key is the message type (e.g., "status", "sync").
Responses map[string]any
// StatusResponse is the status to return for status requests.
StatusResponse *daemon.StatusData
// SyncError is the error to return for sync requests (nil = success).
SyncError error
// Calls records all RPC calls made to the mock.
Calls []RPCCall
// contains filtered or unexported fields
}
MockDaemon provides a mock daemon for unit tests. It records all RPC calls and returns configurable responses.
Deprecated: Use OxFaultDaemon for new tests. It provides the same functionality plus fault injection capabilities.
Example ¶
ExampleMockDaemon demonstrates how to use MockDaemon.
// in a test function:
// env := NewTestEnvironment(t)
// mock := env.StartMock()
//
// configure mock responses:
// mock.StatusResponse = &daemon.StatusData{Running: true}
// mock.SyncError = errors.New("test error")
//
// make assertions:
// client := daemon.NewClientForCurrentRepo()
// err := client.Ping()
// assert.NoError(t, err)
// assert.Equal(t, 1, mock.CallCount(daemon.MsgTypePing))
func (*MockDaemon) CallCount ¶
func (m *MockDaemon) CallCount(msgType string) int
CallCount returns the number of calls of a specific type.
func (*MockDaemon) GetCalls ¶
func (m *MockDaemon) GetCalls() []RPCCall
GetCalls returns a copy of all recorded calls.
func (*MockDaemon) ResetCalls ¶
func (m *MockDaemon) ResetCalls()
ResetCalls clears all recorded calls.
func (*MockDaemon) Start ¶
func (m *MockDaemon) Start(t *testing.T)
Start starts the mock daemon on the default socket path. Call this after setting environment variables for XDG_RUNTIME_DIR.
func (*MockDaemon) WithResponse ¶
func (m *MockDaemon) WithResponse(msgType string, response any) *MockDaemon
WithResponse adds a custom response for a message type.
func (*MockDaemon) WithStatus ¶
func (m *MockDaemon) WithStatus(status *daemon.StatusData) *MockDaemon
WithStatus configures the status response.
func (*MockDaemon) WithSyncError ¶
func (m *MockDaemon) WithSyncError(err error) *MockDaemon
WithSyncError configures sync to return an error.
type MockService ¶ added in v0.6.0
type MockService struct {
// sync operations
SyncFunc func() error
SyncWithProgressFunc func(progress *daemon.ProgressWriter) error
TeamSyncFunc func(progress *daemon.ProgressWriter) error
SyncHistoryFunc func() []daemon.SyncEvent
// status / query operations
StatusFunc func() *daemon.StatusData
GetErrorsFunc func() []daemon.StoredError
SessionsFunc func() []daemon.AgentSession
InstancesFunc func() []daemon.InstanceInfo
WhispersFunc func(agentID string, attention whisperstore.Attention, topics []string) ([]whisperstore.WhisperEntry, error)
CodeStatusFunc func() *daemon.CodeDBStats
// mutation operations
StopFunc func()
CheckoutFunc func(payload daemon.CheckoutPayload, progress *daemon.ProgressWriter) (*daemon.CheckoutResult, error)
MarkErrorsFunc func(ids []string)
TriggerGCFunc func() *daemon.TriggerGCResponse
CodeIndexFunc func(payload daemon.CodeIndexPayload, progress *daemon.ProgressWriter) (*daemon.CodeIndexResult, error)
DoctorFunc func() *daemon.DoctorResponse
SessionFinalizeFunc func(payload daemon.SessionFinalizeIPCPayload)
SessionWatchStartFunc func(payload daemon.SessionWatchStartPayload)
SessionWatchStopFunc func(payload daemon.SessionWatchStopPayload)
// fire-and-forget operations
ActivityFunc func()
HeartbeatFunc func(callerID string, payload json.RawMessage)
TelemetryFunc func(payload json.RawMessage)
FrictionFunc func(payload daemon.FrictionPayload)
PublishMurmurFunc func(payload daemon.MurmurPayload)
PauseMurmuringFunc func(agentID string)
ResumeMurmuringFunc func(agentID string)
}
MockService implements daemon.DaemonService with sensible defaults for testing. Override specific methods by setting the corresponding function fields. Unlike the socket-level MockDaemon, this operates at the Go interface level and can be passed directly to NewServerWithService or any code that accepts DaemonService.
func NewMockService ¶ added in v0.6.0
func NewMockService() *MockService
NewMockService creates a MockService with sensible defaults: healthy status, no errors, empty slices. All function fields are nil, so the default implementations are used.
func (*MockService) Activity ¶ added in v0.6.0
func (m *MockService) Activity()
func (*MockService) Checkout ¶ added in v0.6.0
func (m *MockService) Checkout(payload daemon.CheckoutPayload, progress *daemon.ProgressWriter) (*daemon.CheckoutResult, error)
func (*MockService) CodeIndex ¶ added in v0.6.0
func (m *MockService) CodeIndex(payload daemon.CodeIndexPayload, progress *daemon.ProgressWriter) (*daemon.CodeIndexResult, error)
func (*MockService) CodeStatus ¶ added in v0.6.0
func (m *MockService) CodeStatus() *daemon.CodeDBStats
func (*MockService) Doctor ¶ added in v0.6.0
func (m *MockService) Doctor() *daemon.DoctorResponse
func (*MockService) Friction ¶ added in v0.6.0
func (m *MockService) Friction(payload daemon.FrictionPayload)
func (*MockService) GetErrors ¶ added in v0.6.0
func (m *MockService) GetErrors() []daemon.StoredError
func (*MockService) Heartbeat ¶ added in v0.6.0
func (m *MockService) Heartbeat(callerID string, payload json.RawMessage)
func (*MockService) Instances ¶ added in v0.6.0
func (m *MockService) Instances() []daemon.InstanceInfo
func (*MockService) MarkErrors ¶ added in v0.6.0
func (m *MockService) MarkErrors(ids []string)
func (*MockService) PauseMurmuring ¶ added in v0.6.0
func (m *MockService) PauseMurmuring(agentID string)
func (*MockService) PublishMurmur ¶ added in v0.6.0
func (m *MockService) PublishMurmur(payload daemon.MurmurPayload)
func (*MockService) ResumeMurmuring ¶ added in v0.6.0
func (m *MockService) ResumeMurmuring(agentID string)
func (*MockService) SessionFinalize ¶ added in v0.6.0
func (m *MockService) SessionFinalize(payload daemon.SessionFinalizeIPCPayload)
func (*MockService) SessionWatchStart ¶ added in v0.6.1
func (m *MockService) SessionWatchStart(payload daemon.SessionWatchStartPayload)
func (*MockService) SessionWatchStop ¶ added in v0.6.1
func (m *MockService) SessionWatchStop(payload daemon.SessionWatchStopPayload)
func (*MockService) Sessions ¶ added in v0.6.0
func (m *MockService) Sessions() []daemon.AgentSession
func (*MockService) Status ¶ added in v0.6.0
func (m *MockService) Status() *daemon.StatusData
func (*MockService) Stop ¶ added in v0.6.0
func (m *MockService) Stop()
func (*MockService) Sync ¶ added in v0.6.0
func (m *MockService) Sync() error
func (*MockService) SyncHistory ¶ added in v0.6.0
func (m *MockService) SyncHistory() []daemon.SyncEvent
func (*MockService) SyncWithProgress ¶ added in v0.6.0
func (m *MockService) SyncWithProgress(progress *daemon.ProgressWriter) error
func (*MockService) TeamSync ¶ added in v0.6.0
func (m *MockService) TeamSync(progress *daemon.ProgressWriter) error
func (*MockService) Telemetry ¶ added in v0.6.0
func (m *MockService) Telemetry(payload json.RawMessage)
func (*MockService) TriggerGC ¶ added in v0.6.0
func (m *MockService) TriggerGC() *daemon.TriggerGCResponse
func (*MockService) WhisperHistory ¶ added in v0.6.0
func (m *MockService) WhisperHistory(agentID string, before time.Time, limit int) (*daemon.WhisperHistoryResponse, error)
func (*MockService) Whispers ¶ added in v0.6.0
func (m *MockService) Whispers(agentID string, attention whisperstore.Attention, topics []string) ([]whisperstore.WhisperEntry, error)
type OxFaultConfig ¶
type OxFaultConfig struct {
// Embedded generic config
faultdaemon.Config
// StatusResponse is returned for status requests.
StatusResponse *daemon.StatusData
// DoctorResponse is returned for doctor requests.
DoctorResponse *daemon.DoctorResponse
// CheckoutResponse is returned for checkout requests.
CheckoutResponse *daemon.CheckoutResult
// SyncError is the error to return for sync requests (nil = success).
SyncError error
// CustomResponses maps message types to custom response data.
// Value will be marshaled to JSON and wrapped in daemon.Response.
CustomResponses map[string]any
}
OxFaultConfig extends generic fault config with ox-specific responses.
type OxFaultDaemon ¶
type OxFaultDaemon struct {
*faultdaemon.FaultDaemon
// contains filtered or unexported fields
}
OxFaultDaemon wraps the generic FaultDaemon with ox protocol knowledge. It generates ox-specific responses (daemon.Response) for incoming messages.
func NewCorruptDaemon ¶
func NewCorruptDaemon(t *testing.T) *OxFaultDaemon
NewCorruptDaemon creates a daemon that sends garbage responses.
func NewCrashingDaemon ¶
func NewCrashingDaemon(t *testing.T) *OxFaultDaemon
NewCrashingDaemon creates a daemon that closes connections immediately.
func NewFaultDaemon ¶
func NewFaultDaemon(t *testing.T, config FaultConfig) *OxFaultDaemon
NewFaultDaemon creates an ox fault daemon with the given config.
func NewFlakyDaemon ¶
func NewFlakyDaemon(t *testing.T, dropEveryN int) *OxFaultDaemon
NewFlakyDaemon creates a daemon that drops every Nth connection.
func NewHealthyFaultDaemon ¶
func NewHealthyFaultDaemon(t *testing.T) *OxFaultDaemon
NewHealthyFaultDaemon creates a fault daemon with no faults.
func NewHungDaemon ¶
func NewHungDaemon(t *testing.T) *OxFaultDaemon
NewHungDaemon creates a daemon that accepts connections but never responds.
func NewOxCorruptDaemon ¶
func NewOxCorruptDaemon(t *testing.T) *OxFaultDaemon
NewOxCorruptDaemon creates a daemon that sends garbage responses.
func NewOxCrashingDaemon ¶
func NewOxCrashingDaemon(t *testing.T) *OxFaultDaemon
NewOxCrashingDaemon creates a daemon that closes connections immediately.
func NewOxFaultDaemon ¶
func NewOxFaultDaemon(t *testing.T, config OxFaultConfig) *OxFaultDaemon
NewOxFaultDaemon creates an ox-specific fault daemon for testing. It understands ox IPC protocol and generates appropriate responses.
func NewOxFlakyDaemon ¶
func NewOxFlakyDaemon(t *testing.T, dropEveryN int) *OxFaultDaemon
NewOxFlakyDaemon creates a daemon that drops every Nth connection.
func NewOxHealthyFaultDaemon ¶
func NewOxHealthyFaultDaemon(t *testing.T) *OxFaultDaemon
NewOxHealthyFaultDaemon creates a fault daemon with no faults (for baseline testing).
func NewOxHungDaemon ¶
func NewOxHungDaemon(t *testing.T) *OxFaultDaemon
NewOxHungDaemon creates a daemon that accepts connections but never responds.
func NewOxSlowDaemon ¶
func NewOxSlowDaemon(t *testing.T, delay time.Duration) *OxFaultDaemon
NewOxSlowDaemon creates a daemon that responds after a delay.
func NewSlowDaemon ¶
func NewSlowDaemon(t *testing.T, delay time.Duration) *OxFaultDaemon
NewSlowDaemon creates a daemon that responds after a delay.
func (*OxFaultDaemon) SetOxConfig ¶
func (d *OxFaultDaemon) SetOxConfig(config OxFaultConfig)
SetOxConfig updates the ox-specific configuration.
type RPCCall ¶
type RPCCall struct {
Type string
Payload json.RawMessage
Timestamp time.Time
}
RPCCall records an RPC call made to the mock daemon.
type TestEnvironment ¶
type TestEnvironment struct {
TmpDir string
LedgerDir string
ProjectDir string
// contains filtered or unexported fields
}
TestEnvironment sets up an isolated test environment for daemon tests. Returns a cleanup function that must be called to restore the environment.
func NewTestEnvironment ¶
func NewTestEnvironment(t *testing.T) *TestEnvironment
NewTestEnvironment creates a new isolated test environment. Sets up XDG directories to isolate tests from user's real config.
func (*TestEnvironment) StartDaemon ¶
func (e *TestEnvironment) StartDaemon() func()
StartDaemon starts a test daemon using this environment.
func (*TestEnvironment) StartFault ¶
func (e *TestEnvironment) StartFault(config OxFaultConfig) *OxFaultDaemon
StartFault starts an ox fault daemon using this environment. This provides access to all fault injection modes while understanding ox protocol.
func (*TestEnvironment) StartMock ¶
func (e *TestEnvironment) StartMock() *MockDaemon
StartMock starts a mock daemon using this environment. Deprecated: Use StartFault for new tests.