| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986 |
- package foodgroup
- import (
- "context"
- "errors"
- "io"
- "log/slog"
- "net"
- "net/netip"
- "sync"
- "testing"
- "time"
- "github.com/mk6i/open-oscar-server/state"
- "github.com/mk6i/open-oscar-server/wire"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
- )
- func TestICBMService_ChannelMsgToHost(t *testing.T) {
- cases := []struct {
- // name is the unit test name
- name string
- // instance is the session of the user sending the message
- instance *state.SessionInstance
- // inputSNAC is the SNAC frame sent from the server to the recipient
- // client
- inputSNAC wire.SNACMessage
- // expectOutput is the expected return SNAC value.
- expectOutput *wire.SNACMessage
- // wantErr is the expected error (nil for success)
- wantErr error
- // mockParams is the list of params sent to mocks that satisfy this
- // method's dependencies
- mockParams mockParams
- // expectForwardICQAuthEvents indicates whether ChannelMsgToHost should
- // delegate ICQ channel-4 auth events to forwardICQAuthEvents.
- expectForwardICQAuthEvents bool
- // expectForwardRecipient is the expected recipient passed to
- // forwardICQAuthEvents when expectForwardICQAuthEvents is true.
- expectForwardRecipient state.IdentScreenName
- // expectForwardAuthMsg is the expected auth message passed to
- // forwardICQAuthEvents when expectForwardICQAuthEvents is true.
- expectForwardAuthMsg wire.ICBMCh4Message
- // timeNow returns the current time
- timeNow func() time.Time
- }{
- {
- name: "transmit message from sender to recipient, ack message back to sender",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10), sessOptWantTypingEvents),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptWarning(20), sessOptSignonComplete).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelIM,
- TLVUserInfo: newTestInstance("sender-screen-name", sessOptWarning(10)).Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVData,
- Value: []byte{1, 2, 3, 4},
- },
- {
- Tag: wire.ICBMTLVWantEvents,
- Value: []byte{},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVRequestHostAck,
- Value: []byte{},
- },
- {
- Tag: wire.ICBMTLVData,
- Value: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- expectOutput: &wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMHostAck,
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x0C_ICBMHostAck{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- },
- },
- },
- {
- name: "transmit message from sender to recipient, don't ack message back to sender",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10), sessOptWantTypingEvents),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptWarning(20), sessOptSignonComplete).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelIM,
- TLVUserInfo: newTestInstance("sender-screen-name", sessOptWarning(10)).Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVData,
- Value: []byte{1, 2, 3, 4},
- },
- {
- Tag: wire.ICBMTLVWantEvents,
- Value: []byte{},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVData,
- Value: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- expectOutput: nil,
- },
- {
- name: "transmit message from sender to recipient, don't ack message back to sender, don't want typing events",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptWarning(20), sessOptSignonComplete).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelIM,
- TLVUserInfo: newTestInstance("sender-screen-name", sessOptWarning(10)).Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVData,
- Value: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVData,
- Value: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- expectOutput: nil,
- },
- {
- name: "strip store directive from message relayed to online recipient",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptWarning(20), sessOptSignonComplete).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelIM,
- TLVUserInfo: newTestInstance("sender-screen-name", sessOptWarning(10)).Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- },
- expectOutput: nil,
- },
- {
- // Only the server stamps a send time, and only on a replay out of the
- // offline store. Forwarding the sender's would let them pass a live
- // message off as a stored one and date it at will.
- name: "strip sender-supplied send time from message relayed to online recipient",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptWarning(20), sessOptSignonComplete).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelIM,
- TLVUserInfo: newTestInstance("sender-screen-name", sessOptWarning(10)).Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVSendTime, uint32(time.Unix(1700000000, 0).Unix())),
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- },
- expectOutput: nil,
- },
- {
- name: "don't transmit message from sender to recipient because sender has blocked recipient",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: true,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{},
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{},
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVRequestHostAck,
- Value: []byte{},
- },
- },
- },
- },
- },
- expectOutput: &wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMErr,
- RequestID: 1234,
- },
- Body: wire.SNACError{
- Code: wire.ErrorCodeInLocalPermitDeny,
- },
- },
- },
- {
- name: "don't transmit message from sender to recipient because recipient has blocked sender",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: true,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{},
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{},
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVRequestHostAck,
- Value: []byte{},
- },
- },
- },
- },
- },
- expectOutput: &wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMErr,
- RequestID: 1234,
- },
- Body: wire.SNACError{
- Code: wire.ErrorCodeNotLoggedOn,
- },
- },
- },
- {
- name: "don't transmit message from sender to recipient because recipient doesn't exist",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: nil,
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{},
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVRequestHostAck,
- Value: []byte{},
- },
- },
- },
- },
- },
- expectOutput: &wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMErr,
- RequestID: 1234,
- },
- Body: wire.SNACError{
- Code: wire.ErrorCodeNotLoggedOn,
- },
- },
- },
- {
- name: "send offline message to ICQ recipient",
- instance: newTestInstance("11111111", sessOptUIN(11111111)),
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "22222222",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- },
- },
- },
- },
- expectOutput: nil,
- timeNow: func() time.Time {
- return time.Date(2020, time.August, 1, 0, 0, 0, 0, time.UTC)
- },
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("11111111"),
- them: state.NewIdentScreenName("22222222"),
- result: state.Relationship{
- User: state.NewIdentScreenName("22222222"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("22222222"),
- result: nil,
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{},
- },
- offlineMessageManagerParams: offlineMessageManagerParams{
- saveMessageParams: saveMessageParams{
- {
- offlineMessageIn: state.OfflineMessage{
- Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "22222222",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- },
- },
- },
- Recipient: state.NewIdentScreenName("22222222"),
- Sender: state.NewIdentScreenName("11111111"),
- Sent: time.Date(2020, time.August, 1, 0, 0, 0, 0, time.UTC),
- },
- },
- },
- },
- feedbagManagerParams: feedbagManagerParams{
- feedbagParams: feedbagParams{
- {
- screenName: state.NewIdentScreenName("22222222"),
- results: []wire.FeedbagItem{},
- },
- },
- },
- },
- },
- {
- name: "send offline message to recipient with accept offline IM flag set",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVRequestHostAck, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- },
- expectOutput: &wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMHostAck,
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x0C_ICBMHostAck{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- },
- },
- timeNow: func() time.Time {
- return time.Date(2020, time.August, 1, 0, 0, 0, 0, time.UTC)
- },
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: nil,
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameParams: relayToScreenNameParams{},
- },
- offlineMessageManagerParams: offlineMessageManagerParams{
- saveMessageParams: saveMessageParams{
- {
- offlineMessageIn: state.OfflineMessage{
- Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVRequestHostAck, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- Recipient: state.NewIdentScreenName("recipient-screen-name"),
- Sender: state.NewIdentScreenName("sender-screen-name"),
- Sent: time.Date(2020, time.August, 1, 0, 0, 0, 0, time.UTC),
- },
- countOut: 1,
- },
- },
- },
- feedbagManagerParams: feedbagManagerParams{
- feedbagParams: feedbagParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- results: []wire.FeedbagItem{
- {
- ClassID: wire.FeedbagClassIdBuddyPrefs,
- TLVLBlock: wire.TLVLBlock{
- TLVList: wire.TLVList{
- {Tag: wire.FeedbagAttributesBuddyPrefsValid, Value: []byte{0, 0, 24, 64}},
- {Tag: wire.FeedbagAttributesBuddyPrefs, Value: []byte{0, 0, 24, 64}},
- {Tag: wire.FeedbagAttributesBuddyPrefs2Valid, Value: []byte{0, 0, 17}},
- {Tag: wire.FeedbagAttributesBuddyPrefs2, Value: []byte{0, 0, 17}},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- {
- name: "reject offline message when recipient has opted out of offline messages",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVRequestHostAck, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- },
- expectOutput: &wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMErr,
- RequestID: 1234,
- },
- Body: wire.SNACError{
- Code: wire.ErrorCodeNotLoggedOn,
- },
- },
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: nil,
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameParams: relayToScreenNameParams{},
- },
- offlineMessageManagerParams: offlineMessageManagerParams{
- saveMessageParams: saveMessageParams{},
- },
- feedbagManagerParams: feedbagManagerParams{
- feedbagParams: feedbagParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- results: []wire.FeedbagItem{
- {
- ClassID: wire.FeedbagClassIdBuddyPrefs,
- TLVLBlock: wire.TLVLBlock{
- TLVList: wire.TLVList{
- {Tag: wire.FeedbagAttributesBuddyPrefsValid, Value: []byte{0, 0, 24, 64}},
- {Tag: wire.FeedbagAttributesBuddyPrefs, Value: []byte{0, 0, 24, 64}},
- {Tag: wire.FeedbagAttributesBuddyPrefs2Valid, Value: []byte{0, 0, 17}},
- {Tag: wire.FeedbagAttributesBuddyPrefs2, Value: []byte{0, 0, 1}},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- {
- name: "send offline message when offline IM preference is not valid",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVRequestHostAck, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- },
- expectOutput: &wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMHostAck,
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x0C_ICBMHostAck{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- },
- },
- timeNow: func() time.Time {
- return time.Date(2020, time.August, 1, 0, 0, 0, 0, time.UTC)
- },
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: nil,
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameParams: relayToScreenNameParams{},
- },
- offlineMessageManagerParams: offlineMessageManagerParams{
- saveMessageParams: saveMessageParams{
- {
- offlineMessageIn: state.OfflineMessage{
- Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVRequestHostAck, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- Recipient: state.NewIdentScreenName("recipient-screen-name"),
- Sender: state.NewIdentScreenName("sender-screen-name"),
- Sent: time.Date(2020, time.August, 1, 0, 0, 0, 0, time.UTC),
- },
- countOut: 1,
- },
- },
- },
- feedbagManagerParams: feedbagManagerParams{
- feedbagParams: feedbagParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- results: []wire.FeedbagItem{
- {
- ClassID: wire.FeedbagClassIdBuddyPrefs,
- TLVLBlock: wire.TLVLBlock{
- TLVList: wire.TLVList{
- {Tag: wire.FeedbagAttributesBuddyPrefsValid, Value: []byte{0, 0, 24, 64}},
- {Tag: wire.FeedbagAttributesBuddyPrefs, Value: []byte{0, 0, 24, 64}},
- {Tag: wire.FeedbagAttributesBuddyPrefs2Valid, Value: []byte{0, 0, 7}},
- {Tag: wire.FeedbagAttributesBuddyPrefs2, Value: []byte{0, 0, 17}},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- {
- name: "send rendezvous request for file transfer, expect IP TLV override",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10),
- sessRemoteAddr(netip.AddrPortFrom(netip.MustParseAddr("129.168.0.1"), 0))),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptWarning(20), sessOptSignonComplete).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelRendezvous,
- TLVUserInfo: newTestInstance("sender-screen-name", sessOptWarning(10)).Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVData, wire.ICBMCh2Fragment{
- Type: wire.ICBMRdvMessagePropose,
- Capability: wire.CapFileTransfer,
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMRdvTLVTagsPort, uint16(4000)),
- wire.NewTLVBE(wire.ICBMRdvTLVTagsRequesterIP, net.ParseIP("129.168.0.1").To4()),
- wire.NewTLVBE(wire.ICBMRdvTLVTagsVerifiedIP, net.ParseIP("129.168.0.1").To4()),
- },
- },
- }),
- },
- },
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelRendezvous,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVData, wire.ICBMCh2Fragment{
- Type: wire.ICBMRdvMessagePropose,
- Capability: wire.CapFileTransfer,
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMRdvTLVTagsPort, uint16(4000)),
- wire.NewTLVBE(wire.ICBMRdvTLVTagsRequesterIP, net.ParseIP("127.0.0.1").To4()),
- },
- },
- }),
- },
- },
- },
- },
- expectOutput: nil,
- },
- {
- name: "send rendezvous rejection for file transfer, expect no IP TLV override",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10),
- sessRemoteAddr(netip.AddrPortFrom(netip.MustParseAddr("129.168.0.1"), 0))),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptWarning(20), sessOptSignonComplete).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelRendezvous,
- TLVUserInfo: newTestInstance("sender-screen-name", sessOptWarning(10)).Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVData, wire.ICBMCh2Fragment{
- Type: wire.ICBMRdvMessageCancel,
- Capability: wire.CapFileTransfer,
- }),
- },
- },
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelRendezvous,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVData, wire.ICBMCh2Fragment{
- Type: wire.ICBMRdvMessageCancel,
- Capability: wire.CapFileTransfer,
- }),
- },
- },
- },
- },
- expectOutput: nil,
- },
- {
- name: "send rendezvous request for file transfer without IP in session, expect no IP TLV override",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptWarning(20), sessOptSignonComplete).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelRendezvous,
- TLVUserInfo: newTestInstance("sender-screen-name", sessOptWarning(10)).Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVData, wire.ICBMCh2Fragment{
- Type: wire.ICBMRdvMessagePropose,
- Capability: wire.CapFileTransfer,
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMRdvTLVTagsPort, uint16(4000)),
- wire.NewTLVBE(wire.ICBMRdvTLVTagsRequesterIP, net.ParseIP("127.0.0.1").To4()),
- },
- },
- }),
- },
- },
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelRendezvous,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVData, wire.ICBMCh2Fragment{
- Type: wire.ICBMRdvMessagePropose,
- Capability: wire.CapFileTransfer,
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMRdvTLVTagsPort, uint16(4000)),
- wire.NewTLVBE(wire.ICBMRdvTLVTagsRequesterIP, net.ParseIP("127.0.0.1").To4()),
- },
- },
- }),
- },
- },
- },
- },
- expectOutput: nil,
- },
- {
- name: "relay Xtraz XStatus message",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptWarning(20), sessOptSignonComplete).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelRendezvous,
- TLVUserInfo: newTestInstance("sender-screen-name", sessOptWarning(10)).Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVData, wire.ICBMCh2Fragment{
- Type: wire.ICBMRdvMessagePropose,
- Capability: wire.CapXtrazScript,
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(0x2711, []byte("xtraz-xml-payload")),
- },
- },
- }),
- },
- },
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelRendezvous,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVData, wire.ICBMCh2Fragment{
- Type: wire.ICBMRdvMessagePropose,
- Capability: wire.CapXtrazScript,
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(0x2711, []byte("xtraz-xml-payload")),
- },
- },
- }),
- },
- },
- },
- },
- expectOutput: nil,
- },
- {
- name: "transmit message to recipient with all sessions inactive - use RelayToScreenName",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptWarning(20), sessOptAllInactive).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameParams: relayToScreenNameParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelIM,
- TLVUserInfo: newTestInstance("sender-screen-name", sessOptWarning(10)).Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVData,
- Value: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVData,
- Value: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- expectOutput: nil,
- },
- {
- name: "transmit message to recipient with some active sessions - use RelayToScreenNameActiveOnly",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptWarning(20), sessOptSomeActive, sessOptSignonComplete).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelIM,
- TLVUserInfo: newTestInstance("sender-screen-name", sessOptWarning(10)).Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVData,
- Value: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVData,
- Value: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- expectOutput: nil,
- },
- {
- name: "transmit message to recipient with closed session - use RelayToScreenName",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptWarning(20), sessOptClosed).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameParams: relayToScreenNameParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelIM,
- TLVUserInfo: newTestInstance("sender-screen-name", sessOptWarning(10)).Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVData,
- Value: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVData,
- Value: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- expectOutput: nil,
- },
- {
- name: "transmit message to recipient with mixed session states - use RelayToScreenNameActiveOnly",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptWarning(20), sessOptMixedStates, sessOptSignonComplete).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelIM,
- TLVUserInfo: newTestInstance("sender-screen-name", sessOptWarning(10)).Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVData,
- Value: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- {
- Tag: wire.ICBMTLVData,
- Value: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- expectOutput: nil,
- },
- {
- name: "send offline message when inbox is full, return ICBM error with subcode",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVRequestHostAck, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- },
- expectOutput: &wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMErr,
- RequestID: 1234,
- },
- Body: wire.SNACError{
- Code: wire.ErrorCodeNotLoggedOn,
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ErrorTLVErrorSubcode, wire.ICBMSubErrOfflineIMExceedMax),
- },
- },
- },
- },
- wantErr: nil,
- timeNow: func() time.Time {
- return time.Date(2020, time.August, 1, 0, 0, 0, 0, time.UTC)
- },
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: nil,
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameParams: relayToScreenNameParams{},
- },
- offlineMessageManagerParams: offlineMessageManagerParams{
- saveMessageParams: saveMessageParams{
- {
- offlineMessageIn: state.OfflineMessage{
- Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVRequestHostAck, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- Recipient: state.NewIdentScreenName("recipient-screen-name"),
- Sender: state.NewIdentScreenName("sender-screen-name"),
- Sent: time.Date(2020, time.August, 1, 0, 0, 0, 0, time.UTC),
- },
- err: state.ErrOfflineInboxFull,
- },
- },
- },
- feedbagManagerParams: feedbagManagerParams{
- feedbagParams: feedbagParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- results: []wire.FeedbagItem{
- {
- ClassID: wire.FeedbagClassIdBuddyPrefs,
- TLVLBlock: wire.TLVLBlock{
- TLVList: wire.TLVList{
- {Tag: wire.FeedbagAttributesBuddyPrefsValid, Value: []byte{0, 0, 24, 64}},
- {Tag: wire.FeedbagAttributesBuddyPrefs, Value: []byte{0, 0, 24, 64}},
- {Tag: wire.FeedbagAttributesBuddyPrefs2Valid, Value: []byte{0, 0, 17}},
- {Tag: wire.FeedbagAttributesBuddyPrefs2, Value: []byte{0, 0, 17}},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- {
- name: "send offline message when SaveMessage returns generic error",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVRequestHostAck, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- },
- expectOutput: nil,
- wantErr: assert.AnError,
- timeNow: func() time.Time {
- return time.Date(2020, time.August, 1, 0, 0, 0, 0, time.UTC)
- },
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: nil,
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameParams: relayToScreenNameParams{},
- },
- offlineMessageManagerParams: offlineMessageManagerParams{
- saveMessageParams: saveMessageParams{
- {
- offlineMessageIn: state.OfflineMessage{
- Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVRequestHostAck, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- Recipient: state.NewIdentScreenName("recipient-screen-name"),
- Sender: state.NewIdentScreenName("sender-screen-name"),
- Sent: time.Date(2020, time.August, 1, 0, 0, 0, 0, time.UTC),
- },
- err: assert.AnError,
- },
- },
- },
- feedbagManagerParams: feedbagManagerParams{
- feedbagParams: feedbagParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- results: []wire.FeedbagItem{
- {
- ClassID: wire.FeedbagClassIdBuddyPrefs,
- TLVLBlock: wire.TLVLBlock{
- TLVList: wire.TLVList{
- {Tag: wire.FeedbagAttributesBuddyPrefsValid, Value: []byte{0, 0, 24, 64}},
- {Tag: wire.FeedbagAttributesBuddyPrefs, Value: []byte{0, 0, 24, 64}},
- {Tag: wire.FeedbagAttributesBuddyPrefs2Valid, Value: []byte{0, 0, 17}},
- {Tag: wire.FeedbagAttributesBuddyPrefs2, Value: []byte{0, 0, 17}},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- {
- name: "send offline message when SaveMessage returns ErrNoUser, return ICBM error",
- instance: newTestInstance("sender-screen-name", sessOptWarning(10)),
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVRequestHostAck, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- },
- expectOutput: &wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMErr,
- RequestID: 1234,
- },
- Body: wire.SNACError{
- Code: wire.ErrorCodeNotLoggedOn,
- },
- },
- wantErr: nil,
- timeNow: func() time.Time {
- return time.Date(2020, time.August, 1, 0, 0, 0, 0, time.UTC)
- },
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: nil,
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameParams: relayToScreenNameParams{},
- },
- offlineMessageManagerParams: offlineMessageManagerParams{
- saveMessageParams: saveMessageParams{
- {
- offlineMessageIn: state.OfflineMessage{
- Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- ScreenName: "recipient-screen-name",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVRequestHostAck, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3, 4}),
- },
- },
- },
- Recipient: state.NewIdentScreenName("recipient-screen-name"),
- Sender: state.NewIdentScreenName("sender-screen-name"),
- Sent: time.Date(2020, time.August, 1, 0, 0, 0, 0, time.UTC),
- },
- err: state.ErrNoUser,
- },
- },
- },
- feedbagManagerParams: feedbagManagerParams{
- feedbagParams: feedbagParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- results: []wire.FeedbagItem{
- {
- ClassID: wire.FeedbagClassIdBuddyPrefs,
- TLVLBlock: wire.TLVLBlock{
- TLVList: wire.TLVList{
- {Tag: wire.FeedbagAttributesBuddyPrefsValid, Value: []byte{0, 0, 24, 64}},
- {Tag: wire.FeedbagAttributesBuddyPrefs, Value: []byte{0, 0, 24, 64}},
- {Tag: wire.FeedbagAttributesBuddyPrefs2Valid, Value: []byte{0, 0, 17}},
- {Tag: wire.FeedbagAttributesBuddyPrefs2, Value: []byte{0, 0, 17}},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- {
- name: "ICQ channel feedbag ch4: auth_ok",
- instance: newTestInstance("100001", sessOptUIN(100001)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("100001"),
- them: state.NewIdentScreenName("200002"),
- result: state.Relationship{
- User: state.NewIdentScreenName("200002"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("200002"),
- result: newTestInstance("200002", sessOptFeedbagEnabled, sessOptSignonComplete).Session(),
- },
- },
- },
- },
- expectForwardICQAuthEvents: true,
- expectForwardRecipient: state.NewIdentScreenName("200002"),
- expectForwardAuthMsg: wire.ICBMCh4Message{
- UIN: 100001,
- MessageType: wire.ICBMMsgTypeAuthOK,
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{},
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelICQ,
- ScreenName: "200002",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVLE(wire.ICBMTLVData, wire.ICBMCh4Message{
- UIN: 100001,
- MessageType: wire.ICBMMsgTypeAuthOK,
- }),
- },
- },
- },
- },
- expectOutput: nil,
- wantErr: nil,
- },
- {
- name: "ICQ channel non-feedbag ch4: auth_ok",
- instance: newTestInstance("100001", sessOptUIN(100001)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("100001"),
- them: state.NewIdentScreenName("200002"),
- result: state.Relationship{
- User: state.NewIdentScreenName("200002"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("200002"),
- result: newTestInstance("200002", sessOptSignonComplete).Session(),
- },
- },
- },
- contactPreAuthorizerParams: contactPreAuthorizerParams{
- recordPreAuthParams: recordPreAuthParams{
- {owner: state.NewIdentScreenName("100001"), buddy: state.NewIdentScreenName("200002")},
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("200002"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelICQ,
- TLVUserInfo: newTestInstance("100001", sessOptUIN(100001)).Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVLE(wire.ICBMTLVData, wire.ICBMCh4Message{
- UIN: 100001,
- MessageType: wire.ICBMMsgTypeAuthOK,
- }),
- },
- },
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{},
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelICQ,
- ScreenName: "200002",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVLE(wire.ICBMTLVData, wire.ICBMCh4Message{
- UIN: 100001,
- MessageType: wire.ICBMMsgTypeAuthOK,
- }),
- },
- },
- },
- },
- expectOutput: nil,
- wantErr: nil,
- },
- {
- name: "ICQ channel feedbag ch4: auth_deny",
- instance: newTestInstance("100001", sessOptUIN(100001)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("100001"),
- them: state.NewIdentScreenName("200002"),
- result: state.Relationship{
- User: state.NewIdentScreenName("200002"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("200002"),
- result: newTestInstance("200002", sessOptFeedbagEnabled, sessOptSignonComplete).Session(),
- },
- },
- },
- },
- expectForwardICQAuthEvents: true,
- expectForwardRecipient: state.NewIdentScreenName("200002"),
- expectForwardAuthMsg: wire.ICBMCh4Message{
- UIN: 100001,
- MessageType: wire.ICBMMsgTypeAuthDeny,
- Message: "no thanks",
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{},
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelICQ,
- ScreenName: "200002",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVLE(wire.ICBMTLVData, wire.ICBMCh4Message{
- UIN: 100001,
- MessageType: wire.ICBMMsgTypeAuthDeny,
- Message: "no thanks",
- }),
- },
- },
- },
- },
- expectOutput: nil,
- wantErr: nil,
- },
- {
- name: "ICQ channel feedbag ch4: added",
- instance: newTestInstance("100001", sessOptUIN(100001)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("100001"),
- them: state.NewIdentScreenName("200002"),
- result: state.Relationship{
- User: state.NewIdentScreenName("200002"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("200002"),
- result: newTestInstance("200002", sessOptFeedbagEnabled, sessOptSignonComplete).Session(),
- },
- },
- },
- },
- expectForwardICQAuthEvents: true,
- expectForwardRecipient: state.NewIdentScreenName("200002"),
- expectForwardAuthMsg: wire.ICBMCh4Message{
- UIN: 100001,
- MessageType: wire.ICBMMsgTypeAdded,
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{},
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelICQ,
- ScreenName: "200002",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVLE(wire.ICBMTLVData, wire.ICBMCh4Message{
- UIN: 100001,
- MessageType: wire.ICBMMsgTypeAdded,
- }),
- },
- },
- },
- },
- expectOutput: nil,
- wantErr: nil,
- },
- {
- name: "ICQ channel feedbag ch4: auth_req",
- instance: newTestInstance("100001", sessOptUIN(100001)),
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("100001"),
- them: state.NewIdentScreenName("200002"),
- result: state.Relationship{
- User: state.NewIdentScreenName("200002"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("200002"),
- result: newTestInstance("200002", sessOptFeedbagEnabled, sessOptSignonComplete).Session(),
- },
- },
- },
- },
- expectForwardICQAuthEvents: true,
- expectForwardRecipient: state.NewIdentScreenName("200002"),
- expectForwardAuthMsg: wire.ICBMCh4Message{
- UIN: 100001,
- MessageType: wire.ICBMMsgTypeAuthReq,
- Message: "hi",
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{},
- Body: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelICQ,
- ScreenName: "200002",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVLE(wire.ICBMTLVData, wire.ICBMCh4Message{
- UIN: 100001,
- MessageType: wire.ICBMMsgTypeAuthReq,
- Message: "hi",
- }),
- },
- },
- },
- },
- expectOutput: nil,
- wantErr: nil,
- },
- }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- discardLogger := slog.New(slog.NewTextHandler(io.Discard, nil))
- relationshipFetcher := newMockRelationshipFetcher(t)
- for _, item := range tc.mockParams.relationshipParams {
- relationshipFetcher.EXPECT().
- Relationship(matchContext(), item.me, item.them).
- Return(item.result, item.err)
- }
- sessionRetriever := newMockSessionRetriever(t)
- for _, item := range tc.mockParams.retrieveSessionParams {
- sessionRetriever.EXPECT().
- RetrieveSession(item.screenName).
- Return(item.result)
- }
- messageRelayer := newMockMessageRelayer(t)
- for _, item := range tc.mockParams.relayToScreenNameParams {
- messageRelayer.EXPECT().
- RelayToScreenName(mock.Anything, item.screenName, item.message)
- }
- for _, item := range tc.mockParams.relayToScreenNameActiveOnlyParams {
- messageRelayer.EXPECT().
- RelayToScreenNameActiveOnly(mock.Anything, item.screenName, item.message)
- }
- offlineMessageManager := newMockOfflineMessageManager(t)
- for _, params := range tc.mockParams.saveMessageParams {
- offlineMessageManager.EXPECT().
- SaveMessage(matchContext(), params.offlineMessageIn).
- Return(params.countOut, params.err)
- }
- feedbagManager := newMockFeedbagManager(t)
- for _, params := range tc.mockParams.feedbagParams {
- feedbagManager.EXPECT().
- Feedbag(matchContext(), params.screenName).
- Return(params.results, params.err)
- }
- for _, params := range tc.mockParams.feedbagUpsertParams {
- feedbagManager.EXPECT().
- FeedbagUpsert(matchContext(), params.screenName, params.items).
- Return(nil)
- }
- buddyBroadcaster := newMockbuddyBroadcaster(t)
- for _, params := range tc.mockParams.broadcastBuddyArrivedParams {
- buddyBroadcaster.EXPECT().
- BroadcastBuddyArrived(matchContext(), state.NewIdentScreenName(params.screenName.String()), mock.Anything).
- Return(params.err)
- }
- for _, params := range tc.mockParams.broadcastVisibilityParams {
- buddyBroadcaster.EXPECT().
- BroadcastVisibility(mock.Anything, matchSession(params.from), params.filter, params.doSendDepartures).
- Return(params.err)
- }
- contactPreAuth := newMockContactPreAuthorizer(t)
- for _, params := range tc.mockParams.recordPreAuthParams {
- contactPreAuth.EXPECT().
- RecordPreAuth(matchContext(), params.owner, params.buddy).
- Return(params.err)
- }
- svc := ICBMService{
- relationshipFetcher: relationshipFetcher,
- messageRelayer: messageRelayer,
- offlineMessageSaver: offlineMessageManager,
- sessionRetriever: sessionRetriever,
- timeNow: tc.timeNow,
- convoTracker: newConvoTracker(),
- feedbagManager: feedbagManager,
- contactPreAuthorizer: contactPreAuth,
- buddyBroadcaster: buddyBroadcaster,
- logger: discardLogger,
- }
- var forwardCalled bool
- svc.forwardICQAuthEvents = func(ctx context.Context, sender state.IdentScreenName, recipient state.IdentScreenName, authMsg wire.ICBMCh4Message) error {
- forwardCalled = true
- assert.Equal(t, tc.instance.IdentScreenName(), sender)
- assert.Equal(t, tc.expectForwardRecipient, recipient)
- assert.Equal(t, tc.expectForwardAuthMsg, authMsg)
- return nil
- }
- outputSNAC, err := svc.ChannelMsgToHost(context.Background(), tc.instance, tc.inputSNAC.Frame,
- tc.inputSNAC.Body.(wire.SNAC_0x04_0x06_ICBMChannelMsgToHost))
- assert.ErrorIs(t, err, tc.wantErr)
- assert.Equal(t, tc.expectOutput, outputSNAC)
- assert.Equal(t, tc.expectForwardICQAuthEvents, forwardCalled)
- })
- }
- }
- func TestICBMService_ClientEvent(t *testing.T) {
- cases := []struct {
- // name is the unit test name
- name string
- // senderScreenName is the screen name of the user sending the event
- senderScreenName state.DisplayScreenName
- // inputSNAC is the SNAC sent by the sender client
- inputSNAC wire.SNACMessage
- // mockParams is the list of params sent to mocks that satisfy this
- // method's dependencies
- mockParams mockParams
- // expectError indicates whether an error is expected
- expectError bool
- }{
- {
- name: "transmit typing event (event=2) from sender to recipient",
- senderScreenName: "sender-screen-name",
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMClientEvent,
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x14_ICBMClientEvent{
- Cookie: 12345678,
- ChannelID: 42,
- ScreenName: "sender-screen-name",
- Event: 2, // typing
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x14_ICBMClientEvent{
- Cookie: 12345678,
- ChannelID: 42,
- ScreenName: "recipient-screen-name",
- Event: 2, // typing
- },
- },
- },
- {
- name: "transmit text typed event (event=1) from sender to recipient",
- senderScreenName: "sender-screen-name",
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMClientEvent,
- RequestID: 5678,
- },
- Body: wire.SNAC_0x04_0x14_ICBMClientEvent{
- Cookie: 87654321,
- ChannelID: 1,
- ScreenName: "sender-screen-name",
- Event: 1, // text typed
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 5678,
- },
- Body: wire.SNAC_0x04_0x14_ICBMClientEvent{
- Cookie: 87654321,
- ChannelID: 1,
- ScreenName: "recipient-screen-name",
- Event: 1, // text typed
- },
- },
- },
- {
- name: "transmit stopped typing event (event=0) from sender to recipient",
- senderScreenName: "sender-screen-name",
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMClientEvent,
- RequestID: 9999,
- },
- Body: wire.SNAC_0x04_0x14_ICBMClientEvent{
- Cookie: 98765432,
- ChannelID: 5,
- ScreenName: "sender-screen-name",
- Event: 0, // stopped typing
- },
- },
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 9999,
- },
- Body: wire.SNAC_0x04_0x14_ICBMClientEvent{
- Cookie: 98765432,
- ChannelID: 5,
- ScreenName: "recipient-screen-name",
- Event: 0, // stopped typing
- },
- },
- },
- {
- name: "don't transmit typing event because sender has blocked recipient",
- senderScreenName: "sender-screen-name",
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: true,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{},
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x14_ICBMClientEvent{
- Cookie: 12345678,
- ChannelID: 42,
- ScreenName: "recipient-screen-name",
- Event: 2, // typing
- },
- },
- },
- {
- name: "don't transmit typing event because recipient has blocked sender",
- senderScreenName: "sender-screen-name",
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: true,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{},
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x14_ICBMClientEvent{
- Cookie: 12345678,
- ChannelID: 42,
- ScreenName: "recipient-screen-name",
- Event: 2, // typing
- },
- },
- },
- {
- name: "return error when relationship fetcher fails",
- senderScreenName: "sender-screen-name",
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{},
- err: errors.New("database connection failed"),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameActiveOnlyParams: relayToScreenNameActiveOnlyParams{},
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x14_ICBMClientEvent{
- Cookie: 12345678,
- ChannelID: 42,
- ScreenName: "recipient-screen-name",
- Event: 2, // typing
- },
- },
- expectError: true,
- },
- }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- relationshipFetcher := newMockRelationshipFetcher(t)
- for _, item := range tc.mockParams.relationshipParams {
- relationshipFetcher.EXPECT().
- Relationship(matchContext(), item.me, item.them).
- Return(item.result, item.err)
- }
- messageRelayer := newMockMessageRelayer(t)
- for _, item := range tc.mockParams.relayToScreenNameActiveOnlyParams {
- messageRelayer.EXPECT().
- RelayToScreenNameActiveOnly(matchContext(), item.screenName, item.message)
- }
- senderSession := newTestInstance(tc.senderScreenName)
- svc := ICBMService{
- relationshipFetcher: relationshipFetcher,
- messageRelayer: messageRelayer,
- }
- err := svc.ClientEvent(context.Background(), senderSession, tc.inputSNAC.Frame,
- tc.inputSNAC.Body.(wire.SNAC_0x04_0x14_ICBMClientEvent))
- if tc.expectError {
- assert.Error(t, err)
- } else {
- assert.NoError(t, err)
- }
- })
- }
- }
- func TestICBMService_EvilRequest(t *testing.T) {
- cases := []struct {
- // name is the unit test name
- name string
- // senderScreenName is the session of the user sending the EvilRequest
- instance *state.SessionInstance
- // msgsReceived is the # of messages received from the warned user
- msgsReceived int
- // inputSNAC is the SNAC sent by the sender client
- inputSNAC wire.SNACMessage
- // expectOutput is the SNAC sent from the server to client
- expectOutput wire.SNACMessage
- // mockParams is the list of params sent to mocks that satisfy this
- // method's dependencies
- mockParams mockParams
- // waitForWarnMsg indicates whether to wait for session warn signal
- waitForWarnMsg bool
- }{
- {
- name: "transmit anonymous warning from sender to recipient",
- instance: newTestInstance("sender-screen-name"),
- msgsReceived: 1,
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x08_ICBMEvilRequest{
- SendAs: 1, // make it anonymous
- ScreenName: "recipient-screen-name",
- },
- },
- expectOutput: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMEvilReply,
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x09_ICBMEvilReply{
- EvilDeltaApplied: 30,
- UpdatedEvilValue: 30,
- },
- },
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptCannedSignonTime).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameParams: relayToScreenNameParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.OService,
- SubGroup: wire.OServiceEvilNotification,
- },
- Body: wire.SNAC_0x01_0x10_OServiceEvilNotification{
- NewEvil: evilDeltaAnon,
- },
- },
- },
- },
- },
- },
- waitForWarnMsg: true,
- },
- {
- name: "transmit non-anonymous warning from sender to recipient",
- instance: newTestInstance("sender-screen-name", sessOptWarning(110)),
- msgsReceived: 1,
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x08_ICBMEvilRequest{
- SendAs: 0, // make it identified
- ScreenName: "recipient-screen-name",
- },
- },
- expectOutput: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMEvilReply,
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x09_ICBMEvilReply{
- EvilDeltaApplied: 100,
- UpdatedEvilValue: 100,
- },
- },
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptCannedSignonTime).Session(),
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToScreenNameParams: relayToScreenNameParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.OService,
- SubGroup: wire.OServiceEvilNotification,
- },
- Body: wire.SNAC_0x01_0x10_OServiceEvilNotification{
- NewEvil: evilDelta,
- Snitcher: &struct {
- wire.TLVUserInfo
- }{
- wire.TLVUserInfo{
- ScreenName: "sender-screen-name",
- WarningLevel: 110,
- },
- },
- },
- },
- },
- },
- },
- },
- waitForWarnMsg: true,
- },
- {
- name: "don't transmit non-anonymous warning from sender to recipient because sender has blocked recipient",
- instance: newTestInstance("sender-screen-name"),
- msgsReceived: 1,
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x08_ICBMEvilRequest{
- SendAs: 0, // make it identified
- ScreenName: "recipient-screen-name",
- },
- },
- expectOutput: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMErr,
- RequestID: 1234,
- },
- Body: wire.SNACError{
- Code: wire.ErrorCodeNotLoggedOn,
- },
- },
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: true,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- },
- },
- {
- name: "don't transmit non-anonymous warning from sender to recipient because recipient has blocked sender",
- instance: newTestInstance("sender-screen-name"),
- msgsReceived: 1,
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x08_ICBMEvilRequest{
- SendAs: 0, // make it identified
- ScreenName: "recipient-screen-name",
- },
- },
- expectOutput: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMErr,
- RequestID: 1234,
- },
- Body: wire.SNACError{
- Code: wire.ErrorCodeNotLoggedOn,
- },
- },
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: true,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- },
- },
- {
- name: "can't warn bots",
- instance: newTestInstance("sender-screen-name"),
- msgsReceived: 1,
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x08_ICBMEvilRequest{
- SendAs: 0, // make it identified
- ScreenName: "recipient-screen-name",
- },
- },
- expectOutput: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMErr,
- RequestID: 1234,
- },
- Body: wire.SNACError{
- Code: wire.ErrorCodeRequestDenied,
- },
- },
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: newTestInstance("recipient-screen-name", sessOptBot).Session(),
- },
- },
- },
- },
- },
- {
- name: "don't let users warn themselves",
- instance: newTestInstance("sender-screen-name"),
- msgsReceived: 1,
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x08_ICBMEvilRequest{
- SendAs: 0, // make it identified
- ScreenName: "sender-screen-name",
- },
- },
- expectOutput: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMErr,
- RequestID: 1234,
- },
- Body: wire.SNACError{
- Code: wire.ErrorCodeNotSupportedByHost,
- },
- },
- },
- {
- name: "don't transmit non-anonymous warning from sender to recipient because recipient is offline",
- instance: newTestInstance("sender-screen-name"),
- msgsReceived: 1,
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: nil,
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x08_ICBMEvilRequest{
- SendAs: 0, // make it identified
- ScreenName: "recipient-screen-name",
- },
- },
- expectOutput: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMErr,
- RequestID: 1234,
- },
- Body: wire.SNACError{
- Code: wire.ErrorCodeNotLoggedOn,
- },
- },
- },
- {
- name: "don't transmit anonymous warning from sender to recipient because recipient is offline",
- instance: newTestInstance("sender-screen-name"),
- msgsReceived: 1,
- mockParams: mockParams{
- relationshipFetcherParams: relationshipFetcherParams{
- relationshipParams: relationshipParams{
- {
- me: state.NewIdentScreenName("sender-screen-name"),
- them: state.NewIdentScreenName("recipient-screen-name"),
- result: state.Relationship{
- User: state.NewIdentScreenName("recipient-screen-name"),
- BlocksYou: false,
- YouBlock: false,
- IsOnTheirList: false,
- IsOnYourList: false,
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("recipient-screen-name"),
- result: nil,
- },
- },
- },
- },
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x08_ICBMEvilRequest{
- SendAs: 1, // make it anonymous
- ScreenName: "recipient-screen-name",
- },
- },
- expectOutput: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMErr,
- RequestID: 1234,
- },
- Body: wire.SNACError{
- Code: wire.ErrorCodeNotLoggedOn,
- },
- },
- },
- }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- relationshipFetcher := newMockRelationshipFetcher(t)
- for _, item := range tc.mockParams.relationshipParams {
- relationshipFetcher.EXPECT().
- Relationship(matchContext(), item.me, item.them).
- Return(item.result, item.err)
- }
- sessionRetriever := newMockSessionRetriever(t)
- for _, item := range tc.mockParams.retrieveSessionParams {
- sessionRetriever.EXPECT().
- RetrieveSession(item.screenName).
- Return(item.result)
- }
- messageRelayer := newMockMessageRelayer(t)
- for _, item := range tc.mockParams.relayToScreenNameParams {
- messageRelayer.EXPECT().
- RelayToScreenName(mock.Anything, item.screenName, item.message)
- }
- for _, item := range tc.mockParams.relayToScreenNameActiveOnlyParams {
- messageRelayer.EXPECT().
- RelayToScreenNameActiveOnly(mock.Anything, item.screenName, item.message)
- }
- offlineMessageManager := newMockOfflineMessageManager(t)
- for _, params := range tc.mockParams.saveMessageParams {
- offlineMessageManager.EXPECT().
- SaveMessage(matchContext(), params.offlineMessageIn).
- Return(params.countOut, params.err)
- }
- svc := ICBMService{
- relationshipFetcher: relationshipFetcher,
- messageRelayer: messageRelayer,
- offlineMessageSaver: offlineMessageManager,
- sessionRetriever: sessionRetriever,
- convoTracker: newConvoTracker(),
- snacRateLimits: wire.DefaultSNACRateLimits(),
- }
- for i := 0; i < tc.msgsReceived; i++ {
- svc.convoTracker.trackConvo(time.Now(),
- state.NewIdentScreenName(tc.inputSNAC.Body.(wire.SNAC_0x04_0x08_ICBMEvilRequest).ScreenName),
- tc.instance.IdentScreenName())
- }
- var wg sync.WaitGroup
- if tc.waitForWarnMsg {
- wg.Add(1)
- go func() {
- defer wg.Done()
- for _, sess := range tc.mockParams.retrieveSessionParams {
- <-sess.result.WarningCh()
- }
- }()
- }
- outputSNAC, err := svc.EvilRequest(context.Background(), tc.instance, tc.inputSNAC.Frame,
- tc.inputSNAC.Body.(wire.SNAC_0x04_0x08_ICBMEvilRequest))
- assert.NoError(t, err)
- assert.Equal(t, tc.expectOutput, outputSNAC)
- wg.Wait()
- })
- }
- }
- func TestICBMService_ParameterQuery(t *testing.T) {
- svc := NewICBMService(nil, nil, nil, nil, nil, nil, nil, nil, wire.DefaultSNACRateLimits(), slog.Default())
- have := svc.ParameterQuery(context.TODO(), wire.SNACFrame{RequestID: 1234})
- want := wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMParameterReply,
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x05_ICBMParameterReply{
- MaxSlots: 100,
- ICBMFlags: 3,
- MaxIncomingICBMLen: 512,
- MaxSourceEvil: 999,
- MaxDestinationEvil: 999,
- MinInterICBMInterval: 0,
- },
- }
- assert.Equal(t, want, have)
- }
- func TestICBMService_ClientErr(t *testing.T) {
- instance := newTestInstance("theScreenName")
- inBody := wire.SNAC_0x04_0x0B_ICBMClientErr{
- Cookie: 1234,
- ChannelID: wire.ICBMChannelMIME,
- ScreenName: "recipientScreenName",
- Code: 10,
- ErrInfo: []byte{1, 2, 3, 4},
- }
- expect := wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMClientErr,
- RequestID: 1234,
- },
- Body: wire.SNAC_0x04_0x0B_ICBMClientErr{
- Cookie: inBody.Cookie,
- ChannelID: inBody.ChannelID,
- ScreenName: instance.DisplayScreenName().String(),
- Code: inBody.Code,
- ErrInfo: inBody.ErrInfo,
- },
- }
- messageRelayer := newMockMessageRelayer(t)
- messageRelayer.EXPECT().
- RelayToScreenName(mock.Anything, state.NewIdentScreenName("recipientScreenName"), expect)
- svc := NewICBMService(nil, messageRelayer, nil, nil, nil, nil, nil, nil, wire.DefaultSNACRateLimits(), slog.Default())
- err := svc.ClientErr(context.Background(), instance, wire.SNACFrame{RequestID: 1234}, inBody)
- assert.NoError(t, err)
- }
- func TestICBMService_OfflineRetrieve(t *testing.T) {
- cases := []struct {
- // name is the unit test name
- name string
- // senderInstance is the session of the user retrieving messages
- senderInstance *state.SessionInstance
- // inputSNAC is the input frame (RequestID checked on reply)
- inputSNAC wire.SNACMessage
- // expectOutput is the expected return SNAC value.
- expectOutput wire.SNACMessage
- // wantErr is the expected error (nil for success)
- wantErr error
- // mockParams is the list of params sent to mocks that satisfy this method's dependencies
- mockParams mockParams
- }{
- {
- name: "relays stored messages and replies",
- senderInstance: newTestInstance("recipient"),
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{RequestID: 42},
- },
- expectOutput: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMOfflineRetrieveReply,
- RequestID: 42,
- },
- Body: wire.SNAC_0x04_0x17_ICBMOfflineRetrieveReply{},
- },
- wantErr: nil,
- mockParams: mockParams{
- offlineMessageManagerParams: offlineMessageManagerParams{
- retrieveMessagesParams: retrieveMessagesParams{
- {
- recipIn: state.NewIdentScreenName("recipient"),
- messagesOut: []state.OfflineMessage{
- {
- // The stored SNAC carries a send time the sender
- // supplied. TLVList lookups return the first
- // match, so it has to be dropped rather than
- // shadow the Sent stamp appended on replay.
- Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- Cookie: 1234,
- ChannelID: wire.ICBMChannelIM,
- TLVRestBlock: wire.TLVRestBlock{TLVList: []wire.TLV{
- wire.NewTLVBE(wire.ICBMTLVSendTime, uint32(1)),
- wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3}),
- }},
- },
- Recipient: state.NewIdentScreenName("recipient"),
- Sender: state.NewIdentScreenName("sender"),
- Sent: time.Unix(1700000000, 0).UTC(),
- },
- },
- },
- },
- deleteMessagesParams: deleteMessagesParams{
- {
- recipIn: state.NewIdentScreenName("recipient"),
- err: nil,
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToSelfParams: relayToSelfParams{
- {
- screenName: state.NewIdentScreenName("recipient"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: func() wire.SNAC_0x04_0x07_ICBMChannelMsgToClient {
- msg := wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- Cookie: 1234,
- ChannelID: wire.ICBMChannelIM,
- TLVUserInfo: wire.TLVUserInfo{
- ScreenName: "sender",
- },
- TLVRestBlock: wire.TLVRestBlock{},
- }
- msg.Append(wire.NewTLVBE(wire.ICBMTLVData, []byte{1, 2, 3}))
- msg.Append(wire.NewTLVBE(wire.ICBMTLVSendTime, uint32(time.Unix(1700000000, 0).UTC().Unix())))
- return msg
- }(),
- },
- },
- },
- },
- },
- },
- {
- name: "no stored messages returns reply without relays or deletes",
- senderInstance: newTestInstance("recipient"),
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{RequestID: 55},
- },
- expectOutput: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMOfflineRetrieveReply,
- RequestID: 55,
- },
- Body: wire.SNAC_0x04_0x17_ICBMOfflineRetrieveReply{},
- },
- wantErr: nil,
- mockParams: mockParams{
- offlineMessageManagerParams: offlineMessageManagerParams{
- retrieveMessagesParams: retrieveMessagesParams{
- {
- recipIn: state.NewIdentScreenName("recipient"),
- messagesOut: []state.OfflineMessage{},
- err: nil,
- },
- },
- deleteMessagesParams: deleteMessagesParams{},
- },
- messageRelayerParams: messageRelayerParams{
- relayToSelfParams: relayToSelfParams{},
- },
- },
- },
- {
- name: "delete messages error after relay",
- senderInstance: newTestInstance("recipient"),
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{RequestID: 99},
- },
- expectOutput: wire.SNACMessage{},
- wantErr: assert.AnError,
- mockParams: mockParams{
- offlineMessageManagerParams: offlineMessageManagerParams{
- retrieveMessagesParams: retrieveMessagesParams{
- {
- recipIn: state.NewIdentScreenName("recipient"),
- messagesOut: []state.OfflineMessage{
- {
- Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- Cookie: 4321,
- ChannelID: wire.ICBMChannelIM,
- TLVRestBlock: wire.TLVRestBlock{TLVList: []wire.TLV{wire.NewTLVBE(wire.ICBMTLVData, []byte{9, 8, 7})}},
- },
- Recipient: state.NewIdentScreenName("recipient"),
- Sender: state.NewIdentScreenName("sender"),
- Sent: time.Unix(1700001234, 0).UTC(),
- },
- },
- },
- },
- deleteMessagesParams: deleteMessagesParams{
- {
- recipIn: state.NewIdentScreenName("recipient"),
- err: assert.AnError,
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToSelfParams: relayToSelfParams{
- {
- screenName: state.NewIdentScreenName("recipient"),
- message: wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToClient,
- RequestID: wire.ReqIDFromServer,
- },
- Body: func() wire.SNAC_0x04_0x07_ICBMChannelMsgToClient {
- msg := wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- Cookie: 4321,
- ChannelID: wire.ICBMChannelIM,
- TLVUserInfo: wire.TLVUserInfo{
- ScreenName: "sender",
- },
- TLVRestBlock: wire.TLVRestBlock{},
- }
- msg.Append(wire.NewTLVBE(wire.ICBMTLVData, []byte{9, 8, 7}))
- msg.Append(wire.NewTLVBE(wire.ICBMTLVSendTime, uint32(time.Unix(1700001234, 0).UTC().Unix())))
- return msg
- }(),
- },
- },
- },
- },
- },
- },
- {
- name: "propagates retrieve error",
- senderInstance: newTestInstance("recipient"),
- inputSNAC: wire.SNACMessage{
- Frame: wire.SNACFrame{RequestID: 7},
- },
- expectOutput: wire.SNACMessage{},
- wantErr: assert.AnError,
- mockParams: mockParams{
- offlineMessageManagerParams: offlineMessageManagerParams{
- retrieveMessagesParams: retrieveMessagesParams{
- {
- recipIn: state.NewIdentScreenName("recipient"),
- messagesOut: nil,
- err: assert.AnError,
- },
- },
- },
- messageRelayerParams: messageRelayerParams{
- relayToSelfParams: relayToSelfParams{},
- },
- },
- },
- }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- offlineMessageManager := newMockOfflineMessageManager(t)
- for _, params := range tc.mockParams.retrieveMessagesParams {
- offlineMessageManager.EXPECT().
- RetrieveMessages(matchContext(), params.recipIn).
- Return(params.messagesOut, params.err)
- }
- for _, params := range tc.mockParams.deleteMessagesParams {
- offlineMessageManager.EXPECT().
- DeleteMessages(matchContext(), params.recipIn).
- Return(params.err)
- }
- messageRelayer := newMockMessageRelayer(t)
- for _, item := range tc.mockParams.relayToSelfParams {
- messageRelayer.EXPECT().
- RelayToSelf(mock.Anything, matchSession(item.screenName), item.message)
- }
- svc := ICBMService{
- messageRelayer: messageRelayer,
- offlineMessageManager: offlineMessageManager,
- }
- out, err := svc.OfflineRetrieve(context.Background(), tc.senderInstance, tc.inputSNAC.Frame)
- assert.Equal(t, tc.expectOutput, out)
- assert.ErrorIs(t, err, tc.wantErr)
- })
- }
- }
- func TestRingBuffer(t *testing.T) {
- t.Run("new ringBuffer should have zero values", func(t *testing.T) {
- rb := &ringBuffer{}
- // Test val() on empty ringBuffer - should return zero time
- result := rb.val()
- zeroTime := time.Time{}
- assert.Equal(t, zeroTime, result)
- })
- t.Run("val() should return current time", func(t *testing.T) {
- now := time.Now()
- rb := &ringBuffer{
- cur: 1,
- vals: [3]time.Time{
- now.Add(-2 * time.Hour),
- now.Add(-1 * time.Hour),
- now,
- },
- }
- result := rb.val()
- assert.Equal(t, rb.vals[1], result)
- })
- t.Run("set() should store time and advance cursor", func(t *testing.T) {
- rb := &ringBuffer{cur: 0}
- newTime := time.Now()
- // Set the time
- rb.set(newTime)
- // After set, cursor should advance to position 1
- // We can verify this by setting another time and checking that it's stored at position 1
- secondTime := time.Now().Add(time.Hour)
- rb.set(secondTime)
- // Now cursor should be at position 2, so val() should return the time at position 2
- // But since we only set 2 times, position 2 should still be the zero time
- zeroTime := time.Time{}
- assert.Equal(t, zeroTime, rb.val())
- })
- t.Run("set() should wrap around after reaching end of array", func(t *testing.T) {
- rb := &ringBuffer{cur: 2}
- newTime := time.Now()
- // Set the time at position 2
- rb.set(newTime)
- // Cursor should wrap around to position 0
- // We can verify this by setting another time and checking behavior
- rb.set(time.Now().Add(time.Hour))
- // Now cursor should be at position 1, so val() should return the time at position 1
- // But since we only set 2 times, position 1 should still be the zero time
- zeroTime := time.Time{}
- assert.Equal(t, zeroTime, rb.val())
- })
- t.Run("set() should handle multiple insertions correctly", func(t *testing.T) {
- rb := &ringBuffer{}
- // Insert 3 times
- time1 := time.Now()
- time2 := time.Now().Add(time.Hour)
- time3 := time.Now().Add(2 * time.Hour)
- rb.set(time1)
- rb.set(time2)
- rb.set(time3)
- // After 3 insertions, cursor should be at position 0
- // So val() should return the time at position 0
- // This should be time1 since it was the first time set
- assert.Equal(t, time1, rb.val())
- })
- t.Run("set() should overwrite existing values in order", func(t *testing.T) {
- rb := &ringBuffer{}
- // Set 3 times to fill the buffer
- rb.set(time.Now())
- rb.set(time.Now().Add(time.Hour))
- rb.set(time.Now().Add(2 * time.Hour))
- // After 3 sets, cursor is at position 0, val() returns first time
- firstTime := rb.val()
- assert.False(t, firstTime.IsZero())
- // Set a 4th time - should overwrite position 0
- fourthTime := time.Now().Add(3 * time.Hour)
- rb.set(fourthTime)
- // Now cursor is at position 1, val() returns second time
- secondTime := rb.val()
- assert.False(t, secondTime.IsZero())
- // Set a 5th time - should overwrite position 1
- fifthTime := time.Now().Add(4 * time.Hour)
- rb.set(fifthTime)
- // Now cursor is at position 2, val() returns third time
- thirdTime := rb.val()
- assert.False(t, thirdTime.IsZero())
- // Set a 6th time - should overwrite position 2
- sixthTime := time.Now().Add(5 * time.Hour)
- rb.set(sixthTime)
- // Now cursor wraps around to position 0, val() returns fourth time
- assert.Equal(t, fourthTime, rb.val())
- })
- t.Run("val() should return correct time after multiple operations", func(t *testing.T) {
- rb := &ringBuffer{}
- // Insert times and verify val() returns correct current time
- time1 := time.Now()
- time2 := time.Now().Add(time.Hour)
- rb.set(time1)
- rb.set(time2)
- // After 2 sets, cursor is at position 2
- // So val() should return the time at position 2
- // But since we only set 2 times, position 2 should still be the zero time
- zeroTime := time.Time{}
- assert.Equal(t, zeroTime, rb.val())
- // Set one more to wrap around
- time3 := time.Now().Add(2 * time.Hour)
- rb.set(time3)
- // Now cursor is at position 0, so val() should return the time at position 0
- // This should be time1
- assert.Equal(t, time1, rb.val())
- })
- t.Run("ringBuffer should maintain circular behavior over many operations", func(t *testing.T) {
- rb := &ringBuffer{}
- // Perform many operations to test circular behavior
- for i := 0; i < 10; i++ {
- rb.set(time.Now().Add(time.Duration(i) * time.Hour))
- }
- // After 10 operations, cursor should be at position 1 (10 % 3 = 1)
- // So val() should return the time at position 1
- // This should be the 8th time set (at position 1)
- // We can't compare exact times since they're set in a loop, so just verify it's not zero
- assert.False(t, rb.val().IsZero())
- // Set one more to advance cursor to position 2
- rb.set(time.Now().Add(10 * time.Hour))
- // Now cursor is at position 2, so val() should return the time at position 2
- // This should be the 9th time set (at position 2)
- assert.False(t, rb.val().IsZero())
- // Set one more to wrap around to position 0
- rb.set(time.Now().Add(11 * time.Hour))
- // Now cursor is at position 0, so val() should return the time at position 0
- // This should be the 10th time set (at position 0)
- assert.False(t, rb.val().IsZero())
- })
- t.Run("ringBuffer should cycle through all positions correctly", func(t *testing.T) {
- rb := &ringBuffer{}
- // Test cycling through all 3 positions
- times := []time.Time{
- time.Now(),
- time.Now().Add(time.Hour),
- time.Now().Add(2 * time.Hour),
- }
- // Set all 3 times
- for _, t := range times {
- rb.set(t)
- }
- // After 3 sets, cursor should be at position 0
- // So val() should return the time at position 0
- assert.Equal(t, times[0], rb.val())
- // Set one more to advance cursor to position 1
- nextTime := time.Now().Add(3 * time.Hour)
- rb.set(nextTime)
- // Now cursor is at position 1, so val() should return the time at position 1
- // This should be the second time since it was stored at position 1
- assert.Equal(t, times[1], rb.val())
- })
- }
- func TestConvoTracker(t *testing.T) {
- ct := newConvoTracker()
- sender := state.NewIdentScreenName("sender")
- recip := state.NewIdentScreenName("recipient")
- now := time.Now()
- // can't warn until a message is sent
- assert.False(t, ct.trackWarn(now, recip, sender))
- // can warn 1st time
- ct.trackConvo(now, sender, recip)
- assert.True(t, ct.trackWarn(now, recip, sender))
- // can't warn 2nd time until 2nd message is sent
- assert.False(t, ct.trackWarn(now, recip, sender))
- // can warn 2nd time
- now = now.Add(1 * time.Second)
- ct.trackConvo(now, sender, recip)
- assert.True(t, ct.trackWarn(now, recip, sender))
- // can't warn 3rd time until 3rd message is sent
- assert.False(t, ct.trackWarn(now, recip, sender))
- // can warn 3rd time
- now = now.Add(1 * time.Second)
- ct.trackConvo(now, sender, recip)
- assert.True(t, ct.trackWarn(now, recip, sender))
- // can't warn 4th time
- now = now.Add(1 * time.Second)
- ct.trackConvo(now, sender, recip)
- assert.False(t, ct.trackWarn(now, recip, sender))
- // let an hour pass, we should be able to warn again
- now = now.Add(1 * time.Hour)
- ct.trackConvo(now, sender, recip)
- assert.True(t, ct.trackWarn(now, recip, sender))
- }
- func TestICBMService_UpdateWarnLevel(t *testing.T) {
- t.Run("happy path", func(t *testing.T) {
- now := time.Now()
- instance := newTestInstance("screen-name")
- warnCh := make(chan uint16)
- mockBuddyBroadcaster := newMockbuddyBroadcaster(t)
- mockBuddyBroadcaster.EXPECT().
- BroadcastBuddyArrived(mock.Anything, instance.IdentScreenName(), mock.MatchedBy(func(userInfo wire.TLVUserInfo) bool {
- return userInfo.ScreenName == instance.IdentScreenName().String()
- })).
- Run(func(ctx context.Context, screenName state.IdentScreenName, userInfo wire.TLVUserInfo) {
- warnCh <- userInfo.WarningLevel
- }).Return(nil)
- u := &state.User{}
- userManager := newMockUserManager(t)
- userManager.EXPECT().
- User(matchContext(), instance.IdentScreenName()).
- Return(u, nil)
- userManager.EXPECT().
- SetWarnLevel(matchContext(), instance.IdentScreenName(), now, uint16(100)).
- Return(nil)
- userManager.EXPECT().
- SetWarnLevel(matchContext(), instance.IdentScreenName(), now, uint16(50)).
- Return(nil)
- userManager.EXPECT().
- SetWarnLevel(matchContext(), instance.IdentScreenName(), now, uint16(30)).
- Return(nil)
- userManager.EXPECT().
- SetWarnLevel(matchContext(), instance.IdentScreenName(), now, uint16(0)).
- Return(nil)
- svc := ICBMService{
- buddyBroadcaster: mockBuddyBroadcaster,
- interval: 1 * time.Millisecond,
- logger: slog.Default(),
- snacRateLimits: wire.DefaultSNACRateLimits(),
- timeNow: func() time.Time { return now },
- userManager: userManager,
- }
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
- var wg sync.WaitGroup
- wg.Add(1)
- go func() {
- defer wg.Done()
- svc.UpdateWarnLevel(ctx, instance) // do a sync test here?
- }()
- ok, _ := instance.Session().ScaleWarningAndRateLimit(100, 3)
- assert.True(t, ok)
- assert.Equal(t, uint16(100), <-warnCh)
- assert.Equal(t, uint16(50), <-warnCh)
- assert.Equal(t, uint16(0), <-warnCh)
- ok, _ = instance.Session().ScaleWarningAndRateLimit(100, 3)
- assert.True(t, ok)
- assert.Equal(t, uint16(100), <-warnCh)
- assert.Equal(t, uint16(50), <-warnCh)
- assert.Equal(t, uint16(0), <-warnCh)
- instance.Session().ScaleWarningAndRateLimit(30, 3)
- assert.Equal(t, uint16(30), <-warnCh)
- assert.Equal(t, uint16(0), <-warnCh)
- cancel()
- wg.Wait()
- })
- }
- func TestICBMService_RestoreWarningLevel(t *testing.T) {
- tests := []struct {
- name string
- lastWarnUpdate time.Duration
- lastWarnLevel uint16
- expectedWarn uint16
- }{
- {
- name: "decays warning when last update is before interval boundary",
- lastWarnUpdate: -15*time.Millisecond - 1*time.Millisecond,
- lastWarnLevel: 250,
- expectedWarn: 100,
- },
- {
- name: "decays warning when last update is after interval boundary",
- lastWarnUpdate: -15*time.Millisecond + 1*time.Millisecond,
- lastWarnLevel: 250,
- expectedWarn: 150,
- },
- {
- name: "decays warning when last update is exactly on interval boundary",
- lastWarnUpdate: -15 * time.Millisecond,
- lastWarnLevel: 250,
- expectedWarn: 100,
- },
- {
- name: "resets warning to zero when time is exactly at decay period",
- lastWarnUpdate: -25 * time.Millisecond,
- lastWarnLevel: 250,
- expectedWarn: 0,
- },
- {
- name: "resets warning to zero when time far decay period",
- lastWarnUpdate: -1 * time.Second,
- lastWarnLevel: 250,
- expectedWarn: 0,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- now := time.Now()
- instance := newTestInstance("screen-name")
- u := &state.User{
- LastWarnUpdate: now.Add(tt.lastWarnUpdate),
- LastWarnLevel: tt.lastWarnLevel,
- }
- userManager := newMockUserManager(t)
- userManager.EXPECT().
- User(matchContext(), instance.IdentScreenName()).
- Return(u, nil)
- svc := ICBMService{
- logger: slog.Default(),
- interval: 5 * time.Millisecond,
- snacRateLimits: wire.DefaultSNACRateLimits(),
- timeNow: func() time.Time { return now },
- userManager: userManager,
- }
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
- statesBefore := instance.RateLimitStates()
- err := svc.RestoreWarningLevel(ctx, instance)
- assert.NoError(t, err)
- assert.Equal(t, tt.expectedWarn, instance.Warning())
- statesAfter := instance.RateLimitStates()
- if tt.expectedWarn > 0 {
- // make sure the rate limits changed
- assert.NotEqual(t, statesBefore, statesAfter)
- } else {
- // make sure the rate limits have been restored
- assert.Equal(t, statesBefore, statesAfter)
- }
- })
- }
- }
- func TestICBMService_RestoreWarningLevel_ErrorCases(t *testing.T) {
- t.Run("user does not exist", func(t *testing.T) {
- instance := newTestInstance("screen-name")
- userManager := newMockUserManager(t)
- userManager.EXPECT().
- User(matchContext(), instance.IdentScreenName()).
- Return(nil, nil)
- svc := ICBMService{
- logger: slog.Default(),
- interval: 5 * time.Millisecond,
- snacRateLimits: wire.DefaultSNACRateLimits(),
- timeNow: time.Now,
- userManager: userManager,
- }
- err := svc.RestoreWarningLevel(context.Background(), instance)
- assert.ErrorIs(t, err, state.ErrNoUser)
- })
- t.Run("user manager returns error", func(t *testing.T) {
- instance := newTestInstance("screen-name")
- expectedErr := errors.New("database connection failed")
- userManager := newMockUserManager(t)
- userManager.EXPECT().
- User(matchContext(), instance.IdentScreenName()).
- Return(nil, expectedErr)
- svc := ICBMService{
- logger: slog.Default(),
- interval: 5 * time.Millisecond,
- snacRateLimits: wire.DefaultSNACRateLimits(),
- timeNow: time.Now,
- userManager: userManager,
- }
- err := svc.RestoreWarningLevel(context.Background(), instance)
- assert.Error(t, err)
- // When user is nil, it returns ErrNoUser regardless of the error
- assert.ErrorIs(t, err, expectedErr)
- })
- t.Run("user exists with zero warning level", func(t *testing.T) {
- instance := newTestInstance("screen-name")
- u := &state.User{
- LastWarnUpdate: time.Now().Add(-10 * time.Millisecond),
- LastWarnLevel: 0, // No warning level
- }
- userManager := newMockUserManager(t)
- userManager.EXPECT().
- User(matchContext(), instance.IdentScreenName()).
- Return(u, nil)
- svc := ICBMService{
- logger: slog.Default(),
- interval: 5 * time.Millisecond,
- snacRateLimits: wire.DefaultSNACRateLimits(),
- timeNow: time.Now,
- userManager: userManager,
- }
- err := svc.RestoreWarningLevel(context.Background(), instance)
- assert.NoError(t, err)
- assert.Equal(t, uint16(0), instance.Warning())
- })
- }
- func Test_calcWarningLevelChange(t *testing.T) {
- t.Run("active warn level, last modified between intervals", func(t *testing.T) {
- now := time.Now()
- interval := 5 * time.Millisecond
- lastWarn := now.Add(-15 * time.Millisecond).Add(-1 * time.Millisecond)
- warnDelta := calcElapsedWarningLevel(lastWarn, now, interval)
- assert.Equal(t, int16(-150), warnDelta)
- })
- t.Run("active warn level, last modified between intervals", func(t *testing.T) {
- now := time.Now()
- interval := 5 * time.Millisecond
- lastWarn := now.Add(-15 * time.Millisecond).Add(1 * time.Millisecond)
- warnDelta := calcElapsedWarningLevel(lastWarn, now, interval)
- assert.Equal(t, int16(-100), warnDelta)
- })
- t.Run("active warn level, last modified exactly on interval", func(t *testing.T) {
- now := time.Now()
- interval := 5 * time.Millisecond
- lastWarn := now.Add(-15 * time.Millisecond)
- warnDelta := calcElapsedWarningLevel(lastWarn, now, interval)
- assert.Equal(t, int16(-150), warnDelta)
- })
- t.Run("resolved warn level", func(t *testing.T) {
- now := time.Now()
- interval := 5 * time.Millisecond
- lastWarn := now.Add(-25 * time.Millisecond)
- warnDelta := calcElapsedWarningLevel(lastWarn, now, interval)
- assert.Equal(t, int16(-250), warnDelta)
- })
- t.Run("resolved warn level - time past exceeds maximum window", func(t *testing.T) {
- now := time.Now()
- interval := 5 * time.Millisecond
- lastWarn := now.Add(-200 * time.Millisecond)
- warnDelta := calcElapsedWarningLevel(lastWarn, now, interval)
- assert.Equal(t, int16(-2000), warnDelta)
- })
- }
- func Test_calcRefreshInterval(t *testing.T) {
- t.Run("active warn level, last modified between intervals", func(t *testing.T) {
- now := time.Now()
- interval := 5 * time.Millisecond
- lastWarn := now.Add(-15 * time.Millisecond).Add(-1 * time.Millisecond)
- newInterval := timeTillNextInterval(lastWarn, now, interval)
- assert.Equal(t, 4*time.Millisecond, newInterval)
- })
- t.Run("active warn level, last modified between intervals", func(t *testing.T) {
- now := time.Now()
- interval := 5 * time.Millisecond
- lastWarn := now.Add(-15 * time.Millisecond).Add(1 * time.Millisecond)
- newInterval := timeTillNextInterval(lastWarn, now, interval)
- assert.Equal(t, 1*time.Millisecond, newInterval)
- })
- t.Run("active warn level, last modified exactly on interval", func(t *testing.T) {
- now := time.Now()
- interval := 5 * time.Millisecond
- lastWarn := now.Add(-15 * time.Millisecond)
- newInterval := timeTillNextInterval(lastWarn, now, interval)
- assert.Equal(t, 5*time.Millisecond, newInterval)
- })
- t.Run("resolved warn level", func(t *testing.T) {
- now := time.Now()
- interval := 5 * time.Millisecond
- lastWarn := now.Add(-25 * time.Millisecond)
- newInterval := timeTillNextInterval(lastWarn, now, interval)
- assert.Equal(t, interval, newInterval)
- })
- t.Run("resolved warn level - time past exceeds maximum window", func(t *testing.T) {
- now := time.Now()
- interval := 5 * time.Millisecond
- lastWarn := now.Add(-200 * time.Millisecond)
- newInterval := timeTillNextInterval(lastWarn, now, interval)
- assert.Equal(t, interval, newInterval)
- })
- }
- func TestStripHTML(t *testing.T) {
- tests := []struct {
- name string
- input []byte
- expected []byte
- }{
- {
- name: "simple HTML tags",
- input: []byte("<HTML><BODY>Hello World</BODY></HTML>"),
- expected: []byte("Hello World"),
- },
- {
- name: "BR tag to newline",
- input: []byte("Line 1<BR>Line 2"),
- expected: []byte("Line 1\nLine 2"),
- },
- {
- name: "lowercase br tag",
- input: []byte("Line 1<br>Line 2"),
- expected: []byte("Line 1\nLine 2"),
- },
- {
- name: "self-closing br tag",
- input: []byte("Line 1<br/>Line 2"),
- expected: []byte("Line 1\nLine 2"),
- },
- {
- name: "HTML entities",
- input: []byte("<test> & "quoted""),
- expected: []byte("<test> & \"quoted\""),
- },
- {
- name: "FONT tags with attributes",
- input: []byte(`<FONT FACE="Arial" SIZE="3">Text</FONT>`),
- expected: []byte("Text"),
- },
- {
- name: "mixed formatting",
- input: []byte("<HTML><BODY><B>Bold</B> <I>Italic</I></BODY></HTML>"),
- expected: []byte("Bold Italic"),
- },
- {
- name: "plain text unchanged",
- input: []byte("Hello World"),
- expected: []byte("Hello World"),
- },
- {
- name: "empty input",
- input: []byte(""),
- expected: []byte(""),
- },
- {
- name: "nbsp entity",
- input: []byte("Hello World"),
- expected: []byte("Hello\u00a0World"),
- },
- {
- name: "realistic HTML message",
- input: []byte(`<HTML><BODY dir="ltr"><FONT color="#000000" size="2" face="Arial">Hello</FONT></BODY></HTML>`),
- expected: []byte("Hello"),
- },
- {
- name: "apos entity",
- input: []byte("it's working"),
- expected: []byte("it's working"),
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- result := stripHTML(tt.input)
- assert.Equal(t, tt.expected, result)
- })
- }
- }
|