github.com/Synthesix/Sia@v1.3.3-0.20180413141344-f863baeed3ca/modules/renter/persist_test.go (about) 1 package renter 2 3 import ( 4 "bytes" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strconv" 9 "testing" 10 11 "github.com/Synthesix/Sia/build" 12 "github.com/Synthesix/Sia/crypto" 13 "github.com/Synthesix/Sia/encoding" 14 "github.com/Synthesix/Sia/persist" 15 "github.com/NebulousLabs/fastrand" 16 ) 17 18 // newTestingFile initializes a file object with random parameters. 19 func newTestingFile() *file { 20 data := fastrand.Bytes(8) 21 nData := fastrand.Intn(10) 22 nParity := fastrand.Intn(10) 23 rsc, _ := NewRSCode(nData+1, nParity+1) 24 25 return &file{ 26 name: "testfile-" + strconv.Itoa(int(data[0])), 27 size: encoding.DecUint64(data[1:5]), 28 masterKey: crypto.GenerateTwofishKey(), 29 erasureCode: rsc, 30 pieceSize: encoding.DecUint64(data[6:8]), 31 staticUID: persist.RandomSuffix(), 32 } 33 } 34 35 // equalFiles is a helper function that compares two files for equality. 36 func equalFiles(f1, f2 *file) error { 37 if f1 == nil || f2 == nil { 38 return fmt.Errorf("one or both files are nil") 39 } 40 if f1.name != f2.name { 41 return fmt.Errorf("names do not match: %v %v", f1.name, f2.name) 42 } 43 if f1.size != f2.size { 44 return fmt.Errorf("sizes do not match: %v %v", f1.size, f2.size) 45 } 46 if f1.masterKey != f2.masterKey { 47 return fmt.Errorf("keys do not match: %v %v", f1.masterKey, f2.masterKey) 48 } 49 if f1.pieceSize != f2.pieceSize { 50 return fmt.Errorf("pieceSizes do not match: %v %v", f1.pieceSize, f2.pieceSize) 51 } 52 return nil 53 } 54 55 // TestFileMarshalling tests the MarshalSia and UnmarshalSia functions of the 56 // file type. 57 func TestFileMarshalling(t *testing.T) { 58 savedFile := newTestingFile() 59 buf := new(bytes.Buffer) 60 savedFile.MarshalSia(buf) 61 62 loadedFile := new(file) 63 err := loadedFile.UnmarshalSia(buf) 64 if err != nil { 65 t.Fatal(err) 66 } 67 68 err = equalFiles(savedFile, loadedFile) 69 if err != nil { 70 t.Fatal(err) 71 } 72 } 73 74 // TestFileShareLoad tests the sharing/loading functions of the renter. 75 func TestFileShareLoad(t *testing.T) { 76 if testing.Short() { 77 t.SkipNow() 78 } 79 rt, err := newRenterTester(t.Name()) 80 if err != nil { 81 t.Fatal(err) 82 } 83 defer rt.Close() 84 85 // Create a file and add it to the renter. 86 savedFile := newTestingFile() 87 id := rt.renter.mu.Lock() 88 rt.renter.files[savedFile.name] = savedFile 89 rt.renter.mu.Unlock(id) 90 91 // Share .sia file to disk. 92 path := filepath.Join(build.SiaTestingDir, "renter", t.Name(), "test.sia") 93 err = rt.renter.ShareFiles([]string{savedFile.name}, path) 94 if err != nil { 95 t.Fatal(err) 96 } 97 98 // Remove the file from the renter. 99 delete(rt.renter.files, savedFile.name) 100 101 // Load the .sia file back into the renter. 102 names, err := rt.renter.LoadSharedFiles(path) 103 if err != nil { 104 t.Fatal(err) 105 } 106 if len(names) != 1 || names[0] != savedFile.name { 107 t.Fatal("nickname not loaded properly:", names) 108 } 109 err = equalFiles(rt.renter.files[savedFile.name], savedFile) 110 if err != nil { 111 t.Fatal(err) 112 } 113 114 // Share and load multiple files. 115 savedFile2 := newTestingFile() 116 rt.renter.files[savedFile2.name] = savedFile2 117 path = filepath.Join(build.SiaTestingDir, "renter", t.Name(), "test2.sia") 118 err = rt.renter.ShareFiles([]string{savedFile.name, savedFile2.name}, path) 119 if err != nil { 120 t.Fatal(err) 121 } 122 123 // Remove the files from the renter. 124 delete(rt.renter.files, savedFile.name) 125 delete(rt.renter.files, savedFile2.name) 126 127 names, err = rt.renter.LoadSharedFiles(path) 128 if err != nil { 129 t.Fatal(nil) 130 } 131 if len(names) != 2 || (names[0] != savedFile2.name && names[1] != savedFile2.name) { 132 t.Fatal("nicknames not loaded properly:", names) 133 } 134 err = equalFiles(rt.renter.files[savedFile.name], savedFile) 135 if err != nil { 136 t.Fatal(err) 137 } 138 err = equalFiles(rt.renter.files[savedFile2.name], savedFile2) 139 if err != nil { 140 t.Fatal(err) 141 } 142 } 143 144 // TestFileShareLoadASCII tests the ASCII sharing/loading functions. 145 func TestFileShareLoadASCII(t *testing.T) { 146 if testing.Short() { 147 t.SkipNow() 148 } 149 rt, err := newRenterTester(t.Name()) 150 if err != nil { 151 t.Fatal(err) 152 } 153 defer rt.Close() 154 155 // Create a file and add it to the renter. 156 savedFile := newTestingFile() 157 id := rt.renter.mu.Lock() 158 rt.renter.files[savedFile.name] = savedFile 159 rt.renter.mu.Unlock(id) 160 161 ascii, err := rt.renter.ShareFilesASCII([]string{savedFile.name}) 162 if err != nil { 163 t.Fatal(err) 164 } 165 166 // Remove the file from the renter. 167 delete(rt.renter.files, savedFile.name) 168 169 names, err := rt.renter.LoadSharedFilesASCII(ascii) 170 if err != nil { 171 t.Fatal(err) 172 } 173 if len(names) != 1 || names[0] != savedFile.name { 174 t.Fatal("nickname not loaded properly") 175 } 176 177 err = equalFiles(rt.renter.files[savedFile.name], savedFile) 178 if err != nil { 179 t.Fatal(err) 180 } 181 } 182 183 // TestRenterSaveLoad probes the save and load methods of the renter type. 184 func TestRenterSaveLoad(t *testing.T) { 185 if testing.Short() { 186 t.SkipNow() 187 } 188 rt, err := newRenterTester(t.Name()) 189 if err != nil { 190 t.Fatal(err) 191 } 192 defer rt.Close() 193 194 // Create and save some files 195 var f1, f2, f3 *file 196 f1 = newTestingFile() 197 f2 = newTestingFile() 198 f3 = newTestingFile() 199 // names must not conflict 200 for f2.name == f1.name || f2.name == f3.name { 201 f2 = newTestingFile() 202 } 203 for f3.name == f1.name || f3.name == f2.name { 204 f3 = newTestingFile() 205 } 206 rt.renter.saveFile(f1) 207 rt.renter.saveFile(f2) 208 rt.renter.saveFile(f3) 209 210 err = rt.renter.saveSync() // save metadata 211 if err != nil { 212 t.Fatal(err) 213 } 214 215 // load should now load the files into memory. 216 id := rt.renter.mu.Lock() 217 err = rt.renter.load() 218 rt.renter.mu.Unlock(id) 219 if err != nil && !os.IsNotExist(err) { 220 t.Fatal(err) 221 } 222 223 if err := equalFiles(f1, rt.renter.files[f1.name]); err != nil { 224 t.Fatal(err) 225 } 226 if err := equalFiles(f2, rt.renter.files[f2.name]); err != nil { 227 t.Fatal(err) 228 } 229 if err := equalFiles(f3, rt.renter.files[f3.name]); err != nil { 230 t.Fatal(err) 231 } 232 } 233 234 // TestRenterPaths checks that the renter properly handles nicknames 235 // containing the path separator ("/"). 236 func TestRenterPaths(t *testing.T) { 237 if testing.Short() { 238 t.SkipNow() 239 } 240 rt, err := newRenterTester(t.Name()) 241 if err != nil { 242 t.Fatal(err) 243 } 244 defer rt.Close() 245 246 // Create and save some files. 247 // The result of saving these files should be a directory containing: 248 // foo.sia 249 // foo/bar.sia 250 // foo/bar/baz.sia 251 f1 := newTestingFile() 252 f1.name = "foo" 253 f2 := newTestingFile() 254 f2.name = "foo/bar" 255 f3 := newTestingFile() 256 f3.name = "foo/bar/baz" 257 rt.renter.saveFile(f1) 258 rt.renter.saveFile(f2) 259 rt.renter.saveFile(f3) 260 261 // Load the files into the renter. 262 id := rt.renter.mu.Lock() 263 err = rt.renter.load() 264 rt.renter.mu.Unlock(id) 265 if err != nil && !os.IsNotExist(err) { 266 t.Fatal(err) 267 } 268 // Check that the files were loaded properly. 269 if err := equalFiles(f1, rt.renter.files[f1.name]); err != nil { 270 t.Fatal(err) 271 } 272 if err := equalFiles(f2, rt.renter.files[f2.name]); err != nil { 273 t.Fatal(err) 274 } 275 if err := equalFiles(f3, rt.renter.files[f3.name]); err != nil { 276 t.Fatal(err) 277 } 278 279 // To confirm that the file structure was preserved, we walk the renter 280 // folder and emit the name of each .sia file encountered (filepath.Walk 281 // is deterministic; it orders the files lexically). 282 var walkStr string 283 filepath.Walk(rt.renter.persistDir, func(path string, _ os.FileInfo, _ error) error { 284 // capture only .sia files 285 if filepath.Ext(path) != ".sia" { 286 return nil 287 } 288 rel, _ := filepath.Rel(rt.renter.persistDir, path) // strip testdir prefix 289 walkStr += rel 290 return nil 291 }) 292 // walk will descend into foo/bar/, reading baz, bar, and finally foo 293 expWalkStr := (f3.name + ".sia") + (f2.name + ".sia") + (f1.name + ".sia") 294 if filepath.ToSlash(walkStr) != expWalkStr { 295 t.Fatalf("Bad walk string: expected %v, got %v", expWalkStr, walkStr) 296 } 297 } 298 299 // TestSiafileCompatibility tests that the renter is able to load v0.4.8 .sia files. 300 func TestSiafileCompatibility(t *testing.T) { 301 if testing.Short() { 302 t.SkipNow() 303 } 304 rt, err := newRenterTester(t.Name()) 305 if err != nil { 306 t.Fatal(err) 307 } 308 defer rt.Close() 309 310 // Load the compatibility file into the renter. 311 path := filepath.Join("..", "..", "compatibility", "siafile_v0.4.8.sia") 312 names, err := rt.renter.LoadSharedFiles(path) 313 if err != nil { 314 t.Fatal(err) 315 } 316 if len(names) != 1 || names[0] != "testfile-183" { 317 t.Fatal("nickname not loaded properly:", names) 318 } 319 }