| 1 | package hostbox |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "errors" |
| 6 | "github.com/carlosframework/platform/internal/lease" |
| 7 | "io" |
| 8 | "strings" |
| 9 | "testing" |
| 10 | "time" |
| 11 | ) |
| 12 | |
| 13 | type budgetStore struct { |
| 14 | lease.VersionedStore |
| 15 | seen context.Context |
| 16 | calls int |
| 17 | } |
| 18 | |
| 19 | func (s *budgetStore) PutIfAbsent(ctx context.Context, _, _ string, _ []byte) (string, error) { |
| 20 | s.seen = ctx |
| 21 | s.calls++ |
| 22 | return "version", nil |
| 23 | } |
| 24 | func (s *budgetStore) OpenVersion(ctx context.Context, _, _, _ string) (io.ReadCloser, error) { |
| 25 | s.seen = ctx |
| 26 | s.calls++ |
| 27 | return io.NopCloser(strings.NewReader("version")), nil |
| 28 | } |
| 29 | func TestRequestStoreBudgetAndReadLifetime(t *testing.T) { |
| 30 | raw := &budgetStore{} |
| 31 | s := RequestStore{Store: raw, Check: func(context.Context) error { return nil }} |
| 32 | if _, err := s.PutIfAbsent(context.Background(), "b", "key", nil); err != nil { |
| 33 | t.Fatal(err) |
| 34 | } |
| 35 | deadline, ok := raw.seen.Deadline() |
| 36 | if !ok || time.Until(deadline) > RequestLimit { |
| 37 | t.Fatal(deadline) |
| 38 | } |
| 39 | if !errors.Is(raw.seen.Err(), context.Canceled) { |
| 40 | t.Fatal("request context not released") |
| 41 | } |
| 42 | r, err := s.OpenVersion(context.Background(), "b", "key", "v") |
| 43 | if err != nil { |
| 44 | t.Fatal(err) |
| 45 | } |
| 46 | if raw.seen.Err() != nil { |
| 47 | t.Fatal("stream cancelled before read") |
| 48 | } |
| 49 | if err := r.Close(); err != nil { |
| 50 | t.Fatal(err) |
| 51 | } |
| 52 | if !errors.Is(raw.seen.Err(), context.Canceled) { |
| 53 | t.Fatal("stream context leaked") |
| 54 | } |
| 55 | s.Check = func(context.Context) error { return ErrChanged } |
| 56 | if _, err := s.PutIfAbsent(context.Background(), "b", "key", nil); err == nil || raw.calls != 2 { |
| 57 | t.Fatal(err, raw.calls) |
| 58 | } |
| 59 | } |
| 60 | |