| package testutil |
|
|
| import ( |
| "bytes" |
| "encoding/json" |
| "io" |
| "net/http" |
| "net/http/httptest" |
| "reflect" |
| "runtime" |
| "testing" |
| "time" |
|
|
| "github.com/gin-gonic/gin" |
| ) |
|
|
| func init() { |
| gin.SetMode(gin.TestMode) |
| } |
|
|
| |
| func NewTestContext(t testing.TB, req *http.Request) (*gin.Context, *httptest.ResponseRecorder) { |
| t.Helper() |
|
|
| w := httptest.NewRecorder() |
| c, _ := gin.CreateTestContext(w) |
| c.Request = req |
| return c, w |
| } |
|
|
| |
| func NewRecorder() *httptest.ResponseRecorder { |
| return httptest.NewRecorder() |
| } |
|
|
| func normalizeReader(r io.Reader) io.Reader { |
| if r == nil { |
| return nil |
| } |
| v := reflect.ValueOf(r) |
| switch v.Kind() { |
| case reflect.Pointer, reflect.Interface, reflect.Slice, reflect.Map, reflect.Func, reflect.Chan: |
| if v.IsNil() { |
| return nil |
| } |
| } |
| return r |
| } |
|
|
| |
| func NewRequestReader(method, target string, body io.Reader) *http.Request { |
| return httptest.NewRequest(method, target, normalizeReader(body)) |
| } |
|
|
| |
| func NewRequest(method, target string, body []byte) *http.Request { |
| var reader io.Reader |
| if body != nil { |
| reader = bytes.NewReader(body) |
| } |
| return NewRequestReader(method, target, reader) |
| } |
|
|
| |
| func NewJSONRequest(method, target string, v any) (*http.Request, error) { |
| b, err := json.Marshal(v) |
| if err != nil { |
| return nil, err |
| } |
| req := httptest.NewRequest(method, target, bytes.NewReader(b)) |
| req.Header.Set("Content-Type", "application/json") |
| return req, nil |
| } |
|
|
| |
| func MustNewJSONRequest(t testing.TB, method, target string, v any) *http.Request { |
| t.Helper() |
|
|
| req, err := NewJSONRequest(method, target, v) |
| if err != nil { |
| t.Fatalf("marshal json failed: %v", err) |
| } |
| return req |
| } |
|
|
| |
| func NewJSONRequestBytes(method, target string, b []byte) *http.Request { |
| req := httptest.NewRequest(method, target, bytes.NewReader(b)) |
| req.Header.Set("Content-Type", "application/json") |
| return req |
| } |
|
|
| |
| func ServeHTTP(t testing.TB, h http.Handler, req *http.Request) *httptest.ResponseRecorder { |
| t.Helper() |
|
|
| w := httptest.NewRecorder() |
| h.ServeHTTP(w, req) |
| return w |
| } |
|
|
| |
| func MustUnmarshalJSON(t testing.TB, b []byte, v any) { |
| t.Helper() |
| if err := json.Unmarshal(b, v); err != nil { |
| t.Fatalf("unmarshal json failed: %v", err) |
| } |
| } |
|
|
| |
| type APIResponse[T any] struct { |
| Success bool `json:"success"` |
| Data T `json:"data,omitempty"` |
| Error string `json:"error,omitempty"` |
| } |
|
|
| |
| func MustParseAPIResponse[T any](t testing.TB, body []byte) APIResponse[T] { |
| t.Helper() |
|
|
| var resp APIResponse[T] |
| MustUnmarshalJSON(t, body, &resp) |
| return resp |
| } |
|
|
| |
| |
| func WaitForGoroutineDeltaLE(t testing.TB, baseline int, maxDelta int, timeout time.Duration) int { |
| t.Helper() |
|
|
| if maxDelta < 0 { |
| maxDelta = 0 |
| } |
| deadline := time.Now().Add(timeout) |
| for { |
| runtime.GC() |
| cur := runtime.NumGoroutine() |
| if cur <= baseline+maxDelta { |
| return cur |
| } |
| if time.Now().After(deadline) { |
| return cur |
| } |
| time.Sleep(10 * time.Millisecond) |
| } |
| } |
|
|
| |
| func GetGoroutineBaseline() int { |
| runtime.GC() |
| return runtime.NumGoroutine() |
| } |
|
|