cmd_client_test.go 100 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744
  1. package toc
  2. import (
  3. "context"
  4. "encoding/hex"
  5. "io"
  6. "log/slog"
  7. "testing"
  8. "github.com/google/uuid"
  9. "github.com/stretchr/testify/assert"
  10. "github.com/stretchr/testify/mock"
  11. "github.com/mk6i/retro-aim-server/state"
  12. "github.com/mk6i/retro-aim-server/wire"
  13. )
  14. func TestOSCARProxy_AddBuddy(t *testing.T) {
  15. cases := []struct {
  16. // name is the unit test name
  17. name string
  18. // me is the TOC user session
  19. me *state.Session
  20. // givenCmd is the TOC command
  21. givenCmd []byte
  22. // wantMsg is the expected TOC response
  23. wantMsg string
  24. // mockParams is the list of params sent to mocks that satisfy this
  25. // method's dependencies
  26. mockParams mockParams
  27. }{
  28. {
  29. name: "successfully add buddies",
  30. me: newTestSession("me"),
  31. givenCmd: []byte("toc_add_buddy friend1 friend2 friend3"),
  32. mockParams: mockParams{
  33. buddyParams: buddyParams{
  34. addBuddiesParams: addBuddiesParams{
  35. {
  36. me: state.NewIdentScreenName("me"),
  37. inBody: wire.SNAC_0x03_0x04_BuddyAddBuddies{
  38. Buddies: []struct {
  39. ScreenName string `oscar:"len_prefix=uint8"`
  40. }{
  41. {ScreenName: "friend1"},
  42. {ScreenName: "friend2"},
  43. {ScreenName: "friend3"},
  44. },
  45. },
  46. },
  47. },
  48. },
  49. },
  50. },
  51. {
  52. name: "add buddies, receive error from buddy service",
  53. me: newTestSession("me"),
  54. givenCmd: []byte("toc_add_buddy friend1"),
  55. mockParams: mockParams{
  56. buddyParams: buddyParams{
  57. addBuddiesParams: addBuddiesParams{
  58. {
  59. me: state.NewIdentScreenName("me"),
  60. inBody: wire.SNAC_0x03_0x04_BuddyAddBuddies{
  61. Buddies: []struct {
  62. ScreenName string `oscar:"len_prefix=uint8"`
  63. }{
  64. {ScreenName: "friend1"},
  65. },
  66. },
  67. err: io.EOF,
  68. },
  69. },
  70. },
  71. },
  72. wantMsg: cmdInternalSvcErr,
  73. },
  74. {
  75. name: "bad command",
  76. givenCmd: []byte(`toc_add_buddy_bad`),
  77. wantMsg: cmdInternalSvcErr,
  78. },
  79. }
  80. for _, tc := range cases {
  81. t.Run(tc.name, func(t *testing.T) {
  82. ctx := context.Background()
  83. buddySvc := newMockBuddyService(t)
  84. for _, params := range tc.mockParams.addBuddiesParams {
  85. buddySvc.EXPECT().
  86. AddBuddies(ctx, matchSession(params.me), params.inBody).
  87. Return(params.err)
  88. }
  89. svc := OSCARProxy{
  90. Logger: slog.Default(),
  91. BuddyService: buddySvc,
  92. }
  93. msg := svc.AddBuddy(ctx, tc.me, tc.givenCmd)
  94. assert.Equal(t, tc.wantMsg, msg)
  95. })
  96. }
  97. }
  98. func TestOSCARProxy_AddPermit(t *testing.T) {
  99. cases := []struct {
  100. // name is the unit test name
  101. name string
  102. // me is the TOC user session
  103. me *state.Session
  104. // givenCmd is the TOC command
  105. givenCmd []byte
  106. // wantMsg is the expected TOC response
  107. wantMsg string
  108. // mockParams is the list of params sent to mocks that satisfy this
  109. // method's dependencies
  110. mockParams mockParams
  111. }{
  112. {
  113. name: "successfully permit buddies",
  114. me: newTestSession("me"),
  115. givenCmd: []byte("toc_add_permit friend1 friend2 friend3"),
  116. mockParams: mockParams{
  117. permitDenyParams: permitDenyParams{
  118. addPermListEntriesParams: addPermListEntriesParams{
  119. {
  120. me: state.NewIdentScreenName("me"),
  121. body: wire.SNAC_0x09_0x05_PermitDenyAddPermListEntries{
  122. Users: []struct {
  123. ScreenName string `oscar:"len_prefix=uint8"`
  124. }{
  125. {ScreenName: "friend1"},
  126. {ScreenName: "friend2"},
  127. {ScreenName: "friend3"},
  128. },
  129. },
  130. },
  131. },
  132. },
  133. },
  134. },
  135. {
  136. name: "permit buddies, receive error from buddy service",
  137. me: newTestSession("me"),
  138. givenCmd: []byte("toc_add_permit friend1"),
  139. mockParams: mockParams{
  140. permitDenyParams: permitDenyParams{
  141. addPermListEntriesParams: addPermListEntriesParams{
  142. {
  143. me: state.NewIdentScreenName("me"),
  144. body: wire.SNAC_0x09_0x05_PermitDenyAddPermListEntries{
  145. Users: []struct {
  146. ScreenName string `oscar:"len_prefix=uint8"`
  147. }{
  148. {ScreenName: "friend1"},
  149. },
  150. },
  151. err: io.EOF,
  152. },
  153. },
  154. },
  155. },
  156. wantMsg: cmdInternalSvcErr,
  157. },
  158. {
  159. name: "bad command",
  160. givenCmd: []byte(`toc_remove_buddy_bad`),
  161. wantMsg: cmdInternalSvcErr,
  162. },
  163. }
  164. for _, tc := range cases {
  165. t.Run(tc.name, func(t *testing.T) {
  166. ctx := context.Background()
  167. pdSvc := newMockPermitDenyService(t)
  168. for _, params := range tc.mockParams.addPermListEntriesParams {
  169. pdSvc.EXPECT().
  170. AddPermListEntries(ctx, matchSession(params.me), params.body).
  171. Return(params.err)
  172. }
  173. svc := OSCARProxy{
  174. Logger: slog.Default(),
  175. PermitDenyService: pdSvc,
  176. }
  177. msg := svc.AddPermit(ctx, tc.me, tc.givenCmd)
  178. assert.Equal(t, tc.wantMsg, msg)
  179. })
  180. }
  181. }
  182. func TestOSCARProxy_AddDeny(t *testing.T) {
  183. cases := []struct {
  184. // name is the unit test name
  185. name string
  186. // me is the TOC user session
  187. me *state.Session
  188. // givenCmd is the TOC command
  189. givenCmd []byte
  190. // wantMsg is the expected TOC response
  191. wantMsg string
  192. // mockParams is the list of params sent to mocks that satisfy this
  193. // method's dependencies
  194. mockParams mockParams
  195. }{
  196. {
  197. name: "successfully deny buddies",
  198. me: newTestSession("me"),
  199. givenCmd: []byte("toc_add_deny friend1 friend2 friend3"),
  200. mockParams: mockParams{
  201. permitDenyParams: permitDenyParams{
  202. addDenyListEntriesParams: addDenyListEntriesParams{
  203. {
  204. me: state.NewIdentScreenName("me"),
  205. body: wire.SNAC_0x09_0x07_PermitDenyAddDenyListEntries{
  206. Users: []struct {
  207. ScreenName string `oscar:"len_prefix=uint8"`
  208. }{
  209. {ScreenName: "friend1"},
  210. {ScreenName: "friend2"},
  211. {ScreenName: "friend3"},
  212. },
  213. },
  214. },
  215. },
  216. },
  217. },
  218. },
  219. {
  220. name: "deny buddies, receive error from buddy service",
  221. me: newTestSession("me"),
  222. givenCmd: []byte("toc_add_deny friend1"),
  223. mockParams: mockParams{
  224. permitDenyParams: permitDenyParams{
  225. addDenyListEntriesParams: addDenyListEntriesParams{
  226. {
  227. me: state.NewIdentScreenName("me"),
  228. body: wire.SNAC_0x09_0x07_PermitDenyAddDenyListEntries{
  229. Users: []struct {
  230. ScreenName string `oscar:"len_prefix=uint8"`
  231. }{
  232. {ScreenName: "friend1"},
  233. },
  234. },
  235. err: io.EOF,
  236. },
  237. },
  238. },
  239. },
  240. wantMsg: cmdInternalSvcErr,
  241. },
  242. {
  243. name: "bad command",
  244. givenCmd: []byte(`toc_add_deny_bad`),
  245. wantMsg: cmdInternalSvcErr,
  246. },
  247. }
  248. for _, tc := range cases {
  249. t.Run(tc.name, func(t *testing.T) {
  250. ctx := context.Background()
  251. pdSvc := newMockPermitDenyService(t)
  252. for _, params := range tc.mockParams.addDenyListEntriesParams {
  253. pdSvc.EXPECT().
  254. AddDenyListEntries(ctx, matchSession(params.me), params.body).
  255. Return(params.err)
  256. }
  257. svc := OSCARProxy{
  258. Logger: slog.Default(),
  259. PermitDenyService: pdSvc,
  260. }
  261. msg := svc.AddDeny(ctx, tc.me, tc.givenCmd)
  262. assert.Equal(t, tc.wantMsg, msg)
  263. })
  264. }
  265. }
  266. func TestOSCARProxy_ChangePassword(t *testing.T) {
  267. cases := []struct {
  268. // name is the unit test name
  269. name string
  270. // me is the TOC user session
  271. me *state.Session
  272. // givenCmd is the TOC command
  273. givenCmd []byte
  274. // wantMsg is the expected TOC response
  275. wantMsg string
  276. // mockParams is the list of params sent to mocks that satisfy this
  277. // method's dependencies
  278. mockParams mockParams
  279. }{
  280. {
  281. name: "successfully change password",
  282. me: newTestSession("me"),
  283. givenCmd: []byte("toc_change_passwd oldpass newpass"),
  284. mockParams: mockParams{
  285. adminParams: adminParams{
  286. infoChangeRequestParams: infoChangeRequestParams{
  287. {
  288. me: state.NewIdentScreenName("me"),
  289. inBody: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  290. TLVRestBlock: wire.TLVRestBlock{
  291. TLVList: wire.TLVList{
  292. wire.NewTLVBE(wire.AdminTLVOldPassword, "oldpass"),
  293. wire.NewTLVBE(wire.AdminTLVNewPassword, "newpass"),
  294. },
  295. },
  296. },
  297. msg: wire.SNACMessage{
  298. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  299. Permissions: wire.AdminInfoPermissionsReadWrite,
  300. TLVBlock: wire.TLVBlock{
  301. TLVList: wire.TLVList{
  302. wire.NewTLVBE(wire.AdminTLVNewPassword, []byte{}),
  303. },
  304. },
  305. },
  306. },
  307. },
  308. },
  309. },
  310. },
  311. wantMsg: "ADMIN_PASSWD_STATUS:0",
  312. },
  313. {
  314. name: "change password - invalid password length",
  315. me: newTestSession("me"),
  316. givenCmd: []byte("toc_change_passwd oldpass np"),
  317. mockParams: mockParams{
  318. adminParams: adminParams{
  319. infoChangeRequestParams: infoChangeRequestParams{
  320. {
  321. me: state.NewIdentScreenName("me"),
  322. inBody: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  323. TLVRestBlock: wire.TLVRestBlock{
  324. TLVList: wire.TLVList{
  325. wire.NewTLVBE(wire.AdminTLVOldPassword, "oldpass"),
  326. wire.NewTLVBE(wire.AdminTLVNewPassword, "np"),
  327. },
  328. },
  329. },
  330. msg: wire.SNACMessage{
  331. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  332. Permissions: wire.AdminInfoPermissionsReadWrite,
  333. TLVBlock: wire.TLVBlock{
  334. TLVList: wire.TLVList{
  335. wire.NewTLVBE(wire.AdminTLVNewPassword, []byte{}),
  336. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorInvalidPasswordLength),
  337. },
  338. },
  339. },
  340. },
  341. },
  342. },
  343. },
  344. },
  345. wantMsg: "ERROR:911",
  346. },
  347. {
  348. name: "change password - incorrect password",
  349. me: newTestSession("me"),
  350. givenCmd: []byte("toc_change_passwd oldpass baddpass"),
  351. mockParams: mockParams{
  352. adminParams: adminParams{
  353. infoChangeRequestParams: infoChangeRequestParams{
  354. {
  355. me: state.NewIdentScreenName("me"),
  356. inBody: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  357. TLVRestBlock: wire.TLVRestBlock{
  358. TLVList: wire.TLVList{
  359. wire.NewTLVBE(wire.AdminTLVOldPassword, "oldpass"),
  360. wire.NewTLVBE(wire.AdminTLVNewPassword, "baddpass"),
  361. },
  362. },
  363. },
  364. msg: wire.SNACMessage{
  365. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  366. Permissions: wire.AdminInfoPermissionsReadWrite,
  367. TLVBlock: wire.TLVBlock{
  368. TLVList: wire.TLVList{
  369. wire.NewTLVBE(wire.AdminTLVNewPassword, []byte{}),
  370. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorValidatePassword),
  371. },
  372. },
  373. },
  374. },
  375. },
  376. },
  377. },
  378. },
  379. wantMsg: "ERROR:912",
  380. },
  381. {
  382. name: "change password - catch-all error response",
  383. me: newTestSession("me"),
  384. givenCmd: []byte("toc_change_passwd oldpass baddpass"),
  385. mockParams: mockParams{
  386. adminParams: adminParams{
  387. infoChangeRequestParams: infoChangeRequestParams{
  388. {
  389. me: state.NewIdentScreenName("me"),
  390. inBody: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  391. TLVRestBlock: wire.TLVRestBlock{
  392. TLVList: wire.TLVList{
  393. wire.NewTLVBE(wire.AdminTLVOldPassword, "oldpass"),
  394. wire.NewTLVBE(wire.AdminTLVNewPassword, "baddpass"),
  395. },
  396. },
  397. },
  398. msg: wire.SNACMessage{
  399. Body: wire.SNAC_0x07_0x05_AdminChangeReply{
  400. Permissions: wire.AdminInfoPermissionsReadWrite,
  401. TLVBlock: wire.TLVBlock{
  402. TLVList: wire.TLVList{
  403. wire.NewTLVBE(wire.AdminTLVNewPassword, []byte{}),
  404. wire.NewTLVBE(wire.AdminTLVErrorCode, wire.AdminInfoErrorAllOtherErrors),
  405. },
  406. },
  407. },
  408. },
  409. },
  410. },
  411. },
  412. },
  413. wantMsg: "ERROR:913",
  414. },
  415. {
  416. name: "change password - runtime error from admin svc",
  417. me: newTestSession("me"),
  418. givenCmd: []byte("toc_change_passwd oldpass baddpass"),
  419. mockParams: mockParams{
  420. adminParams: adminParams{
  421. infoChangeRequestParams: infoChangeRequestParams{
  422. {
  423. me: state.NewIdentScreenName("me"),
  424. inBody: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  425. TLVRestBlock: wire.TLVRestBlock{
  426. TLVList: wire.TLVList{
  427. wire.NewTLVBE(wire.AdminTLVOldPassword, "oldpass"),
  428. wire.NewTLVBE(wire.AdminTLVNewPassword, "baddpass"),
  429. },
  430. },
  431. },
  432. err: io.EOF,
  433. },
  434. },
  435. },
  436. },
  437. wantMsg: cmdInternalSvcErr,
  438. },
  439. {
  440. name: "change password - unexpected response from admin svc",
  441. me: newTestSession("me"),
  442. givenCmd: []byte("toc_change_passwd oldpass baddpass"),
  443. mockParams: mockParams{
  444. adminParams: adminParams{
  445. infoChangeRequestParams: infoChangeRequestParams{
  446. {
  447. me: state.NewIdentScreenName("me"),
  448. inBody: wire.SNAC_0x07_0x04_AdminInfoChangeRequest{
  449. TLVRestBlock: wire.TLVRestBlock{
  450. TLVList: wire.TLVList{
  451. wire.NewTLVBE(wire.AdminTLVOldPassword, "oldpass"),
  452. wire.NewTLVBE(wire.AdminTLVNewPassword, "baddpass"),
  453. },
  454. },
  455. },
  456. msg: wire.SNACMessage{
  457. Body: wire.SNACError{},
  458. },
  459. },
  460. },
  461. },
  462. },
  463. wantMsg: cmdInternalSvcErr,
  464. },
  465. {
  466. name: "bad command",
  467. givenCmd: []byte(`toc_change_passwd`),
  468. wantMsg: cmdInternalSvcErr,
  469. },
  470. }
  471. for _, tc := range cases {
  472. t.Run(tc.name, func(t *testing.T) {
  473. ctx := context.Background()
  474. adminSvc := newMockAdminService(t)
  475. for _, params := range tc.mockParams.infoChangeRequestParams {
  476. adminSvc.EXPECT().
  477. InfoChangeRequest(ctx, matchSession(params.me), wire.SNACFrame{}, params.inBody).
  478. Return(params.msg, params.err)
  479. }
  480. svc := OSCARProxy{
  481. Logger: slog.Default(),
  482. AdminService: adminSvc,
  483. }
  484. msg := svc.ChangePassword(ctx, tc.me, tc.givenCmd)
  485. assert.Equal(t, tc.wantMsg, msg)
  486. })
  487. }
  488. }
  489. func TestOSCARProxy_ChatAccept(t *testing.T) {
  490. fnNewChatNavParams := func(err error) chatNavParams {
  491. ret := chatNavParams{
  492. requestRoomInfoParams: requestRoomInfoParams{
  493. {
  494. inBody: wire.SNAC_0x0D_0x04_ChatNavRequestRoomInfo{
  495. Cookie: "the-cookie",
  496. Exchange: 4,
  497. InstanceNumber: 0,
  498. },
  499. },
  500. },
  501. }
  502. if err != nil {
  503. ret.requestRoomInfoParams[0].err = err
  504. } else {
  505. ret.requestRoomInfoParams[0].msg = wire.SNACMessage{
  506. Body: wire.SNAC_0x0D_0x09_ChatNavNavInfo{
  507. TLVRestBlock: wire.TLVRestBlock{
  508. TLVList: wire.TLVList{
  509. wire.NewTLVBE(wire.ChatNavTLVRoomInfo, wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
  510. Cookie: "the-cookie",
  511. TLVBlock: wire.TLVBlock{
  512. TLVList: wire.TLVList{
  513. wire.NewTLVBE(wire.ChatRoomTLVRoomName, "cool room"),
  514. },
  515. },
  516. }),
  517. },
  518. },
  519. },
  520. }
  521. }
  522. return ret
  523. }
  524. fnNewOServiceBOSParams := func(err error) oServiceParams {
  525. ret := oServiceParams{
  526. serviceRequestParams: serviceRequestParams{
  527. {
  528. me: state.NewIdentScreenName("me"),
  529. bodyIn: wire.SNAC_0x01_0x04_OServiceServiceRequest{
  530. FoodGroup: wire.Chat,
  531. TLVRestBlock: wire.TLVRestBlock{
  532. TLVList: wire.TLVList{
  533. wire.NewTLVBE(0x01, wire.SNAC_0x01_0x04_TLVRoomInfo{
  534. Cookie: "the-cookie",
  535. }),
  536. },
  537. },
  538. },
  539. },
  540. },
  541. }
  542. if err != nil {
  543. ret.serviceRequestParams[0].err = err
  544. } else {
  545. ret.serviceRequestParams[0].msg = wire.SNACMessage{
  546. Body: wire.SNAC_0x01_0x05_OServiceServiceResponse{
  547. TLVRestBlock: wire.TLVRestBlock{
  548. TLVList: wire.TLVList{
  549. wire.NewTLVBE(wire.OServiceTLVTagsLoginCookie, "chat-auth-cookie"),
  550. },
  551. },
  552. },
  553. }
  554. }
  555. return ret
  556. }
  557. fnNewAuthParams := func(err error) authParams {
  558. ret := authParams{
  559. registerChatSessionParams: registerChatSessionParams{
  560. {
  561. authCookie: []byte("chat-auth-cookie"),
  562. },
  563. },
  564. }
  565. if err != nil {
  566. ret.registerChatSessionParams[0].err = err
  567. } else {
  568. ret.registerChatSessionParams[0].sess = newTestSession("me-chat")
  569. }
  570. return ret
  571. }
  572. fnNewOServiceChatParams := func(err error) oServiceParams {
  573. ret := oServiceParams{
  574. clientOnlineParams: clientOnlineParams{
  575. {
  576. body: wire.SNAC_0x01_0x02_OServiceClientOnline{},
  577. me: state.NewIdentScreenName("me-chat"),
  578. },
  579. },
  580. }
  581. if err != nil {
  582. ret.clientOnlineParams[0].err = err
  583. }
  584. return ret
  585. }
  586. cases := []struct {
  587. // name is the unit test name
  588. name string
  589. // me is the TOC user session
  590. me *state.Session
  591. // givenCmd is the TOC command
  592. givenCmd []byte
  593. // givenChatRegistry is the chat registry passed to the function
  594. givenChatRegistry *ChatRegistry
  595. // wantMsg is the expected TOC response
  596. wantMsg string
  597. // wantChatID is the expected chat ID
  598. wantChatID int
  599. // mockParams is the list of params sent to mocks that satisfy this
  600. // method's dependencies
  601. mockParams mockParams
  602. }{
  603. {
  604. name: "successfully accept chat",
  605. me: newTestSession("me"),
  606. givenCmd: []byte(`toc_chat_accept 0`),
  607. givenChatRegistry: func() *ChatRegistry {
  608. reg := NewChatRegistry()
  609. reg.Add(wire.ICBMRoomInfo{
  610. Cookie: "the-cookie",
  611. Exchange: 4,
  612. Instance: 0,
  613. })
  614. return reg
  615. }(),
  616. mockParams: mockParams{
  617. chatNavParams: fnNewChatNavParams(nil),
  618. oServiceBOSParams: fnNewOServiceBOSParams(nil),
  619. authParams: fnNewAuthParams(nil),
  620. oServiceChatParams: fnNewOServiceChatParams(nil),
  621. },
  622. wantMsg: "CHAT_JOIN:0:cool room",
  623. },
  624. {
  625. name: "accept chat, receive error from chat oservice svc",
  626. me: newTestSession("me"),
  627. givenCmd: []byte(`toc_chat_accept 0`),
  628. givenChatRegistry: func() *ChatRegistry {
  629. reg := NewChatRegistry()
  630. reg.Add(wire.ICBMRoomInfo{
  631. Cookie: "the-cookie",
  632. Exchange: 4,
  633. Instance: 0,
  634. })
  635. return reg
  636. }(),
  637. mockParams: mockParams{
  638. chatNavParams: fnNewChatNavParams(nil),
  639. oServiceBOSParams: fnNewOServiceBOSParams(nil),
  640. authParams: fnNewAuthParams(nil),
  641. oServiceChatParams: fnNewOServiceChatParams(io.EOF),
  642. },
  643. wantMsg: cmdInternalSvcErr,
  644. },
  645. {
  646. name: "accept chat, receive error from auth svc",
  647. me: newTestSession("me"),
  648. givenCmd: []byte(`toc_chat_accept 0`),
  649. givenChatRegistry: func() *ChatRegistry {
  650. reg := NewChatRegistry()
  651. reg.Add(wire.ICBMRoomInfo{
  652. Cookie: "the-cookie",
  653. Exchange: 4,
  654. Instance: 0,
  655. })
  656. return reg
  657. }(),
  658. mockParams: mockParams{
  659. chatNavParams: fnNewChatNavParams(nil),
  660. oServiceBOSParams: fnNewOServiceBOSParams(nil),
  661. authParams: fnNewAuthParams(io.EOF),
  662. },
  663. wantMsg: cmdInternalSvcErr,
  664. },
  665. {
  666. name: "accept chat, receive error from BOS oservice svc",
  667. me: newTestSession("me"),
  668. givenCmd: []byte(`toc_chat_accept 0`),
  669. givenChatRegistry: func() *ChatRegistry {
  670. reg := NewChatRegistry()
  671. reg.Add(wire.ICBMRoomInfo{
  672. Cookie: "the-cookie",
  673. Exchange: 4,
  674. Instance: 0,
  675. })
  676. return reg
  677. }(),
  678. mockParams: mockParams{
  679. chatNavParams: fnNewChatNavParams(nil),
  680. oServiceBOSParams: fnNewOServiceBOSParams(io.EOF),
  681. },
  682. wantMsg: cmdInternalSvcErr,
  683. },
  684. {
  685. name: "accept chat, receive error from chat nav svc",
  686. me: newTestSession("me"),
  687. givenCmd: []byte(`toc_chat_accept 0`),
  688. givenChatRegistry: func() *ChatRegistry {
  689. reg := NewChatRegistry()
  690. reg.Add(wire.ICBMRoomInfo{
  691. Cookie: "the-cookie",
  692. Exchange: 4,
  693. Instance: 0,
  694. })
  695. return reg
  696. }(),
  697. mockParams: mockParams{
  698. chatNavParams: fnNewChatNavParams(io.EOF),
  699. },
  700. wantMsg: cmdInternalSvcErr,
  701. },
  702. {
  703. name: "chat doesn't exist",
  704. givenCmd: []byte(`toc_chat_accept 0`),
  705. givenChatRegistry: NewChatRegistry(),
  706. wantMsg: cmdInternalSvcErr,
  707. },
  708. {
  709. name: "bad command",
  710. givenCmd: []byte(`toc_chat_accept`),
  711. wantMsg: cmdInternalSvcErr,
  712. },
  713. {
  714. name: "bad exchange number",
  715. givenCmd: []byte(`toc_chat_accept four`),
  716. wantMsg: cmdInternalSvcErr,
  717. },
  718. }
  719. for _, tc := range cases {
  720. t.Run(tc.name, func(t *testing.T) {
  721. ctx := context.Background()
  722. chatNavSvc := newMockChatNavService(t)
  723. for _, params := range tc.mockParams.requestRoomInfoParams {
  724. chatNavSvc.EXPECT().
  725. RequestRoomInfo(ctx, wire.SNACFrame{}, params.inBody).
  726. Return(params.msg, params.err)
  727. }
  728. bosOServiceSvc := newMockOServiceService(t)
  729. for _, params := range tc.mockParams.oServiceBOSParams.serviceRequestParams {
  730. bosOServiceSvc.EXPECT().
  731. ServiceRequest(ctx, matchSession(params.me), wire.SNACFrame{}, params.bodyIn).
  732. Return(params.msg, params.err)
  733. }
  734. chatOServiceSvc := newMockOServiceService(t)
  735. for _, params := range tc.mockParams.oServiceChatParams.clientOnlineParams {
  736. chatOServiceSvc.EXPECT().
  737. ClientOnline(ctx, params.body, matchSession(params.me)).
  738. Return(params.err)
  739. }
  740. authSvc := newMockAuthService(t)
  741. for _, params := range tc.mockParams.authParams.registerChatSessionParams {
  742. authSvc.EXPECT().
  743. RegisterChatSession(ctx, params.authCookie).
  744. Return(params.sess, params.err)
  745. }
  746. svc := OSCARProxy{
  747. AuthService: authSvc,
  748. ChatNavService: chatNavSvc,
  749. Logger: slog.Default(),
  750. OServiceServiceBOS: bosOServiceSvc,
  751. OServiceServiceChat: chatOServiceSvc,
  752. }
  753. chatID, msg := svc.ChatAccept(ctx, tc.me, tc.givenChatRegistry, tc.givenCmd)
  754. assert.Equal(t, tc.wantMsg, msg)
  755. assert.Equal(t, tc.wantChatID, chatID)
  756. })
  757. }
  758. }
  759. func TestOSCARProxy_ChatInvite(t *testing.T) {
  760. cases := []struct {
  761. // name is the unit test name
  762. name string
  763. // me is the TOC user session
  764. me *state.Session
  765. // givenCmd is the TOC command
  766. givenCmd []byte
  767. // givenChatRegistry is the chat registry passed to the function
  768. givenChatRegistry *ChatRegistry
  769. // wantMsg is the expected TOC response
  770. wantMsg string
  771. // mockParams is the list of params sent to mocks that satisfy this
  772. // method's dependencies
  773. mockParams mockParams
  774. }{
  775. {
  776. name: "successfully send chat invitation",
  777. me: newTestSession("me"),
  778. givenCmd: []byte(`toc_chat_invite 0 "join my chat!" friend1`),
  779. givenChatRegistry: func() *ChatRegistry {
  780. reg := NewChatRegistry()
  781. reg.Add(wire.ICBMRoomInfo{
  782. Exchange: 4,
  783. Cookie: "the-cookie",
  784. Instance: 0,
  785. })
  786. return reg
  787. }(),
  788. mockParams: mockParams{
  789. icbmParams: icbmParams{
  790. channelMsgToHostParamsICBM: channelMsgToHostParamsICBM{
  791. {
  792. sender: state.NewIdentScreenName("me"),
  793. inBody: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  794. ChannelID: wire.ICBMChannelRendezvous,
  795. ScreenName: "friend1",
  796. TLVRestBlock: wire.TLVRestBlock{
  797. TLVList: wire.TLVList{
  798. wire.NewTLVBE(0x05, wire.ICBMCh2Fragment{
  799. Type: 0,
  800. Capability: capChat,
  801. TLVRestBlock: wire.TLVRestBlock{
  802. TLVList: wire.TLVList{
  803. wire.NewTLVBE(10, uint16(1)),
  804. wire.NewTLVBE(12, "join my chat!"),
  805. wire.NewTLVBE(13, "us-ascii"),
  806. wire.NewTLVBE(14, "en"),
  807. wire.NewTLVBE(10001, wire.ICBMRoomInfo{
  808. Exchange: 4,
  809. Cookie: "the-cookie",
  810. Instance: 0,
  811. }),
  812. },
  813. },
  814. }),
  815. },
  816. },
  817. },
  818. },
  819. },
  820. },
  821. },
  822. },
  823. {
  824. name: "send chat invitation, receive error from ICBM svc",
  825. me: newTestSession("me"),
  826. givenCmd: []byte(`toc_chat_invite 0 "join my chat!" friend1`),
  827. givenChatRegistry: func() *ChatRegistry {
  828. reg := NewChatRegistry()
  829. reg.Add(wire.ICBMRoomInfo{
  830. Exchange: 4,
  831. Cookie: "the-cookie",
  832. Instance: 0,
  833. })
  834. return reg
  835. }(),
  836. mockParams: mockParams{
  837. icbmParams: icbmParams{
  838. channelMsgToHostParamsICBM: channelMsgToHostParamsICBM{
  839. {
  840. sender: state.NewIdentScreenName("me"),
  841. inBody: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  842. ChannelID: wire.ICBMChannelRendezvous,
  843. ScreenName: "friend1",
  844. TLVRestBlock: wire.TLVRestBlock{
  845. TLVList: wire.TLVList{
  846. wire.NewTLVBE(0x05, wire.ICBMCh2Fragment{
  847. Type: 0,
  848. Capability: capChat,
  849. TLVRestBlock: wire.TLVRestBlock{
  850. TLVList: wire.TLVList{
  851. wire.NewTLVBE(10, uint16(1)),
  852. wire.NewTLVBE(12, "join my chat!"),
  853. wire.NewTLVBE(13, "us-ascii"),
  854. wire.NewTLVBE(14, "en"),
  855. wire.NewTLVBE(10001, wire.ICBMRoomInfo{
  856. Exchange: 4,
  857. Cookie: "the-cookie",
  858. Instance: 0,
  859. }),
  860. },
  861. },
  862. }),
  863. },
  864. },
  865. },
  866. err: io.EOF,
  867. },
  868. },
  869. },
  870. },
  871. wantMsg: cmdInternalSvcErr,
  872. },
  873. {
  874. name: "send chat invitation to non-existent room",
  875. me: newTestSession("me"),
  876. givenCmd: []byte(`toc_chat_invite 0 "join my chat!" friend1`),
  877. givenChatRegistry: NewChatRegistry(),
  878. wantMsg: cmdInternalSvcErr,
  879. },
  880. {
  881. name: "bad chat room ID",
  882. givenCmd: []byte(`toc_chat_invite zero "join my chat!" friend1`),
  883. wantMsg: cmdInternalSvcErr,
  884. },
  885. {
  886. name: "bad command",
  887. givenCmd: []byte(`toc_chat_invite`),
  888. wantMsg: cmdInternalSvcErr,
  889. },
  890. }
  891. for _, tc := range cases {
  892. t.Run(tc.name, func(t *testing.T) {
  893. ctx := context.Background()
  894. icbmSvc := newMockICBMService(t)
  895. for _, params := range tc.mockParams.channelMsgToHostParamsICBM {
  896. icbmSvc.EXPECT().
  897. ChannelMsgToHost(ctx, matchSession(params.sender), wire.SNACFrame{}, params.inBody).
  898. Return(nil, params.err)
  899. }
  900. svc := OSCARProxy{
  901. Logger: slog.Default(),
  902. ICBMService: icbmSvc,
  903. }
  904. msg := svc.ChatInvite(ctx, tc.me, tc.givenChatRegistry, tc.givenCmd)
  905. assert.Equal(t, tc.wantMsg, msg)
  906. })
  907. }
  908. }
  909. func TestOSCARProxy_ChatJoin(t *testing.T) {
  910. fnNewChatNavParams := func(err error) chatNavParams {
  911. ret := chatNavParams{
  912. createRoomParams: createRoomParams{
  913. {
  914. me: state.NewIdentScreenName("me"),
  915. inBody: wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
  916. Exchange: 4,
  917. Cookie: "create",
  918. TLVBlock: wire.TLVBlock{
  919. TLVList: wire.TLVList{
  920. wire.NewTLVBE(wire.ChatRoomTLVRoomName, "cool room"),
  921. },
  922. },
  923. },
  924. },
  925. },
  926. }
  927. if err != nil {
  928. ret.createRoomParams[0].err = err
  929. } else {
  930. ret.createRoomParams[0].msg = wire.SNACMessage{
  931. Body: wire.SNAC_0x0D_0x09_ChatNavNavInfo{
  932. TLVRestBlock: wire.TLVRestBlock{
  933. TLVList: wire.TLVList{
  934. wire.NewTLVBE(wire.ChatNavTLVRoomInfo, wire.SNAC_0x0E_0x02_ChatRoomInfoUpdate{
  935. Cookie: "the-cookie",
  936. }),
  937. },
  938. },
  939. },
  940. }
  941. }
  942. return ret
  943. }
  944. fnNewOServiceBOSParams := func(err error) oServiceParams {
  945. ret := oServiceParams{
  946. serviceRequestParams: serviceRequestParams{
  947. {
  948. me: state.NewIdentScreenName("me"),
  949. bodyIn: wire.SNAC_0x01_0x04_OServiceServiceRequest{
  950. FoodGroup: wire.Chat,
  951. TLVRestBlock: wire.TLVRestBlock{
  952. TLVList: wire.TLVList{
  953. wire.NewTLVBE(0x01, wire.SNAC_0x01_0x04_TLVRoomInfo{
  954. Cookie: "the-cookie",
  955. }),
  956. },
  957. },
  958. },
  959. },
  960. },
  961. }
  962. if err != nil {
  963. ret.serviceRequestParams[0].err = err
  964. } else {
  965. ret.serviceRequestParams[0].msg = wire.SNACMessage{
  966. Body: wire.SNAC_0x01_0x05_OServiceServiceResponse{
  967. TLVRestBlock: wire.TLVRestBlock{
  968. TLVList: wire.TLVList{
  969. wire.NewTLVBE(wire.OServiceTLVTagsLoginCookie, "chat-auth-cookie"),
  970. },
  971. },
  972. },
  973. }
  974. }
  975. return ret
  976. }
  977. fnNewAuthParams := func(err error) authParams {
  978. ret := authParams{
  979. registerChatSessionParams: registerChatSessionParams{
  980. {
  981. authCookie: []byte("chat-auth-cookie"),
  982. },
  983. },
  984. }
  985. if err != nil {
  986. ret.registerChatSessionParams[0].err = err
  987. } else {
  988. ret.registerChatSessionParams[0].sess = newTestSession("me-chat")
  989. }
  990. return ret
  991. }
  992. fnNewOServiceChatParams := func(err error) oServiceParams {
  993. ret := oServiceParams{
  994. clientOnlineParams: clientOnlineParams{
  995. {
  996. body: wire.SNAC_0x01_0x02_OServiceClientOnline{},
  997. me: state.NewIdentScreenName("me-chat"),
  998. },
  999. },
  1000. }
  1001. if err != nil {
  1002. ret.clientOnlineParams[0].err = err
  1003. }
  1004. return ret
  1005. }
  1006. cases := []struct {
  1007. // name is the unit test name
  1008. name string
  1009. // me is the TOC user session
  1010. me *state.Session
  1011. // givenCmd is the TOC command
  1012. givenCmd []byte
  1013. // givenChatRegistry is the chat registry passed to the function
  1014. givenChatRegistry *ChatRegistry
  1015. // wantMsg is the expected TOC response
  1016. wantMsg string
  1017. // wantChatID is the expected chat ID
  1018. wantChatID int
  1019. // mockParams is the list of params sent to mocks that satisfy this
  1020. // method's dependencies
  1021. mockParams mockParams
  1022. }{
  1023. {
  1024. name: "successfully join chat",
  1025. me: newTestSession("me"),
  1026. givenCmd: []byte(`toc_chat_join 4 "cool room"`),
  1027. givenChatRegistry: NewChatRegistry(),
  1028. mockParams: mockParams{
  1029. chatNavParams: fnNewChatNavParams(nil),
  1030. oServiceBOSParams: fnNewOServiceBOSParams(nil),
  1031. authParams: fnNewAuthParams(nil),
  1032. oServiceChatParams: fnNewOServiceChatParams(nil),
  1033. },
  1034. wantMsg: "CHAT_JOIN:0:cool room",
  1035. },
  1036. {
  1037. name: "join chat, receive error from chat oservice svc",
  1038. me: newTestSession("me"),
  1039. givenCmd: []byte(`toc_chat_join 4 "cool room"`),
  1040. givenChatRegistry: NewChatRegistry(),
  1041. mockParams: mockParams{
  1042. chatNavParams: fnNewChatNavParams(nil),
  1043. oServiceBOSParams: fnNewOServiceBOSParams(nil),
  1044. authParams: fnNewAuthParams(nil),
  1045. oServiceChatParams: fnNewOServiceChatParams(io.EOF),
  1046. },
  1047. wantMsg: cmdInternalSvcErr,
  1048. },
  1049. {
  1050. name: "join chat, receive error from auth svc",
  1051. me: newTestSession("me"),
  1052. givenCmd: []byte(`toc_chat_join 4 "cool room"`),
  1053. givenChatRegistry: NewChatRegistry(),
  1054. mockParams: mockParams{
  1055. chatNavParams: fnNewChatNavParams(nil),
  1056. oServiceBOSParams: fnNewOServiceBOSParams(nil),
  1057. authParams: fnNewAuthParams(io.EOF),
  1058. },
  1059. wantMsg: cmdInternalSvcErr,
  1060. },
  1061. {
  1062. name: "join chat, receive error from BOS oservice svc",
  1063. me: newTestSession("me"),
  1064. givenCmd: []byte(`toc_chat_join 4 "cool room"`),
  1065. givenChatRegistry: NewChatRegistry(),
  1066. mockParams: mockParams{
  1067. chatNavParams: fnNewChatNavParams(nil),
  1068. oServiceBOSParams: fnNewOServiceBOSParams(io.EOF),
  1069. },
  1070. wantMsg: cmdInternalSvcErr,
  1071. },
  1072. {
  1073. name: "join chat, receive error from chat nav svc",
  1074. me: newTestSession("me"),
  1075. givenCmd: []byte(`toc_chat_join 4 "cool room"`),
  1076. givenChatRegistry: NewChatRegistry(),
  1077. mockParams: mockParams{
  1078. chatNavParams: fnNewChatNavParams(io.EOF),
  1079. },
  1080. wantMsg: cmdInternalSvcErr,
  1081. },
  1082. {
  1083. name: "bad command",
  1084. givenCmd: []byte(`toc_chat_join`),
  1085. wantMsg: cmdInternalSvcErr,
  1086. },
  1087. {
  1088. name: "bad exchange number",
  1089. givenCmd: []byte(`toc_chat_join four "cool room"`),
  1090. wantMsg: cmdInternalSvcErr,
  1091. },
  1092. }
  1093. for _, tc := range cases {
  1094. t.Run(tc.name, func(t *testing.T) {
  1095. ctx := context.Background()
  1096. chatNavSvc := newMockChatNavService(t)
  1097. for _, params := range tc.mockParams.createRoomParams {
  1098. chatNavSvc.EXPECT().
  1099. CreateRoom(ctx, matchSession(params.me), wire.SNACFrame{}, params.inBody).
  1100. Return(params.msg, params.err)
  1101. }
  1102. bosOServiceSvc := newMockOServiceService(t)
  1103. for _, params := range tc.mockParams.oServiceBOSParams.serviceRequestParams {
  1104. bosOServiceSvc.EXPECT().
  1105. ServiceRequest(ctx, matchSession(params.me), wire.SNACFrame{}, params.bodyIn).
  1106. Return(params.msg, params.err)
  1107. }
  1108. chatOServiceSvc := newMockOServiceService(t)
  1109. for _, params := range tc.mockParams.oServiceChatParams.clientOnlineParams {
  1110. chatOServiceSvc.EXPECT().
  1111. ClientOnline(ctx, params.body, matchSession(params.me)).
  1112. Return(params.err)
  1113. }
  1114. authSvc := newMockAuthService(t)
  1115. for _, params := range tc.mockParams.authParams.registerChatSessionParams {
  1116. authSvc.EXPECT().
  1117. RegisterChatSession(ctx, params.authCookie).
  1118. Return(params.sess, params.err)
  1119. }
  1120. svc := OSCARProxy{
  1121. AuthService: authSvc,
  1122. ChatNavService: chatNavSvc,
  1123. Logger: slog.Default(),
  1124. OServiceServiceBOS: bosOServiceSvc,
  1125. OServiceServiceChat: chatOServiceSvc,
  1126. }
  1127. chatID, msg := svc.ChatJoin(ctx, tc.me, tc.givenChatRegistry, tc.givenCmd)
  1128. assert.Equal(t, tc.wantMsg, msg)
  1129. assert.Equal(t, tc.wantChatID, chatID)
  1130. })
  1131. }
  1132. }
  1133. func TestOSCARProxy_ChatLeave(t *testing.T) {
  1134. cases := []struct {
  1135. // name is the unit test name
  1136. name string
  1137. // me is the TOC user session
  1138. me *state.Session
  1139. // givenCmd is the TOC command
  1140. givenCmd []byte
  1141. // givenChatRegistry is the chat registry passed to the function
  1142. givenChatRegistry *ChatRegistry
  1143. // wantMsg is the expected TOC response
  1144. wantMsg string
  1145. // mockParams is the list of params sent to mocks that satisfy this
  1146. // method's dependencies
  1147. mockParams mockParams
  1148. }{
  1149. {
  1150. name: "successfully leave chat",
  1151. me: newTestSession("me"),
  1152. givenCmd: []byte(`toc_chat_leave 0`),
  1153. givenChatRegistry: func() *ChatRegistry {
  1154. reg := NewChatRegistry()
  1155. reg.RegisterSess(0, newTestSession("me"))
  1156. return reg
  1157. }(),
  1158. mockParams: mockParams{
  1159. authParams: authParams{
  1160. signoutChatParams: signoutChatParams{
  1161. {
  1162. me: state.NewIdentScreenName("me"),
  1163. },
  1164. },
  1165. },
  1166. },
  1167. wantMsg: "CHAT_LEFT:0",
  1168. },
  1169. {
  1170. name: "chat room ID with invalid format",
  1171. givenCmd: []byte(`toc_chat_leave zero`),
  1172. wantMsg: cmdInternalSvcErr,
  1173. },
  1174. {
  1175. name: "missing chat session",
  1176. givenCmd: []byte(`toc_chat_leave 0`),
  1177. givenChatRegistry: NewChatRegistry(),
  1178. wantMsg: cmdInternalSvcErr,
  1179. },
  1180. {
  1181. name: "bad command",
  1182. givenCmd: []byte(`toc_chat_leave`),
  1183. wantMsg: cmdInternalSvcErr,
  1184. },
  1185. }
  1186. for _, tc := range cases {
  1187. t.Run(tc.name, func(t *testing.T) {
  1188. ctx := context.Background()
  1189. authSvc := newMockAuthService(t)
  1190. for _, params := range tc.mockParams.signoutChatParams {
  1191. authSvc.EXPECT().SignoutChat(ctx, matchSession(params.me))
  1192. }
  1193. svc := OSCARProxy{
  1194. Logger: slog.Default(),
  1195. AuthService: authSvc,
  1196. }
  1197. msg := svc.ChatLeave(ctx, tc.givenChatRegistry, tc.givenCmd)
  1198. assert.Equal(t, tc.wantMsg, msg)
  1199. })
  1200. }
  1201. }
  1202. func TestOSCARProxy_ChatSend(t *testing.T) {
  1203. cases := []struct {
  1204. // name is the unit test name
  1205. name string
  1206. // me is the TOC user session
  1207. me *state.Session
  1208. // givenCmd is the TOC command
  1209. givenCmd []byte
  1210. // givenChatRegistry is the chat registry passed to the function
  1211. givenChatRegistry *ChatRegistry
  1212. // wantMsg is the expected TOC response
  1213. wantMsg string
  1214. // mockParams is the list of params sent to mocks that satisfy this
  1215. // method's dependencies
  1216. mockParams mockParams
  1217. }{
  1218. {
  1219. name: "successfully send chat message",
  1220. me: newTestSession("me"),
  1221. givenCmd: []byte(`toc_chat_send 0 "Hello world!"`),
  1222. givenChatRegistry: func() *ChatRegistry {
  1223. reg := NewChatRegistry()
  1224. reg.RegisterSess(0, newTestSession("me"))
  1225. return reg
  1226. }(),
  1227. mockParams: mockParams{
  1228. chatParams: chatParams{
  1229. channelMsgToHostParamsChat: channelMsgToHostParamsChat{
  1230. {
  1231. sender: state.NewIdentScreenName("me"),
  1232. inBody: wire.SNAC_0x0E_0x05_ChatChannelMsgToHost{
  1233. Channel: wire.ICBMChannelMIME,
  1234. TLVRestBlock: wire.TLVRestBlock{
  1235. TLVList: wire.TLVList{
  1236. wire.NewTLVBE(wire.ChatTLVEnableReflectionFlag, uint8(1)),
  1237. wire.NewTLVBE(wire.ChatTLVSenderInformation, newTestSession("me").TLVUserInfo()),
  1238. wire.NewTLVBE(wire.ChatTLVPublicWhisperFlag, []byte{}),
  1239. wire.NewTLVBE(wire.ChatTLVMessageInfo, wire.TLVRestBlock{
  1240. TLVList: wire.TLVList{
  1241. wire.NewTLVBE(wire.ChatTLVMessageInfoText, "Hello world!"),
  1242. },
  1243. }),
  1244. },
  1245. },
  1246. },
  1247. result: &wire.SNACMessage{
  1248. Body: wire.SNAC_0x0E_0x06_ChatChannelMsgToClient{
  1249. Channel: wire.ICBMChannelMIME,
  1250. TLVRestBlock: wire.TLVRestBlock{
  1251. TLVList: wire.TLVList{
  1252. wire.NewTLVBE(wire.ChatTLVSenderInformation,
  1253. newTestSession("me").TLVUserInfo()),
  1254. wire.NewTLVBE(wire.ChatTLVPublicWhisperFlag, []byte{}),
  1255. wire.NewTLVBE(wire.ChatTLVMessageInfo, wire.TLVRestBlock{
  1256. TLVList: wire.TLVList{
  1257. wire.NewTLVBE(wire.ChatTLVMessageInfoText, "Hello world!"),
  1258. },
  1259. }),
  1260. },
  1261. },
  1262. },
  1263. },
  1264. },
  1265. },
  1266. },
  1267. },
  1268. wantMsg: "CHAT_IN:0:me:F:Hello world!",
  1269. },
  1270. {
  1271. name: "send chat message, receive error from chat svc",
  1272. me: newTestSession("me"),
  1273. givenCmd: []byte(`toc_chat_send 0 "Hello world!"`),
  1274. givenChatRegistry: func() *ChatRegistry {
  1275. reg := NewChatRegistry()
  1276. reg.RegisterSess(0, newTestSession("me"))
  1277. return reg
  1278. }(),
  1279. mockParams: mockParams{
  1280. chatParams: chatParams{
  1281. channelMsgToHostParamsChat: channelMsgToHostParamsChat{
  1282. {
  1283. sender: state.NewIdentScreenName("me"),
  1284. inBody: wire.SNAC_0x0E_0x05_ChatChannelMsgToHost{
  1285. Channel: wire.ICBMChannelMIME,
  1286. TLVRestBlock: wire.TLVRestBlock{
  1287. TLVList: wire.TLVList{
  1288. wire.NewTLVBE(wire.ChatTLVEnableReflectionFlag, uint8(1)),
  1289. wire.NewTLVBE(wire.ChatTLVSenderInformation, newTestSession("me").TLVUserInfo()),
  1290. wire.NewTLVBE(wire.ChatTLVPublicWhisperFlag, []byte{}),
  1291. wire.NewTLVBE(wire.ChatTLVMessageInfo, wire.TLVRestBlock{
  1292. TLVList: wire.TLVList{
  1293. wire.NewTLVBE(wire.ChatTLVMessageInfoText, "Hello world!"),
  1294. },
  1295. }),
  1296. },
  1297. },
  1298. },
  1299. err: io.EOF,
  1300. },
  1301. },
  1302. },
  1303. },
  1304. wantMsg: cmdInternalSvcErr,
  1305. },
  1306. {
  1307. name: "send chat message, receive nil response from chat svc",
  1308. me: newTestSession("me"),
  1309. givenCmd: []byte(`toc_chat_send 0 "Hello world!"`),
  1310. givenChatRegistry: func() *ChatRegistry {
  1311. reg := NewChatRegistry()
  1312. reg.RegisterSess(0, newTestSession("me"))
  1313. return reg
  1314. }(),
  1315. mockParams: mockParams{
  1316. chatParams: chatParams{
  1317. channelMsgToHostParamsChat: channelMsgToHostParamsChat{
  1318. {
  1319. sender: state.NewIdentScreenName("me"),
  1320. inBody: wire.SNAC_0x0E_0x05_ChatChannelMsgToHost{
  1321. Channel: wire.ICBMChannelMIME,
  1322. TLVRestBlock: wire.TLVRestBlock{
  1323. TLVList: wire.TLVList{
  1324. wire.NewTLVBE(wire.ChatTLVEnableReflectionFlag, uint8(1)),
  1325. wire.NewTLVBE(wire.ChatTLVSenderInformation, newTestSession("me").TLVUserInfo()),
  1326. wire.NewTLVBE(wire.ChatTLVPublicWhisperFlag, []byte{}),
  1327. wire.NewTLVBE(wire.ChatTLVMessageInfo, wire.TLVRestBlock{
  1328. TLVList: wire.TLVList{
  1329. wire.NewTLVBE(wire.ChatTLVMessageInfoText, "Hello world!"),
  1330. },
  1331. }),
  1332. },
  1333. },
  1334. },
  1335. result: nil,
  1336. },
  1337. },
  1338. },
  1339. },
  1340. wantMsg: cmdInternalSvcErr,
  1341. },
  1342. {
  1343. name: "send chat message, receive unexpected response from chat svc",
  1344. me: newTestSession("me"),
  1345. givenCmd: []byte(`toc_chat_send 0 "Hello world!"`),
  1346. givenChatRegistry: func() *ChatRegistry {
  1347. reg := NewChatRegistry()
  1348. reg.RegisterSess(0, newTestSession("me"))
  1349. return reg
  1350. }(),
  1351. mockParams: mockParams{
  1352. chatParams: chatParams{
  1353. channelMsgToHostParamsChat: channelMsgToHostParamsChat{
  1354. {
  1355. sender: state.NewIdentScreenName("me"),
  1356. inBody: wire.SNAC_0x0E_0x05_ChatChannelMsgToHost{
  1357. Channel: wire.ICBMChannelMIME,
  1358. TLVRestBlock: wire.TLVRestBlock{
  1359. TLVList: wire.TLVList{
  1360. wire.NewTLVBE(wire.ChatTLVEnableReflectionFlag, uint8(1)),
  1361. wire.NewTLVBE(wire.ChatTLVSenderInformation, newTestSession("me").TLVUserInfo()),
  1362. wire.NewTLVBE(wire.ChatTLVPublicWhisperFlag, []byte{}),
  1363. wire.NewTLVBE(wire.ChatTLVMessageInfo, wire.TLVRestBlock{
  1364. TLVList: wire.TLVList{
  1365. wire.NewTLVBE(wire.ChatTLVMessageInfoText, "Hello world!"),
  1366. },
  1367. }),
  1368. },
  1369. },
  1370. },
  1371. result: &wire.SNACMessage{
  1372. Body: wire.SNACError{},
  1373. },
  1374. },
  1375. },
  1376. },
  1377. },
  1378. wantMsg: cmdInternalSvcErr,
  1379. },
  1380. {
  1381. name: "chat room ID with invalid format",
  1382. givenCmd: []byte(`toc_chat_send zero "Hello world!"`),
  1383. wantMsg: cmdInternalSvcErr,
  1384. },
  1385. {
  1386. name: "missing chat session",
  1387. givenCmd: []byte(`toc_chat_send 0 "Hello world!"`),
  1388. givenChatRegistry: NewChatRegistry(),
  1389. wantMsg: cmdInternalSvcErr,
  1390. },
  1391. {
  1392. name: "bad command",
  1393. givenCmd: []byte(`toc_chat_send`),
  1394. wantMsg: cmdInternalSvcErr,
  1395. },
  1396. }
  1397. for _, tc := range cases {
  1398. t.Run(tc.name, func(t *testing.T) {
  1399. ctx := context.Background()
  1400. chatSvc := newMockChatService(t)
  1401. for _, params := range tc.mockParams.channelMsgToHostParamsChat {
  1402. chatSvc.EXPECT().
  1403. ChannelMsgToHost(ctx, matchSession(params.sender), wire.SNACFrame{}, params.inBody).
  1404. Return(params.result, params.err)
  1405. }
  1406. svc := OSCARProxy{
  1407. Logger: slog.Default(),
  1408. ChatService: chatSvc,
  1409. }
  1410. msg := svc.ChatSend(ctx, tc.givenChatRegistry, tc.givenCmd)
  1411. assert.Equal(t, tc.wantMsg, msg)
  1412. })
  1413. }
  1414. }
  1415. func TestOSCARProxy_Evil(t *testing.T) {
  1416. cases := []struct {
  1417. // name is the unit test name
  1418. name string
  1419. // me is the TOC user session
  1420. me *state.Session
  1421. // givenCmd is the TOC command
  1422. givenCmd []byte
  1423. // wantMsg is the expected TOC response
  1424. wantMsg string
  1425. // mockParams is the list of params sent to mocks that satisfy this
  1426. // method's dependencies
  1427. mockParams mockParams
  1428. }{
  1429. {
  1430. name: "successfully warn normally",
  1431. me: newTestSession("me"),
  1432. givenCmd: []byte(`toc_evil them norm`),
  1433. mockParams: mockParams{
  1434. icbmParams: icbmParams{
  1435. evilRequestParams: evilRequestParams{
  1436. {
  1437. me: state.NewIdentScreenName("me"),
  1438. inBody: wire.SNAC_0x04_0x08_ICBMEvilRequest{
  1439. SendAs: 0,
  1440. ScreenName: "them",
  1441. },
  1442. msg: wire.SNACMessage{
  1443. Body: wire.SNAC_0x04_0x09_ICBMEvilReply{},
  1444. },
  1445. },
  1446. },
  1447. },
  1448. },
  1449. },
  1450. {
  1451. name: "successfully warn anonymously",
  1452. me: newTestSession("me"),
  1453. givenCmd: []byte(`toc_evil them anon`),
  1454. mockParams: mockParams{
  1455. icbmParams: icbmParams{
  1456. evilRequestParams: evilRequestParams{
  1457. {
  1458. me: state.NewIdentScreenName("me"),
  1459. inBody: wire.SNAC_0x04_0x08_ICBMEvilRequest{
  1460. SendAs: 1,
  1461. ScreenName: "them",
  1462. },
  1463. msg: wire.SNACMessage{
  1464. Body: wire.SNAC_0x04_0x09_ICBMEvilReply{},
  1465. },
  1466. },
  1467. },
  1468. },
  1469. },
  1470. },
  1471. {
  1472. name: "warn, receive error from ICBM service",
  1473. me: newTestSession("me"),
  1474. givenCmd: []byte(`toc_evil them anon`),
  1475. mockParams: mockParams{
  1476. icbmParams: icbmParams{
  1477. evilRequestParams: evilRequestParams{
  1478. {
  1479. me: state.NewIdentScreenName("me"),
  1480. inBody: wire.SNAC_0x04_0x08_ICBMEvilRequest{
  1481. SendAs: 1,
  1482. ScreenName: "them",
  1483. },
  1484. err: io.EOF,
  1485. },
  1486. },
  1487. },
  1488. },
  1489. wantMsg: cmdInternalSvcErr,
  1490. },
  1491. {
  1492. name: "warn, receive snac err",
  1493. me: newTestSession("me"),
  1494. givenCmd: []byte(`toc_evil them anon`),
  1495. mockParams: mockParams{
  1496. icbmParams: icbmParams{
  1497. evilRequestParams: evilRequestParams{
  1498. {
  1499. me: state.NewIdentScreenName("me"),
  1500. inBody: wire.SNAC_0x04_0x08_ICBMEvilRequest{
  1501. SendAs: 1,
  1502. ScreenName: "them",
  1503. },
  1504. msg: wire.SNACMessage{
  1505. Body: wire.SNACError{},
  1506. },
  1507. },
  1508. },
  1509. },
  1510. },
  1511. },
  1512. {
  1513. name: "warn, ICBM svc returns unexpected snac type",
  1514. me: newTestSession("me"),
  1515. givenCmd: []byte(`toc_evil them anon`),
  1516. mockParams: mockParams{
  1517. icbmParams: icbmParams{
  1518. evilRequestParams: evilRequestParams{
  1519. {
  1520. me: state.NewIdentScreenName("me"),
  1521. inBody: wire.SNAC_0x04_0x08_ICBMEvilRequest{
  1522. SendAs: 1,
  1523. ScreenName: "them",
  1524. },
  1525. msg: wire.SNACMessage{
  1526. Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{},
  1527. },
  1528. },
  1529. },
  1530. },
  1531. },
  1532. wantMsg: cmdInternalSvcErr,
  1533. },
  1534. {
  1535. name: "warn with incorrect type",
  1536. me: newTestSession("me"),
  1537. givenCmd: []byte(`toc_evil them blah`),
  1538. wantMsg: cmdInternalSvcErr,
  1539. },
  1540. {
  1541. name: "bad command",
  1542. givenCmd: []byte(`toc_evil`),
  1543. wantMsg: cmdInternalSvcErr,
  1544. },
  1545. }
  1546. for _, tc := range cases {
  1547. t.Run(tc.name, func(t *testing.T) {
  1548. ctx := context.Background()
  1549. icbmSvc := newMockICBMService(t)
  1550. for _, params := range tc.mockParams.evilRequestParams {
  1551. icbmSvc.EXPECT().
  1552. EvilRequest(ctx, matchSession(params.me), wire.SNACFrame{}, params.inBody).
  1553. Return(params.msg, params.err)
  1554. }
  1555. svc := OSCARProxy{
  1556. Logger: slog.Default(),
  1557. ICBMService: icbmSvc,
  1558. }
  1559. msg := svc.Evil(ctx, tc.me, tc.givenCmd)
  1560. assert.Equal(t, tc.wantMsg, msg)
  1561. })
  1562. }
  1563. }
  1564. func TestOSCARProxy_GetDirSearchURL(t *testing.T) {
  1565. cases := []struct {
  1566. // name is the unit test name
  1567. name string
  1568. // me is the TOC user session
  1569. me *state.Session
  1570. // givenCmd is the TOC command
  1571. givenCmd []byte
  1572. // wantMsg is the expected TOC response
  1573. wantMsg string
  1574. // mockParams is the list of params sent to mocks that satisfy this
  1575. // method's dependencies
  1576. mockParams mockParams
  1577. }{
  1578. {
  1579. name: "successfully request user info",
  1580. me: newTestSession("me"),
  1581. givenCmd: []byte(`toc_dir_search "first name":"middle name":"last name":"maiden name":"city":"state":"country":"email"`),
  1582. mockParams: mockParams{
  1583. cookieBakerParams: cookieBakerParams{
  1584. issueParams: issueParams{
  1585. {
  1586. data: []byte("me"),
  1587. returnData: []byte("monster"),
  1588. },
  1589. },
  1590. },
  1591. },
  1592. wantMsg: "GOTO_URL:search results:dir_search?city=city&cookie=6d6f6e73746572&country=country&email=email&first_name=first+name&last_name=last+name&maiden_name=maiden+name&middle_name=middle+name&state=state",
  1593. },
  1594. {
  1595. name: "successfully request user info by keywords",
  1596. me: newTestSession("me"),
  1597. givenCmd: []byte(`toc_dir_search ::::::::::"searchkw"`),
  1598. mockParams: mockParams{
  1599. cookieBakerParams: cookieBakerParams{
  1600. issueParams: issueParams{
  1601. {
  1602. data: []byte("me"),
  1603. returnData: []byte("monster"),
  1604. },
  1605. },
  1606. },
  1607. },
  1608. wantMsg: "GOTO_URL:search results:dir_search?cookie=6d6f6e73746572&keyword=searchkw",
  1609. },
  1610. {
  1611. name: "request user info with too many params",
  1612. me: newTestSession("me"),
  1613. givenCmd: []byte(`toc_dir_search ::::::::::::::::::::"searchkw"`),
  1614. wantMsg: cmdInternalSvcErr,
  1615. },
  1616. {
  1617. name: "request user info, get cookie issue error",
  1618. me: newTestSession("me"),
  1619. givenCmd: []byte(`toc_dir_search them`),
  1620. mockParams: mockParams{
  1621. cookieBakerParams: cookieBakerParams{
  1622. issueParams: issueParams{
  1623. {
  1624. data: []byte("me"),
  1625. returnErr: io.EOF,
  1626. },
  1627. },
  1628. },
  1629. },
  1630. wantMsg: cmdInternalSvcErr,
  1631. },
  1632. {
  1633. name: "bad command",
  1634. givenCmd: []byte(`toc_dir_search`),
  1635. wantMsg: cmdInternalSvcErr,
  1636. },
  1637. }
  1638. for _, tc := range cases {
  1639. t.Run(tc.name, func(t *testing.T) {
  1640. ctx := context.Background()
  1641. cookieBaker := newMockCookieBaker(t)
  1642. for _, params := range tc.mockParams.issueParams {
  1643. cookieBaker.EXPECT().
  1644. Issue(params.data).
  1645. Return(params.returnData, params.returnErr)
  1646. }
  1647. svc := OSCARProxy{
  1648. Logger: slog.Default(),
  1649. CookieBaker: cookieBaker,
  1650. }
  1651. msg := svc.GetDirSearchURL(ctx, tc.me, tc.givenCmd)
  1652. assert.Equal(t, tc.wantMsg, msg)
  1653. })
  1654. }
  1655. }
  1656. func TestOSCARProxy_GetDirURL(t *testing.T) {
  1657. cases := []struct {
  1658. // name is the unit test name
  1659. name string
  1660. // me is the TOC user session
  1661. me *state.Session
  1662. // givenCmd is the TOC command
  1663. givenCmd []byte
  1664. // wantMsg is the expected TOC response
  1665. wantMsg string
  1666. // mockParams is the list of params sent to mocks that satisfy this
  1667. // method's dependencies
  1668. mockParams mockParams
  1669. }{
  1670. {
  1671. name: "successfully request user dir info",
  1672. me: newTestSession("me"),
  1673. givenCmd: []byte(`toc_get_dir them`),
  1674. mockParams: mockParams{
  1675. cookieBakerParams: cookieBakerParams{
  1676. issueParams: issueParams{
  1677. {
  1678. data: []byte("me"),
  1679. returnData: []byte("monster"),
  1680. },
  1681. },
  1682. },
  1683. },
  1684. wantMsg: "GOTO_URL:directory info:dir_info?cookie=6d6f6e73746572&user=them",
  1685. },
  1686. {
  1687. name: "request user info, get cookie issue error",
  1688. me: newTestSession("me"),
  1689. givenCmd: []byte(`toc_get_dir them`),
  1690. mockParams: mockParams{
  1691. cookieBakerParams: cookieBakerParams{
  1692. issueParams: issueParams{
  1693. {
  1694. data: []byte("me"),
  1695. returnErr: io.EOF,
  1696. },
  1697. },
  1698. },
  1699. },
  1700. wantMsg: cmdInternalSvcErr,
  1701. },
  1702. {
  1703. name: "bad command",
  1704. givenCmd: []byte(`toc_get_dir`),
  1705. wantMsg: cmdInternalSvcErr,
  1706. },
  1707. }
  1708. for _, tc := range cases {
  1709. t.Run(tc.name, func(t *testing.T) {
  1710. ctx := context.Background()
  1711. cookieBaker := newMockCookieBaker(t)
  1712. for _, params := range tc.mockParams.issueParams {
  1713. cookieBaker.EXPECT().
  1714. Issue(params.data).
  1715. Return(params.returnData, params.returnErr)
  1716. }
  1717. svc := OSCARProxy{
  1718. Logger: slog.Default(),
  1719. CookieBaker: cookieBaker,
  1720. }
  1721. msg := svc.GetDirURL(ctx, tc.me, tc.givenCmd)
  1722. assert.Equal(t, tc.wantMsg, msg)
  1723. })
  1724. }
  1725. }
  1726. func TestOSCARProxy_GetInfoURL(t *testing.T) {
  1727. cases := []struct {
  1728. // name is the unit test name
  1729. name string
  1730. // me is the TOC user session
  1731. me *state.Session
  1732. // givenCmd is the TOC command
  1733. givenCmd []byte
  1734. // wantMsg is the expected TOC response
  1735. wantMsg string
  1736. // mockParams is the list of params sent to mocks that satisfy this
  1737. // method's dependencies
  1738. mockParams mockParams
  1739. }{
  1740. {
  1741. name: "successfully request user info",
  1742. me: newTestSession("me"),
  1743. givenCmd: []byte(`toc_get_info them`),
  1744. mockParams: mockParams{
  1745. cookieBakerParams: cookieBakerParams{
  1746. issueParams: issueParams{
  1747. {
  1748. data: []byte("me"),
  1749. returnData: []byte("monster"),
  1750. },
  1751. },
  1752. },
  1753. },
  1754. wantMsg: "GOTO_URL:profile:info?cookie=6d6f6e73746572&from=me&user=them",
  1755. },
  1756. {
  1757. name: "request user info, get cookie issue error",
  1758. me: newTestSession("me"),
  1759. givenCmd: []byte(`toc_get_info them`),
  1760. mockParams: mockParams{
  1761. cookieBakerParams: cookieBakerParams{
  1762. issueParams: issueParams{
  1763. {
  1764. data: []byte("me"),
  1765. returnErr: io.EOF,
  1766. },
  1767. },
  1768. },
  1769. },
  1770. wantMsg: cmdInternalSvcErr,
  1771. },
  1772. {
  1773. name: "bad command",
  1774. givenCmd: []byte(`toc_get_info`),
  1775. wantMsg: cmdInternalSvcErr,
  1776. },
  1777. }
  1778. for _, tc := range cases {
  1779. t.Run(tc.name, func(t *testing.T) {
  1780. ctx := context.Background()
  1781. cookieBaker := newMockCookieBaker(t)
  1782. for _, params := range tc.mockParams.issueParams {
  1783. cookieBaker.EXPECT().
  1784. Issue(params.data).
  1785. Return(params.returnData, params.returnErr)
  1786. }
  1787. svc := OSCARProxy{
  1788. Logger: slog.Default(),
  1789. CookieBaker: cookieBaker,
  1790. }
  1791. msg := svc.GetInfoURL(ctx, tc.me, tc.givenCmd)
  1792. assert.Equal(t, tc.wantMsg, msg)
  1793. })
  1794. }
  1795. }
  1796. func TestOSCARProxy_InitDone(t *testing.T) {
  1797. cases := []struct {
  1798. // name is the unit test name
  1799. name string
  1800. // me is the TOC user session
  1801. me *state.Session
  1802. // givenCmd is the TOC command
  1803. givenCmd []byte
  1804. // wantMsg is the expected TOC response
  1805. wantMsg string
  1806. // mockParams is the list of params sent to mocks that satisfy this
  1807. // method's dependencies
  1808. mockParams mockParams
  1809. }{
  1810. {
  1811. name: "successfully initialize connection",
  1812. me: newTestSession("me"),
  1813. givenCmd: []byte(`toc_init_done`),
  1814. mockParams: mockParams{
  1815. oServiceBOSParams: oServiceParams{
  1816. clientOnlineParams: clientOnlineParams{
  1817. {
  1818. me: state.NewIdentScreenName("me"),
  1819. body: wire.SNAC_0x01_0x02_OServiceClientOnline{},
  1820. },
  1821. },
  1822. },
  1823. },
  1824. },
  1825. {
  1826. name: "initialize connection, receive err from BOS oservice svc",
  1827. me: newTestSession("me"),
  1828. givenCmd: []byte(`toc_init_done`),
  1829. mockParams: mockParams{
  1830. oServiceBOSParams: oServiceParams{
  1831. clientOnlineParams: clientOnlineParams{
  1832. {
  1833. me: state.NewIdentScreenName("me"),
  1834. body: wire.SNAC_0x01_0x02_OServiceClientOnline{},
  1835. err: io.EOF,
  1836. },
  1837. },
  1838. },
  1839. },
  1840. wantMsg: cmdInternalSvcErr,
  1841. },
  1842. {
  1843. name: "bad command",
  1844. givenCmd: []byte(`toc_init_done_diff`),
  1845. wantMsg: cmdInternalSvcErr,
  1846. },
  1847. }
  1848. for _, tc := range cases {
  1849. t.Run(tc.name, func(t *testing.T) {
  1850. ctx := context.Background()
  1851. oSvc := newMockOServiceService(t)
  1852. for _, params := range tc.mockParams.oServiceBOSParams.clientOnlineParams {
  1853. oSvc.EXPECT().
  1854. ClientOnline(ctx, params.body, matchSession(params.me)).
  1855. Return(params.err)
  1856. }
  1857. svc := OSCARProxy{
  1858. Logger: slog.Default(),
  1859. OServiceServiceBOS: oSvc,
  1860. }
  1861. msg := svc.InitDone(ctx, tc.me, tc.givenCmd)
  1862. assert.Equal(t, tc.wantMsg, msg)
  1863. })
  1864. }
  1865. }
  1866. func TestOSCARProxy_RemoveBuddy(t *testing.T) {
  1867. cases := []struct {
  1868. // name is the unit test name
  1869. name string
  1870. // me is the TOC user session
  1871. me *state.Session
  1872. // givenCmd is the TOC command
  1873. givenCmd []byte
  1874. // wantMsg is the expected TOC response
  1875. wantMsg string
  1876. // mockParams is the list of params sent to mocks that satisfy this
  1877. // method's dependencies
  1878. mockParams mockParams
  1879. }{
  1880. {
  1881. name: "successfully remove buddies",
  1882. me: newTestSession("me"),
  1883. givenCmd: []byte("toc_remove_buddy friend1 friend2 friend3"),
  1884. mockParams: mockParams{
  1885. buddyParams: buddyParams{
  1886. delBuddiesParams: delBuddiesParams{
  1887. {
  1888. me: state.NewIdentScreenName("me"),
  1889. inBody: wire.SNAC_0x03_0x05_BuddyDelBuddies{
  1890. Buddies: []struct {
  1891. ScreenName string `oscar:"len_prefix=uint8"`
  1892. }{
  1893. {ScreenName: "friend1"},
  1894. {ScreenName: "friend2"},
  1895. {ScreenName: "friend3"},
  1896. },
  1897. },
  1898. },
  1899. },
  1900. },
  1901. },
  1902. },
  1903. {
  1904. name: "remove buddies, receive error from buddy service",
  1905. me: newTestSession("me"),
  1906. givenCmd: []byte("toc_remove_buddy friend1"),
  1907. mockParams: mockParams{
  1908. buddyParams: buddyParams{
  1909. delBuddiesParams: delBuddiesParams{
  1910. {
  1911. me: state.NewIdentScreenName("me"),
  1912. inBody: wire.SNAC_0x03_0x05_BuddyDelBuddies{
  1913. Buddies: []struct {
  1914. ScreenName string `oscar:"len_prefix=uint8"`
  1915. }{
  1916. {ScreenName: "friend1"},
  1917. },
  1918. },
  1919. err: io.EOF,
  1920. },
  1921. },
  1922. },
  1923. },
  1924. wantMsg: cmdInternalSvcErr,
  1925. },
  1926. {
  1927. name: "bad command",
  1928. givenCmd: []byte(`toc_remove_buddy_bad`),
  1929. wantMsg: cmdInternalSvcErr,
  1930. },
  1931. }
  1932. for _, tc := range cases {
  1933. t.Run(tc.name, func(t *testing.T) {
  1934. ctx := context.Background()
  1935. buddySvc := newMockBuddyService(t)
  1936. for _, params := range tc.mockParams.delBuddiesParams {
  1937. buddySvc.EXPECT().
  1938. DelBuddies(ctx, matchSession(params.me), params.inBody).
  1939. Return(params.err)
  1940. }
  1941. svc := OSCARProxy{
  1942. Logger: slog.Default(),
  1943. BuddyService: buddySvc,
  1944. }
  1945. msg := svc.RemoveBuddy(ctx, tc.me, tc.givenCmd)
  1946. assert.Equal(t, tc.wantMsg, msg)
  1947. })
  1948. }
  1949. }
  1950. func TestOSCARProxy_SendIM(t *testing.T) {
  1951. cases := []struct {
  1952. // name is the unit test name
  1953. name string
  1954. // me is the TOC user session
  1955. me *state.Session
  1956. // givenCmd is the TOC command
  1957. givenCmd []byte
  1958. // wantMsg is the expected TOC response
  1959. wantMsg string
  1960. // mockParams is the list of params sent to mocks that satisfy this
  1961. // method's dependencies
  1962. mockParams mockParams
  1963. }{
  1964. {
  1965. name: "successfully send instant message",
  1966. me: newTestSession("me"),
  1967. givenCmd: []byte(`toc_send_im chattingChuck "hello world!"`),
  1968. mockParams: mockParams{
  1969. icbmParams: icbmParams{
  1970. channelMsgToHostParamsICBM: channelMsgToHostParamsICBM{
  1971. {
  1972. sender: state.NewIdentScreenName("me"),
  1973. inBody: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  1974. ChannelID: wire.ICBMChannelIM,
  1975. ScreenName: "chattingChuck",
  1976. TLVRestBlock: wire.TLVRestBlock{
  1977. TLVList: wire.TLVList{
  1978. wire.NewTLVBE(wire.ICBMTLVAOLIMData, []wire.ICBMCh1Fragment{
  1979. {
  1980. ID: 5,
  1981. Version: 1,
  1982. Payload: []byte{1, 1, 2},
  1983. },
  1984. {
  1985. ID: 1,
  1986. Version: 1,
  1987. Payload: []byte{
  1988. 0x00, 0x00,
  1989. 0x00, 0x00,
  1990. 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
  1991. },
  1992. },
  1993. }),
  1994. },
  1995. },
  1996. },
  1997. },
  1998. },
  1999. },
  2000. },
  2001. },
  2002. {
  2003. name: "successfully auto-reply send instant message",
  2004. me: newTestSession("me"),
  2005. givenCmd: []byte(`toc_send_im chattingChuck "hello world!" auto`),
  2006. mockParams: mockParams{
  2007. icbmParams: icbmParams{
  2008. channelMsgToHostParamsICBM: channelMsgToHostParamsICBM{
  2009. {
  2010. sender: state.NewIdentScreenName("me"),
  2011. inBody: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  2012. ChannelID: wire.ICBMChannelIM,
  2013. ScreenName: "chattingChuck",
  2014. TLVRestBlock: wire.TLVRestBlock{
  2015. TLVList: wire.TLVList{
  2016. wire.NewTLVBE(wire.ICBMTLVAOLIMData, []wire.ICBMCh1Fragment{
  2017. {
  2018. ID: 5,
  2019. Version: 1,
  2020. Payload: []byte{1, 1, 2},
  2021. },
  2022. {
  2023. ID: 1,
  2024. Version: 1,
  2025. Payload: []byte{
  2026. 0x00, 0x00,
  2027. 0x00, 0x00,
  2028. 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
  2029. },
  2030. },
  2031. }),
  2032. wire.NewTLVBE(wire.ICBMTLVAutoResponse, []byte{}),
  2033. },
  2034. },
  2035. },
  2036. },
  2037. },
  2038. },
  2039. },
  2040. },
  2041. {
  2042. name: "send instant message, receive error from ICBM service",
  2043. me: newTestSession("me"),
  2044. givenCmd: []byte(`toc_send_im chattingChuck "hello world!"`),
  2045. mockParams: mockParams{
  2046. icbmParams: icbmParams{
  2047. channelMsgToHostParamsICBM: channelMsgToHostParamsICBM{
  2048. {
  2049. sender: state.NewIdentScreenName("me"),
  2050. inBody: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  2051. ChannelID: wire.ICBMChannelIM,
  2052. ScreenName: "chattingChuck",
  2053. TLVRestBlock: wire.TLVRestBlock{
  2054. TLVList: wire.TLVList{
  2055. wire.NewTLVBE(wire.ICBMTLVAOLIMData, []wire.ICBMCh1Fragment{
  2056. {
  2057. ID: 5,
  2058. Version: 1,
  2059. Payload: []byte{1, 1, 2},
  2060. },
  2061. {
  2062. ID: 1,
  2063. Version: 1,
  2064. Payload: []byte{
  2065. 0x00, 0x00,
  2066. 0x00, 0x00,
  2067. 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
  2068. },
  2069. },
  2070. }),
  2071. },
  2072. },
  2073. },
  2074. err: io.EOF,
  2075. },
  2076. },
  2077. },
  2078. },
  2079. wantMsg: cmdInternalSvcErr,
  2080. },
  2081. {
  2082. name: "bad command",
  2083. givenCmd: []byte(`toc_send_im`),
  2084. wantMsg: cmdInternalSvcErr,
  2085. },
  2086. }
  2087. for _, tc := range cases {
  2088. t.Run(tc.name, func(t *testing.T) {
  2089. ctx := context.Background()
  2090. icbmSvc := newMockICBMService(t)
  2091. for _, params := range tc.mockParams.channelMsgToHostParamsICBM {
  2092. icbmSvc.EXPECT().
  2093. ChannelMsgToHost(ctx, matchSession(params.sender), params.inFrame, params.inBody).
  2094. Return(params.result, params.err)
  2095. }
  2096. svc := OSCARProxy{
  2097. Logger: slog.Default(),
  2098. ICBMService: icbmSvc,
  2099. }
  2100. msg := svc.SendIM(ctx, tc.me, tc.givenCmd)
  2101. assert.Equal(t, tc.wantMsg, msg)
  2102. })
  2103. }
  2104. }
  2105. func TestOSCARProxy_SetAway(t *testing.T) {
  2106. cases := []struct {
  2107. // name is the unit test name
  2108. name string
  2109. // me is the TOC user session
  2110. me *state.Session
  2111. // givenCmd is the TOC command
  2112. givenCmd []byte
  2113. // wantMsg is the expected TOC response
  2114. wantMsg string
  2115. // mockParams is the list of params sent to mocks that satisfy this
  2116. // method's dependencies
  2117. mockParams mockParams
  2118. }{
  2119. {
  2120. name: "successfully set away with message",
  2121. me: newTestSession("me"),
  2122. givenCmd: []byte(`toc_set_away "I'm away from my computer right now."`),
  2123. mockParams: mockParams{
  2124. locateParams: locateParams{
  2125. setInfoParams: setInfoParams{
  2126. {
  2127. me: state.NewIdentScreenName("me"),
  2128. inBody: wire.SNAC_0x02_0x04_LocateSetInfo{
  2129. TLVRestBlock: wire.TLVRestBlock{
  2130. TLVList: wire.TLVList{
  2131. wire.NewTLVBE(wire.LocateTLVTagsInfoUnavailableData, "I'm away from my computer right now."),
  2132. },
  2133. },
  2134. },
  2135. },
  2136. },
  2137. },
  2138. },
  2139. },
  2140. {
  2141. name: "successfully set away without message",
  2142. me: newTestSession("me"),
  2143. givenCmd: []byte(`toc_set_away`),
  2144. mockParams: mockParams{
  2145. locateParams: locateParams{
  2146. setInfoParams: setInfoParams{
  2147. {
  2148. me: state.NewIdentScreenName("me"),
  2149. inBody: wire.SNAC_0x02_0x04_LocateSetInfo{
  2150. TLVRestBlock: wire.TLVRestBlock{
  2151. TLVList: wire.TLVList{
  2152. wire.NewTLVBE(wire.LocateTLVTagsInfoUnavailableData, ""),
  2153. },
  2154. },
  2155. },
  2156. },
  2157. },
  2158. },
  2159. },
  2160. },
  2161. {
  2162. name: "set away message, receive error from locate service",
  2163. me: newTestSession("me"),
  2164. givenCmd: []byte(`toc_set_away "I'm away from my computer right now."`),
  2165. mockParams: mockParams{
  2166. locateParams: locateParams{
  2167. setInfoParams: setInfoParams{
  2168. {
  2169. me: state.NewIdentScreenName("me"),
  2170. inBody: wire.SNAC_0x02_0x04_LocateSetInfo{
  2171. TLVRestBlock: wire.TLVRestBlock{
  2172. TLVList: wire.TLVList{
  2173. wire.NewTLVBE(wire.LocateTLVTagsInfoUnavailableData, "I'm away from my computer right now."),
  2174. },
  2175. },
  2176. },
  2177. err: io.EOF,
  2178. },
  2179. },
  2180. },
  2181. },
  2182. wantMsg: cmdInternalSvcErr,
  2183. },
  2184. {
  2185. name: "bad command",
  2186. givenCmd: []byte(`toc_set_away_bad`),
  2187. wantMsg: cmdInternalSvcErr,
  2188. },
  2189. }
  2190. for _, tc := range cases {
  2191. t.Run(tc.name, func(t *testing.T) {
  2192. ctx := context.Background()
  2193. locateSvc := newMockLocateService(t)
  2194. for _, params := range tc.mockParams.setInfoParams {
  2195. locateSvc.EXPECT().
  2196. SetInfo(ctx, matchSession(params.me), params.inBody).
  2197. Return(params.err)
  2198. }
  2199. svc := OSCARProxy{
  2200. Logger: slog.Default(),
  2201. LocateService: locateSvc,
  2202. }
  2203. msg := svc.SetAway(ctx, tc.me, tc.givenCmd)
  2204. assert.Equal(t, tc.wantMsg, msg)
  2205. })
  2206. }
  2207. }
  2208. func TestOSCARProxy_SetCaps(t *testing.T) {
  2209. cases := []struct {
  2210. // name is the unit test name
  2211. name string
  2212. // me is the TOC user session
  2213. me *state.Session
  2214. // givenCmd is the TOC command
  2215. givenCmd []byte
  2216. // wantMsg is the expected TOC response
  2217. wantMsg string
  2218. // mockParams is the list of params sent to mocks that satisfy this
  2219. // method's dependencies
  2220. mockParams mockParams
  2221. }{
  2222. {
  2223. name: "successfully set capabilities",
  2224. me: newTestSession("me"),
  2225. givenCmd: []byte(`toc_set_caps 09460000-4C7F-11D1-8222-444553540000 09460001-4C7F-11D1-8222-444553540000`),
  2226. mockParams: mockParams{
  2227. locateParams: locateParams{
  2228. setInfoParams: setInfoParams{
  2229. {
  2230. me: state.NewIdentScreenName("me"),
  2231. inBody: wire.SNAC_0x02_0x04_LocateSetInfo{
  2232. TLVRestBlock: wire.TLVRestBlock{
  2233. TLVList: wire.TLVList{
  2234. wire.NewTLVBE(wire.LocateTLVTagsInfoCapabilities, []uuid.UUID{
  2235. uuid.MustParse("09460000-4C7F-11D1-8222-444553540000"),
  2236. uuid.MustParse("09460001-4C7F-11D1-8222-444553540000"),
  2237. capChat,
  2238. }),
  2239. },
  2240. },
  2241. },
  2242. },
  2243. },
  2244. },
  2245. },
  2246. },
  2247. {
  2248. name: "set capability, receive error from locate service",
  2249. me: newTestSession("me"),
  2250. givenCmd: []byte(`toc_set_caps 09460000-4C7F-11D1-8222-444553540000`),
  2251. mockParams: mockParams{
  2252. locateParams: locateParams{
  2253. setInfoParams: setInfoParams{
  2254. {
  2255. me: state.NewIdentScreenName("me"),
  2256. inBody: wire.SNAC_0x02_0x04_LocateSetInfo{
  2257. TLVRestBlock: wire.TLVRestBlock{
  2258. TLVList: wire.TLVList{
  2259. wire.NewTLVBE(wire.LocateTLVTagsInfoCapabilities, []uuid.UUID{
  2260. uuid.MustParse("09460000-4C7F-11D1-8222-444553540000"),
  2261. capChat,
  2262. }),
  2263. },
  2264. },
  2265. },
  2266. err: io.EOF,
  2267. },
  2268. },
  2269. },
  2270. },
  2271. wantMsg: cmdInternalSvcErr,
  2272. },
  2273. {
  2274. name: "set malformed capability UUID",
  2275. me: newTestSession("me"),
  2276. givenCmd: []byte(`toc_set_caps 09460000-`),
  2277. wantMsg: cmdInternalSvcErr,
  2278. },
  2279. {
  2280. name: "bad command",
  2281. givenCmd: []byte(`toc_set_caps_bad`),
  2282. wantMsg: cmdInternalSvcErr,
  2283. },
  2284. }
  2285. for _, tc := range cases {
  2286. t.Run(tc.name, func(t *testing.T) {
  2287. ctx := context.Background()
  2288. locateSvc := newMockLocateService(t)
  2289. for _, params := range tc.mockParams.setInfoParams {
  2290. locateSvc.EXPECT().
  2291. SetInfo(ctx, matchSession(params.me), params.inBody).
  2292. Return(params.err)
  2293. }
  2294. svc := OSCARProxy{
  2295. Logger: slog.Default(),
  2296. LocateService: locateSvc,
  2297. }
  2298. msg := svc.SetCaps(ctx, tc.me, tc.givenCmd)
  2299. assert.Equal(t, tc.wantMsg, msg)
  2300. })
  2301. }
  2302. }
  2303. func TestOSCARProxy_SetConfig(t *testing.T) {
  2304. cases := []struct {
  2305. // name is the unit test name
  2306. name string
  2307. // me is the TOC user session
  2308. me *state.Session
  2309. // givenCmd is the TOC command
  2310. givenCmd []byte
  2311. // wantMsg is the expected TOC response
  2312. wantMsg string
  2313. // mockParams is the list of params sent to mocks that satisfy this
  2314. // method's dependencies
  2315. mockParams mockParams
  2316. }{
  2317. {
  2318. name: "successfully set permit all config",
  2319. me: newTestSession("me"),
  2320. givenCmd: []byte("toc_set_config {m 1\ng Buddies\nb friend1\nb friend2\n}\n"),
  2321. mockParams: mockParams{
  2322. permitDenyParams: permitDenyParams{
  2323. // confusingly, setting "permit all" mode requires adding a
  2324. // deny list entry
  2325. addDenyListEntriesParams: addDenyListEntriesParams{
  2326. {
  2327. me: state.NewIdentScreenName("me"),
  2328. body: wire.SNAC_0x09_0x07_PermitDenyAddDenyListEntries{
  2329. Users: []struct {
  2330. ScreenName string `oscar:"len_prefix=uint8"`
  2331. }{
  2332. {ScreenName: "me"},
  2333. },
  2334. },
  2335. },
  2336. },
  2337. },
  2338. buddyParams: buddyParams{
  2339. addBuddiesParams: addBuddiesParams{
  2340. {
  2341. me: state.NewIdentScreenName("me"),
  2342. inBody: wire.SNAC_0x03_0x04_BuddyAddBuddies{
  2343. Buddies: []struct {
  2344. ScreenName string `oscar:"len_prefix=uint8"`
  2345. }{
  2346. {ScreenName: "friend1"},
  2347. {ScreenName: "friend2"},
  2348. },
  2349. },
  2350. },
  2351. },
  2352. },
  2353. tocConfigParams: tocConfigParams{
  2354. setTOCConfigParams: setTOCConfigParams{
  2355. {
  2356. user: state.NewIdentScreenName("me"),
  2357. config: "m 1\ng Buddies\nb friend1\nb friend2",
  2358. },
  2359. },
  2360. },
  2361. },
  2362. },
  2363. {
  2364. name: "set permit all config, receive err from config store svc",
  2365. me: newTestSession("me"),
  2366. givenCmd: []byte("toc_set_config {m 1\ng Buddies\nb friend1\n}\n"),
  2367. mockParams: mockParams{
  2368. permitDenyParams: permitDenyParams{
  2369. // confusingly, setting "permit all" mode requires adding a
  2370. // deny list entry
  2371. addDenyListEntriesParams: addDenyListEntriesParams{
  2372. {
  2373. me: state.NewIdentScreenName("me"),
  2374. body: wire.SNAC_0x09_0x07_PermitDenyAddDenyListEntries{
  2375. Users: []struct {
  2376. ScreenName string `oscar:"len_prefix=uint8"`
  2377. }{
  2378. {ScreenName: "me"},
  2379. },
  2380. },
  2381. },
  2382. },
  2383. },
  2384. buddyParams: buddyParams{
  2385. addBuddiesParams: addBuddiesParams{
  2386. {
  2387. me: state.NewIdentScreenName("me"),
  2388. inBody: wire.SNAC_0x03_0x04_BuddyAddBuddies{
  2389. Buddies: []struct {
  2390. ScreenName string `oscar:"len_prefix=uint8"`
  2391. }{
  2392. {ScreenName: "friend1"},
  2393. },
  2394. },
  2395. },
  2396. },
  2397. },
  2398. tocConfigParams: tocConfigParams{
  2399. setTOCConfigParams: setTOCConfigParams{
  2400. {
  2401. user: state.NewIdentScreenName("me"),
  2402. config: "m 1\ng Buddies\nb friend1",
  2403. err: io.EOF,
  2404. },
  2405. },
  2406. },
  2407. },
  2408. wantMsg: cmdInternalSvcErr,
  2409. },
  2410. {
  2411. name: "set permit all config, receive err from buddy svc",
  2412. me: newTestSession("me"),
  2413. givenCmd: []byte("toc_set_config {m 1\ng Buddies\nb friend1\n}\n"),
  2414. mockParams: mockParams{
  2415. permitDenyParams: permitDenyParams{
  2416. // confusingly, setting "permit all" mode requires adding a
  2417. // deny list entry
  2418. addDenyListEntriesParams: addDenyListEntriesParams{
  2419. {
  2420. me: state.NewIdentScreenName("me"),
  2421. body: wire.SNAC_0x09_0x07_PermitDenyAddDenyListEntries{
  2422. Users: []struct {
  2423. ScreenName string `oscar:"len_prefix=uint8"`
  2424. }{
  2425. {ScreenName: "me"},
  2426. },
  2427. },
  2428. },
  2429. },
  2430. },
  2431. buddyParams: buddyParams{
  2432. addBuddiesParams: addBuddiesParams{
  2433. {
  2434. me: state.NewIdentScreenName("me"),
  2435. inBody: wire.SNAC_0x03_0x04_BuddyAddBuddies{
  2436. Buddies: []struct {
  2437. ScreenName string `oscar:"len_prefix=uint8"`
  2438. }{
  2439. {ScreenName: "friend1"},
  2440. },
  2441. },
  2442. err: io.EOF,
  2443. },
  2444. },
  2445. },
  2446. },
  2447. wantMsg: cmdInternalSvcErr,
  2448. },
  2449. {
  2450. name: "set permit all config, receive err from permit-deny svc",
  2451. me: newTestSession("me"),
  2452. givenCmd: []byte("toc_set_config {m 1\ng Buddies\nb friend1\nb friend2\n}\n"),
  2453. mockParams: mockParams{
  2454. permitDenyParams: permitDenyParams{
  2455. // confusingly, setting "permit all" mode requires adding a
  2456. // deny list entry
  2457. addDenyListEntriesParams: addDenyListEntriesParams{
  2458. {
  2459. me: state.NewIdentScreenName("me"),
  2460. body: wire.SNAC_0x09_0x07_PermitDenyAddDenyListEntries{
  2461. Users: []struct {
  2462. ScreenName string `oscar:"len_prefix=uint8"`
  2463. }{
  2464. {ScreenName: "me"},
  2465. },
  2466. },
  2467. err: io.EOF,
  2468. },
  2469. },
  2470. },
  2471. },
  2472. wantMsg: cmdInternalSvcErr,
  2473. },
  2474. {
  2475. name: "successfully set deny all config",
  2476. me: newTestSession("me"),
  2477. givenCmd: []byte("toc_set_config {m 2\ng Buddies\nb friend1\nb friend2\n}\n"),
  2478. mockParams: mockParams{
  2479. permitDenyParams: permitDenyParams{
  2480. // confusingly, setting "deny all" mode requires adding a
  2481. // permit list entry
  2482. addPermListEntriesParams: addPermListEntriesParams{
  2483. {
  2484. me: state.NewIdentScreenName("me"),
  2485. body: wire.SNAC_0x09_0x05_PermitDenyAddPermListEntries{
  2486. Users: []struct {
  2487. ScreenName string `oscar:"len_prefix=uint8"`
  2488. }{
  2489. {ScreenName: "me"},
  2490. },
  2491. },
  2492. },
  2493. },
  2494. },
  2495. buddyParams: buddyParams{
  2496. addBuddiesParams: addBuddiesParams{
  2497. {
  2498. me: state.NewIdentScreenName("me"),
  2499. inBody: wire.SNAC_0x03_0x04_BuddyAddBuddies{
  2500. Buddies: []struct {
  2501. ScreenName string `oscar:"len_prefix=uint8"`
  2502. }{
  2503. {ScreenName: "friend1"},
  2504. {ScreenName: "friend2"},
  2505. },
  2506. },
  2507. },
  2508. },
  2509. },
  2510. tocConfigParams: tocConfigParams{
  2511. setTOCConfigParams: setTOCConfigParams{
  2512. {
  2513. user: state.NewIdentScreenName("me"),
  2514. config: "m 2\ng Buddies\nb friend1\nb friend2",
  2515. },
  2516. },
  2517. },
  2518. },
  2519. },
  2520. {
  2521. name: "set deny all config, receive err from permit-deny svc",
  2522. me: newTestSession("me"),
  2523. givenCmd: []byte("toc_set_config {m 2\ng Buddies\nb friend1\nb friend2\n}\n"),
  2524. mockParams: mockParams{
  2525. permitDenyParams: permitDenyParams{
  2526. // confusingly, setting "deny all" mode requires adding a
  2527. // permit list entry
  2528. addPermListEntriesParams: addPermListEntriesParams{
  2529. {
  2530. me: state.NewIdentScreenName("me"),
  2531. body: wire.SNAC_0x09_0x05_PermitDenyAddPermListEntries{
  2532. Users: []struct {
  2533. ScreenName string `oscar:"len_prefix=uint8"`
  2534. }{
  2535. {ScreenName: "me"},
  2536. },
  2537. },
  2538. err: io.EOF,
  2539. },
  2540. },
  2541. },
  2542. },
  2543. wantMsg: cmdInternalSvcErr,
  2544. },
  2545. {
  2546. name: "successfully set permit some config",
  2547. me: newTestSession("me"),
  2548. givenCmd: []byte("toc_set_config {m 3\np friend3\np friend4\n\ng Buddies\nb friend1\nb friend2\n}\n"),
  2549. mockParams: mockParams{
  2550. permitDenyParams: permitDenyParams{
  2551. addPermListEntriesParams: addPermListEntriesParams{
  2552. {
  2553. me: state.NewIdentScreenName("me"),
  2554. body: wire.SNAC_0x09_0x05_PermitDenyAddPermListEntries{
  2555. Users: []struct {
  2556. ScreenName string `oscar:"len_prefix=uint8"`
  2557. }{
  2558. {ScreenName: "friend3"},
  2559. {ScreenName: "friend4"},
  2560. },
  2561. },
  2562. },
  2563. },
  2564. },
  2565. buddyParams: buddyParams{
  2566. addBuddiesParams: addBuddiesParams{
  2567. {
  2568. me: state.NewIdentScreenName("me"),
  2569. inBody: wire.SNAC_0x03_0x04_BuddyAddBuddies{
  2570. Buddies: []struct {
  2571. ScreenName string `oscar:"len_prefix=uint8"`
  2572. }{
  2573. {ScreenName: "friend1"},
  2574. {ScreenName: "friend2"},
  2575. },
  2576. },
  2577. },
  2578. },
  2579. },
  2580. tocConfigParams: tocConfigParams{
  2581. setTOCConfigParams: setTOCConfigParams{
  2582. {
  2583. user: state.NewIdentScreenName("me"),
  2584. config: "m 3\np friend3\np friend4\n\ng Buddies\nb friend1\nb friend2",
  2585. },
  2586. },
  2587. },
  2588. },
  2589. },
  2590. {
  2591. name: "set permit some config, receive err from permit-deny svc",
  2592. me: newTestSession("me"),
  2593. givenCmd: []byte("toc_set_config {m 3\np friend3\np friend4\n\ng Buddies\nb friend1\nb friend2\n}\n"),
  2594. mockParams: mockParams{
  2595. permitDenyParams: permitDenyParams{
  2596. addPermListEntriesParams: addPermListEntriesParams{
  2597. {
  2598. me: state.NewIdentScreenName("me"),
  2599. body: wire.SNAC_0x09_0x05_PermitDenyAddPermListEntries{
  2600. Users: []struct {
  2601. ScreenName string `oscar:"len_prefix=uint8"`
  2602. }{
  2603. {ScreenName: "friend3"},
  2604. {ScreenName: "friend4"},
  2605. },
  2606. },
  2607. err: io.EOF,
  2608. },
  2609. },
  2610. },
  2611. },
  2612. wantMsg: cmdInternalSvcErr,
  2613. },
  2614. {
  2615. name: "successfully set deny some config",
  2616. me: newTestSession("me"),
  2617. givenCmd: []byte("toc_set_config {m 4\nd friend3\nd friend4\n\ng Buddies\nb friend1\nb friend2\n}\n"),
  2618. mockParams: mockParams{
  2619. permitDenyParams: permitDenyParams{
  2620. addDenyListEntriesParams: addDenyListEntriesParams{
  2621. {
  2622. me: state.NewIdentScreenName("me"),
  2623. body: wire.SNAC_0x09_0x07_PermitDenyAddDenyListEntries{
  2624. Users: []struct {
  2625. ScreenName string `oscar:"len_prefix=uint8"`
  2626. }{
  2627. {ScreenName: "friend3"},
  2628. {ScreenName: "friend4"},
  2629. },
  2630. },
  2631. },
  2632. },
  2633. },
  2634. buddyParams: buddyParams{
  2635. addBuddiesParams: addBuddiesParams{
  2636. {
  2637. me: state.NewIdentScreenName("me"),
  2638. inBody: wire.SNAC_0x03_0x04_BuddyAddBuddies{
  2639. Buddies: []struct {
  2640. ScreenName string `oscar:"len_prefix=uint8"`
  2641. }{
  2642. {ScreenName: "friend1"},
  2643. {ScreenName: "friend2"},
  2644. },
  2645. },
  2646. },
  2647. },
  2648. },
  2649. tocConfigParams: tocConfigParams{
  2650. setTOCConfigParams: setTOCConfigParams{
  2651. {
  2652. user: state.NewIdentScreenName("me"),
  2653. config: "m 4\nd friend3\nd friend4\n\ng Buddies\nb friend1\nb friend2",
  2654. },
  2655. },
  2656. },
  2657. },
  2658. },
  2659. {
  2660. name: "set deny some config, receive err from permit-deny svc",
  2661. me: newTestSession("me"),
  2662. givenCmd: []byte("toc_set_config {m 4\nd friend3\nd friend4\n\ng Buddies\nb friend1\nb friend2\n}\n"),
  2663. mockParams: mockParams{
  2664. permitDenyParams: permitDenyParams{
  2665. addDenyListEntriesParams: addDenyListEntriesParams{
  2666. {
  2667. me: state.NewIdentScreenName("me"),
  2668. body: wire.SNAC_0x09_0x07_PermitDenyAddDenyListEntries{
  2669. Users: []struct {
  2670. ScreenName string `oscar:"len_prefix=uint8"`
  2671. }{
  2672. {ScreenName: "friend3"},
  2673. {ScreenName: "friend4"},
  2674. },
  2675. },
  2676. err: io.EOF,
  2677. },
  2678. },
  2679. },
  2680. },
  2681. wantMsg: cmdInternalSvcErr,
  2682. },
  2683. {
  2684. name: "set unknown PD mode",
  2685. me: newTestSession("me"),
  2686. givenCmd: []byte("toc_set_config {m 5\nd friend3\nd friend4\n\ng Buddies\nb friend1\nb friend2\n}\n"),
  2687. wantMsg: cmdInternalSvcErr,
  2688. },
  2689. {
  2690. name: "bad command",
  2691. givenCmd: []byte(`toc_chat_leave`),
  2692. wantMsg: cmdInternalSvcErr,
  2693. },
  2694. }
  2695. for _, tc := range cases {
  2696. t.Run(tc.name, func(t *testing.T) {
  2697. ctx := context.Background()
  2698. pdSvc := newMockPermitDenyService(t)
  2699. for _, params := range tc.mockParams.addDenyListEntriesParams {
  2700. pdSvc.EXPECT().
  2701. AddDenyListEntries(ctx, matchSession(params.me), params.body).
  2702. Return(params.err)
  2703. }
  2704. for _, params := range tc.mockParams.addPermListEntriesParams {
  2705. pdSvc.EXPECT().
  2706. AddPermListEntries(ctx, matchSession(params.me), params.body).
  2707. Return(params.err)
  2708. }
  2709. buddySvc := newMockBuddyService(t)
  2710. for _, params := range tc.mockParams.addBuddiesParams {
  2711. buddySvc.EXPECT().
  2712. AddBuddies(ctx, matchSession(params.me), params.inBody).
  2713. Return(params.err)
  2714. }
  2715. tocConfigSvc := newMockTOCConfigStore(t)
  2716. for _, params := range tc.mockParams.setTOCConfigParams {
  2717. tocConfigSvc.EXPECT().
  2718. SetTOCConfig(params.user, params.config).
  2719. Return(params.err)
  2720. }
  2721. svc := OSCARProxy{
  2722. BuddyService: buddySvc,
  2723. Logger: slog.Default(),
  2724. PermitDenyService: pdSvc,
  2725. TOCConfigStore: tocConfigSvc,
  2726. }
  2727. msg := svc.SetConfig(ctx, tc.me, tc.givenCmd)
  2728. assert.Equal(t, tc.wantMsg, msg)
  2729. })
  2730. }
  2731. }
  2732. func TestOSCARProxy_SetDir(t *testing.T) {
  2733. cases := []struct {
  2734. // name is the unit test name
  2735. name string
  2736. // me is the TOC user session
  2737. me *state.Session
  2738. // givenCmd is the TOC command
  2739. givenCmd []byte
  2740. // wantMsg is the expected TOC response
  2741. wantMsg string
  2742. // mockParams is the list of params sent to mocks that satisfy this
  2743. // method's dependencies
  2744. mockParams mockParams
  2745. }{
  2746. {
  2747. name: "successfully set directory info with quoted fields",
  2748. me: newTestSession("me"),
  2749. givenCmd: []byte(`toc_set_dir "first name":"middle name":"last name":"maiden name":"city":"state":"country":"email":"allow web searches"`),
  2750. mockParams: mockParams{
  2751. locateParams: locateParams{
  2752. setDirInfoParams: setDirInfoParams{
  2753. {
  2754. me: state.NewIdentScreenName("me"),
  2755. inBody: wire.SNAC_0x02_0x09_LocateSetDirInfo{
  2756. TLVRestBlock: wire.TLVRestBlock{
  2757. TLVList: wire.TLVList{
  2758. wire.NewTLVBE(wire.ODirTLVFirstName, "first name"),
  2759. wire.NewTLVBE(wire.ODirTLVMiddleName, "middle name"),
  2760. wire.NewTLVBE(wire.ODirTLVLastName, "last name"),
  2761. wire.NewTLVBE(wire.ODirTLVMaidenName, "maiden name"),
  2762. wire.NewTLVBE(wire.ODirTLVCountry, "country"),
  2763. wire.NewTLVBE(wire.ODirTLVState, "state"),
  2764. wire.NewTLVBE(wire.ODirTLVCity, "city"),
  2765. },
  2766. },
  2767. },
  2768. },
  2769. },
  2770. },
  2771. },
  2772. },
  2773. {
  2774. name: "successfully set directory info with some blank fields",
  2775. me: newTestSession("me"),
  2776. givenCmd: []byte(`toc_set_dir "first name"::"last name"::"city":"state":"country":"email":"allow web searches"`),
  2777. mockParams: mockParams{
  2778. locateParams: locateParams{
  2779. setDirInfoParams: setDirInfoParams{
  2780. {
  2781. me: state.NewIdentScreenName("me"),
  2782. inBody: wire.SNAC_0x02_0x09_LocateSetDirInfo{
  2783. TLVRestBlock: wire.TLVRestBlock{
  2784. TLVList: wire.TLVList{
  2785. wire.NewTLVBE(wire.ODirTLVFirstName, "first name"),
  2786. wire.NewTLVBE(wire.ODirTLVMiddleName, ""),
  2787. wire.NewTLVBE(wire.ODirTLVLastName, "last name"),
  2788. wire.NewTLVBE(wire.ODirTLVMaidenName, ""),
  2789. wire.NewTLVBE(wire.ODirTLVCountry, "country"),
  2790. wire.NewTLVBE(wire.ODirTLVState, "state"),
  2791. wire.NewTLVBE(wire.ODirTLVCity, "city"),
  2792. },
  2793. },
  2794. },
  2795. },
  2796. },
  2797. },
  2798. },
  2799. },
  2800. {
  2801. name: "successfully set directory info with last two fields absent",
  2802. me: newTestSession("me"),
  2803. givenCmd: []byte(`toc_set_dir "first name"::"last name"::"city":"state":"country"`),
  2804. mockParams: mockParams{
  2805. locateParams: locateParams{
  2806. setDirInfoParams: setDirInfoParams{
  2807. {
  2808. me: state.NewIdentScreenName("me"),
  2809. inBody: wire.SNAC_0x02_0x09_LocateSetDirInfo{
  2810. TLVRestBlock: wire.TLVRestBlock{
  2811. TLVList: wire.TLVList{
  2812. wire.NewTLVBE(wire.ODirTLVFirstName, "first name"),
  2813. wire.NewTLVBE(wire.ODirTLVMiddleName, ""),
  2814. wire.NewTLVBE(wire.ODirTLVLastName, "last name"),
  2815. wire.NewTLVBE(wire.ODirTLVMaidenName, ""),
  2816. wire.NewTLVBE(wire.ODirTLVCountry, "country"),
  2817. wire.NewTLVBE(wire.ODirTLVState, "state"),
  2818. wire.NewTLVBE(wire.ODirTLVCity, "city"),
  2819. },
  2820. },
  2821. },
  2822. },
  2823. },
  2824. },
  2825. },
  2826. },
  2827. {
  2828. name: "set directory info, receive error from locate svc",
  2829. me: newTestSession("me"),
  2830. givenCmd: []byte(`toc_set_dir "first name":"middle name":"last name":"maiden name":"city":"state":"country":"email":"allow web searches"`),
  2831. mockParams: mockParams{
  2832. locateParams: locateParams{
  2833. setDirInfoParams: setDirInfoParams{
  2834. {
  2835. me: state.NewIdentScreenName("me"),
  2836. inBody: wire.SNAC_0x02_0x09_LocateSetDirInfo{
  2837. TLVRestBlock: wire.TLVRestBlock{
  2838. TLVList: wire.TLVList{
  2839. wire.NewTLVBE(wire.ODirTLVFirstName, "first name"),
  2840. wire.NewTLVBE(wire.ODirTLVMiddleName, "middle name"),
  2841. wire.NewTLVBE(wire.ODirTLVLastName, "last name"),
  2842. wire.NewTLVBE(wire.ODirTLVMaidenName, "maiden name"),
  2843. wire.NewTLVBE(wire.ODirTLVCountry, "country"),
  2844. wire.NewTLVBE(wire.ODirTLVState, "state"),
  2845. wire.NewTLVBE(wire.ODirTLVCity, "city"),
  2846. },
  2847. },
  2848. },
  2849. err: io.EOF,
  2850. },
  2851. },
  2852. },
  2853. },
  2854. wantMsg: cmdInternalSvcErr,
  2855. },
  2856. {
  2857. name: "set directory with too many fields present",
  2858. me: newTestSession("me"),
  2859. givenCmd: []byte(`toc_set_dir "first name"::"last name"::"city":"state":"country":"email":"allow web searches":"extra":"extra"`),
  2860. wantMsg: cmdInternalSvcErr,
  2861. },
  2862. {
  2863. name: "bad command",
  2864. givenCmd: []byte(`toc_set_dir`),
  2865. wantMsg: cmdInternalSvcErr,
  2866. },
  2867. }
  2868. for _, tc := range cases {
  2869. t.Run(tc.name, func(t *testing.T) {
  2870. ctx := context.Background()
  2871. locateSvc := newMockLocateService(t)
  2872. for _, params := range tc.mockParams.setDirInfoParams {
  2873. locateSvc.EXPECT().
  2874. SetDirInfo(ctx, matchSession(params.me), wire.SNACFrame{}, params.inBody).
  2875. Return(params.msg, params.err)
  2876. }
  2877. svc := OSCARProxy{
  2878. Logger: slog.Default(),
  2879. LocateService: locateSvc,
  2880. }
  2881. msg := svc.SetDir(ctx, tc.me, tc.givenCmd)
  2882. assert.Equal(t, tc.wantMsg, msg)
  2883. })
  2884. }
  2885. }
  2886. func TestOSCARProxy_SetIdle(t *testing.T) {
  2887. cases := []struct {
  2888. // name is the unit test name
  2889. name string
  2890. // me is the TOC user session
  2891. me *state.Session
  2892. // givenCmd is the TOC command
  2893. givenCmd []byte
  2894. // wantMsg is the expected TOC response
  2895. wantMsg string
  2896. // mockParams is the list of params sent to mocks that satisfy this
  2897. // method's dependencies
  2898. mockParams mockParams
  2899. }{
  2900. {
  2901. name: "successfully set idle status",
  2902. me: newTestSession("me"),
  2903. givenCmd: []byte(`toc_set_idle 10`),
  2904. mockParams: mockParams{
  2905. oServiceBOSParams: oServiceParams{
  2906. idleNotificationParams: idleNotificationParams{
  2907. {
  2908. me: state.NewIdentScreenName("me"),
  2909. bodyIn: wire.SNAC_0x01_0x11_OServiceIdleNotification{
  2910. IdleTime: uint32(10),
  2911. },
  2912. },
  2913. },
  2914. },
  2915. },
  2916. },
  2917. {
  2918. name: "set idle status, receive err from BOS oservice svc",
  2919. me: newTestSession("me"),
  2920. givenCmd: []byte(`toc_set_idle 10`),
  2921. mockParams: mockParams{
  2922. oServiceBOSParams: oServiceParams{
  2923. idleNotificationParams: idleNotificationParams{
  2924. {
  2925. me: state.NewIdentScreenName("me"),
  2926. bodyIn: wire.SNAC_0x01_0x11_OServiceIdleNotification{
  2927. IdleTime: uint32(10),
  2928. },
  2929. err: io.EOF,
  2930. },
  2931. },
  2932. },
  2933. },
  2934. wantMsg: cmdInternalSvcErr,
  2935. },
  2936. {
  2937. name: "bad secs param",
  2938. givenCmd: []byte(`toc_set_idle zero`),
  2939. wantMsg: cmdInternalSvcErr,
  2940. },
  2941. {
  2942. name: "bad command",
  2943. givenCmd: []byte(`toc_set_idle`),
  2944. wantMsg: cmdInternalSvcErr,
  2945. },
  2946. }
  2947. for _, tc := range cases {
  2948. t.Run(tc.name, func(t *testing.T) {
  2949. ctx := context.Background()
  2950. oServiceSvc := newMockOServiceService(t)
  2951. for _, params := range tc.mockParams.oServiceBOSParams.idleNotificationParams {
  2952. oServiceSvc.EXPECT().
  2953. IdleNotification(ctx, matchSession(params.me), params.bodyIn).
  2954. Return(params.err)
  2955. }
  2956. svc := OSCARProxy{
  2957. Logger: slog.Default(),
  2958. OServiceServiceBOS: oServiceSvc,
  2959. }
  2960. msg := svc.SetIdle(ctx, tc.me, tc.givenCmd)
  2961. assert.Equal(t, tc.wantMsg, msg)
  2962. })
  2963. }
  2964. }
  2965. func TestOSCARProxy_SetInfo(t *testing.T) {
  2966. cases := []struct {
  2967. // name is the unit test name
  2968. name string
  2969. // me is the TOC user session
  2970. me *state.Session
  2971. // givenCmd is the TOC command
  2972. givenCmd []byte
  2973. // wantMsg is the expected TOC response
  2974. wantMsg string
  2975. // mockParams is the list of params sent to mocks that satisfy this
  2976. // method's dependencies
  2977. mockParams mockParams
  2978. }{
  2979. {
  2980. name: "successfully set profile",
  2981. me: newTestSession("me"),
  2982. givenCmd: []byte(`toc_set_info "my profile!"`),
  2983. mockParams: mockParams{
  2984. locateParams: locateParams{
  2985. setInfoParams: setInfoParams{
  2986. {
  2987. me: state.NewIdentScreenName("me"),
  2988. inBody: wire.SNAC_0x02_0x04_LocateSetInfo{
  2989. TLVRestBlock: wire.TLVRestBlock{
  2990. TLVList: wire.TLVList{
  2991. wire.NewTLVBE(wire.LocateTLVTagsInfoSigData, "my profile!"),
  2992. },
  2993. },
  2994. },
  2995. },
  2996. },
  2997. },
  2998. },
  2999. },
  3000. {
  3001. name: "set profile, receive error from locate svc",
  3002. me: newTestSession("me"),
  3003. givenCmd: []byte(`toc_set_info "my profile!"`),
  3004. mockParams: mockParams{
  3005. locateParams: locateParams{
  3006. setInfoParams: setInfoParams{
  3007. {
  3008. me: state.NewIdentScreenName("me"),
  3009. inBody: wire.SNAC_0x02_0x04_LocateSetInfo{
  3010. TLVRestBlock: wire.TLVRestBlock{
  3011. TLVList: wire.TLVList{
  3012. wire.NewTLVBE(wire.LocateTLVTagsInfoSigData, "my profile!"),
  3013. },
  3014. },
  3015. },
  3016. err: io.EOF,
  3017. },
  3018. },
  3019. },
  3020. },
  3021. wantMsg: cmdInternalSvcErr,
  3022. },
  3023. {
  3024. name: "bad command",
  3025. givenCmd: []byte(`toc_set_info`),
  3026. wantMsg: cmdInternalSvcErr,
  3027. },
  3028. }
  3029. for _, tc := range cases {
  3030. t.Run(tc.name, func(t *testing.T) {
  3031. ctx := context.Background()
  3032. locateSvc := newMockLocateService(t)
  3033. for _, params := range tc.mockParams.setInfoParams {
  3034. locateSvc.EXPECT().
  3035. SetInfo(ctx, matchSession(params.me), params.inBody).
  3036. Return(params.err)
  3037. }
  3038. svc := OSCARProxy{
  3039. Logger: slog.Default(),
  3040. LocateService: locateSvc,
  3041. }
  3042. msg := svc.SetInfo(ctx, tc.me, tc.givenCmd)
  3043. assert.Equal(t, tc.wantMsg, msg)
  3044. })
  3045. }
  3046. }
  3047. func TestOSCARProxy_Signon(t *testing.T) {
  3048. roastedPass := wire.RoastTOCPassword([]byte("thepass"))
  3049. cases := []struct {
  3050. // name is the unit test name
  3051. name string
  3052. // me is the TOC user session
  3053. me *state.Session
  3054. // givenCmd is the TOC command
  3055. givenCmd []byte
  3056. // wantMsg is the expected TOC response
  3057. wantMsg []string
  3058. // mockParams is the list of params sent to mocks that satisfy this
  3059. // method's dependencies
  3060. mockParams mockParams
  3061. }{
  3062. {
  3063. name: "successfully login",
  3064. me: newTestSession("me", func(session *state.Session) {
  3065. session.SetCaps([][16]byte{capChat})
  3066. }),
  3067. givenCmd: []byte(`toc_signon "" "" me "xx` + hex.EncodeToString(roastedPass) + `"`),
  3068. mockParams: mockParams{
  3069. authParams: authParams{
  3070. flapLoginParams: flapLoginParams{
  3071. {
  3072. frame: wire.FLAPSignonFrame{
  3073. TLVRestBlock: wire.TLVRestBlock{
  3074. TLVList: wire.TLVList{
  3075. wire.NewTLVBE(wire.LoginTLVTagsScreenName, "me"),
  3076. wire.NewTLVBE(wire.LoginTLVTagsRoastedTOCPassword, roastedPass),
  3077. },
  3078. },
  3079. },
  3080. newUserFn: state.NewStubUser,
  3081. tlv: wire.TLVRestBlock{
  3082. TLVList: wire.TLVList{
  3083. wire.NewTLVBE(wire.OServiceTLVTagsLoginCookie, []byte("thecookie")),
  3084. },
  3085. },
  3086. },
  3087. },
  3088. registerBOSSessionParams: registerBOSSessionParams{
  3089. {
  3090. authCookie: []byte("thecookie"),
  3091. sess: newTestSession("me"),
  3092. },
  3093. },
  3094. },
  3095. buddyListRegistryParams: buddyListRegistryParams{
  3096. registerBuddyListParams: registerBuddyListParams{
  3097. {
  3098. user: state.NewIdentScreenName("me"),
  3099. },
  3100. },
  3101. },
  3102. tocConfigParams: tocConfigParams{
  3103. userParams: userParams{
  3104. {
  3105. screenName: state.NewIdentScreenName("me"),
  3106. returnedUser: &state.User{
  3107. TOCConfig: "my-toc-config",
  3108. },
  3109. },
  3110. },
  3111. },
  3112. },
  3113. wantMsg: []string{"SIGN_ON:TOC1.0", "CONFIG:my-toc-config"},
  3114. },
  3115. {
  3116. name: "login, receive error from auth svc FLAP login",
  3117. givenCmd: []byte(`toc_signon "" "" me "xx` + hex.EncodeToString(roastedPass) + `"`),
  3118. mockParams: mockParams{
  3119. authParams: authParams{
  3120. flapLoginParams: flapLoginParams{
  3121. {
  3122. frame: wire.FLAPSignonFrame{
  3123. TLVRestBlock: wire.TLVRestBlock{
  3124. TLVList: wire.TLVList{
  3125. wire.NewTLVBE(wire.LoginTLVTagsScreenName, "me"),
  3126. wire.NewTLVBE(wire.LoginTLVTagsRoastedTOCPassword, roastedPass),
  3127. },
  3128. },
  3129. },
  3130. newUserFn: state.NewStubUser,
  3131. err: io.EOF,
  3132. },
  3133. },
  3134. },
  3135. },
  3136. wantMsg: []string{string(cmdInternalSvcErr)},
  3137. },
  3138. {
  3139. name: "login, receive error from auth svc registration",
  3140. givenCmd: []byte(`toc_signon "" "" me "xx` + hex.EncodeToString(roastedPass) + `"`),
  3141. mockParams: mockParams{
  3142. authParams: authParams{
  3143. flapLoginParams: flapLoginParams{
  3144. {
  3145. frame: wire.FLAPSignonFrame{
  3146. TLVRestBlock: wire.TLVRestBlock{
  3147. TLVList: wire.TLVList{
  3148. wire.NewTLVBE(wire.LoginTLVTagsScreenName, "me"),
  3149. wire.NewTLVBE(wire.LoginTLVTagsRoastedTOCPassword, roastedPass),
  3150. },
  3151. },
  3152. },
  3153. newUserFn: state.NewStubUser,
  3154. tlv: wire.TLVRestBlock{
  3155. TLVList: wire.TLVList{
  3156. wire.NewTLVBE(wire.OServiceTLVTagsLoginCookie, []byte("thecookie")),
  3157. },
  3158. },
  3159. },
  3160. },
  3161. registerBOSSessionParams: registerBOSSessionParams{
  3162. {
  3163. authCookie: []byte("thecookie"),
  3164. err: io.EOF,
  3165. },
  3166. },
  3167. },
  3168. },
  3169. wantMsg: []string{string(cmdInternalSvcErr)},
  3170. },
  3171. {
  3172. name: "login, receive error from buddy list registry",
  3173. givenCmd: []byte(`toc_signon "" "" me "xx` + hex.EncodeToString(roastedPass) + `"`),
  3174. mockParams: mockParams{
  3175. authParams: authParams{
  3176. flapLoginParams: flapLoginParams{
  3177. {
  3178. frame: wire.FLAPSignonFrame{
  3179. TLVRestBlock: wire.TLVRestBlock{
  3180. TLVList: wire.TLVList{
  3181. wire.NewTLVBE(wire.LoginTLVTagsScreenName, "me"),
  3182. wire.NewTLVBE(wire.LoginTLVTagsRoastedTOCPassword, roastedPass),
  3183. },
  3184. },
  3185. },
  3186. newUserFn: state.NewStubUser,
  3187. tlv: wire.TLVRestBlock{
  3188. TLVList: wire.TLVList{
  3189. wire.NewTLVBE(wire.OServiceTLVTagsLoginCookie, []byte("thecookie")),
  3190. },
  3191. },
  3192. },
  3193. },
  3194. registerBOSSessionParams: registerBOSSessionParams{
  3195. {
  3196. authCookie: []byte("thecookie"),
  3197. sess: newTestSession("me"),
  3198. },
  3199. },
  3200. },
  3201. buddyListRegistryParams: buddyListRegistryParams{
  3202. registerBuddyListParams: registerBuddyListParams{
  3203. {
  3204. user: state.NewIdentScreenName("me"),
  3205. err: io.EOF,
  3206. },
  3207. },
  3208. },
  3209. },
  3210. wantMsg: []string{string(cmdInternalSvcErr)},
  3211. },
  3212. {
  3213. name: "login, receive error from TOC config store",
  3214. givenCmd: []byte(`toc_signon "" "" me "xx` + hex.EncodeToString(roastedPass) + `"`),
  3215. mockParams: mockParams{
  3216. authParams: authParams{
  3217. flapLoginParams: flapLoginParams{
  3218. {
  3219. frame: wire.FLAPSignonFrame{
  3220. TLVRestBlock: wire.TLVRestBlock{
  3221. TLVList: wire.TLVList{
  3222. wire.NewTLVBE(wire.LoginTLVTagsScreenName, "me"),
  3223. wire.NewTLVBE(wire.LoginTLVTagsRoastedTOCPassword, roastedPass),
  3224. },
  3225. },
  3226. },
  3227. newUserFn: state.NewStubUser,
  3228. tlv: wire.TLVRestBlock{
  3229. TLVList: wire.TLVList{
  3230. wire.NewTLVBE(wire.OServiceTLVTagsLoginCookie, []byte("thecookie")),
  3231. },
  3232. },
  3233. },
  3234. },
  3235. registerBOSSessionParams: registerBOSSessionParams{
  3236. {
  3237. authCookie: []byte("thecookie"),
  3238. sess: newTestSession("me"),
  3239. },
  3240. },
  3241. },
  3242. buddyListRegistryParams: buddyListRegistryParams{
  3243. registerBuddyListParams: registerBuddyListParams{
  3244. {
  3245. user: state.NewIdentScreenName("me"),
  3246. },
  3247. },
  3248. },
  3249. tocConfigParams: tocConfigParams{
  3250. userParams: userParams{
  3251. {
  3252. screenName: state.NewIdentScreenName("me"),
  3253. err: io.EOF,
  3254. },
  3255. },
  3256. },
  3257. },
  3258. wantMsg: []string{string(cmdInternalSvcErr)},
  3259. },
  3260. {
  3261. name: "login, user not found after login",
  3262. givenCmd: []byte(`toc_signon "" "" me "xx` + hex.EncodeToString(roastedPass) + `"`),
  3263. mockParams: mockParams{
  3264. authParams: authParams{
  3265. flapLoginParams: flapLoginParams{
  3266. {
  3267. frame: wire.FLAPSignonFrame{
  3268. TLVRestBlock: wire.TLVRestBlock{
  3269. TLVList: wire.TLVList{
  3270. wire.NewTLVBE(wire.LoginTLVTagsScreenName, "me"),
  3271. wire.NewTLVBE(wire.LoginTLVTagsRoastedTOCPassword, roastedPass),
  3272. },
  3273. },
  3274. },
  3275. newUserFn: state.NewStubUser,
  3276. tlv: wire.TLVRestBlock{
  3277. TLVList: wire.TLVList{
  3278. wire.NewTLVBE(wire.OServiceTLVTagsLoginCookie, []byte("thecookie")),
  3279. },
  3280. },
  3281. },
  3282. },
  3283. registerBOSSessionParams: registerBOSSessionParams{
  3284. {
  3285. authCookie: []byte("thecookie"),
  3286. sess: newTestSession("me"),
  3287. },
  3288. },
  3289. },
  3290. buddyListRegistryParams: buddyListRegistryParams{
  3291. registerBuddyListParams: registerBuddyListParams{
  3292. {
  3293. user: state.NewIdentScreenName("me"),
  3294. },
  3295. },
  3296. },
  3297. tocConfigParams: tocConfigParams{
  3298. userParams: userParams{
  3299. {
  3300. screenName: state.NewIdentScreenName("me"),
  3301. returnedUser: nil,
  3302. },
  3303. },
  3304. },
  3305. },
  3306. wantMsg: []string{string(cmdInternalSvcErr)},
  3307. },
  3308. {
  3309. name: "login with bad credentials",
  3310. givenCmd: []byte(`toc_signon "" "" me "xx` + hex.EncodeToString(roastedPass) + `"`),
  3311. mockParams: mockParams{
  3312. authParams: authParams{
  3313. flapLoginParams: flapLoginParams{
  3314. {
  3315. frame: wire.FLAPSignonFrame{
  3316. TLVRestBlock: wire.TLVRestBlock{
  3317. TLVList: wire.TLVList{
  3318. wire.NewTLVBE(wire.LoginTLVTagsScreenName, "me"),
  3319. wire.NewTLVBE(wire.LoginTLVTagsRoastedTOCPassword, roastedPass),
  3320. },
  3321. },
  3322. },
  3323. newUserFn: state.NewStubUser,
  3324. tlv: wire.TLVRestBlock{
  3325. TLVList: wire.TLVList{
  3326. wire.NewTLVBE(wire.LoginTLVTagsErrorSubcode, wire.LoginErrInvalidUsernameOrPassword),
  3327. },
  3328. },
  3329. },
  3330. },
  3331. },
  3332. },
  3333. wantMsg: []string{"ERROR:980"},
  3334. },
  3335. {
  3336. name: "bad command",
  3337. givenCmd: []byte(`toc_init_done_diff`),
  3338. wantMsg: []string{string(cmdInternalSvcErr)},
  3339. },
  3340. }
  3341. for _, tc := range cases {
  3342. t.Run(tc.name, func(t *testing.T) {
  3343. ctx := context.Background()
  3344. authSvc := newMockAuthService(t)
  3345. for _, params := range tc.mockParams.flapLoginParams {
  3346. authSvc.EXPECT().
  3347. FLAPLogin(params.frame, mock.Anything).
  3348. Return(params.tlv, params.err)
  3349. }
  3350. for _, params := range tc.mockParams.registerBOSSessionParams {
  3351. authSvc.EXPECT().
  3352. RegisterBOSSession(ctx, params.authCookie).
  3353. Return(params.sess, params.err)
  3354. }
  3355. buddyRegistry := newMockBuddyListRegistry(t)
  3356. for _, params := range tc.mockParams.registerBuddyListParams {
  3357. buddyRegistry.EXPECT().
  3358. RegisterBuddyList(params.user).
  3359. Return(params.err)
  3360. }
  3361. tocCfg := newMockTOCConfigStore(t)
  3362. for _, params := range tc.mockParams.userParams {
  3363. tocCfg.EXPECT().
  3364. User(params.screenName).
  3365. Return(params.returnedUser, params.err)
  3366. }
  3367. svc := OSCARProxy{
  3368. AuthService: authSvc,
  3369. BuddyListRegistry: buddyRegistry,
  3370. Logger: slog.Default(),
  3371. TOCConfigStore: tocCfg,
  3372. }
  3373. sess, msg := svc.Signon(ctx, tc.givenCmd)
  3374. assert.Equal(t, tc.wantMsg, msg)
  3375. if tc.me == nil {
  3376. assert.Nil(t, sess)
  3377. } else if assert.NotNil(t, sess) {
  3378. assert.Equal(t, tc.me.IdentScreenName(), sess.IdentScreenName())
  3379. assert.Equal(t, tc.me.Caps(), sess.Caps())
  3380. }
  3381. })
  3382. }
  3383. }
  3384. func TestOSCARProxy_Signout(t *testing.T) {
  3385. cases := []struct {
  3386. // name is the unit test name
  3387. name string
  3388. // me is the TOC user session
  3389. me *state.Session
  3390. // mockParams is the list of params sent to mocks that satisfy this
  3391. // method's dependencies
  3392. mockParams mockParams
  3393. }{
  3394. {
  3395. name: "successfully sign out",
  3396. me: newTestSession("me"),
  3397. mockParams: mockParams{
  3398. buddyParams: buddyParams{
  3399. broadcastBuddyDepartedParams: broadcastBuddyDepartedParams{
  3400. {
  3401. me: state.NewIdentScreenName("me"),
  3402. },
  3403. },
  3404. },
  3405. buddyListRegistryParams: buddyListRegistryParams{
  3406. unregisterBuddyListParams: unregisterBuddyListParams{
  3407. {
  3408. user: state.NewIdentScreenName("me"),
  3409. },
  3410. },
  3411. },
  3412. authParams: authParams{
  3413. signoutParams: signoutParams{
  3414. {
  3415. me: state.NewIdentScreenName("me"),
  3416. },
  3417. },
  3418. },
  3419. },
  3420. },
  3421. {
  3422. name: "sign out, receive error from buddy service",
  3423. me: newTestSession("me"),
  3424. mockParams: mockParams{
  3425. buddyParams: buddyParams{
  3426. broadcastBuddyDepartedParams: broadcastBuddyDepartedParams{
  3427. {
  3428. me: state.NewIdentScreenName("me"),
  3429. err: io.EOF,
  3430. },
  3431. },
  3432. },
  3433. buddyListRegistryParams: buddyListRegistryParams{
  3434. unregisterBuddyListParams: unregisterBuddyListParams{
  3435. {
  3436. user: state.NewIdentScreenName("me"),
  3437. },
  3438. },
  3439. },
  3440. authParams: authParams{
  3441. signoutParams: signoutParams{
  3442. {
  3443. me: state.NewIdentScreenName("me"),
  3444. },
  3445. },
  3446. },
  3447. },
  3448. },
  3449. {
  3450. name: "sign out, receive error from buddy list registry",
  3451. me: newTestSession("me"),
  3452. mockParams: mockParams{
  3453. buddyParams: buddyParams{
  3454. broadcastBuddyDepartedParams: broadcastBuddyDepartedParams{
  3455. {
  3456. me: state.NewIdentScreenName("me"),
  3457. },
  3458. },
  3459. },
  3460. buddyListRegistryParams: buddyListRegistryParams{
  3461. unregisterBuddyListParams: unregisterBuddyListParams{
  3462. {
  3463. user: state.NewIdentScreenName("me"),
  3464. err: io.EOF,
  3465. },
  3466. },
  3467. },
  3468. authParams: authParams{
  3469. signoutParams: signoutParams{
  3470. {
  3471. me: state.NewIdentScreenName("me"),
  3472. },
  3473. },
  3474. },
  3475. },
  3476. },
  3477. }
  3478. for _, tc := range cases {
  3479. t.Run(tc.name, func(t *testing.T) {
  3480. ctx := context.Background()
  3481. buddySvc := newMockBuddyService(t)
  3482. for _, params := range tc.mockParams.broadcastBuddyDepartedParams {
  3483. buddySvc.EXPECT().
  3484. BroadcastBuddyDeparted(ctx, matchSession(params.me)).
  3485. Return(params.err)
  3486. }
  3487. buddyListSvc := newMockBuddyListRegistry(t)
  3488. for _, params := range tc.mockParams.unregisterBuddyListParams {
  3489. buddyListSvc.EXPECT().
  3490. UnregisterBuddyList(params.user).
  3491. Return(params.err)
  3492. }
  3493. authSvc := newMockAuthService(t)
  3494. for _, params := range tc.mockParams.signoutParams {
  3495. authSvc.EXPECT().Signout(ctx, matchSession(params.me))
  3496. }
  3497. svc := OSCARProxy{
  3498. AuthService: authSvc,
  3499. BuddyListRegistry: buddyListSvc,
  3500. BuddyService: buddySvc,
  3501. Logger: slog.Default(),
  3502. }
  3503. svc.Signout(ctx, tc.me)
  3504. })
  3505. }
  3506. }
  3507. func Test_parseArgs(t *testing.T) {
  3508. type testCase struct {
  3509. name string
  3510. givenPayload string
  3511. givenCmd string
  3512. givenArgs []*string
  3513. wantVarArgs []string
  3514. wantArgs []string
  3515. wantErrMsg string
  3516. }
  3517. tests := []testCase{
  3518. {
  3519. name: "no positional args or varargs",
  3520. givenPayload: `toc_chat_invite`,
  3521. givenCmd: "toc_chat_invite",
  3522. givenArgs: nil,
  3523. wantVarArgs: []string{},
  3524. },
  3525. {
  3526. name: "positional args with varargs",
  3527. givenPayload: `toc_chat_invite 1234 "Join me!" user1 user2 user3`,
  3528. givenCmd: "toc_chat_invite",
  3529. givenArgs: []*string{new(string), new(string)},
  3530. wantVarArgs: []string{"user1", "user2", "user3"},
  3531. wantArgs: []string{"1234", "Join me!"},
  3532. },
  3533. {
  3534. name: "nil positional argument placeholders should get skipped",
  3535. givenPayload: `toc_chat_invite 1234 "Join me!" user1 user2 user3`,
  3536. givenCmd: "toc_chat_invite",
  3537. givenArgs: []*string{nil, nil}, // still 2 placeholders, both nil
  3538. wantVarArgs: []string{"user1", "user2", "user3"},
  3539. wantArgs: []string{"", ""},
  3540. },
  3541. {
  3542. name: "positional args with no varargs",
  3543. givenPayload: `toc_chat_invite 1234 "Join me!"`,
  3544. givenCmd: "toc_chat_invite",
  3545. givenArgs: []*string{new(string), new(string)}, // roomID + msg
  3546. wantVarArgs: []string{},
  3547. wantArgs: []string{"1234", "Join me!"},
  3548. },
  3549. {
  3550. name: "varargs only",
  3551. givenPayload: `toc_chat_invite user1 user2 user3`,
  3552. givenCmd: "toc_chat_invite",
  3553. givenArgs: nil,
  3554. wantVarArgs: []string{"user1", "user2", "user3"},
  3555. },
  3556. {
  3557. name: "command mismatch",
  3558. givenPayload: `toc_chat_invite user1 user2 user3`,
  3559. givenCmd: "toc_chat_accept",
  3560. givenArgs: nil,
  3561. wantVarArgs: []string{},
  3562. wantErrMsg: "mismatch",
  3563. },
  3564. {
  3565. name: "too many positional arg placeholders",
  3566. givenPayload: `toc_chat_invite`,
  3567. givenCmd: "toc_chat_invite",
  3568. givenArgs: []*string{new(string), new(string)},
  3569. wantVarArgs: []string{},
  3570. wantErrMsg: "command contains fewer arguments than expected",
  3571. },
  3572. {
  3573. name: "CSV parser error",
  3574. givenPayload: ``,
  3575. givenCmd: "toc_chat_invite",
  3576. givenArgs: []*string{nil},
  3577. wantVarArgs: []string{},
  3578. wantErrMsg: "CSV reader error",
  3579. },
  3580. }
  3581. for _, tt := range tests {
  3582. t.Run(tt.name, func(t *testing.T) {
  3583. varArgs, err := parseArgs([]byte(tt.givenPayload), tt.givenCmd, tt.givenArgs...)
  3584. if tt.wantErrMsg != "" {
  3585. assert.ErrorContains(t, err, tt.wantErrMsg)
  3586. return
  3587. }
  3588. assert.NoError(t, err)
  3589. // verify the placeholder pointers got populated
  3590. for i, want := range tt.wantArgs {
  3591. if want == "" {
  3592. assert.Nil(t, tt.givenArgs[i])
  3593. } else {
  3594. got := *tt.givenArgs[i]
  3595. assert.Equal(t, want, got)
  3596. }
  3597. }
  3598. // verify we have the same varargs
  3599. assert.Equal(t, tt.wantVarArgs, varArgs)
  3600. assert.Equal(t, len(tt.wantArgs), len(tt.givenArgs))
  3601. })
  3602. }
  3603. }