chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
package indexer
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/zzet/gortex/internal/config"
|
||||
"github.com/zzet/gortex/internal/contracts"
|
||||
"github.com/zzet/gortex/internal/graph"
|
||||
"github.com/zzet/gortex/internal/parser"
|
||||
)
|
||||
|
||||
// recordingBulkGraph embeds *graph.Graph (auto-satisfying graph.Store)
|
||||
// and adds the BulkLoader methods so it also satisfies
|
||||
// graph.BulkLoader. It records the order of BeginBulkLoad / AddBatch
|
||||
// / FlushBulk calls so a test can assert that the contracts commit
|
||||
// path routes through the bulk fast lane instead of per-row
|
||||
// AddNode / AddEdge writes.
|
||||
type recordingBulkGraph struct {
|
||||
*graph.Graph
|
||||
|
||||
calls []string
|
||||
addNode atomic.Int64
|
||||
addEdge atomic.Int64
|
||||
}
|
||||
|
||||
func newRecordingBulkGraph() *recordingBulkGraph {
|
||||
return &recordingBulkGraph{Graph: graph.New()}
|
||||
}
|
||||
|
||||
func (r *recordingBulkGraph) BeginBulkLoad() {
|
||||
r.calls = append(r.calls, "BeginBulkLoad")
|
||||
}
|
||||
|
||||
func (r *recordingBulkGraph) FlushBulk() error {
|
||||
r.calls = append(r.calls, "FlushBulk")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *recordingBulkGraph) AddNode(n *graph.Node) {
|
||||
r.addNode.Add(1)
|
||||
r.Graph.AddNode(n)
|
||||
}
|
||||
|
||||
func (r *recordingBulkGraph) AddEdge(e *graph.Edge) {
|
||||
r.addEdge.Add(1)
|
||||
r.Graph.AddEdge(e)
|
||||
}
|
||||
|
||||
func (r *recordingBulkGraph) AddBatch(nodes []*graph.Node, edges []*graph.Edge) {
|
||||
r.calls = append(r.calls, "AddBatch")
|
||||
r.Graph.AddBatch(nodes, edges)
|
||||
}
|
||||
|
||||
// TestCommitContracts_BatchesViaAddBatch asserts that the final
|
||||
// write phase of commitContracts emits all contract nodes and
|
||||
// edges through a single AddBatch call and does NOT engage the
|
||||
// BulkLoader COPY bracket. Contract IDs frequently coincide with
|
||||
// existing source-symbol IDs (a handler appears as both a Go
|
||||
// function and an HTTP-contract anchor), and the on-disk backend's
|
||||
// bulk load is INSERT-only on the node table — wrapping the contracts
|
||||
// pass in BeginBulkLoad/FlushBulk would crash on the first collision.
|
||||
// AddBatch's per-call MERGE path absorbs duplicates safely.
|
||||
func TestCommitContracts_BatchesViaAddBatch(t *testing.T) {
|
||||
g := newRecordingBulkGraph()
|
||||
require.Implements(t, (*graph.BulkLoader)(nil), graph.Store(g))
|
||||
|
||||
// Anchor symbol the contract's provides-edge will point from.
|
||||
g.Graph.AddNode(&graph.Node{
|
||||
ID: "pkg/foo.go::Handler.List",
|
||||
Kind: graph.KindMethod,
|
||||
Name: "List",
|
||||
FilePath: "pkg/foo.go",
|
||||
Language: "go",
|
||||
})
|
||||
|
||||
idx := New(g, parser.NewRegistry(), config.Default().Index, zap.NewNop())
|
||||
|
||||
reg := contracts.NewRegistry()
|
||||
reg.Add(contracts.Contract{
|
||||
ID: "http::GET::/v1/items",
|
||||
Type: contracts.ContractHTTP,
|
||||
Role: contracts.RoleProvider,
|
||||
SymbolID: "pkg/foo.go::Handler.List",
|
||||
FilePath: "pkg/foo.go",
|
||||
Line: 42,
|
||||
})
|
||||
reg.Add(contracts.Contract{
|
||||
ID: "http::POST::/v1/items",
|
||||
Type: contracts.ContractHTTP,
|
||||
Role: contracts.RoleConsumer,
|
||||
SymbolID: "pkg/foo.go::Handler.List",
|
||||
FilePath: "pkg/foo.go",
|
||||
Line: 58,
|
||||
})
|
||||
|
||||
idx.commitContracts(reg)
|
||||
|
||||
require.Equal(t,
|
||||
[]string{"AddBatch"},
|
||||
g.calls,
|
||||
"contracts commit must batch through a single AddBatch call",
|
||||
)
|
||||
require.Zero(t, g.addNode.Load(), "no per-row AddNode calls expected")
|
||||
require.Zero(t, g.addEdge.Load(), "no per-row AddEdge calls expected")
|
||||
|
||||
require.NotNil(t, g.GetNode("http::GET::/v1/items"))
|
||||
require.NotNil(t, g.GetNode("http::POST::/v1/items"))
|
||||
|
||||
// Provider contract emits both EdgeProvides and EdgeHandlesRoute;
|
||||
// consumer contract emits only EdgeConsumes.
|
||||
provides := g.GetOutEdges("pkg/foo.go::Handler.List")
|
||||
var nProvides, nConsumes, nHandles int
|
||||
for _, e := range provides {
|
||||
switch e.Kind {
|
||||
case graph.EdgeProvides:
|
||||
nProvides++
|
||||
case graph.EdgeConsumes:
|
||||
nConsumes++
|
||||
case graph.EdgeHandlesRoute:
|
||||
nHandles++
|
||||
}
|
||||
}
|
||||
require.Equal(t, 1, nProvides, "expected 1 EdgeProvides for the provider contract")
|
||||
require.Equal(t, 1, nConsumes, "expected 1 EdgeConsumes for the consumer contract")
|
||||
require.Equal(t, 1, nHandles, "expected 1 EdgeHandlesRoute for the HTTP provider")
|
||||
}
|
||||
|
||||
// TestCommitContracts_NoBulkLoader_FallsBackToAddBatch asserts that
|
||||
// when the backend does not implement graph.BulkLoader (the
|
||||
// in-memory *graph.Graph case) commitContracts still issues a
|
||||
// single AddBatch — not the per-row AddNode / AddEdge writes — and
|
||||
// does not attempt to call BeginBulkLoad / FlushBulk.
|
||||
func TestCommitContracts_NoBulkLoader_FallsBackToAddBatch(t *testing.T) {
|
||||
g := graph.New()
|
||||
require.NotImplements(t, (*graph.BulkLoader)(nil), graph.Store(g))
|
||||
|
||||
g.AddNode(&graph.Node{
|
||||
ID: "pkg/foo.go::Handler.List",
|
||||
Kind: graph.KindMethod,
|
||||
Name: "List",
|
||||
FilePath: "pkg/foo.go",
|
||||
Language: "go",
|
||||
})
|
||||
|
||||
idx := New(g, parser.NewRegistry(), config.Default().Index, zap.NewNop())
|
||||
|
||||
reg := contracts.NewRegistry()
|
||||
reg.Add(contracts.Contract{
|
||||
ID: "http::GET::/v1/items",
|
||||
Type: contracts.ContractHTTP,
|
||||
Role: contracts.RoleProvider,
|
||||
SymbolID: "pkg/foo.go::Handler.List",
|
||||
FilePath: "pkg/foo.go",
|
||||
Line: 42,
|
||||
})
|
||||
|
||||
idx.commitContracts(reg)
|
||||
|
||||
require.NotNil(t, g.GetNode("http::GET::/v1/items"))
|
||||
out := g.GetOutEdges("pkg/foo.go::Handler.List")
|
||||
var nProvides, nHandles int
|
||||
for _, e := range out {
|
||||
switch e.Kind {
|
||||
case graph.EdgeProvides:
|
||||
nProvides++
|
||||
case graph.EdgeHandlesRoute:
|
||||
nHandles++
|
||||
}
|
||||
}
|
||||
require.Equal(t, 1, nProvides)
|
||||
require.Equal(t, 1, nHandles)
|
||||
}
|
||||
|
||||
// TestExtractGoModContracts_UsesAddBatch asserts that go.mod
|
||||
// dependency-contract emission goes through a single AddBatch
|
||||
// call (with the bulk path engaged when the backend supports it)
|
||||
// instead of the per-row AddNode loop that previously did one
|
||||
// round-trip per dependency on the on-disk backend.
|
||||
func TestExtractGoModContracts_UsesAddBatch(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
goMod := []byte(`module example.com/test
|
||||
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/dep/one v1.0.0
|
||||
github.com/dep/two v0.5.0
|
||||
)
|
||||
`)
|
||||
require.NoError(t, os.WriteFile(filepath.Join(dir, "go.mod"), goMod, 0o644))
|
||||
|
||||
g := newRecordingBulkGraph()
|
||||
idx := New(g, parser.NewRegistry(), config.Default().Index, zap.NewNop())
|
||||
idx.rootPath = dir
|
||||
|
||||
reg := contracts.NewRegistry()
|
||||
idx.extractGoModContracts(reg)
|
||||
|
||||
require.Contains(t, g.calls, "AddBatch",
|
||||
"extractGoModContracts must emit dep nodes via a single AddBatch")
|
||||
require.Zero(t, g.addNode.Load(), "no per-row AddNode calls expected")
|
||||
}
|
||||
Reference in New Issue
Block a user