Full Mattermost server source with integrated Community Enterprise features. Includes vendor directory for offline/air-gapped builds. Structure: - enterprise-impl/: Enterprise feature implementations - enterprise-community/: Init files that register implementations - enterprise/: Bridge imports (community_imports.go) - vendor/: All dependencies for offline builds Build (online): go build ./cmd/mattermost Build (offline/air-gapped): go build -mod=vendor ./cmd/mattermost 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
438 lines
12 KiB
Go
438 lines
12 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package app
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestIsKeywordMultibyte(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
id1 := model.NewId()
|
|
|
|
for name, tc := range map[string]struct {
|
|
Message string
|
|
Attachments []*model.SlackAttachment
|
|
Keywords map[string][]string
|
|
Groups map[string]*model.Group
|
|
Expected *MentionResults
|
|
}{
|
|
"MultibyteCharacter": {
|
|
Message: "My name is 萌",
|
|
Keywords: map[string][]string{"萌": {id1}},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
id1: KeywordMention,
|
|
},
|
|
},
|
|
},
|
|
"MultibyteCharacterWithNoUser": {
|
|
Message: "My name is 萌",
|
|
Keywords: map[string][]string{"萌": {}},
|
|
Expected: &MentionResults{
|
|
Mentions: nil,
|
|
},
|
|
},
|
|
"MultibyteCharacterAtBeginningOfSentence": {
|
|
Message: "이메일을 보내다.",
|
|
Keywords: map[string][]string{"이메일": {id1}},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
id1: KeywordMention,
|
|
},
|
|
},
|
|
},
|
|
"MultibyteCharacterAtBeginningOfSentenceWithNoUser": {
|
|
Message: "이메일을 보내다.",
|
|
Keywords: map[string][]string{"이메일": {}},
|
|
Expected: &MentionResults{
|
|
Mentions: nil,
|
|
},
|
|
},
|
|
"MultibyteCharacterInPartOfSentence": {
|
|
Message: "我爱吃番茄炒饭",
|
|
Keywords: map[string][]string{"番茄": {id1}},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
id1: KeywordMention,
|
|
},
|
|
},
|
|
},
|
|
"MultibyteCharacterInPartOfSentenceWithNoUser": {
|
|
Message: "我爱吃番茄炒饭",
|
|
Keywords: map[string][]string{"番茄": {}},
|
|
Expected: &MentionResults{
|
|
Mentions: nil,
|
|
},
|
|
},
|
|
"MultibyteCharacterAtEndOfSentence": {
|
|
Message: "こんにちは、世界",
|
|
Keywords: map[string][]string{"世界": {id1}},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
id1: KeywordMention,
|
|
},
|
|
},
|
|
},
|
|
"MultibyteCharacterAtEndOfSentenceWithNoUser": {
|
|
Message: "こんにちは、世界",
|
|
Keywords: map[string][]string{"世界": {}},
|
|
Expected: &MentionResults{
|
|
Mentions: nil,
|
|
},
|
|
},
|
|
"MultibyteCharacterTwiceInSentence": {
|
|
Message: "石橋さんが石橋を渡る",
|
|
Keywords: map[string][]string{"石橋": {id1}},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
id1: KeywordMention,
|
|
},
|
|
},
|
|
},
|
|
"MultibyteCharacterTwiceInSentenceWithNoUser": {
|
|
Message: "石橋さんが石橋を渡る",
|
|
Keywords: map[string][]string{"石橋": {}},
|
|
Expected: &MentionResults{
|
|
Mentions: nil,
|
|
},
|
|
},
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
post := &model.Post{
|
|
Message: tc.Message,
|
|
Props: model.StringInterface{
|
|
model.PostPropsAttachments: tc.Attachments,
|
|
},
|
|
}
|
|
|
|
m := getExplicitMentions(post, mapsToMentionKeywords(tc.Keywords, tc.Groups))
|
|
assert.EqualValues(t, tc.Expected, m)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCheckForMentionUsers(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
id1 := model.NewId()
|
|
id2 := model.NewId()
|
|
|
|
for name, tc := range map[string]struct {
|
|
Word string
|
|
Attachments []*model.SlackAttachment
|
|
Keywords map[string][]string
|
|
Expected *MentionResults
|
|
}{
|
|
"Nobody": {
|
|
Word: "nothing",
|
|
Keywords: map[string][]string{},
|
|
Expected: &MentionResults{},
|
|
},
|
|
"UppercaseUser1": {
|
|
Word: "@User",
|
|
Keywords: map[string][]string{"@user": {id1}},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
id1: KeywordMention,
|
|
},
|
|
},
|
|
},
|
|
"LowercaseUser1": {
|
|
Word: "@user",
|
|
Keywords: map[string][]string{"@user": {id1}},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
id1: KeywordMention,
|
|
},
|
|
},
|
|
},
|
|
"LowercaseUser2": {
|
|
Word: "@user2",
|
|
Keywords: map[string][]string{"@user2": {id2}},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
id2: KeywordMention,
|
|
},
|
|
},
|
|
},
|
|
"UppercaseUser2": {
|
|
Word: "@UsEr2",
|
|
Keywords: map[string][]string{"@user2": {id2}},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
id2: KeywordMention,
|
|
},
|
|
},
|
|
},
|
|
"HereMention": {
|
|
Word: "@here",
|
|
Expected: &MentionResults{
|
|
HereMentioned: true,
|
|
},
|
|
},
|
|
"ChannelMention": {
|
|
Word: "@channel",
|
|
Expected: &MentionResults{
|
|
ChannelMentioned: true,
|
|
},
|
|
},
|
|
"AllMention": {
|
|
Word: "@all",
|
|
Expected: &MentionResults{
|
|
AllMentioned: true,
|
|
},
|
|
},
|
|
"UppercaseHere": {
|
|
Word: "@HeRe",
|
|
Expected: &MentionResults{
|
|
HereMentioned: true,
|
|
},
|
|
},
|
|
"UppercaseChannel": {
|
|
Word: "@ChaNNel",
|
|
Expected: &MentionResults{
|
|
ChannelMentioned: true,
|
|
},
|
|
},
|
|
"UppercaseAll": {
|
|
Word: "@ALL",
|
|
Expected: &MentionResults{
|
|
AllMentioned: true,
|
|
},
|
|
},
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
p := makeStandardMentionParser(mapsToMentionKeywords(tc.Keywords, nil))
|
|
p.checkForMention(tc.Word)
|
|
|
|
assert.EqualValues(t, tc.Expected, p.Results())
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCheckForMentionGroups(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
groupID1 := model.NewId()
|
|
groupID2 := model.NewId()
|
|
|
|
for name, tc := range map[string]struct {
|
|
Word string
|
|
Groups map[string]*model.Group
|
|
Expected *MentionResults
|
|
}{
|
|
"No groups": {
|
|
Word: "nothing",
|
|
Groups: map[string]*model.Group{},
|
|
Expected: &MentionResults{},
|
|
},
|
|
"No matching groups": {
|
|
Word: "nothing",
|
|
Groups: map[string]*model.Group{
|
|
groupID1: {Id: groupID1, Name: model.NewPointer("engineering")},
|
|
groupID2: {Id: groupID2, Name: model.NewPointer("developers")},
|
|
},
|
|
Expected: &MentionResults{},
|
|
},
|
|
"matching group with no @": {
|
|
Word: "engineering",
|
|
Groups: map[string]*model.Group{
|
|
groupID1: {Id: groupID1, Name: model.NewPointer("engineering")},
|
|
groupID2: {Id: groupID2, Name: model.NewPointer("developers")},
|
|
},
|
|
Expected: &MentionResults{},
|
|
},
|
|
"matching group with preceding @": {
|
|
Word: "@engineering",
|
|
Groups: map[string]*model.Group{
|
|
groupID1: {Id: groupID1, Name: model.NewPointer("engineering")},
|
|
groupID2: {Id: groupID2, Name: model.NewPointer("developers")},
|
|
},
|
|
Expected: &MentionResults{
|
|
GroupMentions: map[string]MentionType{
|
|
groupID1: GroupMention,
|
|
},
|
|
},
|
|
},
|
|
"matching upper case group with preceding @": {
|
|
Word: "@Engineering",
|
|
Groups: map[string]*model.Group{
|
|
groupID1: {Id: groupID1, Name: model.NewPointer("engineering")},
|
|
groupID2: {Id: groupID2, Name: model.NewPointer("developers")},
|
|
},
|
|
Expected: &MentionResults{
|
|
GroupMentions: map[string]MentionType{
|
|
groupID1: GroupMention,
|
|
},
|
|
},
|
|
},
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
p := makeStandardMentionParser(mapsToMentionKeywords(nil, tc.Groups))
|
|
p.checkForMention(tc.Word)
|
|
|
|
mr := p.Results()
|
|
|
|
assert.EqualValues(t, tc.Expected, mr)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestProcessText(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
userID1 := model.NewId()
|
|
|
|
groupID1 := model.NewId()
|
|
groupID2 := model.NewId()
|
|
|
|
for name, tc := range map[string]struct {
|
|
Text string
|
|
Keywords map[string][]string
|
|
Groups map[string]*model.Group
|
|
Expected *MentionResults
|
|
}{
|
|
"Mention user in text": {
|
|
Text: "hello user @user1",
|
|
Keywords: map[string][]string{"@user1": {userID1}},
|
|
Groups: map[string]*model.Group{
|
|
groupID1: {Id: groupID1, Name: model.NewPointer("engineering")},
|
|
groupID2: {Id: groupID2, Name: model.NewPointer("developers")},
|
|
},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
userID1: KeywordMention,
|
|
},
|
|
},
|
|
},
|
|
"Mention user after ending a sentence with full stop": {
|
|
Text: "hello user.@user1",
|
|
Keywords: map[string][]string{"@user1": {userID1}},
|
|
Groups: map[string]*model.Group{
|
|
groupID1: {Id: groupID1, Name: model.NewPointer("engineering")},
|
|
groupID2: {Id: groupID2, Name: model.NewPointer("developers")},
|
|
},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
userID1: KeywordMention,
|
|
},
|
|
},
|
|
},
|
|
"Mention user after hyphen": {
|
|
Text: "hello user-@user1",
|
|
Keywords: map[string][]string{"@user1": {userID1}},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
userID1: KeywordMention,
|
|
},
|
|
},
|
|
},
|
|
"Mention user after colon": {
|
|
Text: "hello user:@user1",
|
|
Keywords: map[string][]string{"@user1": {userID1}},
|
|
Groups: map[string]*model.Group{
|
|
groupID1: {Id: groupID1, Name: model.NewPointer("engineering")},
|
|
groupID2: {Id: groupID2, Name: model.NewPointer("developers")},
|
|
},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
userID1: KeywordMention,
|
|
},
|
|
},
|
|
},
|
|
"Mention here after colon": {
|
|
Text: "hello all:@here",
|
|
Keywords: map[string][]string{},
|
|
Groups: map[string]*model.Group{
|
|
groupID1: {Id: groupID1, Name: model.NewPointer("engineering")},
|
|
groupID2: {Id: groupID2, Name: model.NewPointer("developers")},
|
|
},
|
|
Expected: &MentionResults{
|
|
HereMentioned: true,
|
|
},
|
|
},
|
|
"Mention all after hyphen": {
|
|
Text: "hello all-@all",
|
|
Keywords: map[string][]string{},
|
|
Groups: map[string]*model.Group{
|
|
groupID1: {Id: groupID1, Name: model.NewPointer("engineering")},
|
|
groupID2: {Id: groupID2, Name: model.NewPointer("developers")},
|
|
},
|
|
Expected: &MentionResults{
|
|
AllMentioned: true,
|
|
},
|
|
},
|
|
"Mention channel after full stop": {
|
|
Text: "hello channel.@channel",
|
|
Keywords: map[string][]string{},
|
|
Groups: map[string]*model.Group{
|
|
groupID1: {Id: groupID1, Name: model.NewPointer("engineering")},
|
|
groupID2: {Id: groupID2, Name: model.NewPointer("developers")},
|
|
},
|
|
Expected: &MentionResults{
|
|
ChannelMentioned: true,
|
|
},
|
|
},
|
|
"Mention other potential users or system calls": {
|
|
Text: "hello @potentialuser and @otherpotentialuser",
|
|
Keywords: map[string][]string{},
|
|
Groups: map[string]*model.Group{
|
|
groupID1: {Id: groupID1, Name: model.NewPointer("engineering")},
|
|
groupID2: {Id: groupID2, Name: model.NewPointer("developers")},
|
|
},
|
|
Expected: &MentionResults{
|
|
OtherPotentialMentions: []string{"potentialuser", "otherpotentialuser"},
|
|
},
|
|
},
|
|
"Mention a real user and another potential user": {
|
|
Text: "@user1, you can use @systembot to get help",
|
|
Keywords: map[string][]string{"@user1": {userID1}},
|
|
Groups: map[string]*model.Group{
|
|
groupID1: {Id: groupID1, Name: model.NewPointer("engineering")},
|
|
groupID2: {Id: groupID2, Name: model.NewPointer("developers")},
|
|
},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
userID1: KeywordMention,
|
|
},
|
|
OtherPotentialMentions: []string{"systembot"},
|
|
},
|
|
},
|
|
"Mention a group": {
|
|
Text: "@engineering",
|
|
Keywords: map[string][]string{"@user1": {userID1}},
|
|
Groups: map[string]*model.Group{
|
|
groupID1: {Id: groupID1, Name: model.NewPointer("engineering")},
|
|
groupID2: {Id: groupID2, Name: model.NewPointer("developers")},
|
|
},
|
|
Expected: &MentionResults{
|
|
GroupMentions: map[string]MentionType{groupID1: GroupMention},
|
|
},
|
|
},
|
|
"Mention a real user and another potential user and a group": {
|
|
Text: "@engineering @user1, you can use @systembot to get help from",
|
|
Keywords: map[string][]string{"@user1": {userID1}},
|
|
Groups: map[string]*model.Group{
|
|
groupID1: {Id: groupID1, Name: model.NewPointer("engineering")},
|
|
groupID2: {Id: groupID2, Name: model.NewPointer("developers")},
|
|
},
|
|
Expected: &MentionResults{
|
|
Mentions: map[string]MentionType{
|
|
userID1: KeywordMention,
|
|
},
|
|
GroupMentions: map[string]MentionType{groupID1: GroupMention},
|
|
OtherPotentialMentions: []string{"systembot"},
|
|
},
|
|
},
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
p := makeStandardMentionParser(mapsToMentionKeywords(tc.Keywords, tc.Groups))
|
|
p.ProcessText(tc.Text)
|
|
|
|
assert.EqualValues(t, tc.Expected, p.Results())
|
|
})
|
|
}
|
|
}
|