98 lines
2.7 KiB
Go
98 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestSnapshotBuildContinuesAfterRequesterCancellation(t *testing.T) {
|
|
svc := NewGraphSnapshotService(nil, Config{})
|
|
|
|
var fetchCalls atomic.Int32
|
|
started := make(chan struct{})
|
|
release := make(chan struct{})
|
|
expected := GraphResponse{
|
|
Nodes: []Node{{ID: 1}},
|
|
Edges: []Edge{{Source: 1, Target: 1, PredicateID: 0}},
|
|
Meta: &GraphMeta{GraphQueryID: "default", Nodes: 1, Edges: 1},
|
|
}
|
|
|
|
svc.fetchSnapshot = func(ctx context.Context, _ *AnzoGraphClient, _ Config, nodeLimit int, edgeLimit int, graphQueryID string) (GraphResponse, error) {
|
|
fetchCalls.Add(1)
|
|
if nodeLimit != 10 || edgeLimit != 20 || graphQueryID != "default" {
|
|
t.Fatalf("unexpected fetch args nodeLimit=%d edgeLimit=%d graphQueryID=%s", nodeLimit, edgeLimit, graphQueryID)
|
|
}
|
|
close(started)
|
|
<-release
|
|
return expected, nil
|
|
}
|
|
|
|
ctx1, cancel1 := context.WithCancel(context.Background())
|
|
defer cancel1()
|
|
|
|
firstErrCh := make(chan error, 1)
|
|
go func() {
|
|
_, err := svc.Get(ctx1, 10, 20, "default")
|
|
firstErrCh <- err
|
|
}()
|
|
|
|
<-started
|
|
cancel1()
|
|
|
|
select {
|
|
case err := <-firstErrCh:
|
|
if !errors.Is(err, context.Canceled) {
|
|
t.Fatalf("first Get error = %v, want context.Canceled", err)
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
t.Fatal("timed out waiting for first Get to return after cancellation")
|
|
}
|
|
|
|
secondSnapCh := make(chan GraphResponse, 1)
|
|
secondErrCh := make(chan error, 1)
|
|
go func() {
|
|
snap, err := svc.Get(context.Background(), 10, 20, "default")
|
|
if err != nil {
|
|
secondErrCh <- err
|
|
return
|
|
}
|
|
secondSnapCh <- snap
|
|
}()
|
|
|
|
time.Sleep(50 * time.Millisecond)
|
|
if got := fetchCalls.Load(); got != 1 {
|
|
t.Fatalf("fetchCalls after second waiter start = %d, want 1", got)
|
|
}
|
|
|
|
close(release)
|
|
|
|
select {
|
|
case err := <-secondErrCh:
|
|
t.Fatalf("second Get error = %v", err)
|
|
case snap := <-secondSnapCh:
|
|
if snap.Meta == nil || snap.Meta.Nodes != expected.Meta.Nodes || snap.Meta.Edges != expected.Meta.Edges {
|
|
t.Fatalf("second Get snapshot meta = %#v, want %#v", snap.Meta, expected.Meta)
|
|
}
|
|
case <-time.After(2 * time.Second):
|
|
t.Fatal("timed out waiting for second Get to return")
|
|
}
|
|
|
|
if got := fetchCalls.Load(); got != 1 {
|
|
t.Fatalf("fetchCalls after background completion = %d, want 1", got)
|
|
}
|
|
|
|
snap, err := svc.Get(context.Background(), 10, 20, "default")
|
|
if err != nil {
|
|
t.Fatalf("cached Get error = %v", err)
|
|
}
|
|
if snap.Meta == nil || snap.Meta.Nodes != expected.Meta.Nodes || snap.Meta.Edges != expected.Meta.Edges {
|
|
t.Fatalf("cached Get snapshot meta = %#v, want %#v", snap.Meta, expected.Meta)
|
|
}
|
|
if got := fetchCalls.Load(); got != 1 {
|
|
t.Fatalf("fetchCalls after cached Get = %d, want 1", got)
|
|
}
|
|
}
|