Files
aws-server-sdk/client_test.go
T
shiran 3d4c2dbb20
test / go (push) Successful in 1m7s
feat: initial AWS Server Go SDK
2026-08-22 22:14:08 +08:00

109 lines
3.5 KiB
Go

package awsserversdk
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"sync"
"testing"
"time"
)
func testClient(t *testing.T, handler http.HandlerFunc) (*Client, *httptest.Server) {
t.Helper()
server := httptest.NewServer(handler)
t.Cleanup(server.Close)
client, err := NewClient(server.URL, "awsapp_test_secret", WithMaxRetries(2))
if err != nil {
t.Fatal(err)
}
return client, server
}
func TestClientSendsAuthAndStableIdempotencyOnRetry(t *testing.T) {
var mutex sync.Mutex
attempts := 0
keys := []string{}
client, _ := testClient(t, func(w http.ResponseWriter, r *http.Request) {
mutex.Lock()
defer mutex.Unlock()
attempts++
keys = append(keys, r.Header.Get("Idempotency-Key"))
if r.Header.Get("Authorization") != "Bearer awsapp_test_secret" {
t.Errorf("missing auth header")
}
w.Header().Set("Content-Type", "application/json")
if attempts == 1 {
w.WriteHeader(503)
_, _ = w.Write([]byte(`{"code":503,"message":"retry"}`))
return
}
_, _ = w.Write([]byte(`{"code":202,"message":"Accepted","data":{"id":"local-1","task_id":"task-1","status":"queued"}}`))
})
operation, err := client.Instances.Create(context.Background(), "us-east-1", CreateInstanceRequest{ImageID: "ami-1", InstanceType: "t3.nano", PlacementID: "default"})
if err != nil {
t.Fatal(err)
}
if operation.TaskID != "task-1" || attempts != 2 {
t.Fatalf("unexpected operation %#v attempts=%d", operation, attempts)
}
if keys[0] == "" || keys[0] != keys[1] {
t.Fatalf("idempotency key changed: %#v", keys)
}
}
func TestAPIErrorAndHelpers(t *testing.T) {
client, _ := testClient(t, func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(409)
_, _ = w.Write([]byte(`{"code":409,"message":"budget","data":{"shortfall":1.25}}`))
})
_, err := client.Instances.Create(context.Background(), "us-east-1", CreateInstanceRequest{})
if err == nil || !IsConflict(err) || !IsBudgetExceeded(err) {
t.Fatalf("unexpected error %v", err)
}
}
func TestTaskWait(t *testing.T) {
calls := 0
client, _ := testClient(t, func(w http.ResponseWriter, r *http.Request) {
calls++
status := "running"
if calls > 1 {
status = "succeeded"
}
_ = json.NewEncoder(w).Encode(map[string]any{"code": 200, "message": "Success", "data": map[string]any{"id": "task-1", "status": status, "progress": 100}})
})
task, err := client.Tasks.Wait(context.Background(), "task-1", WithPollInterval(time.Millisecond))
if err != nil || task.Status != "succeeded" || calls != 2 {
t.Fatalf("task=%#v err=%v calls=%d", task, err, calls)
}
}
func TestSecretIsRedacted(t *testing.T) {
var secret Secret
if err := json.Unmarshal([]byte(`"very-secret"`), &secret); err != nil {
t.Fatal(err)
}
if secret.Reveal() != "very-secret" || secret.String() != "[REDACTED]" {
t.Fatal("secret behavior invalid")
}
raw, _ := json.Marshal(secret)
if string(raw) != `"[REDACTED]"` {
t.Fatalf("secret marshaled as %s", raw)
}
}
func TestListQueryParametersAreNotEscapedIntoPath(t *testing.T) {
client, _ := testClient(t, func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/api/sdk/v1/regions/us-east-1/images" || r.URL.Query().Get("q") != "ubuntu 24" || r.URL.Query().Get("limit") != "10" {
t.Errorf("unexpected URL %s", r.URL.String())
}
_, _ = w.Write([]byte(`{"code":200,"message":"Success","data":{"items":[],"total":0,"limit":10,"offset":0}}`))
})
if _, err := client.Catalog.ListImages(context.Background(), "us-east-1", ListOptions{Query: "ubuntu 24", Limit: 10}); err != nil {
t.Fatal(err)
}
}