github.com/advanderveer/restic@v0.8.1-0.20171209104529-42a8c19aaea6/internal/restic/node_test.go (about) 1 package restic_test 2 3 import ( 4 "context" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "runtime" 9 "testing" 10 "time" 11 12 "github.com/restic/restic/internal/restic" 13 rtest "github.com/restic/restic/internal/test" 14 ) 15 16 func BenchmarkNodeFillUser(t *testing.B) { 17 tempfile, err := ioutil.TempFile("", "restic-test-temp-") 18 if err != nil { 19 t.Fatal(err) 20 } 21 22 fi, err := tempfile.Stat() 23 if err != nil { 24 t.Fatal(err) 25 } 26 27 path := tempfile.Name() 28 29 t.ResetTimer() 30 31 for i := 0; i < t.N; i++ { 32 restic.NodeFromFileInfo(path, fi) 33 } 34 35 rtest.OK(t, tempfile.Close()) 36 rtest.RemoveAll(t, tempfile.Name()) 37 } 38 39 func BenchmarkNodeFromFileInfo(t *testing.B) { 40 tempfile, err := ioutil.TempFile("", "restic-test-temp-") 41 if err != nil { 42 t.Fatal(err) 43 } 44 45 fi, err := tempfile.Stat() 46 if err != nil { 47 t.Fatal(err) 48 } 49 50 path := tempfile.Name() 51 52 t.ResetTimer() 53 54 for i := 0; i < t.N; i++ { 55 _, err := restic.NodeFromFileInfo(path, fi) 56 if err != nil { 57 t.Fatal(err) 58 } 59 } 60 61 rtest.OK(t, tempfile.Close()) 62 rtest.RemoveAll(t, tempfile.Name()) 63 } 64 65 func parseTime(s string) time.Time { 66 t, err := time.Parse("2006-01-02 15:04:05.999", s) 67 if err != nil { 68 panic(err) 69 } 70 71 return t.Local() 72 } 73 74 var nodeTests = []restic.Node{ 75 { 76 Name: "testFile", 77 Type: "file", 78 Content: restic.IDs{}, 79 UID: uint32(os.Getuid()), 80 GID: uint32(os.Getgid()), 81 Mode: 0604, 82 ModTime: parseTime("2015-05-14 21:07:23.111"), 83 AccessTime: parseTime("2015-05-14 21:07:24.222"), 84 ChangeTime: parseTime("2015-05-14 21:07:25.333"), 85 }, 86 { 87 Name: "testSuidFile", 88 Type: "file", 89 Content: restic.IDs{}, 90 UID: uint32(os.Getuid()), 91 GID: uint32(os.Getgid()), 92 Mode: 0755 | os.ModeSetuid, 93 ModTime: parseTime("2015-05-14 21:07:23.111"), 94 AccessTime: parseTime("2015-05-14 21:07:24.222"), 95 ChangeTime: parseTime("2015-05-14 21:07:25.333"), 96 }, 97 { 98 Name: "testSuidFile2", 99 Type: "file", 100 Content: restic.IDs{}, 101 UID: uint32(os.Getuid()), 102 GID: uint32(os.Getgid()), 103 Mode: 0755 | os.ModeSetgid, 104 ModTime: parseTime("2015-05-14 21:07:23.111"), 105 AccessTime: parseTime("2015-05-14 21:07:24.222"), 106 ChangeTime: parseTime("2015-05-14 21:07:25.333"), 107 }, 108 { 109 Name: "testSticky", 110 Type: "file", 111 Content: restic.IDs{}, 112 UID: uint32(os.Getuid()), 113 GID: uint32(os.Getgid()), 114 Mode: 0755 | os.ModeSticky, 115 ModTime: parseTime("2015-05-14 21:07:23.111"), 116 AccessTime: parseTime("2015-05-14 21:07:24.222"), 117 ChangeTime: parseTime("2015-05-14 21:07:25.333"), 118 }, 119 { 120 Name: "testDir", 121 Type: "dir", 122 Subtree: nil, 123 UID: uint32(os.Getuid()), 124 GID: uint32(os.Getgid()), 125 Mode: 0750 | os.ModeDir, 126 ModTime: parseTime("2015-05-14 21:07:23.111"), 127 AccessTime: parseTime("2015-05-14 21:07:24.222"), 128 ChangeTime: parseTime("2015-05-14 21:07:25.333"), 129 }, 130 { 131 Name: "testSymlink", 132 Type: "symlink", 133 LinkTarget: "invalid", 134 UID: uint32(os.Getuid()), 135 GID: uint32(os.Getgid()), 136 Mode: 0777 | os.ModeSymlink, 137 ModTime: parseTime("2015-05-14 21:07:23.111"), 138 AccessTime: parseTime("2015-05-14 21:07:24.222"), 139 ChangeTime: parseTime("2015-05-14 21:07:25.333"), 140 }, 141 142 // include "testFile" and "testDir" again with slightly different 143 // metadata, so we can test if CreateAt works with pre-existing files. 144 { 145 Name: "testFile", 146 Type: "file", 147 Content: restic.IDs{}, 148 UID: uint32(os.Getuid()), 149 GID: uint32(os.Getgid()), 150 Mode: 0604, 151 ModTime: parseTime("2005-05-14 21:07:03.111"), 152 AccessTime: parseTime("2005-05-14 21:07:04.222"), 153 ChangeTime: parseTime("2005-05-14 21:07:05.333"), 154 }, 155 { 156 Name: "testDir", 157 Type: "dir", 158 Subtree: nil, 159 UID: uint32(os.Getuid()), 160 GID: uint32(os.Getgid()), 161 Mode: 0750 | os.ModeDir, 162 ModTime: parseTime("2005-05-14 21:07:03.111"), 163 AccessTime: parseTime("2005-05-14 21:07:04.222"), 164 ChangeTime: parseTime("2005-05-14 21:07:05.333"), 165 }, 166 } 167 168 func TestNodeRestoreAt(t *testing.T) { 169 tempdir, err := ioutil.TempDir(rtest.TestTempDir, "restic-test-") 170 rtest.OK(t, err) 171 172 defer func() { 173 if rtest.TestCleanupTempDirs { 174 rtest.RemoveAll(t, tempdir) 175 } else { 176 t.Logf("leaving tempdir at %v", tempdir) 177 } 178 }() 179 180 idx := restic.NewHardlinkIndex() 181 182 for _, test := range nodeTests { 183 nodePath := filepath.Join(tempdir, test.Name) 184 rtest.OK(t, test.CreateAt(context.TODO(), nodePath, nil, idx)) 185 186 if test.Type == "symlink" && runtime.GOOS == "windows" { 187 continue 188 } 189 if test.Type == "dir" { 190 rtest.OK(t, test.RestoreTimestamps(nodePath)) 191 } 192 193 fi, err := os.Lstat(nodePath) 194 rtest.OK(t, err) 195 196 n2, err := restic.NodeFromFileInfo(nodePath, fi) 197 rtest.OK(t, err) 198 199 rtest.Assert(t, test.Name == n2.Name, 200 "%v: name doesn't match (%v != %v)", test.Type, test.Name, n2.Name) 201 rtest.Assert(t, test.Type == n2.Type, 202 "%v: type doesn't match (%v != %v)", test.Type, test.Type, n2.Type) 203 rtest.Assert(t, test.Size == n2.Size, 204 "%v: size doesn't match (%v != %v)", test.Size, test.Size, n2.Size) 205 206 if runtime.GOOS != "windows" { 207 rtest.Assert(t, test.UID == n2.UID, 208 "%v: UID doesn't match (%v != %v)", test.Type, test.UID, n2.UID) 209 rtest.Assert(t, test.GID == n2.GID, 210 "%v: GID doesn't match (%v != %v)", test.Type, test.GID, n2.GID) 211 if test.Type != "symlink" { 212 rtest.Assert(t, test.Mode == n2.Mode, 213 "%v: mode doesn't match (0%o != 0%o)", test.Type, test.Mode, n2.Mode) 214 } 215 } 216 217 AssertFsTimeEqual(t, "AccessTime", test.Type, test.AccessTime, n2.AccessTime) 218 AssertFsTimeEqual(t, "ModTime", test.Type, test.ModTime, n2.ModTime) 219 } 220 } 221 222 func AssertFsTimeEqual(t *testing.T, label string, nodeType string, t1 time.Time, t2 time.Time) { 223 var equal bool 224 225 // Go currently doesn't support setting timestamps of symbolic links on darwin and bsd 226 if nodeType == "symlink" { 227 switch runtime.GOOS { 228 case "darwin", "freebsd", "openbsd": 229 return 230 } 231 } 232 233 switch runtime.GOOS { 234 case "darwin": 235 // HFS+ timestamps don't support sub-second precision, 236 // see https://en.wikipedia.org/wiki/Comparison_of_file_systems 237 diff := int(t1.Sub(t2).Seconds()) 238 equal = diff == 0 239 default: 240 equal = t1.Equal(t2) 241 } 242 243 rtest.Assert(t, equal, "%s: %s doesn't match (%v != %v)", label, nodeType, t1, t2) 244 }