transfer_test.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. package common
  2. import (
  3. "errors"
  4. "os"
  5. "path/filepath"
  6. "testing"
  7. "time"
  8. "github.com/sftpgo/sdk"
  9. "github.com/stretchr/testify/assert"
  10. "github.com/stretchr/testify/require"
  11. "github.com/drakkan/sftpgo/v2/dataprovider"
  12. "github.com/drakkan/sftpgo/v2/kms"
  13. "github.com/drakkan/sftpgo/v2/vfs"
  14. )
  15. func TestTransferUpdateQuota(t *testing.T) {
  16. conn := NewBaseConnection("", ProtocolSFTP, "", "", dataprovider.User{})
  17. transfer := BaseTransfer{
  18. Connection: conn,
  19. transferType: TransferUpload,
  20. BytesReceived: 123,
  21. Fs: vfs.NewOsFs("", os.TempDir(), ""),
  22. }
  23. errFake := errors.New("fake error")
  24. transfer.TransferError(errFake)
  25. assert.False(t, transfer.updateQuota(1, 0))
  26. err := transfer.Close()
  27. if assert.Error(t, err) {
  28. assert.EqualError(t, err, errFake.Error())
  29. }
  30. mappedPath := filepath.Join(os.TempDir(), "vdir")
  31. vdirPath := "/vdir"
  32. conn.User.VirtualFolders = append(conn.User.VirtualFolders, vfs.VirtualFolder{
  33. BaseVirtualFolder: vfs.BaseVirtualFolder{
  34. MappedPath: mappedPath,
  35. },
  36. VirtualPath: vdirPath,
  37. QuotaFiles: -1,
  38. QuotaSize: -1,
  39. })
  40. transfer.ErrTransfer = nil
  41. transfer.BytesReceived = 1
  42. transfer.requestPath = "/vdir/file"
  43. assert.True(t, transfer.updateQuota(1, 0))
  44. err = transfer.Close()
  45. assert.NoError(t, err)
  46. }
  47. func TestTransferThrottling(t *testing.T) {
  48. u := dataprovider.User{
  49. BaseUser: sdk.BaseUser{
  50. Username: "test",
  51. UploadBandwidth: 50,
  52. DownloadBandwidth: 40,
  53. },
  54. }
  55. fs := vfs.NewOsFs("", os.TempDir(), "")
  56. testFileSize := int64(131072)
  57. wantedUploadElapsed := 1000 * (testFileSize / 1024) / u.UploadBandwidth
  58. wantedDownloadElapsed := 1000 * (testFileSize / 1024) / u.DownloadBandwidth
  59. // some tolerance
  60. wantedUploadElapsed -= wantedDownloadElapsed / 10
  61. wantedDownloadElapsed -= wantedDownloadElapsed / 10
  62. conn := NewBaseConnection("id", ProtocolSCP, "", "", u)
  63. transfer := NewBaseTransfer(nil, conn, nil, "", "", "", TransferUpload, 0, 0, 0, true, fs)
  64. transfer.BytesReceived = testFileSize
  65. transfer.Connection.UpdateLastActivity()
  66. startTime := transfer.Connection.GetLastActivity()
  67. transfer.HandleThrottle()
  68. elapsed := time.Since(startTime).Nanoseconds() / 1000000
  69. assert.GreaterOrEqual(t, elapsed, wantedUploadElapsed, "upload bandwidth throttling not respected")
  70. err := transfer.Close()
  71. assert.NoError(t, err)
  72. transfer = NewBaseTransfer(nil, conn, nil, "", "", "", TransferDownload, 0, 0, 0, true, fs)
  73. transfer.BytesSent = testFileSize
  74. transfer.Connection.UpdateLastActivity()
  75. startTime = transfer.Connection.GetLastActivity()
  76. transfer.HandleThrottle()
  77. elapsed = time.Since(startTime).Nanoseconds() / 1000000
  78. assert.GreaterOrEqual(t, elapsed, wantedDownloadElapsed, "download bandwidth throttling not respected")
  79. err = transfer.Close()
  80. assert.NoError(t, err)
  81. }
  82. func TestRealPath(t *testing.T) {
  83. testFile := filepath.Join(os.TempDir(), "afile.txt")
  84. fs := vfs.NewOsFs("123", os.TempDir(), "")
  85. u := dataprovider.User{
  86. BaseUser: sdk.BaseUser{
  87. Username: "user",
  88. HomeDir: os.TempDir(),
  89. },
  90. }
  91. u.Permissions = make(map[string][]string)
  92. u.Permissions["/"] = []string{dataprovider.PermAny}
  93. file, err := os.Create(testFile)
  94. require.NoError(t, err)
  95. conn := NewBaseConnection(fs.ConnectionID(), ProtocolSFTP, "", "", u)
  96. transfer := NewBaseTransfer(file, conn, nil, testFile, testFile, "/transfer_test_file", TransferUpload, 0, 0, 0, true, fs)
  97. rPath := transfer.GetRealFsPath(testFile)
  98. assert.Equal(t, testFile, rPath)
  99. rPath = conn.getRealFsPath(testFile)
  100. assert.Equal(t, testFile, rPath)
  101. err = transfer.Close()
  102. assert.NoError(t, err)
  103. err = file.Close()
  104. assert.NoError(t, err)
  105. transfer.File = nil
  106. rPath = transfer.GetRealFsPath(testFile)
  107. assert.Equal(t, testFile, rPath)
  108. rPath = transfer.GetRealFsPath("")
  109. assert.Empty(t, rPath)
  110. err = os.Remove(testFile)
  111. assert.NoError(t, err)
  112. assert.Len(t, conn.GetTransfers(), 0)
  113. }
  114. func TestTruncate(t *testing.T) {
  115. testFile := filepath.Join(os.TempDir(), "transfer_test_file")
  116. fs := vfs.NewOsFs("123", os.TempDir(), "")
  117. u := dataprovider.User{
  118. BaseUser: sdk.BaseUser{
  119. Username: "user",
  120. HomeDir: os.TempDir(),
  121. },
  122. }
  123. u.Permissions = make(map[string][]string)
  124. u.Permissions["/"] = []string{dataprovider.PermAny}
  125. file, err := os.Create(testFile)
  126. if !assert.NoError(t, err) {
  127. assert.FailNow(t, "unable to open test file")
  128. }
  129. _, err = file.Write([]byte("hello"))
  130. assert.NoError(t, err)
  131. conn := NewBaseConnection(fs.ConnectionID(), ProtocolSFTP, "", "", u)
  132. transfer := NewBaseTransfer(file, conn, nil, testFile, testFile, "/transfer_test_file", TransferUpload, 0, 5, 100, false, fs)
  133. err = conn.SetStat("/transfer_test_file", &StatAttributes{
  134. Size: 2,
  135. Flags: StatAttrSize,
  136. })
  137. assert.NoError(t, err)
  138. assert.Equal(t, int64(103), transfer.MaxWriteSize)
  139. err = transfer.Close()
  140. assert.NoError(t, err)
  141. err = file.Close()
  142. assert.NoError(t, err)
  143. fi, err := os.Stat(testFile)
  144. if assert.NoError(t, err) {
  145. assert.Equal(t, int64(2), fi.Size())
  146. }
  147. transfer = NewBaseTransfer(file, conn, nil, testFile, testFile, "/transfer_test_file", TransferUpload, 0, 0, 100, true, fs)
  148. // file.Stat will fail on a closed file
  149. err = conn.SetStat("/transfer_test_file", &StatAttributes{
  150. Size: 2,
  151. Flags: StatAttrSize,
  152. })
  153. assert.Error(t, err)
  154. err = transfer.Close()
  155. assert.NoError(t, err)
  156. transfer = NewBaseTransfer(nil, conn, nil, testFile, testFile, "", TransferUpload, 0, 0, 0, true, fs)
  157. _, err = transfer.Truncate("mismatch", 0)
  158. assert.EqualError(t, err, errTransferMismatch.Error())
  159. _, err = transfer.Truncate(testFile, 0)
  160. assert.NoError(t, err)
  161. _, err = transfer.Truncate(testFile, 1)
  162. assert.EqualError(t, err, vfs.ErrVfsUnsupported.Error())
  163. err = transfer.Close()
  164. assert.NoError(t, err)
  165. err = os.Remove(testFile)
  166. assert.NoError(t, err)
  167. assert.Len(t, conn.GetTransfers(), 0)
  168. }
  169. func TestTransferErrors(t *testing.T) {
  170. isCancelled := false
  171. cancelFn := func() {
  172. isCancelled = true
  173. }
  174. testFile := filepath.Join(os.TempDir(), "transfer_test_file")
  175. fs := vfs.NewOsFs("id", os.TempDir(), "")
  176. u := dataprovider.User{
  177. BaseUser: sdk.BaseUser{
  178. Username: "test",
  179. HomeDir: os.TempDir(),
  180. },
  181. }
  182. err := os.WriteFile(testFile, []byte("test data"), os.ModePerm)
  183. assert.NoError(t, err)
  184. file, err := os.Open(testFile)
  185. if !assert.NoError(t, err) {
  186. assert.FailNow(t, "unable to open test file")
  187. }
  188. conn := NewBaseConnection("id", ProtocolSFTP, "", "", u)
  189. transfer := NewBaseTransfer(file, conn, nil, testFile, testFile, "/transfer_test_file", TransferUpload, 0, 0, 0, true, fs)
  190. assert.Nil(t, transfer.cancelFn)
  191. assert.Equal(t, testFile, transfer.GetFsPath())
  192. transfer.SetCancelFn(cancelFn)
  193. errFake := errors.New("err fake")
  194. transfer.BytesReceived = 9
  195. transfer.TransferError(ErrQuotaExceeded)
  196. assert.True(t, isCancelled)
  197. transfer.TransferError(errFake)
  198. assert.Error(t, transfer.ErrTransfer, ErrQuotaExceeded.Error())
  199. // the file is closed from the embedding struct before to call close
  200. err = file.Close()
  201. assert.NoError(t, err)
  202. err = transfer.Close()
  203. if assert.Error(t, err) {
  204. assert.Error(t, err, ErrQuotaExceeded.Error())
  205. }
  206. assert.NoFileExists(t, testFile)
  207. err = os.WriteFile(testFile, []byte("test data"), os.ModePerm)
  208. assert.NoError(t, err)
  209. file, err = os.Open(testFile)
  210. if !assert.NoError(t, err) {
  211. assert.FailNow(t, "unable to open test file")
  212. }
  213. fsPath := filepath.Join(os.TempDir(), "test_file")
  214. transfer = NewBaseTransfer(file, conn, nil, fsPath, file.Name(), "/test_file", TransferUpload, 0, 0, 0, true, fs)
  215. transfer.BytesReceived = 9
  216. transfer.TransferError(errFake)
  217. assert.Error(t, transfer.ErrTransfer, errFake.Error())
  218. // the file is closed from the embedding struct before to call close
  219. err = file.Close()
  220. assert.NoError(t, err)
  221. err = transfer.Close()
  222. if assert.Error(t, err) {
  223. assert.Error(t, err, errFake.Error())
  224. }
  225. assert.NoFileExists(t, testFile)
  226. err = os.WriteFile(testFile, []byte("test data"), os.ModePerm)
  227. assert.NoError(t, err)
  228. file, err = os.Open(testFile)
  229. if !assert.NoError(t, err) {
  230. assert.FailNow(t, "unable to open test file")
  231. }
  232. transfer = NewBaseTransfer(file, conn, nil, fsPath, file.Name(), "/test_file", TransferUpload, 0, 0, 0, true, fs)
  233. transfer.BytesReceived = 9
  234. // the file is closed from the embedding struct before to call close
  235. err = file.Close()
  236. assert.NoError(t, err)
  237. err = transfer.Close()
  238. assert.NoError(t, err)
  239. assert.NoFileExists(t, testFile)
  240. assert.FileExists(t, fsPath)
  241. err = os.Remove(fsPath)
  242. assert.NoError(t, err)
  243. assert.Len(t, conn.GetTransfers(), 0)
  244. }
  245. func TestRemovePartialCryptoFile(t *testing.T) {
  246. testFile := filepath.Join(os.TempDir(), "transfer_test_file")
  247. fs, err := vfs.NewCryptFs("id", os.TempDir(), "", vfs.CryptFsConfig{Passphrase: kms.NewPlainSecret("secret")})
  248. require.NoError(t, err)
  249. u := dataprovider.User{
  250. BaseUser: sdk.BaseUser{
  251. Username: "test",
  252. HomeDir: os.TempDir(),
  253. },
  254. }
  255. conn := NewBaseConnection(fs.ConnectionID(), ProtocolSFTP, "", "", u)
  256. transfer := NewBaseTransfer(nil, conn, nil, testFile, testFile, "/transfer_test_file", TransferUpload, 0, 0, 0, true, fs)
  257. transfer.ErrTransfer = errors.New("test error")
  258. _, err = transfer.getUploadFileSize()
  259. assert.Error(t, err)
  260. err = os.WriteFile(testFile, []byte("test data"), os.ModePerm)
  261. assert.NoError(t, err)
  262. size, err := transfer.getUploadFileSize()
  263. assert.NoError(t, err)
  264. assert.Equal(t, int64(9), size)
  265. assert.NoFileExists(t, testFile)
  266. }
  267. func TestFTPMode(t *testing.T) {
  268. conn := NewBaseConnection("", ProtocolFTP, "", "", dataprovider.User{})
  269. transfer := BaseTransfer{
  270. Connection: conn,
  271. transferType: TransferUpload,
  272. BytesReceived: 123,
  273. Fs: vfs.NewOsFs("", os.TempDir(), ""),
  274. }
  275. assert.Empty(t, transfer.ftpMode)
  276. transfer.SetFtpMode("active")
  277. assert.Equal(t, "active", transfer.ftpMode)
  278. }