/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/chat/push_test.go
288 строк
8 KB
zoom-ua
gofumpt (#28710)
17 дек 2025, 17:16
Не верифицирован
17 дек 2025, 17:16
cda510b
Код
Авторство
О чём код?
package chat import ( "context" "crypto/rand" "testing" "time" "github.com/keybase/client/go/chat/storage" "github.com/keybase/client/go/chat/types" "github.com/keybase/client/go/gregor" "github.com/keybase/client/go/kbtest" "github.com/keybase/client/go/protocol/chat1" "github.com/keybase/client/go/protocol/gregor1" "github.com/keybase/client/go/protocol/keybase1" "github.com/keybase/go-codec/codec" "github.com/stretchr/testify/require" ) func randBytes(t *testing.T, n int) []byte { buf := make([]byte, n) if _, err := rand.Read(buf); err != nil { t.Fatal(err) } return buf } func sendSimple(ctx context.Context, t *testing.T, tc *kbtest.ChatTestContext, ph *PushHandler, sender types.Sender, conv chat1.Conversation, user *kbtest.FakeUser, iboxXform func(chat1.InboxVers) chat1.InboxVers, ) { uid := gregor1.UID(user.User.GetUID().ToBytes()) convID := conv.GetConvID() outboxID := chat1.OutboxID(randBytes(t, 8)) nr := tc.G.NotifyRouter tc.G.NotifyRouter = nil pt := chat1.MessagePlaintext{ ClientHeader: chat1.MessageClientHeader{ Conv: conv.Metadata.IdTriple, Sender: uid, TlfName: user.Username, TlfPublic: false, MessageType: chat1.MessageType_TEXT, OutboxID: &outboxID, }, MessageBody: chat1.NewMessageBodyWithText(chat1.MessageText{ Body: "hi", }), } _, boxed, err := sender.Send(ctx, convID, pt, 0, nil, nil, nil) require.NoError(t, err) ibox := storage.NewInbox(tc.Context()) vers, err := ibox.Version(ctx, uid) if err != nil { require.IsType(t, storage.MissError{}, err) vers = 0 } newVers := iboxXform(vers) t.Logf("newVers: %d vers: %d", newVers, vers) nm := chat1.NewMessagePayload{ Action: types.ActionNewMessage, ConvID: conv.GetConvID(), Message: *boxed, InboxVers: iboxXform(vers), TopicType: chat1.TopicType_CHAT, } var data []byte enc := codec.NewEncoderBytes(&data, &codec.MsgpackHandle{WriteExt: true}) require.NoError(t, enc.Encode(nm)) m := gregor1.OutOfBandMessage{ Uid_: uid, System_: "chat.activity", Body_: data, } tc.G.NotifyRouter = nr require.NoError(t, ph.Activity(ctx, m)) } func TestPushOrdering(t *testing.T) { ctx, world, ri2, _, sender, list := setupTest(t, 1) defer world.Cleanup() ri := ri2.(*kbtest.ChatRemoteMock) u := world.GetUsers()[0] uid := u.User.GetUID().ToBytes() tc := world.Tcs[u.Username] handler := NewPushHandler(tc.Context()) handler.Start(context.TODO(), nil) defer func() { <-handler.Stop(context.TODO()) }() handler.SetClock(world.Fc) timeout := 2 * time.Second conv := newBlankConv(ctx, t, tc, uid, ri, sender, u.Username) sendSimple(ctx, t, tc, handler, sender, conv, u, func(vers chat1.InboxVers) chat1.InboxVers { return vers + 1 }) select { case <-list.incomingRemote: case <-time.After(timeout): require.Fail(t, "no notification received") } sendSimple(ctx, t, tc, handler, sender, conv, u, func(vers chat1.InboxVers) chat1.InboxVers { return vers + 2 }) select { case <-list.incomingRemote: require.Fail(t, "should not have gotten one of these") default: } sendSimple(ctx, t, tc, handler, sender, conv, u, func(vers chat1.InboxVers) chat1.InboxVers { return vers + 1 }) select { case <-list.incomingRemote: case <-time.After(timeout): require.Fail(t, "no notification received") } select { case <-list.incomingRemote: case <-time.After(timeout): require.Fail(t, "no notification received") } handler.orderer.Lock() require.Zero(t, len(handler.orderer.waiters)) handler.orderer.Unlock() sendSimple(ctx, t, tc, handler, sender, conv, u, func(vers chat1.InboxVers) chat1.InboxVers { return vers + 2 }) select { case <-list.incomingRemote: require.Fail(t, "should not have gotten one of these") default: } t.Logf("advancing clock") world.Fc.Advance(time.Second) select { case <-list.incomingRemote: require.Fail(t, "not notification expected") default: } world.Fc.Advance(time.Second) select { case <-list.incomingRemote: case <-time.After(timeout): require.Fail(t, "no notification received") } handler.orderer.Lock() require.Zero(t, len(handler.orderer.waiters)) handler.orderer.Unlock() } func TestPushAppState(t *testing.T) { ctx, world, ri2, _, sender, list := setupTest(t, 1) defer world.Cleanup() ri := ri2.(*kbtest.ChatRemoteMock) u := world.GetUsers()[0] uid := u.User.GetUID().ToBytes() tc := world.Tcs[u.Username] handler := NewPushHandler(tc.Context()) handler.Start(context.TODO(), nil) defer func() { <-handler.Stop(context.TODO()) }() handler.SetClock(world.Fc) conv := newBlankConv(ctx, t, tc, uid, ri, sender, u.Username) tc.G.MobileAppState.Update(keybase1.MobileAppState_BACKGROUND) sendSimple(ctx, t, tc, handler, sender, conv, u, func(vers chat1.InboxVers) chat1.InboxVers { return vers + 1 }) select { case <-list.incomingRemote: case <-time.After(20 * time.Second): require.Fail(t, "no message received") } tc.G.MobileAppState.Update(keybase1.MobileAppState_FOREGROUND) sendSimple(ctx, t, tc, handler, sender, conv, u, func(vers chat1.InboxVers) chat1.InboxVers { return vers + 1 }) select { case <-list.incomingRemote: case <-time.After(20 * time.Second): require.Fail(t, "no message received") } } func makeTypingNotification(t *testing.T, uid gregor1.UID, convID chat1.ConversationID, typing bool) gregor.OutOfBandMessage { nm := chat1.RemoteUserTypingUpdate{ Uid: uid, ConvID: convID, Typing: typing, } var data []byte enc := codec.NewEncoderBytes(&data, &codec.MsgpackHandle{WriteExt: true}) require.NoError(t, enc.Encode(nm)) m := gregor1.OutOfBandMessage{ Uid_: uid, System_: "chat.typing", Body_: data, } return m } func TestPushTyping(t *testing.T) { ctx, world, ri2, _, sender, list := setupTest(t, 1) defer world.Cleanup() ri := ri2.(*kbtest.ChatRemoteMock) u := world.GetUsers()[0] uid := u.User.GetUID().ToBytes() tc := world.Tcs[u.Username] handler := NewPushHandler(tc.Context()) handler.Start(context.TODO(), nil) defer func() { <-handler.Stop(context.TODO()) }() handler.SetClock(world.Fc) handler.typingMonitor.SetClock(world.Fc) handler.typingMonitor.SetTimeout(time.Minute) conv := newBlankConv(ctx, t, tc, uid, ri, sender, u.Username) confirmTyping := func(list *chatListener) { select { case updates := <-list.typingUpdate: require.Equal(t, 1, len(updates)) require.Equal(t, conv.GetConvID(), updates[0].ConvID) require.Equal(t, 1, len(updates[0].Typers)) require.Equal(t, uid, updates[0].Typers[0].Uid.ToBytes()) case <-time.After(20 * time.Second): require.Fail(t, "no typing notification") } } confirmNotTyping := func(list *chatListener) { select { case updates := <-list.typingUpdate: require.Equal(t, 1, len(updates)) require.Equal(t, conv.GetConvID(), updates[0].ConvID) require.Zero(t, len(updates[0].Typers)) case <-time.After(2 * time.Second): require.Fail(t, "no typing notification") } } t.Logf("test basic") err := handler.Typing(context.TODO(), makeTypingNotification(t, uid, conv.GetConvID(), true)) require.NoError(t, err) confirmTyping(list) err = handler.Typing(context.TODO(), makeTypingNotification(t, uid, conv.GetConvID(), false)) require.NoError(t, err) confirmNotTyping(list) t.Logf("test expiration") err = handler.Typing(context.TODO(), makeTypingNotification(t, uid, conv.GetConvID(), true)) require.NoError(t, err) confirmTyping(list) world.Fc.Advance(time.Hour) confirmNotTyping(list) t.Logf("test extend") extendCh := make(chan struct{}) handler.typingMonitor.extendCh = &extendCh err = handler.Typing(context.TODO(), makeTypingNotification(t, uid, conv.GetConvID(), true)) require.NoError(t, err) confirmTyping(list) world.Fc.Advance(30 * time.Second) err = handler.Typing(context.TODO(), makeTypingNotification(t, uid, conv.GetConvID(), true)) require.NoError(t, err) select { case <-list.typingUpdate: require.Fail(t, "should have extended") default: } select { case <-extendCh: case <-time.After(20 * time.Second): require.Fail(t, "no extend callback") } world.Fc.Advance(40 * time.Second) select { case <-list.typingUpdate: require.Fail(t, "not far enough") default: } world.Fc.Advance(40 * time.Second) confirmNotTyping(list) require.Zero(t, len(handler.typingMonitor.typers)) }