github.com/mattermost/mattermost-server/v5@v5.39.3/store/storetest/file_info_store.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package storetest
     5  
     6  import (
     7  	"fmt"
     8  	"sort"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/mattermost/mattermost-server/v5/model"
    13  	"github.com/mattermost/mattermost-server/v5/store"
    14  
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  func TestFileInfoStore(t *testing.T, ss store.Store) {
    20  	t.Run("FileInfoSaveGet", func(t *testing.T) { testFileInfoSaveGet(t, ss) })
    21  	t.Run("FileInfoSaveGetByPath", func(t *testing.T) { testFileInfoSaveGetByPath(t, ss) })
    22  	t.Run("FileInfoGetForPost", func(t *testing.T) { testFileInfoGetForPost(t, ss) })
    23  	t.Run("FileInfoGetForUser", func(t *testing.T) { testFileInfoGetForUser(t, ss) })
    24  	t.Run("FileInfoGetWithOptions", func(t *testing.T) { testFileInfoGetWithOptions(t, ss) })
    25  	t.Run("FileInfoAttachToPost", func(t *testing.T) { testFileInfoAttachToPost(t, ss) })
    26  	t.Run("FileInfoDeleteForPost", func(t *testing.T) { testFileInfoDeleteForPost(t, ss) })
    27  	t.Run("FileInfoPermanentDelete", func(t *testing.T) { testFileInfoPermanentDelete(t, ss) })
    28  	t.Run("FileInfoPermanentDeleteBatch", func(t *testing.T) { testFileInfoPermanentDeleteBatch(t, ss) })
    29  	t.Run("FileInfoPermanentDeleteByUser", func(t *testing.T) { testFileInfoPermanentDeleteByUser(t, ss) })
    30  	t.Run("GetFilesBatchForIndexing", func(t *testing.T) { testFileInfoStoreGetFilesBatchForIndexing(t, ss) })
    31  	t.Run("CountAll", func(t *testing.T) { testFileInfoStoreCountAll(t, ss) })
    32  }
    33  
    34  func testFileInfoSaveGet(t *testing.T, ss store.Store) {
    35  	info := &model.FileInfo{
    36  		CreatorId: model.NewId(),
    37  		Path:      "file.txt",
    38  	}
    39  
    40  	info, err := ss.FileInfo().Save(info)
    41  	require.NoError(t, err)
    42  	require.NotEqual(t, len(info.Id), 0)
    43  
    44  	defer func() {
    45  		ss.FileInfo().PermanentDelete(info.Id)
    46  	}()
    47  
    48  	rinfo, err := ss.FileInfo().Get(info.Id)
    49  	require.NoError(t, err)
    50  	require.Equal(t, info.Id, rinfo.Id)
    51  
    52  	info2, err := ss.FileInfo().Save(&model.FileInfo{
    53  		CreatorId: model.NewId(),
    54  		Path:      "file.txt",
    55  		DeleteAt:  123,
    56  	})
    57  	require.NoError(t, err)
    58  
    59  	_, err = ss.FileInfo().Get(info2.Id)
    60  	assert.Error(t, err)
    61  
    62  	defer func() {
    63  		ss.FileInfo().PermanentDelete(info2.Id)
    64  	}()
    65  }
    66  
    67  func testFileInfoSaveGetByPath(t *testing.T, ss store.Store) {
    68  	info := &model.FileInfo{
    69  		CreatorId: model.NewId(),
    70  		Path:      fmt.Sprintf("%v/file.txt", model.NewId()),
    71  	}
    72  
    73  	info, err := ss.FileInfo().Save(info)
    74  	require.NoError(t, err)
    75  	assert.NotEqual(t, len(info.Id), 0)
    76  	defer func() {
    77  		ss.FileInfo().PermanentDelete(info.Id)
    78  	}()
    79  
    80  	rinfo, err := ss.FileInfo().GetByPath(info.Path)
    81  	require.NoError(t, err)
    82  	assert.Equal(t, info.Id, rinfo.Id)
    83  
    84  	info2, err := ss.FileInfo().Save(&model.FileInfo{
    85  		CreatorId: model.NewId(),
    86  		Path:      "file.txt",
    87  		DeleteAt:  123,
    88  	})
    89  	require.NoError(t, err)
    90  
    91  	_, err = ss.FileInfo().GetByPath(info2.Id)
    92  	assert.Error(t, err)
    93  
    94  	defer func() {
    95  		ss.FileInfo().PermanentDelete(info2.Id)
    96  	}()
    97  }
    98  
    99  func testFileInfoGetForPost(t *testing.T, ss store.Store) {
   100  	userId := model.NewId()
   101  	postId := model.NewId()
   102  
   103  	infos := []*model.FileInfo{
   104  		{
   105  			PostId:    postId,
   106  			CreatorId: userId,
   107  			Path:      "file.txt",
   108  		},
   109  		{
   110  			PostId:    postId,
   111  			CreatorId: userId,
   112  			Path:      "file.txt",
   113  		},
   114  		{
   115  			PostId:    postId,
   116  			CreatorId: userId,
   117  			Path:      "file.txt",
   118  			DeleteAt:  123,
   119  		},
   120  		{
   121  			PostId:    model.NewId(),
   122  			CreatorId: userId,
   123  			Path:      "file.txt",
   124  		},
   125  	}
   126  
   127  	for i, info := range infos {
   128  		newInfo, err := ss.FileInfo().Save(info)
   129  		require.NoError(t, err)
   130  		infos[i] = newInfo
   131  		defer func(id string) {
   132  			ss.FileInfo().PermanentDelete(id)
   133  		}(newInfo.Id)
   134  	}
   135  
   136  	testCases := []struct {
   137  		Name           string
   138  		PostId         string
   139  		ReadFromMaster bool
   140  		IncludeDeleted bool
   141  		AllowFromCache bool
   142  		ExpectedPosts  int
   143  	}{
   144  		{
   145  			Name:           "Fetch from master, without deleted and without cache",
   146  			PostId:         postId,
   147  			ReadFromMaster: true,
   148  			IncludeDeleted: false,
   149  			AllowFromCache: false,
   150  			ExpectedPosts:  2,
   151  		},
   152  		{
   153  			Name:           "Fetch from master, with deleted and without cache",
   154  			PostId:         postId,
   155  			ReadFromMaster: true,
   156  			IncludeDeleted: true,
   157  			AllowFromCache: false,
   158  			ExpectedPosts:  3,
   159  		},
   160  		{
   161  			Name:           "Fetch from master, with deleted and with cache",
   162  			PostId:         postId,
   163  			ReadFromMaster: true,
   164  			IncludeDeleted: true,
   165  			AllowFromCache: true,
   166  			ExpectedPosts:  3,
   167  		},
   168  		{
   169  			Name:           "Fetch from replica, without deleted and without cache",
   170  			PostId:         postId,
   171  			ReadFromMaster: false,
   172  			IncludeDeleted: false,
   173  			AllowFromCache: false,
   174  			ExpectedPosts:  2,
   175  		},
   176  		{
   177  			Name:           "Fetch from replica, with deleted and without cache",
   178  			PostId:         postId,
   179  			ReadFromMaster: false,
   180  			IncludeDeleted: true,
   181  			AllowFromCache: false,
   182  			ExpectedPosts:  3,
   183  		},
   184  		{
   185  			Name:           "Fetch from replica, with deleted and without cache",
   186  			PostId:         postId,
   187  			ReadFromMaster: false,
   188  			IncludeDeleted: true,
   189  			AllowFromCache: true,
   190  			ExpectedPosts:  3,
   191  		},
   192  		{
   193  			Name:           "Fetch from replica, without deleted and with cache",
   194  			PostId:         postId,
   195  			ReadFromMaster: true,
   196  			IncludeDeleted: false,
   197  			AllowFromCache: true,
   198  			ExpectedPosts:  2,
   199  		},
   200  	}
   201  
   202  	for _, tc := range testCases {
   203  		t.Run(tc.Name, func(t *testing.T) {
   204  			postInfos, err := ss.FileInfo().GetForPost(
   205  				tc.PostId,
   206  				tc.ReadFromMaster,
   207  				tc.IncludeDeleted,
   208  				tc.AllowFromCache,
   209  			)
   210  			require.NoError(t, err)
   211  			assert.Len(t, postInfos, tc.ExpectedPosts)
   212  
   213  		})
   214  	}
   215  }
   216  
   217  func testFileInfoGetForUser(t *testing.T, ss store.Store) {
   218  	userId := model.NewId()
   219  	userId2 := model.NewId()
   220  	postId := model.NewId()
   221  
   222  	infos := []*model.FileInfo{
   223  		{
   224  			PostId:    postId,
   225  			CreatorId: userId,
   226  			Path:      "file.txt",
   227  		},
   228  		{
   229  			PostId:    postId,
   230  			CreatorId: userId,
   231  			Path:      "file.txt",
   232  		},
   233  		{
   234  			PostId:    postId,
   235  			CreatorId: userId,
   236  			Path:      "file.txt",
   237  		},
   238  		{
   239  			PostId:    model.NewId(),
   240  			CreatorId: userId2,
   241  			Path:      "file.txt",
   242  		},
   243  	}
   244  
   245  	for i, info := range infos {
   246  		newInfo, err := ss.FileInfo().Save(info)
   247  		require.NoError(t, err)
   248  		infos[i] = newInfo
   249  		defer func(id string) {
   250  			ss.FileInfo().PermanentDelete(id)
   251  		}(newInfo.Id)
   252  	}
   253  
   254  	userPosts, err := ss.FileInfo().GetForUser(userId)
   255  	require.NoError(t, err)
   256  	assert.Len(t, userPosts, 3)
   257  
   258  	userPosts, err = ss.FileInfo().GetForUser(userId2)
   259  	require.NoError(t, err)
   260  	assert.Len(t, userPosts, 1)
   261  }
   262  
   263  func testFileInfoGetWithOptions(t *testing.T, ss store.Store) {
   264  	makePost := func(chId string, user string) *model.Post {
   265  		post := model.Post{}
   266  		post.ChannelId = chId
   267  		post.UserId = user
   268  		_, err := ss.Post().Save(&post)
   269  		require.NoError(t, err)
   270  		return &post
   271  	}
   272  
   273  	makeFile := func(post *model.Post, user string, createAt int64, idPrefix string) model.FileInfo {
   274  		id := model.NewId()
   275  		id = idPrefix + id[1:] // hacky way to get sortable Ids to confirm secondary Id sort works
   276  		fileInfo := model.FileInfo{
   277  			Id:        id,
   278  			CreatorId: user,
   279  			Path:      "file.txt",
   280  			CreateAt:  createAt,
   281  		}
   282  		if post.Id != "" {
   283  			fileInfo.PostId = post.Id
   284  		}
   285  		_, err := ss.FileInfo().Save(&fileInfo)
   286  		require.NoError(t, err)
   287  		return fileInfo
   288  	}
   289  
   290  	userId1 := model.NewId()
   291  	userId2 := model.NewId()
   292  
   293  	channelId1 := model.NewId()
   294  	channelId2 := model.NewId()
   295  	channelId3 := model.NewId()
   296  
   297  	post1_1 := makePost(channelId1, userId1) // post 1 by user 1
   298  	post1_2 := makePost(channelId3, userId1) // post 2 by user 1
   299  	post2_1 := makePost(channelId2, userId2)
   300  	post2_2 := makePost(channelId3, userId2)
   301  
   302  	epoch := time.Date(2020, 1, 1, 1, 1, 1, 1, time.UTC)
   303  	file1_1 := makeFile(post1_1, userId1, epoch.AddDate(0, 0, 1).Unix(), "a")       // file 1 by user 1
   304  	file1_2 := makeFile(post1_2, userId1, epoch.AddDate(0, 0, 2).Unix(), "b")       // file 2 by user 1
   305  	file1_3 := makeFile(&model.Post{}, userId1, epoch.AddDate(0, 0, 3).Unix(), "c") // file that is not attached to a post
   306  	file2_1 := makeFile(post2_1, userId2, epoch.AddDate(0, 0, 4).Unix(), "d")       // file 2 by user 1
   307  	file2_2 := makeFile(post2_2, userId2, epoch.AddDate(0, 0, 5).Unix(), "e")
   308  
   309  	// delete a file
   310  	_, err := ss.FileInfo().DeleteForPost(file2_2.PostId)
   311  	require.NoError(t, err)
   312  
   313  	testCases := []struct {
   314  		Name            string
   315  		Page, PerPage   int
   316  		Opt             *model.GetFileInfosOptions
   317  		ExpectedFileIds []string
   318  	}{
   319  		{
   320  			Name:            "Get files with nil option",
   321  			Page:            0,
   322  			PerPage:         10,
   323  			Opt:             nil,
   324  			ExpectedFileIds: []string{file1_1.Id, file1_2.Id, file1_3.Id, file2_1.Id},
   325  		},
   326  		{
   327  			Name:            "Get files including deleted",
   328  			Page:            0,
   329  			PerPage:         10,
   330  			Opt:             &model.GetFileInfosOptions{IncludeDeleted: true},
   331  			ExpectedFileIds: []string{file1_1.Id, file1_2.Id, file1_3.Id, file2_1.Id, file2_2.Id},
   332  		},
   333  		{
   334  			Name:    "Get files including deleted filtered by channel",
   335  			Page:    0,
   336  			PerPage: 10,
   337  			Opt: &model.GetFileInfosOptions{
   338  				IncludeDeleted: true,
   339  				ChannelIds:     []string{channelId3},
   340  			},
   341  			ExpectedFileIds: []string{file1_2.Id, file2_2.Id},
   342  		},
   343  		{
   344  			Name:    "Get files including deleted filtered by channel and user",
   345  			Page:    0,
   346  			PerPage: 10,
   347  			Opt: &model.GetFileInfosOptions{
   348  				IncludeDeleted: true,
   349  				UserIds:        []string{userId1},
   350  				ChannelIds:     []string{channelId3},
   351  			},
   352  			ExpectedFileIds: []string{file1_2.Id},
   353  		},
   354  		{
   355  			Name:    "Get files including deleted sorted by created at",
   356  			Page:    0,
   357  			PerPage: 10,
   358  			Opt: &model.GetFileInfosOptions{
   359  				IncludeDeleted: true,
   360  				SortBy:         model.FILEINFO_SORT_BY_CREATED,
   361  			},
   362  			ExpectedFileIds: []string{file1_1.Id, file1_2.Id, file1_3.Id, file2_1.Id, file2_2.Id},
   363  		},
   364  		{
   365  			Name:    "Get files filtered by user ordered by created at descending",
   366  			Page:    0,
   367  			PerPage: 10,
   368  			Opt: &model.GetFileInfosOptions{
   369  				UserIds:        []string{userId1},
   370  				SortBy:         model.FILEINFO_SORT_BY_CREATED,
   371  				SortDescending: true,
   372  			},
   373  			ExpectedFileIds: []string{file1_3.Id, file1_2.Id, file1_1.Id},
   374  		},
   375  		{
   376  			Name:    "Get all files including deleted ordered by created descending 2nd page of 3 per page ",
   377  			Page:    1,
   378  			PerPage: 3,
   379  			Opt: &model.GetFileInfosOptions{
   380  				IncludeDeleted: true,
   381  				SortBy:         model.FILEINFO_SORT_BY_CREATED,
   382  				SortDescending: true,
   383  			},
   384  			ExpectedFileIds: []string{file1_2.Id, file1_1.Id},
   385  		},
   386  	}
   387  
   388  	for _, tc := range testCases {
   389  		t.Run(tc.Name, func(t *testing.T) {
   390  			fileInfos, err := ss.FileInfo().GetWithOptions(tc.Page, tc.PerPage, tc.Opt)
   391  			require.NoError(t, err)
   392  			require.Len(t, fileInfos, len(tc.ExpectedFileIds))
   393  			for i := range tc.ExpectedFileIds {
   394  				assert.Equal(t, tc.ExpectedFileIds[i], fileInfos[i].Id)
   395  			}
   396  		})
   397  	}
   398  }
   399  
   400  type byFileInfoId []*model.FileInfo
   401  
   402  func (a byFileInfoId) Len() int           { return len(a) }
   403  func (a byFileInfoId) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   404  func (a byFileInfoId) Less(i, j int) bool { return a[i].Id < a[j].Id }
   405  
   406  func testFileInfoAttachToPost(t *testing.T, ss store.Store) {
   407  	t.Run("should attach files", func(t *testing.T) {
   408  		userId := model.NewId()
   409  		postId := model.NewId()
   410  
   411  		info1, err := ss.FileInfo().Save(&model.FileInfo{
   412  			CreatorId: userId,
   413  			Path:      "file.txt",
   414  		})
   415  		require.NoError(t, err)
   416  		info2, err := ss.FileInfo().Save(&model.FileInfo{
   417  			CreatorId: userId,
   418  			Path:      "file2.txt",
   419  		})
   420  		require.NoError(t, err)
   421  
   422  		require.Equal(t, "", info1.PostId)
   423  		require.Equal(t, "", info2.PostId)
   424  
   425  		err = ss.FileInfo().AttachToPost(info1.Id, postId, userId)
   426  		assert.NoError(t, err)
   427  		info1.PostId = postId
   428  
   429  		err = ss.FileInfo().AttachToPost(info2.Id, postId, userId)
   430  		assert.NoError(t, err)
   431  		info2.PostId = postId
   432  
   433  		data, err := ss.FileInfo().GetForPost(postId, true, false, false)
   434  		require.NoError(t, err)
   435  
   436  		expected := []*model.FileInfo{info1, info2}
   437  		sort.Sort(byFileInfoId(expected))
   438  		sort.Sort(byFileInfoId(data))
   439  		assert.EqualValues(t, expected, data)
   440  	})
   441  
   442  	t.Run("should not attach files to multiple posts", func(t *testing.T) {
   443  		userId := model.NewId()
   444  		postId := model.NewId()
   445  
   446  		info, err := ss.FileInfo().Save(&model.FileInfo{
   447  			CreatorId: userId,
   448  			Path:      "file.txt",
   449  		})
   450  		require.NoError(t, err)
   451  
   452  		require.Equal(t, "", info.PostId)
   453  
   454  		err = ss.FileInfo().AttachToPost(info.Id, model.NewId(), userId)
   455  		require.NoError(t, err)
   456  
   457  		err = ss.FileInfo().AttachToPost(info.Id, postId, userId)
   458  		require.Error(t, err)
   459  	})
   460  
   461  	t.Run("should not attach files owned from a different user", func(t *testing.T) {
   462  		userId := model.NewId()
   463  		postId := model.NewId()
   464  
   465  		info, err := ss.FileInfo().Save(&model.FileInfo{
   466  			CreatorId: model.NewId(),
   467  			Path:      "file.txt",
   468  		})
   469  		require.NoError(t, err)
   470  
   471  		require.Equal(t, "", info.PostId)
   472  
   473  		err = ss.FileInfo().AttachToPost(info.Id, postId, userId)
   474  		assert.Error(t, err)
   475  	})
   476  
   477  	t.Run("should attach files uploaded by nouser", func(t *testing.T) {
   478  		postId := model.NewId()
   479  
   480  		info, err := ss.FileInfo().Save(&model.FileInfo{
   481  			CreatorId: "nouser",
   482  			Path:      "file.txt",
   483  		})
   484  		require.NoError(t, err)
   485  		assert.Equal(t, "", info.PostId)
   486  
   487  		err = ss.FileInfo().AttachToPost(info.Id, postId, model.NewId())
   488  		require.NoError(t, err)
   489  
   490  		data, err := ss.FileInfo().GetForPost(postId, true, false, false)
   491  		require.NoError(t, err)
   492  		info.PostId = postId
   493  		assert.EqualValues(t, []*model.FileInfo{info}, data)
   494  	})
   495  }
   496  
   497  func testFileInfoDeleteForPost(t *testing.T, ss store.Store) {
   498  	userId := model.NewId()
   499  	postId := model.NewId()
   500  
   501  	infos := []*model.FileInfo{
   502  		{
   503  			PostId:    postId,
   504  			CreatorId: userId,
   505  			Path:      "file.txt",
   506  		},
   507  		{
   508  			PostId:    postId,
   509  			CreatorId: userId,
   510  			Path:      "file.txt",
   511  		},
   512  		{
   513  			PostId:    postId,
   514  			CreatorId: userId,
   515  			Path:      "file.txt",
   516  			DeleteAt:  123,
   517  		},
   518  		{
   519  			PostId:    model.NewId(),
   520  			CreatorId: userId,
   521  			Path:      "file.txt",
   522  		},
   523  	}
   524  
   525  	for i, info := range infos {
   526  		newInfo, err := ss.FileInfo().Save(info)
   527  		require.NoError(t, err)
   528  		infos[i] = newInfo
   529  		defer func(id string) {
   530  			ss.FileInfo().PermanentDelete(id)
   531  		}(newInfo.Id)
   532  	}
   533  
   534  	_, err := ss.FileInfo().DeleteForPost(postId)
   535  	require.NoError(t, err)
   536  
   537  	infos, err = ss.FileInfo().GetForPost(postId, true, false, false)
   538  	require.NoError(t, err)
   539  	assert.Empty(t, infos)
   540  }
   541  
   542  func testFileInfoPermanentDelete(t *testing.T, ss store.Store) {
   543  	info, err := ss.FileInfo().Save(&model.FileInfo{
   544  		PostId:    model.NewId(),
   545  		CreatorId: model.NewId(),
   546  		Path:      "file.txt",
   547  	})
   548  	require.NoError(t, err)
   549  
   550  	err = ss.FileInfo().PermanentDelete(info.Id)
   551  	require.NoError(t, err)
   552  }
   553  
   554  func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) {
   555  	postId := model.NewId()
   556  
   557  	_, err := ss.FileInfo().Save(&model.FileInfo{
   558  		PostId:    postId,
   559  		CreatorId: model.NewId(),
   560  		Path:      "file.txt",
   561  		CreateAt:  1000,
   562  	})
   563  	require.NoError(t, err)
   564  
   565  	_, err = ss.FileInfo().Save(&model.FileInfo{
   566  		PostId:    postId,
   567  		CreatorId: model.NewId(),
   568  		Path:      "file.txt",
   569  		CreateAt:  1200,
   570  	})
   571  	require.NoError(t, err)
   572  
   573  	_, err = ss.FileInfo().Save(&model.FileInfo{
   574  		PostId:    postId,
   575  		CreatorId: model.NewId(),
   576  		Path:      "file.txt",
   577  		CreateAt:  2000,
   578  	})
   579  	require.NoError(t, err)
   580  
   581  	postFiles, err := ss.FileInfo().GetForPost(postId, true, false, false)
   582  	require.NoError(t, err)
   583  	assert.Len(t, postFiles, 3)
   584  
   585  	_, err = ss.FileInfo().PermanentDeleteBatch(1500, 1000)
   586  	require.NoError(t, err)
   587  
   588  	postFiles, err = ss.FileInfo().GetForPost(postId, true, false, false)
   589  	require.NoError(t, err)
   590  	assert.Len(t, postFiles, 1)
   591  }
   592  
   593  func testFileInfoPermanentDeleteByUser(t *testing.T, ss store.Store) {
   594  	userId := model.NewId()
   595  	postId := model.NewId()
   596  
   597  	_, err := ss.FileInfo().Save(&model.FileInfo{
   598  		PostId:    postId,
   599  		CreatorId: userId,
   600  		Path:      "file.txt",
   601  	})
   602  	require.NoError(t, err)
   603  
   604  	_, err = ss.FileInfo().PermanentDeleteByUser(userId)
   605  	require.NoError(t, err)
   606  }
   607  
   608  func testFileInfoStoreGetFilesBatchForIndexing(t *testing.T, ss store.Store) {
   609  	c1 := &model.Channel{}
   610  	c1.TeamId = model.NewId()
   611  	c1.DisplayName = "Channel1"
   612  	c1.Name = "zz" + model.NewId() + "b"
   613  	c1.Type = model.CHANNEL_OPEN
   614  	c1, _ = ss.Channel().Save(c1, -1)
   615  
   616  	c2 := &model.Channel{}
   617  	c2.TeamId = model.NewId()
   618  	c2.DisplayName = "Channel2"
   619  	c2.Name = "zz" + model.NewId() + "b"
   620  	c2.Type = model.CHANNEL_OPEN
   621  	c2, _ = ss.Channel().Save(c2, -1)
   622  
   623  	o1 := &model.Post{}
   624  	o1.ChannelId = c1.Id
   625  	o1.UserId = model.NewId()
   626  	o1.Message = "zz" + model.NewId() + "AAAAAAAAAAA"
   627  	o1, err := ss.Post().Save(o1)
   628  	require.NoError(t, err)
   629  	f1, err := ss.FileInfo().Save(&model.FileInfo{
   630  		PostId:    o1.Id,
   631  		CreatorId: model.NewId(),
   632  		Path:      "file1.txt",
   633  	})
   634  	require.NoError(t, err)
   635  	defer func() {
   636  		ss.FileInfo().PermanentDelete(f1.Id)
   637  	}()
   638  	time.Sleep(1 * time.Millisecond)
   639  
   640  	o2 := &model.Post{}
   641  	o2.ChannelId = c2.Id
   642  	o2.UserId = model.NewId()
   643  	o2.Message = "zz" + model.NewId() + "CCCCCCCCC"
   644  	o2, err = ss.Post().Save(o2)
   645  	require.NoError(t, err)
   646  
   647  	f2, err := ss.FileInfo().Save(&model.FileInfo{
   648  		PostId:    o2.Id,
   649  		CreatorId: model.NewId(),
   650  		Path:      "file2.txt",
   651  	})
   652  	require.NoError(t, err)
   653  	defer func() {
   654  		ss.FileInfo().PermanentDelete(f2.Id)
   655  	}()
   656  	time.Sleep(1 * time.Millisecond)
   657  
   658  	o3 := &model.Post{}
   659  	o3.ChannelId = c1.Id
   660  	o3.UserId = model.NewId()
   661  	o3.ParentId = o1.Id
   662  	o3.RootId = o1.Id
   663  	o3.Message = "zz" + model.NewId() + "QQQQQQQQQQ"
   664  	o3, err = ss.Post().Save(o3)
   665  	require.NoError(t, err)
   666  
   667  	f3, err := ss.FileInfo().Save(&model.FileInfo{
   668  		PostId:    o3.Id,
   669  		CreatorId: model.NewId(),
   670  		Path:      "file3.txt",
   671  	})
   672  	require.NoError(t, err)
   673  	defer func() {
   674  		ss.FileInfo().PermanentDelete(f3.Id)
   675  	}()
   676  
   677  	t.Run("get all files", func(t *testing.T) {
   678  		r, err := ss.FileInfo().GetFilesBatchForIndexing(f1.CreateAt, model.GetMillis()+100000, 100)
   679  		require.NoError(t, err)
   680  		require.Len(t, r, 3, "Expected 3 posts in results. Got %v", len(r))
   681  		for _, f := range r {
   682  			if f.Id == f1.Id {
   683  				require.Equal(t, f.ChannelId, o1.ChannelId, "Unexpected channel ID")
   684  				require.Equal(t, f.Path, "file1.txt", "Unexpected filename")
   685  			} else if f.Id == f2.Id {
   686  				require.Equal(t, f.ChannelId, o2.ChannelId, "Unexpected channel ID")
   687  				require.Equal(t, f.Path, "file2.txt", "Unexpected filename")
   688  			} else if f.Id == f3.Id {
   689  				require.Equal(t, f.ChannelId, o3.ChannelId, "Unexpected channel ID")
   690  				require.Equal(t, f.Path, "file3.txt", "Unexpected filename")
   691  			} else {
   692  				require.Fail(t, "unexpected file returned")
   693  			}
   694  		}
   695  	})
   696  
   697  	t.Run("get files after certain date", func(t *testing.T) {
   698  		r, err := ss.FileInfo().GetFilesBatchForIndexing(f1.CreateAt+1, model.GetMillis()+100000, 100)
   699  		require.NoError(t, err)
   700  		require.Len(t, r, 2, "Expected 2 posts in results. Got %v", len(r))
   701  		for _, f := range r {
   702  			if f.Id == f2.Id {
   703  				require.Equal(t, f.ChannelId, o2.ChannelId, "Unexpected channel ID")
   704  				require.Equal(t, f.Path, "file2.txt", "Unexpected filename")
   705  			} else if f.Id == f3.Id {
   706  				require.Equal(t, f.ChannelId, o3.ChannelId, "Unexpected channel ID")
   707  				require.Equal(t, f.Path, "file3.txt", "Unexpected filename")
   708  			} else {
   709  				require.Fail(t, "unexpected file returned")
   710  			}
   711  		}
   712  	})
   713  }
   714  
   715  func testFileInfoStoreCountAll(t *testing.T, ss store.Store) {
   716  	_, err := ss.FileInfo().PermanentDeleteBatch(model.GetMillis(), 100000)
   717  	require.NoError(t, err)
   718  	f1, err := ss.FileInfo().Save(&model.FileInfo{
   719  		PostId:    model.NewId(),
   720  		CreatorId: model.NewId(),
   721  		Path:      "file1.txt",
   722  	})
   723  	require.NoError(t, err)
   724  
   725  	_, err = ss.FileInfo().Save(&model.FileInfo{
   726  		PostId:    model.NewId(),
   727  		CreatorId: model.NewId(),
   728  		Path:      "file2.txt",
   729  	})
   730  	require.NoError(t, err)
   731  	_, err = ss.FileInfo().Save(&model.FileInfo{
   732  		PostId:    model.NewId(),
   733  		CreatorId: model.NewId(),
   734  		Path:      "file3.txt",
   735  	})
   736  	require.NoError(t, err)
   737  
   738  	count, err := ss.FileInfo().CountAll()
   739  	require.NoError(t, err)
   740  	require.Equal(t, int64(3), count)
   741  
   742  	_, err = ss.FileInfo().DeleteForPost(f1.PostId)
   743  	require.NoError(t, err)
   744  	count, err = ss.FileInfo().CountAll()
   745  	require.NoError(t, err)
   746  	require.Equal(t, int64(2), count)
   747  }