| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052 |
- package icq_legacy
- import (
- "context"
- "log/slog"
- "strconv"
- "testing"
- "time"
- "github.com/mk6i/open-oscar-server/config"
- "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 TestICQLegacyService_AuthenticateUser(t *testing.T) {
- password := "secret123"
- authCookie := []byte("auth-cookie")
- screenName := state.DisplayScreenName("12345")
- serverCookie := state.ServerCookie{ScreenName: screenName}
- oscarSession := newTestOSCARInstance(screenName)
- successBlock := wire.TLVRestBlock{
- TLVList: []wire.TLV{
- wire.NewTLVBE(wire.LoginTLVTagsAuthorizationCookie, authCookie),
- },
- }
- tests := []struct {
- name string
- setupAuth func(*mockAuthService)
- req AuthRequest
- wantResult *AuthResult
- wantErr error
- }{
- {
- name: "valid credentials",
- req: AuthRequest{
- UIN: 12345,
- Password: password,
- Version: ICQLegacyVersionV5,
- },
- setupAuth: func(authSvc *mockAuthService) {
- authSvc.EXPECT().FLAPLogin(mock.Anything, mock.Anything, config.Endpoint{}).
- Return(successBlock, nil)
- authSvc.EXPECT().CrackCookie(authCookie).
- Return(serverCookie, nil)
- authSvc.EXPECT().RegisterBOSSession(mock.Anything, serverCookie, mock.Anything).
- Return(oscarSession, nil)
- },
- wantResult: &AuthResult{
- Success: true,
- ErrorCode: 0,
- },
- },
- {
- name: "bad password",
- req: AuthRequest{
- UIN: 12345,
- Password: "wrongpass",
- Version: ICQLegacyVersionV5,
- },
- setupAuth: func(authSvc *mockAuthService) {
- authSvc.EXPECT().FLAPLogin(mock.Anything, mock.Anything, config.Endpoint{}).
- Return(wire.TLVRestBlock{
- TLVList: []wire.TLV{
- wire.NewTLVBE(wire.LoginTLVTagsErrorSubcode, wire.LoginErrInvalidPassword),
- },
- }, nil)
- },
- wantResult: &AuthResult{
- Success: false,
- ErrorCode: 0x0001,
- },
- },
- {
- name: "user not found",
- req: AuthRequest{
- UIN: 99999,
- Password: password,
- Version: ICQLegacyVersionV5,
- },
- setupAuth: func(authSvc *mockAuthService) {
- authSvc.EXPECT().FLAPLogin(mock.Anything, mock.Anything, config.Endpoint{}).
- Return(wire.TLVRestBlock{
- TLVList: []wire.TLV{
- wire.NewTLVBE(wire.LoginTLVTagsErrorSubcode, wire.LoginErrICQUserErr),
- },
- }, nil)
- },
- wantResult: &AuthResult{
- Success: false,
- ErrorCode: 0x0002,
- },
- },
- {
- name: "missing UIN (UIN=0)",
- req: AuthRequest{
- UIN: 0,
- Password: password,
- },
- wantResult: &AuthResult{
- Success: false,
- ErrorCode: 0x0002,
- },
- },
- {
- name: "no password hash",
- req: AuthRequest{
- UIN: 12345,
- Password: password,
- Version: ICQLegacyVersionV5,
- },
- setupAuth: func(authSvc *mockAuthService) {
- authSvc.EXPECT().FLAPLogin(mock.Anything, mock.Anything, config.Endpoint{}).
- Return(wire.TLVRestBlock{
- TLVList: []wire.TLV{
- wire.NewTLVBE(wire.LoginTLVTagsErrorSubcode, wire.LoginErrInvalidPassword),
- },
- }, nil)
- },
- wantResult: &AuthResult{
- Success: false,
- ErrorCode: 0x0001,
- },
- },
- }
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- authSvc := newMockAuthService(t)
- if tc.setupAuth != nil {
- tc.setupAuth(authSvc)
- }
- svc := NewICQLegacyService(
- authSvc,
- newMockUserManager(t),
- newMockAccountManager(t),
- newMockSessionRetriever(t),
- newMockMessageRelayer(t),
- newMockBuddyBroadcaster(t),
- newMockOfflineMessageManager(t),
- newMockICQUserFinder(t),
- newMockICQUserUpdater(t),
- newMockFeedbagManager(t),
- newMockRelationshipFetcher(t),
- newMockBuddyListRegistry(t),
- newMockBuddyService(t),
- newMockICBMService(t),
- &LegacySessionManager{sessions: map[uint32]*LegacySession{}},
- slog.Default(),
- )
- got, err := svc.AuthenticateUser(context.Background(), tc.req)
- if tc.wantErr != nil {
- assert.ErrorIs(t, err, tc.wantErr)
- return
- }
- assert.NoError(t, err)
- assert.Equal(t, tc.wantResult.Success, got.Success)
- assert.Equal(t, tc.wantResult.ErrorCode, got.ErrorCode)
- if tc.wantResult.Success {
- assert.NotEmpty(t, got.SessionID)
- assert.Same(t, oscarSession, got.oscarSession)
- }
- })
- }
- }
- func TestICQLegacyService_ProcessMessage(t *testing.T) {
- tests := []struct {
- name string
- sess *LegacySession
- mockParams mockParams
- req MessageRequest
- wantResult *MessageResult
- wantErr error
- legacyMgr *LegacySessionManager
- }{
- {
- name: "target online - legacy session exists",
- req: MessageRequest{
- FromUIN: 11111,
- ToUIN: 22222,
- MsgType: ICQLegacyMsgText,
- Message: "hello",
- },
- legacyMgr: &LegacySessionManager{
- sessions: map[uint32]*LegacySession{
- 22222: newTestLegacySession(22222),
- },
- },
- wantResult: &MessageResult{
- Delivered: true,
- StoredOffline: false,
- TargetOnline: true,
- TargetVersion: ICQLegacyVersionV5,
- },
- },
- {
- name: "target online - OSCAR session",
- sess: newTestLegacySession(11111, legacySessionOptOSCARSess),
- req: MessageRequest{
- FromUIN: 11111,
- ToUIN: 22222,
- MsgType: ICQLegacyMsgText,
- Message: "hello from legacy",
- },
- mockParams: mockParams{
- icbmFoodgroupParams: icbmFoodgroupParams{
- channelMsgToHostParams: channelMsgToHostParams{
- {
- screenName: state.NewIdentScreenName("11111"),
- inFrame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToHost,
- },
- inBody: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelICQ,
- ScreenName: "22222",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVLE(wire.ICBMTLVData, wire.ICBMCh4Message{
- UIN: 11111,
- MessageType: wire.ICBMMsgTypePlain,
- Message: "hello from legacy",
- }),
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- },
- },
- },
- },
- },
- },
- },
- wantResult: &MessageResult{
- Delivered: true,
- StoredOffline: false,
- TargetOnline: true,
- TargetVersion: 0,
- },
- legacyMgr: &LegacySessionManager{sessions: map[uint32]*LegacySession{}},
- },
- {
- name: "target offline - stored",
- sess: newTestLegacySession(11111, legacySessionOptOSCARSess),
- req: MessageRequest{
- FromUIN: 11111,
- ToUIN: 22222,
- MsgType: ICQLegacyMsgText,
- Message: "offline msg",
- },
- mockParams: mockParams{
- icbmFoodgroupParams: icbmFoodgroupParams{
- channelMsgToHostParams: channelMsgToHostParams{
- {
- screenName: state.NewIdentScreenName("11111"),
- inFrame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMChannelMsgToHost,
- },
- inBody: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelICQ,
- ScreenName: "22222",
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVLE(wire.ICBMTLVData, wire.ICBMCh4Message{
- UIN: 11111,
- MessageType: wire.ICBMMsgTypePlain,
- Message: "offline msg",
- }),
- wire.NewTLVBE(wire.ICBMTLVStore, []byte{}),
- },
- },
- },
- result: &wire.SNACMessage{
- Frame: wire.SNACFrame{
- FoodGroup: wire.ICBM,
- SubGroup: wire.ICBMErr,
- },
- Body: wire.SNACError{
- Code: wire.ErrorCodeNotLoggedOn,
- },
- },
- },
- },
- },
- },
- wantResult: &MessageResult{
- Delivered: false,
- StoredOffline: true,
- TargetOnline: false,
- TargetVersion: 0,
- },
- legacyMgr: &LegacySessionManager{sessions: map[uint32]*LegacySession{}},
- },
- {
- name: "invalid sender UIN (0)",
- req: MessageRequest{
- FromUIN: 0,
- ToUIN: 22222,
- MsgType: ICQLegacyMsgText,
- Message: "hello",
- },
- wantResult: &MessageResult{
- Delivered: false,
- StoredOffline: false,
- TargetOnline: false,
- },
- legacyMgr: &LegacySessionManager{sessions: map[uint32]*LegacySession{}},
- },
- {
- name: "invalid target UIN (0)",
- req: MessageRequest{
- FromUIN: 11111,
- ToUIN: 0,
- MsgType: ICQLegacyMsgText,
- Message: "hello",
- },
- wantResult: &MessageResult{
- Delivered: false,
- StoredOffline: false,
- TargetOnline: false,
- },
- legacyMgr: &LegacySessionManager{sessions: map[uint32]*LegacySession{}},
- },
- }
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- icbmSvc := newMockICBMService(t)
- for _, msg := range tc.mockParams.channelMsgToHostParams {
- icbmSvc.EXPECT().
- ChannelMsgToHost(matchContext(), matchSession(msg.screenName), msg.inFrame, msg.inBody).
- Return(msg.result, msg.err)
- }
- svc := NewICQLegacyService(
- newMockAuthService(t),
- newMockUserManager(t),
- newMockAccountManager(t),
- newMockSessionRetriever(t),
- newMockMessageRelayer(t),
- newMockBuddyBroadcaster(t),
- newMockOfflineMessageManager(t),
- newMockICQUserFinder(t),
- newMockICQUserUpdater(t),
- newMockFeedbagManager(t),
- newMockRelationshipFetcher(t),
- newMockBuddyListRegistry(t),
- newMockBuddyService(t),
- icbmSvc,
- tc.legacyMgr,
- slog.Default(),
- )
- got, err := svc.ProcessMessage(context.Background(), tc.sess, tc.req)
- if tc.wantErr != nil {
- assert.ErrorIs(t, err, tc.wantErr)
- return
- }
- assert.NoError(t, err)
- assert.Equal(t, tc.wantResult.Delivered, got.Delivered)
- assert.Equal(t, tc.wantResult.StoredOffline, got.StoredOffline)
- assert.Equal(t, tc.wantResult.TargetOnline, got.TargetOnline)
- assert.Equal(t, tc.wantResult.TargetVersion, got.TargetVersion)
- })
- }
- }
- func TestICQLegacyService_ProcessContactList(t *testing.T) {
- tests := []struct {
- name string
- mockParams mockParams
- req ContactListRequest
- legacyMgr *LegacySessionManager
- wantResult *ContactListResult
- }{
- {
- name: "mixed online/offline contacts",
- req: ContactListRequest{
- UIN: 11111,
- Contacts: []uint32{22222, 33333},
- },
- mockParams: mockParams{
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams: retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("22222"),
- result: nil, // not on OSCAR either
- },
- {
- screenName: state.NewIdentScreenName("33333"),
- result: &state.Session{}, // online via OSCAR
- },
- },
- },
- },
- legacyMgr: &LegacySessionManager{
- sessions: make(map[uint32]*LegacySession),
- },
- wantResult: &ContactListResult{
- OnlineContacts: []ContactStatus{
- {UIN: 22222, Online: false, Status: 0},
- {UIN: 33333, Online: true, Status: ICQLegacyStatusOnline},
- },
- },
- },
- {
- name: "empty list",
- req: ContactListRequest{
- UIN: 11111,
- Contacts: []uint32{},
- },
- legacyMgr: &LegacySessionManager{sessions: map[uint32]*LegacySession{}},
- wantResult: &ContactListResult{
- OnlineContacts: []ContactStatus{},
- },
- },
- }
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- sessionRetriever := newMockSessionRetriever(t)
- for _, p := range tc.mockParams.retrieveSessionParams {
- sessionRetriever.EXPECT().
- RetrieveSession(p.screenName).
- Return(p.result)
- }
- buddySvc := newMockBuddyService(t)
- userFinder := newMockICQUserFinder(t)
- // ProcessContactList adds both forward and reverse buddy entries
- buddySvc.EXPECT().
- AddBuddies(mock.Anything, mock.Anything, mock.Anything, mock.Anything).
- Return(nil, nil).
- Maybe()
- userFinder.EXPECT().
- FindByUIN(mock.Anything, mock.Anything).
- Return(state.User{}, nil).
- Maybe()
- svc := NewICQLegacyService(
- newMockAuthService(t),
- newMockUserManager(t),
- newMockAccountManager(t),
- sessionRetriever,
- newMockMessageRelayer(t),
- newMockBuddyBroadcaster(t),
- newMockOfflineMessageManager(t),
- userFinder,
- newMockICQUserUpdater(t),
- newMockFeedbagManager(t),
- newMockRelationshipFetcher(t),
- newMockBuddyListRegistry(t),
- buddySvc,
- newMockICBMService(t),
- tc.legacyMgr,
- slog.Default(),
- )
- var instance *state.SessionInstance
- if tc.req.UIN != 0 {
- instance = newTestOSCARInstance(state.DisplayScreenName(strconv.FormatUint(uint64(tc.req.UIN), 10)))
- }
- got, err := svc.ProcessContactList(context.Background(), instance, tc.req)
- assert.NoError(t, err)
- assert.Equal(t, len(tc.wantResult.OnlineContacts), len(got.OnlineContacts))
- for i, want := range tc.wantResult.OnlineContacts {
- assert.Equal(t, want.UIN, got.OnlineContacts[i].UIN)
- assert.Equal(t, want.Online, got.OnlineContacts[i].Online)
- if want.Online {
- assert.Equal(t, want.Status, got.OnlineContacts[i].Status)
- }
- }
- })
- }
- }
- func TestICQLegacyService_ProcessStatusChange(t *testing.T) {
- tests := []struct {
- name string
- mockParams mockParams
- req StatusChangeRequest
- legacyMgr *LegacySessionManager
- wantTargets int
- }{
- {
- name: "status change with notification targets",
- req: StatusChangeRequest{
- UIN: 11111,
- OldStatus: ICQLegacyStatusOnline,
- NewStatus: ICQLegacyStatusAway,
- },
- legacyMgr: &LegacySessionManager{
- sessions: map[uint32]*LegacySession{
- 11111: newTestLegacySession(11111, legacySessionOptContactList([]uint32{22222})),
- 22222: newTestLegacySession(22222, legacySessionOptContactList([]uint32{11111})),
- },
- },
- wantTargets: 1,
- },
- {
- name: "no targets - session not found",
- req: StatusChangeRequest{
- UIN: 99999,
- OldStatus: ICQLegacyStatusOnline,
- NewStatus: ICQLegacyStatusAway,
- },
- legacyMgr: &LegacySessionManager{sessions: map[uint32]*LegacySession{}},
- wantTargets: 0,
- },
- }
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- svc := NewICQLegacyService(
- newMockAuthService(t),
- newMockUserManager(t),
- newMockAccountManager(t),
- newMockSessionRetriever(t),
- newMockMessageRelayer(t),
- newMockBuddyBroadcaster(t),
- newMockOfflineMessageManager(t),
- newMockICQUserFinder(t),
- newMockICQUserUpdater(t),
- newMockFeedbagManager(t),
- newMockRelationshipFetcher(t),
- newMockBuddyListRegistry(t),
- newMockBuddyService(t),
- newMockICBMService(t),
- tc.legacyMgr,
- slog.Default(),
- )
- got, err := svc.ProcessStatusChange(context.Background(), tc.req)
- assert.NoError(t, err)
- assert.Len(t, got.NotifyTargets, tc.wantTargets)
- })
- }
- }
- func TestICQLegacyService_SearchByUIN(t *testing.T) {
- tests := []struct {
- name string
- mockParams mockParams
- uin uint32
- wantResult *LegacyUserSearchResult
- wantErr bool
- }{
- {
- name: "found",
- uin: 12345,
- mockParams: mockParams{
- icqUserFinderParams: icqUserFinderParams{
- findByUINParams: findByUINParams{
- {
- UIN: 12345,
- result: state.User{
- IdentScreenName: state.NewIdentScreenName("12345"),
- ICQInfo: state.ICQInfo{
- Basic: state.ICQBasicInfo{
- Nickname: "CoolUser",
- FirstName: "John",
- LastName: "Doe",
- EmailAddress: "john@example.com",
- },
- },
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams: retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("12345"),
- result: nil,
- },
- },
- },
- },
- wantResult: &LegacyUserSearchResult{
- UIN: 12345,
- Nickname: "CoolUser",
- FirstName: "John",
- LastName: "Doe",
- Email: "john@example.com",
- },
- },
- {
- name: "not found",
- uin: 99999,
- mockParams: mockParams{
- icqUserFinderParams: icqUserFinderParams{
- findByUINParams: findByUINParams{
- {
- UIN: 99999,
- err: state.ErrNoUser,
- },
- },
- },
- },
- wantErr: true,
- },
- }
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- userFinder := newMockICQUserFinder(t)
- for _, p := range tc.mockParams.findByUINParams {
- userFinder.EXPECT().
- FindByUIN(matchContext(), p.UIN).
- Return(p.result, p.err)
- }
- sessionRetriever := newMockSessionRetriever(t)
- for _, p := range tc.mockParams.retrieveSessionParams {
- sessionRetriever.EXPECT().
- RetrieveSession(p.screenName).
- Return(p.result)
- }
- svc := NewICQLegacyService(
- newMockAuthService(t),
- newMockUserManager(t),
- newMockAccountManager(t),
- sessionRetriever,
- newMockMessageRelayer(t),
- newMockBuddyBroadcaster(t),
- newMockOfflineMessageManager(t),
- userFinder,
- newMockICQUserUpdater(t),
- newMockFeedbagManager(t),
- newMockRelationshipFetcher(t),
- newMockBuddyListRegistry(t),
- newMockBuddyService(t),
- newMockICBMService(t),
- &LegacySessionManager{sessions: map[uint32]*LegacySession{}},
- slog.Default(),
- )
- got, err := svc.SearchByUIN(context.Background(), tc.uin)
- if tc.wantErr {
- assert.Error(t, err)
- return
- }
- assert.NoError(t, err)
- assert.Equal(t, tc.wantResult.UIN, got.UIN)
- assert.Equal(t, tc.wantResult.Nickname, got.Nickname)
- assert.Equal(t, tc.wantResult.FirstName, got.FirstName)
- assert.Equal(t, tc.wantResult.LastName, got.LastName)
- assert.Equal(t, tc.wantResult.Email, got.Email)
- })
- }
- }
- func TestICQLegacyService_SearchByName(t *testing.T) {
- tests := []struct {
- name string
- mockParams mockParams
- nick string
- first string
- last string
- email string
- wantCount int
- }{
- {
- name: "matches by name",
- first: "John",
- last: "Doe",
- mockParams: mockParams{
- icqUserFinderParams: icqUserFinderParams{
- findByICQNameParams: findByICQNameParams{
- {
- firstName: "John",
- lastName: "Doe",
- nickName: "",
- result: []state.User{
- {
- IdentScreenName: state.NewIdentScreenName("12345"),
- ICQInfo: state.ICQInfo{
- Basic: state.ICQBasicInfo{
- Nickname: "JD",
- FirstName: "John",
- LastName: "Doe",
- },
- },
- },
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams: retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("12345"),
- result: nil,
- },
- },
- },
- },
- wantCount: 1,
- },
- {
- name: "matches by email",
- email: "john@example.com",
- mockParams: mockParams{
- icqUserFinderParams: icqUserFinderParams{
- findByICQEmailParams: findByICQEmailParams{
- {
- email: "john@example.com",
- result: state.User{
- IdentScreenName: state.NewIdentScreenName("12345"),
- ICQInfo: state.ICQInfo{
- Basic: state.ICQBasicInfo{
- Nickname: "JD",
- EmailAddress: "john@example.com",
- },
- },
- },
- },
- },
- },
- sessionRetrieverParams: sessionRetrieverParams{
- retrieveSessionParams: retrieveSessionParams{
- {
- screenName: state.NewIdentScreenName("12345"),
- result: nil,
- },
- },
- },
- },
- wantCount: 1,
- },
- }
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- userFinder := newMockICQUserFinder(t)
- for _, p := range tc.mockParams.findByICQNameParams {
- userFinder.EXPECT().
- FindByICQName(matchContext(), p.firstName, p.lastName, p.nickName).
- Return(p.result, p.err)
- }
- for _, p := range tc.mockParams.findByICQEmailParams {
- userFinder.EXPECT().
- FindByICQEmail(matchContext(), p.email).
- Return(p.result, p.err)
- }
- sessionRetriever := newMockSessionRetriever(t)
- for _, p := range tc.mockParams.retrieveSessionParams {
- sessionRetriever.EXPECT().
- RetrieveSession(p.screenName).
- Return(p.result)
- }
- svc := NewICQLegacyService(
- newMockAuthService(t),
- newMockUserManager(t),
- newMockAccountManager(t),
- sessionRetriever,
- newMockMessageRelayer(t),
- newMockBuddyBroadcaster(t),
- newMockOfflineMessageManager(t),
- userFinder,
- newMockICQUserUpdater(t),
- newMockFeedbagManager(t),
- newMockRelationshipFetcher(t),
- newMockBuddyListRegistry(t),
- newMockBuddyService(t),
- newMockICBMService(t),
- &LegacySessionManager{sessions: map[uint32]*LegacySession{}},
- slog.Default(),
- )
- got, err := svc.SearchByName(context.Background(), tc.nick, tc.first, tc.last, tc.email)
- assert.NoError(t, err)
- assert.Len(t, got, tc.wantCount)
- })
- }
- }
- func TestICQLegacyService_GetOfflineMessages(t *testing.T) {
- fixedTime := time.Date(2024, 1, 15, 10, 30, 0, 0, time.UTC)
- tests := []struct {
- name string
- mockParams mockParams
- uin uint32
- wantCount int
- }{
- {
- name: "messages exist",
- uin: 12345,
- mockParams: mockParams{
- offlineMessageManagerParams: offlineMessageManagerParams{
- retrieveMessagesParams: retrieveMessagesParams{
- {
- recip: state.NewIdentScreenName("12345"),
- messages: []state.OfflineMessage{
- {
- Sender: state.NewIdentScreenName("99999"),
- Recipient: state.NewIdentScreenName("12345"),
- Sent: fixedTime,
- Message: wire.SNAC_0x04_0x06_ICBMChannelMsgToHost{
- ChannelID: wire.ICBMChannelIM,
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: func() wire.TLVList {
- frags, _ := wire.ICBMFragmentList("hello offline")
- return wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVAOLIMData, frags),
- }
- }(),
- },
- },
- },
- },
- },
- },
- },
- },
- wantCount: 1,
- },
- {
- name: "no messages",
- uin: 12345,
- mockParams: mockParams{
- offlineMessageManagerParams: offlineMessageManagerParams{
- retrieveMessagesParams: retrieveMessagesParams{
- {
- recip: state.NewIdentScreenName("12345"),
- messages: []state.OfflineMessage{},
- },
- },
- },
- },
- wantCount: 0,
- },
- }
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- offlineMsgMgr := newMockOfflineMessageManager(t)
- for _, p := range tc.mockParams.retrieveMessagesParams {
- offlineMsgMgr.EXPECT().
- RetrieveMessages(matchContext(), p.recip).
- Return(p.messages, p.err)
- }
- svc := NewICQLegacyService(
- newMockAuthService(t),
- newMockUserManager(t),
- newMockAccountManager(t),
- newMockSessionRetriever(t),
- newMockMessageRelayer(t),
- newMockBuddyBroadcaster(t),
- offlineMsgMgr,
- newMockICQUserFinder(t),
- newMockICQUserUpdater(t),
- newMockFeedbagManager(t),
- newMockRelationshipFetcher(t),
- newMockBuddyListRegistry(t),
- newMockBuddyService(t),
- newMockICBMService(t),
- &LegacySessionManager{sessions: map[uint32]*LegacySession{}},
- slog.Default(),
- )
- got, err := svc.GetOfflineMessages(context.Background(), tc.uin)
- assert.NoError(t, err)
- assert.Len(t, got, tc.wantCount)
- if tc.wantCount > 0 {
- assert.Equal(t, uint32(99999), got[0].FromUIN)
- assert.Equal(t, tc.uin, got[0].ToUIN)
- }
- })
- }
- }
- func TestICQLegacyService_RegisterNewUser(t *testing.T) {
- tests := []struct {
- name string
- wantErr bool
- }{
- {
- name: "success",
- },
- }
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- userManager := newMockUserManager(t)
- // generateNewUIN calls User() to find an available UIN.
- // Return nil (available) for the first UIN checked (100000).
- userManager.EXPECT().
- User(matchContext(), state.NewIdentScreenName(strconv.FormatUint(100000, 10))).
- Return(nil, nil)
- // InsertUser is called with the new user
- userManager.EXPECT().
- InsertUser(matchContext(), mock.Anything).
- Return(nil)
- svc := NewICQLegacyService(
- newMockAuthService(t),
- userManager,
- newMockAccountManager(t),
- newMockSessionRetriever(t),
- newMockMessageRelayer(t),
- newMockBuddyBroadcaster(t),
- newMockOfflineMessageManager(t),
- newMockICQUserFinder(t),
- newMockICQUserUpdater(t),
- newMockFeedbagManager(t),
- newMockRelationshipFetcher(t),
- newMockBuddyListRegistry(t),
- newMockBuddyService(t),
- newMockICBMService(t),
- &LegacySessionManager{sessions: map[uint32]*LegacySession{}},
- slog.Default(),
- )
- uin, err := svc.RegisterNewUser(context.Background(), "Nick", "First", "Last", "test@example.com", "password123")
- if tc.wantErr {
- assert.Error(t, err)
- return
- }
- assert.NoError(t, err)
- assert.Equal(t, uint32(100000), uin)
- })
- }
- }
- func TestICQLegacyService_DeleteUser(t *testing.T) {
- authKey := "test-auth-key"
- password := "secret123"
- passHash := wire.StrongMD5PasswordHash(password, authKey)
- tests := []struct {
- name string
- mockParams mockParams
- uin uint32
- password string
- wantErr bool
- }{
- {
- name: "success",
- uin: 12345,
- password: password,
- mockParams: mockParams{
- userManagerParams: userManagerParams{
- userParams: userParams{
- {
- screenName: state.NewIdentScreenName("12345"),
- result: &state.User{
- AuthKey: authKey,
- StrongMD5Pass: passHash,
- },
- },
- },
- deleteUserParams: deleteUserParams{
- {
- screenName: state.NewIdentScreenName("12345"),
- },
- },
- },
- },
- },
- {
- name: "wrong password",
- uin: 12345,
- password: "wrongpass",
- mockParams: mockParams{
- userManagerParams: userManagerParams{
- userParams: userParams{
- {
- screenName: state.NewIdentScreenName("12345"),
- result: &state.User{
- AuthKey: authKey,
- StrongMD5Pass: passHash,
- },
- },
- },
- },
- },
- wantErr: true,
- },
- }
- for _, tc := range tests {
- t.Run(tc.name, func(t *testing.T) {
- authSvc := newMockAuthService(t)
- if tc.wantErr {
- authSvc.EXPECT().FLAPLogin(mock.Anything, mock.Anything, config.Endpoint{}).
- Return(wire.TLVRestBlock{
- TLVList: []wire.TLV{
- wire.NewTLVBE(wire.LoginTLVTagsErrorSubcode, wire.LoginErrInvalidPassword),
- },
- }, nil)
- } else {
- authSvc.EXPECT().FLAPLogin(mock.Anything, mock.Anything, config.Endpoint{}).
- Return(wire.TLVRestBlock{}, nil)
- }
- userManager := newMockUserManager(t)
- for _, p := range tc.mockParams.deleteUserParams {
- userManager.EXPECT().
- DeleteUser(matchContext(), p.screenName).
- Return(p.err)
- }
- svc := NewICQLegacyService(
- authSvc,
- userManager,
- newMockAccountManager(t),
- newMockSessionRetriever(t),
- newMockMessageRelayer(t),
- newMockBuddyBroadcaster(t),
- newMockOfflineMessageManager(t),
- newMockICQUserFinder(t),
- newMockICQUserUpdater(t),
- newMockFeedbagManager(t),
- newMockRelationshipFetcher(t),
- newMockBuddyListRegistry(t),
- newMockBuddyService(t),
- newMockICBMService(t),
- &LegacySessionManager{sessions: map[uint32]*LegacySession{}},
- slog.Default(),
- )
- err := svc.DeleteUser(context.Background(), tc.uin, tc.password)
- if tc.wantErr {
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "invalid password")
- return
- }
- assert.NoError(t, err)
- })
- }
- }
|