buddylist_test.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. package handlers
  2. import (
  3. "context"
  4. "errors"
  5. "log/slog"
  6. "net/http"
  7. "net/http/httptest"
  8. "net/url"
  9. "strings"
  10. "testing"
  11. "time"
  12. "github.com/stretchr/testify/assert"
  13. "github.com/stretchr/testify/mock"
  14. "github.com/mk6i/open-oscar-server/server/webapi/types"
  15. "github.com/mk6i/open-oscar-server/state"
  16. "github.com/mk6i/open-oscar-server/wire"
  17. )
  18. // MockWebAPISessionManager is a mock implementation of the WebAPISessionManager
  19. type MockWebAPISessionManager struct {
  20. mock.Mock
  21. }
  22. func (m *MockWebAPISessionManager) GetSession(ctx context.Context, aimsid string) (*state.WebAPISession, error) {
  23. args := m.Called(ctx, aimsid)
  24. if session := args.Get(0); session != nil {
  25. return session.(*state.WebAPISession), args.Error(1)
  26. }
  27. return nil, args.Error(1)
  28. }
  29. func (m *MockWebAPISessionManager) TouchSession(ctx context.Context, aimsid string) error {
  30. args := m.Called(ctx, aimsid)
  31. return args.Error(0)
  32. }
  33. // MockFeedbagManager is a mock implementation of FeedbagManager
  34. type MockFeedbagManager struct {
  35. mock.Mock
  36. }
  37. func (m *MockFeedbagManager) RetrieveFeedbag(ctx context.Context, screenName state.IdentScreenName) ([]wire.FeedbagItem, error) {
  38. args := m.Called(ctx, screenName)
  39. if items := args.Get(0); items != nil {
  40. return items.([]wire.FeedbagItem), args.Error(1)
  41. }
  42. return nil, args.Error(1)
  43. }
  44. func (m *MockFeedbagManager) InsertItem(ctx context.Context, screenName state.IdentScreenName, item wire.FeedbagItem) error {
  45. args := m.Called(ctx, screenName, item)
  46. return args.Error(0)
  47. }
  48. func (m *MockFeedbagManager) UpdateItem(ctx context.Context, screenName state.IdentScreenName, item wire.FeedbagItem) error {
  49. args := m.Called(ctx, screenName, item)
  50. return args.Error(0)
  51. }
  52. func (m *MockFeedbagManager) DeleteItem(ctx context.Context, screenName state.IdentScreenName, item wire.FeedbagItem) error {
  53. args := m.Called(ctx, screenName, item)
  54. return args.Error(0)
  55. }
  56. func TestBuddyListHandler_AddTempBuddy(t *testing.T) {
  57. tests := []struct {
  58. name string
  59. queryParams map[string][]string
  60. setupMocks func(*MockWebAPISessionManager, *MockFeedbagManager, string)
  61. expectedStatusCode int
  62. expectedResponse string
  63. checkSession func(*testing.T, *state.WebAPISession)
  64. }{
  65. {
  66. name: "Success_SingleBuddy",
  67. queryParams: map[string][]string{
  68. "aimsid": {"test-session-id"},
  69. "t": {"buddy1"},
  70. },
  71. setupMocks: func(sm *MockWebAPISessionManager, fm *MockFeedbagManager, aimsid string) {
  72. session := &state.WebAPISession{
  73. AimSID: aimsid,
  74. ScreenName: state.DisplayScreenName("testuser"),
  75. EventQueue: types.NewEventQueue(100),
  76. TempBuddies: nil,
  77. LastAccessed: time.Now(),
  78. }
  79. sm.On("GetSession", mock.Anything, aimsid).Return(session, nil)
  80. sm.On("TouchSession", mock.Anything, aimsid).Return(nil)
  81. },
  82. expectedStatusCode: http.StatusOK,
  83. expectedResponse: `{"response":{"statusCode":200,"statusText":"OK","data":{"buddyNames":["buddy1"],"resultCode":"success"}}}`,
  84. checkSession: func(t *testing.T, session *state.WebAPISession) {
  85. assert.NotNil(t, session.TempBuddies)
  86. assert.True(t, session.TempBuddies["buddy1"])
  87. assert.Equal(t, 1, len(session.TempBuddies))
  88. },
  89. },
  90. {
  91. name: "Success_MultipleBuddies",
  92. queryParams: map[string][]string{
  93. "aimsid": {"test-session-id"},
  94. "t": {"buddy1", "buddy2", "buddy3"},
  95. },
  96. setupMocks: func(sm *MockWebAPISessionManager, fm *MockFeedbagManager, aimsid string) {
  97. session := &state.WebAPISession{
  98. AimSID: aimsid,
  99. ScreenName: state.DisplayScreenName("testuser"),
  100. EventQueue: types.NewEventQueue(100),
  101. TempBuddies: nil,
  102. LastAccessed: time.Now(),
  103. }
  104. sm.On("GetSession", mock.Anything, aimsid).Return(session, nil)
  105. sm.On("TouchSession", mock.Anything, aimsid).Return(nil)
  106. },
  107. expectedStatusCode: http.StatusOK,
  108. expectedResponse: `{"response":{"statusCode":200,"statusText":"OK","data":{"buddyNames":["buddy1","buddy2","buddy3"],"resultCode":"success"}}}`,
  109. checkSession: func(t *testing.T, session *state.WebAPISession) {
  110. assert.NotNil(t, session.TempBuddies)
  111. assert.True(t, session.TempBuddies["buddy1"])
  112. assert.True(t, session.TempBuddies["buddy2"])
  113. assert.True(t, session.TempBuddies["buddy3"])
  114. assert.Equal(t, 3, len(session.TempBuddies))
  115. },
  116. },
  117. {
  118. name: "Success_AddToExistingTempBuddies",
  119. queryParams: map[string][]string{
  120. "aimsid": {"test-session-id"},
  121. "t": {"buddy2"},
  122. },
  123. setupMocks: func(sm *MockWebAPISessionManager, fm *MockFeedbagManager, aimsid string) {
  124. session := &state.WebAPISession{
  125. AimSID: aimsid,
  126. ScreenName: state.DisplayScreenName("testuser"),
  127. EventQueue: types.NewEventQueue(100),
  128. TempBuddies: map[string]bool{
  129. "buddy1": true,
  130. },
  131. LastAccessed: time.Now(),
  132. }
  133. sm.On("GetSession", mock.Anything, aimsid).Return(session, nil)
  134. sm.On("TouchSession", mock.Anything, aimsid).Return(nil)
  135. },
  136. expectedStatusCode: http.StatusOK,
  137. expectedResponse: `{"response":{"statusCode":200,"statusText":"OK","data":{"buddyNames":["buddy2"],"resultCode":"success"}}}`,
  138. checkSession: func(t *testing.T, session *state.WebAPISession) {
  139. assert.NotNil(t, session.TempBuddies)
  140. assert.True(t, session.TempBuddies["buddy1"])
  141. assert.True(t, session.TempBuddies["buddy2"])
  142. assert.Equal(t, 2, len(session.TempBuddies))
  143. },
  144. },
  145. {
  146. name: "Error_MissingAimSID",
  147. queryParams: map[string][]string{
  148. "t": {"buddy1"},
  149. },
  150. setupMocks: func(sm *MockWebAPISessionManager, fm *MockFeedbagManager, aimsid string) {},
  151. expectedStatusCode: http.StatusBadRequest,
  152. expectedResponse: `{"response":{"statusCode":400,"statusText":"missing aimsid parameter"}}`,
  153. },
  154. {
  155. name: "Error_MissingBuddyNames",
  156. queryParams: map[string][]string{
  157. "aimsid": {"test-session-id"},
  158. },
  159. setupMocks: func(sm *MockWebAPISessionManager, fm *MockFeedbagManager, aimsid string) {
  160. session := &state.WebAPISession{
  161. AimSID: aimsid,
  162. ScreenName: state.DisplayScreenName("testuser"),
  163. EventQueue: types.NewEventQueue(100),
  164. LastAccessed: time.Now(),
  165. }
  166. sm.On("GetSession", mock.Anything, aimsid).Return(session, nil)
  167. sm.On("TouchSession", mock.Anything, aimsid).Return(nil)
  168. },
  169. expectedStatusCode: http.StatusBadRequest,
  170. expectedResponse: `{"response":{"statusCode":400,"statusText":"missing buddy names (t parameter)"}}`,
  171. },
  172. {
  173. name: "Error_SessionNotFound",
  174. queryParams: map[string][]string{
  175. "aimsid": {"invalid-session"},
  176. "t": {"buddy1"},
  177. },
  178. setupMocks: func(sm *MockWebAPISessionManager, fm *MockFeedbagManager, aimsid string) {
  179. sm.On("GetSession", mock.Anything, aimsid).Return(nil, state.ErrNoWebAPISession)
  180. },
  181. expectedStatusCode: http.StatusNotFound,
  182. expectedResponse: `{"response":{"statusCode":404,"statusText":"session not found"}}`,
  183. },
  184. {
  185. name: "Error_SessionExpired",
  186. queryParams: map[string][]string{
  187. "aimsid": {"expired-session"},
  188. "t": {"buddy1"},
  189. },
  190. setupMocks: func(sm *MockWebAPISessionManager, fm *MockFeedbagManager, aimsid string) {
  191. sm.On("GetSession", mock.Anything, aimsid).Return(nil, state.ErrWebAPISessionExpired)
  192. },
  193. expectedStatusCode: http.StatusGone,
  194. expectedResponse: `{"response":{"statusCode":410,"statusText":"session expired"}}`,
  195. },
  196. {
  197. name: "Error_InternalServerError",
  198. queryParams: map[string][]string{
  199. "aimsid": {"test-session-id"},
  200. "t": {"buddy1"},
  201. },
  202. setupMocks: func(sm *MockWebAPISessionManager, fm *MockFeedbagManager, aimsid string) {
  203. sm.On("GetSession", mock.Anything, aimsid).Return(nil, errors.New("database error"))
  204. },
  205. expectedStatusCode: http.StatusInternalServerError,
  206. expectedResponse: `{"response":{"statusCode":500,"statusText":"internal server error"}}`,
  207. },
  208. {
  209. name: "Success_WithWhitespace",
  210. queryParams: map[string][]string{
  211. "aimsid": {"test-session-id"},
  212. "t": {" buddy1 ", "buddy2 ", " buddy3"},
  213. },
  214. setupMocks: func(sm *MockWebAPISessionManager, fm *MockFeedbagManager, aimsid string) {
  215. session := &state.WebAPISession{
  216. AimSID: aimsid,
  217. ScreenName: state.DisplayScreenName("testuser"),
  218. EventQueue: types.NewEventQueue(100),
  219. TempBuddies: nil,
  220. LastAccessed: time.Now(),
  221. }
  222. sm.On("GetSession", mock.Anything, aimsid).Return(session, nil)
  223. sm.On("TouchSession", mock.Anything, aimsid).Return(nil)
  224. },
  225. expectedStatusCode: http.StatusOK,
  226. expectedResponse: `{"response":{"statusCode":200,"statusText":"OK","data":{"buddyNames":[" buddy1 ","buddy2 "," buddy3"],"resultCode":"success"}}}`,
  227. checkSession: func(t *testing.T, session *state.WebAPISession) {
  228. assert.NotNil(t, session.TempBuddies)
  229. assert.True(t, session.TempBuddies["buddy1"])
  230. assert.True(t, session.TempBuddies["buddy2"])
  231. assert.True(t, session.TempBuddies["buddy3"])
  232. assert.Equal(t, 3, len(session.TempBuddies))
  233. },
  234. },
  235. }
  236. for _, tt := range tests {
  237. t.Run(tt.name, func(t *testing.T) {
  238. // Setup
  239. sessionManager := &MockWebAPISessionManager{}
  240. feedbagManager := &MockFeedbagManager{}
  241. logger := slog.Default()
  242. handler := &BuddyListHandler{
  243. SessionManager: sessionManager,
  244. FeedbagManager: feedbagManager,
  245. Logger: logger,
  246. }
  247. aimsid := ""
  248. if aimsids, ok := tt.queryParams["aimsid"]; ok && len(aimsids) > 0 {
  249. aimsid = aimsids[0]
  250. }
  251. tt.setupMocks(sessionManager, feedbagManager, aimsid)
  252. // Create request with query parameters
  253. reqURL := "/aim/addTempBuddy"
  254. if len(tt.queryParams) > 0 {
  255. values := url.Values{}
  256. for key, vals := range tt.queryParams {
  257. for _, val := range vals {
  258. values.Add(key, val)
  259. }
  260. }
  261. reqURL += "?" + values.Encode()
  262. }
  263. req, err := http.NewRequest("GET", reqURL, nil)
  264. assert.NoError(t, err)
  265. // Create response recorder
  266. rr := httptest.NewRecorder()
  267. // Execute
  268. handler.AddTempBuddy(rr, req)
  269. // Verify status code
  270. assert.Equal(t, tt.expectedStatusCode, rr.Code)
  271. // Verify response body
  272. responseBody := strings.TrimSpace(rr.Body.String())
  273. assert.Equal(t, tt.expectedResponse, responseBody)
  274. // Check session state if provided
  275. if tt.checkSession != nil && aimsid != "" {
  276. // Get the session from mock to verify state
  277. for _, call := range sessionManager.Calls {
  278. if call.Method == "GetSession" {
  279. if session, ok := call.ReturnArguments[0].(*state.WebAPISession); ok {
  280. tt.checkSession(t, session)
  281. break
  282. }
  283. }
  284. }
  285. }
  286. // Verify all mock expectations were met
  287. sessionManager.AssertExpectations(t)
  288. feedbagManager.AssertExpectations(t)
  289. })
  290. }
  291. }
  292. func TestBuddyListHandler_AddTempBuddy_EventQueueBehavior(t *testing.T) {
  293. // Test that events are properly added to the event queue
  294. sessionManager := &MockWebAPISessionManager{}
  295. feedbagManager := &MockFeedbagManager{}
  296. logger := slog.Default()
  297. handler := &BuddyListHandler{
  298. SessionManager: sessionManager,
  299. FeedbagManager: feedbagManager,
  300. Logger: logger,
  301. }
  302. eventQueue := types.NewEventQueue(100)
  303. session := &state.WebAPISession{
  304. AimSID: "test-session",
  305. ScreenName: state.DisplayScreenName("testuser"),
  306. EventQueue: eventQueue,
  307. TempBuddies: nil,
  308. LastAccessed: time.Now(),
  309. }
  310. sessionManager.On("GetSession", mock.Anything, "test-session").Return(session, nil)
  311. sessionManager.On("TouchSession", mock.Anything, "test-session").Return(nil)
  312. req, err := http.NewRequest("GET", "/aim/addTempBuddy?aimsid=test-session&t=buddy1&t=buddy2", nil)
  313. assert.NoError(t, err)
  314. rr := httptest.NewRecorder()
  315. handler.AddTempBuddy(rr, req)
  316. // Verify that events were added to the queue
  317. assert.Equal(t, http.StatusOK, rr.Code)
  318. // Check that the event queue has the correct number of events
  319. events := eventQueue.GetAllEvents()
  320. assert.GreaterOrEqual(t, len(events), 2, "Should have at least 2 events for 2 buddies")
  321. // Verify event content
  322. for _, event := range events {
  323. assert.Equal(t, types.EventTypeBuddyList, event.Type)
  324. eventData, ok := event.Data.(types.BuddyListEvent)
  325. assert.True(t, ok, "Event data should be BuddyListEvent")
  326. assert.Equal(t, "addTemp", eventData.Action)
  327. assert.NotNil(t, eventData.Buddy)
  328. buddyInfo, ok := eventData.Buddy.(*BuddyPresenceInfo)
  329. assert.True(t, ok, "Buddy should be *BuddyPresenceInfo")
  330. if ok {
  331. assert.Contains(t, []string{"buddy1", "buddy2"}, buddyInfo.AimID)
  332. assert.Equal(t, "offline", buddyInfo.State)
  333. assert.Equal(t, "aim", buddyInfo.UserType)
  334. }
  335. }
  336. sessionManager.AssertExpectations(t)
  337. }
  338. func TestBuddyListHandler_AddBuddy(t *testing.T) {
  339. tests := []struct {
  340. name string
  341. queryParams map[string][]string
  342. setupMocks func(*MockWebAPISessionManager, *MockFeedbagManager, string)
  343. expectedStatusCode int
  344. expectedResponse string
  345. }{
  346. {
  347. name: "Success_AddBuddyToExistingGroup",
  348. queryParams: map[string][]string{
  349. "aimsid": {"test-session"},
  350. "buddy": {"newbuddy"},
  351. "group": {"Friends"},
  352. },
  353. setupMocks: func(sm *MockWebAPISessionManager, fm *MockFeedbagManager, aimsid string) {
  354. session := &state.WebAPISession{
  355. AimSID: aimsid,
  356. ScreenName: state.DisplayScreenName("testuser"),
  357. EventQueue: types.NewEventQueue(100),
  358. LastAccessed: time.Now(),
  359. }
  360. sm.On("GetSession", mock.Anything, aimsid).Return(session, nil)
  361. sm.On("TouchSession", mock.Anything, aimsid).Return(nil)
  362. // Mock feedbag retrieval with existing group
  363. existingItems := []wire.FeedbagItem{
  364. {
  365. ItemID: 1,
  366. ClassID: wire.FeedbagClassIdGroup,
  367. Name: "Friends",
  368. GroupID: 0,
  369. },
  370. }
  371. fm.On("RetrieveFeedbag", mock.Anything, state.NewIdentScreenName("testuser")).
  372. Return(existingItems, nil)
  373. // Mock buddy insertion
  374. fm.On("InsertItem", mock.Anything, state.NewIdentScreenName("testuser"), mock.MatchedBy(func(item wire.FeedbagItem) bool {
  375. return item.ClassID == wire.FeedbagClassIdBuddy &&
  376. item.Name == "newbuddy" &&
  377. item.GroupID == 1
  378. })).Return(nil)
  379. },
  380. expectedStatusCode: http.StatusOK,
  381. expectedResponse: `{"response":{"statusCode":200,"statusText":"OK","data":{"buddyInfo":{"aimId":"newbuddy","state":"offline","userType":"aim"},"resultCode":"success"}}}`,
  382. },
  383. {
  384. name: "Success_AddBuddyCreateNewGroup",
  385. queryParams: map[string][]string{
  386. "aimsid": {"test-session"},
  387. "buddy": {"newbuddy"},
  388. "group": {"NewGroup"},
  389. },
  390. setupMocks: func(sm *MockWebAPISessionManager, fm *MockFeedbagManager, aimsid string) {
  391. session := &state.WebAPISession{
  392. AimSID: aimsid,
  393. ScreenName: state.DisplayScreenName("testuser"),
  394. EventQueue: types.NewEventQueue(100),
  395. LastAccessed: time.Now(),
  396. }
  397. sm.On("GetSession", mock.Anything, aimsid).Return(session, nil)
  398. sm.On("TouchSession", mock.Anything, aimsid).Return(nil)
  399. // Mock feedbag retrieval with no existing groups
  400. fm.On("RetrieveFeedbag", mock.Anything, state.NewIdentScreenName("testuser")).
  401. Return([]wire.FeedbagItem{}, nil)
  402. // Mock group creation
  403. fm.On("InsertItem", mock.Anything, state.NewIdentScreenName("testuser"), mock.MatchedBy(func(item wire.FeedbagItem) bool {
  404. return item.ClassID == wire.FeedbagClassIdGroup &&
  405. item.Name == "NewGroup" &&
  406. item.ItemID == 1
  407. })).Return(nil)
  408. // Mock buddy insertion
  409. fm.On("InsertItem", mock.Anything, state.NewIdentScreenName("testuser"), mock.MatchedBy(func(item wire.FeedbagItem) bool {
  410. return item.ClassID == wire.FeedbagClassIdBuddy &&
  411. item.Name == "newbuddy" &&
  412. item.GroupID == 1
  413. })).Return(nil)
  414. },
  415. expectedStatusCode: http.StatusOK,
  416. expectedResponse: `{"response":{"statusCode":200,"statusText":"OK","data":{"buddyInfo":{"aimId":"newbuddy","state":"offline","userType":"aim"},"resultCode":"success"}}}`,
  417. },
  418. {
  419. name: "Error_BuddyAlreadyExists",
  420. queryParams: map[string][]string{
  421. "aimsid": {"test-session"},
  422. "buddy": {"existingbuddy"},
  423. "group": {"Friends"},
  424. },
  425. setupMocks: func(sm *MockWebAPISessionManager, fm *MockFeedbagManager, aimsid string) {
  426. session := &state.WebAPISession{
  427. AimSID: aimsid,
  428. ScreenName: state.DisplayScreenName("testuser"),
  429. EventQueue: types.NewEventQueue(100),
  430. LastAccessed: time.Now(),
  431. }
  432. sm.On("GetSession", mock.Anything, aimsid).Return(session, nil)
  433. sm.On("TouchSession", mock.Anything, aimsid).Return(nil)
  434. // Mock feedbag retrieval with existing buddy
  435. existingItems := []wire.FeedbagItem{
  436. {
  437. ItemID: 1,
  438. ClassID: wire.FeedbagClassIdBuddy,
  439. Name: "existingbuddy",
  440. GroupID: 1,
  441. },
  442. }
  443. fm.On("RetrieveFeedbag", mock.Anything, state.NewIdentScreenName("testuser")).
  444. Return(existingItems, nil)
  445. },
  446. expectedStatusCode: http.StatusOK,
  447. expectedResponse: `{"response":{"statusCode":200,"statusText":"OK","data":{"resultCode":"alreadyExists"}}}`,
  448. },
  449. {
  450. name: "Error_MissingBuddyParameter",
  451. queryParams: map[string][]string{
  452. "aimsid": {"test-session"},
  453. "group": {"Friends"},
  454. },
  455. setupMocks: func(sm *MockWebAPISessionManager, fm *MockFeedbagManager, aimsid string) {
  456. session := &state.WebAPISession{
  457. AimSID: aimsid,
  458. ScreenName: state.DisplayScreenName("testuser"),
  459. EventQueue: types.NewEventQueue(100),
  460. LastAccessed: time.Now(),
  461. }
  462. sm.On("GetSession", mock.Anything, aimsid).Return(session, nil)
  463. sm.On("TouchSession", mock.Anything, aimsid).Return(nil)
  464. },
  465. expectedStatusCode: http.StatusBadRequest,
  466. expectedResponse: `{"response":{"statusCode":400,"statusText":"missing buddy parameter"}}`,
  467. },
  468. }
  469. for _, tt := range tests {
  470. t.Run(tt.name, func(t *testing.T) {
  471. // Setup
  472. sessionManager := &MockWebAPISessionManager{}
  473. feedbagManager := &MockFeedbagManager{}
  474. logger := slog.Default()
  475. handler := &BuddyListHandler{
  476. SessionManager: sessionManager,
  477. FeedbagManager: feedbagManager,
  478. Logger: logger,
  479. }
  480. aimsid := ""
  481. if aimsids, ok := tt.queryParams["aimsid"]; ok && len(aimsids) > 0 {
  482. aimsid = aimsids[0]
  483. }
  484. tt.setupMocks(sessionManager, feedbagManager, aimsid)
  485. // Create request
  486. reqURL := "/buddylist/addBuddy"
  487. if len(tt.queryParams) > 0 {
  488. values := url.Values{}
  489. for key, vals := range tt.queryParams {
  490. for _, val := range vals {
  491. values.Add(key, val)
  492. }
  493. }
  494. reqURL += "?" + values.Encode()
  495. }
  496. req, err := http.NewRequest("GET", reqURL, nil)
  497. assert.NoError(t, err)
  498. // Create response recorder
  499. rr := httptest.NewRecorder()
  500. // Execute
  501. handler.AddBuddy(rr, req)
  502. // Verify
  503. assert.Equal(t, tt.expectedStatusCode, rr.Code)
  504. responseBody := strings.TrimSpace(rr.Body.String())
  505. assert.Equal(t, tt.expectedResponse, responseBody)
  506. sessionManager.AssertExpectations(t)
  507. feedbagManager.AssertExpectations(t)
  508. })
  509. }
  510. }