Files
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

184 lines
6.3 KiB
Go

package graph
import (
"fmt"
"sync"
"testing"
)
func isPowerOfTwo(n int) bool { return n > 0 && n&(n-1) == 0 }
// TestNextPow2 pins the rounding helper that guarantees the power-of-two
// invariant the shardMask trick depends on.
func TestNextPow2(t *testing.T) {
cases := map[int]int{
-3: 1, 0: 1, 1: 1, 2: 2, 3: 4, 4: 4,
5: 8, 9: 16, 15: 16, 16: 16, 17: 32, 255: 256, 256: 256, 257: 512,
}
for in, want := range cases {
if got := nextPow2(in); got != want {
t.Errorf("nextPow2(%d) = %d, want %d", in, got, want)
}
}
}
// TestCoerceShardCountBounds asserts every coerced count is a power of
// two within [minShards, maxShards] regardless of the input.
func TestCoerceShardCountBounds(t *testing.T) {
for _, in := range []int{-100, 0, 1, 3, 4, 7, 16, 100, 256, 511, 512, 1000, 1 << 20} {
got := coerceShardCount(in)
if !isPowerOfTwo(got) {
t.Errorf("coerceShardCount(%d) = %d, not a power of two", in, got)
}
if got < minShards || got > maxShards {
t.Errorf("coerceShardCount(%d) = %d, outside [%d, %d]", in, got, minShards, maxShards)
}
}
}
// TestDefaultShardCountDerived asserts the CPU-derived default (no
// override) is always a power of two in the derived range.
func TestDefaultShardCountDerived(t *testing.T) {
t.Setenv(shardCountEnv, "") // ensure no override is in effect
got := defaultShardCount()
if !isPowerOfTwo(got) {
t.Fatalf("defaultShardCount() = %d, not a power of two", got)
}
if got < derivedShardFloor || got > derivedShardCeiling {
t.Fatalf("defaultShardCount() = %d, outside derived range [%d, %d]", got, derivedShardFloor, derivedShardCeiling)
}
}
// TestGraphShardFieldsConsistent asserts the constructed graph's shard
// bookkeeping is internally consistent: the slice length equals
// shardCount, shardCount is a power of two, and shardMask == count-1.
func TestGraphShardFieldsConsistent(t *testing.T) {
for _, req := range []int{1, 2, 4, 7, 16, 64, 300, 1000} {
g := newWithShardCount(req)
if !isPowerOfTwo(g.shardCount) {
t.Errorf("newWithShardCount(%d): shardCount = %d, not a power of two", req, g.shardCount)
}
if g.shardCount < minShards || g.shardCount > maxShards {
t.Errorf("newWithShardCount(%d): shardCount = %d, outside [%d, %d]", req, g.shardCount, minShards, maxShards)
}
if g.shardMask != uint32(g.shardCount-1) {
t.Errorf("newWithShardCount(%d): shardMask = %d, want %d", req, g.shardMask, g.shardCount-1)
}
if len(g.shards) != g.shardCount {
t.Errorf("newWithShardCount(%d): len(shards) = %d, want %d", req, len(g.shards), g.shardCount)
}
for i, s := range g.shards {
if s == nil || s.nodes == nil {
t.Errorf("newWithShardCount(%d): shard %d not initialized", req, i)
}
}
}
}
// TestShardCountEnvOverride asserts GORTEX_GRAPH_SHARDS is honored,
// coerced to a power of two within bounds, and reflected in the graph
// built by New().
func TestShardCountEnvOverride(t *testing.T) {
cases := []struct {
env string
want int
}{
{"4", 4}, // exact power of two below the derived floor — still honored
{"5", 8}, // not a power of two — coerced up
{"64", 64}, // exact
{"300", 512}, // not a power of two — coerced up
{"1000", 512}, // above maxShards — clamped
{"1", 1}, // minimum
}
for _, c := range cases {
t.Run(c.env, func(t *testing.T) {
t.Setenv(shardCountEnv, c.env)
if got := defaultShardCount(); got != c.want {
t.Fatalf("defaultShardCount() with %s=%q = %d, want %d", shardCountEnv, c.env, got, c.want)
}
g := New()
if g.shardCount != c.want {
t.Fatalf("New().shardCount = %d, want %d", g.shardCount, c.want)
}
if g.shardMask != uint32(c.want-1) {
t.Fatalf("New().shardMask = %d, want %d", g.shardMask, c.want-1)
}
if len(g.shards) != c.want {
t.Fatalf("len(New().shards) = %d, want %d", len(g.shards), c.want)
}
})
}
}
// TestShardCountInvalidEnvFallsBack asserts a malformed or non-positive
// override is ignored and the graph falls back to the derived default.
func TestShardCountInvalidEnvFallsBack(t *testing.T) {
for _, v := range []string{"abc", "0", "-4", " ", "3.5"} {
t.Run(v, func(t *testing.T) {
t.Setenv(shardCountEnv, v)
got := defaultShardCount()
if !isPowerOfTwo(got) || got < derivedShardFloor || got > derivedShardCeiling {
t.Fatalf("override %q: defaultShardCount() = %d, want power-of-two in [%d, %d]", v, got, derivedShardFloor, derivedShardCeiling)
}
})
}
}
// TestShardedConcurrentInsertNoLoss inserts a large, disjoint set of
// nodes and edges from many goroutines into graphs built with several
// shard counts (including non-default 1, 4, 64) and asserts nothing is
// lost or duplicated — proving every shard is correctly initialized and
// indexed regardless of count.
func TestShardedConcurrentInsertNoLoss(t *testing.T) {
for _, count := range []int{1, 4, 16, 64} {
t.Run(fmt.Sprintf("shards=%d", count), func(t *testing.T) {
g := newWithShardCount(count)
if g.shardCount != count {
t.Fatalf("newWithShardCount(%d).shardCount = %d", count, g.shardCount)
}
const workers = 32
const perWorker = 500
var wg sync.WaitGroup
wg.Add(workers)
for w := range workers {
go func(w int) {
defer wg.Done()
for i := range perWorker {
nid := fmt.Sprintf("w%d-n%d::N", w, i)
g.AddNode(&Node{ID: nid, Name: "N", Kind: KindFunction, FilePath: "f"})
// One out-edge per node to a shared sink, so the From
// and To endpoints frequently land in different shards.
g.AddEdge(&Edge{
From: nid,
To: fmt.Sprintf("sink-%d::S", i%17),
Kind: EdgeCalls,
FilePath: "f",
Line: w,
})
}
}(w)
}
wg.Wait()
wantNodes := workers * perWorker
for w := range workers {
for i := range perWorker {
nid := fmt.Sprintf("w%d-n%d::N", w, i)
if g.GetNode(nid) == nil {
t.Fatalf("node %q missing after concurrent insert (shards=%d)", nid, count)
}
if outs := g.GetOutEdges(nid); len(outs) != 1 {
t.Fatalf("node %q has %d out-edges, want 1 (shards=%d)", nid, len(outs), count)
}
}
}
// Sink targets are never AddNode'd, so NodeCount counts only the
// inserted N nodes — exactly one per (worker, index) pair.
if got := g.NodeCount(); got != wantNodes {
t.Fatalf("NodeCount() = %d, want %d (shards=%d)", got, wantNodes, count)
}
})
}
}