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
113 lines
4.5 KiB
Go
113 lines
4.5 KiB
Go
package semantic
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/zzet/gortex/internal/graph"
|
|
)
|
|
|
|
// slowSolutionProvider models a Roslyn/MSBuild-class server: its queries only
|
|
// succeed once its solution has loaded, which the manager triggers by calling
|
|
// WaitReady before the enrichment deadline. It records whether readiness ran
|
|
// and only lands edges when it did.
|
|
type slowSolutionProvider struct {
|
|
name string
|
|
languages []string
|
|
waited bool
|
|
ready bool
|
|
}
|
|
|
|
func (s *slowSolutionProvider) Name() string { return s.name }
|
|
func (s *slowSolutionProvider) Languages() []string { return s.languages }
|
|
func (s *slowSolutionProvider) Available() bool { return true }
|
|
func (s *slowSolutionProvider) Close() error { return nil }
|
|
|
|
func (s *slowSolutionProvider) Enrich(g graph.Store, repoRoot string) (*EnrichResult, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (s *slowSolutionProvider) EnrichFile(g graph.Store, repoRoot, filePath string) (*EnrichResult, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (s *slowSolutionProvider) WaitReady(ctx context.Context, repoRoot string) error {
|
|
s.waited = true
|
|
s.ready = true
|
|
return nil
|
|
}
|
|
|
|
func (s *slowSolutionProvider) EnrichRepoContext(ctx context.Context, g graph.Store, repoPrefix, repoRoot string, deadline EnrichDeadlinePolicy) (*EnrichResult, error) {
|
|
res := &EnrichResult{Provider: s.name, Language: s.languages[0]}
|
|
// A solution-load server serves empty results until its load finishes; the
|
|
// readiness gate must run first for the pass to land any edges.
|
|
if s.ready {
|
|
res.EdgesAdded = 3
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
// TestRunEnrichOne_ReadinessGate: a ReadinessProber provider is brought to
|
|
// readiness BEFORE the enrichment deadline starts, so its pass lands edges
|
|
// instead of spending the whole budget on the cold solution load.
|
|
func TestRunEnrichOne_ReadinessGate(t *testing.T) {
|
|
mgr := NewManager(Config{Enabled: true}, zap.NewNop())
|
|
p := &slowSolutionProvider{name: "csharp-like", languages: []string{"csharp"}}
|
|
|
|
results := mgr.runEnrichOne(graph.New(), "repo", "/tmp/repo", "csharp", p, 10, RepoEnrichState{}, nil, map[string]bool{})
|
|
|
|
require.True(t, p.waited, "readiness prober must be invoked before the enrichment pass")
|
|
require.Len(t, results, 1)
|
|
assert.Equal(t, 3, results[0].EdgesAdded,
|
|
"the pass lands edges because the deadline started only after readiness")
|
|
}
|
|
|
|
// TestRunEnrichOne_FastProviderSkipsReadiness: a provider that does not
|
|
// implement ReadinessProber (a gopls-shaped server, ready after initialize)
|
|
// runs without incurring the readiness wait.
|
|
func TestRunEnrichOne_FastProviderSkipsReadiness(t *testing.T) {
|
|
mgr := NewManager(Config{Enabled: true}, zap.NewNop())
|
|
// mockProvider (from manager_test.go) does not implement ReadinessProber.
|
|
p := &mockProvider{name: "gopls-like", languages: []string{"go"}, available: true}
|
|
|
|
results := mgr.runEnrichOne(graph.New(), "repo", "/tmp/repo", "go", p, 10, RepoEnrichState{}, nil, map[string]bool{})
|
|
|
|
require.Len(t, results, 1, "a fast provider still runs; the readiness gate is simply skipped")
|
|
assert.Equal(t, "gopls-like", results[0].Provider)
|
|
}
|
|
|
|
// notReadyProvider models a ReadinessProber whose workspace never finishes
|
|
// loading: WaitReady reports ErrWorkspaceNotReady. The manager must record the
|
|
// honest not-ready state and skip the sweep instead of running it against an
|
|
// empty server and reporting a misleading "completed, 0 coverage".
|
|
type notReadyProvider struct {
|
|
slowSolutionProvider
|
|
}
|
|
|
|
func (n *notReadyProvider) WaitReady(ctx context.Context, repoRoot string) error {
|
|
n.waited = true
|
|
return ErrWorkspaceNotReady
|
|
}
|
|
|
|
// TestRunEnrichOne_NeverReadySkipsSweepWithHonestState: when readiness never
|
|
// confirms, the pass is skipped and recorded as not_ready — no result is
|
|
// produced, so a later cycle retries.
|
|
func TestRunEnrichOne_NeverReadySkipsSweepWithHonestState(t *testing.T) {
|
|
mgr := NewManager(Config{Enabled: true}, zap.NewNop())
|
|
p := ¬ReadyProvider{slowSolutionProvider{name: "csharp-like", languages: []string{"csharp"}}}
|
|
|
|
results := mgr.runEnrichOne(graph.New(), "repo", "/tmp/repo", "csharp", p, 10, RepoEnrichState{}, nil, map[string]bool{})
|
|
|
|
require.True(t, p.waited, "readiness prober must be invoked")
|
|
assert.Empty(t, results, "the sweep is skipped, so no result is produced")
|
|
|
|
statuses := mgr.EnrichmentStatuses()
|
|
require.Len(t, statuses, 1)
|
|
assert.Equal(t, EnrichStateNotReady, statuses[0].State,
|
|
"a workspace that never loads is recorded as not_ready, not completed")
|
|
}
|