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