locate_test.go 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993
  1. package foodgroup
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/mock"
  8. "github.com/stretchr/testify/require"
  9. "github.com/mk6i/open-oscar-server/state"
  10. "github.com/mk6i/open-oscar-server/wire"
  11. )
  12. func TestLocateService_UserInfoQuery(t *testing.T) {
  13. cases := []struct {
  14. // name is the unit test name
  15. name string
  16. // mockParams is the list of params sent to mocks that satisfy this
  17. // method's dependencies
  18. mockParams mockParams
  19. // instance is the session of the user requesting user info
  20. instance *state.SessionInstance
  21. // inputSNAC is the SNAC sent from client to server
  22. inputSNAC wire.SNACMessage
  23. // expectOutput is the SNAC sent from the server to client
  24. expectOutput wire.SNACMessage
  25. }{
  26. {
  27. name: "request user info, expect user info response",
  28. mockParams: mockParams{
  29. relationshipFetcherParams: relationshipFetcherParams{
  30. relationshipParams: relationshipParams{
  31. {
  32. me: state.NewIdentScreenName("user_screen_name"),
  33. them: state.NewIdentScreenName("requested-user"),
  34. result: state.Relationship{
  35. User: state.NewIdentScreenName("requested-user"),
  36. BlocksYou: false,
  37. YouBlock: false,
  38. IsOnYourList: true,
  39. IsOnTheirList: true,
  40. },
  41. },
  42. },
  43. },
  44. sessionRetrieverParams: sessionRetrieverParams{
  45. retrieveSessionParams: retrieveSessionParams{
  46. {
  47. screenName: state.NewIdentScreenName("requested-user"),
  48. result: newTestInstance("requested-user",
  49. sessOptCannedSignonTime,
  50. sessOptCannedAwayMessage,
  51. sessOptUserInfoFlag(wire.OServiceUserFlagUnavailable)).Session(),
  52. },
  53. },
  54. },
  55. },
  56. instance: newTestInstance("user_screen_name"),
  57. inputSNAC: wire.SNACMessage{
  58. Frame: wire.SNACFrame{
  59. RequestID: 1234,
  60. },
  61. Body: wire.SNAC_0x02_0x05_LocateUserInfoQuery{
  62. Type: 0,
  63. ScreenName: "requested-user",
  64. },
  65. },
  66. expectOutput: wire.SNACMessage{
  67. Frame: wire.SNACFrame{
  68. FoodGroup: wire.Locate,
  69. SubGroup: wire.LocateUserInfoReply,
  70. RequestID: 1234,
  71. },
  72. Body: wire.SNAC_0x02_0x06_LocateUserInfoReply{
  73. TLVUserInfo: newTestInstance("requested-user",
  74. sessOptCannedSignonTime,
  75. sessOptCannedAwayMessage,
  76. sessOptUserInfoFlag(wire.OServiceUserFlagUnavailable)).
  77. Session().TLVUserInfo(),
  78. LocateInfo: wire.TLVRestBlock{},
  79. },
  80. },
  81. },
  82. {
  83. name: "request user info + profile, expect user info response + profile",
  84. mockParams: mockParams{
  85. relationshipFetcherParams: relationshipFetcherParams{
  86. relationshipParams: relationshipParams{
  87. {
  88. me: state.NewIdentScreenName("user_screen_name"),
  89. them: state.NewIdentScreenName("requested-user"),
  90. result: state.Relationship{
  91. User: state.NewIdentScreenName("requested-user"),
  92. BlocksYou: false,
  93. YouBlock: false,
  94. IsOnYourList: true,
  95. IsOnTheirList: true,
  96. },
  97. },
  98. },
  99. },
  100. sessionRetrieverParams: sessionRetrieverParams{
  101. retrieveSessionParams: retrieveSessionParams{
  102. {
  103. screenName: state.NewIdentScreenName("requested-user"),
  104. result: newTestInstance("requested-user",
  105. sessOptCannedSignonTime,
  106. sessOptCannedAwayMessage,
  107. sessOptUserInfoFlag(wire.OServiceUserFlagUnavailable),
  108. sessOptProfile(state.UserProfile{
  109. ProfileText: "this is my profile!",
  110. MIMEType: "text/aolrtf; charset=\"us-ascii\"",
  111. UpdateTime: time.Now(),
  112. })).Session(),
  113. },
  114. },
  115. },
  116. },
  117. instance: newTestInstance("user_screen_name"),
  118. inputSNAC: wire.SNACMessage{
  119. Frame: wire.SNACFrame{
  120. RequestID: 1234,
  121. },
  122. Body: wire.SNAC_0x02_0x05_LocateUserInfoQuery{
  123. // 2048 is a dummy to make sure bitmask check works
  124. Type: uint16(wire.LocateTypeSig) | 2048,
  125. ScreenName: "requested-user",
  126. },
  127. },
  128. expectOutput: wire.SNACMessage{
  129. Frame: wire.SNACFrame{
  130. FoodGroup: wire.Locate,
  131. SubGroup: wire.LocateUserInfoReply,
  132. RequestID: 1234,
  133. },
  134. Body: wire.SNAC_0x02_0x06_LocateUserInfoReply{
  135. TLVUserInfo: newTestInstance("requested-user",
  136. sessOptCannedSignonTime,
  137. sessOptCannedAwayMessage,
  138. sessOptUserInfoFlag(wire.OServiceUserFlagUnavailable)).Session().TLVUserInfo(),
  139. LocateInfo: wire.TLVRestBlock{
  140. TLVList: wire.TLVList{
  141. wire.NewTLVBE(wire.LocateTLVTagsInfoSigMime, `text/aolrtf; charset="us-ascii"`),
  142. wire.NewTLVBE(wire.LocateTLVTagsInfoSigData, "this is my profile!"),
  143. },
  144. },
  145. },
  146. },
  147. },
  148. {
  149. name: "request user info + away message, expect user info response + away message",
  150. mockParams: mockParams{
  151. relationshipFetcherParams: relationshipFetcherParams{
  152. relationshipParams: relationshipParams{
  153. {
  154. me: state.NewIdentScreenName("user_screen_name"),
  155. them: state.NewIdentScreenName("requested-user"),
  156. result: state.Relationship{
  157. User: state.NewIdentScreenName("requested-user"),
  158. BlocksYou: false,
  159. YouBlock: false,
  160. IsOnYourList: true,
  161. IsOnTheirList: true,
  162. },
  163. },
  164. },
  165. },
  166. sessionRetrieverParams: sessionRetrieverParams{
  167. retrieveSessionParams: retrieveSessionParams{
  168. {
  169. screenName: state.NewIdentScreenName("requested-user"),
  170. result: newTestInstance("requested-user",
  171. sessOptCannedSignonTime,
  172. sessOptCannedAwayMessage,
  173. sessOptUserInfoFlag(wire.OServiceUserFlagUnavailable)).Session(),
  174. },
  175. },
  176. },
  177. },
  178. instance: newTestInstance("user_screen_name"),
  179. inputSNAC: wire.SNACMessage{
  180. Frame: wire.SNACFrame{
  181. RequestID: 1234,
  182. },
  183. Body: wire.SNAC_0x02_0x05_LocateUserInfoQuery{
  184. // 2048 is a dummy to make sure bitmask check works
  185. Type: uint16(wire.LocateTypeUnavailable) | 2048,
  186. ScreenName: "requested-user",
  187. },
  188. },
  189. expectOutput: wire.SNACMessage{
  190. Frame: wire.SNACFrame{
  191. FoodGroup: wire.Locate,
  192. SubGroup: wire.LocateUserInfoReply,
  193. RequestID: 1234,
  194. },
  195. Body: wire.SNAC_0x02_0x06_LocateUserInfoReply{
  196. TLVUserInfo: newTestInstance("requested-user",
  197. sessOptCannedSignonTime,
  198. sessOptCannedAwayMessage,
  199. sessOptUserInfoFlag(wire.OServiceUserFlagUnavailable)).
  200. Session().TLVUserInfo(),
  201. LocateInfo: wire.TLVRestBlock{
  202. TLVList: wire.TLVList{
  203. wire.NewTLVBE(wire.LocateTLVTagsInfoUnavailableMime, `text/aolrtf; charset="us-ascii"`),
  204. wire.NewTLVBE(wire.LocateTLVTagsInfoUnavailableData, "this is my away message!"),
  205. },
  206. },
  207. },
  208. },
  209. },
  210. {
  211. name: "request user info of user who blocked requester, expect not logged in error",
  212. mockParams: mockParams{
  213. relationshipFetcherParams: relationshipFetcherParams{
  214. relationshipParams: relationshipParams{
  215. {
  216. me: state.NewIdentScreenName("user_screen_name"),
  217. them: state.NewIdentScreenName("requested-user"),
  218. result: state.Relationship{
  219. User: state.NewIdentScreenName("requested-user"),
  220. BlocksYou: true,
  221. YouBlock: false,
  222. IsOnYourList: true,
  223. IsOnTheirList: true,
  224. },
  225. },
  226. },
  227. },
  228. },
  229. instance: newTestInstance("user_screen_name"),
  230. inputSNAC: wire.SNACMessage{
  231. Frame: wire.SNACFrame{
  232. RequestID: 1234,
  233. },
  234. Body: wire.SNAC_0x02_0x05_LocateUserInfoQuery{
  235. ScreenName: "requested-user",
  236. },
  237. },
  238. expectOutput: wire.SNACMessage{
  239. Frame: wire.SNACFrame{
  240. FoodGroup: wire.Locate,
  241. SubGroup: wire.LocateErr,
  242. RequestID: 1234,
  243. },
  244. Body: wire.SNACError{
  245. Code: wire.ErrorCodeNotLoggedOn,
  246. },
  247. },
  248. },
  249. {
  250. name: "request user info of user who does not exist, expect not logged in error",
  251. mockParams: mockParams{
  252. relationshipFetcherParams: relationshipFetcherParams{
  253. relationshipParams: relationshipParams{
  254. {
  255. me: state.NewIdentScreenName("user_screen_name"),
  256. them: state.NewIdentScreenName("non_existent_requested_user"),
  257. result: state.Relationship{
  258. User: state.NewIdentScreenName("non_existent_requested_user"),
  259. BlocksYou: false,
  260. YouBlock: false,
  261. IsOnYourList: true,
  262. IsOnTheirList: true,
  263. },
  264. },
  265. },
  266. },
  267. sessionRetrieverParams: sessionRetrieverParams{
  268. retrieveSessionParams: retrieveSessionParams{
  269. {
  270. screenName: state.NewIdentScreenName("non_existent_requested_user"),
  271. result: nil,
  272. },
  273. },
  274. },
  275. },
  276. instance: newTestInstance("user_screen_name"),
  277. inputSNAC: wire.SNACMessage{
  278. Frame: wire.SNACFrame{
  279. RequestID: 1234,
  280. },
  281. Body: wire.SNAC_0x02_0x05_LocateUserInfoQuery{
  282. ScreenName: "non_existent_requested_user",
  283. },
  284. },
  285. expectOutput: wire.SNACMessage{
  286. Frame: wire.SNACFrame{
  287. FoodGroup: wire.Locate,
  288. SubGroup: wire.LocateErr,
  289. RequestID: 1234,
  290. },
  291. Body: wire.SNACError{
  292. Code: wire.ErrorCodeNotLoggedOn,
  293. },
  294. },
  295. },
  296. }
  297. for _, tc := range cases {
  298. t.Run(tc.name, func(t *testing.T) {
  299. relationshipFetcher := newMockRelationshipFetcher(t)
  300. for _, params := range tc.mockParams.relationshipParams {
  301. relationshipFetcher.EXPECT().
  302. Relationship(matchContext(), params.me, params.them).
  303. Return(params.result, params.err)
  304. }
  305. sessionRetriever := newMockSessionRetriever(t)
  306. for _, val := range tc.mockParams.retrieveSessionParams {
  307. sessionRetriever.EXPECT().
  308. RetrieveSession(val.screenName).
  309. Return(val.result)
  310. }
  311. messageRelayer := newMockMessageRelayer(t)
  312. svc := LocateService{
  313. relationshipFetcher: relationshipFetcher,
  314. messageRelayer: messageRelayer,
  315. sessionRetriever: sessionRetriever,
  316. }
  317. outputSNAC, err := svc.UserInfoQuery(context.Background(), tc.instance, tc.inputSNAC.Frame,
  318. tc.inputSNAC.Body.(wire.SNAC_0x02_0x05_LocateUserInfoQuery))
  319. assert.NoError(t, err)
  320. assert.Equal(t, tc.expectOutput, outputSNAC)
  321. })
  322. }
  323. }
  324. func TestLocateService_SetKeywordInfo(t *testing.T) {
  325. tests := []struct {
  326. // name is the unit test name
  327. name string
  328. // instance is the session of the user setting info
  329. instance *state.SessionInstance
  330. // inputSNAC is the SNAC sent from client to server
  331. inputSNAC wire.SNACMessage
  332. // expectOutput is the SNAC sent from the server to client
  333. expectOutput wire.SNACMessage
  334. // mockParams is the list of params sent to mocks that satisfy this
  335. // method's dependencies
  336. mockParams mockParams
  337. // wantErr is the expected error
  338. wantErr error
  339. }{
  340. {
  341. name: "set exactly 5 interests",
  342. instance: newTestInstance("test-user"),
  343. inputSNAC: wire.SNACMessage{
  344. Frame: wire.SNACFrame{
  345. RequestID: 1234,
  346. },
  347. Body: wire.SNAC_0x02_0x0F_LocateSetKeywordInfo{
  348. TLVRestBlock: wire.TLVRestBlock{
  349. TLVList: wire.TLVList{
  350. wire.NewTLVBE(wire.ODirTLVInterest, "interest1"),
  351. wire.NewTLVBE(wire.ODirTLVFirstName, "first_name"),
  352. wire.NewTLVBE(wire.ODirTLVInterest, "interest2"),
  353. wire.NewTLVBE(wire.ODirTLVLastName, "last_name"),
  354. wire.NewTLVBE(wire.ODirTLVInterest, "interest3"),
  355. wire.NewTLVBE(wire.ODirTLVInterest, "interest4"),
  356. wire.NewTLVBE(wire.ODirTLVInterest, "interest5"),
  357. },
  358. },
  359. },
  360. },
  361. expectOutput: wire.SNACMessage{
  362. Frame: wire.SNACFrame{
  363. FoodGroup: wire.Locate,
  364. SubGroup: wire.LocateSetKeywordReply,
  365. RequestID: 1234,
  366. },
  367. Body: wire.SNAC_0x02_0x10_LocateSetKeywordReply{
  368. Unknown: 1,
  369. },
  370. },
  371. mockParams: mockParams{
  372. profileManagerParams: profileManagerParams{
  373. setKeywordsParams: setKeywordsParams{
  374. {
  375. screenName: state.NewIdentScreenName("test-user"),
  376. keywords: [5]string{
  377. "interest1",
  378. "interest2",
  379. "interest3",
  380. "interest4",
  381. "interest5",
  382. },
  383. },
  384. },
  385. },
  386. },
  387. },
  388. {
  389. name: "set less than 5 interests",
  390. instance: newTestInstance("test-user"),
  391. inputSNAC: wire.SNACMessage{
  392. Frame: wire.SNACFrame{
  393. RequestID: 1234,
  394. },
  395. Body: wire.SNAC_0x02_0x0F_LocateSetKeywordInfo{
  396. TLVRestBlock: wire.TLVRestBlock{
  397. TLVList: wire.TLVList{
  398. wire.NewTLVBE(wire.ODirTLVInterest, "interest1"),
  399. wire.NewTLVBE(wire.ODirTLVFirstName, "first_name"),
  400. wire.NewTLVBE(wire.ODirTLVInterest, "interest2"),
  401. wire.NewTLVBE(wire.ODirTLVLastName, "last_name"),
  402. wire.NewTLVBE(wire.ODirTLVInterest, "interest3"),
  403. wire.NewTLVBE(wire.ODirTLVInterest, "interest4"),
  404. },
  405. },
  406. },
  407. },
  408. expectOutput: wire.SNACMessage{
  409. Frame: wire.SNACFrame{
  410. FoodGroup: wire.Locate,
  411. SubGroup: wire.LocateSetKeywordReply,
  412. RequestID: 1234,
  413. },
  414. Body: wire.SNAC_0x02_0x10_LocateSetKeywordReply{
  415. Unknown: 1,
  416. },
  417. },
  418. mockParams: mockParams{
  419. profileManagerParams: profileManagerParams{
  420. setKeywordsParams: setKeywordsParams{
  421. {
  422. screenName: state.NewIdentScreenName("test-user"),
  423. keywords: [5]string{
  424. "interest1",
  425. "interest2",
  426. "interest3",
  427. "interest4",
  428. },
  429. },
  430. },
  431. },
  432. },
  433. },
  434. {
  435. name: "set more than 5 interests",
  436. instance: newTestInstance("test-user"),
  437. inputSNAC: wire.SNACMessage{
  438. Frame: wire.SNACFrame{
  439. RequestID: 1234,
  440. },
  441. Body: wire.SNAC_0x02_0x0F_LocateSetKeywordInfo{
  442. TLVRestBlock: wire.TLVRestBlock{
  443. TLVList: wire.TLVList{
  444. wire.NewTLVBE(wire.ODirTLVInterest, "interest1"),
  445. wire.NewTLVBE(wire.ODirTLVFirstName, "first_name"),
  446. wire.NewTLVBE(wire.ODirTLVInterest, "interest2"),
  447. wire.NewTLVBE(wire.ODirTLVLastName, "last_name"),
  448. wire.NewTLVBE(wire.ODirTLVInterest, "interest3"),
  449. wire.NewTLVBE(wire.ODirTLVInterest, "interest4"),
  450. wire.NewTLVBE(wire.ODirTLVInterest, "interest5"),
  451. wire.NewTLVBE(wire.ODirTLVInterest, "interest6"),
  452. },
  453. },
  454. },
  455. },
  456. expectOutput: wire.SNACMessage{
  457. Frame: wire.SNACFrame{
  458. FoodGroup: wire.Locate,
  459. SubGroup: wire.LocateSetKeywordReply,
  460. RequestID: 1234,
  461. },
  462. Body: wire.SNAC_0x02_0x10_LocateSetKeywordReply{
  463. Unknown: 1,
  464. },
  465. },
  466. mockParams: mockParams{
  467. profileManagerParams: profileManagerParams{
  468. setKeywordsParams: setKeywordsParams{
  469. {
  470. screenName: state.NewIdentScreenName("test-user"),
  471. keywords: [5]string{
  472. "interest1",
  473. "interest2",
  474. "interest3",
  475. "interest4",
  476. "interest5",
  477. },
  478. },
  479. },
  480. },
  481. },
  482. },
  483. }
  484. for _, tt := range tests {
  485. t.Run(tt.name, func(t *testing.T) {
  486. profileManager := newMockProfileManager(t)
  487. for _, params := range tt.mockParams.setKeywordsParams {
  488. profileManager.EXPECT().
  489. SetKeywords(matchContext(), params.screenName, params.keywords).
  490. Return(params.err)
  491. }
  492. messageRelayer := newMockMessageRelayer(t)
  493. svc := NewLocateService(nil, messageRelayer, profileManager, nil, nil, nil)
  494. outputSNAC, err := svc.SetKeywordInfo(context.Background(), tt.instance, tt.inputSNAC.Frame, tt.inputSNAC.Body.(wire.SNAC_0x02_0x0F_LocateSetKeywordInfo))
  495. assert.NoError(t, err)
  496. assert.Equal(t, tt.expectOutput, outputSNAC)
  497. })
  498. }
  499. }
  500. func TestLocateService_SetDirInfo(t *testing.T) {
  501. tests := []struct {
  502. // name is the unit test name
  503. name string
  504. // instance is the session of the user setting info
  505. instance *state.SessionInstance
  506. // inputSNAC is the SNAC sent from client to server
  507. inputSNAC wire.SNACMessage
  508. // expectOutput is the SNAC sent from the server to client
  509. expectOutput wire.SNACMessage
  510. // mockParams is the list of params sent to mocks that satisfy this
  511. // method's dependencies
  512. mockParams mockParams
  513. // wantErr is the expected error
  514. wantErr error
  515. }{
  516. {
  517. name: "set directory info",
  518. instance: newTestInstance("test-user"),
  519. inputSNAC: wire.SNACMessage{
  520. Frame: wire.SNACFrame{
  521. RequestID: 1234,
  522. },
  523. Body: wire.SNAC_0x02_0x09_LocateSetDirInfo{
  524. TLVRestBlock: wire.TLVRestBlock{
  525. TLVList: wire.TLVList{
  526. wire.NewTLVBE(wire.ODirTLVFirstName, "first_name"),
  527. wire.NewTLVBE(wire.ODirTLVLastName, "last_name"),
  528. wire.NewTLVBE(wire.ODirTLVMiddleName, "middle_name"),
  529. wire.NewTLVBE(wire.ODirTLVMaidenName, "maiden_name"),
  530. wire.NewTLVBE(wire.ODirTLVCountry, "country"),
  531. wire.NewTLVBE(wire.ODirTLVState, "state"),
  532. wire.NewTLVBE(wire.ODirTLVCity, "city"),
  533. wire.NewTLVBE(wire.ODirTLVNickName, "nick_name"),
  534. wire.NewTLVBE(wire.ODirTLVZIP, "zip"),
  535. wire.NewTLVBE(wire.ODirTLVAddress, "address"),
  536. },
  537. },
  538. },
  539. },
  540. expectOutput: wire.SNACMessage{
  541. Frame: wire.SNACFrame{
  542. FoodGroup: wire.Locate,
  543. SubGroup: wire.LocateSetDirReply,
  544. RequestID: 1234,
  545. },
  546. Body: wire.SNAC_0x02_0x0A_LocateSetDirReply{
  547. Result: 1,
  548. },
  549. },
  550. mockParams: mockParams{
  551. profileManagerParams: profileManagerParams{
  552. setDirectoryInfoParams: setDirectoryInfoParams{
  553. {
  554. screenName: state.NewIdentScreenName("test-user"),
  555. info: state.AIMNameAndAddr{
  556. FirstName: "first_name",
  557. LastName: "last_name",
  558. MiddleName: "middle_name",
  559. MaidenName: "maiden_name",
  560. Country: "country",
  561. State: "state",
  562. City: "city",
  563. NickName: "nick_name",
  564. ZIPCode: "zip",
  565. Address: "address",
  566. },
  567. },
  568. },
  569. },
  570. },
  571. },
  572. }
  573. for _, tt := range tests {
  574. t.Run(tt.name, func(t *testing.T) {
  575. profileManager := newMockProfileManager(t)
  576. for _, params := range tt.mockParams.setDirectoryInfoParams {
  577. profileManager.EXPECT().
  578. SetDirectoryInfo(matchContext(), params.screenName, params.info).
  579. Return(nil)
  580. }
  581. messageRelayer := newMockMessageRelayer(t)
  582. svc := NewLocateService(nil, messageRelayer, profileManager, nil, nil, nil)
  583. outputSNAC, err := svc.SetDirInfo(context.Background(), tt.instance, tt.inputSNAC.Frame, tt.inputSNAC.Body.(wire.SNAC_0x02_0x09_LocateSetDirInfo))
  584. assert.NoError(t, err)
  585. assert.Equal(t, tt.expectOutput, outputSNAC)
  586. })
  587. }
  588. }
  589. func TestLocateService_SetInfo(t *testing.T) {
  590. tests := []struct {
  591. // name is the unit test name
  592. name string
  593. // instance is the session of the user setting info
  594. instance *state.SessionInstance
  595. // inBody is the message sent from client to server
  596. inBody wire.SNAC_0x02_0x04_LocateSetInfo
  597. // mockParams is the list of params sent to mocks that satisfy this
  598. // method's dependencies
  599. mockParams mockParams
  600. // checkSession validates the state of the session
  601. checkSession func(*testing.T, *state.Session)
  602. // wantErr is the expected error
  603. wantErr error
  604. }{
  605. {
  606. name: "set session profile (AIM < 6)",
  607. instance: func() *state.SessionInstance {
  608. curInstance := newTestInstance("test-user")
  609. curInstance.SetKerberosAuth(false)
  610. // set up other concurrent instances
  611. instance2 := curInstance.Session().AddInstance()
  612. instance2.SetKerberosAuth(true)
  613. instance3 := curInstance.Session().AddInstance()
  614. instance3.SetKerberosAuth(false)
  615. return curInstance
  616. }(),
  617. inBody: wire.SNAC_0x02_0x04_LocateSetInfo{
  618. TLVRestBlock: wire.TLVRestBlock{
  619. TLVList: wire.TLVList{
  620. wire.NewTLVBE(wire.LocateTLVTagsInfoSigData, "profile-result"),
  621. wire.NewTLVBE(wire.LocateTLVTagsInfoSigMime, `text/aolrtf; charset="us-ascii"`),
  622. },
  623. },
  624. },
  625. checkSession: func(t *testing.T, session *state.Session) {
  626. require.Equal(t, 3, session.InstanceCount())
  627. assert.Equal(t, "profile-result", session.Instance(1).Profile().ProfileText)
  628. assert.Equal(t, `text/aolrtf; charset="us-ascii"`, session.Instance(1).Profile().MIMEType)
  629. assert.NotZero(t, session.Instance(1).Profile().UpdateTime)
  630. assert.True(t, session.Instance(2).Profile().IsZero())
  631. assert.True(t, session.Instance(3).Profile().IsZero())
  632. },
  633. },
  634. {
  635. name: "set stored profile (AIM 6-7)",
  636. instance: func() *state.SessionInstance {
  637. curInstance := newTestInstance("test-user", sessOptSetFoodGroupVersion(wire.OService, 4))
  638. curInstance.SetKerberosAuth(true)
  639. // set up other concurrent instances
  640. instance2 := curInstance.Session().AddInstance()
  641. instance2.SetKerberosAuth(true)
  642. instance3 := curInstance.Session().AddInstance()
  643. instance3.SetKerberosAuth(false)
  644. return curInstance
  645. }(),
  646. inBody: wire.SNAC_0x02_0x04_LocateSetInfo{
  647. TLVRestBlock: wire.TLVRestBlock{
  648. TLVList: wire.TLVList{
  649. wire.NewTLVBE(wire.LocateTLVTagsInfoSigData, "profile-result"),
  650. wire.NewTLVBE(wire.LocateTLVTagsInfoSigMime, `text/aolrtf; charset="us-ascii"`),
  651. },
  652. },
  653. },
  654. mockParams: mockParams{
  655. profileManagerParams: profileManagerParams{
  656. setProfileParams: setProfileParams{
  657. {
  658. screenName: state.NewIdentScreenName("test-user"),
  659. body: state.UserProfile{
  660. ProfileText: "profile-result",
  661. MIMEType: `text/aolrtf; charset="us-ascii"`,
  662. UpdateTime: time.Now(),
  663. },
  664. },
  665. },
  666. },
  667. messageRelayerParams: messageRelayerParams{
  668. relayToOtherInstancesParams: relayToOtherInstancesParams{
  669. {
  670. screenName: state.NewIdentScreenName("test-user"),
  671. message: wire.SNACMessage{
  672. Frame: wire.SNACFrame{
  673. FoodGroup: wire.OService,
  674. SubGroup: wire.OServiceUserInfoUpdate,
  675. },
  676. Body: func(val any) bool {
  677. snac, ok := val.(wire.SNAC_0x01_0x0F_OServiceUserInfoUpdate)
  678. if !ok {
  679. return false
  680. }
  681. require.Len(t, snac.UserInfo, 4)
  682. _, hasSigTime1 := snac.UserInfo[1].Uint32BE(wire.OServiceUserInfoSigTime)
  683. return assert.True(t, hasSigTime1, "has signature update time")
  684. },
  685. },
  686. },
  687. },
  688. },
  689. },
  690. checkSession: func(t *testing.T, session *state.Session) {
  691. require.Equal(t, 3, session.InstanceCount())
  692. assert.Equal(t, "profile-result", session.Instance(1).Profile().ProfileText)
  693. assert.Equal(t, `text/aolrtf; charset="us-ascii"`, session.Instance(1).Profile().MIMEType)
  694. assert.NotZero(t, session.Instance(1).Profile().UpdateTime)
  695. assert.Equal(t, "profile-result", session.Instance(2).Profile().ProfileText)
  696. assert.Equal(t, `text/aolrtf; charset="us-ascii"`, session.Instance(2).Profile().MIMEType)
  697. assert.NotZero(t, session.Instance(2).Profile().UpdateTime)
  698. assert.True(t, session.Instance(3).Profile().IsZero())
  699. },
  700. },
  701. {
  702. name: "set away message during sign on flow",
  703. instance: newTestInstance("user_screen_name"),
  704. inBody: wire.SNAC_0x02_0x04_LocateSetInfo{
  705. TLVRestBlock: wire.TLVRestBlock{
  706. TLVList: wire.TLVList{
  707. wire.NewTLVBE(wire.LocateTLVTagsInfoUnavailableData, "this is my away message!"),
  708. },
  709. },
  710. },
  711. mockParams: mockParams{
  712. buddyBroadcasterParams: buddyBroadcasterParams{
  713. broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{},
  714. },
  715. },
  716. checkSession: func(t *testing.T, session *state.Session) {
  717. assert.True(t, session.Instance(1).Profile().IsZero())
  718. },
  719. },
  720. {
  721. name: "set away message after sign on flow",
  722. instance: newTestInstance("user_screen_name", sessOptSignonComplete),
  723. inBody: wire.SNAC_0x02_0x04_LocateSetInfo{
  724. TLVRestBlock: wire.TLVRestBlock{
  725. TLVList: wire.TLVList{
  726. wire.NewTLVBE(wire.LocateTLVTagsInfoUnavailableData, "this is my away message!"),
  727. },
  728. },
  729. },
  730. mockParams: mockParams{
  731. buddyBroadcasterParams: buddyBroadcasterParams{
  732. broadcastBuddyArrivedParams: broadcastBuddyArrivedParams{
  733. {
  734. screenName: state.DisplayScreenName("user_screen_name"),
  735. },
  736. },
  737. },
  738. },
  739. checkSession: func(t *testing.T, session *state.Session) {
  740. assert.True(t, session.Instance(1).Profile().IsZero())
  741. },
  742. },
  743. }
  744. for _, tt := range tests {
  745. t.Run(tt.name, func(t *testing.T) {
  746. profileManager := newMockProfileManager(t)
  747. for _, params := range tt.mockParams.setProfileParams {
  748. profileManager.EXPECT().
  749. SetProfile(matchContext(), params.screenName, mock.MatchedBy(func(profile state.UserProfile) bool {
  750. return profile.ProfileText == params.body.ProfileText &&
  751. profile.MIMEType == params.body.MIMEType &&
  752. !profile.UpdateTime.IsZero()
  753. })).
  754. Return(nil)
  755. }
  756. buddyUpdateBroadcaster := newMockbuddyBroadcaster(t)
  757. for _, params := range tt.mockParams.broadcastBuddyArrivedParams {
  758. buddyUpdateBroadcaster.EXPECT().
  759. BroadcastBuddyArrived(mock.Anything, state.NewIdentScreenName(params.screenName.String()), mock.MatchedBy(func(userInfo wire.TLVUserInfo) bool {
  760. return userInfo.ScreenName == params.screenName.String()
  761. })).
  762. Return(params.err)
  763. }
  764. messageRelayer := newMockMessageRelayer(t)
  765. for _, params := range tt.mockParams.relayToOtherInstancesParams {
  766. if matcherFn, ok := params.message.Body.(func(val any) bool); ok {
  767. messageRelayer.EXPECT().
  768. RelayToOtherInstances(matchContext(), matchSession(params.screenName), mock.MatchedBy(func(message wire.SNACMessage) bool {
  769. return params.message.Frame == message.Frame &&
  770. matcherFn(message.Body)
  771. }))
  772. } else {
  773. t.Fail()
  774. }
  775. }
  776. svc := NewLocateService(nil, messageRelayer, profileManager, nil, nil, nil)
  777. svc.buddyBroadcaster = buddyUpdateBroadcaster
  778. err := svc.SetInfo(context.Background(), tt.instance, tt.inBody)
  779. assert.Equal(t, tt.wantErr, err)
  780. tt.checkSession(t, tt.instance.Session())
  781. })
  782. }
  783. }
  784. func TestLocateService_SetInfo_SetCaps(t *testing.T) {
  785. messageRelayer := newMockMessageRelayer(t)
  786. svc := NewLocateService(nil, messageRelayer, nil, nil, nil, nil)
  787. instance := newTestInstance("screen-name")
  788. inBody := wire.SNAC_0x02_0x04_LocateSetInfo{
  789. TLVRestBlock: wire.TLVRestBlock{
  790. TLVList: wire.TLVList{
  791. wire.NewTLVBE(wire.LocateTLVTagsInfoCapabilities, []byte{
  792. // chat: "748F2420-6287-11D1-8222-444553540000"
  793. 0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00,
  794. // avatar: "09461346-4c7f-11d1-8222-444553540000"
  795. 9, 70, 19, 70, 76, 127, 17, 209, 130, 34, 68, 69, 83, 84, 0, 0,
  796. // 0946134a-4c7f-11d1-8222-444553540000 (games)
  797. 9, 70, 19, 74, 76, 127, 17, 209, 130, 34, 68, 69, 83, 84, 0, 0,
  798. // 0946134d-4c7f-11d1-8222-444553540000 (ICQ inter-op)
  799. 9, 70, 19, 77, 76, 127, 17, 209, 130, 34, 68, 69, 83, 84, 0, 0,
  800. // 09461341-4c7f-11d1-8222-444553540000 (voice chat)
  801. 9, 70, 19, 65, 76, 127, 17, 209, 130, 34, 68, 69, 83, 84, 0, 0,
  802. }),
  803. },
  804. },
  805. }
  806. assert.NoError(t, svc.SetInfo(context.Background(), instance, inBody))
  807. expect := [][16]byte{
  808. // 748F2420-6287-11D1-8222-444553540000 (chat)
  809. {0x74, 0x8f, 0x24, 0x20, 0x62, 0x87, 0x11, 0xd1, 0x82, 0x22, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00},
  810. // 09461346-4C7F-11D1-8222-444553540000 (avatar)
  811. {9, 70, 19, 70, 76, 127, 17, 209, 130, 34, 68, 69, 83, 84, 0, 0},
  812. }
  813. assert.ElementsMatch(t, expect, instance.Session().Caps())
  814. }
  815. func TestLocateService_RightsQuery(t *testing.T) {
  816. messageRelayer := newMockMessageRelayer(t)
  817. svc := NewLocateService(nil, messageRelayer, nil, nil, nil, nil)
  818. outputSNAC := svc.RightsQuery(context.Background(), wire.SNACFrame{RequestID: 1234})
  819. expectSNAC := wire.SNACMessage{
  820. Frame: wire.SNACFrame{
  821. FoodGroup: wire.Locate,
  822. SubGroup: wire.LocateRightsReply,
  823. RequestID: 1234,
  824. },
  825. Body: wire.SNAC_0x02_0x03_LocateRightsReply{
  826. TLVRestBlock: wire.TLVRestBlock{
  827. TLVList: wire.TLVList{
  828. wire.NewTLVBE(wire.LocateTLVTagsRightsMaxSigLen, uint16(1000)),
  829. wire.NewTLVBE(wire.LocateTLVTagsRightsMaxCapabilitiesLen, uint16(1000)),
  830. wire.NewTLVBE(wire.LocateTLVTagsRightsMaxFindByEmailList, uint16(1000)),
  831. wire.NewTLVBE(wire.LocateTLVTagsRightsMaxCertsLen, uint16(1000)),
  832. wire.NewTLVBE(wire.LocateTLVTagsRightsMaxMaxShortCapabilities, uint16(1000)),
  833. },
  834. },
  835. },
  836. }
  837. assert.Equal(t, expectSNAC, outputSNAC)
  838. }
  839. func TestLocateService_DirInfo(t *testing.T) {
  840. tests := []struct {
  841. // name is the unit test name
  842. name string
  843. // instance is the session of the user setting info
  844. instance *state.SessionInstance
  845. // inputSNAC is the SNAC sent from client to server
  846. inputSNAC wire.SNACMessage
  847. // expectOutput is the SNAC sent from the server to client
  848. expectOutput wire.SNACMessage
  849. // mockParams is the list of params sent to mocks that satisfy this
  850. // method's dependencies
  851. mockParams mockParams
  852. // wantErr is the expected error
  853. wantErr error
  854. }{
  855. {
  856. name: "happy path",
  857. instance: newTestInstance("test-user"),
  858. inputSNAC: wire.SNACMessage{
  859. Frame: wire.SNACFrame{
  860. RequestID: 1234,
  861. },
  862. Body: wire.SNAC_0x02_0x0B_LocateGetDirInfo{
  863. ScreenName: "test-user",
  864. },
  865. },
  866. expectOutput: wire.SNACMessage{
  867. Frame: wire.SNACFrame{
  868. FoodGroup: wire.Locate,
  869. SubGroup: wire.LocateGetDirReply,
  870. RequestID: 1234,
  871. },
  872. Body: wire.SNAC_0x02_0x0C_LocateGetDirReply{
  873. Status: wire.LocateGetDirReplyOK,
  874. TLVBlock: wire.TLVBlock{
  875. TLVList: wire.TLVList{
  876. wire.NewTLVBE(wire.ODirTLVFirstName, "John"),
  877. wire.NewTLVBE(wire.ODirTLVLastName, "Doe"),
  878. wire.NewTLVBE(wire.ODirTLVMiddleName, "A"),
  879. wire.NewTLVBE(wire.ODirTLVMaidenName, "Smith"),
  880. wire.NewTLVBE(wire.ODirTLVCountry, "USA"),
  881. wire.NewTLVBE(wire.ODirTLVState, "CA"),
  882. wire.NewTLVBE(wire.ODirTLVCity, "San Francisco"),
  883. wire.NewTLVBE(wire.ODirTLVNickName, "Johnny"),
  884. wire.NewTLVBE(wire.ODirTLVZIP, "94107"),
  885. wire.NewTLVBE(wire.ODirTLVAddress, "123 Main St"),
  886. },
  887. },
  888. },
  889. },
  890. mockParams: mockParams{
  891. profileManagerParams: profileManagerParams{
  892. getUserParams: getUserParams{
  893. {
  894. screenName: state.NewIdentScreenName("test-user"),
  895. result: &state.User{
  896. AIMDirectoryInfo: state.AIMNameAndAddr{
  897. FirstName: "John",
  898. LastName: "Doe",
  899. MiddleName: "A",
  900. MaidenName: "Smith",
  901. Country: "USA",
  902. State: "CA",
  903. City: "San Francisco",
  904. NickName: "Johnny",
  905. ZIPCode: "94107",
  906. Address: "123 Main St",
  907. },
  908. },
  909. },
  910. },
  911. },
  912. },
  913. },
  914. {
  915. name: "user not found",
  916. instance: newTestInstance("test-user"),
  917. inputSNAC: wire.SNACMessage{
  918. Frame: wire.SNACFrame{
  919. RequestID: 1234,
  920. },
  921. Body: wire.SNAC_0x02_0x0B_LocateGetDirInfo{
  922. ScreenName: "test-user",
  923. },
  924. },
  925. expectOutput: wire.SNACMessage{
  926. Frame: wire.SNACFrame{
  927. FoodGroup: wire.Locate,
  928. SubGroup: wire.LocateGetDirReply,
  929. RequestID: 1234,
  930. },
  931. Body: wire.SNAC_0x02_0x0C_LocateGetDirReply{
  932. Status: wire.LocateGetDirReplyOK,
  933. TLVBlock: wire.TLVBlock{
  934. TLVList: wire.TLVList{},
  935. },
  936. },
  937. },
  938. mockParams: mockParams{
  939. profileManagerParams: profileManagerParams{
  940. getUserParams: getUserParams{
  941. {
  942. screenName: state.NewIdentScreenName("test-user"),
  943. result: nil,
  944. },
  945. },
  946. },
  947. },
  948. },
  949. }
  950. for _, tt := range tests {
  951. t.Run(tt.name, func(t *testing.T) {
  952. profileManager := newMockProfileManager(t)
  953. for _, params := range tt.mockParams.profileManagerParams.getUserParams {
  954. profileManager.EXPECT().
  955. User(matchContext(), params.screenName).
  956. Return(params.result, params.err)
  957. }
  958. messageRelayer := newMockMessageRelayer(t)
  959. svc := NewLocateService(nil, messageRelayer, profileManager, nil, nil, nil)
  960. outputSNAC, err := svc.DirInfo(context.Background(), tt.inputSNAC.Frame, tt.inputSNAC.Body.(wire.SNAC_0x02_0x0B_LocateGetDirInfo))
  961. assert.NoError(t, err)
  962. assert.Equal(t, tt.expectOutput, outputSNAC)
  963. })
  964. }
  965. }