icbm_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. package handler
  2. import (
  3. "testing"
  4. "github.com/mk6i/retro-aim-server/oscar"
  5. "github.com/mk6i/retro-aim-server/state"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/mock"
  8. )
  9. func TestICBMService_ChannelMsgToHostHandler(t *testing.T) {
  10. cases := []struct {
  11. // name is the unit test name
  12. name string
  13. // blockedState is the response to the sender/recipient block check
  14. blockedState state.BlockedState
  15. // recipRetrieveErr is the error returned by the recipient session
  16. // lookup
  17. recipRetrieveErr error
  18. senderSession *state.Session
  19. recipientSession *state.Session
  20. // inputSNAC is the SNAC sent by the sender client
  21. inputSNAC oscar.SNACMessage
  22. // expectSNACToClient is the SNAC sent from the server to the
  23. // recipient client
  24. expectSNACToClient oscar.SNACMessage
  25. // inputSNAC is the SNAC frame sent from the server to the recipient
  26. // client
  27. expectOutput *oscar.SNACMessage
  28. }{
  29. {
  30. name: "transmit message from sender to recipient, ack message back to sender",
  31. blockedState: state.BlockedNo,
  32. senderSession: newTestSession("sender-screen-name", sessOptWarning(10)),
  33. recipientSession: newTestSession("recipient-screen-name", sessOptWarning(20)),
  34. inputSNAC: oscar.SNACMessage{
  35. Frame: oscar.SNACFrame{
  36. RequestID: 1234,
  37. },
  38. Body: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  39. ScreenName: "recipient-screen-name",
  40. TLVRestBlock: oscar.TLVRestBlock{
  41. TLVList: oscar.TLVList{
  42. {
  43. Tag: oscar.ICBMTLVTagRequestHostAck,
  44. Value: []byte{},
  45. },
  46. },
  47. },
  48. },
  49. },
  50. expectSNACToClient: oscar.SNACMessage{
  51. Frame: oscar.SNACFrame{
  52. FoodGroup: oscar.ICBM,
  53. SubGroup: oscar.ICBMChannelMsgToClient,
  54. },
  55. Body: oscar.SNAC_0x04_0x07_ICBMChannelMsgToClient{
  56. TLVUserInfo: oscar.TLVUserInfo{
  57. ScreenName: "sender-screen-name",
  58. WarningLevel: 10,
  59. },
  60. TLVRestBlock: oscar.TLVRestBlock{
  61. TLVList: oscar.TLVList{
  62. {
  63. Tag: oscar.ICBMTLVTagsWantEvents,
  64. Value: []byte{},
  65. },
  66. {
  67. Tag: oscar.ICBMTLVTagRequestHostAck,
  68. Value: []byte{},
  69. },
  70. },
  71. },
  72. },
  73. },
  74. expectOutput: &oscar.SNACMessage{
  75. Frame: oscar.SNACFrame{
  76. FoodGroup: oscar.ICBM,
  77. SubGroup: oscar.ICBMHostAck,
  78. RequestID: 1234,
  79. },
  80. Body: oscar.SNAC_0x04_0x0C_ICBMHostAck{
  81. ScreenName: "recipient-screen-name",
  82. },
  83. },
  84. },
  85. {
  86. name: "transmit message from sender to recipient, don't ack message back to sender",
  87. blockedState: state.BlockedNo,
  88. senderSession: newTestSession("sender-screen-name", sessOptWarning(10)),
  89. recipientSession: newTestSession("recipient-screen-name", sessOptWarning(20)),
  90. inputSNAC: oscar.SNACMessage{
  91. Frame: oscar.SNACFrame{
  92. RequestID: 1234,
  93. },
  94. Body: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  95. ScreenName: "recipient-screen-name",
  96. TLVRestBlock: oscar.TLVRestBlock{
  97. TLVList: oscar.TLVList{},
  98. },
  99. },
  100. },
  101. expectSNACToClient: oscar.SNACMessage{
  102. Frame: oscar.SNACFrame{
  103. FoodGroup: oscar.ICBM,
  104. SubGroup: oscar.ICBMChannelMsgToClient,
  105. },
  106. Body: oscar.SNAC_0x04_0x07_ICBMChannelMsgToClient{
  107. TLVUserInfo: oscar.TLVUserInfo{
  108. ScreenName: "sender-screen-name",
  109. WarningLevel: 10,
  110. },
  111. TLVRestBlock: oscar.TLVRestBlock{
  112. TLVList: oscar.TLVList{
  113. {
  114. Tag: oscar.ICBMTLVTagsWantEvents,
  115. Value: []byte{},
  116. },
  117. },
  118. },
  119. },
  120. },
  121. expectOutput: nil,
  122. },
  123. {
  124. name: "don't transmit message from sender to recipient because sender has blocked recipient",
  125. blockedState: state.BlockedA,
  126. senderSession: newTestSession("sender-screen-name", sessOptWarning(10)),
  127. recipientSession: newTestSession("recipient-screen-name", sessOptWarning(20)),
  128. inputSNAC: oscar.SNACMessage{
  129. Frame: oscar.SNACFrame{
  130. RequestID: 1234,
  131. },
  132. Body: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  133. ScreenName: "recipient-screen-name",
  134. TLVRestBlock: oscar.TLVRestBlock{
  135. TLVList: oscar.TLVList{
  136. {
  137. Tag: oscar.ICBMTLVTagRequestHostAck,
  138. Value: []byte{},
  139. },
  140. },
  141. },
  142. },
  143. },
  144. expectOutput: &oscar.SNACMessage{
  145. Frame: oscar.SNACFrame{
  146. FoodGroup: oscar.ICBM,
  147. SubGroup: oscar.ICBMErr,
  148. RequestID: 1234,
  149. },
  150. Body: oscar.SNACError{
  151. Code: oscar.ErrorCodeInLocalPermitDeny,
  152. },
  153. },
  154. },
  155. {
  156. name: "don't transmit message from sender to recipient because recipient has blocked sender",
  157. blockedState: state.BlockedB,
  158. senderSession: newTestSession("sender-screen-name", sessOptWarning(10)),
  159. recipientSession: newTestSession("recipient-screen-name", sessOptWarning(20)),
  160. inputSNAC: oscar.SNACMessage{
  161. Frame: oscar.SNACFrame{
  162. RequestID: 1234,
  163. },
  164. Body: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  165. ScreenName: "recipient-screen-name",
  166. TLVRestBlock: oscar.TLVRestBlock{
  167. TLVList: oscar.TLVList{
  168. {
  169. Tag: oscar.ICBMTLVTagRequestHostAck,
  170. Value: []byte{},
  171. },
  172. },
  173. },
  174. },
  175. },
  176. expectOutput: &oscar.SNACMessage{
  177. Frame: oscar.SNACFrame{
  178. FoodGroup: oscar.ICBM,
  179. SubGroup: oscar.ICBMErr,
  180. RequestID: 1234,
  181. },
  182. Body: oscar.SNACError{
  183. Code: oscar.ErrorCodeNotLoggedOn,
  184. },
  185. },
  186. },
  187. {
  188. name: "don't transmit message from sender to recipient because recipient doesn't exist",
  189. blockedState: state.BlockedNo,
  190. senderSession: newTestSession("sender-screen-name", sessOptWarning(10)),
  191. recipientSession: nil,
  192. inputSNAC: oscar.SNACMessage{
  193. Frame: oscar.SNACFrame{
  194. RequestID: 1234,
  195. },
  196. Body: oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  197. ScreenName: "recipient-screen-name",
  198. TLVRestBlock: oscar.TLVRestBlock{
  199. TLVList: oscar.TLVList{
  200. {
  201. Tag: oscar.ICBMTLVTagRequestHostAck,
  202. Value: []byte{},
  203. },
  204. },
  205. },
  206. },
  207. },
  208. expectOutput: &oscar.SNACMessage{
  209. Frame: oscar.SNACFrame{
  210. FoodGroup: oscar.ICBM,
  211. SubGroup: oscar.ICBMErr,
  212. RequestID: 1234,
  213. },
  214. Body: oscar.SNACError{
  215. Code: oscar.ErrorCodeNotLoggedOn,
  216. },
  217. },
  218. },
  219. }
  220. for _, tc := range cases {
  221. t.Run(tc.name, func(t *testing.T) {
  222. //
  223. // initialize dependencies
  224. //
  225. feedbagManager := newMockFeedbagManager(t)
  226. feedbagManager.EXPECT().
  227. BlockedState(tc.senderSession.ScreenName(),
  228. tc.inputSNAC.Body.(oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost).ScreenName).
  229. Return(tc.blockedState, nil).
  230. Maybe()
  231. messageRelayer := newMockMessageRelayer(t)
  232. messageRelayer.EXPECT().
  233. RetrieveByScreenName(tc.inputSNAC.Body.(oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost).ScreenName).
  234. Return(tc.recipientSession).
  235. Maybe()
  236. if tc.recipientSession != nil {
  237. messageRelayer.EXPECT().
  238. RelayToScreenName(mock.Anything, tc.recipientSession.ScreenName(), tc.expectSNACToClient).
  239. Maybe()
  240. }
  241. //
  242. // send input SNAC
  243. //
  244. svc := NewICBMService(messageRelayer, feedbagManager)
  245. outputSNAC, err := svc.ChannelMsgToHostHandler(nil, tc.senderSession, tc.inputSNAC.Frame,
  246. tc.inputSNAC.Body.(oscar.SNAC_0x04_0x06_ICBMChannelMsgToHost))
  247. assert.NoError(t, err)
  248. //
  249. // verify output
  250. //
  251. assert.Equal(t, tc.expectOutput, outputSNAC)
  252. })
  253. }
  254. }
  255. func TestICBMService_ClientEventHandler(t *testing.T) {
  256. cases := []struct {
  257. // name is the unit test name
  258. name string
  259. // blockedState is the response to the sender/recipient block check
  260. blockedState state.BlockedState
  261. // senderScreenName is the screen name of the user sending the event
  262. senderScreenName string
  263. // inputSNAC is the SNAC sent by the sender client
  264. inputSNAC oscar.SNACMessage
  265. // expectSNACToClient is the SNAC sent from the server to the
  266. // recipient client
  267. expectSNACToClient oscar.SNACMessage
  268. }{
  269. {
  270. name: "transmit message from sender to recipient",
  271. blockedState: state.BlockedNo,
  272. senderScreenName: "sender-screen-name",
  273. inputSNAC: oscar.SNACMessage{
  274. Frame: oscar.SNACFrame{
  275. RequestID: 1234,
  276. },
  277. Body: oscar.SNAC_0x04_0x14_ICBMClientEvent{
  278. Cookie: 12345678,
  279. ChannelID: 42,
  280. ScreenName: "recipient-screen-name",
  281. Event: 12,
  282. },
  283. },
  284. expectSNACToClient: oscar.SNACMessage{
  285. Frame: oscar.SNACFrame{
  286. FoodGroup: oscar.ICBM,
  287. SubGroup: oscar.ICBMClientEvent,
  288. RequestID: 1234,
  289. },
  290. Body: oscar.SNAC_0x04_0x14_ICBMClientEvent{
  291. Cookie: 12345678,
  292. ChannelID: 42,
  293. ScreenName: "sender-screen-name",
  294. Event: 12,
  295. },
  296. },
  297. },
  298. {
  299. name: "don't transmit message from sender to recipient because sender has blocked recipient",
  300. blockedState: state.BlockedA,
  301. senderScreenName: "sender-screen-name",
  302. inputSNAC: oscar.SNACMessage{
  303. Frame: oscar.SNACFrame{
  304. RequestID: 1234,
  305. },
  306. Body: oscar.SNAC_0x04_0x14_ICBMClientEvent{
  307. ScreenName: "recipient-screen-name",
  308. },
  309. },
  310. },
  311. }
  312. for _, tc := range cases {
  313. t.Run(tc.name, func(t *testing.T) {
  314. //
  315. // initialize dependencies
  316. //
  317. feedbagManager := newMockFeedbagManager(t)
  318. feedbagManager.EXPECT().
  319. BlockedState(tc.senderScreenName, tc.inputSNAC.Body.(oscar.SNAC_0x04_0x14_ICBMClientEvent).ScreenName).
  320. Return(tc.blockedState, nil).
  321. Maybe()
  322. messageRelayer := newMockMessageRelayer(t)
  323. if tc.blockedState == state.BlockedNo {
  324. messageRelayer.EXPECT().
  325. RelayToScreenName(mock.Anything, tc.inputSNAC.Body.(oscar.SNAC_0x04_0x14_ICBMClientEvent).ScreenName,
  326. tc.expectSNACToClient)
  327. }
  328. //
  329. // send input SNAC
  330. //
  331. senderSession := newTestSession(tc.senderScreenName)
  332. svc := NewICBMService(messageRelayer, feedbagManager)
  333. assert.NoError(t, svc.ClientEventHandler(nil, senderSession, tc.inputSNAC.Frame,
  334. tc.inputSNAC.Body.(oscar.SNAC_0x04_0x14_ICBMClientEvent)))
  335. })
  336. }
  337. }
  338. func TestICBMService_EvilRequestHandler(t *testing.T) {
  339. cases := []struct {
  340. // name is the unit test name
  341. name string
  342. // blockedState is the response to the sender/recipient block check
  343. blockedState state.BlockedState
  344. // recipRetrieveErr is the error returned by the recipient session
  345. // lookup
  346. recipRetrieveErr error
  347. // senderScreenName is the session name of the user sending the IM
  348. senderSession *state.Session
  349. // recipientScreenName is the screen name of the user receiving the IM
  350. recipientScreenName string
  351. // recipientBuddies is a list of the recipient's buddies that get
  352. // updated warning level
  353. recipientBuddies []string
  354. broadcastMessage oscar.SNACMessage
  355. // inputSNAC is the SNAC sent by the sender client
  356. inputSNAC oscar.SNACMessage
  357. // expectSNACToClient is the SNAC sent from the server to the
  358. // recipient client
  359. expectSNACToClient oscar.SNACMessage
  360. expectOutput oscar.SNACMessage
  361. }{
  362. {
  363. name: "transmit anonymous warning from sender to recipient",
  364. blockedState: state.BlockedNo,
  365. senderSession: newTestSession("sender-screen-name"),
  366. recipientScreenName: "recipient-screen-name",
  367. broadcastMessage: oscar.SNACMessage{
  368. Frame: oscar.SNACFrame{
  369. FoodGroup: oscar.Buddy,
  370. SubGroup: oscar.BuddyArrived,
  371. },
  372. Body: oscar.SNAC_0x03_0x0B_BuddyArrived{
  373. TLVUserInfo: newTestSession("recipient-screen-name", sessOptCannedSignonTime, sessOptWarning(evilDeltaAnon)).TLVUserInfo(),
  374. },
  375. },
  376. recipientBuddies: []string{"buddy1", "buddy2"},
  377. inputSNAC: oscar.SNACMessage{
  378. Frame: oscar.SNACFrame{
  379. RequestID: 1234,
  380. },
  381. Body: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
  382. SendAs: 1, // make it anonymous
  383. ScreenName: "recipient-screen-name",
  384. },
  385. },
  386. expectSNACToClient: oscar.SNACMessage{
  387. Frame: oscar.SNACFrame{
  388. FoodGroup: oscar.OService,
  389. SubGroup: oscar.OServiceEvilNotification,
  390. },
  391. Body: oscar.SNAC_0x01_0x10_OServiceEvilNotificationAnon{
  392. NewEvil: evilDeltaAnon,
  393. },
  394. },
  395. expectOutput: oscar.SNACMessage{
  396. Frame: oscar.SNACFrame{
  397. FoodGroup: oscar.ICBM,
  398. SubGroup: oscar.ICBMEvilReply,
  399. RequestID: 1234,
  400. },
  401. Body: oscar.SNAC_0x04_0x09_ICBMEvilReply{
  402. EvilDeltaApplied: 30,
  403. UpdatedEvilValue: 30,
  404. },
  405. },
  406. },
  407. {
  408. name: "transmit non-anonymous warning from sender to recipient",
  409. blockedState: state.BlockedNo,
  410. senderSession: newTestSession("sender-screen-name"),
  411. recipientScreenName: "recipient-screen-name",
  412. recipientBuddies: []string{"buddy1", "buddy2"},
  413. broadcastMessage: oscar.SNACMessage{
  414. Frame: oscar.SNACFrame{
  415. FoodGroup: oscar.Buddy,
  416. SubGroup: oscar.BuddyArrived,
  417. },
  418. Body: oscar.SNAC_0x03_0x0B_BuddyArrived{
  419. TLVUserInfo: newTestSession("recipient-screen-name", sessOptCannedSignonTime, sessOptWarning(evilDelta)).TLVUserInfo(),
  420. },
  421. },
  422. inputSNAC: oscar.SNACMessage{
  423. Frame: oscar.SNACFrame{
  424. RequestID: 1234,
  425. },
  426. Body: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
  427. SendAs: 0, // make it identified
  428. ScreenName: "recipient-screen-name",
  429. },
  430. },
  431. expectSNACToClient: oscar.SNACMessage{
  432. Frame: oscar.SNACFrame{
  433. FoodGroup: oscar.OService,
  434. SubGroup: oscar.OServiceEvilNotification,
  435. },
  436. Body: oscar.SNAC_0x01_0x10_OServiceEvilNotification{
  437. NewEvil: evilDelta,
  438. TLVUserInfo: oscar.TLVUserInfo{
  439. ScreenName: "sender-screen-name",
  440. WarningLevel: 100,
  441. },
  442. },
  443. },
  444. expectOutput: oscar.SNACMessage{
  445. Frame: oscar.SNACFrame{
  446. FoodGroup: oscar.ICBM,
  447. SubGroup: oscar.ICBMEvilReply,
  448. RequestID: 1234,
  449. },
  450. Body: oscar.SNAC_0x04_0x09_ICBMEvilReply{
  451. EvilDeltaApplied: 100,
  452. UpdatedEvilValue: 100,
  453. },
  454. },
  455. },
  456. {
  457. name: "don't transmit non-anonymous warning from sender to recipient because sender has blocked recipient",
  458. blockedState: state.BlockedA,
  459. senderSession: newTestSession("sender-screen-name"),
  460. recipientScreenName: "recipient-screen-name",
  461. recipientBuddies: []string{"buddy1", "buddy2"},
  462. inputSNAC: oscar.SNACMessage{
  463. Frame: oscar.SNACFrame{
  464. RequestID: 1234,
  465. },
  466. Body: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
  467. SendAs: 0, // make it identified
  468. ScreenName: "recipient-screen-name",
  469. },
  470. },
  471. expectOutput: oscar.SNACMessage{
  472. Frame: oscar.SNACFrame{
  473. FoodGroup: oscar.ICBM,
  474. SubGroup: oscar.ICBMErr,
  475. RequestID: 1234,
  476. },
  477. Body: oscar.SNACError{
  478. Code: oscar.ErrorCodeNotLoggedOn,
  479. },
  480. },
  481. },
  482. {
  483. name: "don't transmit non-anonymous warning from sender to recipient because recipient has blocked sender",
  484. blockedState: state.BlockedB,
  485. senderSession: newTestSession("sender-screen-name"),
  486. recipientScreenName: "recipient-screen-name",
  487. recipientBuddies: []string{"buddy1", "buddy2"},
  488. inputSNAC: oscar.SNACMessage{
  489. Frame: oscar.SNACFrame{
  490. RequestID: 1234,
  491. },
  492. Body: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
  493. SendAs: 0, // make it identified
  494. ScreenName: "recipient-screen-name",
  495. },
  496. },
  497. expectOutput: oscar.SNACMessage{
  498. Frame: oscar.SNACFrame{
  499. FoodGroup: oscar.ICBM,
  500. SubGroup: oscar.ICBMErr,
  501. RequestID: 1234,
  502. },
  503. Body: oscar.SNACError{
  504. Code: oscar.ErrorCodeNotLoggedOn,
  505. },
  506. },
  507. },
  508. {
  509. name: "don't let users block themselves",
  510. senderSession: newTestSession("sender-screen-name"),
  511. recipientScreenName: "sender-screen-name",
  512. inputSNAC: oscar.SNACMessage{
  513. Frame: oscar.SNACFrame{
  514. RequestID: 1234,
  515. },
  516. Body: oscar.SNAC_0x04_0x08_ICBMEvilRequest{
  517. SendAs: 0, // make it identified
  518. ScreenName: "sender-screen-name",
  519. },
  520. },
  521. expectOutput: oscar.SNACMessage{
  522. Frame: oscar.SNACFrame{
  523. FoodGroup: oscar.ICBM,
  524. SubGroup: oscar.ICBMErr,
  525. RequestID: 1234,
  526. },
  527. Body: oscar.SNACError{
  528. Code: oscar.ErrorCodeNotSupportedByHost,
  529. },
  530. },
  531. },
  532. }
  533. for _, tc := range cases {
  534. t.Run(tc.name, func(t *testing.T) {
  535. //
  536. // initialize dependencies
  537. //
  538. feedbagManager := newMockFeedbagManager(t)
  539. feedbagManager.EXPECT().
  540. BlockedState(tc.senderSession.ScreenName(), tc.recipientScreenName).
  541. Return(tc.blockedState, nil).
  542. Maybe()
  543. feedbagManager.EXPECT().
  544. AdjacentUsers(tc.recipientScreenName).
  545. Return(tc.recipientBuddies, nil).
  546. Maybe()
  547. recipSess := newTestSession(tc.recipientScreenName, sessOptCannedSignonTime)
  548. messageRelayer := newMockMessageRelayer(t)
  549. messageRelayer.EXPECT().
  550. RetrieveByScreenName(tc.recipientScreenName).
  551. Return(recipSess).
  552. Maybe()
  553. messageRelayer.EXPECT().
  554. RelayToScreenName(mock.Anything, tc.recipientScreenName, tc.expectSNACToClient).
  555. Maybe()
  556. messageRelayer.EXPECT().
  557. RelayToScreenNames(mock.Anything, tc.recipientBuddies, tc.broadcastMessage).
  558. Maybe()
  559. //
  560. // send input SNAC
  561. //
  562. senderSession := newTestSession(tc.senderSession.ScreenName())
  563. svc := NewICBMService(messageRelayer, feedbagManager)
  564. outputSNAC, err := svc.EvilRequestHandler(nil, senderSession, tc.inputSNAC.Frame,
  565. tc.inputSNAC.Body.(oscar.SNAC_0x04_0x08_ICBMEvilRequest))
  566. assert.NoError(t, err)
  567. assert.Equal(t, tc.expectOutput, outputSNAC)
  568. })
  569. }
  570. }
  571. func TestICBMService_ParameterQueryHandler(t *testing.T) {
  572. svc := NewICBMService(nil, nil)
  573. have := svc.ParameterQueryHandler(nil, oscar.SNACFrame{RequestID: 1234})
  574. want := oscar.SNACMessage{
  575. Frame: oscar.SNACFrame{
  576. FoodGroup: oscar.ICBM,
  577. SubGroup: oscar.ICBMParameterReply,
  578. RequestID: 1234,
  579. },
  580. Body: oscar.SNAC_0x04_0x05_ICBMParameterReply{
  581. MaxSlots: 100,
  582. ICBMFlags: 3,
  583. MaxIncomingICBMLen: 512,
  584. MaxSourceEvil: 999,
  585. MaxDestinationEvil: 999,
  586. MinInterICBMInterval: 0,
  587. },
  588. }
  589. assert.Equal(t, want, have)
  590. }