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  }