folder_test.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Copyright (C) 2018 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 https://mozilla.org/MPL/2.0/.
  6. package model
  7. import (
  8. "path/filepath"
  9. "testing"
  10. "github.com/d4l3k/messagediff"
  11. "github.com/syncthing/syncthing/lib/build"
  12. "github.com/syncthing/syncthing/lib/config"
  13. "github.com/syncthing/syncthing/lib/fs"
  14. "github.com/syncthing/syncthing/lib/protocol"
  15. )
  16. type unifySubsCase struct {
  17. in []string // input to unifySubs
  18. exists []string // paths that exist in the database
  19. out []string // expected output
  20. }
  21. func unifySubsCases() []unifySubsCase {
  22. cases := []unifySubsCase{
  23. {
  24. // 0. trailing slashes are cleaned, known paths are just passed on
  25. []string{"foo/", "bar//"},
  26. []string{"foo", "bar"},
  27. []string{"bar", "foo"}, // the output is sorted
  28. },
  29. {
  30. // 1. "foo/bar" gets trimmed as it's covered by foo
  31. []string{"foo", "bar/", "foo/bar/"},
  32. []string{"foo", "bar"},
  33. []string{"bar", "foo"},
  34. },
  35. {
  36. // 2. "" gets simplified to the empty list; ie scan all
  37. []string{"foo", ""},
  38. []string{"foo"},
  39. nil,
  40. },
  41. {
  42. // 3. "foo/bar" is unknown, but it's kept
  43. // because its parent is known
  44. []string{"foo/bar"},
  45. []string{"foo"},
  46. []string{"foo/bar"},
  47. },
  48. {
  49. // 4. two independent known paths, both are kept
  50. // "usr/lib" is not a prefix of "usr/libexec"
  51. []string{"usr/lib", "usr/libexec"},
  52. []string{"usr", "usr/lib", "usr/libexec"},
  53. []string{"usr/lib", "usr/libexec"},
  54. },
  55. {
  56. // 5. "usr/lib" is a prefix of "usr/lib/exec"
  57. []string{"usr/lib", "usr/lib/exec"},
  58. []string{"usr", "usr/lib", "usr/libexec"},
  59. []string{"usr/lib"},
  60. },
  61. {
  62. // 6. .stignore and .stfolder are special and are passed on
  63. // verbatim even though they are unknown
  64. []string{config.DefaultMarkerName, ".stignore"},
  65. []string{},
  66. []string{config.DefaultMarkerName, ".stignore"},
  67. },
  68. {
  69. // 7. but the presence of something else unknown forces an actual
  70. // scan
  71. []string{config.DefaultMarkerName, ".stignore", "foo/bar"},
  72. []string{},
  73. []string{config.DefaultMarkerName, ".stignore", "foo"},
  74. },
  75. {
  76. // 8. explicit request to scan all
  77. nil,
  78. []string{"foo"},
  79. nil,
  80. },
  81. {
  82. // 9. empty list of subs
  83. []string{},
  84. []string{"foo"},
  85. nil,
  86. },
  87. {
  88. // 10. absolute path
  89. []string{"/foo"},
  90. []string{"foo"},
  91. []string{"foo"},
  92. },
  93. }
  94. if build.IsWindows {
  95. // Fixup path separators
  96. for i := range cases {
  97. for j, p := range cases[i].in {
  98. cases[i].in[j] = filepath.FromSlash(p)
  99. }
  100. for j, p := range cases[i].exists {
  101. cases[i].exists[j] = filepath.FromSlash(p)
  102. }
  103. for j, p := range cases[i].out {
  104. cases[i].out[j] = filepath.FromSlash(p)
  105. }
  106. }
  107. }
  108. return cases
  109. }
  110. func unifyExists(f string, tc unifySubsCase) bool {
  111. for _, e := range tc.exists {
  112. if f == e {
  113. return true
  114. }
  115. }
  116. return false
  117. }
  118. func TestUnifySubs(t *testing.T) {
  119. cases := unifySubsCases()
  120. for i, tc := range cases {
  121. exists := func(f string) bool {
  122. return unifyExists(f, tc)
  123. }
  124. out := unifySubs(tc.in, exists)
  125. if diff, equal := messagediff.PrettyDiff(tc.out, out); !equal {
  126. t.Errorf("Case %d failed; got %v, expected %v, diff:\n%s", i, out, tc.out, diff)
  127. }
  128. }
  129. }
  130. func BenchmarkUnifySubs(b *testing.B) {
  131. cases := unifySubsCases()
  132. b.ReportAllocs()
  133. b.ResetTimer()
  134. for i := 0; i < b.N; i++ {
  135. for _, tc := range cases {
  136. exists := func(f string) bool {
  137. return unifyExists(f, tc)
  138. }
  139. unifySubs(tc.in, exists)
  140. }
  141. }
  142. }
  143. func TestSetPlatformData(t *testing.T) {
  144. // Checks that setPlatformData runs without error when applied to a temp
  145. // file, named differently than the given FileInfo.
  146. dir := t.TempDir()
  147. fs := fs.NewFilesystem(fs.FilesystemTypeBasic, dir)
  148. if fd, err := fs.Create("file.tmp"); err != nil {
  149. t.Fatal(err)
  150. } else {
  151. fd.Close()
  152. }
  153. xattr := []protocol.Xattr{{Name: "user.foo", Value: []byte("bar")}}
  154. fi := &protocol.FileInfo{
  155. Name: "should be ignored",
  156. Permissions: 0400,
  157. ModifiedS: 1234567890,
  158. Platform: protocol.PlatformData{
  159. Linux: &protocol.XattrData{Xattrs: xattr},
  160. Darwin: &protocol.XattrData{Xattrs: xattr},
  161. FreeBSD: &protocol.XattrData{Xattrs: xattr},
  162. NetBSD: &protocol.XattrData{Xattrs: xattr},
  163. },
  164. }
  165. // Minimum required to support setPlatformData
  166. sr := &sendReceiveFolder{
  167. folder: folder{
  168. FolderConfiguration: config.FolderConfiguration{
  169. SyncXattrs: true,
  170. },
  171. mtimefs: fs,
  172. },
  173. }
  174. if err := sr.setPlatformData(fi, "file.tmp"); err != nil {
  175. t.Error(err)
  176. }
  177. }