Keep capacity cancellation tests independent of implementation details
This commit is contained in:
@@ -3,8 +3,6 @@ package promptkit_test
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -172,46 +170,6 @@ func TestUnlimitedBackendsRetainInjectedClientConcurrency(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelWhileWaitingForGenerationCapacityPreservesErrorAndCapacity(t *testing.T) {
|
||||
release := make(chan struct{})
|
||||
client := newCapacityGateClient(release, 3)
|
||||
engine := newBackendCapacityEngine(t, client, 1, capacityInt(1), nil)
|
||||
|
||||
firstResult := make(chan capacityRunResult, 1)
|
||||
go runCapacityRequest(engine, context.Background(), promptkit.RunRequest{PromptID: "prompt"}, firstResult)
|
||||
awaitCapacityRequest(t, client.started)
|
||||
|
||||
waitingContext := newObservedCancelContext()
|
||||
secondResult := make(chan capacityRunResult, 1)
|
||||
go runCapacityRequest(engine, waitingContext, promptkit.RunRequest{PromptID: "prompt"}, secondResult)
|
||||
awaitCapacitySignal(t, waitingContext.waiting, "generation-capacity wait")
|
||||
waitingContext.cancel()
|
||||
|
||||
outcome := awaitCapacityRun(t, secondResult)
|
||||
if outcome.result != nil {
|
||||
t.Fatalf("canceled capacity wait returned partial result: %+v", outcome.result)
|
||||
}
|
||||
if !errors.Is(outcome.err, context.Canceled) || !errors.Is(outcome.err, promptkit.ErrLLMGenerate) {
|
||||
t.Fatalf("canceled capacity wait=%v, want context.Canceled and ErrLLMGenerate", outcome.err)
|
||||
}
|
||||
if _, _, calls := client.snapshot(); calls != 1 {
|
||||
t.Fatalf("client calls=%d after canceled waiter, want only active call", calls)
|
||||
}
|
||||
|
||||
close(release)
|
||||
first := awaitCapacityRun(t, firstResult)
|
||||
if first.err != nil || first.result == nil {
|
||||
t.Fatalf("first run=(%+v, %v), want success", first.result, first.err)
|
||||
}
|
||||
result, err := engine.Run(context.Background(), promptkit.RunRequest{PromptID: "prompt"})
|
||||
if err != nil || result == nil {
|
||||
t.Fatalf("run after cancellation=(%+v, %v), want reusable capacity", result, err)
|
||||
}
|
||||
if _, _, calls := client.snapshot(); calls != 2 {
|
||||
t.Fatalf("client calls=%d after reuse, want 2", calls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCapacityExceededSentinelContract(t *testing.T) {
|
||||
if promptkit.ErrCapacityExceeded == nil {
|
||||
t.Fatal("ErrCapacityExceeded is nil")
|
||||
@@ -366,61 +324,6 @@ func (r *capacityArtifactReader) callCount() int {
|
||||
return r.calls
|
||||
}
|
||||
|
||||
type observedCancelContext struct {
|
||||
done chan struct{}
|
||||
waiting chan struct{}
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func newObservedCancelContext() *observedCancelContext {
|
||||
return &observedCancelContext{
|
||||
done: make(chan struct{}),
|
||||
waiting: make(chan struct{}, 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *observedCancelContext) Deadline() (time.Time, bool) {
|
||||
return time.Time{}, false
|
||||
}
|
||||
|
||||
func (c *observedCancelContext) Done() <-chan struct{} {
|
||||
var callers [8]uintptr
|
||||
frames := runtime.CallersFrames(callers[:runtime.Callers(2, callers[:])])
|
||||
for {
|
||||
frame, more := frames.Next()
|
||||
if strings.Contains(frame.Function, "internal/capacity.(*pool).acquire") {
|
||||
select {
|
||||
case c.waiting <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
break
|
||||
}
|
||||
if !more {
|
||||
break
|
||||
}
|
||||
}
|
||||
return c.done
|
||||
}
|
||||
|
||||
func (c *observedCancelContext) Err() error {
|
||||
select {
|
||||
case <-c.done:
|
||||
return context.Canceled
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *observedCancelContext) Value(any) any {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *observedCancelContext) cancel() {
|
||||
c.once.Do(func() {
|
||||
close(c.done)
|
||||
})
|
||||
}
|
||||
|
||||
func awaitCapacityRequest(
|
||||
t *testing.T,
|
||||
requests <-chan promptkit.GenerateRequest,
|
||||
|
||||
@@ -94,4 +94,7 @@ The [runner tests](../../internal/usecase/runner_test.go) own early admission,
|
||||
lease lifetime, failure release, and shared initial/repair scheduling. The
|
||||
[external package capacity tests](../../capacity_contract_test.go) own the
|
||||
assembled public-engine behavior for configured limits, capacity errors,
|
||||
endpoint identity, engine independence, cancellation, and injected clients.
|
||||
endpoint identity, engine independence, and injected clients. The
|
||||
[root error-boundary tests](../../errors_internal_test.go) own preservation of
|
||||
the public generation category and context identity when generation is
|
||||
canceled.
|
||||
|
||||
22
errors_internal_test.go
Normal file
22
errors_internal_test.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package promptkit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"gitea.maximumdirect.net/eric/promptkit/internal/usecase"
|
||||
)
|
||||
|
||||
func TestMapPublicErrorPreservesGenerationCancellation(t *testing.T) {
|
||||
internalErr := fmt.Errorf("%w: %w", usecase.ErrLLMGenerate, context.Canceled)
|
||||
|
||||
err := mapPublicError(internalErr)
|
||||
if !errors.Is(err, ErrLLMGenerate) {
|
||||
t.Fatalf("mapped error=%v, want ErrLLMGenerate", err)
|
||||
}
|
||||
if !errors.Is(err, context.Canceled) {
|
||||
t.Fatalf("mapped error=%v, want context.Canceled", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user