Files
jbergner 440423c5b6
All checks were successful
release-tag / release-image (push) Successful in 2m43s
RC-3
2026-08-09 11:29:13 +02:00

124 lines
4.3 KiB
Go

package sourceagent
import (
"bytes"
"context"
"testing"
"time"
"github.com/local/glpi-neural-brain/internal/vectorgraph"
)
func TestVectorGraphComputeWireRoundTrip(t *testing.T) {
request := VectorGraphComputeRequest{
Header: VectorGraphComputeHeader{
SchemaVersion: SchemaVersion,
JobID: "compute-test",
Kind: ComputeKindVectorGraph,
GraphVersion: 42,
Primary: vectorgraph.Config{Neighbors: 2, CandidateLimit: 8, HashBits: 8, HashTables: 2, BandBits: 4, MinSimilarity: .8, MinAffinity: .2},
OrphanPass: true,
OrphanFocusIDs: []string{"c"},
},
Entries: []vectorgraph.Entry{
{ID: "a", Vector: []float32{1, 0, 0}},
{ID: "b", Vector: []float32{.99, .01, 0}},
{ID: "c", Vector: []float32{.98, .02, 0}},
},
}
var buffer bytes.Buffer
if err := WriteVectorGraphJob(&buffer, request); err != nil {
t.Fatal(err)
}
decoded, err := ReadVectorGraphJob(bytes.NewReader(buffer.Bytes()), 1<<20)
if err != nil {
t.Fatal(err)
}
if decoded.Header.JobID != request.Header.JobID || decoded.Header.GraphVersion != 42 || len(decoded.Entries) != 3 {
t.Fatalf("unexpected decoded job: %+v", decoded.Header)
}
for i := range request.Entries {
if decoded.Entries[i].ID != request.Entries[i].ID || len(decoded.Entries[i].Vector) != len(request.Entries[i].Vector) {
t.Fatalf("entry %d mismatch: got=%+v want=%+v", i, decoded.Entries[i], request.Entries[i])
}
for j := range request.Entries[i].Vector {
if decoded.Entries[i].Vector[j] != request.Entries[i].Vector[j] {
t.Fatalf("entry %d vector %d mismatch", i, j)
}
}
}
}
func TestExecuteVectorGraphJobRunsOrphanSecondPassWithoutModel(t *testing.T) {
entries := []vectorgraph.Entry{
{ID: "a", Vector: []float32{1, 0, 0}},
{ID: "b", Vector: []float32{.99, .01, 0}},
{ID: "orphan", Vector: []float32{.97, .03, 0}},
{ID: "far", Vector: []float32{0, 1, 0}},
}
request := VectorGraphComputeRequest{Header: VectorGraphComputeHeader{
SchemaVersion: SchemaVersion, JobID: "compute-orphan", Kind: ComputeKindVectorGraph, GraphVersion: 7,
Primary: vectorgraph.Config{Neighbors: 1, CandidateLimit: 4, HashBits: 8, HashTables: 2, BandBits: 4, MinSimilarity: .995, MinAffinity: .2},
OrphanPass: true,
Orphan: vectorgraph.Config{Neighbors: 1, CandidateLimit: 8, HashBits: 8, HashTables: 2, BandBits: 4, MinSimilarity: .90, MinAffinity: .1},
OrphanFocusIDs: []string{"orphan"},
}, Entries: entries}
result := ExecuteVectorGraphJob(request)
if result.Kind != ComputeKindVectorGraph || result.GraphVersion != 7 || result.Error != "" {
t.Fatalf("unexpected result: %+v", result)
}
if result.Orphan.Stats.Focused == 0 {
t.Fatalf("orphan pass did not inspect requested focus: %+v", result.Orphan.Stats)
}
for _, link := range result.Orphan.Links {
if link.Source != "orphan" && link.Target != "orphan" {
t.Fatalf("orphan pass emitted unrelated link: %+v", link)
}
}
}
func TestVectorGraphComputeBrokerClaimComplete(t *testing.T) {
store := &Store{computeJobs: map[string]*computeJobState{}}
request := VectorGraphComputeRequest{Header: VectorGraphComputeHeader{JobID: "broker-job", Kind: ComputeKindVectorGraph, GraphVersion: 9}, Entries: []vectorgraph.Entry{{ID: "a", Vector: []float32{1, 0}}, {ID: "b", Vector: []float32{.99, .01}}}}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
resultCh := make(chan VectorGraphComputeResult, 1)
errCh := make(chan error, 1)
go func() {
result, err := store.SubmitVectorGraphJob(ctx, request)
if err != nil {
errCh <- err
return
}
resultCh <- result
}()
deadline := time.Now().Add(time.Second)
var claimed VectorGraphComputeRequest
var ok bool
for time.Now().Before(deadline) {
claimed, ok = store.ClaimVectorGraphJob("agent-cpu", time.Minute)
if ok {
break
}
time.Sleep(time.Millisecond)
}
if !ok || claimed.Header.JobID != "broker-job" {
t.Fatalf("compute job was not claimable: ok=%v job=%+v", ok, claimed.Header)
}
result := ExecuteVectorGraphJob(claimed)
if err := store.CompleteVectorGraphJob("agent-cpu", result); err != nil {
t.Fatal(err)
}
select {
case err := <-errCh:
t.Fatal(err)
case got := <-resultCh:
if got.AgentID != "agent-cpu" || got.GraphVersion != 9 || got.Kind != ComputeKindVectorGraph {
t.Fatalf("unexpected completed result: %+v", got)
}
case <-ctx.Done():
t.Fatal(ctx.Err())
}
}