a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
100 lines
2.8 KiB
Go
100 lines
2.8 KiB
Go
package main
|
|
|
|
// PURPOSE — unit tests for `gortex track --wait`: the per-repo "index settled"
|
|
// classification and the poll loop, exercised without a running daemon by
|
|
// stubbing the trackStatusFn seam and shrinking the poll interval.
|
|
// KEYWORDS — track, wait, daemon, indexing, poll
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/zzet/gortex/internal/daemon"
|
|
)
|
|
|
|
func statusWithRepo(absPath string, nodes int, ready bool) daemon.StatusResponse {
|
|
return daemon.StatusResponse{
|
|
Ready: ready,
|
|
TrackedRepos: []daemon.TrackedRepoStatus{{Path: absPath, Nodes: nodes}},
|
|
}
|
|
}
|
|
|
|
func TestRepoNodeCount(t *testing.T) {
|
|
abs := t.TempDir()
|
|
st := statusWithRepo(abs, 1234, true)
|
|
if got := repoNodeCount(st, abs); got != 1234 {
|
|
t.Errorf("repoNodeCount = %d, want 1234", got)
|
|
}
|
|
if got := repoNodeCount(st, abs+"/other"); got != -1 {
|
|
t.Errorf("repoNodeCount(absent) = %d, want -1", got)
|
|
}
|
|
}
|
|
|
|
func TestIndexSettled(t *testing.T) {
|
|
abs := t.TempDir()
|
|
cases := []struct {
|
|
name string
|
|
st daemon.StatusResponse
|
|
prevNodes int
|
|
want bool
|
|
}{
|
|
{"absent", daemon.StatusResponse{Ready: true}, -1, false},
|
|
{"not ready", statusWithRepo(abs, 100, false), 100, false},
|
|
{"zero nodes", statusWithRepo(abs, 0, true), 0, false},
|
|
{"count still moving", statusWithRepo(abs, 200, true), 100, false},
|
|
{"stable and ready", statusWithRepo(abs, 200, true), 200, true},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if got, _ := indexSettled(tc.st, abs, tc.prevNodes); got != tc.want {
|
|
t.Errorf("indexSettled = %v, want %v", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestWaitForRepoIndexed_Settles(t *testing.T) {
|
|
abs := t.TempDir()
|
|
origFn, origInterval := trackStatusFn, trackPollInterval
|
|
t.Cleanup(func() { trackStatusFn, trackPollInterval = origFn, origInterval })
|
|
trackPollInterval = time.Millisecond
|
|
|
|
// not-present -> growing -> stable+ready: settles on the repeated reading.
|
|
seq := []daemon.StatusResponse{
|
|
{Ready: false},
|
|
statusWithRepo(abs, 100, true),
|
|
statusWithRepo(abs, 500, true),
|
|
statusWithRepo(abs, 500, true),
|
|
}
|
|
i := 0
|
|
trackStatusFn = func() (daemon.StatusResponse, error) {
|
|
st := seq[i]
|
|
if i < len(seq)-1 {
|
|
i++
|
|
}
|
|
return st, nil
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
if err := waitForRepoIndexed(&buf, abs, time.Second); err != nil {
|
|
t.Fatalf("waitForRepoIndexed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestWaitForRepoIndexed_Timeout(t *testing.T) {
|
|
abs := t.TempDir()
|
|
origFn, origInterval := trackStatusFn, trackPollInterval
|
|
t.Cleanup(func() { trackStatusFn, trackPollInterval = origFn, origInterval })
|
|
trackPollInterval = time.Millisecond
|
|
// Never settles: zero nodes and not ready forever.
|
|
trackStatusFn = func() (daemon.StatusResponse, error) {
|
|
return statusWithRepo(abs, 0, false), nil
|
|
}
|
|
|
|
var buf bytes.Buffer
|
|
if err := waitForRepoIndexed(&buf, abs, 5*time.Millisecond); err == nil {
|
|
t.Fatal("expected timeout error, got nil")
|
|
}
|
|
}
|