mirror of
https://github.com/open-gitagent/langship.sh.git
synced 2026-08-03 07:21:04 +02:00
93 lines
2.6 KiB
Go
93 lines
2.6 KiB
Go
package durability
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
)
|
|
|
|
type sample struct {
|
|
Name string `json:"name"`
|
|
Count int `json:"count"`
|
|
}
|
|
|
|
// fakeReplayCtx returns map[string]any from Run instead of the original type,
|
|
// the way Restate behaves on journal replay. Verifies RunAs handles the
|
|
// JSON round-trip transparently.
|
|
type fakeReplayCtx struct{}
|
|
|
|
func (fakeReplayCtx) Run(_ string, fn func(ctx context.Context) (any, error)) (any, error) {
|
|
v, err := fn(context.Background())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// Simulate JSON round-trip ala Restate replay: encode then decode into map.
|
|
// Real Restate does this via its journal serialization.
|
|
if s, ok := v.(sample); ok {
|
|
return map[string]any{"name": s.Name, "count": float64(s.Count)}, nil
|
|
}
|
|
return v, nil
|
|
}
|
|
|
|
func (fakeReplayCtx) RunWithRetry(name string, _ RetryPolicy, fn func(ctx context.Context) (any, error)) (any, error) {
|
|
return fakeReplayCtx{}.Run(name, fn)
|
|
}
|
|
|
|
func TestRunAs_directPath(t *testing.T) {
|
|
d := &DirectCtx{}
|
|
got, err := RunAs[sample](d, "step", func(_ context.Context) (sample, error) {
|
|
return sample{Name: "alice", Count: 7}, nil
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if got.Name != "alice" || got.Count != 7 {
|
|
t.Fatalf("unexpected: %+v", got)
|
|
}
|
|
}
|
|
|
|
func TestRunAs_replayPath(t *testing.T) {
|
|
got, err := RunAs[sample](fakeReplayCtx{}, "step", func(_ context.Context) (sample, error) {
|
|
return sample{Name: "bob", Count: 9}, nil
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if got.Name != "bob" || got.Count != 9 {
|
|
t.Fatalf("RunAs failed to round-trip via JSON: %+v", got)
|
|
}
|
|
}
|
|
|
|
func TestRunAs_propagatesErrors(t *testing.T) {
|
|
d := &DirectCtx{}
|
|
_, err := RunAs[sample](d, "step", func(_ context.Context) (sample, error) {
|
|
return sample{}, errors.New("boom")
|
|
})
|
|
if err == nil || err.Error() != "boom" {
|
|
t.Fatalf("expected boom, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestScopedDurableCtx_prefixesStepName(t *testing.T) {
|
|
captured := ""
|
|
rec := &recordingCtx{onRun: func(name string) { captured = name }}
|
|
scoped := &ScopedDurableCtx{Inner: rec, Prefix: "iter:0/"}
|
|
_, _ = scoped.Run("foo", func(_ context.Context) (any, error) { return nil, nil })
|
|
if captured != "iter:0/foo" {
|
|
t.Fatalf("expected prefixed step name, got %q", captured)
|
|
}
|
|
}
|
|
|
|
type recordingCtx struct{ onRun func(string) }
|
|
|
|
func (r *recordingCtx) Run(name string, fn func(ctx context.Context) (any, error)) (any, error) {
|
|
if r.onRun != nil {
|
|
r.onRun(name)
|
|
}
|
|
return fn(context.Background())
|
|
}
|
|
|
|
func (r *recordingCtx) RunWithRetry(name string, _ RetryPolicy, fn func(ctx context.Context) (any, error)) (any, error) {
|
|
return r.Run(name, fn)
|
|
}
|