Files
ragflow/internal/harness/graph/pregel/traced_engine_test.go
Yingfeng 5b0b86c276 More resilient graph engine (#16325)
### What problem does this PR solve?

- OpenTelemetry integration
- Checkpoint conformance tests
- State inspector API
- Callbacks
- A series of fault injection tests
- Pregel integration tests

### Type of change

- [x] Refactoring
2026-06-24 23:05:07 +08:00

170 lines
5.2 KiB
Go

// Package pregel provides tests for the OpenTelemetry tracing and callback system.
package pregel
import (
"context"
"sync/atomic"
"testing"
"ragflow/internal/harness/graph/types"
)
// TestTracedEngine_Smoke verifies that TracedEngine.Run does not panic
// and produces output events.
func TestTracedEngine_Smoke(t *testing.T) {
g := newTestGraph(t)
engine := NewEngine(g, WithRecursionLimit(10))
traced := NewTracedEngine(engine)
ctx := context.Background()
outputCh, errCh := traced.Run(ctx, map[string]any{"value": "hello"}, types.StreamModeValues)
var finalState any
for result := range outputCh {
if se, ok := result.(*StreamEvent); ok && se.Type == EventTypeFinal {
if data, ok := se.Data.(map[string]any); ok {
finalState = data["state"]
}
}
}
err := <-errCh
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if finalState == nil {
t.Fatal("expected non-nil final state")
}
}
// TestRunCallback_Dispatch verifies callback dispatch on run start/end.
func TestRunCallback_Dispatch(t *testing.T) {
g := newTestGraph(t)
cbManager := NewCallbackManager()
var runStarted, runEnded atomic.Int32
cbManager.AddCallback(&NoopCallbackMock{
onRunStart: func(_ context.Context, _, _ string) {
runStarted.Add(1)
},
onRunEnd: func(_ context.Context, _, _ string, _ error) {
runEnded.Add(1)
},
})
engine := NewEngine(g,
WithRecursionLimit(10),
)
traced := NewTracedEngine(engine)
traced.SetCallbacks(cbManager)
ctx := context.Background()
outputCh, errCh := traced.Run(ctx, map[string]any{"value": "ping"}, types.StreamModeValues)
for range outputCh {
}
<-errCh
if runStarted.Load() != 1 {
t.Fatalf("expected 1 run start, got %d", runStarted.Load())
}
if runEnded.Load() != 1 {
t.Fatalf("expected 1 run end, got %d", runEnded.Load())
}
}
// TestCheckpointCallback_Dispatch verifies checkpoint callback dispatch.
func TestCheckpointCallback_Dispatch(t *testing.T) {
g := newTestGraph(t)
cbManager := NewCallbackManager()
var cpSaved, cpLoaded atomic.Int32
cbManager.AddCheckpointCallback(&CheckpointCallbackMock{
onSave: func(_ context.Context, _, _ string, _ int) { cpSaved.Add(1) },
onLoad: func(_ context.Context, _, _ string, _ int) { cpLoaded.Add(1) },
})
engine := NewEngine(g,
WithRecursionLimit(10),
)
traced := NewTracedEngine(engine)
traced.SetCallbacks(cbManager)
ctx := context.Background()
outputCh, errCh := traced.Run(ctx, map[string]any{"value": "ping"}, types.StreamModeValues)
for range outputCh {
}
<-errCh
if cpSaved.Load() < 0 {
// Checkpoint callback may or may not fire depending on checkpointer config.
// Just verify no crash.
}
}
// TestTracedEngine_Disabled verifies that disabling tracing still runs correctly.
func TestTracedEngine_Disabled(t *testing.T) {
g := newTestGraph(t)
engine := NewEngine(g, WithRecursionLimit(10))
traced := NewTracedEngine(engine, WithTracedEngineDisabled())
ctx := context.Background()
outputCh, errCh := traced.Run(ctx, map[string]any{"value": "hello"}, types.StreamModeValues)
for range outputCh {
}
err := <-errCh
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
// ---- Mocks ----
// NoopCallbackMock implements GraphCallback with overridable hooks.
type NoopCallbackMock struct {
onRunStart func(context.Context, string, string)
onRunEnd func(context.Context, string, string, error)
}
func (m *NoopCallbackMock) OnRunStart(ctx context.Context, grp, tid string) {
if m.onRunStart != nil {
m.onRunStart(ctx, grp, tid)
}
}
func (m *NoopCallbackMock) OnRunEnd(ctx context.Context, grp, tid string, err error) {
if m.onRunEnd != nil {
m.onRunEnd(ctx, grp, tid, err)
}
}
func (m *NoopCallbackMock) OnStepStart(_ context.Context, _, _ int) {}
func (m *NoopCallbackMock) OnStepEnd(_ context.Context, _ int, _ error) {}
func (m *NoopCallbackMock) OnNodeStart(_ context.Context, _ string, _ int) {}
func (m *NoopCallbackMock) OnNodeEnd(_ context.Context, _ string, _ int, _ interface{}, _ error) {}
func (m *NoopCallbackMock) OnCheckpointSave(_ context.Context, _, _ string, _ int) {}
func (m *NoopCallbackMock) OnCheckpointLoad(_ context.Context, _, _ string, _ int) {}
func (m *NoopCallbackMock) OnCheckpointUpdate(_ context.Context, _, _ string) {}
func (m *NoopCallbackMock) OnInterrupt(_ context.Context, _ []string, _ int) {}
func (m *NoopCallbackMock) OnResume(_ context.Context, _ string) {}
// CheckpointCallbackMock implements CheckpointCallback with overridable hooks.
type CheckpointCallbackMock struct {
onSave func(context.Context, string, string, int)
onLoad func(context.Context, string, string, int)
}
func (m *CheckpointCallbackMock) OnCheckpointSave(ctx context.Context, tid, cpid string, step int) {
if m.onSave != nil {
m.onSave(ctx, tid, cpid, step)
}
}
func (m *CheckpointCallbackMock) OnCheckpointLoad(ctx context.Context, tid, cpid string, step int) {
if m.onLoad != nil {
m.onLoad(ctx, tid, cpid, step)
}
}
func (m *CheckpointCallbackMock) OnCheckpointUpdate(_ context.Context, _, _ string) {}
// Ensure mock implements interfaces.
var (
_ GraphCallback = (*NoopCallbackMock)(nil)
_ CheckpointCallback = (*CheckpointCallbackMock)(nil)
)