github.com/mattermost/mattermost-server/v5@v5.39.3/api4/upload_test.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package api4
     5  
     6  import (
     7  	"bytes"
     8  	"io"
     9  	"mime/multipart"
    10  	"net/http"
    11  	"os"
    12  	"testing"
    13  
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/mattermost/mattermost-server/v5/model"
    17  	"github.com/mattermost/mattermost-server/v5/utils/fileutils"
    18  )
    19  
    20  func TestCreateUpload(t *testing.T) {
    21  	th := Setup(t).InitBasic()
    22  	defer th.TearDown()
    23  
    24  	us := &model.UploadSession{
    25  		ChannelId: th.BasicChannel.Id,
    26  		Filename:  "upload",
    27  		FileSize:  8 * 1024 * 1024,
    28  	}
    29  
    30  	t.Run("file attachments disabled", func(t *testing.T) {
    31  		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.FileSettings.EnableFileAttachments = false })
    32  		defer th.App.UpdateConfig(func(cfg *model.Config) { *cfg.FileSettings.EnableFileAttachments = true })
    33  		u, resp := th.Client.CreateUpload(us)
    34  		require.Nil(t, u)
    35  		require.NotNil(t, resp.Error)
    36  		require.Equal(t, "api.file.attachments.disabled.app_error", resp.Error.Id)
    37  		require.Equal(t, http.StatusNotImplemented, resp.StatusCode)
    38  	})
    39  
    40  	t.Run("no permissions", func(t *testing.T) {
    41  		us.ChannelId = th.BasicPrivateChannel2.Id
    42  		u, resp := th.Client.CreateUpload(us)
    43  		require.Nil(t, u)
    44  		require.NotNil(t, resp.Error)
    45  		require.Equal(t, "api.context.permissions.app_error", resp.Error.Id)
    46  		require.Equal(t, http.StatusForbidden, resp.StatusCode)
    47  	})
    48  
    49  	t.Run("valid", func(t *testing.T) {
    50  		us.ChannelId = th.BasicChannel.Id
    51  		u, resp := th.Client.CreateUpload(us)
    52  		require.Nil(t, resp.Error)
    53  		require.NotEmpty(t, u)
    54  		require.Equal(t, http.StatusCreated, resp.StatusCode)
    55  	})
    56  
    57  	t.Run("import file", func(t *testing.T) {
    58  		testsDir, _ := fileutils.FindDir("tests")
    59  
    60  		importFile, err := os.Open(testsDir + "/import_test.zip")
    61  		require.NoError(t, err)
    62  		defer importFile.Close()
    63  
    64  		info, err := importFile.Stat()
    65  		require.NoError(t, err)
    66  
    67  		t.Run("permissions error", func(t *testing.T) {
    68  			us := &model.UploadSession{
    69  				Filename: info.Name(),
    70  				FileSize: info.Size(),
    71  				Type:     model.UploadTypeImport,
    72  			}
    73  			u, resp := th.Client.CreateUpload(us)
    74  			require.Nil(t, u)
    75  			require.NotNil(t, resp.Error)
    76  			require.Equal(t, "api.context.permissions.app_error", resp.Error.Id)
    77  			require.Equal(t, http.StatusForbidden, resp.StatusCode)
    78  		})
    79  
    80  		t.Run("success", func(t *testing.T) {
    81  			us := &model.UploadSession{
    82  				Filename: info.Name(),
    83  				FileSize: info.Size(),
    84  				Type:     model.UploadTypeImport,
    85  			}
    86  			u, resp := th.SystemAdminClient.CreateUpload(us)
    87  			require.Nil(t, resp.Error)
    88  			require.NotEmpty(t, u)
    89  		})
    90  	})
    91  }
    92  
    93  func TestGetUpload(t *testing.T) {
    94  	th := Setup(t).InitBasic()
    95  	defer th.TearDown()
    96  
    97  	us := &model.UploadSession{
    98  		Id:        model.NewId(),
    99  		Type:      model.UploadTypeAttachment,
   100  		CreateAt:  model.GetMillis(),
   101  		UserId:    th.BasicUser2.Id,
   102  		ChannelId: th.BasicChannel.Id,
   103  		Filename:  "upload",
   104  		FileSize:  8 * 1024 * 1024,
   105  	}
   106  	us, err := th.App.CreateUploadSession(us)
   107  	require.Nil(t, err)
   108  	require.NotNil(t, us)
   109  	require.NotEmpty(t, us)
   110  
   111  	t.Run("upload not found", func(t *testing.T) {
   112  		u, resp := th.Client.GetUpload(model.NewId())
   113  		require.Nil(t, u)
   114  		require.NotNil(t, resp.Error)
   115  		require.Equal(t, "app.upload.get.app_error", resp.Error.Id)
   116  		require.Equal(t, http.StatusNotFound, resp.StatusCode)
   117  	})
   118  
   119  	t.Run("no permissions", func(t *testing.T) {
   120  		u, resp := th.Client.GetUpload(us.Id)
   121  		require.Nil(t, u)
   122  		require.NotNil(t, resp.Error)
   123  		require.Equal(t, "api.upload.get_upload.forbidden.app_error", resp.Error.Id)
   124  	})
   125  
   126  	t.Run("success", func(t *testing.T) {
   127  		expected, resp := th.Client.CreateUpload(us)
   128  		require.Nil(t, resp.Error)
   129  		require.NotEmpty(t, expected)
   130  		require.Equal(t, http.StatusCreated, resp.StatusCode)
   131  
   132  		u, resp := th.Client.GetUpload(expected.Id)
   133  		require.Nil(t, resp.Error)
   134  		require.NotEmpty(t, u)
   135  		require.Equal(t, expected, u)
   136  	})
   137  }
   138  
   139  func TestGetUploadsForUser(t *testing.T) {
   140  	th := Setup(t).InitBasic()
   141  	defer th.TearDown()
   142  
   143  	t.Run("no permissions", func(t *testing.T) {
   144  		uss, resp := th.Client.GetUploadsForUser(th.BasicUser2.Id)
   145  		require.NotNil(t, resp.Error)
   146  		require.Equal(t, "api.user.get_uploads_for_user.forbidden.app_error", resp.Error.Id)
   147  		require.Nil(t, uss)
   148  	})
   149  
   150  	t.Run("empty", func(t *testing.T) {
   151  		uss, resp := th.Client.GetUploadsForUser(th.BasicUser.Id)
   152  		require.Nil(t, resp.Error)
   153  		require.Empty(t, uss)
   154  	})
   155  
   156  	t.Run("success", func(t *testing.T) {
   157  		uploads := make([]*model.UploadSession, 4)
   158  		for i := 0; i < len(uploads); i++ {
   159  			us := &model.UploadSession{
   160  				Id:        model.NewId(),
   161  				Type:      model.UploadTypeAttachment,
   162  				CreateAt:  model.GetMillis(),
   163  				UserId:    th.BasicUser.Id,
   164  				ChannelId: th.BasicChannel.Id,
   165  				Filename:  "upload",
   166  				FileSize:  8 * 1024 * 1024,
   167  			}
   168  			us, err := th.App.CreateUploadSession(us)
   169  			require.Nil(t, err)
   170  			require.NotNil(t, us)
   171  			require.NotEmpty(t, us)
   172  			us.Path = ""
   173  			uploads[i] = us
   174  		}
   175  
   176  		uss, resp := th.Client.GetUploadsForUser(th.BasicUser.Id)
   177  		require.Nil(t, resp.Error)
   178  		require.NotEmpty(t, uss)
   179  		require.Len(t, uss, len(uploads))
   180  		for i := range uploads {
   181  			require.Contains(t, uss, uploads[i])
   182  		}
   183  	})
   184  }
   185  
   186  func TestUploadData(t *testing.T) {
   187  	th := Setup(t).InitBasic()
   188  	defer th.TearDown()
   189  	if *th.App.Config().FileSettings.DriverName == "" {
   190  		t.Skip("skipping because no file driver is enabled")
   191  	}
   192  
   193  	us := &model.UploadSession{
   194  		Id:        model.NewId(),
   195  		Type:      model.UploadTypeAttachment,
   196  		CreateAt:  model.GetMillis(),
   197  		UserId:    th.BasicUser2.Id,
   198  		ChannelId: th.BasicChannel.Id,
   199  		Filename:  "upload",
   200  		FileSize:  8 * 1024 * 1024,
   201  	}
   202  	us, err := th.App.CreateUploadSession(us)
   203  	require.Nil(t, err)
   204  	require.NotNil(t, us)
   205  	require.NotEmpty(t, us)
   206  
   207  	data := randomBytes(t, int(us.FileSize))
   208  
   209  	t.Run("file attachments disabled", func(t *testing.T) {
   210  		th.App.UpdateConfig(func(cfg *model.Config) { *cfg.FileSettings.EnableFileAttachments = false })
   211  		defer th.App.UpdateConfig(func(cfg *model.Config) { *cfg.FileSettings.EnableFileAttachments = true })
   212  		info, resp := th.Client.UploadData(model.NewId(), bytes.NewReader(data))
   213  		require.Nil(t, info)
   214  		require.NotNil(t, resp.Error)
   215  		require.Equal(t, "api.file.attachments.disabled.app_error", resp.Error.Id)
   216  	})
   217  
   218  	t.Run("upload not found", func(t *testing.T) {
   219  		info, resp := th.Client.UploadData(model.NewId(), bytes.NewReader(data))
   220  		require.Nil(t, info)
   221  		require.NotNil(t, resp.Error)
   222  		require.Equal(t, "app.upload.get.app_error", resp.Error.Id)
   223  		require.Equal(t, http.StatusNotFound, resp.StatusCode)
   224  	})
   225  
   226  	t.Run("no permissions", func(t *testing.T) {
   227  		info, resp := th.Client.UploadData(us.Id, bytes.NewReader(data))
   228  		require.Nil(t, info)
   229  		require.NotNil(t, resp.Error)
   230  		require.Equal(t, "api.context.permissions.app_error", resp.Error.Id)
   231  	})
   232  
   233  	t.Run("bad content-length", func(t *testing.T) {
   234  		u, resp := th.Client.CreateUpload(us)
   235  		require.Nil(t, resp.Error)
   236  		require.NotEmpty(t, u)
   237  		require.Equal(t, http.StatusCreated, resp.StatusCode)
   238  
   239  		info, resp := th.Client.UploadData(u.Id, bytes.NewReader(append(data, 0x00)))
   240  		require.Nil(t, info)
   241  		require.NotNil(t, resp.Error)
   242  		require.Equal(t, "api.upload.upload_data.invalid_content_length", resp.Error.Id)
   243  	})
   244  
   245  	t.Run("success", func(t *testing.T) {
   246  		u, resp := th.Client.CreateUpload(us)
   247  		require.Nil(t, resp.Error)
   248  		require.NotEmpty(t, u)
   249  		require.Equal(t, http.StatusCreated, resp.StatusCode)
   250  
   251  		info, resp := th.Client.UploadData(u.Id, bytes.NewReader(data))
   252  		require.Nil(t, resp.Error)
   253  		require.NotEmpty(t, info)
   254  		require.Equal(t, u.Filename, info.Name)
   255  
   256  		file, resp := th.Client.GetFile(info.Id)
   257  		require.Nil(t, resp.Error)
   258  		require.Equal(t, file, data)
   259  	})
   260  
   261  	t.Run("resume success", func(t *testing.T) {
   262  		u, resp := th.Client.CreateUpload(us)
   263  		require.Nil(t, resp.Error)
   264  		require.NotEmpty(t, u)
   265  		require.Equal(t, http.StatusCreated, resp.StatusCode)
   266  
   267  		rd := &io.LimitedReader{
   268  			R: bytes.NewReader(data),
   269  			N: 5 * 1024 * 1024,
   270  		}
   271  		info, resp := th.Client.UploadData(u.Id, rd)
   272  		require.Nil(t, resp.Error)
   273  		require.Nil(t, info)
   274  		require.Equal(t, http.StatusNoContent, resp.StatusCode)
   275  
   276  		info, resp = th.Client.UploadData(u.Id, bytes.NewReader(data[5*1024*1024:]))
   277  		require.Nil(t, resp.Error)
   278  		require.NotEmpty(t, info)
   279  		require.Equal(t, u.Filename, info.Name)
   280  
   281  		file, resp := th.Client.GetFile(info.Id)
   282  		require.Nil(t, resp.Error)
   283  		require.Equal(t, file, data)
   284  	})
   285  }
   286  
   287  func TestUploadDataMultipart(t *testing.T) {
   288  	th := Setup(t).InitBasic()
   289  	defer th.TearDown()
   290  	if *th.App.Config().FileSettings.DriverName == "" {
   291  		t.Skip("skipping because no file driver is enabled")
   292  	}
   293  
   294  	us := &model.UploadSession{
   295  		Id:        model.NewId(),
   296  		Type:      model.UploadTypeAttachment,
   297  		CreateAt:  model.GetMillis(),
   298  		UserId:    th.BasicUser.Id,
   299  		ChannelId: th.BasicChannel.Id,
   300  		Filename:  "upload",
   301  		FileSize:  8 * 1024 * 1024,
   302  	}
   303  	us, resp := th.Client.CreateUpload(us)
   304  	require.Nil(t, resp.Error)
   305  	require.NotNil(t, us)
   306  	require.NotEmpty(t, us)
   307  
   308  	data := randomBytes(t, int(us.FileSize))
   309  
   310  	genMultipartData := func(t *testing.T, data []byte) (io.Reader, string) {
   311  		mpData := &bytes.Buffer{}
   312  		mpWriter := multipart.NewWriter(mpData)
   313  		part, err := mpWriter.CreateFormFile("data", us.Filename)
   314  		require.NoError(t, err)
   315  		n, err := part.Write(data)
   316  		require.NoError(t, err)
   317  		require.Equal(t, len(data), n)
   318  		err = mpWriter.Close()
   319  		require.NoError(t, err)
   320  		return mpData, mpWriter.FormDataContentType()
   321  	}
   322  
   323  	t.Run("bad content-type", func(t *testing.T) {
   324  		info, resp := th.Client.DoUploadFile("/uploads/"+us.Id, data, "multipart/form-data;")
   325  		require.Nil(t, info)
   326  		require.NotNil(t, resp.Error)
   327  		require.Equal(t, "api.upload.upload_data.invalid_content_type", resp.Error.Id)
   328  	})
   329  
   330  	t.Run("success", func(t *testing.T) {
   331  		mpData, contentType := genMultipartData(t, data)
   332  
   333  		req, err := http.NewRequest("POST", th.Client.ApiUrl+"/uploads/"+us.Id, mpData)
   334  		require.NoError(t, err)
   335  		req.Header.Set("Content-Type", contentType)
   336  		req.Header.Set(model.HEADER_AUTH, th.Client.AuthType+" "+th.Client.AuthToken)
   337  		res, err := th.Client.HttpClient.Do(req)
   338  		require.NoError(t, err)
   339  		info := model.FileInfoFromJson(res.Body)
   340  		res.Body.Close()
   341  		require.NotEmpty(t, info)
   342  		require.Equal(t, us.Filename, info.Name)
   343  
   344  		file, resp := th.Client.GetFile(info.Id)
   345  		require.Nil(t, resp.Error)
   346  		require.Equal(t, file, data)
   347  	})
   348  
   349  	t.Run("resume success", func(t *testing.T) {
   350  		mpData, contentType := genMultipartData(t, data[:5*1024*1024])
   351  
   352  		u, resp := th.Client.CreateUpload(us)
   353  		require.Nil(t, resp.Error)
   354  		require.NotNil(t, u)
   355  		require.NotEmpty(t, u)
   356  
   357  		req, err := http.NewRequest("POST", th.Client.ApiUrl+"/uploads/"+u.Id, mpData)
   358  		require.NoError(t, err)
   359  		req.Header.Set("Content-Type", contentType)
   360  		req.Header.Set(model.HEADER_AUTH, th.Client.AuthType+" "+th.Client.AuthToken)
   361  		res, err := th.Client.HttpClient.Do(req)
   362  		require.NoError(t, err)
   363  		require.Equal(t, http.StatusNoContent, res.StatusCode)
   364  		require.Equal(t, int64(0), res.ContentLength)
   365  
   366  		mpData, contentType = genMultipartData(t, data[5*1024*1024:])
   367  
   368  		req, err = http.NewRequest("POST", th.Client.ApiUrl+"/uploads/"+u.Id, mpData)
   369  		require.NoError(t, err)
   370  		req.Header.Set("Content-Type", contentType)
   371  		req.Header.Set(model.HEADER_AUTH, th.Client.AuthType+" "+th.Client.AuthToken)
   372  		res, err = th.Client.HttpClient.Do(req)
   373  		require.NoError(t, err)
   374  		info := model.FileInfoFromJson(res.Body)
   375  		res.Body.Close()
   376  		require.NotEmpty(t, info)
   377  		require.Equal(t, u.Filename, info.Name)
   378  
   379  		file, resp := th.Client.GetFile(info.Id)
   380  		require.Nil(t, resp.Error)
   381  		require.Equal(t, file, data)
   382  	})
   383  }