mattermost/server/public/model/bot_test.go

701 lines
15 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package model
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestBotTrace(t *testing.T) {
bot := &Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
}
require.Equal(t, map[string]any{"user_id": bot.UserId}, bot.Trace())
}
func TestBotClone(t *testing.T) {
bot := &Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
}
clone := bot.Clone()
require.Equal(t, bot, bot.Clone())
require.False(t, bot == clone)
}
func TestBotIsValid(t *testing.T) {
testCases := []struct {
Description string
Bot *Bot
ExpectedIsValid bool
}{
{
"nil bot",
&Bot{},
false,
},
{
"bot with missing user id",
&Bot{
UserId: "",
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
},
false,
},
{
"bot with invalid user id",
&Bot{
UserId: "invalid",
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
},
false,
},
{
"bot with missing username",
&Bot{
UserId: NewId(),
Username: "",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
},
false,
},
{
"bot with invalid username",
&Bot{
UserId: NewId(),
Username: "a@",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
},
false,
},
{
"bot with long description",
&Bot{
UserId: "",
Username: "username",
DisplayName: "display name",
Description: strings.Repeat("x", 1025),
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
},
false,
},
{
"bot with missing creator id",
&Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: "",
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
},
false,
},
{
"bot without create at timestamp",
&Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 0,
UpdateAt: 3,
DeleteAt: 4,
},
false,
},
{
"bot without update at timestamp",
&Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 0,
DeleteAt: 4,
},
false,
},
{
"bot",
&Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 0,
},
true,
},
{
"bot without description",
&Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 0,
},
true,
},
{
"deleted bot",
&Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "a description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
},
true,
},
}
for _, testCase := range testCases {
t.Run(testCase.Description, func(t *testing.T) {
if testCase.ExpectedIsValid {
require.Nil(t, testCase.Bot.IsValid())
} else {
require.NotNil(t, testCase.Bot.IsValid())
}
})
}
}
func TestBotPreSave(t *testing.T) {
bot := &Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 0,
DeleteAt: 0,
}
originalBot := &Bot{
UserId: bot.UserId,
Username: bot.Username,
DisplayName: bot.DisplayName,
Description: bot.Description,
OwnerId: bot.OwnerId,
LastIconUpdate: bot.LastIconUpdate,
DeleteAt: bot.DeleteAt,
}
bot.PreSave()
assert.NotEqual(t, 0, bot.CreateAt)
assert.NotEqual(t, 0, bot.UpdateAt)
originalBot.CreateAt = bot.CreateAt
originalBot.UpdateAt = bot.UpdateAt
assert.Equal(t, originalBot, bot)
}
func TestBotPreUpdate(t *testing.T) {
bot := &Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
DeleteAt: 0,
}
originalBot := &Bot{
UserId: bot.UserId,
Username: bot.Username,
DisplayName: bot.DisplayName,
Description: bot.Description,
OwnerId: bot.OwnerId,
LastIconUpdate: bot.LastIconUpdate,
DeleteAt: bot.DeleteAt,
}
bot.PreSave()
assert.NotEqual(t, 0, bot.UpdateAt)
originalBot.CreateAt = bot.CreateAt
originalBot.UpdateAt = bot.UpdateAt
assert.Equal(t, originalBot, bot)
}
func TestBotEtag(t *testing.T) {
t.Run("same etags", func(t *testing.T) {
bot1 := &Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
}
bot2 := bot1
assert.Equal(t, bot1.Etag(), bot2.Etag())
})
t.Run("different etags", func(t *testing.T) {
t.Run("different user id", func(t *testing.T) {
bot1 := &Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
}
bot2 := &Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: bot1.OwnerId,
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
}
assert.NotEqual(t, bot1.Etag(), bot2.Etag())
})
t.Run("different update at", func(t *testing.T) {
bot1 := &Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
}
bot2 := &Bot{
UserId: bot1.UserId,
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: bot1.OwnerId,
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 10,
DeleteAt: 4,
}
assert.NotEqual(t, bot1.Etag(), bot2.Etag())
})
})
}
func TestBotPatch(t *testing.T) {
userId1 := NewId()
creatorId1 := NewId()
testCases := []struct {
Description string
Bot *Bot
BotPatch *BotPatch
ExpectedBot *Bot
}{
{
"no update",
&Bot{
UserId: userId1,
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: creatorId1,
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
},
&BotPatch{},
&Bot{
UserId: userId1,
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: creatorId1,
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
},
},
{
"partial update",
&Bot{
UserId: userId1,
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: creatorId1,
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
},
&BotPatch{
Username: NewPointer("new_username"),
DisplayName: nil,
Description: NewPointer("new description"),
},
&Bot{
UserId: userId1,
Username: "new_username",
DisplayName: "display name",
Description: "new description",
OwnerId: creatorId1,
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
},
},
{
"full update",
&Bot{
UserId: userId1,
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: creatorId1,
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
},
&BotPatch{
Username: NewPointer("new_username"),
DisplayName: NewPointer("new display name"),
Description: NewPointer("new description"),
},
&Bot{
UserId: userId1,
Username: "new_username",
DisplayName: "new display name",
Description: "new description",
OwnerId: creatorId1,
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
},
},
}
for _, testCase := range testCases {
t.Run(testCase.Description, func(t *testing.T) {
testCase.Bot.Patch(testCase.BotPatch)
assert.Equal(t, testCase.ExpectedBot, testCase.Bot)
})
}
}
func TestBotWouldPatch(t *testing.T) {
b := &Bot{
UserId: NewId(),
}
t.Run("nil patch", func(t *testing.T) {
ok := b.WouldPatch(nil)
require.False(t, ok)
})
t.Run("nil patch fields", func(t *testing.T) {
patch := &BotPatch{}
ok := b.WouldPatch(patch)
require.False(t, ok)
})
t.Run("patch", func(t *testing.T) {
patch := &BotPatch{
DisplayName: NewPointer("BotName"),
}
ok := b.WouldPatch(patch)
require.True(t, ok)
})
t.Run("no patch", func(t *testing.T) {
patch := &BotPatch{
DisplayName: NewPointer("BotName"),
}
b.Patch(patch)
ok := b.WouldPatch(patch)
require.False(t, ok)
})
}
func TestUserFromBot(t *testing.T) {
bot1 := &Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
}
bot2 := &Bot{
UserId: NewId(),
Username: "username2",
DisplayName: "display name 2",
Description: "description 2",
OwnerId: NewId(),
LastIconUpdate: 5,
CreateAt: 6,
UpdateAt: 7,
DeleteAt: 8,
}
assert.Equal(t, &User{
Id: bot1.UserId,
Username: "username",
Email: "username@localhost",
FirstName: "display name",
Roles: "system_user",
}, UserFromBot(bot1))
assert.Equal(t, &User{
Id: bot2.UserId,
Username: "username2",
Email: "username2@localhost",
FirstName: "display name 2",
Roles: "system_user",
}, UserFromBot(bot2))
}
func TestBotFromUser(t *testing.T) {
user := &User{
Id: NewId(),
Username: "username",
CreateAt: 1,
UpdateAt: 2,
DeleteAt: 3,
}
assert.Equal(t, &Bot{
OwnerId: user.Id,
UserId: user.Id,
Username: "username",
DisplayName: "username",
}, BotFromUser(user))
}
func TestBotListEtag(t *testing.T) {
bot1 := &Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 3,
DeleteAt: 4,
}
bot1Updated := &Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 1,
CreateAt: 2,
UpdateAt: 10,
DeleteAt: 4,
}
bot2 := &Bot{
UserId: NewId(),
Username: "username",
DisplayName: "display name",
Description: "description",
OwnerId: NewId(),
LastIconUpdate: 5,
CreateAt: 6,
UpdateAt: 7,
DeleteAt: 8,
}
testCases := []struct {
Description string
BotListA BotList
BotListB BotList
ExpectedEqual bool
}{
{
"empty lists",
BotList{},
BotList{},
true,
},
{
"single item, same list",
BotList{bot1},
BotList{bot1},
true,
},
{
"single item, different update at",
BotList{bot1},
BotList{bot1Updated},
false,
},
{
"single item vs. multiple items",
BotList{bot1},
BotList{bot1, bot2},
false,
},
{
"multiple items, different update at",
BotList{bot1, bot2},
BotList{bot1Updated, bot2},
false,
},
{
"multiple items, same list",
BotList{bot1, bot2},
BotList{bot1, bot2},
true,
},
}
for _, testCase := range testCases {
t.Run(testCase.Description, func(t *testing.T) {
if testCase.ExpectedEqual {
assert.Equal(t, testCase.BotListA.Etag(), testCase.BotListB.Etag())
} else {
assert.NotEqual(t, testCase.BotListA.Etag(), testCase.BotListB.Etag())
}
})
}
}
func TestIsBotChannel(t *testing.T) {
for _, test := range []struct {
Name string
Channel *Channel
Expected bool
}{
{
Name: "not a direct channel",
Channel: &Channel{Type: ChannelTypeOpen},
Expected: false,
},
{
Name: "a direct channel with another user",
Channel: &Channel{
Name: GetDMNameFromIds("user1", "user2"),
Type: ChannelTypeDirect,
},
Expected: false,
},
{
Name: "a direct channel with the name containing the bot's ID first",
Channel: &Channel{
Name: GetDMNameFromIds("botUserID", "user2"),
Type: ChannelTypeDirect,
},
Expected: true,
},
{
Name: "a direct channel with the name containing the bot's ID second",
Channel: &Channel{
Name: GetDMNameFromIds("user1", "botUserID"),
Type: ChannelTypeDirect,
},
Expected: true,
},
} {
t.Run(test.Name, func(t *testing.T) {
assert.Equal(t, test.Expected, IsBotDMChannel(test.Channel, "botUserID"))
})
}
}