http_test.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. package toc
  2. import (
  3. "encoding/base64"
  4. "io"
  5. "log/slog"
  6. "net/http"
  7. "net/http/httptest"
  8. "testing"
  9. "time"
  10. "github.com/stretchr/testify/assert"
  11. "github.com/stretchr/testify/mock"
  12. "golang.org/x/time/rate"
  13. "github.com/mk6i/open-oscar-server/state"
  14. "github.com/mk6i/open-oscar-server/wire"
  15. )
  16. func TestOSCARProxy_NewServeMux(t *testing.T) {
  17. cookieBaker, err := state.NewHMACCookieBaker()
  18. assert.NoError(t, err)
  19. p := OSCARProxy{
  20. CookieBaker: cookieBaker,
  21. Logger: slog.Default(),
  22. }
  23. cookie, err := p.newHTTPAuthToken(state.NewIdentScreenName("me"))
  24. assert.NoError(t, err)
  25. cases := []struct {
  26. // name is the unit test name
  27. name string
  28. // path is the HTTP request path
  29. path string
  30. // expectedStatus is the expected HTTP response code
  31. expectedStatus int
  32. // expectedBody is the expected body payload
  33. expectedBody string
  34. // mockParams is the list of params sent to mocks that satisfy this
  35. // method's dependencies
  36. mockParams mockParams
  37. }{
  38. {
  39. name: "Successfully retrieve HTML profile",
  40. path: "/info?from=me&user=them&cookie=" + cookie,
  41. expectedStatus: http.StatusOK,
  42. expectedBody: `<font lang="0"><a href="aim:GoChat?RoomName=General&amp;Exchange=4">Let's chat</font></a><br><br><font color="#ff0000" lang="0">colorfg</font><font color="#000000"> </font><font back="#00ff00">colorbg</font><font> </font><font size="4">big</font><font size="3"> <b></font><font>bold</b></font><font> <i></font><font>italic</i></font><font> <u></font><font>underline</u></font><font> 8-)</font><hr><s>strike</s><sub>sub</sub><sup>sup</sup>`,
  43. mockParams: mockParams{
  44. locateParams: locateParams{
  45. userInfoQueryParams: userInfoQueryParams{
  46. {
  47. me: state.NewIdentScreenName("me"),
  48. inBody: wire.SNAC_0x02_0x05_LocateUserInfoQuery{
  49. Type: uint16(wire.LocateTypeSig),
  50. ScreenName: "them",
  51. },
  52. msg: wire.SNACMessage{
  53. Frame: wire.SNACFrame{
  54. FoodGroup: wire.Locate,
  55. SubGroup: wire.LocateUserInfoReply,
  56. },
  57. Body: wire.SNAC_0x02_0x06_LocateUserInfoReply{
  58. TLVUserInfo: newTestSession("them").Session().TLVUserInfo(),
  59. LocateInfo: wire.TLVRestBlock{
  60. TLVList: wire.TLVList{
  61. wire.NewTLVBE(wire.LocateTLVTagsInfoSigData, `"<HTML><BODY BGCOLOR="#ffffff"><FONT LANG="0"><A HREF="aim:GoChat?RoomName=General&Exchange=4">Let's chat</FONT></A><BR><BR><FONT COLOR="#ff0000" LANG="0">colorfg</FONT><FONT COLOR="#000000"> </FONT><FONT BACK="#00ff00">colorbg</FONT><FONT> </FONT><FONT SIZE=4>big</FONT><FONT SIZE=3> <B></FONT><FONT>bold</B></FONT><FONT> <I></FONT><FONT>italic</I></FONT><FONT> <U></FONT><FONT>underline</U></FONT><FONT> 8-)</FONT><HR><S>strike</S><SUB>sub</SUB><SUP>sup</SUP></BODY></HTML>"`),
  62. },
  63. },
  64. },
  65. },
  66. },
  67. },
  68. },
  69. sessionRetrieverParams: sessionRetrieverParams{
  70. retrieveSessionParams: retrieveSessionParams{
  71. {
  72. screenName: state.NewIdentScreenName("me"),
  73. returnedSession: newTestSession("me").Session(),
  74. },
  75. },
  76. },
  77. },
  78. },
  79. {
  80. name: "Successfully retrieve plaintext profile",
  81. path: "/info?from=me&user=them&cookie=" + cookie,
  82. expectedStatus: http.StatusOK,
  83. expectedBody: "My profile!",
  84. mockParams: mockParams{
  85. locateParams: locateParams{
  86. userInfoQueryParams: userInfoQueryParams{
  87. {
  88. me: state.NewIdentScreenName("me"),
  89. inBody: wire.SNAC_0x02_0x05_LocateUserInfoQuery{
  90. Type: uint16(wire.LocateTypeSig),
  91. ScreenName: "them",
  92. },
  93. msg: wire.SNACMessage{
  94. Frame: wire.SNACFrame{
  95. FoodGroup: wire.Locate,
  96. SubGroup: wire.LocateUserInfoReply,
  97. },
  98. Body: wire.SNAC_0x02_0x06_LocateUserInfoReply{
  99. TLVUserInfo: newTestSession("them").Session().TLVUserInfo(),
  100. LocateInfo: wire.TLVRestBlock{
  101. TLVList: wire.TLVList{
  102. wire.NewTLVBE(wire.LocateTLVTagsInfoSigData, "My profile!"),
  103. },
  104. },
  105. },
  106. },
  107. },
  108. },
  109. },
  110. sessionRetrieverParams: sessionRetrieverParams{
  111. retrieveSessionParams: retrieveSessionParams{
  112. {
  113. screenName: state.NewIdentScreenName("me"),
  114. returnedSession: newTestSession("me").Session(),
  115. },
  116. },
  117. },
  118. },
  119. },
  120. {
  121. name: "Retrieve profile with missing `from` query param",
  122. path: "/info?user=them&cookie=" + cookie,
  123. expectedStatus: http.StatusBadRequest,
  124. expectedBody: "required `from` param is missing",
  125. },
  126. {
  127. name: "Retrieve profile with missing `from` query param",
  128. path: "/info?from=me&cookie=" + cookie,
  129. expectedStatus: http.StatusBadRequest,
  130. expectedBody: "required `user` param is missing",
  131. },
  132. {
  133. name: "Retrieve profile with missing `cookie` query param",
  134. path: "/info?from=me&user=them",
  135. expectedStatus: http.StatusBadRequest,
  136. expectedBody: "required `cookie` param is missing",
  137. },
  138. {
  139. name: "Retrieve profile with invalid auth cookie",
  140. path: func() string {
  141. return "/info?from=me&user=them&cookie=" + base64.URLEncoding.EncodeToString([]byte("blahblah"))
  142. }(),
  143. expectedStatus: http.StatusForbidden,
  144. expectedBody: "invalid auth cookie",
  145. },
  146. {
  147. name: "Retrieve profile, receive error from locate svc",
  148. path: "/info?from=me&user=them&cookie=" + cookie,
  149. expectedStatus: http.StatusInternalServerError,
  150. expectedBody: "internal server error",
  151. mockParams: mockParams{
  152. locateParams: locateParams{
  153. userInfoQueryParams: userInfoQueryParams{
  154. {
  155. me: state.NewIdentScreenName("me"),
  156. inBody: wire.SNAC_0x02_0x05_LocateUserInfoQuery{
  157. Type: uint16(wire.LocateTypeSig),
  158. ScreenName: "them",
  159. },
  160. msg: wire.SNACMessage{
  161. Frame: wire.SNACFrame{
  162. FoodGroup: wire.Locate,
  163. SubGroup: wire.LocateUserInfoReply,
  164. },
  165. Body: wire.SNAC_0x02_0x06_LocateUserInfoReply{
  166. TLVUserInfo: newTestSession("them").Session().TLVUserInfo(),
  167. LocateInfo: wire.TLVRestBlock{
  168. TLVList: wire.TLVList{
  169. wire.NewTLVBE(wire.LocateTLVTagsInfoSigData, "<HTML><BODY>My profile!</BODY></HTML>"),
  170. },
  171. },
  172. },
  173. },
  174. err: io.EOF,
  175. },
  176. },
  177. },
  178. sessionRetrieverParams: sessionRetrieverParams{
  179. retrieveSessionParams: retrieveSessionParams{
  180. {
  181. screenName: state.NewIdentScreenName("me"),
  182. returnedSession: newTestSession("me").Session(),
  183. },
  184. },
  185. },
  186. },
  187. },
  188. {
  189. name: "Retrieve profile, receive unknown response from locate svc",
  190. path: "/info?from=me&user=them&cookie=" + cookie,
  191. expectedStatus: http.StatusInternalServerError,
  192. expectedBody: "internal server error",
  193. mockParams: mockParams{
  194. locateParams: locateParams{
  195. userInfoQueryParams: userInfoQueryParams{
  196. {
  197. me: state.NewIdentScreenName("me"),
  198. inBody: wire.SNAC_0x02_0x05_LocateUserInfoQuery{
  199. Type: uint16(wire.LocateTypeSig),
  200. ScreenName: "them",
  201. },
  202. msg: wire.SNACMessage{
  203. Frame: wire.SNACFrame{
  204. FoodGroup: wire.Locate,
  205. SubGroup: wire.LocateUserInfoReply,
  206. },
  207. Body: wire.SNAC_0x04_0x09_ICBMEvilReply{},
  208. },
  209. },
  210. },
  211. },
  212. sessionRetrieverParams: sessionRetrieverParams{
  213. retrieveSessionParams: retrieveSessionParams{
  214. {
  215. screenName: state.NewIdentScreenName("me"),
  216. returnedSession: newTestSession("me").Session(),
  217. },
  218. },
  219. },
  220. },
  221. },
  222. {
  223. name: "Retrieve profile, user offline",
  224. path: "/info?from=me&user=them&cookie=" + cookie,
  225. expectedStatus: http.StatusNotFound,
  226. expectedBody: "user is unavailable",
  227. mockParams: mockParams{
  228. locateParams: locateParams{
  229. userInfoQueryParams: userInfoQueryParams{
  230. {
  231. me: state.NewIdentScreenName("me"),
  232. inBody: wire.SNAC_0x02_0x05_LocateUserInfoQuery{
  233. Type: uint16(wire.LocateTypeSig),
  234. ScreenName: "them",
  235. },
  236. msg: wire.SNACMessage{
  237. Frame: wire.SNACFrame{
  238. FoodGroup: wire.Locate,
  239. SubGroup: wire.LocateUserInfoReply,
  240. },
  241. Body: wire.SNACError{
  242. Code: wire.ErrorCodeNotLoggedOn,
  243. },
  244. },
  245. },
  246. },
  247. },
  248. sessionRetrieverParams: sessionRetrieverParams{
  249. retrieveSessionParams: retrieveSessionParams{
  250. {
  251. screenName: state.NewIdentScreenName("me"),
  252. returnedSession: newTestSession("me").Session(),
  253. },
  254. },
  255. },
  256. },
  257. },
  258. {
  259. name: "Retrieve profile, receive error code from locate svc",
  260. path: "/info?from=me&user=them&cookie=" + cookie,
  261. expectedStatus: http.StatusInternalServerError,
  262. expectedBody: "internal server error",
  263. mockParams: mockParams{
  264. locateParams: locateParams{
  265. userInfoQueryParams: userInfoQueryParams{
  266. {
  267. me: state.NewIdentScreenName("me"),
  268. inBody: wire.SNAC_0x02_0x05_LocateUserInfoQuery{
  269. Type: uint16(wire.LocateTypeSig),
  270. ScreenName: "them",
  271. },
  272. msg: wire.SNACMessage{
  273. Frame: wire.SNACFrame{
  274. FoodGroup: wire.Locate,
  275. SubGroup: wire.LocateUserInfoReply,
  276. },
  277. Body: wire.SNACError{
  278. Code: wire.ErrorCodeInvalidSnac,
  279. },
  280. },
  281. },
  282. },
  283. },
  284. sessionRetrieverParams: sessionRetrieverParams{
  285. retrieveSessionParams: retrieveSessionParams{
  286. {
  287. screenName: state.NewIdentScreenName("me"),
  288. returnedSession: newTestSession("me").Session(),
  289. },
  290. },
  291. },
  292. },
  293. },
  294. {
  295. name: "Successfully retrieve directory info",
  296. path: "/dir_info?user=them&cookie=" + cookie,
  297. expectedStatus: http.StatusOK,
  298. expectedBody: "their_first_name",
  299. mockParams: mockParams{
  300. locateParams: locateParams{
  301. dirInfoParams: dirInfoParams{
  302. {
  303. body: wire.SNAC_0x02_0x0B_LocateGetDirInfo{
  304. ScreenName: "them",
  305. },
  306. msg: wire.SNACMessage{
  307. Body: wire.SNAC_0x02_0x0C_LocateGetDirReply{
  308. Status: wire.LocateGetDirReplyOK,
  309. TLVBlock: wire.TLVBlock{
  310. TLVList: wire.TLVList{
  311. wire.NewTLVBE(wire.ODirTLVFirstName, "their_first_name"),
  312. },
  313. },
  314. },
  315. },
  316. },
  317. },
  318. },
  319. },
  320. },
  321. {
  322. name: "Retrieve directory info, no results found",
  323. path: "/dir_info?user=them&cookie=" + cookie,
  324. expectedStatus: http.StatusNotFound,
  325. expectedBody: "no user directory info found",
  326. mockParams: mockParams{
  327. locateParams: locateParams{
  328. dirInfoParams: dirInfoParams{
  329. {
  330. body: wire.SNAC_0x02_0x0B_LocateGetDirInfo{
  331. ScreenName: "them",
  332. },
  333. msg: wire.SNACMessage{
  334. Body: wire.SNAC_0x02_0x0C_LocateGetDirReply{
  335. Status: wire.LocateGetDirReplyOK,
  336. TLVBlock: wire.TLVBlock{
  337. TLVList: wire.TLVList{},
  338. },
  339. },
  340. },
  341. },
  342. },
  343. },
  344. },
  345. },
  346. {
  347. name: "Retrieve directory info, unexpected response from locate svc",
  348. path: "/dir_info?user=them&cookie=" + cookie,
  349. expectedStatus: http.StatusInternalServerError,
  350. expectedBody: "internal server error",
  351. mockParams: mockParams{
  352. locateParams: locateParams{
  353. dirInfoParams: dirInfoParams{
  354. {
  355. body: wire.SNAC_0x02_0x0B_LocateGetDirInfo{
  356. ScreenName: "them",
  357. },
  358. msg: wire.SNACMessage{
  359. Body: wire.SNACError{},
  360. },
  361. },
  362. },
  363. },
  364. },
  365. },
  366. {
  367. name: "Search directory with missing `user` query param",
  368. path: "/dir_info?cookie=" + cookie,
  369. expectedStatus: http.StatusBadRequest,
  370. expectedBody: "required `user` param is missing",
  371. },
  372. {
  373. name: "Retrieve directory info, receive err from locate svc",
  374. path: "/dir_info?user=them&cookie=" + cookie,
  375. expectedStatus: http.StatusInternalServerError,
  376. expectedBody: "internal server error",
  377. mockParams: mockParams{
  378. locateParams: locateParams{
  379. dirInfoParams: dirInfoParams{
  380. {
  381. body: wire.SNAC_0x02_0x0B_LocateGetDirInfo{
  382. ScreenName: "them",
  383. },
  384. msg: wire.SNACMessage{
  385. Body: wire.SNAC_0x02_0x0C_LocateGetDirReply{
  386. Status: wire.LocateGetDirReplyOK,
  387. TLVBlock: wire.TLVBlock{
  388. TLVList: wire.TLVList{
  389. wire.NewTLVBE(wire.ODirTLVFirstName, "their_first_name"),
  390. },
  391. },
  392. },
  393. },
  394. err: io.EOF,
  395. },
  396. },
  397. },
  398. },
  399. },
  400. {
  401. name: "Successfully search directory by name and address",
  402. path: "/dir_search?first_name=their_first_name" +
  403. "&middle_name=their_middle_name" +
  404. "&last_name=their_last_name" +
  405. "&maiden_name=their_maiden_name" +
  406. "&city=their_city" +
  407. "&state=their_state" +
  408. "&country=their_country" +
  409. "&cookie=" + cookie,
  410. expectedStatus: http.StatusOK,
  411. expectedBody: "their_first_name",
  412. mockParams: mockParams{
  413. dirSearchParams: dirSearchParams{
  414. infoQueryParams: infoQueryParams{
  415. {
  416. inBody: wire.SNAC_0x0F_0x02_InfoQuery{
  417. TLVRestBlock: wire.TLVRestBlock{
  418. TLVList: wire.TLVList{
  419. wire.NewTLVBE(wire.ODirTLVFirstName, "their_first_name"),
  420. wire.NewTLVBE(wire.ODirTLVMiddleName, "their_middle_name"),
  421. wire.NewTLVBE(wire.ODirTLVLastName, "their_last_name"),
  422. wire.NewTLVBE(wire.ODirTLVMaidenName, "their_maiden_name"),
  423. wire.NewTLVBE(wire.ODirTLVCity, "their_city"),
  424. wire.NewTLVBE(wire.ODirTLVState, "their_state"),
  425. wire.NewTLVBE(wire.ODirTLVCountry, "their_country"),
  426. },
  427. },
  428. },
  429. msg: wire.SNACMessage{
  430. Body: wire.SNAC_0x0F_0x03_InfoReply{
  431. Status: wire.ODirSearchResponseOK,
  432. Results: struct {
  433. List []wire.TLVBlock `oscar:"count_prefix=uint16"`
  434. }{
  435. List: []wire.TLVBlock{
  436. {
  437. TLVList: wire.TLVList{
  438. wire.NewTLVBE(wire.ODirTLVFirstName, "their_first_name"),
  439. },
  440. },
  441. },
  442. },
  443. },
  444. },
  445. },
  446. },
  447. },
  448. },
  449. },
  450. {
  451. name: "Successfully search directory by email",
  452. path: "/dir_search?email=their_email@aol.com&cookie=" + cookie,
  453. expectedStatus: http.StatusOK,
  454. expectedBody: "their_first_name",
  455. mockParams: mockParams{
  456. dirSearchParams: dirSearchParams{
  457. infoQueryParams: infoQueryParams{
  458. {
  459. inBody: wire.SNAC_0x0F_0x02_InfoQuery{
  460. TLVRestBlock: wire.TLVRestBlock{
  461. TLVList: wire.TLVList{
  462. wire.NewTLVBE(wire.ODirTLVEmailAddress, "their_email@aol.com"),
  463. },
  464. },
  465. },
  466. msg: wire.SNACMessage{
  467. Body: wire.SNAC_0x0F_0x03_InfoReply{
  468. Status: wire.ODirSearchResponseOK,
  469. Results: struct {
  470. List []wire.TLVBlock `oscar:"count_prefix=uint16"`
  471. }{
  472. List: []wire.TLVBlock{
  473. {
  474. TLVList: wire.TLVList{
  475. wire.NewTLVBE(wire.ODirTLVFirstName, "their_first_name"),
  476. },
  477. },
  478. },
  479. },
  480. },
  481. },
  482. },
  483. },
  484. },
  485. },
  486. },
  487. {
  488. name: "Successfully search directory by keyword",
  489. path: "/dir_search?keyword=their_keyword&cookie=" + cookie,
  490. expectedStatus: http.StatusOK,
  491. expectedBody: "their_first_name",
  492. mockParams: mockParams{
  493. dirSearchParams: dirSearchParams{
  494. infoQueryParams: infoQueryParams{
  495. {
  496. inBody: wire.SNAC_0x0F_0x02_InfoQuery{
  497. TLVRestBlock: wire.TLVRestBlock{
  498. TLVList: wire.TLVList{
  499. wire.NewTLVBE(wire.ODirTLVInterest, "their_keyword"),
  500. },
  501. },
  502. },
  503. msg: wire.SNACMessage{
  504. Body: wire.SNAC_0x0F_0x03_InfoReply{
  505. Status: wire.ODirSearchResponseOK,
  506. Results: struct {
  507. List []wire.TLVBlock `oscar:"count_prefix=uint16"`
  508. }{
  509. List: []wire.TLVBlock{
  510. {
  511. TLVList: wire.TLVList{
  512. wire.NewTLVBE(wire.ODirTLVFirstName, "their_first_name"),
  513. },
  514. },
  515. },
  516. },
  517. },
  518. },
  519. },
  520. },
  521. },
  522. },
  523. },
  524. {
  525. name: "Search directory by email, receive err from dir search svc",
  526. path: "/dir_search?email=their_email@aol.com&cookie=" + cookie,
  527. expectedStatus: http.StatusInternalServerError,
  528. expectedBody: "internal server error",
  529. mockParams: mockParams{
  530. dirSearchParams: dirSearchParams{
  531. infoQueryParams: infoQueryParams{
  532. {
  533. inBody: wire.SNAC_0x0F_0x02_InfoQuery{
  534. TLVRestBlock: wire.TLVRestBlock{
  535. TLVList: wire.TLVList{
  536. wire.NewTLVBE(wire.ODirTLVEmailAddress, "their_email@aol.com"),
  537. },
  538. },
  539. },
  540. msg: wire.SNACMessage{
  541. Body: wire.SNAC_0x0F_0x03_InfoReply{
  542. Status: wire.ODirSearchResponseOK,
  543. Results: struct {
  544. List []wire.TLVBlock `oscar:"count_prefix=uint16"`
  545. }{
  546. List: []wire.TLVBlock{
  547. {
  548. TLVList: wire.TLVList{
  549. wire.NewTLVBE(wire.ODirTLVFirstName, "their_first_name"),
  550. },
  551. },
  552. },
  553. },
  554. },
  555. },
  556. err: io.EOF,
  557. },
  558. },
  559. },
  560. },
  561. },
  562. {
  563. name: "Search directory by email, receive unknown response from dir search svc",
  564. path: "/dir_search?email=their_email@aol.com&cookie=" + cookie,
  565. expectedStatus: http.StatusInternalServerError,
  566. expectedBody: "internal server error",
  567. mockParams: mockParams{
  568. dirSearchParams: dirSearchParams{
  569. infoQueryParams: infoQueryParams{
  570. {
  571. inBody: wire.SNAC_0x0F_0x02_InfoQuery{
  572. TLVRestBlock: wire.TLVRestBlock{
  573. TLVList: wire.TLVList{
  574. wire.NewTLVBE(wire.ODirTLVEmailAddress, "their_email@aol.com"),
  575. },
  576. },
  577. },
  578. msg: wire.SNACMessage{
  579. Body: wire.SNACError{},
  580. },
  581. },
  582. },
  583. },
  584. },
  585. },
  586. {
  587. name: "Search directory without any correct search parameters",
  588. path: "/dir_search?cookie=" + cookie,
  589. expectedStatus: http.StatusBadRequest,
  590. expectedBody: "missing search parameters",
  591. mockParams: mockParams{
  592. dirSearchParams: dirSearchParams{
  593. infoQueryParams: infoQueryParams{
  594. {
  595. inBody: wire.SNAC_0x0F_0x02_InfoQuery{},
  596. msg: wire.SNACMessage{
  597. Body: wire.SNAC_0x0F_0x03_InfoReply{
  598. Status: wire.ODirSearchResponseNameMissing,
  599. },
  600. },
  601. },
  602. },
  603. },
  604. },
  605. },
  606. {
  607. name: "Search directory, receive error code from search dir svc",
  608. path: "/dir_search?cookie=" + cookie,
  609. expectedStatus: http.StatusInternalServerError,
  610. expectedBody: "internal server error",
  611. mockParams: mockParams{
  612. dirSearchParams: dirSearchParams{
  613. infoQueryParams: infoQueryParams{
  614. {
  615. inBody: wire.SNAC_0x0F_0x02_InfoQuery{},
  616. msg: wire.SNACMessage{
  617. Body: wire.SNAC_0x0F_0x03_InfoReply{
  618. Status: wire.ODirSearchResponseUnavailable1,
  619. },
  620. },
  621. },
  622. },
  623. },
  624. },
  625. },
  626. {
  627. name: "Search directory, receive unknown response from search dir svc",
  628. path: "/dir_search?cookie=" + cookie,
  629. expectedStatus: http.StatusInternalServerError,
  630. expectedBody: "internal server error",
  631. mockParams: mockParams{
  632. dirSearchParams: dirSearchParams{
  633. infoQueryParams: infoQueryParams{
  634. {
  635. inBody: wire.SNAC_0x0F_0x02_InfoQuery{},
  636. msg: wire.SNACMessage{
  637. Body: wire.SNAC_0x0F_0x03_InfoReply{
  638. Status: wire.ODirSearchResponseUnavailable1,
  639. },
  640. },
  641. },
  642. },
  643. },
  644. },
  645. },
  646. }
  647. for _, tc := range cases {
  648. t.Run(tc.name, func(t *testing.T) {
  649. locateSvc := newMockLocateService(t)
  650. for _, params := range tc.mockParams.userInfoQueryParams {
  651. locateSvc.EXPECT().
  652. UserInfoQuery(mock.Anything, matchSession(params.me), wire.SNACFrame{}, params.inBody).
  653. Return(params.msg, params.err)
  654. }
  655. for _, params := range tc.mockParams.dirInfoParams {
  656. locateSvc.EXPECT().
  657. DirInfo(mock.Anything, wire.SNACFrame{}, params.body).
  658. Return(params.msg, params.err)
  659. }
  660. dirSearchSvc := newMockDirSearchService(t)
  661. for _, params := range tc.mockParams.infoQueryParams {
  662. dirSearchSvc.EXPECT().
  663. InfoQuery(mock.Anything, wire.SNACFrame{}, params.inBody).
  664. Return(params.msg, params.err)
  665. }
  666. sessionRetriever := newMockSessionRetriever(t)
  667. for _, params := range tc.mockParams.retrieveSessionParams {
  668. sessionRetriever.EXPECT().
  669. RetrieveSession(params.screenName).
  670. Return(params.returnedSession)
  671. }
  672. svc := OSCARProxy{
  673. CookieBaker: cookieBaker,
  674. DirSearchService: dirSearchSvc,
  675. LocateService: locateSvc,
  676. Logger: slog.Default(),
  677. SessionRetriever: sessionRetriever,
  678. HTTPIPRateLimiter: NewIPRateLimiter(rate.Every(1*time.Minute), 10, 1*time.Minute),
  679. SNACRateLimits: wire.DefaultSNACRateLimits(),
  680. }
  681. req, err := http.NewRequest(http.MethodGet, tc.path, nil)
  682. req.RemoteAddr = "127.0.0.1:1234"
  683. if err != nil {
  684. t.Fatalf("Failed to create request: %v", err)
  685. }
  686. rr := httptest.NewRecorder()
  687. svc.NewServeMux().ServeHTTP(rr, req)
  688. assert.Equal(t, tc.expectedStatus, rr.Code)
  689. assert.Contains(t, rr.Body.String(), tc.expectedBody)
  690. })
  691. }
  692. }