github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/services/filesstore/filesstore_test.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package filesstore
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"io/ioutil"
    10  	"math/rand"
    11  	"os"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/stretchr/testify/require"
    16  	"github.com/stretchr/testify/suite"
    17  	"github.com/xtgo/uuid"
    18  
    19  	"github.com/mattermost/mattermost-server/v5/mlog"
    20  )
    21  
    22  func randomString() string {
    23  	return uuid.NewRandom().String()
    24  }
    25  
    26  type FileBackendTestSuite struct {
    27  	suite.Suite
    28  
    29  	settings FileBackendSettings
    30  	backend  FileBackend
    31  }
    32  
    33  func TestLocalFileBackendTestSuite(t *testing.T) {
    34  	// Setup a global logger to catch tests logging outside of app context
    35  	// The global logger will be stomped by apps initializing but that's fine for testing. Ideally this won't happen.
    36  	mlog.InitGlobalLogger(mlog.NewLogger(&mlog.LoggerConfiguration{
    37  		EnableConsole: true,
    38  		ConsoleJson:   true,
    39  		ConsoleLevel:  "error",
    40  		EnableFile:    false,
    41  	}))
    42  
    43  	dir, err := ioutil.TempDir("", "")
    44  	require.NoError(t, err)
    45  	defer os.RemoveAll(dir)
    46  
    47  	suite.Run(t, &FileBackendTestSuite{
    48  		settings: FileBackendSettings{
    49  			DriverName: driverLocal,
    50  			Directory:  dir,
    51  		},
    52  	})
    53  }
    54  
    55  func TestS3FileBackendTestSuite(t *testing.T) {
    56  	runBackendTest(t, false)
    57  }
    58  
    59  func TestS3FileBackendTestSuiteWithEncryption(t *testing.T) {
    60  	runBackendTest(t, true)
    61  }
    62  
    63  func runBackendTest(t *testing.T, encrypt bool) {
    64  	s3Host := os.Getenv("CI_MINIO_HOST")
    65  	if s3Host == "" {
    66  		s3Host = "localhost"
    67  	}
    68  
    69  	s3Port := os.Getenv("CI_MINIO_PORT")
    70  	if s3Port == "" {
    71  		s3Port = "9000"
    72  	}
    73  
    74  	s3Endpoint := fmt.Sprintf("%s:%s", s3Host, s3Port)
    75  
    76  	suite.Run(t, &FileBackendTestSuite{
    77  		settings: FileBackendSettings{
    78  			DriverName:              driverS3,
    79  			AmazonS3AccessKeyId:     "minioaccesskey",
    80  			AmazonS3SecretAccessKey: "miniosecretkey",
    81  			AmazonS3Bucket:          "mattermost-test",
    82  			AmazonS3Region:          "",
    83  			AmazonS3Endpoint:        s3Endpoint,
    84  			AmazonS3PathPrefix:      "",
    85  			AmazonS3SSL:             false,
    86  			AmazonS3SSE:             encrypt,
    87  		},
    88  	})
    89  }
    90  
    91  func (s *FileBackendTestSuite) SetupTest() {
    92  	backend, err := NewFileBackend(s.settings)
    93  	require.NoError(s.T(), err)
    94  	s.backend = backend
    95  
    96  	// This is needed to create the bucket if it doesn't exist.
    97  	s.Nil(s.backend.TestConnection())
    98  }
    99  
   100  func (s *FileBackendTestSuite) TestConnection() {
   101  	s.Nil(s.backend.TestConnection())
   102  }
   103  
   104  func (s *FileBackendTestSuite) TestReadWriteFile() {
   105  	b := []byte("test")
   106  	path := "tests/" + randomString()
   107  
   108  	written, err := s.backend.WriteFile(bytes.NewReader(b), path)
   109  	s.Nil(err)
   110  	s.EqualValues(len(b), written, "expected given number of bytes to have been written")
   111  	defer s.backend.RemoveFile(path)
   112  
   113  	read, err := s.backend.ReadFile(path)
   114  	s.Nil(err)
   115  
   116  	readString := string(read)
   117  	s.EqualValues(readString, "test")
   118  }
   119  
   120  func (s *FileBackendTestSuite) TestReadWriteFileImage() {
   121  	b := []byte("testimage")
   122  	path := "tests/" + randomString() + ".png"
   123  
   124  	written, err := s.backend.WriteFile(bytes.NewReader(b), path)
   125  	s.Nil(err)
   126  	s.EqualValues(len(b), written, "expected given number of bytes to have been written")
   127  	defer s.backend.RemoveFile(path)
   128  
   129  	read, err := s.backend.ReadFile(path)
   130  	s.Nil(err)
   131  
   132  	readString := string(read)
   133  	s.EqualValues(readString, "testimage")
   134  }
   135  
   136  func (s *FileBackendTestSuite) TestFileExists() {
   137  	b := []byte("testimage")
   138  	path := "tests/" + randomString() + ".png"
   139  
   140  	_, err := s.backend.WriteFile(bytes.NewReader(b), path)
   141  	s.Nil(err)
   142  	defer s.backend.RemoveFile(path)
   143  
   144  	res, err := s.backend.FileExists(path)
   145  	s.Nil(err)
   146  	s.True(res)
   147  
   148  	res, err = s.backend.FileExists("tests/idontexist.png")
   149  	s.Nil(err)
   150  	s.False(res)
   151  }
   152  
   153  func (s *FileBackendTestSuite) TestCopyFile() {
   154  	b := []byte("test")
   155  	path1 := "tests/" + randomString()
   156  	path2 := "tests/" + randomString()
   157  
   158  	written, err := s.backend.WriteFile(bytes.NewReader(b), path1)
   159  	s.Nil(err)
   160  	s.EqualValues(len(b), written, "expected given number of bytes to have been written")
   161  	defer s.backend.RemoveFile(path1)
   162  
   163  	err = s.backend.CopyFile(path1, path2)
   164  	s.Nil(err)
   165  	defer s.backend.RemoveFile(path2)
   166  
   167  	data1, err := s.backend.ReadFile(path1)
   168  	s.Nil(err)
   169  
   170  	data2, err := s.backend.ReadFile(path2)
   171  	s.Nil(err)
   172  
   173  	s.Equal(b, data1)
   174  	s.Equal(b, data2)
   175  }
   176  
   177  func (s *FileBackendTestSuite) TestCopyFileToDirectoryThatDoesntExist() {
   178  	b := []byte("test")
   179  	path1 := "tests/" + randomString()
   180  	path2 := "tests/newdirectory/" + randomString()
   181  
   182  	written, err := s.backend.WriteFile(bytes.NewReader(b), path1)
   183  	s.Nil(err)
   184  	s.EqualValues(len(b), written, "expected given number of bytes to have been written")
   185  	defer s.backend.RemoveFile(path1)
   186  
   187  	err = s.backend.CopyFile(path1, path2)
   188  	s.Nil(err)
   189  	defer s.backend.RemoveFile(path2)
   190  
   191  	_, err = s.backend.ReadFile(path1)
   192  	s.Nil(err)
   193  
   194  	_, err = s.backend.ReadFile(path2)
   195  	s.Nil(err)
   196  }
   197  
   198  func (s *FileBackendTestSuite) TestMoveFile() {
   199  	b := []byte("test")
   200  	path1 := "tests/" + randomString()
   201  	path2 := "tests/" + randomString()
   202  
   203  	written, err := s.backend.WriteFile(bytes.NewReader(b), path1)
   204  	s.Nil(err)
   205  	s.EqualValues(len(b), written, "expected given number of bytes to have been written")
   206  	defer s.backend.RemoveFile(path1)
   207  
   208  	s.Nil(s.backend.MoveFile(path1, path2))
   209  	defer s.backend.RemoveFile(path2)
   210  
   211  	_, err = s.backend.ReadFile(path1)
   212  	s.Error(err)
   213  
   214  	data, err := s.backend.ReadFile(path2)
   215  	s.Nil(err)
   216  
   217  	s.Equal(b, data)
   218  }
   219  
   220  func (s *FileBackendTestSuite) TestRemoveFile() {
   221  	b := []byte("test")
   222  	path := "tests/" + randomString()
   223  
   224  	written, err := s.backend.WriteFile(bytes.NewReader(b), path)
   225  	s.Nil(err)
   226  	s.EqualValues(len(b), written, "expected given number of bytes to have been written")
   227  	s.Nil(s.backend.RemoveFile(path))
   228  
   229  	_, err = s.backend.ReadFile(path)
   230  	s.Error(err)
   231  
   232  	written, err = s.backend.WriteFile(bytes.NewReader(b), "tests2/foo")
   233  	s.Nil(err)
   234  	s.EqualValues(len(b), written, "expected given number of bytes to have been written")
   235  
   236  	written, err = s.backend.WriteFile(bytes.NewReader(b), "tests2/bar")
   237  	s.Nil(err)
   238  	s.EqualValues(len(b), written, "expected given number of bytes to have been written")
   239  
   240  	written, err = s.backend.WriteFile(bytes.NewReader(b), "tests2/asdf")
   241  	s.Nil(err)
   242  	s.EqualValues(len(b), written, "expected given number of bytes to have been written")
   243  
   244  	s.Nil(s.backend.RemoveDirectory("tests2"))
   245  }
   246  
   247  func (s *FileBackendTestSuite) TestListDirectory() {
   248  	b := []byte("test")
   249  	path1 := "19700101/" + randomString()
   250  	path2 := "19800101/" + randomString()
   251  
   252  	paths, err := s.backend.ListDirectory("19700101")
   253  	s.Nil(err)
   254  	s.Len(paths, 0)
   255  
   256  	written, err := s.backend.WriteFile(bytes.NewReader(b), path1)
   257  	s.Nil(err)
   258  	s.EqualValues(len(b), written, "expected given number of bytes to have been written")
   259  
   260  	written, err = s.backend.WriteFile(bytes.NewReader(b), path2)
   261  	s.Nil(err)
   262  	s.EqualValues(len(b), written, "expected given number of bytes to have been written")
   263  
   264  	paths, err = s.backend.ListDirectory("19700101")
   265  	s.Nil(err)
   266  	s.Len(paths, 1)
   267  	s.Equal(path1, (paths)[0])
   268  
   269  	paths, err = s.backend.ListDirectory("19700101/")
   270  	s.Nil(err)
   271  	s.Len(paths, 1)
   272  	s.Equal(path1, (paths)[0])
   273  
   274  	paths, err = s.backend.ListDirectory("")
   275  	s.Nil(err)
   276  
   277  	found1 := false
   278  	found2 := false
   279  	for _, path := range paths {
   280  		if path == "19700101" {
   281  			found1 = true
   282  		} else if path == "19800101" {
   283  			found2 = true
   284  		}
   285  	}
   286  	s.True(found1)
   287  	s.True(found2)
   288  
   289  	s.backend.RemoveFile(path1)
   290  	s.backend.RemoveFile(path2)
   291  }
   292  
   293  func (s *FileBackendTestSuite) TestRemoveDirectory() {
   294  	b := []byte("test")
   295  
   296  	written, err := s.backend.WriteFile(bytes.NewReader(b), "tests2/foo")
   297  	s.Nil(err)
   298  	s.EqualValues(len(b), written, "expected given number of bytes to have been written")
   299  
   300  	written, err = s.backend.WriteFile(bytes.NewReader(b), "tests2/bar")
   301  	s.Nil(err)
   302  	s.EqualValues(len(b), written, "expected given number of bytes to have been written")
   303  
   304  	written, err = s.backend.WriteFile(bytes.NewReader(b), "tests2/aaa")
   305  	s.Nil(err)
   306  	s.EqualValues(len(b), written, "expected given number of bytes to have been written")
   307  
   308  	s.Nil(s.backend.RemoveDirectory("tests2"))
   309  
   310  	_, err = s.backend.ReadFile("tests2/foo")
   311  	s.Error(err)
   312  	_, err = s.backend.ReadFile("tests2/bar")
   313  	s.Error(err)
   314  	_, err = s.backend.ReadFile("tests2/asdf")
   315  	s.Error(err)
   316  }
   317  
   318  func (s *FileBackendTestSuite) TestAppendFile() {
   319  	s.Run("should fail if target file is missing", func() {
   320  		path := "tests/" + randomString()
   321  		b := make([]byte, 1024)
   322  		written, err := s.backend.AppendFile(bytes.NewReader(b), path)
   323  		s.Error(err)
   324  		s.Zero(written)
   325  	})
   326  
   327  	s.Run("should correctly append the data", func() {
   328  		// First part needs to be at least 5MB for the S3 implementation to work.
   329  		size := 5 * 1024 * 1024
   330  		b := make([]byte, size)
   331  		for i := range b {
   332  			b[i] = 'A'
   333  		}
   334  		path := "tests/" + randomString()
   335  
   336  		written, err := s.backend.WriteFile(bytes.NewReader(b), path)
   337  		s.Nil(err)
   338  		s.EqualValues(len(b), written)
   339  		defer s.backend.RemoveFile(path)
   340  
   341  		b2 := make([]byte, 1024)
   342  		for i := range b2 {
   343  			b2[i] = 'B'
   344  		}
   345  
   346  		written, err = s.backend.AppendFile(bytes.NewReader(b2), path)
   347  		s.Nil(err)
   348  		s.EqualValues(int64(len(b2)), written)
   349  
   350  		read, err := s.backend.ReadFile(path)
   351  		s.Nil(err)
   352  		s.EqualValues(len(b)+len(b2), len(read))
   353  		s.EqualValues(append(b, b2...), read)
   354  
   355  		b3 := make([]byte, 1024)
   356  		for i := range b3 {
   357  			b3[i] = 'C'
   358  		}
   359  
   360  		written, err = s.backend.AppendFile(bytes.NewReader(b3), path)
   361  		s.Nil(err)
   362  		s.EqualValues(int64(len(b3)), written)
   363  
   364  		read, err = s.backend.ReadFile(path)
   365  		s.Nil(err)
   366  		s.EqualValues(len(b)+len(b2)+len(b3), len(read))
   367  		s.EqualValues(append(append(b, b2...), b3...), read)
   368  	})
   369  }
   370  
   371  func (s *FileBackendTestSuite) TestFileSize() {
   372  	s.Run("nonexistent file", func() {
   373  		size, err := s.backend.FileSize("tests/nonexistentfile")
   374  		s.NotNil(err)
   375  		s.Zero(size)
   376  	})
   377  
   378  	s.Run("valid file", func() {
   379  		data := make([]byte, rand.Intn(1024*1024)+1)
   380  		path := "tests/" + randomString()
   381  
   382  		written, err := s.backend.WriteFile(bytes.NewReader(data), path)
   383  		s.Nil(err)
   384  		s.EqualValues(len(data), written)
   385  		defer s.backend.RemoveFile(path)
   386  
   387  		size, err := s.backend.FileSize(path)
   388  		s.Nil(err)
   389  		s.Equal(int64(len(data)), size)
   390  	})
   391  }
   392  
   393  func (s *FileBackendTestSuite) TestFileModTime() {
   394  	s.Run("nonexistent file", func() {
   395  		modTime, err := s.backend.FileModTime("tests/nonexistentfile")
   396  		s.NotNil(err)
   397  		s.Empty(modTime)
   398  	})
   399  
   400  	s.Run("valid file", func() {
   401  		path := "tests/" + randomString()
   402  		data := []byte("some data")
   403  
   404  		written, err := s.backend.WriteFile(bytes.NewReader(data), path)
   405  		s.Nil(err)
   406  		s.EqualValues(len(data), written)
   407  		defer s.backend.RemoveFile(path)
   408  
   409  		modTime, err := s.backend.FileModTime(path)
   410  		s.Nil(err)
   411  		s.NotEmpty(modTime)
   412  
   413  		// We wait 1 second so that the times will differ enough to be testable.
   414  		time.Sleep(1 * time.Second)
   415  
   416  		path2 := "tests/" + randomString()
   417  		written, err = s.backend.WriteFile(bytes.NewReader(data), path2)
   418  		s.Nil(err)
   419  		s.EqualValues(len(data), written)
   420  		defer s.backend.RemoveFile(path2)
   421  
   422  		modTime2, err := s.backend.FileModTime(path2)
   423  		s.Nil(err)
   424  		s.NotEmpty(modTime2)
   425  		s.True(modTime2.After(modTime))
   426  	})
   427  }
   428  
   429  func BenchmarkS3WriteFile(b *testing.B) {
   430  	settings := FileBackendSettings{
   431  		DriverName:              driverS3,
   432  		AmazonS3AccessKeyId:     "minioaccesskey",
   433  		AmazonS3SecretAccessKey: "miniosecretkey",
   434  		AmazonS3Bucket:          "mattermost-test",
   435  		AmazonS3Region:          "",
   436  		AmazonS3Endpoint:        "localhost:9000",
   437  		AmazonS3PathPrefix:      "",
   438  		AmazonS3SSL:             false,
   439  		AmazonS3SSE:             false,
   440  	}
   441  
   442  	backend, err := NewFileBackend(settings)
   443  	require.NoError(b, err)
   444  
   445  	// This is needed to create the bucket if it doesn't exist.
   446  	require.NoError(b, backend.TestConnection())
   447  
   448  	path := "tests/" + randomString()
   449  	size := 1 * 1024 * 1024
   450  	data := make([]byte, size)
   451  
   452  	b.ResetTimer()
   453  
   454  	for i := 0; i < b.N; i++ {
   455  		written, err := backend.WriteFile(bytes.NewReader(data), path)
   456  		defer backend.RemoveFile(path)
   457  		require.NoError(b, err)
   458  		require.Equal(b, len(data), int(written))
   459  	}
   460  
   461  	b.StopTimer()
   462  }