Preserve authentication cancellation at the response limit
This commit is contained in:
@@ -3,6 +3,7 @@ package promptkit_test
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"reflect"
|
||||
@@ -13,6 +14,45 @@ import (
|
||||
"go.maximumdirect.net/promptkit"
|
||||
)
|
||||
|
||||
type cancelingAuthenticationBody struct {
|
||||
remaining int
|
||||
cancel context.CancelFunc
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (b *cancelingAuthenticationBody) Read(p []byte) (int, error) {
|
||||
n := min(len(p), b.remaining)
|
||||
for i := range p[:n] {
|
||||
p[i] = 'x'
|
||||
}
|
||||
b.remaining -= n
|
||||
if b.remaining == 0 {
|
||||
b.cancel()
|
||||
return n, context.Canceled
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
func (b *cancelingAuthenticationBody) Close() error { b.closed = true; return nil }
|
||||
|
||||
func TestAuthenticationReadCancellationWinsOverOverflow(t *testing.T) {
|
||||
for _, size := range []int{1024, (1 << 20) + 1} {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
body := &cancelingAuthenticationBody{remaining: size, cancel: cancel}
|
||||
engine, err := promptkit.NewEngine(promptkit.Config{HTTPClient: &http.Client{Transport: roundTripFunc(func(*http.Request) (*http.Response, error) {
|
||||
return &http.Response{StatusCode: 200, Header: make(http.Header), Body: body}, nil
|
||||
})}})
|
||||
if err != nil {
|
||||
cancel()
|
||||
t.Fatal(err)
|
||||
}
|
||||
report, err := engine.SmokeTest(ctx, promptkit.SmokeTestRequest{Kind: promptkit.SmokeTestAuthentication, BackendID: "openrouter"})
|
||||
cancel()
|
||||
if !errors.Is(err, context.Canceled) || report == nil || report.Completed || report.Failure != promptkit.ExecutionFailureCanceled || report.Facts.CredentialsAccepted != nil || report.Facts.ResponseReceived == nil || !*report.Facts.ResponseReceived || !body.closed {
|
||||
t.Fatalf("size %d: report=%+v error=%v closed=%v", size, report, err, body.closed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBundledSmokeHTTPDefaults(t *testing.T) {
|
||||
t.Setenv("OPENROUTER_API_KEY", "synthetic-key")
|
||||
var urls []string
|
||||
|
||||
@@ -27,7 +27,11 @@ contracts.
|
||||
|
||||
### 1. Preserve Caller Cancellation When Authentication Also Overflows [P2]
|
||||
|
||||
**Status:** Open. **Stages:** 7, 21–22.
|
||||
**Status:** Complete. **Stages:** 7, 21–22.
|
||||
|
||||
Completion: interrupted body reads preserve caller cancellation before overflow
|
||||
classification. Public below-limit and overflow-boundary regressions retain HTTP
|
||||
facts, unknown acceptance, incomplete cancellation reports, and body closure.
|
||||
|
||||
**Locations:** [authentication adapter](../../internal/llm/openrouter_authentication.go),
|
||||
`ProbeOpenRouterKey`, lines 61–67;
|
||||
|
||||
@@ -59,6 +59,9 @@ func (c *OpenAICompatibleClient) ProbeOpenRouterKey(ctx context.Context, endpoin
|
||||
return result, nil
|
||||
}
|
||||
contents, err := io.ReadAll(io.LimitReader(response.Body, maxAuthenticationResponseBytes+1))
|
||||
if err != nil && ctx.Err() != nil {
|
||||
return result, ctx.Err()
|
||||
}
|
||||
if len(contents) > maxAuthenticationResponseBytes {
|
||||
result.Overflow = true
|
||||
return result, nil
|
||||
|
||||
Reference in New Issue
Block a user