Documentation
¶
Overview ¶
Package e2e provides a Go test harness for end-to-end sync testing. It ports the bash harness (scripts/e2e/harness.sh) to Go, building real td and td-sync binaries, running a server, and authenticating multiple actors.
Index ¶
- func ExtractIssueID(output string) string
- type ActionDef
- type ActionResult
- type ActionStats
- type ChaosEngine
- type ChaosReport
- type ChaosStats
- type Config
- type Harness
- func (h *Harness) ClientDir(actor string) string
- func (h *Harness) DBPath(actor string) string
- func (h *Harness) HomeDir(actor string) string
- func (h *Harness) ServerLogContents() string
- func (h *Harness) SetServerEnv(envs ...string)
- func (h *Harness) StartServer() error
- func (h *Harness) StopServer() error
- func (h *Harness) SyncAll() error
- func (h *Harness) Td(actor string, args ...string) (string, error)
- func (h *Harness) TdA(args ...string) (string, error)
- func (h *Harness) TdB(args ...string) (string, error)
- func (h *Harness) TdC(args ...string) (string, error)
- func (h *Harness) Teardown()
- type HistorySummary
- type IssueState
- type OperationHistory
- func (h *OperationHistory) Filter(fn func(OperationRecord) bool) []OperationRecord
- func (h *OperationHistory) ForActor(actor string) []OperationRecord
- func (h *OperationHistory) ForIssue(issueID string) []OperationRecord
- func (h *OperationHistory) Len() int
- func (h *OperationHistory) Record(rec OperationRecord)
- func (h *OperationHistory) Records() []OperationRecord
- func (h *OperationHistory) Summary() HistorySummary
- func (h *OperationHistory) WriteJSON(path string) error
- func (h *OperationHistory) WriteReport(w io.Writer)
- type OperationRecord
- type ReportActionStats
- type ReportResults
- type ReportSyncStats
- type ReportVerification
- type Verifier
- func (v *Verifier) AllPassed() bool
- func (v *Verifier) FailedResults() []VerifyResult
- func (v *Verifier) Results() []VerifyResult
- func (v *Verifier) Summary() string
- func (v *Verifier) VerifyActionLogConvergence(actorA, actorB string) []VerifyResult
- func (v *Verifier) VerifyCausalOrdering(actor string) []VerifyResult
- func (v *Verifier) VerifyConvergence(actorA, actorB string) []VerifyResult
- func (v *Verifier) VerifyEventCounts(actorA, actorB string) []VerifyResult
- func (v *Verifier) VerifyFieldLevelMerge(actorA, actorB string) []VerifyResult
- func (v *Verifier) VerifyIdempotency(rounds int) []VerifyResult
- func (v *Verifier) VerifyMonotonicSequence(actor string) []VerifyResult
- func (v *Verifier) VerifyReadYourWrites(engine *ChaosEngine) []VerifyResult
- type VerifyResult
- func ScenarioBurstNoSync(h *Harness, rng *rand.Rand) []VerifyResult
- func ScenarioCascadeConflict(h *Harness) []VerifyResult
- func ScenarioDependencyCycle(h *Harness) []VerifyResult
- func ScenarioMultiFieldCollision(h *Harness) []VerifyResult
- func ScenarioPartitionRecovery(h *Harness, rng *rand.Rand) []VerifyResult
- func ScenarioRapidCreateDelete(h *Harness) []VerifyResult
- func ScenarioServerRestart(h *Harness) []VerifyResult
- func ScenarioThunderingHerd(h *Harness) []VerifyResult
- func ScenarioUndoSync(h *Harness) []VerifyResult
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExtractIssueID ¶
ExtractIssueID is the exported version for test use.
Types ¶
type ActionDef ¶
type ActionDef struct {
Name string
Weight int
Exec func(engine *ChaosEngine, actor string) ActionResult
}
ActionDef defines a named action with weight and executor.
func SelectAction ¶
SelectAction picks a weighted random action definition.
type ActionResult ¶
type ActionResult struct {
Action string
Actor string
Target string // issue ID or other target
OK bool
ExpFail bool // expected failure (self-review, cycle, etc.)
Skipped bool // no suitable target found
Output string
}
ActionResult records the outcome of a single chaos action.
type ActionStats ¶
ActionStats tracks per-action-type outcomes.
type ChaosEngine ¶
type ChaosEngine struct {
Harness *Harness
Rng *rand.Rand
NumActors int
// State tracking
Issues map[string]*IssueState // id -> state
IssueOrder []string // ordered list of all created issue IDs
Boards []string
DepPairs map[string]bool // "from_to" -> true
ParentChild map[string]string // childID -> parentID
IssueFiles map[string]string // "issueID~filePath" -> role
ActiveWS map[string]string // actor -> ws name
WSTagged map[string]map[string]bool // actor -> set of tagged issue IDs
Stats ChaosStats
}
ChaosEngine drives random mutations against a Harness.
func NewChaosEngine ¶
func NewChaosEngine(h *Harness, seed int64, numActors int) *ChaosEngine
NewChaosEngine creates a ChaosEngine with deterministic seed.
func (*ChaosEngine) RunAction ¶
func (e *ChaosEngine) RunAction() ActionResult
RunAction selects a weighted random action and executes it. Returns the result and whether it was an unexpected failure.
func (*ChaosEngine) RunN ¶
func (e *ChaosEngine) RunN(n int) []ActionResult
RunN executes n random actions and returns all results.
func (*ChaosEngine) Summary ¶
func (e *ChaosEngine) Summary() string
Summary returns a human-readable stats summary.
func (*ChaosEngine) TrackCreatedIssue ¶
func (e *ChaosEngine) TrackCreatedIssue(id, status, owner string)
TrackCreatedIssue manually adds an issue to the engine's state tracking.
type ChaosReport ¶
type ChaosReport struct {
Seed int64 `json:"seed"`
Actions int `json:"actions"`
Duration int64 `json:"duration_ms"`
Actors int `json:"actors"`
Results ReportResults `json:"results"`
PerAction map[string]ReportActionStats `json:"per_action"`
Verifications []ReportVerification `json:"verifications"`
SyncStats ReportSyncStats `json:"sync_stats"`
Pass bool `json:"pass"`
}
ChaosReport is the JSON-serializable report for CI integration.
func BuildReport ¶
func BuildReport(seed int64, eng *ChaosEngine, v *Verifier, elapsed time.Duration) ChaosReport
BuildReport constructs a ChaosReport from engine and verifier state.
type ChaosStats ¶
type ChaosStats struct {
ActionCount int
SyncCount int
Skipped int
ExpectedFailures int
UnexpectedFailures int
FieldCollisions int
DeleteMutate int
BurstCount int
BurstActions int
EdgeDataUsed int
PerAction map[string]*ActionStats
}
ChaosStats aggregates counters across all actions.
type Config ¶
type Config struct {
NumActors int // 2 or 3 (alice, bob, optionally carol)
AutoSync bool // enable auto-sync on clients
Debounce string
Interval string
}
Config controls harness setup options.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns a Config with sensible defaults.
type Harness ¶
type Harness struct {
ServerURL string
ProjectID string
WorkDir string
TdBin string
SyncBin string
// contains filtered or unexported fields
}
Harness manages a td-sync server and multiple td client environments.
func Setup ¶
Setup creates a new Harness: builds binaries, starts the server, authenticates actors, creates a project, and links all actors. When t is non-nil, t.Cleanup is used for teardown.
func (*Harness) ServerLogContents ¶
ServerLogContents returns the server log file contents.
func (*Harness) SetServerEnv ¶
SetServerEnv adds environment variables for the server process. Can be called before Setup() or between StopServer()/StartServer() calls. Later values override earlier ones (appended after defaults).
func (*Harness) StartServer ¶
StartServer starts a new server process using the same data directory and port. Blocks until the server passes a health check.
func (*Harness) StopServer ¶
StopServer kills the running server process and waits for it to exit.
func (*Harness) SyncAll ¶
SyncAll syncs all actors in round-robin for convergence. Performs 3 rounds of push+pull for each actor, with rate-limit retry.
type HistorySummary ¶
type HistorySummary struct {
TotalOps int `json:"total_ops"`
ByResult map[string]int `json:"by_result"`
ByAction map[string]int `json:"by_action"`
ByActor map[string]int `json:"by_actor"`
AvgDuration time.Duration `json:"avg_duration_ns"`
MaxDuration time.Duration `json:"max_duration_ns"`
TotalDuration time.Duration `json:"total_duration_ns"`
UniqueIssues int `json:"unique_issues"`
}
HistorySummary holds aggregate stats over recorded operations.
type IssueState ¶
type IssueState struct {
ID string
Status string // open, in_progress, in_review, closed, blocked
Owner string // actor who created it
Minor bool
Deleted bool
}
IssueState tracks the engine's view of an issue.
type OperationHistory ¶
type OperationHistory struct {
// contains filtered or unexported fields
}
OperationHistory records all operations performed during a chaos run. Thread-safe for concurrent recording from multiple goroutines.
func NewOperationHistory ¶
func NewOperationHistory() *OperationHistory
NewOperationHistory creates an empty history.
func (*OperationHistory) Filter ¶
func (h *OperationHistory) Filter(fn func(OperationRecord) bool) []OperationRecord
Filter returns records matching a predicate.
func (*OperationHistory) ForActor ¶
func (h *OperationHistory) ForActor(actor string) []OperationRecord
ForActor returns records for a specific actor.
func (*OperationHistory) ForIssue ¶
func (h *OperationHistory) ForIssue(issueID string) []OperationRecord
ForIssue returns records targeting a specific issue ID.
func (*OperationHistory) Len ¶
func (h *OperationHistory) Len() int
Len returns the number of recorded operations.
func (*OperationHistory) Record ¶
func (h *OperationHistory) Record(rec OperationRecord)
Record adds an operation to the history. It assigns a monotonic sequence number and timestamps the record if Timestamp is zero.
func (*OperationHistory) Records ¶
func (h *OperationHistory) Records() []OperationRecord
Records returns a snapshot of all recorded operations.
func (*OperationHistory) Summary ¶
func (h *OperationHistory) Summary() HistorySummary
Summary returns aggregate stats over all recorded operations.
func (*OperationHistory) WriteJSON ¶
func (h *OperationHistory) WriteJSON(path string) error
WriteJSON writes the full history as JSON to the given path.
func (*OperationHistory) WriteReport ¶
func (h *OperationHistory) WriteReport(w io.Writer)
WriteReport writes a human-readable summary to w.
type OperationRecord ¶
type OperationRecord struct {
Seq int `json:"seq"`
Timestamp time.Time `json:"timestamp"`
Action string `json:"action"`
Actor string `json:"actor"`
TargetID string `json:"target_id,omitempty"`
Args []string `json:"args"`
Output string `json:"output"`
Result string `json:"result"` // "ok", "expected_fail", "unexpected_fail", "skip"
Duration time.Duration `json:"duration_ns"`
Error string `json:"error,omitempty"`
}
OperationRecord captures a single action performed during a chaos run.
type ReportActionStats ¶
type ReportActionStats struct {
OK int `json:"ok"`
ExpFail int `json:"expected_fail"`
UnexpFail int `json:"unexpected_fail"`
}
ReportActionStats tracks per-action-type outcomes.
type ReportResults ¶
type ReportResults struct {
Total int `json:"total"`
OK int `json:"ok"`
ExpFail int `json:"expected_fail"`
UnexpFail int `json:"unexpected_fail"`
Skipped int `json:"skipped"`
}
ReportResults aggregates action outcomes.
type ReportSyncStats ¶
type ReportSyncStats struct {
Count int `json:"count"`
}
ReportSyncStats tracks sync operations.
type ReportVerification ¶
type ReportVerification struct {
Name string `json:"name"`
Passed bool `json:"passed"`
Details string `json:"details,omitempty"`
}
ReportVerification records the outcome of a single verification.
type Verifier ¶
type Verifier struct {
// contains filtered or unexported fields
}
Verifier runs correctness checks against harness databases.
func NewVerifier ¶
NewVerifier creates a Verifier for the given harness.
func (*Verifier) FailedResults ¶
func (v *Verifier) FailedResults() []VerifyResult
FailedResults returns only failing results.
func (*Verifier) Results ¶
func (v *Verifier) Results() []VerifyResult
Results returns accumulated results.
func (*Verifier) VerifyActionLogConvergence ¶
func (v *Verifier) VerifyActionLogConvergence(actorA, actorB string) []VerifyResult
VerifyActionLogConvergence checks that both actors agree on canonical event order. Compares events by server_seq: for each seq present on both sides, the (entity_type, action_type, entity_id) tuple must match. Clients may have different total event counts due to built-in entity creation during init.
func (*Verifier) VerifyCausalOrdering ¶
func (v *Verifier) VerifyCausalOrdering(actor string) []VerifyResult
VerifyCausalOrdering checks that create events precede updates/transitions for same entity.
func (*Verifier) VerifyConvergence ¶
func (v *Verifier) VerifyConvergence(actorA, actorB string) []VerifyResult
VerifyConvergence compares all synced tables between two actors.
func (*Verifier) VerifyEventCounts ¶
func (v *Verifier) VerifyEventCounts(actorA, actorB string) []VerifyResult
VerifyEventCounts checks synced event counts and distributions match.
func (*Verifier) VerifyFieldLevelMerge ¶
func (v *Verifier) VerifyFieldLevelMerge(actorA, actorB string) []VerifyResult
VerifyFieldLevelMerge tests that concurrent updates to different fields both survive. This is a targeted test: creates an issue, has two actors update different fields without syncing between, then syncs and verifies both changes are preserved.
func (*Verifier) VerifyIdempotency ¶
func (v *Verifier) VerifyIdempotency(rounds int) []VerifyResult
VerifyIdempotency hashes DB content, runs N sync rounds, verifies hashes unchanged.
func (*Verifier) VerifyMonotonicSequence ¶
func (v *Verifier) VerifyMonotonicSequence(actor string) []VerifyResult
VerifyMonotonicSequence checks server_seq is strictly increasing with no duplicates. Gaps are expected (each client only has a subset of server events) and are noted but not failures.
func (*Verifier) VerifyReadYourWrites ¶
func (v *Verifier) VerifyReadYourWrites(engine *ChaosEngine) []VerifyResult
VerifyReadYourWrites checks that after sync, each actor can see issues they created.
type VerifyResult ¶
VerifyResult records the outcome of a single verification check.
func ScenarioBurstNoSync ¶
func ScenarioBurstNoSync(h *Harness, rng *rand.Rand) []VerifyResult
ScenarioBurstNoSync: actor A performs 20 sequential mutations on one issue without any sync, then syncs, and verifies actor B sees the final state.
func ScenarioCascadeConflict ¶
func ScenarioCascadeConflict(h *Harness) []VerifyResult
ScenarioCascadeConflict: parent + children in_progress, actor A moves parent to in_review (cascading children), actor B independently closes one child.
func ScenarioDependencyCycle ¶
func ScenarioDependencyCycle(h *Harness) []VerifyResult
ScenarioDependencyCycle: tests distributed cycle detection during sync. Both actors add conflicting dependencies simultaneously (A->B and B->A), then sync. The sync should detect the cycle and skip one of the deps.
func ScenarioMultiFieldCollision ¶
func ScenarioMultiFieldCollision(h *Harness) []VerifyResult
ScenarioMultiFieldCollision: both actors update different fields on the same issue concurrently. After sync, both changes should survive (field-level merge).
func ScenarioPartitionRecovery ¶
func ScenarioPartitionRecovery(h *Harness, rng *rand.Rand) []VerifyResult
ScenarioPartitionRecovery: both actors perform 50+ mutations without syncing, then sync and verify convergence.
func ScenarioRapidCreateDelete ¶
func ScenarioRapidCreateDelete(h *Harness) []VerifyResult
ScenarioRapidCreateDelete: create 10, sync, delete all, sync, restore 5, sync, delete 3, sync -- verify convergence at each stage.
func ScenarioServerRestart ¶
func ScenarioServerRestart(h *Harness) []VerifyResult
ScenarioServerRestart tests sync resilience across a server restart. 1. Create issues on both actors, sync to convergence 2. Kill the server process 3. Both actors perform local mutations (these queue locally) 4. Restart the server (new process, same data dir) 5. Sync all actors 6. Verify convergence
func ScenarioThunderingHerd ¶
func ScenarioThunderingHerd(h *Harness) []VerifyResult
ScenarioThunderingHerd: both actors make mutations, then both sync SIMULTANEOUSLY using goroutines, then verify convergence.
func ScenarioUndoSync ¶
func ScenarioUndoSync(h *Harness) []VerifyResult
ScenarioUndoSync: actor A creates issue, syncs, actor B sees it, actor A undoes, syncs, verify convergence.