mgmt_api_test.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. package http
  2. import (
  3. "io"
  4. "log/slog"
  5. "net/http"
  6. "net/http/httptest"
  7. "strings"
  8. "testing"
  9. "github.com/mk6i/retro-aim-server/state"
  10. "github.com/stretchr/testify/mock"
  11. )
  12. func TestSessionHandler_GET(t *testing.T) {
  13. fnNewSess := func(screenName string) *state.Session {
  14. sess := state.NewSession()
  15. sess.SetScreenName(screenName)
  16. return sess
  17. }
  18. tt := []struct {
  19. name string
  20. sessions []*state.Session
  21. userHandlerErr error
  22. want string
  23. statusCode int
  24. }{
  25. {
  26. name: "without sessions",
  27. sessions: []*state.Session{},
  28. want: `{"count":0,"sessions":[]}`,
  29. statusCode: http.StatusOK,
  30. },
  31. {
  32. name: "with sessions",
  33. sessions: []*state.Session{
  34. fnNewSess("userA"),
  35. fnNewSess("userB"),
  36. },
  37. want: `{"count":2,"sessions":[{"screen_name":"userA"},{"screen_name":"userB"}]}`,
  38. statusCode: http.StatusOK,
  39. },
  40. }
  41. for _, tc := range tt {
  42. t.Run(tc.name, func(t *testing.T) {
  43. request := httptest.NewRequest(http.MethodGet, "/session", nil)
  44. responseRecorder := httptest.NewRecorder()
  45. sessionRetriever := newMockSessionRetriever(t)
  46. sessionRetriever.EXPECT().
  47. AllSessions().
  48. Return(tc.sessions)
  49. sessionHandler(responseRecorder, request, sessionRetriever)
  50. if responseRecorder.Code != tc.statusCode {
  51. t.Errorf("Want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
  52. }
  53. if strings.TrimSpace(responseRecorder.Body.String()) != tc.want {
  54. t.Errorf("Want '%s', got '%s'", tc.want, responseRecorder.Body)
  55. }
  56. })
  57. }
  58. }
  59. func TestSessionHandler_DisallowedMethod(t *testing.T) {
  60. request := httptest.NewRequest(http.MethodPut, "/session", nil)
  61. responseRecorder := httptest.NewRecorder()
  62. sessionHandler(responseRecorder, request, nil)
  63. wantCode := http.StatusMethodNotAllowed
  64. if responseRecorder.Code != wantCode {
  65. t.Errorf("want status '%d', got '%d'", http.StatusMethodNotAllowed, responseRecorder.Code)
  66. }
  67. wantBody := `method not allowed`
  68. if strings.TrimSpace(responseRecorder.Body.String()) != wantBody {
  69. t.Errorf("want '%s', got '%s'", wantBody, responseRecorder.Body)
  70. }
  71. }
  72. func TestUserHandler_GET(t *testing.T) {
  73. tt := []struct {
  74. name string
  75. users []state.User
  76. userHandlerErr error
  77. want string
  78. statusCode int
  79. }{
  80. {
  81. name: "empty user store",
  82. users: []state.User{},
  83. want: `[]`,
  84. statusCode: http.StatusOK,
  85. },
  86. {
  87. name: "user store containing 2 users",
  88. users: []state.User{
  89. {ScreenName: "userA"},
  90. {ScreenName: "userB"},
  91. },
  92. want: `[{"screen_name":"userA"},{"screen_name":"userB"}]`,
  93. statusCode: http.StatusOK,
  94. },
  95. {
  96. name: "user handler error",
  97. users: []state.User{},
  98. userHandlerErr: io.EOF,
  99. want: `internal server error`,
  100. statusCode: http.StatusInternalServerError,
  101. },
  102. }
  103. for _, tc := range tt {
  104. t.Run(tc.name, func(t *testing.T) {
  105. request := httptest.NewRequest(http.MethodGet, "/user", nil)
  106. responseRecorder := httptest.NewRecorder()
  107. userManager := newMockUserManager(t)
  108. userManager.EXPECT().
  109. AllUsers().
  110. Return(tc.users, tc.userHandlerErr)
  111. userHandler(responseRecorder, request, userManager, slog.Default())
  112. if responseRecorder.Code != tc.statusCode {
  113. t.Errorf("Want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
  114. }
  115. if strings.TrimSpace(responseRecorder.Body.String()) != tc.want {
  116. t.Errorf("Want '%s', got '%s'", tc.want, responseRecorder.Body)
  117. }
  118. })
  119. }
  120. }
  121. func TestUserHandler_POST(t *testing.T) {
  122. tt := []struct {
  123. name string
  124. body string
  125. user state.User
  126. userHandlerErr error
  127. want string
  128. statusCode int
  129. }{
  130. {
  131. name: "with valid user",
  132. body: `{"screen_name":"userA", "password":"thepassword"}`,
  133. user: state.User{
  134. ScreenName: "userA",
  135. },
  136. want: `User account created successfully.`,
  137. statusCode: http.StatusCreated,
  138. },
  139. {
  140. name: "with malformed body",
  141. body: `{"screen_name":"userA", "password":"thepassword"`,
  142. user: state.User{
  143. ScreenName: "userA",
  144. },
  145. want: `malformed input`,
  146. statusCode: http.StatusBadRequest,
  147. },
  148. {
  149. name: "user handler error",
  150. body: `{"screen_name":"userA", "password":"thepassword"}`,
  151. user: state.User{
  152. ScreenName: "userA",
  153. },
  154. userHandlerErr: io.EOF,
  155. want: `internal server error`,
  156. statusCode: http.StatusInternalServerError,
  157. },
  158. }
  159. for _, tc := range tt {
  160. t.Run(tc.name, func(t *testing.T) {
  161. request := httptest.NewRequest(http.MethodPost, "/user", strings.NewReader(tc.body))
  162. responseRecorder := httptest.NewRecorder()
  163. userManager := newMockUserManager(t)
  164. userManager.EXPECT().
  165. InsertUser(mock.Anything). // todo make this more concrete
  166. Return(tc.userHandlerErr).
  167. Maybe()
  168. userHandler(responseRecorder, request, userManager, slog.Default())
  169. if responseRecorder.Code != tc.statusCode {
  170. t.Errorf("want status '%d', got '%d'", tc.statusCode, responseRecorder.Code)
  171. }
  172. if strings.TrimSpace(responseRecorder.Body.String()) != tc.want {
  173. t.Errorf("want '%s', got '%s'", tc.want, responseRecorder.Body)
  174. }
  175. })
  176. }
  177. }
  178. func TestUserHandler_DisallowedMethod(t *testing.T) {
  179. request := httptest.NewRequest(http.MethodPut, "/user", nil)
  180. responseRecorder := httptest.NewRecorder()
  181. userHandler(responseRecorder, request, nil, nil)
  182. wantCode := http.StatusMethodNotAllowed
  183. if responseRecorder.Code != wantCode {
  184. t.Errorf("want status '%d', got '%d'", http.StatusMethodNotAllowed, responseRecorder.Code)
  185. }
  186. wantBody := `method not allowed`
  187. if strings.TrimSpace(responseRecorder.Body.String()) != wantBody {
  188. t.Errorf("want '%s', got '%s'", wantBody, responseRecorder.Body)
  189. }
  190. }