Each limit/offset list method gains an iterator twin that walks pages transparently and stops on the first short page — same endpoints, no new API surface: Python generators (iter_tenant_streams / _stream_events / _windows / _checkpoints / iter_fork_evidence / iter_tenant_ivc_epochs), TypeScript async iterators (for await ... of client.iterTenantStreamEvents(...)), and a Go Iterator with Next(ctx) returning (nil, nil) at exhaustion, plus Iter* twins on the client. Tests drain a 3-page mocked response set in order and confirm a short first page ends iteration after exactly one request. READMEs updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
66 lines
1.4 KiB
Go
66 lines
1.4 KiB
Go
package attesto
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
)
|
|
|
|
func TestIteratorDrainsThreePagesInOrder(t *testing.T) {
|
|
pages := map[int][]M{
|
|
0: {{"seqNo": 1}, {"seqNo": 2}, {"seqNo": 3}},
|
|
3: {{"seqNo": 4}, {"seqNo": 5}, {"seqNo": 6}},
|
|
6: {{"seqNo": 7}},
|
|
}
|
|
calls := 0
|
|
it := NewIterator(func(_ context.Context, limit, offset int) ([]M, error) {
|
|
calls++
|
|
if limit != 3 {
|
|
t.Fatalf("limit = %d, want 3", limit)
|
|
}
|
|
return pages[offset], nil
|
|
}, 3)
|
|
|
|
var seqs []int
|
|
for {
|
|
item, err := it.Next(context.Background())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if item == nil {
|
|
break
|
|
}
|
|
seqs = append(seqs, item["seqNo"].(int))
|
|
}
|
|
want := []int{1, 2, 3, 4, 5, 6, 7}
|
|
if len(seqs) != len(want) {
|
|
t.Fatalf("seqs = %v", seqs)
|
|
}
|
|
for i, v := range want {
|
|
if seqs[i] != v {
|
|
t.Fatalf("seqs = %v, want %v", seqs, want)
|
|
}
|
|
}
|
|
if calls != 3 {
|
|
t.Errorf("calls = %d, want 3", calls)
|
|
}
|
|
}
|
|
|
|
func TestIteratorStopsCleanlyOnShortFirstPage(t *testing.T) {
|
|
calls := 0
|
|
it := NewIterator(func(_ context.Context, _, _ int) ([]M, error) {
|
|
calls++
|
|
return []M{{"streamId": "str_only"}}, nil
|
|
}, 100)
|
|
first, err := it.Next(context.Background())
|
|
if err != nil || first == nil {
|
|
t.Fatalf("first = %v err = %v", first, err)
|
|
}
|
|
second, err := it.Next(context.Background())
|
|
if err != nil || second != nil {
|
|
t.Fatalf("second = %v err = %v", second, err)
|
|
}
|
|
if calls != 1 {
|
|
t.Errorf("calls = %d, want 1 (short page must end iteration)", calls)
|
|
}
|
|
}
|