mirror of
https://github.com/sst/opencode.git
synced 2025-07-07 16:14:59 +00:00
332 lines
9 KiB
Go
332 lines
9 KiB
Go
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
|
|
package opencode_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/sst/opencode-sdk-go"
|
|
"github.com/sst/opencode-sdk-go/internal"
|
|
"github.com/sst/opencode-sdk-go/option"
|
|
)
|
|
|
|
type closureTransport struct {
|
|
fn func(req *http.Request) (*http.Response, error)
|
|
}
|
|
|
|
func (t *closureTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
return t.fn(req)
|
|
}
|
|
|
|
func TestUserAgentHeader(t *testing.T) {
|
|
var userAgent string
|
|
client := opencode.NewClient(
|
|
option.WithHTTPClient(&http.Client{
|
|
Transport: &closureTransport{
|
|
fn: func(req *http.Request) (*http.Response, error) {
|
|
userAgent = req.Header.Get("User-Agent")
|
|
return &http.Response{
|
|
StatusCode: http.StatusOK,
|
|
}, nil
|
|
},
|
|
},
|
|
}),
|
|
)
|
|
client.Event.List(context.Background())
|
|
if userAgent != fmt.Sprintf("Opencode/Go %s", internal.PackageVersion) {
|
|
t.Errorf("Expected User-Agent to be correct, but got: %#v", userAgent)
|
|
}
|
|
}
|
|
|
|
func TestRetryAfter(t *testing.T) {
|
|
retryCountHeaders := make([]string, 0)
|
|
client := opencode.NewClient(
|
|
option.WithHTTPClient(&http.Client{
|
|
Transport: &closureTransport{
|
|
fn: func(req *http.Request) (*http.Response, error) {
|
|
retryCountHeaders = append(retryCountHeaders, req.Header.Get("X-Stainless-Retry-Count"))
|
|
return &http.Response{
|
|
StatusCode: http.StatusTooManyRequests,
|
|
Header: http.Header{
|
|
http.CanonicalHeaderKey("Retry-After"): []string{"0.1"},
|
|
},
|
|
}, nil
|
|
},
|
|
},
|
|
}),
|
|
)
|
|
_, err := client.Event.List(context.Background())
|
|
if err == nil {
|
|
t.Error("Expected there to be a cancel error")
|
|
}
|
|
|
|
attempts := len(retryCountHeaders)
|
|
if attempts != 3 {
|
|
t.Errorf("Expected %d attempts, got %d", 3, attempts)
|
|
}
|
|
|
|
expectedRetryCountHeaders := []string{"0", "1", "2"}
|
|
if !reflect.DeepEqual(retryCountHeaders, expectedRetryCountHeaders) {
|
|
t.Errorf("Expected %v retry count headers, got %v", expectedRetryCountHeaders, retryCountHeaders)
|
|
}
|
|
}
|
|
|
|
func TestDeleteRetryCountHeader(t *testing.T) {
|
|
retryCountHeaders := make([]string, 0)
|
|
client := opencode.NewClient(
|
|
option.WithHTTPClient(&http.Client{
|
|
Transport: &closureTransport{
|
|
fn: func(req *http.Request) (*http.Response, error) {
|
|
retryCountHeaders = append(retryCountHeaders, req.Header.Get("X-Stainless-Retry-Count"))
|
|
return &http.Response{
|
|
StatusCode: http.StatusTooManyRequests,
|
|
Header: http.Header{
|
|
http.CanonicalHeaderKey("Retry-After"): []string{"0.1"},
|
|
},
|
|
}, nil
|
|
},
|
|
},
|
|
}),
|
|
option.WithHeaderDel("X-Stainless-Retry-Count"),
|
|
)
|
|
_, err := client.Event.List(context.Background())
|
|
if err == nil {
|
|
t.Error("Expected there to be a cancel error")
|
|
}
|
|
|
|
expectedRetryCountHeaders := []string{"", "", ""}
|
|
if !reflect.DeepEqual(retryCountHeaders, expectedRetryCountHeaders) {
|
|
t.Errorf("Expected %v retry count headers, got %v", expectedRetryCountHeaders, retryCountHeaders)
|
|
}
|
|
}
|
|
|
|
func TestOverwriteRetryCountHeader(t *testing.T) {
|
|
retryCountHeaders := make([]string, 0)
|
|
client := opencode.NewClient(
|
|
option.WithHTTPClient(&http.Client{
|
|
Transport: &closureTransport{
|
|
fn: func(req *http.Request) (*http.Response, error) {
|
|
retryCountHeaders = append(retryCountHeaders, req.Header.Get("X-Stainless-Retry-Count"))
|
|
return &http.Response{
|
|
StatusCode: http.StatusTooManyRequests,
|
|
Header: http.Header{
|
|
http.CanonicalHeaderKey("Retry-After"): []string{"0.1"},
|
|
},
|
|
}, nil
|
|
},
|
|
},
|
|
}),
|
|
option.WithHeader("X-Stainless-Retry-Count", "42"),
|
|
)
|
|
_, err := client.Event.List(context.Background())
|
|
if err == nil {
|
|
t.Error("Expected there to be a cancel error")
|
|
}
|
|
|
|
expectedRetryCountHeaders := []string{"42", "42", "42"}
|
|
if !reflect.DeepEqual(retryCountHeaders, expectedRetryCountHeaders) {
|
|
t.Errorf("Expected %v retry count headers, got %v", expectedRetryCountHeaders, retryCountHeaders)
|
|
}
|
|
}
|
|
|
|
func TestRetryAfterMs(t *testing.T) {
|
|
attempts := 0
|
|
client := opencode.NewClient(
|
|
option.WithHTTPClient(&http.Client{
|
|
Transport: &closureTransport{
|
|
fn: func(req *http.Request) (*http.Response, error) {
|
|
attempts++
|
|
return &http.Response{
|
|
StatusCode: http.StatusTooManyRequests,
|
|
Header: http.Header{
|
|
http.CanonicalHeaderKey("Retry-After-Ms"): []string{"100"},
|
|
},
|
|
}, nil
|
|
},
|
|
},
|
|
}),
|
|
)
|
|
_, err := client.Event.List(context.Background())
|
|
if err == nil {
|
|
t.Error("Expected there to be a cancel error")
|
|
}
|
|
if want := 3; attempts != want {
|
|
t.Errorf("Expected %d attempts, got %d", want, attempts)
|
|
}
|
|
}
|
|
|
|
func TestContextCancel(t *testing.T) {
|
|
client := opencode.NewClient(
|
|
option.WithHTTPClient(&http.Client{
|
|
Transport: &closureTransport{
|
|
fn: func(req *http.Request) (*http.Response, error) {
|
|
<-req.Context().Done()
|
|
return nil, req.Context().Err()
|
|
},
|
|
},
|
|
}),
|
|
)
|
|
cancelCtx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
_, err := client.Event.List(cancelCtx)
|
|
if err == nil {
|
|
t.Error("Expected there to be a cancel error")
|
|
}
|
|
}
|
|
|
|
func TestContextCancelDelay(t *testing.T) {
|
|
client := opencode.NewClient(
|
|
option.WithHTTPClient(&http.Client{
|
|
Transport: &closureTransport{
|
|
fn: func(req *http.Request) (*http.Response, error) {
|
|
<-req.Context().Done()
|
|
return nil, req.Context().Err()
|
|
},
|
|
},
|
|
}),
|
|
)
|
|
cancelCtx, cancel := context.WithTimeout(context.Background(), 2*time.Millisecond)
|
|
defer cancel()
|
|
_, err := client.Event.List(cancelCtx)
|
|
if err == nil {
|
|
t.Error("expected there to be a cancel error")
|
|
}
|
|
}
|
|
|
|
func TestContextDeadline(t *testing.T) {
|
|
testTimeout := time.After(3 * time.Second)
|
|
testDone := make(chan struct{})
|
|
|
|
deadline := time.Now().Add(100 * time.Millisecond)
|
|
deadlineCtx, cancel := context.WithDeadline(context.Background(), deadline)
|
|
defer cancel()
|
|
|
|
go func() {
|
|
client := opencode.NewClient(
|
|
option.WithHTTPClient(&http.Client{
|
|
Transport: &closureTransport{
|
|
fn: func(req *http.Request) (*http.Response, error) {
|
|
<-req.Context().Done()
|
|
return nil, req.Context().Err()
|
|
},
|
|
},
|
|
}),
|
|
)
|
|
_, err := client.Event.List(deadlineCtx)
|
|
if err == nil {
|
|
t.Error("expected there to be a deadline error")
|
|
}
|
|
close(testDone)
|
|
}()
|
|
|
|
select {
|
|
case <-testTimeout:
|
|
t.Fatal("client didn't finish in time")
|
|
case <-testDone:
|
|
if diff := time.Since(deadline); diff < -30*time.Millisecond || 30*time.Millisecond < diff {
|
|
t.Fatalf("client did not return within 30ms of context deadline, got %s", diff)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestContextDeadlineStreaming(t *testing.T) {
|
|
testTimeout := time.After(3 * time.Second)
|
|
testDone := make(chan struct{})
|
|
|
|
deadline := time.Now().Add(100 * time.Millisecond)
|
|
deadlineCtx, cancel := context.WithDeadline(context.Background(), deadline)
|
|
defer cancel()
|
|
|
|
go func() {
|
|
client := opencode.NewClient(
|
|
option.WithHTTPClient(&http.Client{
|
|
Transport: &closureTransport{
|
|
fn: func(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{
|
|
StatusCode: 200,
|
|
Status: "200 OK",
|
|
Body: io.NopCloser(
|
|
io.Reader(readerFunc(func([]byte) (int, error) {
|
|
<-req.Context().Done()
|
|
return 0, req.Context().Err()
|
|
})),
|
|
),
|
|
}, nil
|
|
},
|
|
},
|
|
}),
|
|
)
|
|
stream := client.Event.ListStreaming(deadlineCtx)
|
|
for stream.Next() {
|
|
_ = stream.Current()
|
|
}
|
|
if stream.Err() == nil {
|
|
t.Error("expected there to be a deadline error")
|
|
}
|
|
close(testDone)
|
|
}()
|
|
|
|
select {
|
|
case <-testTimeout:
|
|
t.Fatal("client didn't finish in time")
|
|
case <-testDone:
|
|
if diff := time.Since(deadline); diff < -30*time.Millisecond || 30*time.Millisecond < diff {
|
|
t.Fatalf("client did not return within 30ms of context deadline, got %s", diff)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestContextDeadlineStreamingWithRequestTimeout(t *testing.T) {
|
|
testTimeout := time.After(3 * time.Second)
|
|
testDone := make(chan struct{})
|
|
deadline := time.Now().Add(100 * time.Millisecond)
|
|
|
|
go func() {
|
|
client := opencode.NewClient(
|
|
option.WithHTTPClient(&http.Client{
|
|
Transport: &closureTransport{
|
|
fn: func(req *http.Request) (*http.Response, error) {
|
|
return &http.Response{
|
|
StatusCode: 200,
|
|
Status: "200 OK",
|
|
Body: io.NopCloser(
|
|
io.Reader(readerFunc(func([]byte) (int, error) {
|
|
<-req.Context().Done()
|
|
return 0, req.Context().Err()
|
|
})),
|
|
),
|
|
}, nil
|
|
},
|
|
},
|
|
}),
|
|
)
|
|
stream := client.Event.ListStreaming(context.Background(), option.WithRequestTimeout((100 * time.Millisecond)))
|
|
for stream.Next() {
|
|
_ = stream.Current()
|
|
}
|
|
if stream.Err() == nil {
|
|
t.Error("expected there to be a deadline error")
|
|
}
|
|
close(testDone)
|
|
}()
|
|
|
|
select {
|
|
case <-testTimeout:
|
|
t.Fatal("client didn't finish in time")
|
|
case <-testDone:
|
|
if diff := time.Since(deadline); diff < -30*time.Millisecond || 30*time.Millisecond < diff {
|
|
t.Fatalf("client did not return within 30ms of context deadline, got %s", diff)
|
|
}
|
|
}
|
|
}
|
|
|
|
type readerFunc func([]byte) (int, error)
|
|
|
|
func (f readerFunc) Read(p []byte) (int, error) { return f(p) }
|
|
func (f readerFunc) Close() error { return nil }
|