1
0

test_server.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package testutil
  2. import (
  3. "context"
  4. "net/http"
  5. "net/http/httptest"
  6. "github.com/imgproxy/imgproxy/v3/httpheaders"
  7. "github.com/stretchr/testify/require"
  8. )
  9. // TestServerHookFunc is a function type for in-request hooks
  10. type TestServerHookFunc func(r *http.Request, rw http.ResponseWriter)
  11. // Sugar alias
  12. type LazyTestServer = LazyObj[*TestServer]
  13. // TestServer is a syntax sugar wrapper over httptest.Server
  14. type TestServer struct {
  15. testServer *httptest.Server
  16. status int
  17. data []byte
  18. header http.Header
  19. hook TestServerHookFunc
  20. }
  21. // NewLazySuiteTestServer creates a lazy TestServer object for use in test suites
  22. func NewLazySuiteTestServer(
  23. l LazySuiteFrom,
  24. init ...func(*TestServer) error,
  25. ) (LazyObj[*TestServer], context.CancelFunc) {
  26. return NewLazySuiteObj(
  27. l,
  28. func() (*TestServer, error) {
  29. s := NewTestServer()
  30. if len(init) > 0 {
  31. for _, fn := range init {
  32. if fn == nil {
  33. continue
  34. }
  35. err := fn(s)
  36. require.NoError(l.Lazy().T(), err, "Failed to reset test server")
  37. }
  38. }
  39. return s, nil
  40. },
  41. func(s *TestServer) error {
  42. s.Close()
  43. return nil
  44. },
  45. )
  46. }
  47. // New creates and starts new http.TestServer
  48. func NewTestServer() *TestServer {
  49. ts := &TestServer{
  50. status: http.StatusOK,
  51. header: make(http.Header),
  52. data: nil,
  53. hook: nil,
  54. }
  55. return ts.start()
  56. }
  57. // SetStatusCode sets the status code that will be returned by the server
  58. func (s *TestServer) SetStatusCode(status int) *TestServer {
  59. s.status = status
  60. return s
  61. }
  62. // SetBody sets the body that will be returned by the server
  63. func (s *TestServer) SetBody(data []byte) *TestServer {
  64. s.data = data
  65. return s
  66. }
  67. // WithHeader adds headers that will be returned by the server.
  68. // Odd arguments are treated as keys, even arguments as values.
  69. func (s *TestServer) SetHeaders(kv ...string) *TestServer {
  70. for i := 0; i+1 < len(kv); i += 2 {
  71. key := kv[i]
  72. value := kv[i+1]
  73. s.header.Set(key, value)
  74. }
  75. return s
  76. }
  77. // SetHook sets a function that will be called on each request. It is called
  78. // after headsers are set, but before status and body are written.
  79. func (s *TestServer) SetHook(f TestServerHookFunc) *TestServer {
  80. s.hook = f
  81. return s
  82. }
  83. // Start starts the server
  84. func (s *TestServer) start() *TestServer {
  85. s.testServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  86. httpheaders.CopyAll(s.header, w.Header(), true)
  87. if s.hook != nil {
  88. s.hook(r, w)
  89. }
  90. w.WriteHeader(s.status)
  91. w.Write(s.data)
  92. }))
  93. return s
  94. }
  95. // Close stops the server
  96. func (s *TestServer) Close() {
  97. s.testServer.Close()
  98. }
  99. // URL returns the server URL
  100. func (s *TestServer) URL() string {
  101. return s.testServer.URL
  102. }