mtimefs_test.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // Copyright (C) 2016 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at http://mozilla.org/MPL/2.0/.
  6. package fs
  7. import (
  8. "errors"
  9. "io/ioutil"
  10. "os"
  11. "testing"
  12. "time"
  13. )
  14. func TestMtimeFS(t *testing.T) {
  15. os.RemoveAll("testdata")
  16. defer os.RemoveAll("testdata")
  17. os.Mkdir("testdata", 0755)
  18. ioutil.WriteFile("testdata/exists0", []byte("hello"), 0644)
  19. ioutil.WriteFile("testdata/exists1", []byte("hello"), 0644)
  20. ioutil.WriteFile("testdata/exists2", []byte("hello"), 0644)
  21. // a random time with nanosecond precision
  22. testTime := time.Unix(1234567890, 123456789)
  23. mtimefs := NewMtimeFS(make(mapStore))
  24. // Do one Chtimes call that will go through to the normal filesystem
  25. osChtimes = os.Chtimes
  26. if err := mtimefs.Chtimes("testdata/exists0", testTime, testTime); err != nil {
  27. t.Error("Should not have failed:", err)
  28. }
  29. // Do one call that gets an error back from the underlying Chtimes
  30. osChtimes = failChtimes
  31. if err := mtimefs.Chtimes("testdata/exists1", testTime, testTime); err != nil {
  32. t.Error("Should not have failed:", err)
  33. }
  34. // Do one call that gets struck by an exceptionally evil Chtimes
  35. osChtimes = evilChtimes
  36. if err := mtimefs.Chtimes("testdata/exists2", testTime, testTime); err != nil {
  37. t.Error("Should not have failed:", err)
  38. }
  39. // All of the calls were successfull, so an Lstat on them should return
  40. // the test timestamp.
  41. for _, file := range []string{"testdata/exists0", "testdata/exists1", "testdata/exists2"} {
  42. if info, err := mtimefs.Lstat(file); err != nil {
  43. t.Error("Lstat shouldn't fail:", err)
  44. } else if !info.ModTime().Equal(testTime) {
  45. t.Errorf("Time mismatch; %v != expected %v", info.ModTime(), testTime)
  46. }
  47. }
  48. // The two last files should certainly not have the correct timestamp
  49. // when looking directly on disk though.
  50. for _, file := range []string{"testdata/exists1", "testdata/exists2"} {
  51. if info, err := os.Lstat(file); err != nil {
  52. t.Error("Lstat shouldn't fail:", err)
  53. } else if info.ModTime().Equal(testTime) {
  54. t.Errorf("Unexpected time match; %v == %v", info.ModTime(), testTime)
  55. }
  56. }
  57. // Changing the timestamp on disk should be reflected in a new Lstat
  58. // call. Choose a time that is likely to be able to be on all reasonable
  59. // filesystems.
  60. testTime = time.Now().Add(5 * time.Hour).Truncate(time.Minute)
  61. os.Chtimes("testdata/exists0", testTime, testTime)
  62. if info, err := mtimefs.Lstat("testdata/exists0"); err != nil {
  63. t.Error("Lstat shouldn't fail:", err)
  64. } else if !info.ModTime().Equal(testTime) {
  65. t.Errorf("Time mismatch; %v != expected %v", info.ModTime(), testTime)
  66. }
  67. }
  68. // The mapStore is a simple database
  69. type mapStore map[string][]byte
  70. func (s mapStore) PutBytes(key string, data []byte) {
  71. s[key] = data
  72. }
  73. func (s mapStore) Bytes(key string) (data []byte, ok bool) {
  74. data, ok = s[key]
  75. return
  76. }
  77. func (s mapStore) Delete(key string) {
  78. delete(s, key)
  79. }
  80. // failChtimes does nothing, and fails
  81. func failChtimes(name string, mtime, atime time.Time) error {
  82. return errors.New("no")
  83. }
  84. // evilChtimes will set an mtime that's 300 days in the future of what was
  85. // asked for, and truncate the time to the closest hour.
  86. func evilChtimes(name string, mtime, atime time.Time) error {
  87. return os.Chtimes(name, mtime.Add(300*time.Hour).Truncate(time.Hour), atime.Add(300*time.Hour).Truncate(time.Hour))
  88. }