github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/chat/bots/utils_test.go (about) 1 package bots 2 3 import ( 4 "context" 5 "crypto/sha256" 6 "testing" 7 8 "github.com/keybase/client/go/chat/globals" 9 "github.com/keybase/client/go/chat/types" 10 "github.com/keybase/client/go/chat/utils" 11 "github.com/keybase/client/go/externalstest" 12 "github.com/keybase/client/go/libkb" 13 "github.com/keybase/client/go/protocol/chat1" 14 "github.com/keybase/client/go/protocol/gregor1" 15 "github.com/keybase/client/go/protocol/keybase1" 16 "github.com/stretchr/testify/require" 17 ) 18 19 var mockCmdOutput []chat1.UserBotCommandOutput 20 21 type MockBotCommandManager struct{ types.DummyBotCommandManager } 22 23 func (m MockBotCommandManager) ListCommands(context.Context, chat1.ConversationID) ([]chat1.UserBotCommandOutput, map[string]string, error) { 24 return mockCmdOutput, make(map[string]string), nil 25 } 26 27 type mockUPAKLoader struct { 28 libkb.UPAKLoader 29 } 30 31 func (m mockUPAKLoader) LookupUsername(ctx context.Context, uid keybase1.UID) (libkb.NormalizedUsername, error) { 32 return libkb.NewNormalizedUsername("botua"), nil 33 } 34 35 func TestApplyTeamBotSettings(t *testing.T) { 36 tc := externalstest.SetupTest(t, "chat-utils", 0) 37 defer tc.Cleanup() 38 39 g := globals.NewContext(tc.G, &globals.ChatContext{}) 40 tc.G.OverrideUPAKLoader(mockUPAKLoader{}) 41 debugLabeler := utils.NewDebugLabeler(g.ExternalG(), "ApplyTeamBotSettings", false) 42 ctx := context.TODO() 43 convID := chat1.ConversationID([]byte("conv")) 44 botUID := gregor1.UID([]byte("botua")) 45 botSettings := keybase1.TeamBotSettings{} 46 msg := chat1.MessagePlaintext{} 47 mentionMap := make(map[string]struct{}) 48 49 assertMatch := func(expected bool) { 50 isMatch, err := ApplyTeamBotSettings(ctx, g, botUID, botSettings, msg, &convID, 51 mentionMap, debugLabeler) 52 require.NoError(t, err) 53 require.Equal(t, expected, isMatch) 54 } 55 56 assertMatch(false) 57 58 // DELETEHISTORY always matches 59 msg.ClientHeader = chat1.MessageClientHeader{ 60 MessageType: chat1.MessageType_DELETEHISTORY, 61 } 62 assertMatch(true) 63 64 bannedTypes := []chat1.MessageType{ 65 chat1.MessageType_NONE, 66 chat1.MessageType_METADATA, 67 chat1.MessageType_TLFNAME, 68 chat1.MessageType_HEADLINE, 69 chat1.MessageType_JOIN, 70 chat1.MessageType_LEAVE, 71 chat1.MessageType_SYSTEM, 72 } 73 for _, typ := range bannedTypes { 74 msg.ClientHeader.MessageType = typ 75 assertMatch(false) 76 } 77 78 // if the sender is botUID, always match 79 msg.ClientHeader.MessageType = chat1.MessageType_TEXT 80 msg.ClientHeader.Sender = botUID 81 assertMatch(true) 82 83 // restrict the bot to certain convs 84 botSettings.Convs = []string{"conv"} 85 assertMatch(false) 86 msg.ClientHeader.Sender = gregor1.UID("hi") 87 botSettings.Convs = nil 88 89 // mentions 90 mentionMap[botUID.String()] = struct{}{} 91 assertMatch(false) 92 93 botSettings.Mentions = true 94 assertMatch(true) 95 96 delete(mentionMap, botUID.String()) 97 assertMatch(false) 98 99 botSettings.Mentions = false 100 assertMatch(false) 101 102 // triggers 103 msg.MessageBody = chat1.NewMessageBodyWithText(chat1.MessageText{ 104 Body: "shipit", 105 }) 106 assertMatch(false) 107 108 botSettings.Triggers = []string{"shipit"} 109 assertMatch(true) 110 111 botSettings.Triggers = []string{".+"} 112 assertMatch(true) 113 114 msg.MessageBody = chat1.NewMessageBodyWithText(chat1.MessageText{ 115 Body: "", 116 }) 117 assertMatch(false) 118 119 // invalid trigger regex ignored 120 botSettings.Triggers = []string{"*"} 121 assertMatch(false) 122 123 botSettings.Triggers = nil 124 assertMatch(false) 125 126 g.BotCommandManager = &MockBotCommandManager{} 127 mockCmdOutput = []chat1.UserBotCommandOutput{ 128 { 129 Name: "remind me", 130 Username: "botua", 131 }, 132 } 133 msg.MessageBody = chat1.NewMessageBodyWithText(chat1.MessageText{ 134 Body: "!remind me ", 135 }) 136 assertMatch(false) 137 botSettings.Cmds = true 138 assertMatch(true) 139 140 // make sure we only match if the given bot username also matches 141 mockCmdOutput = []chat1.UserBotCommandOutput{ 142 { 143 Name: "remind me", 144 Username: "notbotua", 145 }, 146 } 147 msg.MessageBody = chat1.NewMessageBodyWithText(chat1.MessageText{ 148 Body: "!remind me ", 149 }) 150 assertMatch(false) 151 152 // make sure we don't match an erroneous command 153 msg.MessageBody = chat1.NewMessageBodyWithText(chat1.MessageText{ 154 Body: "!help ", 155 }) 156 assertMatch(false) 157 } 158 159 func TestBotInfoHash(t *testing.T) { 160 hash := sha256.New() 161 nilHash := chat1.BotInfoHash(hash.Sum(nil)) 162 163 // Ensure that the latest ClientBotInfoHashVers case is handled if the 164 // version number is incremented. 165 var botInfo chat1.BotInfo 166 for i := chat1.BotInfoHashVers(0); i <= chat1.ClientBotInfoHashVers; i++ { 167 botInfo = chat1.BotInfo{ 168 ClientHashVers: i, 169 } 170 require.NotEqual(t, nilHash, botInfo.Hash()) 171 } 172 173 // bumping the server version changes the hash 174 botInfo2 := chat1.BotInfo{ 175 ServerHashVers: chat1.ServerBotInfoHashVers + 1, 176 ClientHashVers: chat1.ClientBotInfoHashVers, 177 } 178 require.NotEqual(t, botInfo.Hash(), botInfo2.Hash()) 179 180 // non-existent client version returns a nil hash 181 botInfo = chat1.BotInfo{ 182 ClientHashVers: chat1.ClientBotInfoHashVers + 1, 183 } 184 require.Equal(t, nilHash, botInfo.Hash()) 185 }