gitlab.com/SkynetLabs/skyd@v1.6.9/skymodules/renter/filesystem/siafile/persist_compat_test.go (about) 1 package siafile 2 3 import ( 4 "fmt" 5 "testing" 6 7 "gitlab.com/NebulousLabs/errors" 8 "go.sia.tech/siad/crypto" 9 "go.sia.tech/siad/modules" 10 "go.sia.tech/siad/types" 11 ) 12 13 // TestMetadataCompatCheck probes the metadataCompatCheck method 14 func TestMetadataCompatCheck(t *testing.T) { 15 if testing.Short() { 16 t.SkipNow() 17 } 18 t.Parallel() 19 20 t.Run("NilMetadataToV1", testUpgradeNilMetadataToV1) 21 t.Run("V1MetadataToV2", testUpgradeV1MetadataToV2) 22 t.Run("V2MetadataToV3", testUpgradeV2MetadataToV3) 23 } 24 25 // testUpgradeNilMetadataToV1 tests the compat code related to upgrading from a 26 // nilMetadataVerion to metadataVersion1 27 func testUpgradeNilMetadataToV1(t *testing.T) { 28 t.Parallel() 29 t.Run("UniqueIDMissing", testUniqueIDMissing) 30 t.Run("ZeroByteFile", testZeroByteFileCompat) 31 } 32 33 // testUpgradeV1MetadataToV2 tests the compat code related to upgrading from a 34 // metadataVersion1 to metadataVersion2 35 func testUpgradeV1MetadataToV2(t *testing.T) { 36 t.Parallel() 37 38 // Create siafile 39 sf := newBlankTestFile() 40 41 // Add a piece to the file so that it shows uploaded bytes 42 err := sf.AddPiece(types.SiaPublicKey{}, uint64(0), 0, crypto.Hash{}) 43 if err != nil { 44 t.Fatal(err) 45 } 46 47 // Assert test conditions 48 _, unique, err := sf.uploadedBytes() 49 if err != nil { 50 t.Fatal(err) 51 } 52 if unique != modules.SectorSize { 53 t.Fatal("unique not expected", unique) 54 } 55 56 // check checks the metadata 57 check := func(sf *SiaFile, finished, stuck bool, version [16]byte) error { 58 // Version check 59 if sf.staticMetadata.StaticVersion != version { 60 return fmt.Errorf("Wrong version, expected %v got %v", version, sf.staticMetadata.StaticVersion) 61 } 62 63 // Check Stuck 64 isStuck := sf.staticMetadata.NumStuckChunks > 0 65 if stuck != isStuck { 66 return fmt.Errorf("Expected stuck %v, got stuck %v", stuck, isStuck) 67 } 68 69 // Check finished 70 if finished != sf.finished() { 71 return fmt.Errorf("Expected finished %v, got finished %v", finished, sf.finished()) 72 } 73 return nil 74 } 75 76 // reset resets the metadata 77 reset := func(sf *SiaFile, finished, stuck, localPath bool) { 78 // Reset version and finished flag 79 sf.staticMetadata.StaticVersion = metadataVersion1 80 sf.staticMetadata.Finished = false 81 82 // Set the expected stuck state 83 if stuck { 84 sf.staticMetadata.NumStuckChunks = 1 85 } else { 86 sf.staticMetadata.NumStuckChunks = 0 87 } 88 89 // Set the expected finished state 90 if finished { 91 sf.staticMetadata.FileSize = 1 92 } else { 93 sf.staticMetadata.FileSize = int64(modules.SectorSize) + 1 94 } 95 96 // Set the localPath 97 if localPath { 98 sf.staticMetadata.LocalPath = "localpath" 99 } else { 100 sf.staticMetadata.LocalPath = "" 101 } 102 } 103 104 // Define tests 105 var tests = []struct { 106 name string 107 108 finished bool 109 stuck bool 110 111 localPath bool 112 }{ 113 // With Local Path 114 // 115 // Test for finished stuck 116 {"Finished_Stuck", true, true, true}, 117 // Test for unfinished stuck 118 {"Unfinished_Stuck", false, true, true}, 119 // Test for finished unstuck 120 {"Finished_Unstuck", true, false, true}, 121 // Test for unfinished unstuck 122 {"Unfinished_Unstuck", false, false, true}, 123 // Without Local Path 124 // 125 // Test for finished stuck 126 {"Finished_Stuck", true, true, false}, 127 // Test for unfinished stuck 128 {"Unfinished_Stuck", false, true, false}, 129 // Test for finished unstuck 130 {"Finished_Unstuck", true, false, false}, 131 // Test for unfinished unstuck 132 {"Unfinished_Unstuck", false, false, false}, 133 } 134 135 // Run tests 136 for _, test := range tests { 137 // A file is considered finished if it finished or has a localpath 138 finished := test.finished || test.localPath 139 140 // At the end of the compat, the file should only be stuck if it 141 // was originally finished or has a localpath, and is stuck. 142 stuck := finished && test.stuck 143 144 // Reset the metadata 145 reset(sf, test.finished, test.stuck, test.localPath) 146 147 // test testUpgradeV1MetadataToV2 148 err = sf.upgradeMetadataFromV1ToV2() 149 if err != nil { 150 t.Fatal(test, err) 151 } 152 153 // Check the metadata 154 err = check(sf, finished, stuck, metadataVersion2) 155 if err != nil { 156 t.Fatal(test, err) 157 } 158 159 // Reset the metadata 160 reset(sf, test.finished, test.stuck, test.localPath) 161 162 // Save the metadata to disk 163 err = sf.SaveMetadata() 164 if err != nil { 165 t.Fatal(test, err) 166 } 167 168 // Reload the SiaFile from disk 169 sf, err = LoadSiaFile(sf.siaFilePath, sf.wal) 170 if err != nil { 171 t.Fatal(test, err) 172 } 173 174 // Check the metadata 175 // 176 // Update for MetadateVersion3, all cases should now be 177 // !finished and !stuck 178 err = check(sf, false, false, metadataVersion) 179 if err != nil { 180 t.Fatal(test, err) 181 } 182 } 183 } 184 185 // testUpgradeV2MetadataToV3 tests the compat code related to upgrading from a 186 // metadataVersion2 to metadataVersion3 187 func testUpgradeV2MetadataToV3(t *testing.T) { 188 t.Parallel() 189 190 // Create siafile 191 sf := newBlankTestFile() 192 193 // check checks the metadata 194 check := func(sf *SiaFile, version [16]byte) error { 195 // Version check 196 if sf.staticMetadata.StaticVersion != version { 197 return fmt.Errorf("Wrong version, expected %v got %v", version, sf.staticMetadata.StaticVersion) 198 } 199 200 // Check Stuck 201 if sf.staticMetadata.NumStuckChunks > 0 { 202 return fmt.Errorf("File should not be stuck %v", sf.staticMetadata.NumStuckChunks) 203 } 204 205 // Check finished 206 if sf.finished() { 207 return errors.New("file should not be finished") 208 } 209 return nil 210 } 211 212 // reset resets the metadata 213 reset := func(sf *SiaFile, finished, stuck bool) { 214 // Reset version and finished flag 215 sf.staticMetadata.StaticVersion = metadataVersion2 216 sf.staticMetadata.Finished = finished 217 218 // Set the expected stuck state 219 if stuck { 220 sf.staticMetadata.NumStuckChunks = 1 221 } else { 222 sf.staticMetadata.NumStuckChunks = 0 223 } 224 } 225 226 // Define tests 227 var tests = []struct { 228 name string 229 230 finished bool 231 stuck bool 232 }{ 233 // Test for finished stuck 234 {"Finished_Stuck", true, true}, 235 // Test for unfinished stuck 236 {"Unfinished_Stuck", false, true}, 237 // Test for finished unstuck 238 {"Finished_Unstuck", true, false}, 239 // Test for unfinished unstuck 240 {"Unfinished_Unstuck", false, false}, 241 } 242 243 // Run tests 244 for _, test := range tests { 245 // Reset the metadata 246 reset(sf, test.finished, test.stuck) 247 248 // test testUpgradeV2MetadataToV3 249 err := sf.upgradeMetadataFromV2ToV3() 250 if err != nil { 251 t.Fatal(test, err) 252 } 253 254 // Check the metadata 255 err = check(sf, metadataVersion3) 256 if err != nil { 257 t.Fatal(test, err) 258 } 259 260 // Reset the metadata 261 reset(sf, test.finished, test.stuck) 262 263 // Save the metadata to disk 264 err = sf.SaveMetadata() 265 if err != nil { 266 t.Fatal(test, err) 267 } 268 269 // Reload the SiaFile from disk 270 sf, err = LoadSiaFile(sf.siaFilePath, sf.wal) 271 if err != nil { 272 t.Fatal(test, err) 273 } 274 275 // Check the metadata 276 err = check(sf, metadataVersion) 277 if err != nil { 278 t.Fatal(test, err) 279 } 280 } 281 } 282 283 // testUniqueIDMissing makes sure that loading a siafile sets the unique id in 284 // the metadata if it wasn't set before. 285 func testUniqueIDMissing(t *testing.T) { 286 // Create a new file. 287 sf, wal, _ := newBlankTestFileAndWAL(1) 288 // It should have a UID. 289 if sf.staticMetadata.UniqueID == "" { 290 t.Fatal("unique ID wasn't set") 291 } 292 293 // check checks the metadata 294 check := func(sf *SiaFile, version [16]byte) error { 295 // It should have a UID now. 296 if sf.staticMetadata.UniqueID == "" { 297 return errors.New("unique ID still blank") 298 } 299 300 // Check Version 301 if sf.staticMetadata.StaticVersion != version { 302 return fmt.Errorf("Wrong version, expected %v got %v", version, sf.staticMetadata.StaticVersion) 303 } 304 return nil 305 } 306 307 // reset resets the metadata 308 reset := func(sf *SiaFile) { 309 // Set the UID to a blank string, and reset the metadata version 310 sf.staticMetadata.UniqueID = "" 311 sf.staticMetadata.StaticVersion = nilMetadataVesion 312 } 313 314 // Reset the metadata 315 reset(sf) 316 317 // Test upgradeMetadataFromNilToV1 318 sf.upgradeMetadataFromNilToV1() 319 320 // Check 321 err := check(sf, metadataVersion1) 322 if err != nil { 323 t.Fatal(err) 324 } 325 326 // Reset the metadata 327 reset(sf) 328 329 // Save the metadata to disk 330 err = sf.SaveMetadata() 331 if err != nil { 332 t.Fatal(err) 333 } 334 335 // Load the file again. 336 sf, err = LoadSiaFile(sf.siaFilePath, wal) 337 if err != nil { 338 t.Fatal(err) 339 } 340 341 // Check 342 err = check(sf, metadataVersion) 343 if err != nil { 344 t.Fatal(err) 345 } 346 } 347 348 // testZeroByteFileCompat checks that 0-byte siafiles that have been uploaded 349 // before caching was introduced have the correct cached values after being 350 // loaded. 351 func testZeroByteFileCompat(t *testing.T) { 352 // Create the file. 353 siaFilePath, _, source, rc, sk, _, _, fileMode := newTestFileParams(1, true) 354 sf, wal, _ := customTestFileAndWAL(siaFilePath, source, rc, sk, 0, 0, fileMode) 355 // Check that the number of chunks in the file is correct. 356 if sf.numChunks != 0 { 357 panic(fmt.Sprintf("newTestFile didn't create the expected number of chunks: %v", sf.numChunks)) 358 } 359 360 expectedRedundancy := float64(rc.NumPieces()) / float64(rc.MinPieces()) 361 // check checks the metadata 362 check := func(sf *SiaFile, version [16]byte) error { 363 // Make sure the loaded file has the correct cached values. 364 if sf.staticMetadata.CachedHealth != 0 { 365 return fmt.Errorf("CachedHealth should be 0 but was %v", sf.staticMetadata.CachedHealth) 366 } 367 if sf.staticMetadata.CachedRedundancy != expectedRedundancy { 368 return fmt.Errorf("CachedRedundancy should be %v but was %v", expectedRedundancy, sf.staticMetadata.CachedRedundancy) 369 } 370 if sf.staticMetadata.CachedRepairBytes != 0 { 371 return fmt.Errorf("CachedRepairBytes should be 0 but was %v", sf.staticMetadata.CachedRepairBytes) 372 } 373 if sf.staticMetadata.CachedStuckBytes != 0 { 374 return fmt.Errorf("CachedStuckBytes should be 0 but was %v", sf.staticMetadata.CachedStuckBytes) 375 } 376 if sf.staticMetadata.CachedStuckHealth != 0 { 377 return fmt.Errorf("CachedStuckHealth should be 0 but was %v", sf.staticMetadata.CachedStuckHealth) 378 } 379 if sf.staticMetadata.CachedUserRedundancy != expectedRedundancy { 380 return fmt.Errorf("CachedRedundancy should be %v but was %v", expectedRedundancy, sf.staticMetadata.CachedUserRedundancy) 381 } 382 if sf.staticMetadata.CachedUploadProgress != 100 { 383 return fmt.Errorf("CachedUploadProgress should be 100 but was %v", sf.staticMetadata.CachedUploadProgress) 384 } 385 // Check Version 386 if sf.staticMetadata.StaticVersion != version { 387 return fmt.Errorf("Wrong version, expected %v got %v", version, sf.staticMetadata.StaticVersion) 388 } 389 return nil 390 } 391 392 // reset resets the metadata 393 reset := func(sf *SiaFile) { 394 // Set the cached fields and version to 0 like they would be if the file 395 // was already uploaded before caching was introduced. 396 sf.staticMetadata.StaticVersion = nilMetadataVesion 397 sf.staticMetadata.CachedHealth = 0 398 sf.staticMetadata.CachedRedundancy = 0 399 sf.staticMetadata.CachedRepairBytes = 0 400 sf.staticMetadata.CachedStuckBytes = 0 401 sf.staticMetadata.CachedStuckHealth = 0 402 sf.staticMetadata.CachedUserRedundancy = 0 403 sf.staticMetadata.CachedUploadProgress = 0 404 } 405 406 // Reset the metadata to pre compat state 407 reset(sf) 408 409 // test upgradeMetadataFromNilToV1 410 sf.upgradeMetadataFromNilToV1() 411 412 // Check the Metadata 413 err := check(sf, metadataVersion1) 414 if err != nil { 415 t.Fatal(err) 416 } 417 418 // Reset the metadata to pre compat state 419 reset(sf) 420 421 // Save the file and reload it. 422 if err := sf.SaveMetadata(); err != nil { 423 t.Fatal(err) 424 } 425 sf, err = loadSiaFile(siaFilePath, wal, modules.ProdDependencies) 426 if err != nil { 427 t.Fatal(err) 428 } 429 430 // Check the Metadata 431 err = check(sf, metadataVersion) 432 if err != nil { 433 t.Fatal(err) 434 } 435 }