From a467f6908c4ffd900e6ca8f081cf0436f20c6365 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Fri, 8 Jun 2018 12:02:16 +0200 Subject: [PATCH] lib/protocol: Test for IsEquivalent (#4996) --- lib/protocol/protocol_test.go | 162 ++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/lib/protocol/protocol_test.go b/lib/protocol/protocol_test.go index 4c0a758bb..3bc9af211 100644 --- a/lib/protocol/protocol_test.go +++ b/lib/protocol/protocol_test.go @@ -9,6 +9,7 @@ import ( "errors" "io" "io/ioutil" + "runtime" "strings" "testing" "testing/quick" @@ -389,3 +390,164 @@ func BenchmarkBlockSize(b *testing.B) { blockSize = BlockSize(16 << 30) } } + +func TestIsEquivalent(t *testing.T) { + b := func(v bool) *bool { + return &v + } + + type testCase struct { + a FileInfo + b FileInfo + ignPerms *bool // nil means should not matter, we'll test both variants + ignBlocks *bool + eq bool + } + cases := []testCase{ + // Empty FileInfos are equivalent + {eq: true}, + + // Various basic attributes, all of which cause ineqality when + // they differ + { + a: FileInfo{Name: "foo"}, + b: FileInfo{Name: "bar"}, + eq: false, + }, + { + a: FileInfo{Type: FileInfoTypeFile}, + b: FileInfo{Type: FileInfoTypeDirectory}, + eq: false, + }, + { + a: FileInfo{Size: 1234}, + b: FileInfo{Size: 2345}, + eq: false, + }, + { + a: FileInfo{Deleted: false}, + b: FileInfo{Deleted: true}, + eq: false, + }, + { + a: FileInfo{Invalid: false}, + b: FileInfo{Invalid: true}, + eq: false, + }, + { + a: FileInfo{ModifiedS: 1234}, + b: FileInfo{ModifiedS: 2345}, + eq: false, + }, + { + a: FileInfo{ModifiedNs: 1234}, + b: FileInfo{ModifiedNs: 2345}, + eq: false, + }, + + // Difference in blocks is not OK + { + a: FileInfo{Blocks: []BlockInfo{{Hash: []byte{1, 2, 3, 4}}}}, + b: FileInfo{Blocks: []BlockInfo{{Hash: []byte{2, 3, 4, 5}}}}, + ignBlocks: b(false), + eq: false, + }, + + // ... unless we say it is + { + a: FileInfo{Blocks: []BlockInfo{{Hash: []byte{1, 2, 3, 4}}}}, + b: FileInfo{Blocks: []BlockInfo{{Hash: []byte{2, 3, 4, 5}}}}, + ignBlocks: b(true), + eq: true, + }, + + // Difference in permissions is not OK. + { + a: FileInfo{Permissions: 0444}, + b: FileInfo{Permissions: 0666}, + ignPerms: b(false), + eq: false, + }, + + // ... unless we say it is + { + a: FileInfo{Permissions: 0666}, + b: FileInfo{Permissions: 0444}, + ignPerms: b(true), + eq: true, + }, + + // These attributes are not checked at all + { + a: FileInfo{NoPermissions: false}, + b: FileInfo{NoPermissions: true}, + eq: true, + }, + { + a: FileInfo{Version: Vector{Counters: []Counter{{ID: 1, Value: 42}}}}, + b: FileInfo{Version: Vector{Counters: []Counter{{ID: 42, Value: 1}}}}, + eq: true, + }, + { + a: FileInfo{Sequence: 1}, + b: FileInfo{Sequence: 2}, + eq: true, + }, + + // The block size is not checked (but this would fail the blocks + // check in real world) + { + a: FileInfo{RawBlockSize: 1}, + b: FileInfo{RawBlockSize: 2}, + eq: true, + }, + + // The symlink target is checked for symlinks + { + a: FileInfo{Type: FileInfoTypeSymlink, SymlinkTarget: "a"}, + b: FileInfo{Type: FileInfoTypeSymlink, SymlinkTarget: "b"}, + eq: false, + }, + + // ... but not for non-symlinks + { + a: FileInfo{Type: FileInfoTypeFile, SymlinkTarget: "a"}, + b: FileInfo{Type: FileInfoTypeFile, SymlinkTarget: "b"}, + eq: true, + }, + } + + if runtime.GOOS == "windows" { + // On windows we only check the user writable bit of the permission + // set, so these are equivalent. + cases = append(cases, testCase{ + a: FileInfo{Permissions: 0777}, + b: FileInfo{Permissions: 0600}, + ignPerms: b(false), + eq: true, + }) + } + + for i, tc := range cases { + // Check the standard attributes with all permutations of the + // special ignore flags, unless the value of those flags are given + // in the tests. + for _, ignPerms := range []bool{true, false} { + for _, ignBlocks := range []bool{true, false} { + if tc.ignPerms != nil && *tc.ignPerms != ignPerms { + continue + } + if tc.ignBlocks != nil && *tc.ignBlocks != ignBlocks { + continue + } + + if res := tc.a.IsEquivalent(tc.b, ignPerms, ignBlocks); res != tc.eq { + t.Errorf("Case %d:\na: %v\nb: %v\na.IsEquivalent(b, %v, %v) => %v, expected %v", i, tc.a, tc.b, ignPerms, ignBlocks, res, tc.eq) + } + if res := tc.b.IsEquivalent(tc.a, ignPerms, ignBlocks); res != tc.eq { + t.Errorf("Case %d:\na: %v\nb: %v\nb.IsEquivalent(a, %v, %v) => %v, expected %v", i, tc.a, tc.b, ignPerms, ignBlocks, res, tc.eq) + } + } + } + } +}