Files
mattermost/api/emoji_test.go
George Goldberg 50fc6e1e9e PLT-???? Prepare file upload infrastructure for Data Retention. (#7266)
* Prepare file upload infrastructure for Data Retention.

This commit prepares the file upload infrastructure for the data
retention feature that is under construction. Changes are:

* Move file management code to utils to allow access to it from jobs.

* From now on, store all file uploads in a top level folder which is the
  date of the day on which they were uploaded.

This commit is based on Harrison Healey's branch, but updated to work
with the latest master.

* Use NewAppError
2017-08-25 10:38:13 -04:00

426 lines
14 KiB
Go

// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package api
import (
"bytes"
"image"
"image/gif"
"testing"
"time"
"github.com/mattermost/platform/app"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
)
func TestGetEmoji(t *testing.T) {
th := Setup().InitBasic()
Client := th.BasicClient
EnableCustomEmoji := *utils.Cfg.ServiceSettings.EnableCustomEmoji
defer func() {
*utils.Cfg.ServiceSettings.EnableCustomEmoji = EnableCustomEmoji
}()
*utils.Cfg.ServiceSettings.EnableCustomEmoji = true
emojis := []*model.Emoji{
{
CreatorId: model.NewId(),
Name: model.NewId(),
},
{
CreatorId: model.NewId(),
Name: model.NewId(),
},
{
CreatorId: model.NewId(),
Name: model.NewId(),
},
}
for i, emoji := range emojis {
emojis[i] = store.Must(app.Srv.Store.Emoji().Save(emoji)).(*model.Emoji)
}
defer func() {
for _, emoji := range emojis {
store.Must(app.Srv.Store.Emoji().Delete(emoji.Id, time.Now().Unix()))
}
}()
if returnedEmojis, err := Client.ListEmoji(); err != nil {
t.Fatal(err)
} else {
for _, emoji := range emojis {
found := false
for _, savedEmoji := range returnedEmojis {
if emoji.Id == savedEmoji.Id {
found = true
break
}
}
if !found {
t.Fatalf("failed to get emoji with id %v", emoji.Id)
}
}
}
deleted := &model.Emoji{
CreatorId: model.NewId(),
Name: model.NewId(),
DeleteAt: 1,
}
deleted = store.Must(app.Srv.Store.Emoji().Save(deleted)).(*model.Emoji)
if returnedEmojis, err := Client.ListEmoji(); err != nil {
t.Fatal(err)
} else {
found := false
for _, savedEmoji := range returnedEmojis {
if deleted.Id == savedEmoji.Id {
found = true
break
}
}
if found {
t.Fatalf("shouldn't have gotten deleted emoji %v", deleted.Id)
}
}
}
func TestCreateEmoji(t *testing.T) {
th := Setup().InitBasic().InitSystemAdmin()
Client := th.BasicClient
EnableCustomEmoji := *utils.Cfg.ServiceSettings.EnableCustomEmoji
defer func() {
*utils.Cfg.ServiceSettings.EnableCustomEmoji = EnableCustomEmoji
}()
*utils.Cfg.ServiceSettings.EnableCustomEmoji = false
emoji := &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: model.NewId(),
}
// try to create an emoji when they're disabled
if _, err := Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif"); err == nil {
t.Fatal("shouldn't be able to create an emoji when they're disabled")
}
*utils.Cfg.ServiceSettings.EnableCustomEmoji = true
// try to create a valid gif emoji when they're enabled
if emojiResult, err := Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif"); err != nil {
t.Fatal(err)
} else {
emoji = emojiResult
}
// try to create an emoji with a duplicate name
emoji2 := &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: emoji.Name,
}
if _, err := Client.CreateEmoji(emoji2, utils.CreateTestGif(t, 10, 10), "image.gif"); err == nil {
t.Fatal("shouldn't be able to create an emoji with a duplicate name")
}
Client.MustGeneric(Client.DeleteEmoji(emoji.Id))
// try to create a valid animated gif emoji
emoji = &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: model.NewId(),
}
if emojiResult, err := Client.CreateEmoji(emoji, utils.CreateTestAnimatedGif(t, 10, 10, 10), "image.gif"); err != nil {
t.Fatal(err)
} else {
emoji = emojiResult
}
Client.MustGeneric(Client.DeleteEmoji(emoji.Id))
// try to create a valid jpeg emoji
emoji = &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: model.NewId(),
}
if emojiResult, err := Client.CreateEmoji(emoji, utils.CreateTestJpeg(t, 10, 10), "image.jpeg"); err != nil {
t.Fatal(err)
} else {
emoji = emojiResult
}
Client.MustGeneric(Client.DeleteEmoji(emoji.Id))
// try to create a valid png emoji
emoji = &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: model.NewId(),
}
if emojiResult, err := Client.CreateEmoji(emoji, utils.CreateTestPng(t, 10, 10), "image.png"); err != nil {
t.Fatal(err)
} else {
emoji = emojiResult
}
Client.MustGeneric(Client.DeleteEmoji(emoji.Id))
// try to create an emoji that's too wide
emoji = &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: model.NewId(),
}
if _, err := Client.CreateEmoji(emoji, utils.CreateTestGif(t, 1000, 10), "image.gif"); err != nil {
t.Fatal("should be able to create an emoji that's too wide by resizing it")
}
// try to create an emoji that's too tall
emoji = &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: model.NewId(),
}
if _, err := Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 1000), "image.gif"); err != nil {
t.Fatal("should be able to create an emoji that's too tall by resizing it")
}
// try to create an emoji that's too large
emoji = &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: model.NewId(),
}
if _, err := Client.CreateEmoji(emoji, utils.CreateTestAnimatedGif(t, 100, 100, 10000), "image.gif"); err == nil {
t.Fatal("shouldn't be able to create an emoji that's too large")
}
// try to create an emoji with data that isn't an image
emoji = &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: model.NewId(),
}
if _, err := Client.CreateEmoji(emoji, make([]byte, 100, 100), "image.gif"); err == nil {
t.Fatal("shouldn't be able to create an emoji with non-image data")
}
// try to create an emoji as another user
emoji = &model.Emoji{
CreatorId: th.BasicUser2.Id,
Name: model.NewId(),
}
if _, err := Client.CreateEmoji(emoji, utils.CreateTestGif(t, 10, 10), "image.gif"); err == nil {
t.Fatal("shouldn't be able to create an emoji as another user")
}
}
func TestDeleteEmoji(t *testing.T) {
th := Setup().InitBasic().InitSystemAdmin()
Client := th.BasicClient
EnableCustomEmoji := *utils.Cfg.ServiceSettings.EnableCustomEmoji
defer func() {
*utils.Cfg.ServiceSettings.EnableCustomEmoji = EnableCustomEmoji
}()
*utils.Cfg.ServiceSettings.EnableCustomEmoji = false
emoji1 := createTestEmoji(t, &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: model.NewId(),
}, utils.CreateTestGif(t, 10, 10))
if _, err := Client.DeleteEmoji(emoji1.Id); err == nil {
t.Fatal("shouldn't have been able to delete an emoji when they're disabled")
}
*utils.Cfg.ServiceSettings.EnableCustomEmoji = true
if deleted, err := Client.DeleteEmoji(emoji1.Id); err != nil {
t.Fatal(err)
} else if !deleted {
t.Fatalf("should be able to delete your own emoji %v", emoji1.Id)
}
if _, err := Client.DeleteEmoji(emoji1.Id); err == nil {
t.Fatal("shouldn't be able to delete an already-deleted emoji")
}
emoji2 := createTestEmoji(t, &model.Emoji{
CreatorId: th.BasicUser2.Id,
Name: model.NewId(),
}, utils.CreateTestGif(t, 10, 10))
if _, err := Client.DeleteEmoji(emoji2.Id); err == nil {
t.Fatal("shouldn't be able to delete another user's emoji")
}
if deleted, err := th.SystemAdminClient.DeleteEmoji(emoji2.Id); err != nil {
t.Fatal(err)
} else if !deleted {
t.Fatalf("system admin should be able to delete anyone's emoji %v", emoji2.Id)
}
}
func createTestEmoji(t *testing.T, emoji *model.Emoji, imageData []byte) *model.Emoji {
emoji = store.Must(app.Srv.Store.Emoji().Save(emoji)).(*model.Emoji)
if err := utils.WriteFile(imageData, "emoji/"+emoji.Id+"/image"); err != nil {
store.Must(app.Srv.Store.Emoji().Delete(emoji.Id, time.Now().Unix()))
t.Fatalf("failed to write image: %v", err.Error())
}
return emoji
}
func TestGetEmojiImage(t *testing.T) {
th := Setup().InitBasic()
Client := th.BasicClient
EnableCustomEmoji := *utils.Cfg.ServiceSettings.EnableCustomEmoji
RestrictCustomEmojiCreation := *utils.Cfg.ServiceSettings.RestrictCustomEmojiCreation
defer func() {
*utils.Cfg.ServiceSettings.EnableCustomEmoji = EnableCustomEmoji
*utils.Cfg.ServiceSettings.RestrictCustomEmojiCreation = RestrictCustomEmojiCreation
}()
*utils.Cfg.ServiceSettings.EnableCustomEmoji = true
*utils.Cfg.ServiceSettings.RestrictCustomEmojiCreation = model.RESTRICT_EMOJI_CREATION_ALL
emoji1 := &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: model.NewId(),
}
emoji1 = Client.MustGeneric(Client.CreateEmoji(emoji1, utils.CreateTestGif(t, 10, 10), "image.gif")).(*model.Emoji)
defer func() { Client.MustGeneric(Client.DeleteEmoji(emoji1.Id)) }()
*utils.Cfg.ServiceSettings.EnableCustomEmoji = false
if _, err := Client.DoApiGet(Client.GetCustomEmojiImageUrl(emoji1.Id), "", ""); err == nil {
t.Fatal("should've failed to get emoji image when disabled")
}
*utils.Cfg.ServiceSettings.EnableCustomEmoji = true
if resp, err := Client.DoApiGet(Client.GetCustomEmojiImageUrl(emoji1.Id), "", ""); err != nil {
t.Fatal(err)
} else if resp.Header.Get("Content-Type") != "image/gif" {
t.Fatal("should've received a gif")
} else if _, imageType, err := image.DecodeConfig(resp.Body); err != nil {
t.Fatalf("unable to identify received image: %v", err.Error())
} else if imageType != "gif" {
t.Fatal("should've received gif data")
}
emoji2 := &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: model.NewId(),
}
emoji2 = Client.MustGeneric(Client.CreateEmoji(emoji2, utils.CreateTestAnimatedGif(t, 10, 10, 10), "image.gif")).(*model.Emoji)
defer func() { Client.MustGeneric(Client.DeleteEmoji(emoji2.Id)) }()
if resp, err := Client.DoApiGet(Client.GetCustomEmojiImageUrl(emoji2.Id), "", ""); err != nil {
t.Fatal(err)
} else if resp.Header.Get("Content-Type") != "image/gif" {
t.Fatal("should've received a gif")
} else if _, imageType, err := image.DecodeConfig(resp.Body); err != nil {
t.Fatalf("unable to identify received image: %v", err.Error())
} else if imageType != "gif" {
t.Fatal("should've received gif data")
}
emoji3 := &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: model.NewId(),
}
emoji3 = Client.MustGeneric(Client.CreateEmoji(emoji3, utils.CreateTestJpeg(t, 10, 10), "image.jpeg")).(*model.Emoji)
defer func() { Client.MustGeneric(Client.DeleteEmoji(emoji3.Id)) }()
if resp, err := Client.DoApiGet(Client.GetCustomEmojiImageUrl(emoji3.Id), "", ""); err != nil {
t.Fatal(err)
} else if resp.Header.Get("Content-Type") != "image/jpeg" {
t.Fatal("should've received a jpeg")
} else if _, imageType, err := image.DecodeConfig(resp.Body); err != nil {
t.Fatalf("unable to identify received image: %v", err.Error())
} else if imageType != "jpeg" {
t.Fatal("should've received jpeg data")
}
emoji4 := &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: model.NewId(),
}
emoji4 = Client.MustGeneric(Client.CreateEmoji(emoji4, utils.CreateTestPng(t, 10, 10), "image.png")).(*model.Emoji)
defer func() { Client.MustGeneric(Client.DeleteEmoji(emoji4.Id)) }()
if resp, err := Client.DoApiGet(Client.GetCustomEmojiImageUrl(emoji4.Id), "", ""); err != nil {
t.Fatal(err)
} else if resp.Header.Get("Content-Type") != "image/png" {
t.Fatal("should've received a png")
} else if _, imageType, err := image.DecodeConfig(resp.Body); err != nil {
t.Fatalf("unable to identify received image: %v", err.Error())
} else if imageType != "png" {
t.Fatal("should've received png data")
}
emoji5 := &model.Emoji{
CreatorId: th.BasicUser.Id,
Name: model.NewId(),
}
emoji5 = Client.MustGeneric(Client.CreateEmoji(emoji5, utils.CreateTestPng(t, 10, 10), "image.png")).(*model.Emoji)
Client.MustGeneric(Client.DeleteEmoji(emoji5.Id))
if _, err := Client.DoApiGet(Client.GetCustomEmojiImageUrl(emoji5.Id), "", ""); err == nil {
t.Fatal("should've failed to get image for deleted emoji")
}
}
func TestResizeEmoji(t *testing.T) {
// try to resize a jpeg image within MaxEmojiWidth and MaxEmojiHeight
small_img_data := utils.CreateTestJpeg(t, app.MaxEmojiWidth, app.MaxEmojiHeight)
if small_img, _, err := image.Decode(bytes.NewReader(small_img_data)); err != nil {
t.Fatal("failed to decode jpeg bytes to image.Image")
} else {
resized_img := resizeEmoji(small_img, small_img.Bounds().Dx(), small_img.Bounds().Dy())
if resized_img.Bounds().Dx() > app.MaxEmojiWidth || resized_img.Bounds().Dy() > app.MaxEmojiHeight {
t.Fatal("resized jpeg width and height should not be greater than MaxEmojiWidth or MaxEmojiHeight")
}
if resized_img != small_img {
t.Fatal("should've returned small_img itself")
}
}
// try to resize a jpeg image
jpeg_data := utils.CreateTestJpeg(t, 256, 256)
if jpeg_img, _, err := image.Decode(bytes.NewReader(jpeg_data)); err != nil {
t.Fatal("failed to decode jpeg bytes to image.Image")
} else {
resized_jpeg := resizeEmoji(jpeg_img, jpeg_img.Bounds().Dx(), jpeg_img.Bounds().Dy())
if resized_jpeg.Bounds().Dx() > app.MaxEmojiWidth || resized_jpeg.Bounds().Dy() > app.MaxEmojiHeight {
t.Fatal("resized jpeg width and height should not be greater than MaxEmojiWidth or MaxEmojiHeight")
}
}
// try to resize a png image
png_data := utils.CreateTestJpeg(t, 256, 256)
if png_img, _, err := image.Decode(bytes.NewReader(png_data)); err != nil {
t.Fatal("failed to decode png bytes to image.Image")
} else {
resized_png := resizeEmoji(png_img, png_img.Bounds().Dx(), png_img.Bounds().Dy())
if resized_png.Bounds().Dx() > app.MaxEmojiWidth || resized_png.Bounds().Dy() > app.MaxEmojiHeight {
t.Fatal("resized png width and height should not be greater than MaxEmojiWidth or MaxEmojiHeight")
}
}
// try to resize an animated gif
gif_data := utils.CreateTestAnimatedGif(t, 256, 256, 10)
if gif_img, err := gif.DecodeAll(bytes.NewReader(gif_data)); err != nil {
t.Fatal("failed to decode gif bytes to gif.GIF")
} else {
resized_gif := resizeEmojiGif(gif_img)
if resized_gif.Config.Width > app.MaxEmojiWidth || resized_gif.Config.Height > app.MaxEmojiHeight {
t.Fatal("resized gif width and height should not be greater than MaxEmojiWidth or MaxEmojiHeight")
}
if len(resized_gif.Image) != len(gif_img.Image) {
t.Fatal("resized gif should have the same number of frames as original gif")
}
}
}