user_store_test.go 129 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407
  1. package state
  2. import (
  3. "context"
  4. "fmt"
  5. "math"
  6. "net/mail"
  7. "os"
  8. "reflect"
  9. "testing"
  10. "time"
  11. "github.com/google/uuid"
  12. "github.com/mk6i/open-oscar-server/wire"
  13. "github.com/stretchr/testify/assert"
  14. "github.com/stretchr/testify/require"
  15. )
  16. const testFile string = "aim_test.db"
  17. func TestSQLiteUserStore_FeedbagUpsert(t *testing.T) {
  18. t.Run("buddy screen name is converted to ident screen name", func(t *testing.T) {
  19. defer func() {
  20. assert.NoError(t, os.Remove(testFile))
  21. }()
  22. f, err := NewSQLiteUserStore(testFile)
  23. assert.NoError(t, err)
  24. given := []wire.FeedbagItem{
  25. {
  26. GroupID: 0,
  27. ItemID: 1805,
  28. ClassID: wire.FeedbagClassIdBuddy,
  29. Name: "my Friend Bill",
  30. TLVLBlock: wire.TLVLBlock{},
  31. },
  32. {
  33. GroupID: 0x0A,
  34. ItemID: 0,
  35. ClassID: wire.FeedbagClassIdGroup,
  36. Name: "Friends",
  37. },
  38. }
  39. expect := []wire.FeedbagItem{
  40. {
  41. GroupID: 0,
  42. ItemID: 1805,
  43. ClassID: wire.FeedbagClassIdBuddy,
  44. Name: "myfriendbill",
  45. TLVLBlock: wire.TLVLBlock{},
  46. },
  47. {
  48. GroupID: 0x0A,
  49. ItemID: 0,
  50. ClassID: wire.FeedbagClassIdGroup,
  51. Name: "Friends",
  52. },
  53. }
  54. me := NewIdentScreenName("me")
  55. insertTestUsers(t, f, me)
  56. if err := f.FeedbagUpsert(context.Background(), me, given); err != nil {
  57. t.Fatalf("failed to upsert: %s", err.Error())
  58. }
  59. have, err := f.Feedbag(context.Background(), me)
  60. assert.NoError(t, err)
  61. assert.ElementsMatch(t, expect, have)
  62. })
  63. t.Run("upsert PD info with mode", func(t *testing.T) {
  64. defer func() {
  65. assert.NoError(t, os.Remove(testFile))
  66. }()
  67. f, err := NewSQLiteUserStore(testFile)
  68. assert.NoError(t, err)
  69. given := []wire.FeedbagItem{
  70. {
  71. GroupID: 0x0A,
  72. ItemID: 0,
  73. ClassID: wire.FeedbagClassIdPdinfo,
  74. TLVLBlock: wire.TLVLBlock{
  75. TLVList: wire.TLVList{
  76. wire.NewTLVBE(wire.FeedbagAttributesPdMode, wire.FeedbagPDModePermitSome),
  77. },
  78. },
  79. },
  80. }
  81. me := NewIdentScreenName("me")
  82. insertTestUsers(t, f, me)
  83. err = f.FeedbagUpsert(context.Background(), me, given)
  84. assert.NoError(t, err)
  85. var pdMode uint8
  86. err = f.db.QueryRow(`SELECT pdMode from feedbag WHERE screenName = ?`, me.String()).Scan(&pdMode)
  87. assert.NoError(t, err)
  88. assert.Equal(t, wire.FeedbagPDMode(pdMode), wire.FeedbagPDModePermitSome)
  89. })
  90. t.Run("upsert PD info without mode (QIP behavior)", func(t *testing.T) {
  91. defer func() {
  92. assert.NoError(t, os.Remove(testFile))
  93. }()
  94. f, err := NewSQLiteUserStore(testFile)
  95. assert.NoError(t, err)
  96. given := []wire.FeedbagItem{
  97. {
  98. GroupID: 0x0A,
  99. ItemID: 0,
  100. ClassID: wire.FeedbagClassIdPdinfo,
  101. TLVLBlock: wire.TLVLBlock{},
  102. },
  103. }
  104. me := NewIdentScreenName("me")
  105. insertTestUsers(t, f, me)
  106. err = f.FeedbagUpsert(context.Background(), me, given)
  107. assert.NoError(t, err)
  108. var pdMode uint8
  109. err = f.db.QueryRow(`SELECT pdMode from feedbag WHERE screenName = ?`, me.String()).Scan(&pdMode)
  110. assert.NoError(t, err)
  111. assert.Equal(t, wire.FeedbagPDMode(pdMode), wire.FeedbagPDModePermitAll)
  112. })
  113. t.Run("authPending true for buddy with FeedbagAttributesPending TLV", func(t *testing.T) {
  114. defer func() {
  115. assert.NoError(t, os.Remove(testFile))
  116. }()
  117. f, err := NewSQLiteUserStore(testFile)
  118. require.NoError(t, err)
  119. me := NewIdentScreenName("me")
  120. insertTestUsers(t, f, me)
  121. err = f.FeedbagUpsert(context.Background(), me, []wire.FeedbagItem{
  122. {
  123. GroupID: 0,
  124. ItemID: 1,
  125. ClassID: wire.FeedbagClassIdBuddy,
  126. Name: "buddy1",
  127. TLVLBlock: wire.TLVLBlock{
  128. TLVList: wire.TLVList{
  129. wire.NewTLVBE(wire.FeedbagAttributesPending, uint16(0)),
  130. },
  131. },
  132. },
  133. })
  134. require.NoError(t, err)
  135. var authPending bool
  136. err = f.db.QueryRow(
  137. `SELECT authPending FROM feedbag WHERE screenName = ? AND itemID = 1`,
  138. me.String(),
  139. ).Scan(&authPending)
  140. require.NoError(t, err)
  141. assert.True(t, authPending)
  142. })
  143. t.Run("authPending false for buddy without pending TLV", func(t *testing.T) {
  144. defer func() {
  145. assert.NoError(t, os.Remove(testFile))
  146. }()
  147. f, err := NewSQLiteUserStore(testFile)
  148. require.NoError(t, err)
  149. me := NewIdentScreenName("me")
  150. insertTestUsers(t, f, me)
  151. err = f.FeedbagUpsert(context.Background(), me, []wire.FeedbagItem{
  152. {
  153. GroupID: 0,
  154. ItemID: 1,
  155. ClassID: wire.FeedbagClassIdBuddy,
  156. Name: "buddy1",
  157. TLVLBlock: wire.TLVLBlock{},
  158. },
  159. })
  160. require.NoError(t, err)
  161. var authPending bool
  162. err = f.db.QueryRow(
  163. `SELECT authPending FROM feedbag WHERE screenName = ? AND itemID = 1`,
  164. me.String(),
  165. ).Scan(&authPending)
  166. require.NoError(t, err)
  167. assert.False(t, authPending)
  168. })
  169. }
  170. func TestFeedbagDelete(t *testing.T) {
  171. t.Run("happy path", func(t *testing.T) {
  172. screenName := NewIdentScreenName("sn2day")
  173. defer func() {
  174. assert.NoError(t, os.Remove(testFile))
  175. }()
  176. f, err := NewSQLiteUserStore(testFile)
  177. assert.NoError(t, err)
  178. itemsIn := []wire.FeedbagItem{
  179. {
  180. GroupID: 0,
  181. ItemID: 1805,
  182. ClassID: 3,
  183. Name: "spimmer1234",
  184. TLVLBlock: wire.TLVLBlock{
  185. TLVList: wire.TLVList{
  186. wire.NewTLVBE(0x01, uint16(1000)),
  187. },
  188. },
  189. },
  190. {
  191. GroupID: 0x0A,
  192. ClassID: 1,
  193. Name: "Friends",
  194. },
  195. {
  196. GroupID: 0x0B,
  197. ClassID: 1,
  198. Name: "co-workers",
  199. },
  200. }
  201. insertTestUsers(t, f, screenName)
  202. if err := f.FeedbagUpsert(context.Background(), screenName, itemsIn); err != nil {
  203. t.Fatalf("failed to upsert: %s", err.Error())
  204. }
  205. if err := f.FeedbagDelete(context.Background(), screenName, []wire.FeedbagItem{itemsIn[0]}); err != nil {
  206. t.Fatalf("failed to delete: %s", err.Error())
  207. }
  208. itemsOut, err := f.Feedbag(context.Background(), screenName)
  209. if err != nil {
  210. t.Fatalf("failed to retrieve: %s", err.Error())
  211. }
  212. expect := itemsIn[1:]
  213. if !reflect.DeepEqual(expect, itemsOut) {
  214. t.Fatalf("items did not match:\n in: %v\n out: %v", expect, itemsOut)
  215. }
  216. })
  217. t.Run("delete group", func(t *testing.T) {
  218. screenName := NewIdentScreenName("sn2day")
  219. defer func() {
  220. assert.NoError(t, os.Remove(testFile))
  221. }()
  222. f, err := NewSQLiteUserStore(testFile)
  223. assert.NoError(t, err)
  224. itemsIn := []wire.FeedbagItem{
  225. {
  226. GroupID: 0x0A,
  227. ClassID: 1,
  228. Name: "Friends",
  229. },
  230. {
  231. GroupID: 0x0B,
  232. ClassID: 1,
  233. Name: "co-workers",
  234. },
  235. }
  236. insertTestUsers(t, f, screenName)
  237. if err := f.FeedbagUpsert(context.Background(), screenName, itemsIn); err != nil {
  238. t.Fatalf("failed to upsert: %s", err.Error())
  239. }
  240. toDelete := []wire.FeedbagItem{
  241. {
  242. GroupID: 0x0A,
  243. ClassID: 1,
  244. Name: "Friends",
  245. },
  246. }
  247. if err := f.FeedbagDelete(context.Background(), screenName, toDelete); err != nil {
  248. t.Fatalf("failed to delete: %s", err.Error())
  249. }
  250. itemsOut, err := f.Feedbag(context.Background(), screenName)
  251. if err != nil {
  252. t.Fatalf("failed to retrieve: %s", err.Error())
  253. }
  254. expect := []wire.FeedbagItem{
  255. {
  256. GroupID: 0x0B,
  257. ClassID: 1,
  258. Name: "co-workers",
  259. },
  260. }
  261. if !reflect.DeepEqual(expect, itemsOut) {
  262. t.Fatalf("items did not match:\n in: %v\n out: %v", expect, itemsOut)
  263. }
  264. })
  265. }
  266. func TestLastModifiedEmpty(t *testing.T) {
  267. screenName := NewIdentScreenName("sn2day")
  268. defer func() {
  269. assert.NoError(t, os.Remove(testFile))
  270. }()
  271. f, err := NewSQLiteUserStore(testFile)
  272. assert.NoError(t, err)
  273. _, err = f.FeedbagLastModified(context.Background(), screenName)
  274. if err != nil {
  275. t.Fatalf("get error from last modified: %s", err.Error())
  276. }
  277. }
  278. func TestLastModifiedNotEmpty(t *testing.T) {
  279. screenName := NewIdentScreenName("sn2day")
  280. defer func() {
  281. assert.NoError(t, os.Remove(testFile))
  282. }()
  283. f, err := NewSQLiteUserStore(testFile)
  284. assert.NoError(t, err)
  285. itemsIn := []wire.FeedbagItem{
  286. {
  287. GroupID: 0x0A,
  288. ItemID: 0,
  289. ClassID: 1,
  290. Name: "Friends",
  291. },
  292. }
  293. insertTestUsers(t, f, screenName)
  294. if err := f.FeedbagUpsert(context.Background(), screenName, itemsIn); err != nil {
  295. t.Fatalf("failed to upsert: %s", err.Error())
  296. }
  297. _, err = f.FeedbagLastModified(context.Background(), screenName)
  298. if err != nil {
  299. t.Fatalf("get error from last modified: %s", err.Error())
  300. }
  301. }
  302. func TestProfile(t *testing.T) {
  303. screenName := NewIdentScreenName("sn2day")
  304. defer func() {
  305. assert.NoError(t, os.Remove(testFile))
  306. }()
  307. f, err := NewSQLiteUserStore(testFile)
  308. assert.NoError(t, err)
  309. u := User{
  310. IdentScreenName: screenName,
  311. }
  312. if err := f.InsertUser(context.Background(), u); err != nil {
  313. t.Fatalf("failed to upsert new user: %s", err.Error())
  314. }
  315. profile, err := f.Profile(context.Background(), screenName)
  316. if err != nil {
  317. t.Fatalf("failed to retrieve profile: %s", err.Error())
  318. }
  319. if !profile.IsZero() {
  320. t.Fatalf("expected empty profile for %s", screenName)
  321. }
  322. newProfile := UserProfile{
  323. ProfileText: "here is my profile",
  324. MIMEType: "text/plain",
  325. UpdateTime: time.Now().UTC().Truncate(time.Second),
  326. }
  327. if err := f.SetProfile(context.Background(), screenName, newProfile); err != nil {
  328. t.Fatalf("failed to create new profile: %s", err.Error())
  329. }
  330. profile, err = f.Profile(context.Background(), screenName)
  331. if err != nil {
  332. t.Fatalf("failed to retrieve profile: %s", err.Error())
  333. }
  334. if profile.ProfileText != newProfile.ProfileText {
  335. t.Fatalf("profiles did not match:\n expected: %v\n actual: %v", newProfile.ProfileText, profile.ProfileText)
  336. }
  337. if profile.MIMEType != newProfile.MIMEType {
  338. t.Fatalf("mime types did not match:\n expected: %v\n actual: %v", newProfile.MIMEType, profile.MIMEType)
  339. }
  340. if !profile.UpdateTime.Equal(newProfile.UpdateTime) {
  341. t.Fatalf("update times did not match:\n expected: %v\n actual: %v", newProfile.UpdateTime, profile.UpdateTime)
  342. }
  343. updatedProfile := UserProfile{
  344. ProfileText: "here is my profile [updated]",
  345. MIMEType: "text/html",
  346. UpdateTime: time.Now().UTC().Truncate(time.Second),
  347. }
  348. if err := f.SetProfile(context.Background(), screenName, updatedProfile); err != nil {
  349. t.Fatalf("failed to create new profile: %s", err.Error())
  350. }
  351. profile, err = f.Profile(context.Background(), screenName)
  352. if err != nil {
  353. t.Fatalf("failed to retrieve profile: %s", err.Error())
  354. }
  355. if profile.ProfileText != updatedProfile.ProfileText {
  356. t.Fatalf("updated profiles did not match:\n expected: %v\n actual: %v", updatedProfile.ProfileText, profile.ProfileText)
  357. }
  358. if profile.MIMEType != updatedProfile.MIMEType {
  359. t.Fatalf("updated mime types did not match:\n expected: %v\n actual: %v", updatedProfile.MIMEType, profile.MIMEType)
  360. }
  361. if !profile.UpdateTime.Equal(updatedProfile.UpdateTime) {
  362. t.Fatalf("updated update times did not match:\n expected: %v\n actual: %v", updatedProfile.UpdateTime, profile.UpdateTime)
  363. }
  364. }
  365. func TestProfileNonExistent(t *testing.T) {
  366. screenName := NewIdentScreenName("sn2day")
  367. defer func() {
  368. assert.NoError(t, os.Remove(testFile))
  369. }()
  370. f, err := NewSQLiteUserStore(testFile)
  371. assert.NoError(t, err)
  372. prof, err := f.Profile(context.Background(), screenName)
  373. assert.NoError(t, err)
  374. assert.True(t, prof.IsZero())
  375. assert.Equal(t, "", prof.MIMEType)
  376. assert.True(t, prof.UpdateTime.IsZero())
  377. }
  378. func TestProfile_MimeTypeAndUpdateTime(t *testing.T) {
  379. screenName := NewIdentScreenName("testuser")
  380. defer func() {
  381. assert.NoError(t, os.Remove(testFile))
  382. }()
  383. f, err := NewSQLiteUserStore(testFile)
  384. require.NoError(t, err)
  385. u := User{
  386. IdentScreenName: screenName,
  387. }
  388. require.NoError(t, f.InsertUser(context.Background(), u))
  389. t.Run("profile with empty mimeType and zero updateTime", func(t *testing.T) {
  390. profile := UserProfile{
  391. ProfileText: "test profile",
  392. MIMEType: "",
  393. UpdateTime: time.Time{},
  394. }
  395. require.NoError(t, f.SetProfile(context.Background(), screenName, profile))
  396. retrieved, err := f.Profile(context.Background(), screenName)
  397. require.NoError(t, err)
  398. assert.Equal(t, profile.ProfileText, retrieved.ProfileText)
  399. assert.Equal(t, "", retrieved.MIMEType)
  400. assert.True(t, retrieved.UpdateTime.IsZero())
  401. })
  402. t.Run("profile with mimeType and updateTime", func(t *testing.T) {
  403. updateTime := time.Date(2024, 1, 15, 10, 30, 0, 0, time.UTC)
  404. profile := UserProfile{
  405. ProfileText: "test profile with mime",
  406. MIMEType: "text/html",
  407. UpdateTime: updateTime,
  408. }
  409. require.NoError(t, f.SetProfile(context.Background(), screenName, profile))
  410. retrieved, err := f.Profile(context.Background(), screenName)
  411. require.NoError(t, err)
  412. assert.Equal(t, profile.ProfileText, retrieved.ProfileText)
  413. assert.Equal(t, "text/html", retrieved.MIMEType)
  414. assert.True(t, retrieved.UpdateTime.Equal(updateTime), "expected %v, got %v", updateTime, retrieved.UpdateTime)
  415. })
  416. t.Run("update profile with different mimeType and updateTime", func(t *testing.T) {
  417. updateTime := time.Date(2024, 2, 20, 14, 45, 0, 0, time.UTC)
  418. profile := UserProfile{
  419. ProfileText: "updated profile",
  420. MIMEType: "text/plain",
  421. UpdateTime: updateTime,
  422. }
  423. require.NoError(t, f.SetProfile(context.Background(), screenName, profile))
  424. retrieved, err := f.Profile(context.Background(), screenName)
  425. require.NoError(t, err)
  426. assert.Equal(t, profile.ProfileText, retrieved.ProfileText)
  427. assert.Equal(t, "text/plain", retrieved.MIMEType)
  428. assert.True(t, retrieved.UpdateTime.Equal(updateTime), "expected %v, got %v", updateTime, retrieved.UpdateTime)
  429. })
  430. }
  431. func TestGetUser(t *testing.T) {
  432. defer func() {
  433. assert.NoError(t, os.Remove(testFile))
  434. }()
  435. f, err := NewSQLiteUserStore(testFile)
  436. assert.NoError(t, err)
  437. screenName := NewIdentScreenName("testscreenname")
  438. insertedUser := &User{
  439. IdentScreenName: screenName,
  440. DisplayScreenName: DisplayScreenName("testscreenname"),
  441. AuthKey: "theauthkey",
  442. StrongMD5Pass: []byte("thepasshash"),
  443. RegStatus: 3,
  444. LastWarnUpdate: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC), // Database default value
  445. ICQInfo: ICQInfo{
  446. Permissions: ICQPermissions{AuthRequired: true},
  447. },
  448. }
  449. err = f.InsertUser(context.Background(), *insertedUser)
  450. assert.NoError(t, err)
  451. actualUser, err := f.User(context.Background(), screenName)
  452. if err != nil {
  453. t.Fatalf("failed to get user: %s", err.Error())
  454. }
  455. if !reflect.DeepEqual(insertedUser, actualUser) {
  456. t.Fatalf("users are not equal. expect: %v actual: %v", insertedUser, actualUser)
  457. }
  458. }
  459. func TestSQLiteUserStore_User_OfflineMsgCount(t *testing.T) {
  460. defer func() {
  461. assert.NoError(t, os.Remove(testFile))
  462. }()
  463. f, err := NewSQLiteUserStore(testFile)
  464. assert.NoError(t, err)
  465. screenName := NewIdentScreenName("testuser")
  466. // Insert user first
  467. err = f.InsertUser(context.Background(), User{
  468. IdentScreenName: screenName,
  469. DisplayScreenName: DisplayScreenName("testuser"),
  470. })
  471. assert.NoError(t, err)
  472. // Set offlineMsgCount using the store method
  473. err = f.SetOfflineMsgCount(context.Background(), screenName, 5)
  474. assert.NoError(t, err)
  475. // Retrieve user and verify OfflineMsgCount is loaded
  476. user, err := f.User(context.Background(), screenName)
  477. assert.NoError(t, err)
  478. assert.NotNil(t, user)
  479. assert.Equal(t, 5, user.OfflineMsgCount)
  480. }
  481. func TestGetUserNotFound(t *testing.T) {
  482. defer func() {
  483. assert.NoError(t, os.Remove(testFile))
  484. }()
  485. f, err := NewSQLiteUserStore(testFile)
  486. assert.NoError(t, err)
  487. actualUser, err := f.User(context.Background(), NewIdentScreenName("testscreenname"))
  488. if err != nil {
  489. t.Fatalf("failed to get user: %s", err.Error())
  490. }
  491. if actualUser != nil {
  492. t.Fatal("expected user to not be found")
  493. }
  494. }
  495. func TestSQLiteUserStore_Users(t *testing.T) {
  496. defer func() {
  497. assert.NoError(t, os.Remove(testFile))
  498. }()
  499. f, err := NewSQLiteUserStore(testFile)
  500. assert.NoError(t, err)
  501. want := []User{
  502. {
  503. IdentScreenName: NewIdentScreenName("userA"),
  504. DisplayScreenName: "userA",
  505. },
  506. {
  507. IdentScreenName: NewIdentScreenName("userB"),
  508. DisplayScreenName: "userB",
  509. },
  510. {
  511. IdentScreenName: NewIdentScreenName("userC"),
  512. DisplayScreenName: "userC",
  513. IsBot: true,
  514. },
  515. {
  516. IdentScreenName: NewIdentScreenName("100003"),
  517. DisplayScreenName: "100003",
  518. IsICQ: true,
  519. },
  520. }
  521. for _, u := range want {
  522. err := f.InsertUser(context.Background(), u)
  523. assert.NoError(t, err)
  524. }
  525. have, err := f.AllUsers(context.Background())
  526. assert.NoError(t, err)
  527. assert.Equal(t, want, have)
  528. }
  529. func TestSQLiteUserStore_InsertUser_UINButNotIsICQ(t *testing.T) {
  530. defer func() {
  531. assert.NoError(t, os.Remove(testFile))
  532. }()
  533. f, err := NewSQLiteUserStore(testFile)
  534. assert.NoError(t, err)
  535. user := User{
  536. IdentScreenName: NewIdentScreenName("100003"),
  537. DisplayScreenName: "100003",
  538. }
  539. err = f.InsertUser(context.Background(), user)
  540. assert.ErrorContains(t, err, "inserting user with UIN and isICQ=false")
  541. }
  542. func TestSQLiteUserStore_DeleteUser_DeleteExistentUser(t *testing.T) {
  543. defer func() {
  544. assert.NoError(t, os.Remove(testFile))
  545. }()
  546. f, err := NewSQLiteUserStore(testFile)
  547. assert.NoError(t, err)
  548. err = f.InsertUser(context.Background(), User{
  549. IdentScreenName: NewIdentScreenName("userA"),
  550. DisplayScreenName: "userA",
  551. })
  552. assert.NoError(t, err)
  553. err = f.InsertUser(context.Background(), User{
  554. IdentScreenName: NewIdentScreenName("userB"),
  555. DisplayScreenName: "userB",
  556. })
  557. assert.NoError(t, err)
  558. err = f.DeleteUser(context.Background(), NewIdentScreenName("userA"))
  559. assert.NoError(t, err)
  560. have, err := f.AllUsers(context.Background())
  561. assert.NoError(t, err)
  562. want := []User{{
  563. IdentScreenName: NewIdentScreenName("userB"),
  564. DisplayScreenName: "userB",
  565. }}
  566. assert.Equal(t, want, have)
  567. }
  568. func TestSQLiteUserStore_DeleteUser_DeletesFeedbagAndLinks(t *testing.T) {
  569. defer func() {
  570. assert.NoError(t, os.Remove(testFile))
  571. }()
  572. f, err := NewSQLiteUserStore(testFile)
  573. require.NoError(t, err)
  574. ctx := context.Background()
  575. userA := NewIdentScreenName("userA")
  576. userB := NewIdentScreenName("userB")
  577. userC := NewIdentScreenName("userC")
  578. insertTestUsers(t, f, userA, userB, userC)
  579. linkTo := func(itemID uint16, sn IdentScreenName) wire.FeedbagItem {
  580. return wire.FeedbagItem{ItemID: itemID, ClassID: wire.FeedbagClassIdAlInfo, Name: sn.String()}
  581. }
  582. buddy := func(itemID uint16, sn IdentScreenName) wire.FeedbagItem {
  583. return wire.FeedbagItem{GroupID: 1, ItemID: itemID, ClassID: wire.FeedbagClassIdBuddy, Name: sn.String()}
  584. }
  585. require.NoError(t, f.FeedbagUpsert(ctx, userA, []wire.FeedbagItem{linkTo(1, userB), buddy(2, userC)}))
  586. require.NoError(t, f.FeedbagUpsert(ctx, userB, []wire.FeedbagItem{linkTo(1, userA), buddy(2, userC)}))
  587. require.NoError(t, f.FeedbagUpsert(ctx, userC, []wire.FeedbagItem{linkTo(1, userB), buddy(2, userB)}))
  588. require.NoError(t, f.DeleteUser(ctx, userB))
  589. // the deleted user's own feedbag is gone
  590. have, err := f.Feedbag(ctx, userB)
  591. require.NoError(t, err)
  592. assert.Empty(t, have)
  593. // links to the deleted user are gone; other items, including a buddy item
  594. // that names the deleted user, remain
  595. have, err = f.Feedbag(ctx, userA)
  596. require.NoError(t, err)
  597. assert.Equal(t, []wire.FeedbagItem{buddy(2, userC)}, have)
  598. have, err = f.Feedbag(ctx, userC)
  599. require.NoError(t, err)
  600. assert.Equal(t, []wire.FeedbagItem{buddy(2, userB)}, have)
  601. // a re-registered screen name starts with an empty feedbag
  602. insertTestUsers(t, f, userB)
  603. have, err = f.Feedbag(ctx, userB)
  604. require.NoError(t, err)
  605. assert.Empty(t, have)
  606. }
  607. func TestSQLiteUserStore_FeedbagUpsert_RequiresUser(t *testing.T) {
  608. defer func() {
  609. assert.NoError(t, os.Remove(testFile))
  610. }()
  611. f, err := NewSQLiteUserStore(testFile)
  612. require.NoError(t, err)
  613. err = f.FeedbagUpsert(context.Background(), NewIdentScreenName("nobody"), []wire.FeedbagItem{
  614. {GroupID: 1, ClassID: wire.FeedbagClassIdGroup, Name: "Friends"},
  615. })
  616. assert.ErrorContains(t, err, "FOREIGN KEY constraint failed")
  617. }
  618. func TestSQLiteUserStore_DeleteUser_DeleteNonExistentUser(t *testing.T) {
  619. defer func() {
  620. assert.NoError(t, os.Remove(testFile))
  621. }()
  622. f, err := NewSQLiteUserStore(testFile)
  623. assert.NoError(t, err)
  624. err = f.DeleteUser(context.Background(), NewIdentScreenName("userA"))
  625. assert.ErrorIs(t, ErrNoUser, err)
  626. }
  627. // insertTestUsers creates a minimal account for each screen name, since every
  628. // feedbag row must belong to a user.
  629. func insertTestUsers(t *testing.T, f *SQLiteUserStore, screenNames ...IdentScreenName) {
  630. t.Helper()
  631. for _, sn := range screenNames {
  632. require.NoError(t, f.InsertUser(context.Background(), User{
  633. IdentScreenName: sn,
  634. DisplayScreenName: DisplayScreenName(sn.String()),
  635. IsICQ: sn.UIN() != 0,
  636. }))
  637. }
  638. }
  639. func newFeedbagItem(classID uint16, itemID uint16, name string, feedbagPending bool) wire.FeedbagItem {
  640. item := wire.FeedbagItem{
  641. ClassID: classID,
  642. ItemID: itemID,
  643. Name: name,
  644. }
  645. if feedbagPending && classID == wire.FeedbagClassIdBuddy {
  646. item.Append(wire.NewTLVBE(wire.FeedbagAttributesPending, uint16(0)))
  647. }
  648. return item
  649. }
  650. func pdInfoItem(itemID uint16, pdMode wire.FeedbagPDMode) wire.FeedbagItem {
  651. return wire.FeedbagItem{
  652. ClassID: wire.FeedbagClassIdPdinfo,
  653. ItemID: itemID,
  654. TLVLBlock: wire.TLVLBlock{
  655. TLVList: wire.TLVList{
  656. wire.NewTLVBE(wire.FeedbagAttributesPdMode, uint8(pdMode)),
  657. },
  658. },
  659. }
  660. }
  661. func TestSQLiteUserStore_SetBuddyIconAndRetrieve(t *testing.T) {
  662. hash := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
  663. item := []byte{'a', 'b', 'c', 'd'}
  664. t.Run("insert_and_retrieve", func(t *testing.T) {
  665. defer func() {
  666. assert.NoError(t, os.Remove(testFile))
  667. }()
  668. feedbagStore, err := NewSQLiteUserStore(testFile)
  669. assert.NoError(t, err)
  670. b, err := feedbagStore.BARTItem(context.Background(), hash)
  671. assert.NoError(t, err)
  672. assert.Empty(t, b)
  673. err = feedbagStore.InsertBARTItem(context.Background(), hash, item, 1)
  674. assert.NoError(t, err)
  675. b, err = feedbagStore.BARTItem(context.Background(), hash)
  676. assert.NoError(t, err)
  677. assert.Equal(t, item, b)
  678. })
  679. t.Run("duplicate_insert_returns_error", func(t *testing.T) {
  680. defer func() {
  681. assert.NoError(t, os.Remove(testFile))
  682. }()
  683. feedbagStore, err := NewSQLiteUserStore(testFile)
  684. assert.NoError(t, err)
  685. // First insert the item
  686. err = feedbagStore.InsertBARTItem(context.Background(), hash, item, 1)
  687. assert.NoError(t, err)
  688. // Try to insert the same hash again
  689. err = feedbagStore.InsertBARTItem(context.Background(), hash, item, 1)
  690. assert.Error(t, err)
  691. assert.ErrorIs(t, err, ErrBARTItemExists)
  692. })
  693. }
  694. func TestSQLiteUserStore_ListBARTItems(t *testing.T) {
  695. t.Run("empty_list", func(t *testing.T) {
  696. defer func() {
  697. assert.NoError(t, os.Remove(testFile))
  698. }()
  699. feedbagStore, err := NewSQLiteUserStore(testFile)
  700. assert.NoError(t, err)
  701. items, err := feedbagStore.ListBARTItems(context.Background(), 1)
  702. assert.NoError(t, err)
  703. assert.Empty(t, items)
  704. })
  705. t.Run("list_with_items", func(t *testing.T) {
  706. defer func() {
  707. assert.NoError(t, os.Remove(testFile))
  708. }()
  709. feedbagStore, err := NewSQLiteUserStore(testFile)
  710. assert.NoError(t, err)
  711. // Insert some test items of type 1
  712. hash1 := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
  713. item1 := []byte{'a', 'b', 'c', 'd'}
  714. err = feedbagStore.InsertBARTItem(context.Background(), hash1, item1, 1)
  715. assert.NoError(t, err)
  716. hash2 := []byte{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
  717. item2 := []byte{'e', 'f', 'g', 'h'}
  718. err = feedbagStore.InsertBARTItem(context.Background(), hash2, item2, 1)
  719. assert.NoError(t, err)
  720. // List items of type 1
  721. items, err := feedbagStore.ListBARTItems(context.Background(), 1)
  722. assert.NoError(t, err)
  723. assert.Len(t, items, 2)
  724. // Check that items are sorted by hash
  725. assert.Equal(t, "000102030405060708090a0b0c0d0e0f", items[0].Hash)
  726. assert.Equal(t, uint16(1), items[0].Type)
  727. assert.Equal(t, "0f0e0d0c0b0a09080706050403020100", items[1].Hash)
  728. assert.Equal(t, uint16(1), items[1].Type)
  729. })
  730. }
  731. func TestSQLiteUserStore_BuddyAddedNotifications(t *testing.T) {
  732. defer func() {
  733. assert.NoError(t, os.Remove(testFile))
  734. }()
  735. store, err := NewSQLiteUserStore(testFile)
  736. require.NoError(t, err)
  737. granter := NewIdentScreenName("granter")
  738. requester := NewIdentScreenName("requester")
  739. // ensure both users exist to satisfy FKs
  740. assert.NoError(t, store.InsertUser(context.Background(), User{
  741. IdentScreenName: granter,
  742. DisplayScreenName: DisplayScreenName("Granter"),
  743. }))
  744. assert.NoError(t, store.InsertUser(context.Background(), User{
  745. IdentScreenName: requester,
  746. DisplayScreenName: DisplayScreenName("Requester"),
  747. }))
  748. has, err := store.HasBuddyAddedNotification(context.Background(), granter, requester)
  749. assert.NoError(t, err)
  750. assert.False(t, has)
  751. assert.NoError(t, store.RecordBuddyAddedNotification(context.Background(), granter, requester))
  752. has, err = store.HasBuddyAddedNotification(context.Background(), granter, requester)
  753. assert.NoError(t, err)
  754. assert.True(t, has)
  755. // idempotent
  756. assert.NoError(t, store.RecordBuddyAddedNotification(context.Background(), granter, requester))
  757. }
  758. func TestSQLiteUserStore_RecordBuddyAddedNotification_unknownUser(t *testing.T) {
  759. defer func() {
  760. assert.NoError(t, os.Remove(testFile))
  761. }()
  762. store, err := NewSQLiteUserStore(testFile)
  763. require.NoError(t, err)
  764. granter := NewIdentScreenName("100001")
  765. assert.NoError(t, store.InsertUser(context.Background(), User{
  766. IdentScreenName: granter,
  767. DisplayScreenName: DisplayScreenName("Granter"),
  768. }))
  769. unknownBuddy := NewIdentScreenName("999999")
  770. assert.NoError(t, store.RecordBuddyAddedNotification(context.Background(), granter, unknownBuddy))
  771. has, err := store.HasBuddyAddedNotification(context.Background(), granter, unknownBuddy)
  772. assert.NoError(t, err)
  773. assert.False(t, has)
  774. }
  775. func TestSQLiteUserStore_SetUserPassword_UserExists(t *testing.T) {
  776. defer func() {
  777. assert.NoError(t, os.Remove(testFile))
  778. }()
  779. feedbagStore, err := NewSQLiteUserStore(testFile)
  780. assert.NoError(t, err)
  781. u := User{
  782. IdentScreenName: NewIdentScreenName("theuser"),
  783. DisplayScreenName: "theUser",
  784. }
  785. err = u.HashPassword("thepassword")
  786. assert.NoError(t, err)
  787. err = feedbagStore.InsertUser(context.Background(), u)
  788. assert.NoError(t, err)
  789. err = feedbagStore.SetUserPassword(context.Background(), u.IdentScreenName, "theNEWpassword")
  790. assert.NoError(t, err)
  791. gotUser, err := feedbagStore.User(context.Background(), u.IdentScreenName)
  792. assert.NoError(t, err)
  793. wantUser := User{}
  794. _ = wantUser.HashPassword("theNEWpassword")
  795. valid := gotUser.ValidateHash(wantUser.StrongMD5Pass)
  796. assert.True(t, valid)
  797. }
  798. func TestSQLiteUserStore_SetUserPassword_ErrNoUser(t *testing.T) {
  799. defer func() {
  800. assert.NoError(t, os.Remove(testFile))
  801. }()
  802. feedbagStore, err := NewSQLiteUserStore(testFile)
  803. assert.NoError(t, err)
  804. err = feedbagStore.SetUserPassword(context.Background(), NewIdentScreenName("some_user"), "thepassword")
  805. assert.ErrorIs(t, err, ErrNoUser)
  806. }
  807. func TestSQLiteUserStore_ChatRoomByCookie(t *testing.T) {
  808. tests := []struct {
  809. name string
  810. givenRoom ChatRoom
  811. lookupRoom ChatRoom
  812. expectedErr error
  813. }{
  814. {
  815. name: "chat room found",
  816. givenRoom: NewChatRoom("my chat room", NewIdentScreenName("creator"), PrivateExchange),
  817. lookupRoom: NewChatRoom("my chat room", NewIdentScreenName("creator"), PrivateExchange),
  818. expectedErr: nil,
  819. },
  820. {
  821. name: "chat room found - different name casing",
  822. givenRoom: NewChatRoom("my chat room", NewIdentScreenName("creator"), PrivateExchange),
  823. lookupRoom: NewChatRoom("MY CHAT ROOM", NewIdentScreenName("creator"), PrivateExchange),
  824. expectedErr: nil,
  825. },
  826. {
  827. name: "chat room not found",
  828. givenRoom: NewChatRoom("my chat room", NewIdentScreenName("creator"), PrivateExchange),
  829. lookupRoom: NewChatRoom("your chat room", NewIdentScreenName("creator"), PrivateExchange),
  830. expectedErr: ErrChatRoomNotFound,
  831. },
  832. }
  833. for _, tt := range tests {
  834. t.Run(tt.name, func(t *testing.T) {
  835. defer func() {
  836. assert.NoError(t, os.Remove(testFile))
  837. }()
  838. userStore, err := NewSQLiteUserStore(testFile)
  839. assert.NoError(t, err)
  840. err = userStore.CreateChatRoom(context.Background(), &tt.givenRoom)
  841. assert.NoError(t, err)
  842. gotRoom, err := userStore.ChatRoomByCookie(context.Background(), tt.lookupRoom.Cookie())
  843. assert.ErrorIs(t, err, tt.expectedErr)
  844. if tt.expectedErr == nil {
  845. assert.Equal(t, tt.givenRoom.Cookie(), gotRoom.Cookie())
  846. }
  847. })
  848. }
  849. }
  850. func TestSQLiteUserStore_ChatRoomByName(t *testing.T) {
  851. tests := []struct {
  852. name string
  853. givenRoom ChatRoom
  854. lookupRoom ChatRoom
  855. expectedErr error
  856. }{
  857. {
  858. name: "chat room found",
  859. givenRoom: NewChatRoom("my chat room", NewIdentScreenName("creator"), PrivateExchange),
  860. lookupRoom: NewChatRoom("my chat room", NewIdentScreenName("creator"), PrivateExchange),
  861. expectedErr: nil,
  862. },
  863. {
  864. name: "chat room found - different name casing",
  865. givenRoom: NewChatRoom("my chat room", NewIdentScreenName("creator"), PrivateExchange),
  866. lookupRoom: NewChatRoom("MY CHAT ROOM", NewIdentScreenName("creator"), PrivateExchange),
  867. expectedErr: nil,
  868. },
  869. {
  870. name: "chat room not found",
  871. givenRoom: NewChatRoom("my chat room", NewIdentScreenName("creator"), PrivateExchange),
  872. lookupRoom: NewChatRoom("your chat room", NewIdentScreenName("creator"), PrivateExchange),
  873. expectedErr: ErrChatRoomNotFound,
  874. },
  875. }
  876. for _, tt := range tests {
  877. t.Run(tt.name, func(t *testing.T) {
  878. defer func() {
  879. assert.NoError(t, os.Remove(testFile))
  880. }()
  881. userStore, err := NewSQLiteUserStore(testFile)
  882. assert.NoError(t, err)
  883. err = userStore.CreateChatRoom(context.Background(), &tt.givenRoom)
  884. assert.NoError(t, err)
  885. gotRoom, err := userStore.ChatRoomByName(context.Background(), tt.lookupRoom.Exchange(), tt.lookupRoom.Name())
  886. assert.ErrorIs(t, err, tt.expectedErr)
  887. if tt.expectedErr == nil {
  888. assert.Equal(t, tt.givenRoom.Cookie(), gotRoom.Cookie())
  889. }
  890. })
  891. }
  892. }
  893. func TestSQLiteUserStore_AllChatRooms(t *testing.T) {
  894. defer func() {
  895. assert.NoError(t, os.Remove(testFile))
  896. }()
  897. userStore, err := NewSQLiteUserStore(testFile)
  898. assert.NoError(t, err)
  899. chatRooms := []ChatRoom{
  900. NewChatRoom("chat room 1", NewIdentScreenName("creator"), PrivateExchange),
  901. NewChatRoom("chat room 2", NewIdentScreenName("creator"), PrivateExchange),
  902. NewChatRoom("chat room 3", NewIdentScreenName("creator"), PublicExchange),
  903. }
  904. for i := range chatRooms {
  905. tBefore := (&chatRooms[i]).CreateTime()
  906. err = userStore.CreateChatRoom(context.Background(), &chatRooms[i])
  907. assert.NoError(t, err)
  908. assert.True(t, chatRooms[i].CreateTime().After(tBefore))
  909. }
  910. // public exchange
  911. gotRooms, err := userStore.AllChatRooms(context.Background(), 5)
  912. assert.NoError(t, err)
  913. assert.Equal(t, chatRooms[2:], gotRooms)
  914. // private exchange
  915. gotRooms, err = userStore.AllChatRooms(context.Background(), 4)
  916. assert.NoError(t, err)
  917. assert.Equal(t, chatRooms[0:2], gotRooms)
  918. }
  919. func TestSQLiteUserStore_CreateChatRoom_ErrChatRoomExists(t *testing.T) {
  920. tt := []struct {
  921. name string
  922. firstInsert ChatRoom
  923. secondInsert ChatRoom
  924. wantErr error
  925. }{
  926. {
  927. name: "create two rooms with different cookie/exchange, same name",
  928. firstInsert: NewChatRoom("chat room", NewIdentScreenName("creator"), PublicExchange),
  929. secondInsert: NewChatRoom("chat room", NewIdentScreenName("creator"), PrivateExchange),
  930. wantErr: nil,
  931. },
  932. {
  933. name: "create two rooms with same cookie/exchange/name",
  934. firstInsert: NewChatRoom("chat room", NewIdentScreenName("creator"), PublicExchange),
  935. secondInsert: NewChatRoom("chat room", NewIdentScreenName("creator"), PublicExchange),
  936. wantErr: ErrDupChatRoom,
  937. },
  938. }
  939. for _, tc := range tt {
  940. t.Run(tc.name, func(t *testing.T) {
  941. defer func() {
  942. assert.NoError(t, os.Remove(testFile))
  943. }()
  944. userStore, err := NewSQLiteUserStore(testFile)
  945. assert.NoError(t, err)
  946. err = userStore.CreateChatRoom(context.Background(), &tc.firstInsert)
  947. assert.NoError(t, err)
  948. err = userStore.CreateChatRoom(context.Background(), &tc.secondInsert)
  949. assert.ErrorIs(t, err, tc.wantErr)
  950. })
  951. }
  952. }
  953. func TestUpdateDisplayScreenName(t *testing.T) {
  954. screenNameOriginal := DisplayScreenName("chattingchuck")
  955. screenNameFormatted := DisplayScreenName("Chatting Chuck")
  956. defer func() {
  957. assert.NoError(t, os.Remove(testFile))
  958. }()
  959. f, err := NewSQLiteUserStore(testFile)
  960. assert.NoError(t, err)
  961. user := User{
  962. DisplayScreenName: screenNameOriginal,
  963. IdentScreenName: screenNameOriginal.IdentScreenName(),
  964. RegStatus: 3,
  965. }
  966. if err := f.InsertUser(context.Background(), user); err != nil {
  967. t.Fatalf("failed to upsert new user: %s", err.Error())
  968. }
  969. err = f.UpdateDisplayScreenName(context.Background(), screenNameFormatted)
  970. if err != nil {
  971. t.Fatalf("failed to update display screen name: %s", err.Error())
  972. }
  973. dbUser, err := f.User(context.Background(), screenNameOriginal.IdentScreenName())
  974. if err != nil {
  975. t.Fatalf("failed to retrieve screen name: %s", err.Error())
  976. }
  977. assert.Equal(t, dbUser.DisplayScreenName, screenNameFormatted)
  978. }
  979. func TestSQLiteUserStore_SetWorkInfo(t *testing.T) {
  980. defer func() {
  981. assert.NoError(t, os.Remove(testFile))
  982. }()
  983. f, err := NewSQLiteUserStore(testFile)
  984. assert.NoError(t, err)
  985. screenName := NewIdentScreenName("testuser")
  986. user := User{
  987. IdentScreenName: screenName,
  988. }
  989. err = f.InsertUser(context.Background(), user)
  990. assert.NoError(t, err)
  991. // Define the work info to set
  992. workInfo := ICQWorkInfo{
  993. Company: "Test Company",
  994. Department: "Test Department",
  995. OccupationCode: 10,
  996. Position: "Test Position",
  997. Address: "123 Test St",
  998. City: "Test City",
  999. CountryCode: 1,
  1000. Fax: "123-456-7890",
  1001. Phone: "098-765-4321",
  1002. State: "Test State",
  1003. WebPage: "http://www.test.com",
  1004. ZIPCode: "12345",
  1005. }
  1006. t.Run("Successful Update", func(t *testing.T) {
  1007. // Call SetWorkInfo
  1008. err := f.SetWorkInfo(context.Background(), screenName, workInfo)
  1009. assert.NoError(t, err)
  1010. // Retrieve the user and verify the work info was set correctly
  1011. updatedUser, err := f.User(context.Background(), screenName)
  1012. assert.NoError(t, err)
  1013. assert.Equal(t, workInfo.Company, updatedUser.ICQInfo.Work.Company)
  1014. assert.Equal(t, workInfo.Department, updatedUser.ICQInfo.Work.Department)
  1015. assert.Equal(t, workInfo.OccupationCode, updatedUser.ICQInfo.Work.OccupationCode)
  1016. assert.Equal(t, workInfo.Position, updatedUser.ICQInfo.Work.Position)
  1017. assert.Equal(t, workInfo.Address, updatedUser.ICQInfo.Work.Address)
  1018. assert.Equal(t, workInfo.City, updatedUser.ICQInfo.Work.City)
  1019. assert.Equal(t, workInfo.CountryCode, updatedUser.ICQInfo.Work.CountryCode)
  1020. assert.Equal(t, workInfo.Fax, updatedUser.ICQInfo.Work.Fax)
  1021. assert.Equal(t, workInfo.Phone, updatedUser.ICQInfo.Work.Phone)
  1022. assert.Equal(t, workInfo.State, updatedUser.ICQInfo.Work.State)
  1023. assert.Equal(t, workInfo.WebPage, updatedUser.ICQInfo.Work.WebPage)
  1024. assert.Equal(t, workInfo.ZIPCode, updatedUser.ICQInfo.Work.ZIPCode)
  1025. })
  1026. t.Run("Update Non-Existing User", func(t *testing.T) {
  1027. // Try to set work info for a non-existing user
  1028. nonExistingScreenName := NewIdentScreenName("nonexistentuser")
  1029. err := f.SetWorkInfo(context.Background(), nonExistingScreenName, workInfo)
  1030. // This should return ErrNoUser, as the user does not exist
  1031. assert.ErrorIs(t, err, ErrNoUser)
  1032. })
  1033. t.Run("Empty Work Info", func(t *testing.T) {
  1034. // Test updating with empty work info (depending on business rules, this might be allowed or not)
  1035. emptyWorkInfo := ICQWorkInfo{}
  1036. err := f.SetWorkInfo(context.Background(), screenName, emptyWorkInfo)
  1037. assert.NoError(t, err)
  1038. // Retrieve the user and verify that fields are empty or have default values
  1039. updatedUser, err := f.User(context.Background(), screenName)
  1040. assert.NoError(t, err)
  1041. assert.Empty(t, updatedUser.ICQInfo.Work.Company)
  1042. assert.Empty(t, updatedUser.ICQInfo.Work.Department)
  1043. assert.Empty(t, updatedUser.ICQInfo.Work.OccupationCode)
  1044. assert.Empty(t, updatedUser.ICQInfo.Work.Position)
  1045. assert.Empty(t, updatedUser.ICQInfo.Work.Address)
  1046. assert.Empty(t, updatedUser.ICQInfo.Work.City)
  1047. assert.Empty(t, updatedUser.ICQInfo.Work.CountryCode)
  1048. assert.Empty(t, updatedUser.ICQInfo.Work.Fax)
  1049. assert.Empty(t, updatedUser.ICQInfo.Work.Phone)
  1050. assert.Empty(t, updatedUser.ICQInfo.Work.State)
  1051. assert.Empty(t, updatedUser.ICQInfo.Work.WebPage)
  1052. assert.Empty(t, updatedUser.ICQInfo.Work.ZIPCode)
  1053. })
  1054. }
  1055. func TestSQLiteUserStore_SetMoreInfo(t *testing.T) {
  1056. // Cleanup after test
  1057. defer func() {
  1058. assert.NoError(t, os.Remove(testFile))
  1059. }()
  1060. // Initialize the SQLiteUserStore with a test database file
  1061. f, err := NewSQLiteUserStore(testFile)
  1062. assert.NoError(t, err)
  1063. // Create a test user
  1064. screenName := NewIdentScreenName("testuser")
  1065. user := User{
  1066. IdentScreenName: screenName,
  1067. }
  1068. err = f.InsertUser(context.Background(), user)
  1069. assert.NoError(t, err)
  1070. // Define the more info data to set
  1071. moreInfo := ICQMoreInfo{
  1072. BirthDay: 15,
  1073. BirthMonth: 8,
  1074. BirthYear: 1990,
  1075. Gender: 1,
  1076. HomePageAddr: "http://example.com",
  1077. Lang1: 1,
  1078. Lang2: 2,
  1079. Lang3: 3,
  1080. }
  1081. t.Run("Successful Update", func(t *testing.T) {
  1082. // Call SetMoreInfo
  1083. err := f.SetMoreInfo(context.Background(), screenName, moreInfo)
  1084. assert.NoError(t, err)
  1085. // Retrieve the user and verify the more info was set correctly
  1086. updatedUser, err := f.User(context.Background(), screenName)
  1087. assert.NoError(t, err)
  1088. assert.Equal(t, moreInfo.BirthDay, updatedUser.ICQInfo.More.BirthDay)
  1089. assert.Equal(t, moreInfo.BirthMonth, updatedUser.ICQInfo.More.BirthMonth)
  1090. assert.Equal(t, moreInfo.BirthYear, updatedUser.ICQInfo.More.BirthYear)
  1091. assert.Equal(t, moreInfo.Gender, updatedUser.ICQInfo.More.Gender)
  1092. assert.Equal(t, moreInfo.HomePageAddr, updatedUser.ICQInfo.More.HomePageAddr)
  1093. assert.Equal(t, moreInfo.Lang1, updatedUser.ICQInfo.More.Lang1)
  1094. assert.Equal(t, moreInfo.Lang2, updatedUser.ICQInfo.More.Lang2)
  1095. assert.Equal(t, moreInfo.Lang3, updatedUser.ICQInfo.More.Lang3)
  1096. })
  1097. t.Run("Update Non-Existing User", func(t *testing.T) {
  1098. // Try to set more info for a non-existing user
  1099. nonExistingScreenName := NewIdentScreenName("nonexistentuser")
  1100. err := f.SetMoreInfo(context.Background(), nonExistingScreenName, moreInfo)
  1101. // This should return ErrNoUser, as the user does not exist
  1102. assert.ErrorIs(t, err, ErrNoUser)
  1103. })
  1104. t.Run("Empty More Info", func(t *testing.T) {
  1105. // Test updating with empty more info
  1106. emptyMoreInfo := ICQMoreInfo{}
  1107. err := f.SetMoreInfo(context.Background(), screenName, emptyMoreInfo)
  1108. assert.NoError(t, err)
  1109. // Retrieve the user and verify that fields are empty or have default values
  1110. updatedUser, err := f.User(context.Background(), screenName)
  1111. assert.NoError(t, err)
  1112. assert.Empty(t, updatedUser.ICQInfo.More.BirthDay)
  1113. assert.Empty(t, updatedUser.ICQInfo.More.BirthMonth)
  1114. assert.Empty(t, updatedUser.ICQInfo.More.BirthYear)
  1115. assert.Empty(t, updatedUser.ICQInfo.More.Gender)
  1116. assert.Empty(t, updatedUser.ICQInfo.More.HomePageAddr)
  1117. assert.Empty(t, updatedUser.ICQInfo.More.Lang1)
  1118. assert.Empty(t, updatedUser.ICQInfo.More.Lang2)
  1119. assert.Empty(t, updatedUser.ICQInfo.More.Lang3)
  1120. })
  1121. }
  1122. func TestSQLiteUserStore_SetUserNotes(t *testing.T) {
  1123. // Cleanup after test
  1124. defer func() {
  1125. assert.NoError(t, os.Remove(testFile))
  1126. }()
  1127. // Initialize the SQLiteUserStore with a test database file
  1128. f, err := NewSQLiteUserStore(testFile)
  1129. assert.NoError(t, err)
  1130. // Create a test user
  1131. screenName := NewIdentScreenName("testuser")
  1132. user := User{
  1133. IdentScreenName: screenName,
  1134. }
  1135. err = f.InsertUser(context.Background(), user)
  1136. assert.NoError(t, err)
  1137. // Define the user notes to set
  1138. userNotes := ICQUserNotes{
  1139. Notes: "This is a test note.",
  1140. }
  1141. t.Run("Successful Update", func(t *testing.T) {
  1142. // Call SetUserNotes
  1143. err := f.SetUserNotes(context.Background(), screenName, userNotes)
  1144. assert.NoError(t, err)
  1145. // Retrieve the user and verify the notes were set correctly
  1146. updatedUser, err := f.User(context.Background(), screenName)
  1147. assert.NoError(t, err)
  1148. assert.Equal(t, userNotes.Notes, updatedUser.ICQInfo.Notes.Notes)
  1149. })
  1150. t.Run("Update Non-Existing User", func(t *testing.T) {
  1151. // Try to set notes for a non-existing user
  1152. nonExistingScreenName := NewIdentScreenName("nonexistentuser")
  1153. err := f.SetUserNotes(context.Background(), nonExistingScreenName, userNotes)
  1154. // This should return ErrNoUser, as the user does not exist
  1155. assert.ErrorIs(t, err, ErrNoUser)
  1156. })
  1157. t.Run("Empty Notes", func(t *testing.T) {
  1158. // Test updating with empty notes
  1159. emptyNotes := ICQUserNotes{Notes: ""}
  1160. err := f.SetUserNotes(context.Background(), screenName, emptyNotes)
  1161. assert.NoError(t, err)
  1162. // Retrieve the user and verify that notes are empty
  1163. updatedUser, err := f.User(context.Background(), screenName)
  1164. assert.NoError(t, err)
  1165. assert.Empty(t, updatedUser.ICQInfo.Notes.Notes)
  1166. })
  1167. }
  1168. func TestSQLiteUserStore_SetInterests(t *testing.T) {
  1169. // Cleanup after test
  1170. defer func() {
  1171. assert.NoError(t, os.Remove(testFile))
  1172. }()
  1173. // Initialize the SQLiteUserStore with a test database file
  1174. f, err := NewSQLiteUserStore(testFile)
  1175. assert.NoError(t, err)
  1176. // Create a test user
  1177. screenName := NewIdentScreenName("testuser")
  1178. user := User{
  1179. IdentScreenName: screenName,
  1180. }
  1181. err = f.InsertUser(context.Background(), user)
  1182. assert.NoError(t, err)
  1183. // Define the interests data to set
  1184. interests := ICQInterests{
  1185. Code1: 1,
  1186. Keyword1: "Coding",
  1187. Code2: 2,
  1188. Keyword2: "Music",
  1189. Code3: 3,
  1190. Keyword3: "Gaming",
  1191. Code4: 4,
  1192. Keyword4: "Travel",
  1193. }
  1194. t.Run("Successful Update", func(t *testing.T) {
  1195. // Call SetInterests
  1196. err := f.SetInterests(context.Background(), screenName, interests)
  1197. assert.NoError(t, err)
  1198. // Retrieve the user and verify the interests were set correctly
  1199. updatedUser, err := f.User(context.Background(), screenName)
  1200. assert.NoError(t, err)
  1201. assert.Equal(t, interests.Code1, updatedUser.ICQInfo.Interests.Code1)
  1202. assert.Equal(t, interests.Keyword1, updatedUser.ICQInfo.Interests.Keyword1)
  1203. assert.Equal(t, interests.Code2, updatedUser.ICQInfo.Interests.Code2)
  1204. assert.Equal(t, interests.Keyword2, updatedUser.ICQInfo.Interests.Keyword2)
  1205. assert.Equal(t, interests.Code3, updatedUser.ICQInfo.Interests.Code3)
  1206. assert.Equal(t, interests.Keyword3, updatedUser.ICQInfo.Interests.Keyword3)
  1207. assert.Equal(t, interests.Code4, updatedUser.ICQInfo.Interests.Code4)
  1208. assert.Equal(t, interests.Keyword4, updatedUser.ICQInfo.Interests.Keyword4)
  1209. })
  1210. t.Run("Update Non-Existing User", func(t *testing.T) {
  1211. // Try to set interests for a non-existing user
  1212. nonExistingScreenName := NewIdentScreenName("nonexistentuser")
  1213. err := f.SetInterests(context.Background(), nonExistingScreenName, interests)
  1214. // This should return ErrNoUser, as the user does not exist
  1215. assert.ErrorIs(t, err, ErrNoUser)
  1216. })
  1217. t.Run("Empty Interests", func(t *testing.T) {
  1218. // Test updating with empty interests
  1219. emptyInterests := ICQInterests{}
  1220. err := f.SetInterests(context.Background(), screenName, emptyInterests)
  1221. assert.NoError(t, err)
  1222. // Retrieve the user and verify that interests fields are empty or have default values
  1223. updatedUser, err := f.User(context.Background(), screenName)
  1224. assert.NoError(t, err)
  1225. assert.Empty(t, updatedUser.ICQInfo.Interests.Code1)
  1226. assert.Empty(t, updatedUser.ICQInfo.Interests.Keyword1)
  1227. assert.Empty(t, updatedUser.ICQInfo.Interests.Code2)
  1228. assert.Empty(t, updatedUser.ICQInfo.Interests.Keyword2)
  1229. assert.Empty(t, updatedUser.ICQInfo.Interests.Code3)
  1230. assert.Empty(t, updatedUser.ICQInfo.Interests.Keyword3)
  1231. assert.Empty(t, updatedUser.ICQInfo.Interests.Code4)
  1232. assert.Empty(t, updatedUser.ICQInfo.Interests.Keyword4)
  1233. })
  1234. }
  1235. func TestSQLiteUserStore_SetAffiliations(t *testing.T) {
  1236. // Cleanup after test
  1237. defer func() {
  1238. assert.NoError(t, os.Remove(testFile))
  1239. }()
  1240. // Initialize the SQLiteUserStore with a test database file
  1241. f, err := NewSQLiteUserStore(testFile)
  1242. assert.NoError(t, err)
  1243. // Create a test user
  1244. screenName := NewIdentScreenName("testuser")
  1245. user := User{
  1246. IdentScreenName: screenName,
  1247. }
  1248. err = f.InsertUser(context.Background(), user)
  1249. assert.NoError(t, err)
  1250. // Define the affiliations data to set
  1251. affiliations := ICQAffiliations{
  1252. CurrentCode1: 1,
  1253. CurrentKeyword1: "Sports",
  1254. CurrentCode2: 2,
  1255. CurrentKeyword2: "Science",
  1256. CurrentCode3: 3,
  1257. CurrentKeyword3: "Arts",
  1258. PastCode1: 4,
  1259. PastKeyword1: "Literature",
  1260. PastCode2: 5,
  1261. PastKeyword2: "Music",
  1262. PastCode3: 6,
  1263. PastKeyword3: "Technology",
  1264. }
  1265. t.Run("Successful Update", func(t *testing.T) {
  1266. // Call SetAffiliations
  1267. err := f.SetAffiliations(context.Background(), screenName, affiliations)
  1268. assert.NoError(t, err)
  1269. // Retrieve the user and verify the affiliations were set correctly
  1270. updatedUser, err := f.User(context.Background(), screenName)
  1271. assert.NoError(t, err)
  1272. assert.Equal(t, affiliations.CurrentCode1, updatedUser.ICQInfo.Affiliations.CurrentCode1)
  1273. assert.Equal(t, affiliations.CurrentKeyword1, updatedUser.ICQInfo.Affiliations.CurrentKeyword1)
  1274. assert.Equal(t, affiliations.CurrentCode2, updatedUser.ICQInfo.Affiliations.CurrentCode2)
  1275. assert.Equal(t, affiliations.CurrentKeyword2, updatedUser.ICQInfo.Affiliations.CurrentKeyword2)
  1276. assert.Equal(t, affiliations.CurrentCode3, updatedUser.ICQInfo.Affiliations.CurrentCode3)
  1277. assert.Equal(t, affiliations.CurrentKeyword3, updatedUser.ICQInfo.Affiliations.CurrentKeyword3)
  1278. assert.Equal(t, affiliations.PastCode1, updatedUser.ICQInfo.Affiliations.PastCode1)
  1279. assert.Equal(t, affiliations.PastKeyword1, updatedUser.ICQInfo.Affiliations.PastKeyword1)
  1280. assert.Equal(t, affiliations.PastCode2, updatedUser.ICQInfo.Affiliations.PastCode2)
  1281. assert.Equal(t, affiliations.PastKeyword2, updatedUser.ICQInfo.Affiliations.PastKeyword2)
  1282. assert.Equal(t, affiliations.PastCode3, updatedUser.ICQInfo.Affiliations.PastCode3)
  1283. assert.Equal(t, affiliations.PastKeyword3, updatedUser.ICQInfo.Affiliations.PastKeyword3)
  1284. })
  1285. t.Run("Update Non-Existing User", func(t *testing.T) {
  1286. // Try to set affiliations for a non-existing user
  1287. nonExistingScreenName := NewIdentScreenName("nonexistentuser")
  1288. err := f.SetAffiliations(context.Background(), nonExistingScreenName, affiliations)
  1289. // This should return ErrNoUser, as the user does not exist
  1290. assert.ErrorIs(t, err, ErrNoUser)
  1291. })
  1292. t.Run("Empty Affiliations", func(t *testing.T) {
  1293. // Test updating with empty affiliations
  1294. emptyAffiliations := ICQAffiliations{}
  1295. err := f.SetAffiliations(context.Background(), screenName, emptyAffiliations)
  1296. assert.NoError(t, err)
  1297. // Retrieve the user and verify that affiliations fields are empty or have default values
  1298. updatedUser, err := f.User(context.Background(), screenName)
  1299. assert.NoError(t, err)
  1300. assert.Empty(t, updatedUser.ICQInfo.Affiliations.CurrentCode1)
  1301. assert.Empty(t, updatedUser.ICQInfo.Affiliations.CurrentKeyword1)
  1302. assert.Empty(t, updatedUser.ICQInfo.Affiliations.CurrentCode2)
  1303. assert.Empty(t, updatedUser.ICQInfo.Affiliations.CurrentKeyword2)
  1304. assert.Empty(t, updatedUser.ICQInfo.Affiliations.CurrentCode3)
  1305. assert.Empty(t, updatedUser.ICQInfo.Affiliations.CurrentKeyword3)
  1306. assert.Empty(t, updatedUser.ICQInfo.Affiliations.PastCode1)
  1307. assert.Empty(t, updatedUser.ICQInfo.Affiliations.PastKeyword1)
  1308. assert.Empty(t, updatedUser.ICQInfo.Affiliations.PastCode2)
  1309. assert.Empty(t, updatedUser.ICQInfo.Affiliations.PastKeyword2)
  1310. assert.Empty(t, updatedUser.ICQInfo.Affiliations.PastCode3)
  1311. assert.Empty(t, updatedUser.ICQInfo.Affiliations.PastKeyword3)
  1312. })
  1313. }
  1314. func TestSQLiteUserStore_SetBasicInfo(t *testing.T) {
  1315. // Cleanup after test
  1316. defer func() {
  1317. assert.NoError(t, os.Remove(testFile))
  1318. }()
  1319. // Initialize the SQLiteUserStore with a test database file
  1320. f, err := NewSQLiteUserStore(testFile)
  1321. assert.NoError(t, err)
  1322. // Create a test user
  1323. screenName := NewIdentScreenName("testuser")
  1324. user := User{
  1325. IdentScreenName: screenName,
  1326. }
  1327. err = f.InsertUser(context.Background(), user)
  1328. assert.NoError(t, err)
  1329. // Define the basic info data to set
  1330. basicInfo := ICQBasicInfo{
  1331. CellPhone: "123-456-7890",
  1332. CountryCode: 1,
  1333. EmailAddress: "test@example.com",
  1334. FirstName: "John",
  1335. GMTOffset: 5,
  1336. Address: "123 Main St",
  1337. City: "Test City",
  1338. Fax: "098-765-4321",
  1339. Phone: "111-222-3333",
  1340. State: "Test State",
  1341. LastName: "Doe",
  1342. Nickname: "Johnny",
  1343. PublishEmail: true,
  1344. ZIPCode: "12345",
  1345. }
  1346. t.Run("Successful Update", func(t *testing.T) {
  1347. // Call SetBasicInfo
  1348. err := f.SetBasicInfo(context.Background(), screenName, basicInfo)
  1349. assert.NoError(t, err)
  1350. // Retrieve the user and verify the basic info was set correctly
  1351. updatedUser, err := f.User(context.Background(), screenName)
  1352. assert.NoError(t, err)
  1353. assert.Equal(t, basicInfo.CellPhone, updatedUser.ICQInfo.Basic.CellPhone)
  1354. assert.Equal(t, basicInfo.CountryCode, updatedUser.ICQInfo.Basic.CountryCode)
  1355. assert.Equal(t, basicInfo.EmailAddress, updatedUser.ICQInfo.Basic.EmailAddress)
  1356. assert.Equal(t, basicInfo.FirstName, updatedUser.ICQInfo.Basic.FirstName)
  1357. assert.Equal(t, basicInfo.GMTOffset, updatedUser.ICQInfo.Basic.GMTOffset)
  1358. assert.Equal(t, basicInfo.Address, updatedUser.ICQInfo.Basic.Address)
  1359. assert.Equal(t, basicInfo.City, updatedUser.ICQInfo.Basic.City)
  1360. assert.Equal(t, basicInfo.Fax, updatedUser.ICQInfo.Basic.Fax)
  1361. assert.Equal(t, basicInfo.Phone, updatedUser.ICQInfo.Basic.Phone)
  1362. assert.Equal(t, basicInfo.State, updatedUser.ICQInfo.Basic.State)
  1363. assert.Equal(t, basicInfo.LastName, updatedUser.ICQInfo.Basic.LastName)
  1364. assert.Equal(t, basicInfo.Nickname, updatedUser.ICQInfo.Basic.Nickname)
  1365. assert.Equal(t, basicInfo.PublishEmail, updatedUser.ICQInfo.Basic.PublishEmail)
  1366. assert.Equal(t, basicInfo.ZIPCode, updatedUser.ICQInfo.Basic.ZIPCode)
  1367. })
  1368. t.Run("Update Non-Existing User", func(t *testing.T) {
  1369. // Try to set basic info for a non-existing user
  1370. nonExistingScreenName := NewIdentScreenName("nonexistentuser")
  1371. err := f.SetBasicInfo(context.Background(), nonExistingScreenName, basicInfo)
  1372. // This should return ErrNoUser, as the user does not exist
  1373. assert.ErrorIs(t, err, ErrNoUser)
  1374. })
  1375. t.Run("Empty Basic Info", func(t *testing.T) {
  1376. // Test updating with empty basic info
  1377. emptyBasicInfo := ICQBasicInfo{}
  1378. err := f.SetBasicInfo(context.Background(), screenName, emptyBasicInfo)
  1379. assert.NoError(t, err)
  1380. // Retrieve the user and verify that basic info fields are empty or have default values
  1381. updatedUser, err := f.User(context.Background(), screenName)
  1382. assert.NoError(t, err)
  1383. assert.Empty(t, updatedUser.ICQInfo.Basic.CellPhone)
  1384. assert.Empty(t, updatedUser.ICQInfo.Basic.CountryCode)
  1385. assert.Empty(t, updatedUser.ICQInfo.Basic.EmailAddress)
  1386. assert.Empty(t, updatedUser.ICQInfo.Basic.FirstName)
  1387. assert.Empty(t, updatedUser.ICQInfo.Basic.GMTOffset)
  1388. assert.Empty(t, updatedUser.ICQInfo.Basic.Address)
  1389. assert.Empty(t, updatedUser.ICQInfo.Basic.City)
  1390. assert.Empty(t, updatedUser.ICQInfo.Basic.Fax)
  1391. assert.Empty(t, updatedUser.ICQInfo.Basic.Phone)
  1392. assert.Empty(t, updatedUser.ICQInfo.Basic.State)
  1393. assert.Empty(t, updatedUser.ICQInfo.Basic.LastName)
  1394. assert.Empty(t, updatedUser.ICQInfo.Basic.Nickname)
  1395. assert.Empty(t, updatedUser.ICQInfo.Basic.PublishEmail)
  1396. assert.Empty(t, updatedUser.ICQInfo.Basic.ZIPCode)
  1397. })
  1398. }
  1399. func TestSQLiteUserStore_FindByICQInterests(t *testing.T) {
  1400. // Cleanup after test
  1401. defer func() {
  1402. assert.NoError(t, os.Remove(testFile))
  1403. }()
  1404. // Initialize the SQLiteUserStore with a test database file
  1405. f, err := NewSQLiteUserStore(testFile)
  1406. assert.NoError(t, err)
  1407. // Create and set up test users with different interests
  1408. user1 := User{
  1409. IdentScreenName: NewIdentScreenName("user1"),
  1410. }
  1411. err = f.InsertUser(context.Background(), user1)
  1412. assert.NoError(t, err)
  1413. interests1 := ICQInterests{
  1414. Code1: 1,
  1415. Keyword1: "Coding",
  1416. Code2: 2,
  1417. Keyword2: "Music",
  1418. }
  1419. err = f.SetInterests(context.Background(), user1.IdentScreenName, interests1)
  1420. assert.NoError(t, err)
  1421. user2 := User{
  1422. IdentScreenName: NewIdentScreenName("user2"),
  1423. }
  1424. err = f.InsertUser(context.Background(), user2)
  1425. assert.NoError(t, err)
  1426. interests2 := ICQInterests{
  1427. Code1: 1,
  1428. Keyword1: "Coding",
  1429. Code3: 3,
  1430. Keyword3: "Gaming",
  1431. }
  1432. err = f.SetInterests(context.Background(), user2.IdentScreenName, interests2)
  1433. assert.NoError(t, err)
  1434. user3 := User{
  1435. IdentScreenName: NewIdentScreenName("user3"),
  1436. }
  1437. err = f.InsertUser(context.Background(), user3)
  1438. assert.NoError(t, err)
  1439. interests3 := ICQInterests{
  1440. Code2: 2,
  1441. Keyword2: "Music",
  1442. Code4: 4,
  1443. Keyword4: "Travel",
  1444. }
  1445. err = f.SetInterests(context.Background(), user3.IdentScreenName, interests3)
  1446. assert.NoError(t, err)
  1447. // Helper function to check if a user with a specific IdentScreenName exists in the results
  1448. containsUserWithScreenName := func(users []User, screenName IdentScreenName) bool {
  1449. for _, user := range users {
  1450. if user.IdentScreenName == screenName {
  1451. return true
  1452. }
  1453. }
  1454. return false
  1455. }
  1456. t.Run("Find Users by Single Keyword", func(t *testing.T) {
  1457. // Search for users interested in "Music"
  1458. users, err := f.FindByICQInterests(context.Background(), 2, []string{"Music"})
  1459. assert.NoError(t, err)
  1460. assert.Len(t, users, 2)
  1461. // Check that the correct users are returned by IdentScreenName
  1462. assert.True(t, containsUserWithScreenName(users, user1.IdentScreenName))
  1463. assert.True(t, containsUserWithScreenName(users, user3.IdentScreenName))
  1464. })
  1465. t.Run("Find Users by Multiple Keywords", func(t *testing.T) {
  1466. // Search for users interested in "Coding" or "Gaming"
  1467. users, err := f.FindByICQInterests(context.Background(), 1, []string{"Coding", "Gaming"})
  1468. assert.NoError(t, err)
  1469. assert.Len(t, users, 2)
  1470. // Check that the correct users are returned by IdentScreenName
  1471. assert.True(t, containsUserWithScreenName(users, user1.IdentScreenName))
  1472. assert.True(t, containsUserWithScreenName(users, user2.IdentScreenName))
  1473. })
  1474. t.Run("Find Users by Multiple Codes and Keywords", func(t *testing.T) {
  1475. // Search for users interested in "Coding"
  1476. users, err := f.FindByICQInterests(context.Background(), 1, []string{"Coding"})
  1477. assert.NoError(t, err)
  1478. assert.Len(t, users, 2)
  1479. assert.True(t, containsUserWithScreenName(users, user1.IdentScreenName))
  1480. assert.True(t, containsUserWithScreenName(users, user2.IdentScreenName))
  1481. // Search for users interested in "Travel"
  1482. users, err = f.FindByICQInterests(context.Background(), 4, []string{"Travel"})
  1483. assert.NoError(t, err)
  1484. assert.Len(t, users, 1)
  1485. assert.True(t, containsUserWithScreenName(users, user3.IdentScreenName))
  1486. })
  1487. t.Run("No Users Found", func(t *testing.T) {
  1488. // Search for users interested in a keyword that no user has
  1489. users, err := f.FindByICQInterests(context.Background(), 1, []string{"Status"})
  1490. assert.NoError(t, err)
  1491. assert.Empty(t, users)
  1492. })
  1493. }
  1494. func TestSQLiteUserStore_FindByICQKeyword(t *testing.T) {
  1495. // Cleanup after test
  1496. defer func() {
  1497. assert.NoError(t, os.Remove(testFile))
  1498. }()
  1499. // Initialize the SQLiteUserStore with a test database file
  1500. f, err := NewSQLiteUserStore(testFile)
  1501. assert.NoError(t, err)
  1502. // Create and set up test users with different interests
  1503. user1 := User{
  1504. IdentScreenName: NewIdentScreenName("user1"),
  1505. }
  1506. err = f.InsertUser(context.Background(), user1)
  1507. assert.NoError(t, err)
  1508. interests1 := ICQInterests{
  1509. Keyword1: "Coding",
  1510. Keyword2: "Music",
  1511. }
  1512. err = f.SetInterests(context.Background(), user1.IdentScreenName, interests1)
  1513. assert.NoError(t, err)
  1514. user2 := User{
  1515. IdentScreenName: NewIdentScreenName("user2"),
  1516. }
  1517. err = f.InsertUser(context.Background(), user2)
  1518. assert.NoError(t, err)
  1519. interests2 := ICQInterests{
  1520. Keyword1: "Coding",
  1521. Keyword3: "Gaming",
  1522. }
  1523. err = f.SetInterests(context.Background(), user2.IdentScreenName, interests2)
  1524. assert.NoError(t, err)
  1525. user3 := User{
  1526. IdentScreenName: NewIdentScreenName("user3"),
  1527. }
  1528. err = f.InsertUser(context.Background(), user3)
  1529. assert.NoError(t, err)
  1530. interests3 := ICQInterests{
  1531. Keyword3: "Music",
  1532. Keyword4: "Travel",
  1533. }
  1534. err = f.SetInterests(context.Background(), user3.IdentScreenName, interests3)
  1535. assert.NoError(t, err)
  1536. // Helper function to check if a user with a specific IdentScreenName exists in the results
  1537. containsUserWithScreenName := func(users []User, screenName IdentScreenName) bool {
  1538. for _, user := range users {
  1539. if user.IdentScreenName == screenName {
  1540. return true
  1541. }
  1542. }
  1543. return false
  1544. }
  1545. t.Run("Find Users by Keyword", func(t *testing.T) {
  1546. // Search for users interested in "Music"
  1547. users, err := f.FindByICQKeyword(context.Background(), "Music")
  1548. assert.NoError(t, err)
  1549. assert.Len(t, users, 2)
  1550. // Check that the correct users are returned by IdentScreenName
  1551. assert.True(t, containsUserWithScreenName(users, user1.IdentScreenName))
  1552. assert.True(t, containsUserWithScreenName(users, user3.IdentScreenName))
  1553. })
  1554. t.Run("No Users Found", func(t *testing.T) {
  1555. // Search for users interested in a keyword that no user has
  1556. users, err := f.FindByICQKeyword(context.Background(), "Knitting")
  1557. assert.NoError(t, err)
  1558. assert.Empty(t, users)
  1559. })
  1560. }
  1561. func TestSQLiteUserStore_FindByICQName(t *testing.T) {
  1562. // Cleanup after test
  1563. defer func() {
  1564. assert.NoError(t, os.Remove(testFile))
  1565. }()
  1566. // Initialize the SQLiteUserStore with a test database file
  1567. f, err := NewSQLiteUserStore(testFile)
  1568. assert.NoError(t, err)
  1569. // Create and set up test users with different details using SetBasicInfo
  1570. user1 := User{
  1571. IdentScreenName: NewIdentScreenName("user1"),
  1572. }
  1573. err = f.InsertUser(context.Background(), user1)
  1574. assert.NoError(t, err)
  1575. basicInfo1 := ICQBasicInfo{
  1576. FirstName: "John",
  1577. LastName: "Doe",
  1578. Nickname: "Johnny",
  1579. }
  1580. err = f.SetBasicInfo(context.Background(), user1.IdentScreenName, basicInfo1)
  1581. assert.NoError(t, err)
  1582. user2 := User{
  1583. IdentScreenName: NewIdentScreenName("user2"),
  1584. }
  1585. err = f.InsertUser(context.Background(), user2)
  1586. assert.NoError(t, err)
  1587. basicInfo2 := ICQBasicInfo{
  1588. FirstName: "Jane",
  1589. LastName: "Smith",
  1590. Nickname: "Janey",
  1591. }
  1592. err = f.SetBasicInfo(context.Background(), user2.IdentScreenName, basicInfo2)
  1593. assert.NoError(t, err)
  1594. user3 := User{
  1595. IdentScreenName: NewIdentScreenName("user3"),
  1596. }
  1597. err = f.InsertUser(context.Background(), user3)
  1598. assert.NoError(t, err)
  1599. basicInfo3 := ICQBasicInfo{
  1600. FirstName: "John",
  1601. LastName: "Smith",
  1602. Nickname: "JohnnyS",
  1603. }
  1604. err = f.SetBasicInfo(context.Background(), user3.IdentScreenName, basicInfo3)
  1605. assert.NoError(t, err)
  1606. // Helper function to check if a user with a specific IdentScreenName exists in the results
  1607. containsUserWithScreenName := func(users []User, screenName IdentScreenName) bool {
  1608. for _, user := range users {
  1609. if user.IdentScreenName == screenName {
  1610. return true
  1611. }
  1612. }
  1613. return false
  1614. }
  1615. t.Run("Find Users by First Cookie", func(t *testing.T) {
  1616. // Search for users with the first name "John"
  1617. users, err := f.FindByICQName(context.Background(), "John", "", "")
  1618. assert.NoError(t, err)
  1619. assert.Len(t, users, 2)
  1620. // Check that the correct users are returned by IdentScreenName
  1621. assert.True(t, containsUserWithScreenName(users, user1.IdentScreenName))
  1622. assert.True(t, containsUserWithScreenName(users, user3.IdentScreenName))
  1623. })
  1624. t.Run("Find Users by Last Cookie", func(t *testing.T) {
  1625. // Search for users with the last name "Smith"
  1626. users, err := f.FindByICQName(context.Background(), "", "Smith", "")
  1627. assert.NoError(t, err)
  1628. assert.Len(t, users, 2)
  1629. // Check that the correct users are returned by IdentScreenName
  1630. assert.True(t, containsUserWithScreenName(users, user2.IdentScreenName))
  1631. assert.True(t, containsUserWithScreenName(users, user3.IdentScreenName))
  1632. })
  1633. t.Run("Find Users by Nickname", func(t *testing.T) {
  1634. // Search for users with the nickname "Johnny"
  1635. users, err := f.FindByICQName(context.Background(), "", "", "Johnny")
  1636. assert.NoError(t, err)
  1637. assert.Len(t, users, 1)
  1638. // Check that the correct user is returned by IdentScreenName
  1639. assert.True(t, containsUserWithScreenName(users, user1.IdentScreenName))
  1640. })
  1641. t.Run("Find Users by Multiple Fields", func(t *testing.T) {
  1642. // Search for users with the first name "Jane" and last name "Smith"
  1643. users, err := f.FindByICQName(context.Background(), "Jane", "Smith", "")
  1644. assert.NoError(t, err)
  1645. assert.Len(t, users, 1)
  1646. // Check that the correct user is returned by IdentScreenName
  1647. assert.True(t, containsUserWithScreenName(users, user2.IdentScreenName))
  1648. })
  1649. t.Run("No Users Found", func(t *testing.T) {
  1650. // Search for users with a first name that no user has
  1651. users, err := f.FindByICQName(context.Background(), "NonExistent", "", "")
  1652. assert.NoError(t, err)
  1653. assert.Empty(t, users)
  1654. })
  1655. }
  1656. func TestSQLiteUserStore_FindByDirectoryInfo(t *testing.T) {
  1657. // Cleanup after test
  1658. defer func() {
  1659. assert.NoError(t, os.Remove(testFile))
  1660. }()
  1661. // Initialize the SQLiteUserStore with a test database file
  1662. f, err := NewSQLiteUserStore(testFile)
  1663. assert.NoError(t, err)
  1664. // Create and set up test users with different directory info
  1665. user1 := User{
  1666. IdentScreenName: NewIdentScreenName("user1"),
  1667. }
  1668. err = f.InsertUser(context.Background(), user1)
  1669. assert.NoError(t, err)
  1670. directoryInfo1 := AIMNameAndAddr{
  1671. FirstName: "John",
  1672. LastName: "Doe",
  1673. NickName: "Johnny",
  1674. City: "New York",
  1675. }
  1676. err = f.SetDirectoryInfo(context.Background(), user1.IdentScreenName, directoryInfo1)
  1677. assert.NoError(t, err)
  1678. user2 := User{
  1679. IdentScreenName: NewIdentScreenName("user2"),
  1680. }
  1681. err = f.InsertUser(context.Background(), user2)
  1682. assert.NoError(t, err)
  1683. directoryInfo2 := AIMNameAndAddr{
  1684. FirstName: "Jane",
  1685. LastName: "Smith",
  1686. NickName: "Janey",
  1687. Country: "USA",
  1688. }
  1689. err = f.SetDirectoryInfo(context.Background(), user2.IdentScreenName, directoryInfo2)
  1690. assert.NoError(t, err)
  1691. user3 := User{
  1692. IdentScreenName: NewIdentScreenName("user3"),
  1693. }
  1694. err = f.InsertUser(context.Background(), user3)
  1695. assert.NoError(t, err)
  1696. directoryInfo3 := AIMNameAndAddr{
  1697. FirstName: "John",
  1698. LastName: "Smith",
  1699. NickName: "JohnnyS",
  1700. State: "California",
  1701. }
  1702. err = f.SetDirectoryInfo(context.Background(), user3.IdentScreenName, directoryInfo3)
  1703. assert.NoError(t, err)
  1704. // Helper function to check if a user with a specific IdentScreenName exists in the results
  1705. containsUserWithScreenName := func(users []User, screenName IdentScreenName) bool {
  1706. for _, user := range users {
  1707. if user.IdentScreenName == screenName {
  1708. return true
  1709. }
  1710. }
  1711. return false
  1712. }
  1713. t.Run("Find Users by First Cookie", func(t *testing.T) {
  1714. // Search for users with the first name "John"
  1715. users, err := f.FindByAIMNameAndAddr(context.Background(), AIMNameAndAddr{FirstName: "John"})
  1716. assert.NoError(t, err)
  1717. assert.Len(t, users, 2)
  1718. // Check that the correct users are returned by IdentScreenName
  1719. assert.True(t, containsUserWithScreenName(users, user1.IdentScreenName))
  1720. assert.True(t, containsUserWithScreenName(users, user3.IdentScreenName))
  1721. })
  1722. t.Run("Find Users by Last Cookie", func(t *testing.T) {
  1723. // Search for users with the last name "Smith"
  1724. users, err := f.FindByAIMNameAndAddr(context.Background(), AIMNameAndAddr{LastName: "Smith"})
  1725. assert.NoError(t, err)
  1726. assert.Len(t, users, 2)
  1727. // Check that the correct users are returned by IdentScreenName
  1728. assert.True(t, containsUserWithScreenName(users, user2.IdentScreenName))
  1729. assert.True(t, containsUserWithScreenName(users, user3.IdentScreenName))
  1730. })
  1731. t.Run("Find Users by Nickname", func(t *testing.T) {
  1732. // Search for users with the nickname "Johnny"
  1733. users, err := f.FindByAIMNameAndAddr(context.Background(), AIMNameAndAddr{NickName: "Johnny"})
  1734. assert.NoError(t, err)
  1735. assert.Len(t, users, 1)
  1736. // Check that the correct user is returned by IdentScreenName
  1737. assert.True(t, containsUserWithScreenName(users, user1.IdentScreenName))
  1738. })
  1739. t.Run("Find Users by City", func(t *testing.T) {
  1740. // Search for users with the city "New York"
  1741. users, err := f.FindByAIMNameAndAddr(context.Background(), AIMNameAndAddr{City: "New York"})
  1742. assert.NoError(t, err)
  1743. assert.Len(t, users, 1)
  1744. // Check that the correct user is returned by IdentScreenName
  1745. assert.True(t, containsUserWithScreenName(users, user1.IdentScreenName))
  1746. })
  1747. t.Run("Find Users by Multiple Fields", func(t *testing.T) {
  1748. // Search for users with the first name "Jane" and country "USA"
  1749. users, err := f.FindByAIMNameAndAddr(context.Background(), AIMNameAndAddr{FirstName: "Jane", Country: "USA"})
  1750. assert.NoError(t, err)
  1751. assert.Len(t, users, 1)
  1752. // Check that the correct user is returned by IdentScreenName
  1753. assert.True(t, containsUserWithScreenName(users, user2.IdentScreenName))
  1754. })
  1755. t.Run("No Users Found", func(t *testing.T) {
  1756. // Search for users with a first name that no user has
  1757. users, err := f.FindByAIMNameAndAddr(context.Background(), AIMNameAndAddr{FirstName: "NonExistent"})
  1758. assert.NoError(t, err)
  1759. assert.Empty(t, users)
  1760. })
  1761. }
  1762. func TestSQLiteUserStore_SearchICQUsers(t *testing.T) {
  1763. newStore := func(t *testing.T) (*SQLiteUserStore, string) {
  1764. t.Helper()
  1765. dbFile := fmt.Sprintf("icq_search_test_%s.db", uuid.NewString())
  1766. f, err := NewSQLiteUserStore(dbFile)
  1767. require.NoError(t, err)
  1768. return f, dbFile
  1769. }
  1770. seedUsers := func(t *testing.T, f *SQLiteUserStore) (User, User) {
  1771. t.Helper()
  1772. user1 := User{
  1773. IdentScreenName: NewIdentScreenName("123456"),
  1774. IsICQ: true,
  1775. }
  1776. require.NoError(t, f.InsertUser(context.Background(), user1))
  1777. require.NoError(t, f.SetBasicInfo(context.Background(), user1.IdentScreenName, ICQBasicInfo{
  1778. FirstName: "Jane",
  1779. LastName: "Doe",
  1780. Nickname: "Janey",
  1781. City: "New York",
  1782. State: "NY",
  1783. EmailAddress: "jane@example.com",
  1784. CountryCode: 100,
  1785. }))
  1786. require.NoError(t, f.SetMoreInfo(context.Background(), user1.IdentScreenName, ICQMoreInfo{
  1787. BirthYear: 1985,
  1788. Gender: 2,
  1789. Lang1: 10,
  1790. }))
  1791. require.NoError(t, f.SetWorkInfo(context.Background(), user1.IdentScreenName, ICQWorkInfo{
  1792. Company: "Acme Corp",
  1793. Department: "Engineering",
  1794. Position: "Engineer",
  1795. OccupationCode: 500,
  1796. CountryCode: 300,
  1797. }))
  1798. require.NoError(t, f.SetInterests(context.Background(), user1.IdentScreenName, ICQInterests{
  1799. Code1: 1,
  1800. Keyword1: "Knitting",
  1801. }))
  1802. require.NoError(t, f.SetAffiliations(context.Background(), user1.IdentScreenName, ICQAffiliations{
  1803. CurrentCode1: 99,
  1804. CurrentKeyword1: "RoboticsTeam",
  1805. PastCode1: 100,
  1806. PastKeyword1: "GhostTeam",
  1807. }))
  1808. user2 := User{
  1809. IdentScreenName: NewIdentScreenName("234567"),
  1810. IsICQ: true,
  1811. }
  1812. require.NoError(t, f.InsertUser(context.Background(), user2))
  1813. require.NoError(t, f.SetBasicInfo(context.Background(), user2.IdentScreenName, ICQBasicInfo{
  1814. FirstName: "Alice",
  1815. LastName: "Smith",
  1816. Nickname: "Ally",
  1817. City: "Boston",
  1818. State: "MA",
  1819. EmailAddress: "alice@example.com",
  1820. CountryCode: 200,
  1821. }))
  1822. require.NoError(t, f.SetMoreInfo(context.Background(), user2.IdentScreenName, ICQMoreInfo{
  1823. BirthYear: 2005,
  1824. Gender: 1,
  1825. Lang1: 20,
  1826. }))
  1827. require.NoError(t, f.SetWorkInfo(context.Background(), user2.IdentScreenName, ICQWorkInfo{
  1828. Company: "Globex",
  1829. Position: "Manager",
  1830. OccupationCode: 600,
  1831. CountryCode: 400,
  1832. }))
  1833. require.NoError(t, f.SetInterests(context.Background(), user2.IdentScreenName, ICQInterests{
  1834. Code1: 1,
  1835. Keyword1: "Music",
  1836. }))
  1837. require.NoError(t, f.SetHomepageCategory(context.Background(), user2.IdentScreenName, ICQHomepageCategory{
  1838. Enabled: true,
  1839. Index: 42,
  1840. Description: "My photo blog about cats",
  1841. }))
  1842. return user1, user2
  1843. }
  1844. t.Run("Empty criteria", func(t *testing.T) {
  1845. defer func() { assert.NoError(t, os.Remove(testFile)) }()
  1846. f, err := NewSQLiteUserStore(testFile)
  1847. require.NoError(t, err)
  1848. _, searchErr := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{})
  1849. assert.ErrorIs(t, searchErr, ErrICQSearchEmptyCriteria)
  1850. })
  1851. t.Run("Search by nickname substring", func(t *testing.T) {
  1852. f, dbFile := newStore(t)
  1853. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  1854. user1, _ := seedUsers(t, f)
  1855. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  1856. NickName: new("ane"),
  1857. })
  1858. assert.NoError(t, err)
  1859. require.Len(t, users, 1)
  1860. assert.Equal(t, user1.IdentScreenName, users[0].IdentScreenName)
  1861. })
  1862. t.Run("Search by city+state", func(t *testing.T) {
  1863. f, dbFile := newStore(t)
  1864. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  1865. _, user2 := seedUsers(t, f)
  1866. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  1867. City: new("bost"),
  1868. State: new("MA"),
  1869. })
  1870. assert.NoError(t, err)
  1871. require.Len(t, users, 1)
  1872. assert.Equal(t, user2.IdentScreenName, users[0].IdentScreenName)
  1873. })
  1874. t.Run("Search by keyword", func(t *testing.T) {
  1875. f, dbFile := newStore(t)
  1876. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  1877. user1, _ := seedUsers(t, f)
  1878. kw := "knit"
  1879. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  1880. AnyKeyword: &kw,
  1881. })
  1882. assert.NoError(t, err)
  1883. require.Len(t, users, 1)
  1884. assert.Equal(t, user1.IdentScreenName, users[0].IdentScreenName)
  1885. })
  1886. t.Run("Search by interests node", func(t *testing.T) {
  1887. f, dbFile := newStore(t)
  1888. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  1889. _, user2 := seedUsers(t, f)
  1890. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  1891. InterestsCode: new(uint16(1)),
  1892. InterestsKeywords: []string{"Music"},
  1893. })
  1894. assert.NoError(t, err)
  1895. require.Len(t, users, 1)
  1896. assert.Equal(t, user2.IdentScreenName, users[0].IdentScreenName)
  1897. })
  1898. t.Run("Search by UIN", func(t *testing.T) {
  1899. f, dbFile := newStore(t)
  1900. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  1901. user1, _ := seedUsers(t, f)
  1902. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  1903. UIN: new(uint32(123456)),
  1904. })
  1905. assert.NoError(t, err)
  1906. require.Len(t, users, 1)
  1907. assert.Equal(t, user1.IdentScreenName, users[0].IdentScreenName)
  1908. })
  1909. t.Run("Search by first and last name", func(t *testing.T) {
  1910. f, dbFile := newStore(t)
  1911. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  1912. user1, _ := seedUsers(t, f)
  1913. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  1914. FirstName: new("jan"),
  1915. LastName: new("doe"),
  1916. })
  1917. assert.NoError(t, err)
  1918. require.Len(t, users, 1)
  1919. assert.Equal(t, user1.IdentScreenName, users[0].IdentScreenName)
  1920. })
  1921. t.Run("Search by email substring", func(t *testing.T) {
  1922. f, dbFile := newStore(t)
  1923. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  1924. _, user2 := seedUsers(t, f)
  1925. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  1926. Email: new("alice@"),
  1927. })
  1928. assert.NoError(t, err)
  1929. require.Len(t, users, 1)
  1930. assert.Equal(t, user2.IdentScreenName, users[0].IdentScreenName)
  1931. })
  1932. t.Run("Search by gender", func(t *testing.T) {
  1933. f, dbFile := newStore(t)
  1934. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  1935. _, user2 := seedUsers(t, f)
  1936. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  1937. Gender: new(uint8(1)),
  1938. })
  1939. assert.NoError(t, err)
  1940. require.Len(t, users, 1)
  1941. assert.Equal(t, user2.IdentScreenName, users[0].IdentScreenName)
  1942. })
  1943. t.Run("Search by spoken language", func(t *testing.T) {
  1944. f, dbFile := newStore(t)
  1945. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  1946. user1, _ := seedUsers(t, f)
  1947. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  1948. SpokenLanguage: new(uint8(10)),
  1949. })
  1950. assert.NoError(t, err)
  1951. require.Len(t, users, 1)
  1952. assert.Equal(t, user1.IdentScreenName, users[0].IdentScreenName)
  1953. })
  1954. t.Run("Search by minimum age", func(t *testing.T) {
  1955. f, dbFile := newStore(t)
  1956. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  1957. user1, _ := seedUsers(t, f)
  1958. min := uint16(35)
  1959. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  1960. MinAge: &min,
  1961. })
  1962. assert.NoError(t, err)
  1963. require.Len(t, users, 1)
  1964. assert.Equal(t, user1.IdentScreenName, users[0].IdentScreenName)
  1965. })
  1966. t.Run("Search by maximum age", func(t *testing.T) {
  1967. f, dbFile := newStore(t)
  1968. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  1969. _, user2 := seedUsers(t, f)
  1970. max := uint16(25)
  1971. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  1972. MaxAge: &max,
  1973. })
  1974. assert.NoError(t, err)
  1975. require.Len(t, users, 1)
  1976. assert.Equal(t, user2.IdentScreenName, users[0].IdentScreenName)
  1977. })
  1978. t.Run("Search by home country code", func(t *testing.T) {
  1979. f, dbFile := newStore(t)
  1980. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  1981. user1, _ := seedUsers(t, f)
  1982. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  1983. CountryCode: new(uint16(100)),
  1984. })
  1985. assert.NoError(t, err)
  1986. require.Len(t, users, 1)
  1987. assert.Equal(t, user1.IdentScreenName, users[0].IdentScreenName)
  1988. })
  1989. t.Run("Search by work country code", func(t *testing.T) {
  1990. f, dbFile := newStore(t)
  1991. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  1992. _, user2 := seedUsers(t, f)
  1993. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  1994. CountryCode: new(uint16(400)),
  1995. })
  1996. assert.NoError(t, err)
  1997. require.Len(t, users, 1)
  1998. assert.Equal(t, user2.IdentScreenName, users[0].IdentScreenName)
  1999. })
  2000. t.Run("Search by company", func(t *testing.T) {
  2001. f, dbFile := newStore(t)
  2002. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  2003. _, user2 := seedUsers(t, f)
  2004. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  2005. Company: new("Globex"),
  2006. })
  2007. assert.NoError(t, err)
  2008. require.Len(t, users, 1)
  2009. assert.Equal(t, user2.IdentScreenName, users[0].IdentScreenName)
  2010. })
  2011. t.Run("Search by department", func(t *testing.T) {
  2012. f, dbFile := newStore(t)
  2013. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  2014. user1, _ := seedUsers(t, f)
  2015. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  2016. DepartmentName: new("Engineering"),
  2017. })
  2018. assert.NoError(t, err)
  2019. require.Len(t, users, 1)
  2020. assert.Equal(t, user1.IdentScreenName, users[0].IdentScreenName)
  2021. })
  2022. t.Run("Search by position", func(t *testing.T) {
  2023. f, dbFile := newStore(t)
  2024. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  2025. user1, _ := seedUsers(t, f)
  2026. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  2027. Position: new("Engineer"),
  2028. })
  2029. assert.NoError(t, err)
  2030. require.Len(t, users, 1)
  2031. assert.Equal(t, user1.IdentScreenName, users[0].IdentScreenName)
  2032. })
  2033. t.Run("Search by occupation code", func(t *testing.T) {
  2034. f, dbFile := newStore(t)
  2035. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  2036. _, user2 := seedUsers(t, f)
  2037. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  2038. OccupationCode: new(uint16(600)),
  2039. })
  2040. assert.NoError(t, err)
  2041. require.Len(t, users, 1)
  2042. assert.Equal(t, user2.IdentScreenName, users[0].IdentScreenName)
  2043. })
  2044. t.Run("Search by affiliations node", func(t *testing.T) {
  2045. f, dbFile := newStore(t)
  2046. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  2047. user1, _ := seedUsers(t, f)
  2048. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  2049. AffiliationsCode: new(uint16(99)),
  2050. AffiliationsKeywords: []string{"Robot"},
  2051. })
  2052. assert.NoError(t, err)
  2053. require.Len(t, users, 1)
  2054. assert.Equal(t, user1.IdentScreenName, users[0].IdentScreenName)
  2055. })
  2056. t.Run("Search by past affiliations node", func(t *testing.T) {
  2057. f, dbFile := newStore(t)
  2058. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  2059. user1, _ := seedUsers(t, f)
  2060. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  2061. PastAffiliationsCode: new(uint16(100)),
  2062. PastAffiliationsKeywords: []string{"Ghost"},
  2063. })
  2064. assert.NoError(t, err)
  2065. require.Len(t, users, 1)
  2066. assert.Equal(t, user1.IdentScreenName, users[0].IdentScreenName)
  2067. })
  2068. t.Run("Search by homepage category index", func(t *testing.T) {
  2069. f, dbFile := newStore(t)
  2070. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  2071. _, user2 := seedUsers(t, f)
  2072. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  2073. HomePageCategoryIndex: new(uint16(42)),
  2074. })
  2075. assert.NoError(t, err)
  2076. require.Len(t, users, 1)
  2077. assert.Equal(t, user2.IdentScreenName, users[0].IdentScreenName)
  2078. })
  2079. t.Run("Search by homepage keywords", func(t *testing.T) {
  2080. f, dbFile := newStore(t)
  2081. defer func() { assert.NoError(t, os.Remove(dbFile)) }()
  2082. _, user2 := seedUsers(t, f)
  2083. users, err := f.SearchICQUsers(context.Background(), ICQUserSearchCriteria{
  2084. HomePageKeywords: []string{"cats"},
  2085. })
  2086. assert.NoError(t, err)
  2087. require.Len(t, users, 1)
  2088. assert.Equal(t, user2.IdentScreenName, users[0].IdentScreenName)
  2089. })
  2090. }
  2091. func TestSQLiteUserStore_FindByICQEmail(t *testing.T) {
  2092. // Cleanup after test
  2093. defer func() {
  2094. assert.NoError(t, os.Remove(testFile))
  2095. }()
  2096. // Initialize the SQLiteUserStore with a test database file
  2097. f, err := NewSQLiteUserStore(testFile)
  2098. assert.NoError(t, err)
  2099. // Create and set up test users with different email addresses using SetBasicInfo
  2100. user1 := User{
  2101. IdentScreenName: NewIdentScreenName("user1"),
  2102. }
  2103. err = f.InsertUser(context.Background(), user1)
  2104. assert.NoError(t, err)
  2105. basicInfo1 := ICQBasicInfo{
  2106. EmailAddress: "user1@example.com",
  2107. }
  2108. err = f.SetBasicInfo(context.Background(), user1.IdentScreenName, basicInfo1)
  2109. assert.NoError(t, err)
  2110. user2 := User{
  2111. IdentScreenName: NewIdentScreenName("user2"),
  2112. }
  2113. err = f.InsertUser(context.Background(), user2)
  2114. assert.NoError(t, err)
  2115. basicInfo2 := ICQBasicInfo{
  2116. EmailAddress: "user2@example.com",
  2117. }
  2118. err = f.SetBasicInfo(context.Background(), user2.IdentScreenName, basicInfo2)
  2119. assert.NoError(t, err)
  2120. user3 := User{
  2121. IdentScreenName: NewIdentScreenName("user3"),
  2122. }
  2123. err = f.InsertUser(context.Background(), user3)
  2124. assert.NoError(t, err)
  2125. basicInfo3 := ICQBasicInfo{
  2126. EmailAddress: "user3@example.com",
  2127. }
  2128. err = f.SetBasicInfo(context.Background(), user3.IdentScreenName, basicInfo3)
  2129. assert.NoError(t, err)
  2130. t.Run("Find User by Email", func(t *testing.T) {
  2131. // Search for user with email "user1@example.com"
  2132. user, err := f.FindByICQEmail(context.Background(), "user1@example.com")
  2133. assert.NoError(t, err)
  2134. assert.Equal(t, user1.IdentScreenName, user.IdentScreenName)
  2135. // Search for user with email "user2@example.com"
  2136. user, err = f.FindByICQEmail(context.Background(), "user2@example.com")
  2137. assert.NoError(t, err)
  2138. assert.Equal(t, user2.IdentScreenName, user.IdentScreenName)
  2139. // Search for user with email "user3@example.com"
  2140. user, err = f.FindByICQEmail(context.Background(), "user3@example.com")
  2141. assert.NoError(t, err)
  2142. assert.Equal(t, user3.IdentScreenName, user.IdentScreenName)
  2143. })
  2144. t.Run("User Not Found", func(t *testing.T) {
  2145. // Search for an email that doesn't exist
  2146. _, err := f.FindByICQEmail(context.Background(), "nonexistent@example.com")
  2147. assert.ErrorIs(t, err, ErrNoUser)
  2148. })
  2149. }
  2150. func TestSQLiteUserStore_FindByAIMEmail(t *testing.T) {
  2151. defer func() {
  2152. assert.NoError(t, os.Remove(testFile))
  2153. }()
  2154. f, err := NewSQLiteUserStore(testFile)
  2155. assert.NoError(t, err)
  2156. user1 := User{
  2157. IdentScreenName: NewIdentScreenName("user1"),
  2158. }
  2159. err = f.InsertUser(context.Background(), user1)
  2160. assert.NoError(t, err)
  2161. err = f.UpdateEmailAddress(context.Background(), user1.IdentScreenName, &mail.Address{Address: "user1@example.com"})
  2162. assert.NoError(t, err)
  2163. user2 := User{
  2164. IdentScreenName: NewIdentScreenName("user2"),
  2165. EmailAddress: "user2@example.com",
  2166. }
  2167. err = f.InsertUser(context.Background(), user2)
  2168. assert.NoError(t, err)
  2169. err = f.UpdateEmailAddress(context.Background(), user2.IdentScreenName, &mail.Address{Address: "user2@example.com"})
  2170. assert.NoError(t, err)
  2171. user3 := User{
  2172. IdentScreenName: NewIdentScreenName("user3"),
  2173. EmailAddress: "user3@example.com",
  2174. }
  2175. err = f.InsertUser(context.Background(), user3)
  2176. assert.NoError(t, err)
  2177. err = f.UpdateEmailAddress(context.Background(), user3.IdentScreenName, &mail.Address{Address: "user3@example.com"})
  2178. assert.NoError(t, err)
  2179. t.Run("Find User by Email", func(t *testing.T) {
  2180. // Search for user with email "user1@example.com"
  2181. user, err := f.FindByAIMEmail(context.Background(), "user1@example.com")
  2182. assert.NoError(t, err)
  2183. assert.Equal(t, user1.IdentScreenName, user.IdentScreenName)
  2184. // Search for user with email "user2@example.com"
  2185. user, err = f.FindByAIMEmail(context.Background(), "user2@example.com")
  2186. assert.NoError(t, err)
  2187. assert.Equal(t, user2.IdentScreenName, user.IdentScreenName)
  2188. // Search for user with email "user3@example.com"
  2189. user, err = f.FindByAIMEmail(context.Background(), "user3@example.com")
  2190. assert.NoError(t, err)
  2191. assert.Equal(t, user3.IdentScreenName, user.IdentScreenName)
  2192. })
  2193. t.Run("User Not Found", func(t *testing.T) {
  2194. // Search for an email that doesn't exist
  2195. _, err := f.FindByAIMEmail(context.Background(), "nonexistent@example.com")
  2196. assert.ErrorIs(t, err, ErrNoUser)
  2197. })
  2198. }
  2199. func TestSQLiteUserStore_FindByUIN(t *testing.T) {
  2200. // Cleanup after test
  2201. defer func() {
  2202. assert.NoError(t, os.Remove(testFile))
  2203. }()
  2204. // Initialize the SQLiteUserStore with a test database file
  2205. f, err := NewSQLiteUserStore(testFile)
  2206. assert.NoError(t, err)
  2207. // Create and set up test users where UIN is the same as IdentScreenName
  2208. user1 := User{
  2209. IdentScreenName: NewIdentScreenName("12345"),
  2210. }
  2211. err = f.InsertUser(context.Background(), user1)
  2212. assert.NoError(t, err)
  2213. user2 := User{
  2214. IdentScreenName: NewIdentScreenName("67890"),
  2215. }
  2216. err = f.InsertUser(context.Background(), user2)
  2217. assert.NoError(t, err)
  2218. user3 := User{
  2219. IdentScreenName: NewIdentScreenName("54321"),
  2220. }
  2221. err = f.InsertUser(context.Background(), user3)
  2222. assert.NoError(t, err)
  2223. t.Run("Find User by UIN", func(t *testing.T) {
  2224. // Search for user with UIN 12345
  2225. user, err := f.FindByUIN(context.Background(), 12345)
  2226. assert.NoError(t, err)
  2227. assert.Equal(t, user1.IdentScreenName, user.IdentScreenName)
  2228. // Search for user with UIN 67890
  2229. user, err = f.FindByUIN(context.Background(), 67890)
  2230. assert.NoError(t, err)
  2231. assert.Equal(t, user2.IdentScreenName, user.IdentScreenName)
  2232. // Search for user with UIN 54321
  2233. user, err = f.FindByUIN(context.Background(), 54321)
  2234. assert.NoError(t, err)
  2235. assert.Equal(t, user3.IdentScreenName, user.IdentScreenName)
  2236. })
  2237. t.Run("User Not Found", func(t *testing.T) {
  2238. // Search for a UIN that doesn't exist
  2239. _, err := f.FindByUIN(context.Background(), 99999)
  2240. assert.ErrorIs(t, err, ErrNoUser)
  2241. })
  2242. }
  2243. func TestSQLiteUserStore_RetrieveMessages(t *testing.T) {
  2244. defer func() {
  2245. assert.NoError(t, os.Remove(testFile))
  2246. }()
  2247. f, err := NewSQLiteUserStore(testFile)
  2248. assert.NoError(t, err)
  2249. createStubUser := func(t *testing.T, store SQLiteUserStore, screenName DisplayScreenName) {
  2250. t.Helper()
  2251. user := User{
  2252. IdentScreenName: NewIdentScreenName(string(screenName)),
  2253. DisplayScreenName: screenName,
  2254. AuthKey: uuid.New().String(),
  2255. IsICQ: screenName.IsUIN(),
  2256. }
  2257. require.NoError(t, user.HashPassword("welcome1"))
  2258. require.NoError(t, store.InsertUser(context.Background(), user))
  2259. }
  2260. createStubUser(t, *f, DisplayScreenName("John"))
  2261. createStubUser(t, *f, DisplayScreenName("Jack"))
  2262. createStubUser(t, *f, DisplayScreenName("Anne"))
  2263. sendTime := time.Now().UTC()
  2264. offlineMessages := []OfflineMessage{
  2265. {
  2266. Sender: NewIdentScreenName("John"),
  2267. Recipient: NewIdentScreenName("Jack"),
  2268. Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  2269. Cookie: 1,
  2270. },
  2271. Sent: sendTime,
  2272. },
  2273. {
  2274. Sender: NewIdentScreenName("John"),
  2275. Recipient: NewIdentScreenName("Anne"),
  2276. Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  2277. Cookie: 2,
  2278. },
  2279. Sent: sendTime,
  2280. },
  2281. {
  2282. Sender: NewIdentScreenName("John"),
  2283. Recipient: NewIdentScreenName("Jack"),
  2284. Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  2285. Cookie: 3,
  2286. },
  2287. Sent: sendTime,
  2288. },
  2289. }
  2290. expectedCounts := []int{1, 1, 2}
  2291. for i, msg := range offlineMessages {
  2292. count, err := f.SaveMessage(context.Background(), msg)
  2293. assert.NoError(t, err)
  2294. assert.Equal(t, expectedCounts[i], count)
  2295. // Verify offlineMsgCount is updated in the database
  2296. recipient, err := f.User(context.Background(), msg.Recipient)
  2297. assert.NoError(t, err)
  2298. assert.NotNil(t, recipient)
  2299. assert.Equal(t, expectedCounts[i], recipient.OfflineMsgCount)
  2300. }
  2301. t.Run("Retrieve Messages", func(t *testing.T) {
  2302. messages, err := f.RetrieveMessages(context.Background(), NewIdentScreenName("Jack"))
  2303. assert.NoError(t, err)
  2304. if assert.Len(t, messages, 2) {
  2305. assert.Equal(t, offlineMessages[0], messages[0])
  2306. assert.Equal(t, offlineMessages[2], messages[1])
  2307. }
  2308. })
  2309. t.Run("Retrieve No Messages", func(t *testing.T) {
  2310. messages, err := f.RetrieveMessages(context.Background(), NewIdentScreenName("Franke"))
  2311. assert.NoError(t, err)
  2312. assert.Empty(t, messages)
  2313. })
  2314. }
  2315. func TestSQLiteUserStore_DeleteMessages(t *testing.T) {
  2316. defer func() {
  2317. assert.NoError(t, os.Remove(testFile))
  2318. }()
  2319. f, err := NewSQLiteUserStore(testFile)
  2320. assert.NoError(t, err)
  2321. createStubUser := func(t *testing.T, store SQLiteUserStore, screenName DisplayScreenName) {
  2322. t.Helper()
  2323. user := User{
  2324. IdentScreenName: NewIdentScreenName(string(screenName)),
  2325. DisplayScreenName: screenName,
  2326. AuthKey: uuid.New().String(),
  2327. IsICQ: screenName.IsUIN(),
  2328. }
  2329. require.NoError(t, user.HashPassword("welcome1"))
  2330. require.NoError(t, store.InsertUser(context.Background(), user))
  2331. }
  2332. createStubUser(t, *f, DisplayScreenName("John"))
  2333. createStubUser(t, *f, DisplayScreenName("Jack"))
  2334. createStubUser(t, *f, DisplayScreenName("Anne"))
  2335. sendTime := time.Now().UTC()
  2336. offlineMessages := []OfflineMessage{
  2337. {
  2338. Sender: NewIdentScreenName("John"),
  2339. Recipient: NewIdentScreenName("Jack"),
  2340. Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  2341. Cookie: 1,
  2342. },
  2343. Sent: sendTime,
  2344. },
  2345. {
  2346. Sender: NewIdentScreenName("John"),
  2347. Recipient: NewIdentScreenName("Anne"),
  2348. Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  2349. Cookie: 2,
  2350. },
  2351. Sent: sendTime,
  2352. },
  2353. {
  2354. Sender: NewIdentScreenName("John"),
  2355. Recipient: NewIdentScreenName("Jack"),
  2356. Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  2357. Cookie: 3,
  2358. },
  2359. Sent: sendTime,
  2360. },
  2361. }
  2362. expectedCounts := []int{1, 1, 2}
  2363. for i, msg := range offlineMessages {
  2364. count, err := f.SaveMessage(context.Background(), msg)
  2365. assert.NoError(t, err)
  2366. assert.Equal(t, expectedCounts[i], count)
  2367. // Verify offlineMsgCount is updated in the database
  2368. recipient, err := f.User(context.Background(), msg.Recipient)
  2369. assert.NoError(t, err)
  2370. assert.NotNil(t, recipient)
  2371. assert.Equal(t, expectedCounts[i], recipient.OfflineMsgCount)
  2372. }
  2373. t.Run("Delete Messages", func(t *testing.T) {
  2374. err := f.DeleteMessages(context.Background(), NewIdentScreenName("Jack"))
  2375. assert.NoError(t, err)
  2376. messages, err := f.RetrieveMessages(context.Background(), NewIdentScreenName("Jack"))
  2377. assert.NoError(t, err)
  2378. assert.Empty(t, messages)
  2379. messages, err = f.RetrieveMessages(context.Background(), NewIdentScreenName("Anne"))
  2380. assert.NoError(t, err)
  2381. assert.Len(t, messages, 1)
  2382. })
  2383. t.Run("Delete No Messages", func(t *testing.T) {
  2384. err := f.DeleteMessages(context.Background(), NewIdentScreenName("Franke"))
  2385. assert.NoError(t, err)
  2386. messages, err := f.RetrieveMessages(context.Background(), NewIdentScreenName("Anne"))
  2387. assert.NoError(t, err)
  2388. assert.Len(t, messages, 1)
  2389. })
  2390. }
  2391. func TestSQLiteUserStore_SaveMessage(t *testing.T) {
  2392. defer func() {
  2393. assert.NoError(t, os.Remove(testFile))
  2394. }()
  2395. store, err := NewSQLiteUserStore(testFile)
  2396. require.NoError(t, err)
  2397. createStubUser := func(t *testing.T, store SQLiteUserStore, screenName DisplayScreenName) {
  2398. t.Helper()
  2399. user := User{
  2400. IdentScreenName: NewIdentScreenName(string(screenName)),
  2401. DisplayScreenName: screenName,
  2402. AuthKey: uuid.New().String(),
  2403. IsICQ: screenName.IsUIN(),
  2404. }
  2405. require.NoError(t, user.HashPassword("welcome1"))
  2406. require.NoError(t, store.InsertUser(context.Background(), user))
  2407. }
  2408. createStubUser(t, *store, DisplayScreenName("Sender"))
  2409. createStubUser(t, *store, DisplayScreenName("Recipient"))
  2410. msg := OfflineMessage{
  2411. Sender: NewIdentScreenName("Sender"),
  2412. Recipient: NewIdentScreenName("Recipient"),
  2413. Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
  2414. Cookie: 42,
  2415. },
  2416. Sent: time.Now().UTC(),
  2417. }
  2418. t.Run("within limit", func(t *testing.T) {
  2419. for i := 1; i <= offlineInboxLimit; i++ {
  2420. count, err := store.SaveMessage(context.Background(), msg)
  2421. require.NoError(t, err)
  2422. require.Equal(t, i, count)
  2423. // Verify offlineMsgCount is updated in the database
  2424. recipient, err := store.User(context.Background(), msg.Recipient)
  2425. require.NoError(t, err)
  2426. require.NotNil(t, recipient)
  2427. require.Equal(t, i, recipient.OfflineMsgCount)
  2428. }
  2429. })
  2430. t.Run("limit exceeded", func(t *testing.T) {
  2431. _, err := store.SaveMessage(context.Background(), msg)
  2432. require.ErrorIs(t, err, ErrOfflineInboxFull)
  2433. })
  2434. t.Run("missing sender", func(t *testing.T) {
  2435. missingSenderMsg := OfflineMessage{
  2436. Sender: NewIdentScreenName("UnknownSender"),
  2437. Recipient: NewIdentScreenName("Recipient"),
  2438. Message: msg.Message,
  2439. Sent: time.Now().UTC(),
  2440. }
  2441. _, err := store.SaveMessage(context.Background(), missingSenderMsg)
  2442. require.ErrorIs(t, err, ErrNoUser)
  2443. })
  2444. t.Run("missing recipient", func(t *testing.T) {
  2445. missingRecipientMsg := OfflineMessage{
  2446. Sender: NewIdentScreenName("Sender"),
  2447. Recipient: NewIdentScreenName("UnknownRecipient"),
  2448. Message: msg.Message,
  2449. Sent: time.Now().UTC(),
  2450. }
  2451. _, err := store.SaveMessage(context.Background(), missingRecipientMsg)
  2452. require.ErrorIs(t, err, ErrNoUser)
  2453. })
  2454. }
  2455. func TestSQLiteUserStore_BuddyIconMetadataExistingRef(t *testing.T) {
  2456. defer func() {
  2457. assert.NoError(t, os.Remove(testFile))
  2458. }()
  2459. screenName := NewIdentScreenName("TalkingTyler")
  2460. testHash := []byte{'t', 'h', 'e', 'h', 'a', 's', 'h'}
  2461. feedbagStore, err := NewSQLiteUserStore(testFile)
  2462. assert.NoError(t, err)
  2463. itemsIn := []wire.FeedbagItem{
  2464. {
  2465. Name: "1",
  2466. ClassID: wire.FeedbagClassIdBart,
  2467. TLVLBlock: wire.TLVLBlock{
  2468. TLVList: wire.TLVList{
  2469. wire.NewTLVBE(wire.FeedbagAttributesBartInfo, wire.BARTInfo{
  2470. Hash: testHash,
  2471. }),
  2472. },
  2473. },
  2474. },
  2475. }
  2476. insertTestUsers(t, feedbagStore, screenName)
  2477. if err := feedbagStore.FeedbagUpsert(context.Background(), screenName, itemsIn); err != nil {
  2478. t.Fatalf("failed to upsert: %s", err.Error())
  2479. }
  2480. b, err := feedbagStore.BuddyIconMetadata(context.Background(), screenName)
  2481. assert.NoError(t, err)
  2482. if !reflect.DeepEqual(b.Hash, testHash) {
  2483. t.Fatalf("expected hash did not match")
  2484. }
  2485. }
  2486. func TestSQLiteUserStore_BuddyIconMetadataMissingRef(t *testing.T) {
  2487. defer func() {
  2488. assert.NoError(t, os.Remove(testFile))
  2489. }()
  2490. existingScreenName := NewIdentScreenName("TalkingTyler")
  2491. queryScreenName := NewIdentScreenName("SingingSuzy")
  2492. testHash := []byte{'t', 'h', 'e', 'h', 'a', 's', 'h'}
  2493. feedbagStore, err := NewSQLiteUserStore(testFile)
  2494. assert.NoError(t, err)
  2495. itemsIn := []wire.FeedbagItem{
  2496. {
  2497. Name: "1",
  2498. ClassID: wire.FeedbagClassIdBart,
  2499. TLVLBlock: wire.TLVLBlock{
  2500. TLVList: wire.TLVList{
  2501. wire.NewTLVBE(wire.FeedbagAttributesBartInfo, wire.BARTInfo{
  2502. Hash: testHash,
  2503. }),
  2504. },
  2505. },
  2506. },
  2507. }
  2508. insertTestUsers(t, feedbagStore, existingScreenName)
  2509. if err := feedbagStore.FeedbagUpsert(context.Background(), existingScreenName, itemsIn); err != nil {
  2510. t.Fatalf("failed to upsert: %s", err.Error())
  2511. }
  2512. b, err := feedbagStore.BuddyIconMetadata(context.Background(), queryScreenName)
  2513. assert.NoError(t, err)
  2514. if b != nil {
  2515. t.Fatalf("empty BARTID expected")
  2516. }
  2517. }
  2518. func TestSQLiteUserStore_SetDirectoryInfo(t *testing.T) {
  2519. defer func() {
  2520. assert.NoError(t, os.Remove(testFile))
  2521. }()
  2522. f, err := NewSQLiteUserStore(testFile)
  2523. assert.NoError(t, err)
  2524. screenName := NewIdentScreenName("testuser")
  2525. user := User{
  2526. IdentScreenName: screenName,
  2527. }
  2528. err = f.InsertUser(context.Background(), user)
  2529. assert.NoError(t, err)
  2530. directoryInfo := AIMNameAndAddr{
  2531. FirstName: "John",
  2532. LastName: "Doe",
  2533. MiddleName: "Michael",
  2534. MaidenName: "Smith",
  2535. Country: "USA",
  2536. State: "CA",
  2537. City: "San Francisco",
  2538. NickName: "Johnny",
  2539. ZIPCode: "94105",
  2540. Address: "123 Main St",
  2541. }
  2542. t.Run("Successful Update", func(t *testing.T) {
  2543. err := f.SetDirectoryInfo(context.Background(), screenName, directoryInfo)
  2544. assert.NoError(t, err)
  2545. updatedUser, err := f.User(context.Background(), screenName)
  2546. assert.NoError(t, err)
  2547. assert.Equal(t, directoryInfo.FirstName, updatedUser.AIMDirectoryInfo.FirstName)
  2548. assert.Equal(t, directoryInfo.LastName, updatedUser.AIMDirectoryInfo.LastName)
  2549. assert.Equal(t, directoryInfo.MiddleName, updatedUser.AIMDirectoryInfo.MiddleName)
  2550. assert.Equal(t, directoryInfo.MaidenName, updatedUser.AIMDirectoryInfo.MaidenName)
  2551. assert.Equal(t, directoryInfo.Country, updatedUser.AIMDirectoryInfo.Country)
  2552. assert.Equal(t, directoryInfo.State, updatedUser.AIMDirectoryInfo.State)
  2553. assert.Equal(t, directoryInfo.City, updatedUser.AIMDirectoryInfo.City)
  2554. assert.Equal(t, directoryInfo.NickName, updatedUser.AIMDirectoryInfo.NickName)
  2555. assert.Equal(t, directoryInfo.ZIPCode, updatedUser.AIMDirectoryInfo.ZIPCode)
  2556. assert.Equal(t, directoryInfo.Address, updatedUser.AIMDirectoryInfo.Address)
  2557. })
  2558. t.Run("Update Non-Existing User", func(t *testing.T) {
  2559. nonExistingScreenName := NewIdentScreenName("nonexistentuser")
  2560. err := f.SetDirectoryInfo(context.Background(), nonExistingScreenName, directoryInfo)
  2561. assert.ErrorIs(t, err, ErrNoUser)
  2562. })
  2563. t.Run("Empty Directory Info", func(t *testing.T) {
  2564. emptyDirectoryInfo := AIMNameAndAddr{}
  2565. err := f.SetDirectoryInfo(context.Background(), screenName, emptyDirectoryInfo)
  2566. assert.NoError(t, err)
  2567. updatedUser, err := f.User(context.Background(), screenName)
  2568. assert.NoError(t, err)
  2569. assert.Empty(t, updatedUser.AIMDirectoryInfo.FirstName)
  2570. assert.Empty(t, updatedUser.AIMDirectoryInfo.LastName)
  2571. assert.Empty(t, updatedUser.AIMDirectoryInfo.MiddleName)
  2572. assert.Empty(t, updatedUser.AIMDirectoryInfo.MaidenName)
  2573. assert.Empty(t, updatedUser.AIMDirectoryInfo.Country)
  2574. assert.Empty(t, updatedUser.AIMDirectoryInfo.State)
  2575. assert.Empty(t, updatedUser.AIMDirectoryInfo.City)
  2576. assert.Empty(t, updatedUser.AIMDirectoryInfo.NickName)
  2577. assert.Empty(t, updatedUser.AIMDirectoryInfo.ZIPCode)
  2578. assert.Empty(t, updatedUser.AIMDirectoryInfo.Address)
  2579. })
  2580. }
  2581. func TestSQLiteUserStore_Categories(t *testing.T) {
  2582. t.Run("Retrieve Keyword Categories Successfully", func(t *testing.T) {
  2583. defer func() {
  2584. assert.NoError(t, os.Remove(testFile))
  2585. }()
  2586. f, err := NewSQLiteUserStore(testFile)
  2587. assert.NoError(t, err)
  2588. // Insert some test keyword categories
  2589. categories := []string{"Category3", "Category1", "Category2"}
  2590. for _, categoryName := range categories {
  2591. _, err := f.CreateCategory(context.Background(), categoryName)
  2592. assert.NoError(t, err)
  2593. }
  2594. retrievedCategories, err := f.Categories(context.Background())
  2595. assert.NoError(t, err)
  2596. // Make sure all categories are returned in alphabetical order
  2597. if assert.Len(t, retrievedCategories, len(categories)) {
  2598. expect := []Category{
  2599. {
  2600. ID: 2,
  2601. Name: "Category1",
  2602. },
  2603. {
  2604. ID: 3,
  2605. Name: "Category2",
  2606. },
  2607. {
  2608. ID: 1,
  2609. Name: "Category3",
  2610. },
  2611. }
  2612. assert.Equal(t, expect, retrievedCategories)
  2613. }
  2614. })
  2615. t.Run("No Categories Exist", func(t *testing.T) {
  2616. defer func() {
  2617. assert.NoError(t, os.Remove(testFile))
  2618. }()
  2619. f, err := NewSQLiteUserStore(testFile)
  2620. assert.NoError(t, err)
  2621. // Clean up the database
  2622. _, err = f.db.Exec(`DELETE FROM aimKeywordCategory`)
  2623. assert.NoError(t, err)
  2624. retrievedCategories, err := f.Categories(context.Background())
  2625. assert.NoError(t, err)
  2626. assert.Empty(t, retrievedCategories)
  2627. })
  2628. t.Run("SQL Error Handling", func(t *testing.T) {
  2629. defer func() {
  2630. assert.NoError(t, os.Remove(testFile))
  2631. }()
  2632. f, err := NewSQLiteUserStore(testFile)
  2633. assert.NoError(t, err)
  2634. // Force an error by querying a non-existent table
  2635. _, err = f.db.Exec(`DROP TABLE aimKeywordCategory`)
  2636. assert.NoError(t, err)
  2637. _, err = f.Categories(context.Background())
  2638. assert.Error(t, err)
  2639. })
  2640. t.Run("Unique Constraint Violation", func(t *testing.T) {
  2641. defer func() {
  2642. assert.NoError(t, os.Remove(testFile))
  2643. }()
  2644. f, err := NewSQLiteUserStore(testFile)
  2645. assert.NoError(t, err)
  2646. // Insert a category with a unique name
  2647. categoryName := "UniqueCategory"
  2648. _, err = f.CreateCategory(context.Background(), categoryName)
  2649. assert.NoError(t, err)
  2650. // Try to insert the same category name again to trigger the unique constraint
  2651. _, err = f.CreateCategory(context.Background(), categoryName)
  2652. assert.ErrorIs(t, err, ErrKeywordCategoryExists)
  2653. })
  2654. }
  2655. func TestSQLiteUserStore_CreateCategory(t *testing.T) {
  2656. t.Run("Successfully Create Keyword Category", func(t *testing.T) {
  2657. defer func() {
  2658. assert.NoError(t, os.Remove(testFile))
  2659. }()
  2660. f, err := NewSQLiteUserStore(testFile)
  2661. assert.NoError(t, err)
  2662. categoryName := "TestCategory"
  2663. keywordCategory, err := f.CreateCategory(context.Background(), categoryName)
  2664. assert.NoError(t, err)
  2665. assert.Equal(t, categoryName, keywordCategory.Name)
  2666. assert.NotZero(t, keywordCategory.ID)
  2667. categories, err := f.Categories(context.Background())
  2668. assert.NoError(t, err)
  2669. if assert.Len(t, categories, 1) {
  2670. assert.Equal(t, categoryName, categories[0].Name)
  2671. }
  2672. })
  2673. t.Run("Duplicate Category Cookie", func(t *testing.T) {
  2674. defer func() {
  2675. assert.NoError(t, os.Remove(testFile))
  2676. }()
  2677. f, err := NewSQLiteUserStore(testFile)
  2678. assert.NoError(t, err)
  2679. categoryName := "DuplicateCategory"
  2680. // Create the category
  2681. _, err = f.CreateCategory(context.Background(), categoryName)
  2682. assert.NoError(t, err)
  2683. // Try to create the same category again
  2684. _, err = f.CreateCategory(context.Background(), categoryName)
  2685. assert.ErrorIs(t, err, ErrKeywordCategoryExists)
  2686. })
  2687. t.Run("ID Overflow", func(t *testing.T) {
  2688. defer func() {
  2689. assert.NoError(t, os.Remove(testFile))
  2690. }()
  2691. f, err := NewSQLiteUserStore(testFile)
  2692. assert.NoError(t, err)
  2693. // Simulate ID overflow by inserting max number of entries
  2694. for i := range math.MaxUint8 {
  2695. _, err := f.CreateCategory(context.Background(), fmt.Sprintf("Category_%d", i))
  2696. assert.NoError(t, err)
  2697. }
  2698. // Next insert should cause an ID overflow
  2699. _, err = f.CreateCategory(context.Background(), "OverflowCategory")
  2700. assert.ErrorIs(t, err, errTooManyCategories)
  2701. })
  2702. t.Run("SQL Error Handling", func(t *testing.T) {
  2703. defer func() {
  2704. assert.NoError(t, os.Remove(testFile))
  2705. }()
  2706. f, err := NewSQLiteUserStore(testFile)
  2707. assert.NoError(t, err)
  2708. // Drop the table to cause an error
  2709. _, err = f.db.Exec(`DROP TABLE aimKeywordCategory`)
  2710. assert.NoError(t, err)
  2711. _, err = f.CreateCategory(context.Background(), "ShouldFail")
  2712. assert.Error(t, err)
  2713. })
  2714. }
  2715. func TestSQLiteUserStore_DeleteCategory(t *testing.T) {
  2716. t.Run("Successfully Delete Keyword Category", func(t *testing.T) {
  2717. f, err := NewSQLiteUserStore(testFile)
  2718. assert.NoError(t, err)
  2719. defer func() {
  2720. assert.NoError(t, os.Remove(testFile))
  2721. }()
  2722. // Insert a test category
  2723. categoryName := "CategoryToDelete"
  2724. category, err := f.CreateCategory(context.Background(), categoryName)
  2725. assert.NoError(t, err)
  2726. // Ensure the category was created
  2727. retrievedCategories, err := f.Categories(context.Background())
  2728. assert.NoError(t, err)
  2729. assert.Len(t, retrievedCategories, 1)
  2730. // Delete the category
  2731. err = f.DeleteCategory(context.Background(), category.ID)
  2732. assert.NoError(t, err)
  2733. // Verify the category was deleted
  2734. retrievedCategories, err = f.Categories(context.Background())
  2735. assert.NoError(t, err)
  2736. assert.Empty(t, retrievedCategories)
  2737. })
  2738. t.Run("Delete Non-Existent Category", func(t *testing.T) {
  2739. f, err := NewSQLiteUserStore(testFile)
  2740. assert.NoError(t, err)
  2741. defer func() {
  2742. assert.NoError(t, os.Remove(testFile))
  2743. }()
  2744. // Attempt to delete a category that does not exist
  2745. nonExistentCategoryID := uint8(99)
  2746. err = f.DeleteCategory(context.Background(), nonExistentCategoryID)
  2747. assert.ErrorIs(t, err, ErrKeywordCategoryNotFound)
  2748. })
  2749. t.Run("Delete category and all of its keywords", func(t *testing.T) {
  2750. f, err := NewSQLiteUserStore(testFile)
  2751. assert.NoError(t, err)
  2752. defer func() {
  2753. assert.NoError(t, os.Remove(testFile))
  2754. }()
  2755. // Insert a category
  2756. categoryName := "CategoryInUse"
  2757. category, err := f.CreateCategory(context.Background(), categoryName)
  2758. assert.NoError(t, err)
  2759. // Insert a keyword that references this category
  2760. keywordName := "KeywordInUse"
  2761. _, err = f.CreateKeyword(context.Background(), keywordName, category.ID)
  2762. assert.NoError(t, err)
  2763. // Create a user and associate it with the keyword
  2764. u := User{
  2765. IdentScreenName: NewIdentScreenName("testuser"),
  2766. }
  2767. err = f.InsertUser(context.Background(), u)
  2768. assert.NoError(t, err)
  2769. err = f.SetKeywords(context.Background(), u.IdentScreenName, [5]string{keywordName})
  2770. assert.NoError(t, err)
  2771. // Attempt to delete the category that is in use by the keyword
  2772. err = f.DeleteCategory(context.Background(), category.ID)
  2773. assert.ErrorIs(t, err, ErrKeywordInUse)
  2774. })
  2775. }
  2776. func TestSQLiteUserStore_CreateKeyword(t *testing.T) {
  2777. t.Run("Successfully Create Keyword", func(t *testing.T) {
  2778. defer func() {
  2779. assert.NoError(t, os.Remove(testFile))
  2780. }()
  2781. f, err := NewSQLiteUserStore(testFile)
  2782. assert.NoError(t, err)
  2783. // Create a test category
  2784. categoryName := "TestCategory"
  2785. category, err := f.CreateCategory(context.Background(), categoryName)
  2786. assert.NoError(t, err)
  2787. // Insert a keyword for the category
  2788. keywordName := "TestKeyword"
  2789. keyword, err := f.CreateKeyword(context.Background(), keywordName, category.ID)
  2790. assert.NoError(t, err)
  2791. assert.Equal(t, keywordName, keyword.Name)
  2792. assert.NotZero(t, keyword.ID)
  2793. // Verify the keyword and category were inserted into the database
  2794. keywords, err := f.KeywordsByCategory(context.Background(), category.ID)
  2795. assert.NoError(t, err)
  2796. if assert.Len(t, keywords, 1) {
  2797. expect := []Keyword{
  2798. keyword,
  2799. }
  2800. assert.Equal(t, expect, keywords)
  2801. }
  2802. })
  2803. t.Run("Create Keyword Without Category", func(t *testing.T) {
  2804. defer func() {
  2805. assert.NoError(t, os.Remove(testFile))
  2806. }()
  2807. f, err := NewSQLiteUserStore(testFile)
  2808. assert.NoError(t, err)
  2809. // Insert a keyword with no category (parent is NULL)
  2810. keywordName := "UncategorizedKeyword"
  2811. keyword, err := f.CreateKeyword(context.Background(), keywordName, 0)
  2812. assert.NoError(t, err)
  2813. assert.Equal(t, keywordName, keyword.Name)
  2814. assert.NotZero(t, keyword.ID)
  2815. // Verify the keyword was inserted into the database
  2816. keywords, err := f.KeywordsByCategory(context.Background(), 0)
  2817. assert.NoError(t, err)
  2818. if assert.Len(t, keywords, 1) {
  2819. expect := []Keyword{
  2820. keyword,
  2821. }
  2822. assert.Equal(t, expect, keywords)
  2823. }
  2824. })
  2825. t.Run("Create Keyword With Unknown Category", func(t *testing.T) {
  2826. defer func() {
  2827. assert.NoError(t, os.Remove(testFile))
  2828. }()
  2829. f, err := NewSQLiteUserStore(testFile)
  2830. assert.NoError(t, err)
  2831. // Insert a keyword with no category (parent is NULL)
  2832. keywordName := "AKeyword"
  2833. _, err = f.CreateKeyword(context.Background(), keywordName, 1)
  2834. assert.ErrorIs(t, err, ErrKeywordCategoryNotFound)
  2835. })
  2836. t.Run("Duplicate Keyword Cookie", func(t *testing.T) {
  2837. defer func() {
  2838. assert.NoError(t, os.Remove(testFile))
  2839. }()
  2840. f, err := NewSQLiteUserStore(testFile)
  2841. assert.NoError(t, err)
  2842. keywordName := "DuplicateKeyword"
  2843. // Create the keyword
  2844. _, err = f.CreateKeyword(context.Background(), keywordName, 0)
  2845. assert.NoError(t, err)
  2846. // Try to create the same keyword again
  2847. _, err = f.CreateKeyword(context.Background(), keywordName, 0)
  2848. assert.ErrorIs(t, err, ErrKeywordExists)
  2849. })
  2850. t.Run("ID Overflow", func(t *testing.T) {
  2851. defer func() {
  2852. assert.NoError(t, os.Remove(testFile))
  2853. }()
  2854. f, err := NewSQLiteUserStore(testFile)
  2855. assert.NoError(t, err)
  2856. // Create a test category
  2857. categoryName := "OverflowCategory"
  2858. category, err := f.CreateCategory(context.Background(), categoryName)
  2859. assert.NoError(t, err)
  2860. // Simulate ID overflow by inserting max number of entries
  2861. for i := 0; i < math.MaxUint8; i++ {
  2862. _, err := f.CreateKeyword(context.Background(), fmt.Sprintf("Keyword_%d", i), category.ID)
  2863. assert.NoError(t, err)
  2864. }
  2865. // Next insert should cause an ID overflow
  2866. _, err = f.CreateKeyword(context.Background(), "OverflowKeyword", category.ID)
  2867. assert.ErrorIs(t, err, errTooManyKeywords)
  2868. })
  2869. t.Run("SQL Error Handling", func(t *testing.T) {
  2870. defer func() {
  2871. assert.NoError(t, os.Remove(testFile))
  2872. }()
  2873. f, err := NewSQLiteUserStore(testFile)
  2874. assert.NoError(t, err)
  2875. // Drop the table to cause an error
  2876. _, err = f.db.Exec(`DROP TABLE aimKeyword`)
  2877. assert.NoError(t, err)
  2878. _, err = f.CreateKeyword(context.Background(), "ShouldFail", 0)
  2879. assert.Error(t, err)
  2880. })
  2881. }
  2882. func TestSQLiteUserStore_DeleteKeyword(t *testing.T) {
  2883. t.Run("Successfully Delete Keyword", func(t *testing.T) {
  2884. f, err := NewSQLiteUserStore(testFile)
  2885. assert.NoError(t, err)
  2886. defer func() {
  2887. assert.NoError(t, os.Remove(testFile))
  2888. }()
  2889. // Insert a category
  2890. categoryName := "TestCategory"
  2891. category, err := f.CreateCategory(context.Background(), categoryName)
  2892. assert.NoError(t, err)
  2893. // Insert a keyword for the category
  2894. keywordName := "TestKeyword"
  2895. keyword, err := f.CreateKeyword(context.Background(), keywordName, category.ID)
  2896. assert.NoError(t, err)
  2897. // Ensure the keyword was created
  2898. retrievedKeywords, err := f.KeywordsByCategory(context.Background(), category.ID)
  2899. assert.NoError(t, err)
  2900. assert.Len(t, retrievedKeywords, 1)
  2901. // Delete the keyword
  2902. err = f.DeleteKeyword(context.Background(), keyword.ID)
  2903. assert.NoError(t, err)
  2904. // Verify the keyword was deleted
  2905. retrievedKeywords, err = f.KeywordsByCategory(context.Background(), category.ID)
  2906. assert.NoError(t, err)
  2907. assert.Empty(t, retrievedKeywords)
  2908. })
  2909. t.Run("Delete Non-Existent Keyword", func(t *testing.T) {
  2910. f, err := NewSQLiteUserStore(testFile)
  2911. assert.NoError(t, err)
  2912. defer func() {
  2913. assert.NoError(t, os.Remove(testFile))
  2914. }()
  2915. // Attempt to delete a keyword that does not exist
  2916. nonExistentKeywordID := uint8(99)
  2917. err = f.DeleteKeyword(context.Background(), nonExistentKeywordID)
  2918. assert.ErrorIs(t, err, ErrKeywordNotFound)
  2919. })
  2920. t.Run("Delete Keyword Associated with User", func(t *testing.T) {
  2921. f, err := NewSQLiteUserStore(testFile)
  2922. assert.NoError(t, err)
  2923. defer func() {
  2924. assert.NoError(t, os.Remove(testFile))
  2925. }()
  2926. // Insert a category
  2927. categoryName := "CategoryInUse"
  2928. category, err := f.CreateCategory(context.Background(), categoryName)
  2929. assert.NoError(t, err)
  2930. // Insert a keyword
  2931. keywordName := "KeywordInUse"
  2932. keyword, err := f.CreateKeyword(context.Background(), keywordName, category.ID)
  2933. assert.NoError(t, err)
  2934. // Create a user and associate it with the keyword
  2935. u := User{
  2936. IdentScreenName: NewIdentScreenName("testuser"),
  2937. }
  2938. err = f.InsertUser(context.Background(), u)
  2939. assert.NoError(t, err)
  2940. err = f.SetKeywords(context.Background(), u.IdentScreenName, [5]string{keywordName})
  2941. assert.NoError(t, err)
  2942. // Attempt to delete the keyword and expect an ErrKeywordInUse
  2943. err = f.DeleteKeyword(context.Background(), keyword.ID)
  2944. assert.ErrorIs(t, err, ErrKeywordInUse)
  2945. })
  2946. }
  2947. func TestSQLiteUserStore_InterestList(t *testing.T) {
  2948. t.Run("Full list", func(t *testing.T) {
  2949. f, err := NewSQLiteUserStore(testFile)
  2950. assert.NoError(t, err)
  2951. defer func() {
  2952. assert.NoError(t, os.Remove(testFile))
  2953. }()
  2954. tech, err := f.CreateCategory(context.Background(), "Technology")
  2955. assert.NoError(t, err)
  2956. music, err := f.CreateCategory(context.Background(), "Music")
  2957. assert.NoError(t, err)
  2958. sports, err := f.CreateCategory(context.Background(), "Sports")
  2959. assert.NoError(t, err)
  2960. _, err = f.CreateKeyword(context.Background(), "Rock", music.ID)
  2961. assert.NoError(t, err)
  2962. _, err = f.CreateKeyword(context.Background(), "Soccer", sports.ID)
  2963. assert.NoError(t, err)
  2964. _, err = f.CreateKeyword(context.Background(), "Cybersecurity", tech.ID)
  2965. assert.NoError(t, err)
  2966. _, err = f.CreateKeyword(context.Background(), "Zoology", 0)
  2967. assert.NoError(t, err)
  2968. _, err = f.CreateKeyword(context.Background(), "Jazz", music.ID)
  2969. assert.NoError(t, err)
  2970. _, err = f.CreateKeyword(context.Background(), "Animals", 0)
  2971. assert.NoError(t, err)
  2972. _, err = f.CreateKeyword(context.Background(), "Basketball", sports.ID)
  2973. assert.NoError(t, err)
  2974. _, err = f.CreateKeyword(context.Background(), "Artificial Intelligence", tech.ID)
  2975. assert.NoError(t, err)
  2976. _, err = f.CreateKeyword(context.Background(), "Tennis", sports.ID)
  2977. assert.NoError(t, err)
  2978. expect := []wire.ODirKeywordListItem{
  2979. {
  2980. ID: 0,
  2981. Name: "Animals",
  2982. Type: wire.ODirKeyword,
  2983. },
  2984. {
  2985. ID: 2,
  2986. Name: "Music",
  2987. Type: wire.ODirKeywordCategory,
  2988. },
  2989. {
  2990. ID: 2,
  2991. Name: "Jazz",
  2992. Type: wire.ODirKeyword,
  2993. },
  2994. {
  2995. ID: 2,
  2996. Name: "Rock",
  2997. Type: wire.ODirKeyword,
  2998. },
  2999. {
  3000. ID: 3,
  3001. Name: "Sports",
  3002. Type: wire.ODirKeywordCategory,
  3003. },
  3004. {
  3005. ID: 3,
  3006. Name: "Basketball",
  3007. Type: wire.ODirKeyword,
  3008. },
  3009. {
  3010. ID: 3,
  3011. Name: "Soccer",
  3012. Type: wire.ODirKeyword,
  3013. },
  3014. {
  3015. ID: 3,
  3016. Name: "Tennis",
  3017. Type: wire.ODirKeyword,
  3018. },
  3019. {
  3020. ID: 1,
  3021. Name: "Technology",
  3022. Type: wire.ODirKeywordCategory,
  3023. },
  3024. {
  3025. ID: 1,
  3026. Name: "Artificial Intelligence",
  3027. Type: wire.ODirKeyword,
  3028. },
  3029. {
  3030. ID: 1,
  3031. Name: "Cybersecurity",
  3032. Type: wire.ODirKeyword,
  3033. },
  3034. {
  3035. ID: 0,
  3036. Name: "Zoology",
  3037. Type: wire.ODirKeyword,
  3038. },
  3039. }
  3040. actual, err := f.InterestList(context.Background())
  3041. assert.NoError(t, err)
  3042. assert.Equal(t, expect, actual)
  3043. })
  3044. t.Run("Empty list list", func(t *testing.T) {
  3045. f, err := NewSQLiteUserStore(testFile)
  3046. assert.NoError(t, err)
  3047. defer func() {
  3048. assert.NoError(t, os.Remove(testFile))
  3049. }()
  3050. actual, err := f.InterestList(context.Background())
  3051. assert.NoError(t, err)
  3052. assert.Empty(t, actual)
  3053. })
  3054. }
  3055. func TestSQLiteUserStore_KeywordsByCategory(t *testing.T) {
  3056. t.Run("Category Does Not Exist", func(t *testing.T) {
  3057. defer func() {
  3058. assert.NoError(t, os.Remove(testFile))
  3059. }()
  3060. f, err := NewSQLiteUserStore(testFile)
  3061. assert.NoError(t, err)
  3062. // Create a test category
  3063. categoryName := "TestCategory"
  3064. category, err := f.CreateCategory(context.Background(), categoryName)
  3065. assert.NoError(t, err)
  3066. keywords, err := f.KeywordsByCategory(context.Background(), category.ID+1)
  3067. assert.Empty(t, keywords)
  3068. assert.ErrorIs(t, err, ErrKeywordCategoryNotFound)
  3069. })
  3070. }
  3071. func TestSQLiteUserStore_UnregisterBuddyList(t *testing.T) {
  3072. defer func() {
  3073. assert.NoError(t, os.Remove(testFile))
  3074. }()
  3075. f, err := NewSQLiteUserStore(testFile)
  3076. assert.NoError(t, err)
  3077. users := []IdentScreenName{
  3078. NewIdentScreenName("user1"),
  3079. NewIdentScreenName("user2"),
  3080. NewIdentScreenName("user3"),
  3081. }
  3082. for _, me := range users {
  3083. err = f.RegisterBuddyList(context.Background(), me)
  3084. assert.NoError(t, err)
  3085. for _, them := range users {
  3086. if me == them {
  3087. continue
  3088. }
  3089. err = f.AddBuddy(context.Background(), me, them)
  3090. assert.NoError(t, err)
  3091. }
  3092. }
  3093. relationships, err := f.AllRelationships(context.Background(), users[0], nil)
  3094. assert.NoError(t, err)
  3095. expect := []Relationship{
  3096. {
  3097. User: NewIdentScreenName("user2"),
  3098. IsOnTheirList: true,
  3099. IsOnYourList: true,
  3100. },
  3101. {
  3102. User: NewIdentScreenName("user3"),
  3103. IsOnTheirList: true,
  3104. IsOnYourList: true,
  3105. },
  3106. }
  3107. assert.ElementsMatch(t, relationships, expect)
  3108. err = f.UnregisterBuddyList(context.Background(), users[2])
  3109. assert.NoError(t, err)
  3110. relationships, err = f.AllRelationships(context.Background(), users[0], nil)
  3111. assert.NoError(t, err)
  3112. expect = []Relationship{
  3113. {
  3114. User: NewIdentScreenName("user2"),
  3115. IsOnTheirList: true,
  3116. IsOnYourList: true,
  3117. },
  3118. }
  3119. assert.ElementsMatch(t, relationships, expect)
  3120. }
  3121. func TestSQLiteUserStore_ClearBuddyListRegistry(t *testing.T) {
  3122. defer func() {
  3123. assert.NoError(t, os.Remove(testFile))
  3124. }()
  3125. f, err := NewSQLiteUserStore(testFile)
  3126. assert.NoError(t, err)
  3127. users := []IdentScreenName{
  3128. NewIdentScreenName("user1"),
  3129. NewIdentScreenName("user2"),
  3130. NewIdentScreenName("user3"),
  3131. }
  3132. for _, me := range users {
  3133. err = f.RegisterBuddyList(context.Background(), me)
  3134. assert.NoError(t, err)
  3135. for _, them := range users {
  3136. if me == them {
  3137. continue
  3138. }
  3139. err = f.AddBuddy(context.Background(), me, them)
  3140. assert.NoError(t, err)
  3141. }
  3142. }
  3143. for _, me := range users {
  3144. var relationships []Relationship
  3145. relationships, err = f.AllRelationships(context.Background(), me, nil)
  3146. assert.NoError(t, err)
  3147. assert.Len(t, relationships, 2)
  3148. }
  3149. err = f.ClearBuddyListRegistry(context.Background())
  3150. assert.NoError(t, err)
  3151. for _, me := range users {
  3152. var relationships []Relationship
  3153. relationships, err = f.AllRelationships(context.Background(), me, nil)
  3154. assert.NoError(t, err)
  3155. assert.Empty(t, relationships)
  3156. }
  3157. }
  3158. func TestSQLiteUserStore_RemoveBuddy(t *testing.T) {
  3159. defer func() {
  3160. assert.NoError(t, os.Remove(testFile))
  3161. }()
  3162. f, err := NewSQLiteUserStore(testFile)
  3163. assert.NoError(t, err)
  3164. me := NewIdentScreenName("me")
  3165. err = f.RegisterBuddyList(context.Background(), me)
  3166. assert.NoError(t, err)
  3167. them := NewIdentScreenName("them")
  3168. err = f.RegisterBuddyList(context.Background(), them)
  3169. assert.NoError(t, err)
  3170. err = f.AddBuddy(context.Background(), me, them)
  3171. assert.NoError(t, err)
  3172. relationships, err := f.AllRelationships(context.Background(), me, nil)
  3173. assert.NoError(t, err)
  3174. expect := []Relationship{
  3175. {
  3176. User: them,
  3177. IsOnTheirList: false,
  3178. IsOnYourList: true,
  3179. },
  3180. }
  3181. assert.ElementsMatch(t, relationships, expect)
  3182. err = f.RemoveBuddy(context.Background(), me, them)
  3183. assert.NoError(t, err)
  3184. relationships, err = f.AllRelationships(context.Background(), me, nil)
  3185. assert.NoError(t, err)
  3186. expect = []Relationship{
  3187. {
  3188. User: them,
  3189. IsOnTheirList: false,
  3190. IsOnYourList: false,
  3191. },
  3192. }
  3193. assert.ElementsMatch(t, relationships, expect)
  3194. }
  3195. func TestSQLiteUserStore_RemoveDenyBuddy(t *testing.T) {
  3196. defer func() {
  3197. assert.NoError(t, os.Remove(testFile))
  3198. }()
  3199. f, err := NewSQLiteUserStore(testFile)
  3200. assert.NoError(t, err)
  3201. me := NewIdentScreenName("me")
  3202. err = f.RegisterBuddyList(context.Background(), me)
  3203. assert.NoError(t, err)
  3204. err = f.SetPDMode(context.Background(), me, wire.FeedbagPDModeDenySome)
  3205. assert.NoError(t, err)
  3206. them := NewIdentScreenName("them")
  3207. err = f.RegisterBuddyList(context.Background(), them)
  3208. assert.NoError(t, err)
  3209. err = f.DenyBuddy(context.Background(), me, them)
  3210. assert.NoError(t, err)
  3211. relationships, err := f.AllRelationships(context.Background(), me, nil)
  3212. assert.NoError(t, err)
  3213. expect := []Relationship{
  3214. {
  3215. User: them,
  3216. IsOnTheirList: false,
  3217. IsOnYourList: false,
  3218. YouBlock: true,
  3219. BlocksYou: false,
  3220. },
  3221. }
  3222. assert.ElementsMatch(t, relationships, expect)
  3223. err = f.RemoveDenyBuddy(context.Background(), me, them)
  3224. assert.NoError(t, err)
  3225. relationships, err = f.AllRelationships(context.Background(), me, nil)
  3226. assert.NoError(t, err)
  3227. expect = []Relationship{
  3228. {
  3229. User: them,
  3230. IsOnTheirList: false,
  3231. IsOnYourList: false,
  3232. YouBlock: false,
  3233. BlocksYou: false,
  3234. },
  3235. }
  3236. assert.ElementsMatch(t, relationships, expect)
  3237. }
  3238. func TestSQLiteUserStore_RemovePermitBuddy(t *testing.T) {
  3239. defer func() {
  3240. assert.NoError(t, os.Remove(testFile))
  3241. }()
  3242. f, err := NewSQLiteUserStore(testFile)
  3243. assert.NoError(t, err)
  3244. me := NewIdentScreenName("me")
  3245. err = f.RegisterBuddyList(context.Background(), me)
  3246. assert.NoError(t, err)
  3247. err = f.SetPDMode(context.Background(), me, wire.FeedbagPDModePermitSome)
  3248. assert.NoError(t, err)
  3249. them := NewIdentScreenName("them")
  3250. err = f.RegisterBuddyList(context.Background(), them)
  3251. assert.NoError(t, err)
  3252. err = f.PermitBuddy(context.Background(), me, them)
  3253. assert.NoError(t, err)
  3254. relationships, err := f.AllRelationships(context.Background(), me, nil)
  3255. assert.NoError(t, err)
  3256. expect := []Relationship{
  3257. {
  3258. User: them,
  3259. IsOnTheirList: false,
  3260. IsOnYourList: false,
  3261. YouBlock: false,
  3262. BlocksYou: false,
  3263. },
  3264. }
  3265. assert.ElementsMatch(t, relationships, expect)
  3266. err = f.RemovePermitBuddy(context.Background(), me, them)
  3267. assert.NoError(t, err)
  3268. relationships, err = f.AllRelationships(context.Background(), me, nil)
  3269. assert.NoError(t, err)
  3270. expect = []Relationship{
  3271. {
  3272. User: them,
  3273. IsOnTheirList: false,
  3274. IsOnYourList: false,
  3275. YouBlock: true,
  3276. BlocksYou: false,
  3277. },
  3278. }
  3279. assert.ElementsMatch(t, relationships, expect)
  3280. }
  3281. func TestSQLiteUserStore_SetPDMode(t *testing.T) {
  3282. t.Run("Ensure idempotency", func(t *testing.T) {
  3283. defer func() {
  3284. assert.NoError(t, os.Remove(testFile))
  3285. }()
  3286. f, err := NewSQLiteUserStore(testFile)
  3287. assert.NoError(t, err)
  3288. users := []IdentScreenName{
  3289. NewIdentScreenName("me"),
  3290. NewIdentScreenName("them1"),
  3291. }
  3292. for _, user := range users {
  3293. err = f.RegisterBuddyList(context.Background(), user)
  3294. assert.NoError(t, err)
  3295. }
  3296. assert.NoError(t, f.SetPDMode(context.Background(), users[0], wire.FeedbagPDModePermitSome))
  3297. assert.NoError(t, f.PermitBuddy(context.Background(), users[0], users[1]))
  3298. assert.NoError(t, f.SetPDMode(context.Background(), users[0], wire.FeedbagPDModePermitSome))
  3299. relationships, err := f.AllRelationships(context.Background(), users[0], nil)
  3300. assert.NoError(t, err)
  3301. expect := []Relationship{
  3302. {
  3303. User: users[1],
  3304. IsOnTheirList: false,
  3305. IsOnYourList: false,
  3306. YouBlock: false,
  3307. BlocksYou: false,
  3308. },
  3309. }
  3310. assert.ElementsMatch(t, relationships, expect)
  3311. })
  3312. t.Run("Ensure transition from one mode to another clears previously set flags", func(t *testing.T) {
  3313. defer func() {
  3314. assert.NoError(t, os.Remove(testFile))
  3315. }()
  3316. f, err := NewSQLiteUserStore(testFile)
  3317. assert.NoError(t, err)
  3318. users := []IdentScreenName{
  3319. NewIdentScreenName("me"),
  3320. NewIdentScreenName("them1"),
  3321. }
  3322. for _, user := range users {
  3323. err = f.RegisterBuddyList(context.Background(), user)
  3324. assert.NoError(t, err)
  3325. }
  3326. assert.NoError(t, f.SetPDMode(context.Background(), users[0], wire.FeedbagPDModePermitSome))
  3327. assert.NoError(t, f.PermitBuddy(context.Background(), users[0], users[1]))
  3328. assert.NoError(t, f.SetPDMode(context.Background(), users[0], wire.FeedbagPDModeDenySome))
  3329. relationships, err := f.AllRelationships(context.Background(), users[0], nil)
  3330. assert.NoError(t, err)
  3331. assert.Empty(t, relationships)
  3332. })
  3333. }
  3334. // Ensure that transitioning between all the PD modes works.
  3335. func TestSQLiteUserStore_PermitDenyTransitionIntegration(t *testing.T) {
  3336. defer func() {
  3337. assert.NoError(t, os.Remove(testFile))
  3338. }()
  3339. f, err := NewSQLiteUserStore(testFile)
  3340. assert.NoError(t, err)
  3341. users := []IdentScreenName{
  3342. NewIdentScreenName("me"),
  3343. NewIdentScreenName("them1"),
  3344. NewIdentScreenName("them2"),
  3345. NewIdentScreenName("them3"),
  3346. }
  3347. for _, user := range users {
  3348. err = f.RegisterBuddyList(context.Background(), user)
  3349. assert.NoError(t, err)
  3350. }
  3351. // add them1 to buddy list
  3352. assert.NoError(t, f.AddBuddy(context.Background(), users[0], users[1]))
  3353. // permit them2
  3354. assert.NoError(t, f.SetPDMode(context.Background(), users[0], wire.FeedbagPDModePermitSome))
  3355. assert.NoError(t, f.PermitBuddy(context.Background(), users[0], users[2]))
  3356. relationships, err := f.AllRelationships(context.Background(), users[0], nil)
  3357. assert.NoError(t, err)
  3358. // make sure them1 is blocked and them2 is permitted
  3359. expect := []Relationship{
  3360. {
  3361. User: users[1],
  3362. IsOnTheirList: false,
  3363. IsOnYourList: true,
  3364. YouBlock: true,
  3365. BlocksYou: false,
  3366. },
  3367. {
  3368. User: users[2],
  3369. IsOnTheirList: false,
  3370. IsOnYourList: false,
  3371. YouBlock: false,
  3372. BlocksYou: false,
  3373. },
  3374. }
  3375. assert.ElementsMatch(t, relationships, expect)
  3376. // allow everyone
  3377. assert.NoError(t, f.SetPDMode(context.Background(), users[0], wire.FeedbagPDModePermitAll))
  3378. relationships, err = f.AllRelationships(context.Background(), users[0], nil)
  3379. assert.NoError(t, err)
  3380. // make sure buddy1 is on your buddy list and permitted
  3381. expect = []Relationship{
  3382. {
  3383. User: users[1],
  3384. IsOnTheirList: false,
  3385. IsOnYourList: true,
  3386. YouBlock: false,
  3387. BlocksYou: false,
  3388. },
  3389. }
  3390. assert.ElementsMatch(t, relationships, expect)
  3391. // permit them3
  3392. assert.NoError(t, f.SetPDMode(context.Background(), users[0], wire.FeedbagPDModePermitSome))
  3393. assert.NoError(t, f.PermitBuddy(context.Background(), users[0], users[3]))
  3394. relationships, err = f.AllRelationships(context.Background(), users[0], nil)
  3395. assert.NoError(t, err)
  3396. // make sure them1 is blocked them3 is permitted
  3397. expect = []Relationship{
  3398. {
  3399. User: users[1],
  3400. IsOnTheirList: false,
  3401. IsOnYourList: true,
  3402. YouBlock: true,
  3403. BlocksYou: false,
  3404. },
  3405. {
  3406. User: users[3],
  3407. IsOnTheirList: false,
  3408. IsOnYourList: false,
  3409. YouBlock: false,
  3410. BlocksYou: false,
  3411. },
  3412. }
  3413. assert.ElementsMatch(t, relationships, expect)
  3414. // only allow on buddy list
  3415. assert.NoError(t, f.SetPDMode(context.Background(), users[0], wire.FeedbagPDModePermitOnList))
  3416. relationships, err = f.AllRelationships(context.Background(), users[0], nil)
  3417. assert.NoError(t, err)
  3418. // make sure buddy1 is on your buddy list and permitted
  3419. expect = []Relationship{
  3420. {
  3421. User: users[1],
  3422. IsOnTheirList: false,
  3423. IsOnYourList: true,
  3424. YouBlock: false,
  3425. BlocksYou: false,
  3426. },
  3427. }
  3428. assert.ElementsMatch(t, relationships, expect)
  3429. // deny them2
  3430. assert.NoError(t, f.SetPDMode(context.Background(), users[0], wire.FeedbagPDModeDenySome))
  3431. assert.NoError(t, f.DenyBuddy(context.Background(), users[0], users[2]))
  3432. relationships, err = f.AllRelationships(context.Background(), users[0], nil)
  3433. assert.NoError(t, err)
  3434. // make sure them1 is allowed and them2 is blocked
  3435. expect = []Relationship{
  3436. {
  3437. User: users[1],
  3438. IsOnTheirList: false,
  3439. IsOnYourList: true,
  3440. YouBlock: false,
  3441. BlocksYou: false,
  3442. },
  3443. {
  3444. User: users[2],
  3445. IsOnTheirList: false,
  3446. IsOnYourList: false,
  3447. YouBlock: true,
  3448. BlocksYou: false,
  3449. },
  3450. }
  3451. assert.ElementsMatch(t, relationships, expect)
  3452. // allow everyone
  3453. assert.NoError(t, f.SetPDMode(context.Background(), users[0], wire.FeedbagPDModePermitAll))
  3454. relationships, err = f.AllRelationships(context.Background(), users[0], nil)
  3455. assert.NoError(t, err)
  3456. // make sure buddy1 is on your buddy list and permitted
  3457. expect = []Relationship{
  3458. {
  3459. User: users[1],
  3460. IsOnTheirList: false,
  3461. IsOnYourList: true,
  3462. YouBlock: false,
  3463. BlocksYou: false,
  3464. },
  3465. }
  3466. assert.ElementsMatch(t, relationships, expect)
  3467. // deny them3
  3468. assert.NoError(t, f.SetPDMode(context.Background(), users[0], wire.FeedbagPDModeDenySome))
  3469. assert.NoError(t, f.DenyBuddy(context.Background(), users[0], users[3]))
  3470. relationships, err = f.AllRelationships(context.Background(), users[0], nil)
  3471. assert.NoError(t, err)
  3472. // make sure them1 is allowed and them3 is blocked
  3473. expect = []Relationship{
  3474. {
  3475. User: users[1],
  3476. IsOnTheirList: false,
  3477. IsOnYourList: true,
  3478. YouBlock: false,
  3479. BlocksYou: false,
  3480. },
  3481. {
  3482. User: users[3],
  3483. IsOnTheirList: false,
  3484. IsOnYourList: false,
  3485. YouBlock: true,
  3486. BlocksYou: false,
  3487. },
  3488. }
  3489. assert.ElementsMatch(t, relationships, expect)
  3490. // deny everyone
  3491. assert.NoError(t, f.SetPDMode(context.Background(), users[0], wire.FeedbagPDModeDenyAll))
  3492. relationships, err = f.AllRelationships(context.Background(), users[0], nil)
  3493. assert.NoError(t, err)
  3494. // make sure them1 is blocked
  3495. expect = []Relationship{
  3496. {
  3497. User: users[1],
  3498. IsOnTheirList: false,
  3499. IsOnYourList: true,
  3500. YouBlock: true,
  3501. BlocksYou: false,
  3502. },
  3503. }
  3504. assert.ElementsMatch(t, relationships, expect)
  3505. // allow everyone
  3506. assert.NoError(t, f.SetPDMode(context.Background(), users[0], wire.FeedbagPDModePermitAll))
  3507. relationships, err = f.AllRelationships(context.Background(), users[0], nil)
  3508. assert.NoError(t, err)
  3509. // make sure them1 is on your buddy list and permitted
  3510. expect = []Relationship{
  3511. {
  3512. User: users[1],
  3513. IsOnTheirList: false,
  3514. IsOnYourList: true,
  3515. YouBlock: false,
  3516. BlocksYou: false,
  3517. },
  3518. }
  3519. assert.ElementsMatch(t, relationships, expect)
  3520. }
  3521. func TestSQLiteUserStore_UpdateSuspendedStatus(t *testing.T) {
  3522. defer func() {
  3523. assert.NoError(t, os.Remove(testFile))
  3524. }()
  3525. f, err := NewSQLiteUserStore(testFile)
  3526. assert.NoError(t, err)
  3527. screenName := NewIdentScreenName("userA")
  3528. insertedUser := &User{
  3529. IdentScreenName: screenName,
  3530. DisplayScreenName: DisplayScreenName("usera"),
  3531. AuthKey: "theauthkey",
  3532. StrongMD5Pass: []byte("thepasshash"),
  3533. RegStatus: 3,
  3534. SuspendedStatus: wire.LoginErrSuspendedAccount,
  3535. }
  3536. err = f.InsertUser(context.Background(), *insertedUser)
  3537. assert.NoError(t, err)
  3538. err = f.UpdateSuspendedStatus(context.Background(), wire.LoginErrSuspendedAccountAge, screenName)
  3539. assert.NoError(t, err)
  3540. user, err := f.User(context.Background(), screenName)
  3541. assert.NoError(t, err)
  3542. assert.Equal(t, user.SuspendedStatus, wire.LoginErrSuspendedAccountAge)
  3543. }
  3544. func TestSQLiteUserStore_SetBotStatus(t *testing.T) {
  3545. defer func() {
  3546. assert.NoError(t, os.Remove(testFile))
  3547. }()
  3548. f, err := NewSQLiteUserStore(testFile)
  3549. assert.NoError(t, err)
  3550. screenName := NewIdentScreenName("userA")
  3551. insertedUser := &User{
  3552. IdentScreenName: screenName,
  3553. DisplayScreenName: DisplayScreenName("usera"),
  3554. AuthKey: "theauthkey",
  3555. StrongMD5Pass: []byte("thepasshash"),
  3556. IsBot: false,
  3557. }
  3558. err = f.InsertUser(context.Background(), *insertedUser)
  3559. assert.NoError(t, err)
  3560. user, err := f.User(context.Background(), screenName)
  3561. assert.NoError(t, err)
  3562. assert.False(t, user.IsBot)
  3563. err = f.SetBotStatus(context.Background(), true, screenName)
  3564. assert.NoError(t, err)
  3565. user, err = f.User(context.Background(), screenName)
  3566. assert.NoError(t, err)
  3567. assert.True(t, user.IsBot)
  3568. err = f.SetBotStatus(context.Background(), false, screenName)
  3569. assert.NoError(t, err)
  3570. user, err = f.User(context.Background(), screenName)
  3571. assert.NoError(t, err)
  3572. assert.False(t, user.IsBot)
  3573. }
  3574. func TestSQLiteUserStore_SetWarnLevel(t *testing.T) {
  3575. t.Run("Happy Path - Update Warning Level for Existing User", func(t *testing.T) {
  3576. defer func() {
  3577. assert.NoError(t, os.Remove(testFile))
  3578. }()
  3579. f, err := NewSQLiteUserStore(testFile)
  3580. assert.NoError(t, err)
  3581. screenName := NewIdentScreenName("testuser")
  3582. user := User{
  3583. IdentScreenName: screenName,
  3584. }
  3585. err = f.InsertUser(context.Background(), user)
  3586. assert.NoError(t, err)
  3587. // Set initial warning level
  3588. lastWarnUpdate := time.Date(2023, 12, 1, 10, 30, 0, 0, time.UTC)
  3589. lastWarnLevel := uint16(5)
  3590. err = f.SetWarnLevel(context.Background(), screenName, lastWarnUpdate, lastWarnLevel)
  3591. assert.NoError(t, err)
  3592. // Verify the warning level was updated
  3593. updatedUser, err := f.User(context.Background(), screenName)
  3594. assert.NoError(t, err)
  3595. assert.Equal(t, lastWarnUpdate, updatedUser.LastWarnUpdate)
  3596. assert.Equal(t, lastWarnLevel, updatedUser.LastWarnLevel)
  3597. })
  3598. t.Run("User Does Not Exist", func(t *testing.T) {
  3599. defer func() {
  3600. assert.NoError(t, os.Remove(testFile))
  3601. }()
  3602. f, err := NewSQLiteUserStore(testFile)
  3603. assert.NoError(t, err)
  3604. nonExistentScreenName := NewIdentScreenName("nonexistentuser")
  3605. lastWarnUpdate := time.Date(2023, 12, 1, 10, 30, 0, 0, time.UTC)
  3606. lastWarnLevel := uint16(5)
  3607. err = f.SetWarnLevel(context.Background(), nonExistentScreenName, lastWarnUpdate, lastWarnLevel)
  3608. assert.ErrorIs(t, err, ErrNoUser)
  3609. })
  3610. }
  3611. func TestSQLiteUserStore_DeleteBARTItem(t *testing.T) {
  3612. t.Run("delete_existing_item", func(t *testing.T) {
  3613. defer func() {
  3614. assert.NoError(t, os.Remove(testFile))
  3615. }()
  3616. f, err := NewSQLiteUserStore(testFile)
  3617. require.NoError(t, err)
  3618. ctx := context.Background()
  3619. // Insert a BART item first
  3620. hash := []byte("testhash123456")
  3621. image := []byte("test image data")
  3622. bartType := uint16(1)
  3623. err = f.InsertBARTItem(ctx, hash, image, bartType)
  3624. require.NoError(t, err)
  3625. // Verify it exists
  3626. items, err := f.ListBARTItems(ctx, 1)
  3627. require.NoError(t, err)
  3628. require.Len(t, items, 1)
  3629. // Delete the item
  3630. err = f.DeleteBARTItem(ctx, hash)
  3631. assert.NoError(t, err)
  3632. // Verify it's gone
  3633. items, err = f.ListBARTItems(ctx, 1)
  3634. require.NoError(t, err)
  3635. assert.Len(t, items, 0)
  3636. })
  3637. t.Run("delete_nonexistent_item", func(t *testing.T) {
  3638. defer func() {
  3639. assert.NoError(t, os.Remove(testFile))
  3640. }()
  3641. f, err := NewSQLiteUserStore(testFile)
  3642. require.NoError(t, err)
  3643. ctx := context.Background()
  3644. hash := []byte("nonexistent")
  3645. err = f.DeleteBARTItem(ctx, hash)
  3646. assert.ErrorIs(t, err, ErrBARTItemNotFound)
  3647. })
  3648. }
  3649. func TestSQLiteUserStore_ContactPreAuth(t *testing.T) {
  3650. ctx := context.Background()
  3651. defer func() {
  3652. assert.NoError(t, os.Remove(testFile))
  3653. }()
  3654. f, err := NewSQLiteUserStore(testFile)
  3655. require.NoError(t, err)
  3656. owner := NewIdentScreenName("100001")
  3657. requester := NewIdentScreenName("100002")
  3658. require.NoError(t, f.InsertUser(ctx, User{
  3659. IdentScreenName: owner,
  3660. DisplayScreenName: DisplayScreenName("100001"),
  3661. IsICQ: true,
  3662. ICQInfo: ICQInfo{
  3663. Permissions: ICQPermissions{AuthRequired: true},
  3664. },
  3665. }))
  3666. require.NoError(t, f.InsertUser(ctx, User{
  3667. IdentScreenName: requester,
  3668. DisplayScreenName: DisplayScreenName("100002"),
  3669. IsICQ: true,
  3670. }))
  3671. blocked, err := f.RequiresAuthorization(ctx, owner, requester)
  3672. require.NoError(t, err)
  3673. assert.True(t, blocked)
  3674. require.NoError(t, f.RecordPreAuth(ctx, owner, requester))
  3675. blocked, err = f.RequiresAuthorization(ctx, owner, requester)
  3676. require.NoError(t, err)
  3677. assert.False(t, blocked)
  3678. // Pre-auth rows persist; FeedbagUpsert and AddBuddy do not delete them.
  3679. buddyItem := wire.FeedbagItem{
  3680. GroupID: 0,
  3681. ItemID: 1,
  3682. ClassID: wire.FeedbagClassIdBuddy,
  3683. Name: owner.String(),
  3684. TLVLBlock: wire.TLVLBlock{},
  3685. }
  3686. require.NoError(t, f.FeedbagUpsert(ctx, requester, []wire.FeedbagItem{buddyItem}))
  3687. var count int
  3688. err = f.db.QueryRow(`SELECT COUNT(*) FROM contactPreauth WHERE ownerScreenName = ? AND authorizedScreenName = ?`,
  3689. owner.String(), requester.String()).Scan(&count)
  3690. require.NoError(t, err)
  3691. assert.Equal(t, 1, count)
  3692. require.NoError(t, f.AddBuddy(ctx, requester, owner))
  3693. err = f.db.QueryRow(`SELECT COUNT(*) FROM contactPreauth WHERE ownerScreenName = ? AND authorizedScreenName = ?`,
  3694. owner.String(), requester.String()).Scan(&count)
  3695. require.NoError(t, err)
  3696. assert.Equal(t, 1, count)
  3697. }
  3698. func TestSQLiteUserStore_RecordPreAuth_unknownUser(t *testing.T) {
  3699. ctx := context.Background()
  3700. defer func() {
  3701. assert.NoError(t, os.Remove(testFile))
  3702. }()
  3703. f, err := NewSQLiteUserStore(testFile)
  3704. require.NoError(t, err)
  3705. owner := NewIdentScreenName("100001")
  3706. require.NoError(t, f.InsertUser(ctx, User{
  3707. IdentScreenName: owner,
  3708. DisplayScreenName: DisplayScreenName("100001"),
  3709. IsICQ: true,
  3710. ICQInfo: ICQInfo{
  3711. Permissions: ICQPermissions{AuthRequired: true},
  3712. },
  3713. }))
  3714. unknownRequester := NewIdentScreenName("999999")
  3715. assert.NoError(t, f.RecordPreAuth(ctx, owner, unknownRequester))
  3716. blocked, err := f.RequiresAuthorization(ctx, owner, unknownRequester)
  3717. require.NoError(t, err)
  3718. assert.True(t, blocked)
  3719. var count int
  3720. err = f.db.QueryRow(`SELECT COUNT(*) FROM contactPreauth WHERE ownerScreenName = ? AND authorizedScreenName = ?`,
  3721. owner.String(), unknownRequester.String()).Scan(&count)
  3722. require.NoError(t, err)
  3723. assert.Equal(t, 0, count)
  3724. }