| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552 |
- package server
- import (
- "bytes"
- "github.com/mkaminski/goaim/oscar"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
- "testing"
- "time"
- )
- // newTestSession returns a copy of the prototype session with fixed time
- //
- //goland:noinspection GoVetCopyLock
- func newTestSession(prototype Session) *Session {
- prototype.SignonTime = time.UnixMilli(1696790127565)
- return &prototype
- }
- func TestSendAndReceiveUserInfoQuery2(t *testing.T) {
- cases := []struct {
- // name is the unit test name
- name string
- // blockedState is the response to the sender/recipient block check
- blockedState BlockedState
- // screenNameLookups is the list of user session lookups
- screenNameLookups map[string]struct {
- sess *Session
- err error
- }
- // screenNameLookups is the list of user session lookups
- profileLookups map[string]struct {
- payload string
- err error
- }
- // userSession is the session of the user requesting the user info
- userSession *Session
- // inputSNAC is the SNAC sent by the sender client
- inputSNAC oscar.SNAC_0x02_0x15_LocateUserInfoQuery2
- expectOutput XMessage
- }{
- {
- name: "request user info, expect user info response",
- blockedState: BlockedNo,
- screenNameLookups: map[string]struct {
- sess *Session
- err error
- }{
- "requested-user": {
- sess: newTestSession(Session{
- ScreenName: "requested-user",
- AwayMessage: "this is my away message!",
- }),
- },
- },
- userSession: &Session{
- ScreenName: "user_screen_name",
- },
- inputSNAC: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
- Type2: 0,
- ScreenName: "requested-user",
- },
- expectOutput: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateUserInfoReply,
- },
- snacOut: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
- TLVUserInfo: newTestSession(Session{
- ScreenName: "requested-user",
- AwayMessage: "this is my away message!",
- }).GetTLVUserInfo(),
- LocateInfo: oscar.TLVRestBlock{},
- },
- },
- },
- {
- name: "request user info + profile, expect user info response + profile",
- blockedState: BlockedNo,
- screenNameLookups: map[string]struct {
- sess *Session
- err error
- }{
- "requested-user": {
- sess: newTestSession(Session{
- ScreenName: "requested-user",
- AwayMessage: "this is my away message!",
- }),
- },
- },
- profileLookups: map[string]struct {
- payload string
- err error
- }{
- "requested-user": {
- payload: "this is my profile!",
- },
- },
- userSession: &Session{
- ScreenName: "user_screen_name",
- },
- inputSNAC: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
- // 2048 is a dummy to make sure bitmask check works
- Type2: oscar.LocateType2Sig | 2048,
- ScreenName: "requested-user",
- },
- expectOutput: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateUserInfoReply,
- },
- snacOut: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
- TLVUserInfo: newTestSession(Session{
- ScreenName: "requested-user",
- AwayMessage: "this is my away message!",
- }).GetTLVUserInfo(),
- LocateInfo: oscar.TLVRestBlock{
- TLVList: oscar.TLVList{
- {
- TType: oscar.LocateTLVTagsInfoSigMime,
- Val: `text/aolrtf; charset="us-ascii"`,
- },
- {
- TType: oscar.LocateTLVTagsInfoSigData,
- Val: "this is my profile!",
- },
- },
- },
- },
- },
- },
- {
- name: "request user info + profile, expect user info response + profile",
- blockedState: BlockedNo,
- screenNameLookups: map[string]struct {
- sess *Session
- err error
- }{
- "requested-user": {
- sess: newTestSession(Session{
- ScreenName: "requested-user",
- AwayMessage: "this is my away message!",
- }),
- },
- },
- profileLookups: map[string]struct {
- payload string
- err error
- }{
- "requested-user": {
- payload: "this is my profile!",
- },
- },
- userSession: &Session{
- ScreenName: "user_screen_name",
- },
- inputSNAC: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
- // 2048 is a dummy to make sure bitmask check works
- Type2: oscar.LocateType2Sig | 2048,
- ScreenName: "requested-user",
- },
- expectOutput: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateUserInfoReply,
- },
- snacOut: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
- TLVUserInfo: newTestSession(Session{
- ScreenName: "requested-user",
- AwayMessage: "this is my away message!",
- }).GetTLVUserInfo(),
- LocateInfo: oscar.TLVRestBlock{
- TLVList: oscar.TLVList{
- {
- TType: oscar.LocateTLVTagsInfoSigMime,
- Val: `text/aolrtf; charset="us-ascii"`,
- },
- {
- TType: oscar.LocateTLVTagsInfoSigData,
- Val: "this is my profile!",
- },
- },
- },
- },
- },
- },
- {
- name: "request user info + away message, expect user info response + away message",
- blockedState: BlockedNo,
- screenNameLookups: map[string]struct {
- sess *Session
- err error
- }{
- "requested-user": {
- sess: newTestSession(Session{
- ScreenName: "requested-user",
- AwayMessage: "this is my away message!",
- }),
- },
- },
- userSession: &Session{
- ScreenName: "user_screen_name",
- },
- inputSNAC: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
- // 2048 is a dummy to make sure bitmask check works
- Type2: oscar.LocateType2Unavailable | 2048,
- ScreenName: "requested-user",
- },
- expectOutput: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateUserInfoReply,
- },
- snacOut: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
- TLVUserInfo: newTestSession(Session{
- ScreenName: "requested-user",
- AwayMessage: "this is my away message!",
- }).GetTLVUserInfo(),
- LocateInfo: oscar.TLVRestBlock{
- TLVList: oscar.TLVList{
- {
- TType: oscar.LocateTLVTagsInfoUnavailableMime,
- Val: `text/aolrtf; charset="us-ascii"`,
- },
- {
- TType: oscar.LocateTLVTagsInfoUnavailableData,
- Val: "this is my away message!",
- },
- },
- },
- },
- },
- },
- {
- name: "request user info of user who blocked requester, expect not logged in error",
- blockedState: BlockedB,
- userSession: &Session{
- ScreenName: "user_screen_name",
- },
- inputSNAC: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
- ScreenName: "requested-user",
- },
- expectOutput: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateErr,
- },
- snacOut: oscar.SnacError{
- Code: ErrorCodeNotLoggedOn,
- },
- },
- },
- {
- name: "request user info of user who does not exist, expect not logged in error",
- blockedState: BlockedNo,
- screenNameLookups: map[string]struct {
- sess *Session
- err error
- }{
- "non_existent_requested_user": {
- err: ErrSessNotFound,
- },
- },
- userSession: &Session{
- ScreenName: "user_screen_name",
- },
- inputSNAC: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
- ScreenName: "non_existent_requested_user",
- },
- expectOutput: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateErr,
- },
- snacOut: oscar.SnacError{
- Code: ErrorCodeNotLoggedOn,
- },
- },
- },
- }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- fm := NewMockFeedbagManager(t)
- fm.EXPECT().
- Blocked(tc.userSession.ScreenName, tc.inputSNAC.ScreenName).
- Return(tc.blockedState, nil).
- Maybe()
- sm := NewMockSessionManager(t)
- for screenName, val := range tc.screenNameLookups {
- sm.EXPECT().
- RetrieveByScreenName(screenName).
- Return(val.sess, val.err).
- Maybe()
- }
- pm := NewMockProfileManager(t)
- for screenName, val := range tc.profileLookups {
- pm.EXPECT().
- RetrieveProfile(screenName).
- Return(val.payload, val.err).
- Maybe()
- }
- svc := LocateService{}
- outputSNAC, err := svc.UserInfoQuery2Handler(tc.userSession, sm, fm, pm, tc.inputSNAC)
- assert.NoError(t, err)
- assert.Equal(t, tc.expectOutput, outputSNAC)
- })
- }
- }
- func TestLocateRouter_RouteLocate(t *testing.T) {
- cases := []struct {
- // name is the unit test name
- name string
- // input is the request payload
- input XMessage
- // output is the response payload
- output XMessage
- // handlerErr is the mocked handler error response
- handlerErr error
- // expectErr is the expected error returned by the router
- expectErr error
- }{
- {
- name: "receive LocateRightsQuery, return LocateRightsReply",
- input: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateRightsQuery,
- },
- snacOut: struct{}{},
- },
- output: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateRightsReply,
- },
- snacOut: oscar.SNAC_0x02_0x03_LocateRightsReply{
- TLVRestBlock: oscar.TLVRestBlock{
- TLVList: oscar.TLVList{
- {
- TType: 0x01,
- Val: uint16(1000),
- },
- },
- },
- },
- },
- },
- {
- name: "receive LocateSetInfo, return no response",
- input: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateSetInfo,
- },
- snacOut: oscar.SNAC_0x02_0x04_LocateSetInfo{
- TLVRestBlock: oscar.TLVRestBlock{
- TLVList: oscar.TLVList{
- {
- TType: 0x01,
- Val: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- output: XMessage{
- snacFrame: oscar.SnacFrame{},
- },
- },
- {
- name: "receive LocateSetDirInfo, return LocateSetDirReply",
- input: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateSetDirInfo,
- },
- snacOut: oscar.SNAC_0x02_0x09_LocateSetDirInfo{
- TLVRestBlock: oscar.TLVRestBlock{
- TLVList: oscar.TLVList{
- {
- TType: 0x01,
- Val: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- output: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateSetDirReply,
- },
- snacOut: oscar.SNAC_0x02_0x0A_LocateSetDirReply{
- Result: 1,
- },
- },
- },
- {
- name: "receive LocateGetDirInfo, return no response",
- input: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateGetDirInfo,
- },
- snacOut: oscar.SNAC_0x02_0x0B_LocateGetDirInfo{
- WatcherScreenNames: "screen-name",
- },
- },
- output: XMessage{
- snacFrame: oscar.SnacFrame{},
- },
- },
- {
- name: "receive LocateSetKeywordInfo, return LocateSetKeywordReply",
- input: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateSetKeywordInfo,
- },
- snacOut: oscar.SNAC_0x02_0x0F_LocateSetKeywordInfo{
- TLVRestBlock: oscar.TLVRestBlock{
- TLVList: oscar.TLVList{
- {
- TType: 0x01,
- Val: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- output: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateSetKeywordReply,
- },
- snacOut: oscar.SNAC_0x02_0x10_LocateSetKeywordReply{
- Unknown: 1,
- },
- },
- },
- {
- name: "receive LocateUserInfoQuery2, return LocateUserInfoReply",
- input: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateUserInfoQuery2,
- },
- snacOut: oscar.SNAC_0x02_0x15_LocateUserInfoQuery2{
- Type2: 1,
- },
- },
- output: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateUserInfoReply,
- },
- snacOut: oscar.SNAC_0x02_0x06_LocateUserInfoReply{
- TLVUserInfo: oscar.TLVUserInfo{
- ScreenName: "screen-name",
- },
- LocateInfo: oscar.TLVRestBlock{
- TLVList: oscar.TLVList{
- {
- TType: 0x01,
- Val: []byte{1, 2, 3, 4},
- },
- },
- },
- },
- },
- },
- {
- name: "receive LocateGetKeywordInfo, expect ErrUnsupportedSubGroup",
- input: XMessage{
- snacFrame: oscar.SnacFrame{
- FoodGroup: oscar.LOCATE,
- SubGroup: oscar.LocateGetKeywordInfo,
- },
- snacOut: struct{}{}, // empty SNAC
- },
- output: XMessage{}, // empty SNAC
- expectErr: ErrUnsupportedSubGroup,
- },
- }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- svc := NewMockLocateHandler(t)
- svc.EXPECT().
- RightsQueryHandler().
- Return(tc.output).
- Maybe()
- svc.EXPECT().
- SetDirInfoHandler().
- Return(tc.output).
- Maybe()
- svc.EXPECT().
- SetInfoHandler(mock.Anything, mock.Anything, mock.Anything, mock.Anything, tc.input.snacOut).
- Return(tc.handlerErr).
- Maybe()
- svc.EXPECT().
- SetKeywordInfoHandler().
- Return(tc.output).
- Maybe()
- svc.EXPECT().
- UserInfoQuery2Handler(mock.Anything, mock.Anything, mock.Anything, mock.Anything, tc.input.snacOut).
- Return(tc.output, tc.handlerErr).
- Maybe()
- router := LocateRouter{
- LocateHandler: svc,
- }
- bufIn := &bytes.Buffer{}
- assert.NoError(t, oscar.Marshal(tc.input.snacOut, bufIn))
- bufOut := &bytes.Buffer{}
- seq := uint32(1)
- err := router.RouteLocate(nil, nil, nil, tc.input.snacFrame, bufIn, bufOut, &seq)
- assert.ErrorIs(t, err, tc.expectErr)
- if tc.expectErr != nil {
- return
- }
- if tc.output.snacFrame == (oscar.SnacFrame{}) {
- return // handler doesn't return response
- }
- // make sure the sequence number was incremented
- assert.Equal(t, uint32(2), seq)
- // verify the FLAP frame
- flap := oscar.FlapFrame{}
- assert.NoError(t, oscar.Unmarshal(&flap, bufOut))
- assert.Equal(t, uint16(1), flap.Sequence)
- // verify the SNAC frame
- snacFrame := oscar.SnacFrame{}
- assert.NoError(t, oscar.Unmarshal(&snacFrame, bufOut))
- assert.Equal(t, tc.output.snacFrame, snacFrame)
- // verify the SNAC message
- snacBuf := &bytes.Buffer{}
- assert.NoError(t, oscar.Marshal(tc.output.snacOut, snacBuf))
- assert.Equal(t, snacBuf.Bytes(), bufOut.Bytes())
- })
- }
- }
|