common_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. package common
  2. import (
  3. "fmt"
  4. "net"
  5. "net/http"
  6. "os"
  7. "os/exec"
  8. "runtime"
  9. "strings"
  10. "sync/atomic"
  11. "testing"
  12. "time"
  13. "github.com/rs/zerolog"
  14. "github.com/spf13/viper"
  15. "github.com/stretchr/testify/assert"
  16. "github.com/stretchr/testify/require"
  17. "github.com/drakkan/sftpgo/dataprovider"
  18. "github.com/drakkan/sftpgo/httpclient"
  19. "github.com/drakkan/sftpgo/kms"
  20. "github.com/drakkan/sftpgo/logger"
  21. "github.com/drakkan/sftpgo/vfs"
  22. )
  23. const (
  24. logSenderTest = "common_test"
  25. httpAddr = "127.0.0.1:9999"
  26. httpProxyAddr = "127.0.0.1:7777"
  27. configDir = ".."
  28. osWindows = "windows"
  29. userTestUsername = "common_test_username"
  30. userTestPwd = "common_test_pwd"
  31. )
  32. type providerConf struct {
  33. Config dataprovider.Config `json:"data_provider" mapstructure:"data_provider"`
  34. }
  35. type fakeConnection struct {
  36. *BaseConnection
  37. command string
  38. }
  39. func (c *fakeConnection) AddUser(user dataprovider.User) error {
  40. fs, err := user.GetFilesystem(c.GetID())
  41. if err != nil {
  42. return err
  43. }
  44. c.BaseConnection.User = user
  45. c.BaseConnection.Fs = fs
  46. return nil
  47. }
  48. func (c *fakeConnection) Disconnect() error {
  49. Connections.Remove(c.GetID())
  50. return nil
  51. }
  52. func (c *fakeConnection) GetClientVersion() string {
  53. return ""
  54. }
  55. func (c *fakeConnection) GetCommand() string {
  56. return c.command
  57. }
  58. func (c *fakeConnection) GetRemoteAddress() string {
  59. return ""
  60. }
  61. type customNetConn struct {
  62. net.Conn
  63. id string
  64. isClosed bool
  65. }
  66. func (c *customNetConn) Close() error {
  67. Connections.RemoveSSHConnection(c.id)
  68. c.isClosed = true
  69. return c.Conn.Close()
  70. }
  71. func TestMain(m *testing.M) {
  72. logfilePath := "common_test.log"
  73. logger.InitLogger(logfilePath, 5, 1, 28, false, zerolog.DebugLevel)
  74. viper.SetEnvPrefix("sftpgo")
  75. replacer := strings.NewReplacer(".", "__")
  76. viper.SetEnvKeyReplacer(replacer)
  77. viper.SetConfigName("sftpgo")
  78. viper.AutomaticEnv()
  79. viper.AllowEmptyEnv(true)
  80. driver, err := initializeDataprovider(-1)
  81. if err != nil {
  82. logger.WarnToConsole("error initializing data provider: %v", err)
  83. os.Exit(1)
  84. }
  85. logger.InfoToConsole("Starting COMMON tests, provider: %v", driver)
  86. Initialize(Configuration{})
  87. httpConfig := httpclient.Config{
  88. Timeout: 5,
  89. }
  90. httpConfig.Initialize(configDir)
  91. go func() {
  92. // start a test HTTP server to receive action notifications
  93. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  94. fmt.Fprintf(w, "OK\n")
  95. })
  96. http.HandleFunc("/404", func(w http.ResponseWriter, r *http.Request) {
  97. w.WriteHeader(http.StatusNotFound)
  98. fmt.Fprintf(w, "Not found\n")
  99. })
  100. if err := http.ListenAndServe(httpAddr, nil); err != nil {
  101. logger.ErrorToConsole("could not start HTTP notification server: %v", err)
  102. os.Exit(1)
  103. }
  104. }()
  105. go func() {
  106. Config.ProxyProtocol = 2
  107. listener, err := net.Listen("tcp", httpProxyAddr)
  108. if err != nil {
  109. logger.ErrorToConsole("error creating listener for proxy protocol server: %v", err)
  110. os.Exit(1)
  111. }
  112. proxyListener, err := Config.GetProxyListener(listener)
  113. if err != nil {
  114. logger.ErrorToConsole("error creating proxy protocol listener: %v", err)
  115. os.Exit(1)
  116. }
  117. Config.ProxyProtocol = 0
  118. s := &http.Server{}
  119. if err := s.Serve(proxyListener); err != nil {
  120. logger.ErrorToConsole("could not start HTTP proxy protocol server: %v", err)
  121. os.Exit(1)
  122. }
  123. }()
  124. waitTCPListening(httpAddr)
  125. waitTCPListening(httpProxyAddr)
  126. exitCode := m.Run()
  127. os.Remove(logfilePath) //nolint:errcheck
  128. os.Exit(exitCode)
  129. }
  130. func waitTCPListening(address string) {
  131. for {
  132. conn, err := net.Dial("tcp", address)
  133. if err != nil {
  134. logger.WarnToConsole("tcp server %v not listening: %v\n", address, err)
  135. time.Sleep(100 * time.Millisecond)
  136. continue
  137. }
  138. logger.InfoToConsole("tcp server %v now listening\n", address)
  139. conn.Close()
  140. break
  141. }
  142. }
  143. func initializeDataprovider(trackQuota int) (string, error) {
  144. configDir := ".."
  145. viper.AddConfigPath(configDir)
  146. if err := viper.ReadInConfig(); err != nil {
  147. return "", err
  148. }
  149. var cfg providerConf
  150. if err := viper.Unmarshal(&cfg); err != nil {
  151. return "", err
  152. }
  153. if trackQuota >= 0 && trackQuota <= 2 {
  154. cfg.Config.TrackQuota = trackQuota
  155. }
  156. return cfg.Config.Driver, dataprovider.Initialize(cfg.Config, configDir)
  157. }
  158. func closeDataprovider() error {
  159. return dataprovider.Close()
  160. }
  161. func TestSSHConnections(t *testing.T) {
  162. conn1, conn2 := net.Pipe()
  163. now := time.Now()
  164. sshConn1 := NewSSHConnection("id1", conn1)
  165. sshConn2 := NewSSHConnection("id2", conn2)
  166. sshConn3 := NewSSHConnection("id3", conn2)
  167. assert.Equal(t, "id1", sshConn1.GetID())
  168. assert.Equal(t, "id2", sshConn2.GetID())
  169. assert.Equal(t, "id3", sshConn3.GetID())
  170. sshConn1.UpdateLastActivity()
  171. assert.GreaterOrEqual(t, sshConn1.GetLastActivity().UnixNano(), now.UnixNano())
  172. Connections.AddSSHConnection(sshConn1)
  173. Connections.AddSSHConnection(sshConn2)
  174. Connections.AddSSHConnection(sshConn3)
  175. Connections.RLock()
  176. assert.Len(t, Connections.sshConnections, 3)
  177. Connections.RUnlock()
  178. Connections.RemoveSSHConnection(sshConn1.id)
  179. Connections.RLock()
  180. assert.Len(t, Connections.sshConnections, 2)
  181. assert.Equal(t, sshConn3.id, Connections.sshConnections[0].id)
  182. assert.Equal(t, sshConn2.id, Connections.sshConnections[1].id)
  183. Connections.RUnlock()
  184. Connections.RemoveSSHConnection(sshConn1.id)
  185. Connections.RLock()
  186. assert.Len(t, Connections.sshConnections, 2)
  187. assert.Equal(t, sshConn3.id, Connections.sshConnections[0].id)
  188. assert.Equal(t, sshConn2.id, Connections.sshConnections[1].id)
  189. Connections.RUnlock()
  190. Connections.RemoveSSHConnection(sshConn2.id)
  191. Connections.RLock()
  192. assert.Len(t, Connections.sshConnections, 1)
  193. assert.Equal(t, sshConn3.id, Connections.sshConnections[0].id)
  194. Connections.RUnlock()
  195. Connections.RemoveSSHConnection(sshConn3.id)
  196. Connections.RLock()
  197. assert.Len(t, Connections.sshConnections, 0)
  198. Connections.RUnlock()
  199. assert.NoError(t, sshConn1.Close())
  200. assert.NoError(t, sshConn2.Close())
  201. assert.NoError(t, sshConn3.Close())
  202. }
  203. func TestIdleConnections(t *testing.T) {
  204. configCopy := Config
  205. Config.IdleTimeout = 1
  206. Initialize(Config)
  207. conn1, conn2 := net.Pipe()
  208. customConn1 := &customNetConn{
  209. Conn: conn1,
  210. id: "id1",
  211. }
  212. customConn2 := &customNetConn{
  213. Conn: conn2,
  214. id: "id2",
  215. }
  216. sshConn1 := NewSSHConnection(customConn1.id, customConn1)
  217. sshConn2 := NewSSHConnection(customConn2.id, customConn2)
  218. username := "test_user"
  219. user := dataprovider.User{
  220. Username: username,
  221. }
  222. c := NewBaseConnection(sshConn1.id+"_1", ProtocolSFTP, user, nil)
  223. c.lastActivity = time.Now().Add(-24 * time.Hour).UnixNano()
  224. fakeConn := &fakeConnection{
  225. BaseConnection: c,
  226. }
  227. // both ssh connections are expired but they should get removed only
  228. // if there is no associated connection
  229. sshConn1.lastActivity = c.lastActivity
  230. sshConn2.lastActivity = c.lastActivity
  231. Connections.AddSSHConnection(sshConn1)
  232. Connections.Add(fakeConn)
  233. assert.Equal(t, Connections.GetActiveSessions(username), 1)
  234. c = NewBaseConnection(sshConn2.id+"_1", ProtocolSSH, user, nil)
  235. fakeConn = &fakeConnection{
  236. BaseConnection: c,
  237. }
  238. Connections.AddSSHConnection(sshConn2)
  239. Connections.Add(fakeConn)
  240. assert.Equal(t, Connections.GetActiveSessions(username), 2)
  241. cFTP := NewBaseConnection("id2", ProtocolFTP, dataprovider.User{}, nil)
  242. cFTP.lastActivity = time.Now().UnixNano()
  243. fakeConn = &fakeConnection{
  244. BaseConnection: cFTP,
  245. }
  246. Connections.Add(fakeConn)
  247. assert.Equal(t, Connections.GetActiveSessions(username), 2)
  248. assert.Len(t, Connections.GetStats(), 3)
  249. Connections.RLock()
  250. assert.Len(t, Connections.sshConnections, 2)
  251. Connections.RUnlock()
  252. startIdleTimeoutTicker(100 * time.Millisecond)
  253. assert.Eventually(t, func() bool { return Connections.GetActiveSessions(username) == 1 }, 1*time.Second, 200*time.Millisecond)
  254. assert.Eventually(t, func() bool {
  255. Connections.RLock()
  256. defer Connections.RUnlock()
  257. return len(Connections.sshConnections) == 1
  258. }, 1*time.Second, 200*time.Millisecond)
  259. stopIdleTimeoutTicker()
  260. assert.Len(t, Connections.GetStats(), 2)
  261. c.lastActivity = time.Now().Add(-24 * time.Hour).UnixNano()
  262. cFTP.lastActivity = time.Now().Add(-24 * time.Hour).UnixNano()
  263. sshConn2.lastActivity = c.lastActivity
  264. startIdleTimeoutTicker(100 * time.Millisecond)
  265. assert.Eventually(t, func() bool { return len(Connections.GetStats()) == 0 }, 1*time.Second, 200*time.Millisecond)
  266. assert.Eventually(t, func() bool {
  267. Connections.RLock()
  268. defer Connections.RUnlock()
  269. return len(Connections.sshConnections) == 0
  270. }, 1*time.Second, 200*time.Millisecond)
  271. stopIdleTimeoutTicker()
  272. assert.True(t, customConn1.isClosed)
  273. assert.True(t, customConn2.isClosed)
  274. Config = configCopy
  275. }
  276. func TestCloseConnection(t *testing.T) {
  277. c := NewBaseConnection("id", ProtocolSFTP, dataprovider.User{}, nil)
  278. fakeConn := &fakeConnection{
  279. BaseConnection: c,
  280. }
  281. Connections.Add(fakeConn)
  282. assert.Len(t, Connections.GetStats(), 1)
  283. res := Connections.Close(fakeConn.GetID())
  284. assert.True(t, res)
  285. assert.Eventually(t, func() bool { return len(Connections.GetStats()) == 0 }, 300*time.Millisecond, 50*time.Millisecond)
  286. res = Connections.Close(fakeConn.GetID())
  287. assert.False(t, res)
  288. Connections.Remove(fakeConn.GetID())
  289. }
  290. func TestSwapConnection(t *testing.T) {
  291. c := NewBaseConnection("id", ProtocolFTP, dataprovider.User{}, nil)
  292. fakeConn := &fakeConnection{
  293. BaseConnection: c,
  294. }
  295. Connections.Add(fakeConn)
  296. if assert.Len(t, Connections.GetStats(), 1) {
  297. assert.Equal(t, "", Connections.GetStats()[0].Username)
  298. }
  299. c = NewBaseConnection("id", ProtocolFTP, dataprovider.User{
  300. Username: userTestUsername,
  301. }, nil)
  302. fakeConn = &fakeConnection{
  303. BaseConnection: c,
  304. }
  305. err := Connections.Swap(fakeConn)
  306. assert.NoError(t, err)
  307. if assert.Len(t, Connections.GetStats(), 1) {
  308. assert.Equal(t, userTestUsername, Connections.GetStats()[0].Username)
  309. }
  310. res := Connections.Close(fakeConn.GetID())
  311. assert.True(t, res)
  312. assert.Eventually(t, func() bool { return len(Connections.GetStats()) == 0 }, 300*time.Millisecond, 50*time.Millisecond)
  313. err = Connections.Swap(fakeConn)
  314. assert.Error(t, err)
  315. }
  316. func TestAtomicUpload(t *testing.T) {
  317. configCopy := Config
  318. Config.UploadMode = UploadModeStandard
  319. assert.False(t, Config.IsAtomicUploadEnabled())
  320. Config.UploadMode = UploadModeAtomic
  321. assert.True(t, Config.IsAtomicUploadEnabled())
  322. Config.UploadMode = UploadModeAtomicWithResume
  323. assert.True(t, Config.IsAtomicUploadEnabled())
  324. Config = configCopy
  325. }
  326. func TestConnectionStatus(t *testing.T) {
  327. username := "test_user"
  328. user := dataprovider.User{
  329. Username: username,
  330. }
  331. fs := vfs.NewOsFs("", os.TempDir(), nil)
  332. c1 := NewBaseConnection("id1", ProtocolSFTP, user, fs)
  333. fakeConn1 := &fakeConnection{
  334. BaseConnection: c1,
  335. }
  336. t1 := NewBaseTransfer(nil, c1, nil, "/p1", "/r1", TransferUpload, 0, 0, 0, true, fs)
  337. t1.BytesReceived = 123
  338. t2 := NewBaseTransfer(nil, c1, nil, "/p2", "/r2", TransferDownload, 0, 0, 0, true, fs)
  339. t2.BytesSent = 456
  340. c2 := NewBaseConnection("id2", ProtocolSSH, user, nil)
  341. fakeConn2 := &fakeConnection{
  342. BaseConnection: c2,
  343. command: "md5sum",
  344. }
  345. c3 := NewBaseConnection("id3", ProtocolWebDAV, user, nil)
  346. fakeConn3 := &fakeConnection{
  347. BaseConnection: c3,
  348. command: "PROPFIND",
  349. }
  350. t3 := NewBaseTransfer(nil, c3, nil, "/p2", "/r2", TransferDownload, 0, 0, 0, true, fs)
  351. Connections.Add(fakeConn1)
  352. Connections.Add(fakeConn2)
  353. Connections.Add(fakeConn3)
  354. stats := Connections.GetStats()
  355. assert.Len(t, stats, 3)
  356. for _, stat := range stats {
  357. assert.Equal(t, stat.Username, username)
  358. assert.True(t, strings.HasPrefix(stat.GetConnectionInfo(), stat.Protocol))
  359. assert.True(t, strings.HasPrefix(stat.GetConnectionDuration(), "00:"))
  360. if stat.ConnectionID == "SFTP_id1" {
  361. assert.Len(t, stat.Transfers, 2)
  362. assert.Greater(t, len(stat.GetTransfersAsString()), 0)
  363. for _, tr := range stat.Transfers {
  364. if tr.OperationType == operationDownload {
  365. assert.True(t, strings.HasPrefix(tr.getConnectionTransferAsString(), "DL"))
  366. } else if tr.OperationType == operationUpload {
  367. assert.True(t, strings.HasPrefix(tr.getConnectionTransferAsString(), "UL"))
  368. }
  369. }
  370. } else if stat.ConnectionID == "DAV_id3" {
  371. assert.Len(t, stat.Transfers, 1)
  372. assert.Greater(t, len(stat.GetTransfersAsString()), 0)
  373. } else {
  374. assert.Equal(t, 0, len(stat.GetTransfersAsString()))
  375. }
  376. }
  377. err := t1.Close()
  378. assert.NoError(t, err)
  379. err = t2.Close()
  380. assert.NoError(t, err)
  381. err = fakeConn3.SignalTransfersAbort()
  382. assert.NoError(t, err)
  383. assert.Equal(t, int32(1), atomic.LoadInt32(&t3.AbortTransfer))
  384. err = t3.Close()
  385. assert.NoError(t, err)
  386. err = fakeConn3.SignalTransfersAbort()
  387. assert.Error(t, err)
  388. Connections.Remove(fakeConn1.GetID())
  389. stats = Connections.GetStats()
  390. assert.Len(t, stats, 2)
  391. assert.Equal(t, fakeConn3.GetID(), stats[0].ConnectionID)
  392. assert.Equal(t, fakeConn2.GetID(), stats[1].ConnectionID)
  393. Connections.Remove(fakeConn2.GetID())
  394. stats = Connections.GetStats()
  395. assert.Len(t, stats, 1)
  396. assert.Equal(t, fakeConn3.GetID(), stats[0].ConnectionID)
  397. Connections.Remove(fakeConn3.GetID())
  398. stats = Connections.GetStats()
  399. assert.Len(t, stats, 0)
  400. }
  401. func TestQuotaScans(t *testing.T) {
  402. username := "username"
  403. assert.True(t, QuotaScans.AddUserQuotaScan(username))
  404. assert.False(t, QuotaScans.AddUserQuotaScan(username))
  405. if assert.Len(t, QuotaScans.GetUsersQuotaScans(), 1) {
  406. assert.Equal(t, QuotaScans.GetUsersQuotaScans()[0].Username, username)
  407. }
  408. assert.True(t, QuotaScans.RemoveUserQuotaScan(username))
  409. assert.False(t, QuotaScans.RemoveUserQuotaScan(username))
  410. assert.Len(t, QuotaScans.GetUsersQuotaScans(), 0)
  411. folderName := "/folder"
  412. assert.True(t, QuotaScans.AddVFolderQuotaScan(folderName))
  413. assert.False(t, QuotaScans.AddVFolderQuotaScan(folderName))
  414. if assert.Len(t, QuotaScans.GetVFoldersQuotaScans(), 1) {
  415. assert.Equal(t, QuotaScans.GetVFoldersQuotaScans()[0].MappedPath, folderName)
  416. }
  417. assert.True(t, QuotaScans.RemoveVFolderQuotaScan(folderName))
  418. assert.False(t, QuotaScans.RemoveVFolderQuotaScan(folderName))
  419. assert.Len(t, QuotaScans.GetVFoldersQuotaScans(), 0)
  420. }
  421. func TestProxyProtocolVersion(t *testing.T) {
  422. c := Configuration{
  423. ProxyProtocol: 1,
  424. }
  425. proxyListener, err := c.GetProxyListener(nil)
  426. assert.NoError(t, err)
  427. assert.Nil(t, proxyListener.Policy)
  428. c.ProxyProtocol = 2
  429. proxyListener, err = c.GetProxyListener(nil)
  430. assert.NoError(t, err)
  431. assert.NotNil(t, proxyListener.Policy)
  432. c.ProxyProtocol = 1
  433. c.ProxyAllowed = []string{"invalid"}
  434. _, err = c.GetProxyListener(nil)
  435. assert.Error(t, err)
  436. c.ProxyProtocol = 2
  437. _, err = c.GetProxyListener(nil)
  438. assert.Error(t, err)
  439. }
  440. func TestProxyProtocol(t *testing.T) {
  441. httpClient := httpclient.GetHTTPClient()
  442. resp, err := httpClient.Get(fmt.Sprintf("http://%v", httpProxyAddr))
  443. if assert.NoError(t, err) {
  444. defer resp.Body.Close()
  445. assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
  446. }
  447. }
  448. func TestPostConnectHook(t *testing.T) {
  449. Config.PostConnectHook = ""
  450. remoteAddr := &net.IPAddr{
  451. IP: net.ParseIP("127.0.0.1"),
  452. Zone: "",
  453. }
  454. assert.NoError(t, Config.ExecutePostConnectHook(remoteAddr.String(), ProtocolFTP))
  455. Config.PostConnectHook = "http://foo\x7f.com/"
  456. assert.Error(t, Config.ExecutePostConnectHook(remoteAddr.String(), ProtocolSFTP))
  457. Config.PostConnectHook = "http://invalid:1234/"
  458. assert.Error(t, Config.ExecutePostConnectHook(remoteAddr.String(), ProtocolSFTP))
  459. Config.PostConnectHook = fmt.Sprintf("http://%v/404", httpAddr)
  460. assert.Error(t, Config.ExecutePostConnectHook(remoteAddr.String(), ProtocolFTP))
  461. Config.PostConnectHook = fmt.Sprintf("http://%v", httpAddr)
  462. assert.NoError(t, Config.ExecutePostConnectHook(remoteAddr.String(), ProtocolFTP))
  463. Config.PostConnectHook = "invalid"
  464. assert.Error(t, Config.ExecutePostConnectHook(remoteAddr.String(), ProtocolFTP))
  465. if runtime.GOOS == osWindows {
  466. Config.PostConnectHook = "C:\\bad\\command"
  467. assert.Error(t, Config.ExecutePostConnectHook(remoteAddr.String(), ProtocolSFTP))
  468. } else {
  469. Config.PostConnectHook = "/invalid/path"
  470. assert.Error(t, Config.ExecutePostConnectHook(remoteAddr.String(), ProtocolSFTP))
  471. hookCmd, err := exec.LookPath("true")
  472. assert.NoError(t, err)
  473. Config.PostConnectHook = hookCmd
  474. assert.NoError(t, Config.ExecutePostConnectHook(remoteAddr.String(), ProtocolSFTP))
  475. }
  476. Config.PostConnectHook = ""
  477. }
  478. func TestCryptoConvertFileInfo(t *testing.T) {
  479. name := "name"
  480. fs, err := vfs.NewCryptFs("connID1", os.TempDir(), vfs.CryptFsConfig{Passphrase: kms.NewPlainSecret("secret")})
  481. require.NoError(t, err)
  482. cryptFs := fs.(*vfs.CryptFs)
  483. info := vfs.NewFileInfo(name, true, 48, time.Now(), false)
  484. assert.Equal(t, info, cryptFs.ConvertFileInfo(info))
  485. info = vfs.NewFileInfo(name, false, 48, time.Now(), false)
  486. assert.NotEqual(t, info.Size(), cryptFs.ConvertFileInfo(info).Size())
  487. info = vfs.NewFileInfo(name, false, 33, time.Now(), false)
  488. assert.Equal(t, int64(0), cryptFs.ConvertFileInfo(info).Size())
  489. info = vfs.NewFileInfo(name, false, 1, time.Now(), false)
  490. assert.Equal(t, int64(0), cryptFs.ConvertFileInfo(info).Size())
  491. }