| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615 |
- package toc
- import (
- "context"
- "log/slog"
- "net"
- "sync"
- "testing"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
- "github.com/mk6i/open-oscar-server/state"
- "github.com/mk6i/open-oscar-server/wire"
- )
- func TestOSCARProxy_RecvBOS_ChatIn(t *testing.T) {
- cases := []struct {
- // name is the unit test name
- name string
- // me is the TOC user session
- me *state.SessionInstance
- // chatID is the chat ID
- chatID int
- // givenMsg is the incoming SNAC
- givenMsg wire.SNACMessage
- // wantCmd is the expected TOC response
- wantCmd []byte
- }{
- {
- name: "send chat message",
- me: newTestSession("me"),
- chatID: 0,
- givenMsg: wire.SNACMessage{
- Body: wire.SNAC_0x0E_0x06_ChatChannelMsgToClient{
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ChatTLVSenderInformation, wire.TLVUserInfo{
- ScreenName: "them",
- }),
- wire.NewTLVBE(wire.ChatTLVMessageInfo, wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ChatTLVMessageInfoText, "<p>hello world!</p>"),
- },
- }),
- },
- },
- },
- },
- wantCmd: []byte("CHAT_IN:0:them:F:<p>hello world!</p>"),
- },
- }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- svc := OSCARProxy{
- Logger: slog.Default(),
- }
- ch := make(chan []byte)
- wg := &sync.WaitGroup{}
- wg.Add(1)
- go func() {
- defer wg.Done()
- svc.RecvChat(ctx, tc.me, tc.chatID, ch)
- }()
- status := tc.me.RelayMessageToInstance(tc.givenMsg)
- assert.Equal(t, state.SessSendOK, status)
- gotCmd := <-ch
- assert.Equal(t, string(tc.wantCmd), string(gotCmd))
- cancel()
- wg.Wait()
- })
- }
- }
- func TestOSCARProxy_RecvBOS_ChatUpdateBuddyArrived(t *testing.T) {
- cases := []struct {
- // name is the unit test name
- name string
- // me is the TOC user session
- me *state.SessionInstance
- // chatID is the chat ID
- chatID int
- // givenMsg is the incoming SNAC
- givenMsg wire.SNACMessage
- // wantCmd is the expected TOC response
- wantCmd []byte
- }{
- {
- name: "send chat participant arrival",
- me: newTestSession("me"),
- givenMsg: wire.SNACMessage{
- Body: wire.SNAC_0x0E_0x03_ChatUsersJoined{
- Users: []wire.TLVUserInfo{
- {ScreenName: "user1"},
- {ScreenName: "user2"},
- },
- },
- },
- wantCmd: []byte("CHAT_UPDATE_BUDDY:0:T:user1:user2"),
- },
- }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- svc := OSCARProxy{
- Logger: slog.Default(),
- }
- ch := make(chan []byte)
- wg := &sync.WaitGroup{}
- wg.Add(1)
- go func() {
- defer wg.Done()
- svc.RecvChat(ctx, tc.me, tc.chatID, ch)
- }()
- status := tc.me.RelayMessageToInstance(tc.givenMsg)
- assert.Equal(t, state.SessSendOK, status)
- gotCmd := <-ch
- assert.Equal(t, string(tc.wantCmd), string(gotCmd))
- cancel()
- wg.Wait()
- })
- }
- }
- func TestOSCARProxy_RecvBOS_ChatUpdateBuddyLeft(t *testing.T) {
- cases := []struct {
- // name is the unit test name
- name string
- // me is the TOC user session
- me *state.SessionInstance
- // chatID is the chat ID
- chatID int
- // givenMsg is the incoming SNAC
- givenMsg wire.SNACMessage
- // wantCmd is the expected TOC response
- wantCmd []byte
- }{
- {
- name: "send chat participant departure",
- me: newTestSession("me"),
- givenMsg: wire.SNACMessage{
- Body: wire.SNAC_0x0E_0x04_ChatUsersLeft{
- Users: []wire.TLVUserInfo{
- {ScreenName: "user1"},
- {ScreenName: "user2"},
- },
- },
- },
- wantCmd: []byte("CHAT_UPDATE_BUDDY:0:F:user1:user2"),
- },
- }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- svc := OSCARProxy{
- Logger: slog.Default(),
- }
- ch := make(chan []byte)
- wg := &sync.WaitGroup{}
- wg.Add(1)
- go func() {
- defer wg.Done()
- svc.RecvChat(ctx, tc.me, tc.chatID, ch)
- }()
- status := tc.me.RelayMessageToInstance(tc.givenMsg)
- assert.Equal(t, state.SessSendOK, status)
- gotCmd := <-ch
- assert.Equal(t, string(tc.wantCmd), string(gotCmd))
- cancel()
- wg.Wait()
- })
- }
- }
- func TestOSCARProxy_RecvBOS_Eviled(t *testing.T) {
- cases := []struct {
- // name is the unit test name
- name string
- // me is the TOC user session
- me *state.SessionInstance
- // givenMsg is the incoming SNAC
- givenMsg wire.SNACMessage
- // chatRegistry is the chat registry for the current session
- chatRegistry *ChatRegistry
- // wantCmd is the expected TOC response
- wantCmd []byte
- }{
- {
- name: "anonymous warning - 10%",
- me: newTestSession("me"),
- givenMsg: wire.SNACMessage{
- Body: wire.SNAC_0x01_0x10_OServiceEvilNotification{
- NewEvil: 100,
- },
- },
- wantCmd: []byte("EVILED:10:"),
- },
- {
- name: "normal warning - 10%",
- me: newTestSession("me"),
- givenMsg: wire.SNACMessage{
- Body: wire.SNAC_0x01_0x10_OServiceEvilNotification{
- NewEvil: 100,
- Snitcher: &struct {
- wire.TLVUserInfo
- }{
- TLVUserInfo: wire.TLVUserInfo{
- ScreenName: "them",
- },
- },
- },
- },
- wantCmd: []byte("EVILED:10:them"),
- },
- }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- svc := testOSCARProxy(t)
- ch := make(chan []byte)
- wg := &sync.WaitGroup{}
- wg.Add(1)
- go func() {
- defer wg.Done()
- err := svc.RecvBOS(ctx, tc.me, NewChatRegistry(), ch)
- assert.NoError(t, err)
- }()
- status := tc.me.RelayMessageToInstance(tc.givenMsg)
- assert.Equal(t, state.SessSendOK, status)
- gotCmd := <-ch
- assert.Equal(t, string(tc.wantCmd), string(gotCmd))
- cancel()
- wg.Wait()
- })
- }
- }
- func TestOSCARProxy_RecvBOS_IMIn(t *testing.T) {
- cases := []struct {
- // name is the unit test name
- name string
- // me is the TOC user session
- me *state.SessionInstance
- // givenMsg is the incoming SNAC
- givenMsg wire.SNACMessage
- // wantCmd is the expected TOC response
- wantCmd []byte
- }{
- {
- name: "send IM",
- me: newTestSession("me"),
- givenMsg: wire.SNACMessage{
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelIM,
- TLVUserInfo: wire.TLVUserInfo{
- ScreenName: "them",
- },
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVAOLIMData, []wire.ICBMCh1Fragment{
- {
- ID: 0x5,
- Version: 0x1,
- Payload: []uint8{0x1, 0x1, 0x2},
- },
- {
- ID: 0x1,
- Version: 0x1,
- Payload: []uint8{
- 0x0, 0x0, // charset
- 0x0, 0x0, // lang
- 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
- },
- },
- }),
- },
- },
- },
- },
- wantCmd: []byte("IM_IN:them:F:hello world!"),
- },
- {
- name: "send IM - auto-response",
- me: newTestSession("me"),
- givenMsg: wire.SNACMessage{
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelIM,
- TLVUserInfo: wire.TLVUserInfo{
- ScreenName: "them",
- },
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVAutoResponse, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVAOLIMData, []wire.ICBMCh1Fragment{
- {
- ID: 0x5,
- Version: 0x1,
- Payload: []uint8{0x1, 0x1, 0x2},
- },
- {
- ID: 0x1,
- Version: 0x1,
- Payload: []uint8{
- 0x0, 0x0, // charset
- 0x0, 0x0, // lang
- 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!',
- },
- },
- }),
- },
- },
- },
- },
- wantCmd: []byte("IM_IN:them:T:hello world!"),
- },
- {
- name: "send chat invitation",
- me: newTestSession("me"),
- givenMsg: wire.SNACMessage{
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelRendezvous,
- TLVUserInfo: wire.TLVUserInfo{
- ScreenName: "them",
- },
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVData, []wire.ICBMCh2Fragment{
- {
- Capability: wire.CapChat,
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMRdvTLVTagsInvitation, "join my chat!"),
- wire.NewTLVBE(wire.ICBMRdvTLVTagsSvcData, wire.ICBMRoomInfo{
- Cookie: "a-b-the room",
- }),
- },
- },
- },
- }),
- },
- },
- },
- },
- wantCmd: []byte("CHAT_INVITE:the room:0:them:join my chat!"),
- },
- {
- name: "receive file transfer rendezvous IM",
- me: newTestSession("me"),
- givenMsg: wire.SNACMessage{
- Body: wire.SNAC_0x04_0x07_ICBMChannelMsgToClient{
- ChannelID: wire.ICBMChannelRendezvous,
- TLVUserInfo: newTestSession("them").Session().TLVUserInfo(),
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMTLVWantEvents, []byte{}),
- wire.NewTLVBE(wire.ICBMTLVData, wire.ICBMCh2Fragment{
- Cookie: [8]byte{'h', 'a', 'h', 'a', 'h', 'a', 'h', 'a'},
- Type: wire.ICBMRdvMessagePropose,
- Capability: wire.CapFileTransfer,
- TLVRestBlock: wire.TLVRestBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.ICBMRdvTLVTagsSeqNum, uint16(1)),
- wire.NewTLVBE(wire.ICBMRdvTLVTagsPort, uint16(4000)),
- wire.NewTLVBE(wire.ICBMRdvTLVTagsRdvIP, net.ParseIP("129.168.0.1").To4()),
- wire.NewTLVBE(wire.ICBMRdvTLVTagsRequesterIP, net.ParseIP("129.168.0.2").To4()),
- wire.NewTLVBE(wire.ICBMRdvTLVTagsVerifiedIP, net.ParseIP("129.168.0.3").To4()),
- wire.NewTLVBE(wire.ICBMRdvTLVTagsSvcData, []byte{'l', 'o', 'l'}),
- },
- },
- }),
- },
- },
- },
- },
- wantCmd: []byte("RVOUS_PROPOSE:them:09461343-4C7F-11D1-8222-444553540000:aGFoYWhhaGE=:1:129.168.0.1:129.168.0.2:129.168.0.3:4000:10001:bG9s"),
- },
- }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- svc := testOSCARProxy(t)
- ch := make(chan []byte)
- wg := &sync.WaitGroup{}
- wg.Add(1)
- go func() {
- defer wg.Done()
- err := svc.RecvBOS(ctx, tc.me, NewChatRegistry(), ch)
- assert.NoError(t, err)
- }()
- status := tc.me.RelayMessageToInstance(tc.givenMsg)
- assert.Equal(t, state.SessSendOK, status)
- gotCmd := <-ch
- assert.Equal(t, string(tc.wantCmd), string(gotCmd))
- cancel()
- wg.Wait()
- })
- }
- }
- func TestOSCARProxy_RecvBOS_UpdateBuddyArrival(t *testing.T) {
- cases := []struct {
- // name is the unit test name
- name string
- // me is the TOC user session
- me *state.SessionInstance
- // givenMsg is the incoming SNAC
- givenMsg wire.SNACMessage
- // wantCmd is the expected TOC response
- wantCmd []byte
- }{
- {
- name: "send buddy arrival - buddy online",
- me: newTestSession("me"),
- givenMsg: wire.SNACMessage{
- Body: wire.SNAC_0x03_0x0B_BuddyArrived{
- TLVUserInfo: wire.TLVUserInfo{
- ScreenName: "me",
- WarningLevel: 0,
- TLVBlock: wire.TLVBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.OServiceUserInfoSignonTOD, uint32(1234)),
- wire.NewTLVBE(wire.OServiceUserInfoIdleTime, uint16(5678)),
- },
- },
- },
- },
- },
- wantCmd: []byte("UPDATE_BUDDY:me:T:0:1234:5678: O "),
- },
- {
- name: "send buddy arrival - buddy warned 10%",
- me: newTestSession("me"),
- givenMsg: wire.SNACMessage{
- Body: wire.SNAC_0x03_0x0B_BuddyArrived{
- TLVUserInfo: wire.TLVUserInfo{
- ScreenName: "me",
- WarningLevel: 100,
- TLVBlock: wire.TLVBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.OServiceUserInfoSignonTOD, uint32(1234)),
- wire.NewTLVBE(wire.OServiceUserInfoIdleTime, uint16(5678)),
- },
- },
- },
- },
- },
- wantCmd: []byte("UPDATE_BUDDY:me:T:10:1234:5678: O "),
- },
- {
- name: "send buddy arrival - buddy away",
- me: newTestSession("me"),
- givenMsg: wire.SNACMessage{
- Body: wire.SNAC_0x03_0x0B_BuddyArrived{
- TLVUserInfo: wire.TLVUserInfo{
- ScreenName: "me",
- WarningLevel: 0,
- TLVBlock: wire.TLVBlock{
- TLVList: wire.TLVList{
- wire.NewTLVBE(wire.OServiceUserInfoSignonTOD, uint32(1234)),
- wire.NewTLVBE(wire.OServiceUserInfoIdleTime, uint16(5678)),
- wire.NewTLVBE(wire.OServiceUserInfoUserFlags, wire.OServiceUserFlagUnavailable),
- },
- },
- },
- },
- },
- wantCmd: []byte("UPDATE_BUDDY:me:T:0:1234:5678: OU"),
- },
- }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- svc := testOSCARProxy(t)
- ch := make(chan []byte)
- wg := &sync.WaitGroup{}
- wg.Add(1)
- go func() {
- defer wg.Done()
- err := svc.RecvBOS(ctx, tc.me, NewChatRegistry(), ch)
- assert.NoError(t, err)
- }()
- status := tc.me.RelayMessageToInstance(tc.givenMsg)
- assert.Equal(t, state.SessSendOK, status)
- gotCmd := <-ch
- assert.Equal(t, string(tc.wantCmd), string(gotCmd))
- cancel()
- wg.Wait()
- })
- }
- }
- func TestOSCARProxy_RecvBOS_UpdateBuddyDeparted(t *testing.T) {
- cases := []struct {
- // name is the unit test name
- name string
- // me is the TOC user session
- me *state.SessionInstance
- // givenMsg is the incoming SNAC
- givenMsg wire.SNACMessage
- // wantCmd is the expected TOC response
- wantCmd []byte
- }{
- {
- name: "send buddy departure",
- me: newTestSession("me"),
- givenMsg: wire.SNACMessage{
- Body: wire.SNAC_0x03_0x0C_BuddyDeparted{
- TLVUserInfo: wire.TLVUserInfo{
- ScreenName: "me",
- },
- },
- },
- wantCmd: []byte("UPDATE_BUDDY:me:F:0:0:0: "),
- },
- }
- for _, tc := range cases {
- t.Run(tc.name, func(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- svc := testOSCARProxy(t)
- ch := make(chan []byte)
- wg := &sync.WaitGroup{}
- wg.Add(1)
- go func() {
- defer wg.Done()
- err := svc.RecvBOS(ctx, tc.me, NewChatRegistry(), ch)
- assert.NoError(t, err)
- }()
- status := tc.me.RelayMessageToInstance(tc.givenMsg)
- assert.Equal(t, state.SessSendOK, status)
- gotCmd := <-ch
- assert.Equal(t, string(tc.wantCmd), string(gotCmd))
- cancel()
- wg.Wait()
- })
- }
- }
- func TestOSCARProxy_RecvBOS_Signout(t *testing.T) {
- }
- func testOSCARProxy(t *testing.T) OSCARProxy {
- buddyService := newMockBuddyService(t)
- buddyService.EXPECT().
- BroadcastBuddyDeparted(mock.Anything, mock.Anything).
- Maybe().
- Return(nil)
- buddyListRegistry := newMockBuddyListRegistry(t)
- buddyListRegistry.EXPECT().
- UnregisterBuddyList(mock.Anything, mock.Anything).
- Maybe().
- Return(nil)
- authService := newMockAuthService(t)
- authService.EXPECT().
- Signout(mock.Anything, mock.Anything).
- Maybe()
- authService.EXPECT().
- SignoutChat(mock.Anything, mock.Anything).
- Maybe()
- return OSCARProxy{
- AuthService: authService,
- BuddyListRegistry: buddyListRegistry,
- BuddyService: buddyService,
- Logger: slog.Default(),
- }
- }
|