github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/chat/commands_test.go (about) 1 package chat 2 3 import ( 4 "fmt" 5 "testing" 6 "time" 7 8 "github.com/keybase/client/go/kbtest" 9 "github.com/keybase/client/go/protocol/chat1" 10 "github.com/keybase/client/go/protocol/keybase1" 11 "github.com/stretchr/testify/require" 12 ) 13 14 func TestChatCommands(t *testing.T) { 15 ctc := makeChatTestContext(t, "TestChatCommands", 2) 16 defer ctc.cleanup() 17 users := ctc.users() 18 useRemoteMock = false 19 defer func() { useRemoteMock = true }() 20 timeout := 20 * time.Second 21 checkMsgText := func(list *serverChatListener, text string) { 22 select { 23 case msg := <-list.newMessageRemote: 24 require.True(t, msg.Message.IsValid()) 25 require.True(t, msg.Message.Valid().MessageBody.IsType(chat1.MessageType_TEXT)) 26 require.Equal(t, text, msg.Message.Valid().MessageBody.Text().Body) 27 case <-time.After(timeout): 28 require.Fail(t, "no msg") 29 } 30 } 31 checkHeadline := func(list *serverChatListener, headline string) { 32 select { 33 case msg := <-list.newMessageRemote: 34 require.True(t, msg.Message.IsValid()) 35 require.True(t, msg.Message.Valid().MessageBody.IsType(chat1.MessageType_HEADLINE)) 36 require.Equal(t, "chat about some pointless stuff", 37 msg.Message.Valid().MessageBody.Headline().Headline) 38 case <-time.After(timeout): 39 require.Fail(t, "no msg") 40 } 41 } 42 43 ctx := ctc.as(t, users[0]).startCtx 44 ui := kbtest.NewChatUI() 45 listener0 := newServerChatListener() 46 listener1 := newServerChatListener() 47 ctc.as(t, users[0]).h.mockChatUI = ui 48 ctc.as(t, users[0]).h.G().NotifyRouter.AddListener(listener0) 49 ctc.as(t, users[1]).h.G().NotifyRouter.AddListener(listener1) 50 ctc.world.Tcs[users[0].Username].G.UIRouter = kbtest.NewMockUIRouter(ui) 51 ctc.world.Tcs[users[0].Username].ChatG.Syncer.(*Syncer).isConnected = true 52 ctc.world.Tcs[users[1].Username].ChatG.Syncer.(*Syncer).isConnected = true 53 impConv := mustCreateConversationForTest(t, ctc, users[0], chat1.TopicType_CHAT, 54 chat1.ConversationMembersType_IMPTEAMNATIVE) 55 mustCreateConversationForTest(t, ctc, users[0], 56 chat1.TopicType_CHAT, chat1.ConversationMembersType_IMPTEAMNATIVE, users[1]) 57 teamConv := mustCreateConversationForTest(t, ctc, users[0], chat1.TopicType_CHAT, 58 chat1.ConversationMembersType_TEAM, users[1]) 59 topicName := "mike" 60 ncres, err := ctc.as(t, users[0]).chatLocalHandler().NewConversationLocal(ctx, 61 chat1.NewConversationLocalArg{ 62 TlfName: teamConv.TlfName, 63 TopicName: &topicName, 64 TopicType: chat1.TopicType_CHAT, 65 TlfVisibility: keybase1.TLFVisibility_PRIVATE, 66 MembersType: chat1.ConversationMembersType_TEAM, 67 }) 68 require.NoError(t, err) 69 consumeNewMsgRemote(t, listener0, chat1.MessageType_JOIN) 70 consumeNewMsgRemote(t, listener0, chat1.MessageType_SYSTEM) 71 consumeNewMsgRemote(t, listener0, chat1.MessageType_SYSTEM) 72 consumeNewMsgRemote(t, listener1, chat1.MessageType_SYSTEM) 73 consumeNewMsgRemote(t, listener1, chat1.MessageType_SYSTEM) 74 _, err = ctc.as(t, users[1]).chatLocalHandler().JoinConversationByIDLocal(ctx, ncres.Conv.GetConvID()) 75 require.NoError(t, err) 76 consumeNewMsgRemote(t, listener0, chat1.MessageType_JOIN) 77 consumeNewMsgRemote(t, listener1, chat1.MessageType_JOIN) 78 79 t.Log("test /shrug") 80 mustPostLocalForTest(t, ctc, users[0], impConv, chat1.NewMessageBodyWithText(chat1.MessageText{ 81 Body: "/shrug whatever", 82 })) 83 checkMsgText(listener0, `whatever ¯\_(ツ)_/¯`) 84 mustPostLocalForTest(t, ctc, users[0], impConv, chat1.NewMessageBodyWithText(chat1.MessageText{ 85 Body: "/shrug ", 86 })) 87 checkMsgText(listener0, `¯\_(ツ)_/¯`) 88 89 t.Logf("test /msg") 90 mustPostLocalForTest(t, ctc, users[0], impConv, chat1.NewMessageBodyWithText(chat1.MessageText{ 91 Body: fmt.Sprintf("/msg %s hi", users[1].Username), 92 })) 93 checkMsgText(listener0, "hi") 94 checkMsgText(listener1, "hi") 95 mustPostLocalForTest(t, ctc, users[0], impConv, chat1.NewMessageBodyWithText(chat1.MessageText{ 96 Body: fmt.Sprintf("/msg %s hi team", teamConv.TlfName), 97 })) 98 checkMsgText(listener0, "hi team") 99 checkMsgText(listener1, "hi team") 100 mustPostLocalForTest(t, ctc, users[0], impConv, chat1.NewMessageBodyWithText(chat1.MessageText{ 101 Body: fmt.Sprintf("/msg %s#%s hi channel", teamConv.TlfName, "mike"), 102 })) 103 checkMsgText(listener0, "hi channel") 104 checkMsgText(listener1, "hi channel") 105 106 t.Logf("test /me") 107 mustPostLocalForTest(t, ctc, users[0], impConv, chat1.NewMessageBodyWithText(chat1.MessageText{ 108 Body: "/me rises against the tide", 109 })) 110 checkMsgText(listener0, "_rises against the tide_") 111 112 t.Logf("test /headline") 113 mustPostLocalForTest(t, ctc, users[0], impConv, chat1.NewMessageBodyWithText(chat1.MessageText{ 114 Body: "/topic chat about some pointless stuff", 115 })) 116 checkHeadline(listener0, "/topic chat about some pointless stuff") 117 mustPostLocalForTest(t, ctc, users[0], teamConv, chat1.NewMessageBodyWithText(chat1.MessageText{ 118 Body: "/topic chat about some pointless stuff", 119 })) 120 checkHeadline(listener0, "/topic chat about some pointless stuff") 121 checkHeadline(listener1, "/topic chat about some pointless stuff") 122 123 testLeave := func() { 124 mustPostLocalForTest(t, ctc, users[0], ncres.Conv.Info, 125 chat1.NewMessageBodyWithText(chat1.MessageText{ 126 Body: "/leave", 127 })) 128 consumeNewMsgRemote(t, listener1, chat1.MessageType_LEAVE) 129 select { 130 case convID := <-listener0.leftConv: 131 require.Equal(t, ncres.Conv.GetConvID(), convID) 132 case <-time.After(timeout): 133 require.Fail(t, "no leave") 134 } 135 } 136 t.Logf("test /join and /leave") 137 mustPostLocalForTest(t, ctc, users[0], teamConv, chat1.NewMessageBodyWithText(chat1.MessageText{ 138 Body: "/leave", 139 })) 140 checkMsgText(listener0, "/leave") 141 checkMsgText(listener1, "/leave") 142 testLeave() 143 mustPostLocalForTest(t, ctc, users[0], teamConv, chat1.NewMessageBodyWithText(chat1.MessageText{ 144 Body: "/join", 145 })) 146 select { 147 case <-ui.ShowManageChannels: 148 case <-time.After(timeout): 149 require.Fail(t, "no show") 150 } 151 _, err = ctc.as(t, users[0]).chatLocalHandler().JoinConversationLocal(ctx, chat1.JoinConversationLocalArg{ 152 TlfName: teamConv.TlfName, 153 TopicType: chat1.TopicType_CHAT, 154 TopicName: "mike", 155 Visibility: keybase1.TLFVisibility_PRIVATE, 156 }) 157 require.NoError(t, err) 158 consumeNewMsgRemote(t, listener0, chat1.MessageType_JOIN) 159 consumeNewMsgRemote(t, listener1, chat1.MessageType_JOIN) 160 testLeave() 161 mustPostLocalForTest(t, ctc, users[0], impConv, chat1.NewMessageBodyWithText(chat1.MessageText{ 162 Body: fmt.Sprintf("/join %s#mike", teamConv.TlfName), 163 })) 164 checkMsgText(listener0, fmt.Sprintf("/join %s#mike", teamConv.TlfName)) 165 166 t.Logf("test /hide and /unhide") 167 mustPostLocalForTest(t, ctc, users[0], teamConv, chat1.NewMessageBodyWithText(chat1.MessageText{ 168 Body: fmt.Sprintf("/hide %s", users[0].Username), 169 })) 170 select { 171 case info := <-listener0.setStatus: 172 require.Equal(t, impConv.Id, info.ConvID) 173 require.Equal(t, chat1.ConversationStatus_IGNORED, info.Status) 174 case <-time.After(timeout): 175 require.Fail(t, "no set status") 176 } 177 mustPostLocalForTest(t, ctc, users[0], teamConv, chat1.NewMessageBodyWithText(chat1.MessageText{ 178 Body: fmt.Sprintf("/unhide %s", users[0].Username), 179 })) 180 select { 181 case info := <-listener0.setStatus: 182 require.Equal(t, impConv.Id, info.ConvID) 183 require.Equal(t, chat1.ConversationStatus_UNFILED, info.Status) 184 case <-time.After(timeout): 185 require.Fail(t, "no set status") 186 } 187 mustPostLocalForTest(t, ctc, users[0], impConv, chat1.NewMessageBodyWithText(chat1.MessageText{ 188 Body: "/hide", 189 })) 190 select { 191 case info := <-listener0.setStatus: 192 require.Equal(t, impConv.Id, info.ConvID) 193 require.Equal(t, chat1.ConversationStatus_IGNORED, info.Status) 194 case <-time.After(timeout): 195 require.Fail(t, "no set status") 196 } 197 }