github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/import_test.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package app 5 6 import ( 7 "net/http" 8 "path/filepath" 9 "strings" 10 "testing" 11 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 15 "github.com/mattermost/mattermost-server/v5/model" 16 "github.com/mattermost/mattermost-server/v5/utils/fileutils" 17 ) 18 19 func ptrStr(s string) *string { 20 return &s 21 } 22 23 func ptrInt64(i int64) *int64 { 24 return &i 25 } 26 27 func ptrInt(i int) *int { 28 return &i 29 } 30 31 func ptrBool(b bool) *bool { 32 return &b 33 } 34 35 func checkPreference(t *testing.T, a *App, userId string, category string, name string, value string) { 36 preferences, err := a.Srv().Store.Preference().GetCategory(userId, category) 37 require.Nilf(t, err, "Failed to get preferences for user %v with category %v", userId, category) 38 found := false 39 for _, preference := range preferences { 40 if preference.Name == name { 41 found = true 42 require.Equal(t, preference.Value, value, "Preference for user %v in category %v with name %v has value %v, expected %v", userId, category, name, preference.Value, value) 43 break 44 } 45 } 46 require.Truef(t, found, "Did not find preference for user %v in category %v with name %v", userId, category, name) 47 } 48 49 func checkNotifyProp(t *testing.T, user *model.User, key string, value string) { 50 actual, ok := user.NotifyProps[key] 51 require.True(t, ok, "Notify prop %v not found. User: %v", key, user.Id) 52 require.Equalf(t, actual, value, "Notify Prop %v was %v but expected %v. User: %v", key, actual, value, user.Id) 53 } 54 55 func checkError(t *testing.T, err *model.AppError) { 56 require.NotNil(t, err, "Should have returned an error.") 57 } 58 59 func checkNoError(t *testing.T, err *model.AppError) { 60 require.Nil(t, err, "Unexpected Error: %v", err) 61 } 62 63 func AssertAllPostsCount(t *testing.T, a *App, initialCount int64, change int64, teamName string) { 64 result, err := a.Srv().Store.Post().AnalyticsPostCount(teamName, false, false) 65 require.Nil(t, err) 66 require.Equal(t, initialCount+change, result, "Did not find the expected number of posts.") 67 } 68 69 func AssertChannelCount(t *testing.T, a *App, channelType string, expectedCount int64) { 70 count, err := a.Srv().Store.Channel().AnalyticsTypeCount("", channelType) 71 require.Equalf(t, expectedCount, count, "Channel count of type: %v. Expected: %v, Got: %v", channelType, expectedCount, count) 72 require.Nil(t, err, "Failed to get channel count.") 73 } 74 75 func TestImportImportLine(t *testing.T) { 76 th := Setup(t) 77 defer th.TearDown() 78 79 // Try import line with an invalid type. 80 line := LineImportData{ 81 Type: "gibberish", 82 } 83 84 err := th.App.importLine(line, false) 85 require.NotNil(t, err, "Expected an error when importing a line with invalid type.") 86 87 // Try import line with team type but nil team. 88 line.Type = "team" 89 err = th.App.importLine(line, false) 90 require.NotNil(t, err, "Expected an error when importing a line of type team with a nil team.") 91 92 // Try import line with channel type but nil channel. 93 line.Type = "channel" 94 err = th.App.importLine(line, false) 95 require.NotNil(t, err, "Expected an error when importing a line with type channel with a nil channel.") 96 97 // Try import line with user type but nil user. 98 line.Type = "user" 99 err = th.App.importLine(line, false) 100 require.NotNil(t, err, "Expected an error when importing a line with type user with a nil user.") 101 102 // Try import line with post type but nil post. 103 line.Type = "post" 104 err = th.App.importLine(line, false) 105 require.NotNil(t, err, "Expected an error when importing a line with type post with a nil post.") 106 107 // Try import line with direct_channel type but nil direct_channel. 108 line.Type = "direct_channel" 109 err = th.App.importLine(line, false) 110 require.NotNil(t, err, "Expected an error when importing a line with type direct_channel with a nil direct_channel.") 111 112 // Try import line with direct_post type but nil direct_post. 113 line.Type = "direct_post" 114 err = th.App.importLine(line, false) 115 require.NotNil(t, err, "Expected an error when importing a line with type direct_post with a nil direct_post.") 116 117 // Try import line with scheme type but nil scheme. 118 line.Type = "scheme" 119 err = th.App.importLine(line, false) 120 require.NotNil(t, err, "Expected an error when importing a line with type scheme with a nil scheme.") 121 } 122 123 func TestStopOnError(t *testing.T) { 124 assert.True(t, stopOnError(LineImportWorkerError{ 125 model.NewAppError("test", "app.import.attachment.bad_file.error", nil, "", http.StatusBadRequest), 126 1, 127 })) 128 129 assert.True(t, stopOnError(LineImportWorkerError{ 130 model.NewAppError("test", "app.import.attachment.file_upload.error", nil, "", http.StatusBadRequest), 131 1, 132 })) 133 134 assert.False(t, stopOnError(LineImportWorkerError{ 135 model.NewAppError("test", "api.file.upload_file.large_image.app_error", nil, "", http.StatusBadRequest), 136 1, 137 })) 138 } 139 140 func TestImportBulkImport(t *testing.T) { 141 th := Setup(t) 142 defer th.TearDown() 143 144 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.EnableCustomEmoji = true }) 145 146 teamName := model.NewRandomTeamName() 147 channelName := model.NewId() 148 username := model.NewId() 149 username2 := model.NewId() 150 username3 := model.NewId() 151 emojiName := model.NewId() 152 testsDir, _ := fileutils.FindDir("tests") 153 testImage := filepath.Join(testsDir, "test.png") 154 teamTheme1 := `{\"awayIndicator\":\"#DBBD4E\",\"buttonBg\":\"#23A1FF\",\"buttonColor\":\"#FFFFFF\",\"centerChannelBg\":\"#ffffff\",\"centerChannelColor\":\"#333333\",\"codeTheme\":\"github\",\"image\":\"/static/files/a4a388b38b32678e83823ef1b3e17766.png\",\"linkColor\":\"#2389d7\",\"mentionBg\":\"#2389d7\",\"mentionColor\":\"#ffffff\",\"mentionHighlightBg\":\"#fff2bb\",\"mentionHighlightLink\":\"#2f81b7\",\"newMessageSeparator\":\"#FF8800\",\"onlineIndicator\":\"#7DBE00\",\"sidebarBg\":\"#fafafa\",\"sidebarHeaderBg\":\"#3481B9\",\"sidebarHeaderTextColor\":\"#ffffff\",\"sidebarText\":\"#333333\",\"sidebarTextActiveBorder\":\"#378FD2\",\"sidebarTextActiveColor\":\"#111111\",\"sidebarTextHoverBg\":\"#e6f2fa\",\"sidebarUnreadText\":\"#333333\",\"type\":\"Mattermost\"}` 155 teamTheme2 := `{\"awayIndicator\":\"#DBBD4E\",\"buttonBg\":\"#23A100\",\"buttonColor\":\"#EEEEEE\",\"centerChannelBg\":\"#ffffff\",\"centerChannelColor\":\"#333333\",\"codeTheme\":\"github\",\"image\":\"/static/files/a4a388b38b32678e83823ef1b3e17766.png\",\"linkColor\":\"#2389d7\",\"mentionBg\":\"#2389d7\",\"mentionColor\":\"#ffffff\",\"mentionHighlightBg\":\"#fff2bb\",\"mentionHighlightLink\":\"#2f81b7\",\"newMessageSeparator\":\"#FF8800\",\"onlineIndicator\":\"#7DBE00\",\"sidebarBg\":\"#fafafa\",\"sidebarHeaderBg\":\"#3481B9\",\"sidebarHeaderTextColor\":\"#ffffff\",\"sidebarText\":\"#333333\",\"sidebarTextActiveBorder\":\"#378FD2\",\"sidebarTextActiveColor\":\"#222222\",\"sidebarTextHoverBg\":\"#e6f2fa\",\"sidebarUnreadText\":\"#444444\",\"type\":\"Mattermost\"}` 156 157 // Run bulk import with a valid 1 of everything. 158 data1 := `{"type": "version", "version": 1} 159 {"type": "team", "team": {"type": "O", "display_name": "lskmw2d7a5ao7ppwqh5ljchvr4", "name": "` + teamName + `"}} 160 {"type": "channel", "channel": {"type": "O", "display_name": "xr6m6udffngark2uekvr3hoeny", "team": "` + teamName + `", "name": "` + channelName + `"}} 161 {"type": "user", "user": {"username": "` + username + `", "email": "` + username + `@example.com", "teams": [{"name": "` + teamName + `","theme": "` + teamTheme1 + `", "channels": [{"name": "` + channelName + `"}]}]}} 162 {"type": "user", "user": {"username": "` + username2 + `", "email": "` + username2 + `@example.com", "teams": [{"name": "` + teamName + `","theme": "` + teamTheme2 + `", "channels": [{"name": "` + channelName + `"}]}]}} 163 {"type": "user", "user": {"username": "` + username3 + `", "email": "` + username3 + `@example.com", "teams": [{"name": "` + teamName + `", "channels": [{"name": "` + channelName + `"}], "delete_at": 123456789016}]}} 164 {"type": "post", "post": {"team": "` + teamName + `", "channel": "` + channelName + `", "user": "` + username + `", "message": "Hello World", "create_at": 123456789012, "attachments":[{"path": "` + testImage + `"}]}} 165 {"type": "post", "post": {"team": "` + teamName + `", "channel": "` + channelName + `", "user": "` + username3 + `", "message": "Hey Everyone!", "create_at": 123456789013, "attachments":[{"path": "` + testImage + `"}]}} 166 {"type": "direct_channel", "direct_channel": {"members": ["` + username + `", "` + username + `"]}} 167 {"type": "direct_channel", "direct_channel": {"members": ["` + username + `", "` + username2 + `"]}} 168 {"type": "direct_channel", "direct_channel": {"members": ["` + username + `", "` + username2 + `", "` + username3 + `"]}} 169 {"type": "direct_post", "direct_post": {"channel_members": ["` + username + `", "` + username + `"], "user": "` + username + `", "message": "Hello Direct Channel to myself", "create_at": 123456789014}} 170 {"type": "direct_post", "direct_post": {"channel_members": ["` + username + `", "` + username2 + `"], "user": "` + username + `", "message": "Hello Direct Channel", "create_at": 123456789014}} 171 {"type": "direct_post", "direct_post": {"channel_members": ["` + username + `", "` + username2 + `", "` + username3 + `"], "user": "` + username + `", "message": "Hello Group Channel", "create_at": 123456789015}} 172 {"type": "emoji", "emoji": {"name": "` + emojiName + `", "image": "` + testImage + `"}}` 173 174 err, line := th.App.BulkImport(strings.NewReader(data1), false, 2) 175 require.Nil(t, err, "BulkImport should have succeeded") 176 require.Equal(t, 0, line, "BulkImport line should be 0") 177 178 // Run bulk import using a string that contains a line with invalid json. 179 data2 := `{"type": "version", "version": 1` 180 err, line = th.App.BulkImport(strings.NewReader(data2), false, 2) 181 require.NotNil(t, err, "Should have failed due to invalid JSON on line 1.") 182 require.Equal(t, 1, line, "Should have failed due to invalid JSON on line 1.") 183 184 // Run bulk import using valid JSON but missing version line at the start. 185 data3 := `{"type": "team", "team": {"type": "O", "display_name": "lskmw2d7a5ao7ppwqh5ljchvr4", "name": "` + teamName + `"}} 186 {"type": "channel", "channel": {"type": "O", "display_name": "xr6m6udffngark2uekvr3hoeny", "team": "` + teamName + `", "name": "` + channelName + `"}} 187 {"type": "user", "user": {"username": "kufjgnkxkrhhfgbrip6qxkfsaa", "email": "kufjgnkxkrhhfgbrip6qxkfsaa@example.com"}} 188 {"type": "user", "user": {"username": "bwshaim6qnc2ne7oqkd5b2s2rq", "email": "bwshaim6qnc2ne7oqkd5b2s2rq@example.com", "teams": [{"name": "` + teamName + `", "channels": [{"name": "` + channelName + `"}]}]}}` 189 err, line = th.App.BulkImport(strings.NewReader(data3), false, 2) 190 require.NotNil(t, err, "Should have failed due to missing version line on line 1.") 191 require.Equal(t, 1, line, "Should have failed due to missing version line on line 1.") 192 193 // Run bulk import using a valid and large input and a \r\n line break. 194 t.Run("", func(t *testing.T) { 195 posts := `{"type": "post"` + strings.Repeat(`, "post": {"team": "`+teamName+`", "channel": "`+channelName+`", "user": "`+username+`", "message": "Repeat after me", "create_at": 193456789012}`, 1E4) + "}" 196 data4 := `{"type": "version", "version": 1} 197 {"type": "team", "team": {"type": "O", "display_name": "lskmw2d7a5ao7ppwqh5ljchvr4", "name": "` + teamName + `"}} 198 {"type": "channel", "channel": {"type": "O", "display_name": "xr6m6udffngark2uekvr3hoeny", "team": "` + teamName + `", "name": "` + channelName + `"}} 199 {"type": "user", "user": {"username": "` + username + `", "email": "` + username + `@example.com", "teams": [{"name": "` + teamName + `","theme": "` + teamTheme1 + `", "channels": [{"name": "` + channelName + `"}]}]}} 200 {"type": "post", "post": {"team": "` + teamName + `", "channel": "` + channelName + `", "user": "` + username + `", "message": "Hello World", "create_at": 123456789012}}` 201 err, line = th.App.BulkImport(strings.NewReader(data4+"\r\n"+posts), false, 2) 202 require.Nil(t, err, "BulkImport should have succeeded") 203 require.Equal(t, 0, line, "BulkImport line should be 0") 204 }) 205 206 t.Run("First item after version without type", func(t *testing.T) { 207 data := `{"type": "version", "version": 1} 208 {"name": "custom-emoji-troll", "image": "bulkdata/emoji/trollolol.png"}` 209 err, line := th.App.BulkImport(strings.NewReader(data), false, 2) 210 require.NotNil(t, err, "Should have failed due to invalid type on line 2.") 211 require.Equal(t, 2, line, "Should have failed due to invalid type on line 2.") 212 }) 213 214 t.Run("Posts with prop information", func(t *testing.T) { 215 data6 := `{"type": "version", "version": 1} 216 {"type": "team", "team": {"type": "O", "display_name": "lskmw2d7a5ao7ppwqh5ljchvr4", "name": "` + teamName + `"}} 217 {"type": "channel", "channel": {"type": "O", "display_name": "xr6m6udffngark2uekvr3hoeny", "team": "` + teamName + `", "name": "` + channelName + `"}} 218 {"type": "user", "user": {"username": "` + username + `", "email": "` + username + `@example.com", "teams": [{"name": "` + teamName + `","theme": "` + teamTheme1 + `", "channels": [{"name": "` + channelName + `"}]}]}} 219 {"type": "post", "post": {"team": "` + teamName + `", "channel": "` + channelName + `", "user": "` + username + `", "message": "Hello World", "create_at": 123456789012, "attachments":[{"path": "` + testImage + `"}], "props":{"attachments":[{"id":0,"fallback":"[February 4th, 2020 2:46 PM] author: fallback","color":"D0D0D0","pretext":"","author_name":"author","author_link":"","title":"","title_link":"","text":"this post has props","fields":null,"image_url":"","thumb_url":"","footer":"Posted in #general","footer_icon":"","ts":"1580823992.000100"}]}}} 220 {"type": "direct_channel", "direct_channel": {"members": ["` + username + `", "` + username + `"]}} 221 {"type": "direct_post", "direct_post": {"channel_members": ["` + username + `", "` + username + `"], "user": "` + username + `", "message": "Hello Direct Channel to myself", "create_at": 123456789014, "props":{"attachments":[{"id":0,"fallback":"[February 4th, 2020 2:46 PM] author: fallback","color":"D0D0D0","pretext":"","author_name":"author","author_link":"","title":"","title_link":"","text":"this post has props","fields":null,"image_url":"","thumb_url":"","footer":"Posted in #general","footer_icon":"","ts":"1580823992.000100"}]}}}}` 222 223 err, line := th.App.BulkImport(strings.NewReader(data6), false, 2) 224 require.Nil(t, err, "BulkImport should have succeeded") 225 require.Equal(t, 0, line, "BulkImport line should be 0") 226 }) 227 } 228 229 func TestImportProcessImportDataFileVersionLine(t *testing.T) { 230 data := LineImportData{ 231 Type: "version", 232 Version: ptrInt(1), 233 } 234 version, err := processImportDataFileVersionLine(data) 235 require.Nil(t, err, "Expected no error") 236 require.Equal(t, 1, version, "Expected version 1") 237 238 data.Type = "NotVersion" 239 _, err = processImportDataFileVersionLine(data) 240 require.NotNil(t, err, "Expected error on invalid version line.") 241 242 data.Type = "version" 243 data.Version = nil 244 _, err = processImportDataFileVersionLine(data) 245 require.NotNil(t, err, "Expected error on invalid version line.") 246 } 247 248 func GetAttachments(userId string, th *TestHelper, t *testing.T) []*model.FileInfo { 249 fileInfos, err := th.App.Srv().Store.FileInfo().GetForUser(userId) 250 require.Nil(t, err) 251 return fileInfos 252 } 253 254 func AssertFileIdsInPost(files []*model.FileInfo, th *TestHelper, t *testing.T) { 255 postId := files[0].PostId 256 require.NotNil(t, postId) 257 258 posts, err := th.App.Srv().Store.Post().GetPostsByIds([]string{postId}) 259 require.Nil(t, err) 260 261 require.Len(t, posts, 1) 262 for _, file := range files { 263 assert.Contains(t, posts[0].FileIds, file.Id) 264 } 265 }