github.com/rohankumardubey/proxyfs@v0.0.0-20210108201508-653efa9ab00e/inode/file_extent_test.go (about) 1 package inode 2 3 import ( 4 "bytes" 5 cryptoRand "crypto/rand" 6 "fmt" 7 "math/big" 8 mathRand "math/rand" 9 "testing" 10 11 "github.com/swiftstack/sortedmap" 12 ) 13 14 const ( 15 sizeOfTestFile uint64 = 0x01000000 // 16 MiB 16 maxExtentLength uint64 = 0x00001000 // 4 KiB 17 numExtentOverwrites uint64 = 0x00001000 // 4 Ki 18 numZeroLengthReads uint64 = 0x00001000 // 4 Ki 19 20 pseudoRandom = false 21 pseudoRandomSeed = int64(0) 22 ) 23 24 var ( 25 randSource *mathRand.Rand // A source for pseudo-random numbers (if selected) 26 inMemoryFileInodeContents []byte // A value of 0x00 means the byte has never been written 27 byteToWrite = byte(0x01) // Incremented for each write, wrapping from 0xFF to 0x01 per above 28 curExtentOverwrites = uint64(0) // During write phase, loop until == numExtentOverwrites 29 curFileSize = uint64(0) // Tracks the highest offset actually written 30 ) 31 32 func testChooseUint64(t *testing.T, mustBeLessThan uint64) (u64 uint64) { 33 if pseudoRandom { 34 if nil == randSource { 35 randSource = mathRand.New(mathRand.NewSource(pseudoRandomSeed)) 36 } 37 38 u64 = uint64(randSource.Int63n(int64(mustBeLessThan))) 39 } else { 40 mustBeLessThanBigIntPtr := big.NewInt(int64(mustBeLessThan)) 41 u64BigIntPtr, err := cryptoRand.Int(cryptoRand.Reader, mustBeLessThanBigIntPtr) 42 if nil != err { 43 t.Fatalf("rand.Int(rand.Reader, mustBeLessThanBigIntPtr) returned error == \"%v\"", err) 44 } 45 46 u64 = u64BigIntPtr.Uint64() 47 } 48 49 return 50 } 51 52 func testChooseExtentStart(t *testing.T) (offset uint64) { 53 offset = testChooseUint64(t, sizeOfTestFile) 54 55 return 56 } 57 58 func testChooseExtentSize(t *testing.T) (length uint64) { 59 length = testChooseUint64(t, maxExtentLength) + 1 60 61 return 62 } 63 64 func testChooseExtent(t *testing.T) (offset uint64, length uint64) { 65 offset = testChooseExtentStart(t) 66 length = testChooseExtentSize(t) 67 68 if (offset + length) > sizeOfTestFile { 69 length = sizeOfTestFile - offset 70 } 71 72 return 73 } 74 75 func testPopulateFileInode(t *testing.T, testVolumeHandle VolumeHandle, fileInodeNumber InodeNumber) { 76 for curExtentOverwrites < numExtentOverwrites { 77 offset, length := testChooseExtent(t) 78 79 overwriteOccurred := false 80 81 for i := offset; i < (offset + length); i++ { 82 if byte(0x00) != inMemoryFileInodeContents[i] { 83 overwriteOccurred = true 84 } 85 86 inMemoryFileInodeContents[i] = byteToWrite 87 } 88 if overwriteOccurred { 89 curExtentOverwrites++ 90 } 91 92 err := testVolumeHandle.Write(fileInodeNumber, offset, inMemoryFileInodeContents[offset:(offset+length)], nil) 93 if nil != err { 94 t.Fatalf("Write(fileInodeNumber, offset, inMemoryFileInodeContents[offset:(offset+length)]) failed: %v", err) 95 } 96 97 if (offset + length) > curFileSize { 98 curFileSize = offset + length 99 } 100 101 if byte(0xFF) == byteToWrite { 102 byteToWrite = byte(0x01) 103 } else { 104 byteToWrite++ 105 } 106 } 107 } 108 109 func testValidateFileInodeBPlusTree(t *testing.T, testVolumeHandle VolumeHandle, fileInodeNumber InodeNumber) { 110 // Fetch actual fileInode 111 112 fileInode, err := (testVolumeHandle.(*volumeStruct)).fetchInodeType(fileInodeNumber, FileType) 113 if nil != err { 114 t.Fatalf("testVolumeHandle.fetchInodeType(fileInodeNumber, FileType) failed: %v", err) 115 } 116 117 // Fetch extents B+Tree 118 119 extents := fileInode.payload.(sortedmap.BPlusTree) 120 extentsLen, err := extents.Len() 121 if nil != err { 122 t.Fatalf("extents.Len() failed: %v", err) 123 } 124 125 // Walk extents B+Tree (by index) ensuring coherence with: 126 // 1 - All keys (fileOffset) are monotonically increasing 127 // 2 - All keys agree with the fileOffset field of their values 128 // 3 - All values (extents) don't overlap 129 // 4 - GetByKey(fileOffset) returns the same extent 130 131 if 0 == extentsLen { 132 return 133 } 134 135 var lastExtentTerminationFileOffset uint64 136 137 for extentIndex := 0; extentIndex < extentsLen; extentIndex++ { 138 // Fetch current extent 139 keyByIndex, valueByIndex, ok, err := extents.GetByIndex(extentIndex) 140 if nil != err { 141 t.Fatalf("extents.GetByIndex(extentIndex) failed: %v", err) 142 } 143 if !ok { 144 err = fmt.Errorf("extents.GetByIndex(extentIndex) unexpectedly returned !ok") 145 t.Fatalf(err.Error()) 146 } 147 fileOffsetByIndex, ok := keyByIndex.(uint64) 148 if !ok { 149 err = fmt.Errorf("keyByIndex.(uint64) unexpectedly returned !ok") 150 t.Fatalf(err.Error()) 151 } 152 extentByIndex, ok := valueByIndex.(*fileExtentStruct) 153 if !ok { 154 err = fmt.Errorf("valueByIndex.(*fileExtent) unexpectedly returned !ok") 155 t.Fatalf(err.Error()) 156 } 157 158 // Validate extent 159 if fileOffsetByIndex != extentByIndex.FileOffset { 160 err = fmt.Errorf("fileOffsetByIndex != extentByIndex.fileOffset") 161 t.Fatalf(err.Error()) 162 } 163 if 0 == extentByIndex.Length { 164 err = fmt.Errorf("0 == extentByIndex.length") 165 t.Fatalf(err.Error()) 166 } 167 168 valueByKey, ok, err := extents.GetByKey(fileOffsetByIndex) 169 if nil != err { 170 t.Fatalf("extents.GetByKey(fileOffsetByIndex) failed: %v", err) 171 } 172 if !ok { 173 err = fmt.Errorf("extents.GetByKey(fileOffsetByIndex) unexpectedly returned !ok") 174 t.Fatalf(err.Error()) 175 } 176 extentByKey, ok := valueByKey.(*fileExtentStruct) 177 if !ok { 178 err = fmt.Errorf("valueByKey.(*fileExtent) unexpectedly returned !ok") 179 t.Fatalf(err.Error()) 180 } 181 if fileOffsetByIndex != extentByKey.FileOffset { 182 err = fmt.Errorf("fileOffsetByIndex != extentByKey.fileOffset") 183 t.Fatalf(err.Error()) 184 } 185 186 if 0 < extentIndex { 187 // Ensure this extent strictly follows prior extent 188 if lastExtentTerminationFileOffset > fileOffsetByIndex { 189 err = fmt.Errorf("(lastExtentFileOffset + lastExtentLength) > fileOffsetByIndex") 190 t.Fatalf(err.Error()) 191 } 192 } 193 194 // Save this extent's lastExtentTerminationFileOffset for next iteration 195 lastExtentTerminationFileOffset = fileOffsetByIndex + extentByIndex.Length 196 } 197 198 // If we reach here, extents is valid 199 } 200 201 func testVerifyFileInodeBPlusTree(t *testing.T, testVolumeHandle VolumeHandle, fileInodeNumber InodeNumber) { 202 // Fetch actual fileInode 203 204 fileInode, err := (testVolumeHandle.(*volumeStruct)).fetchInodeType(fileInodeNumber, FileType) 205 if nil != err { 206 t.Fatalf("testVolumeHandle.fetchInodeType(fileInodeNumber, FileType) failed: %v", err) 207 } 208 209 // Fetch extents B+Tree 210 211 extents := fileInode.payload.(sortedmap.BPlusTree) 212 extentsLen, err := extents.Len() 213 if nil != err { 214 t.Fatalf("extents.Len() failed: %v", err) 215 } 216 217 if 0 == extentsLen { 218 // Verify entire inMemoryFileInodeContents is all zeroes 219 for _, byteValue := range inMemoryFileInodeContents { 220 if 0 != byteValue { 221 err = fmt.Errorf("0 != byteValue [case 1]") 222 t.Fatalf(err.Error()) 223 } 224 } 225 226 // If we reach here, inMemoryFileInodeContents was all zeroes and (this trivial) extents is verified 227 return 228 } 229 230 var lastExtentTerminationFileOffset uint64 231 232 for extentIndex := 0; extentIndex < extentsLen; extentIndex++ { 233 // Fetch current extent 234 key, value, ok, err := extents.GetByIndex(extentIndex) 235 if nil != err { 236 t.Fatalf("extents.GetByIndex(extentIndex) failed: %v", err) 237 } 238 if !ok { 239 err = fmt.Errorf("extents.GetByIndex(extentIndex) unexpectedly returned !ok") 240 t.Fatalf(err.Error()) 241 } 242 fileOffset, ok := key.(uint64) 243 if !ok { 244 err = fmt.Errorf("key.(uint64) unexpectedly returned !ok") 245 t.Fatalf(err.Error()) 246 } 247 extent, ok := value.(*fileExtentStruct) 248 if !ok { 249 err = fmt.Errorf("value.(*fileExtent) unexpectedly returned !ok") 250 t.Fatalf(err.Error()) 251 } 252 253 // Verify preceeding hole (if any) in extents matches all zeroes in inMemoryFileInodeContents 254 for _, byteValue := range inMemoryFileInodeContents[lastExtentTerminationFileOffset:fileOffset] { 255 if 0 != byteValue { 256 err = fmt.Errorf("0 != byteValue [case 2]") 257 t.Fatalf(err.Error()) 258 } 259 } 260 261 // Update lastExtentTerminationFileOffset for next iteration but used for non-zero check below as well 262 lastExtentTerminationFileOffset = fileOffset + extent.Length 263 264 // Verify extent matches non-zeroes in inMemoryFileInodeContents 265 for _, byteValue := range inMemoryFileInodeContents[fileOffset:lastExtentTerminationFileOffset] { 266 if 0 == byteValue { 267 err = fmt.Errorf("0 == byteValue") 268 t.Fatalf(err.Error()) 269 } 270 } 271 } 272 273 // Verify inMemoryFileInodeContents agrees that lastExtentTerminationFileOffset is EOF 274 for _, byteValue := range inMemoryFileInodeContents[lastExtentTerminationFileOffset:] { 275 if 0 != byteValue { 276 err = fmt.Errorf("0 != byteValue [case 3]") 277 t.Fatalf(err.Error()) 278 } 279 } 280 281 // If we reach here, extents is verified 282 } 283 284 func testCondenseByteSlice(buf []byte) (condensedString string) { 285 type countValueTupleStruct struct { 286 count uint64 287 value byte 288 } 289 290 var countValueTupleSlice []*countValueTupleStruct 291 292 for _, value := range buf { 293 countValueTupleSliceLen := len(countValueTupleSlice) 294 if (0 == countValueTupleSliceLen) || (value != countValueTupleSlice[countValueTupleSliceLen-1].value) { 295 countValueTupleSlice = append(countValueTupleSlice, &countValueTupleStruct{count: 1, value: value}) 296 } else { 297 countValueTupleSlice[countValueTupleSliceLen-1].count++ 298 } 299 } 300 301 var condensedByteSlice []byte 302 303 condensedByteSlice = append(condensedByteSlice, '[') 304 305 for countValueTupleIndex, countValueTuple := range countValueTupleSlice { 306 if 0 < countValueTupleIndex { 307 condensedByteSlice = append(condensedByteSlice, ',', ' ') 308 } 309 310 valueAsString := fmt.Sprintf("0x%02x", countValueTuple.value) 311 312 if 1 == countValueTuple.count { 313 condensedByteSlice = append(condensedByteSlice, []byte(valueAsString)...) 314 } else { 315 countAsString := fmt.Sprintf("0x%x", countValueTuple.count) 316 condensedByteSlice = append(condensedByteSlice, []byte(countAsString+"("+valueAsString+")")...) 317 } 318 } 319 320 condensedByteSlice = append(condensedByteSlice, ']') 321 322 condensedString = string(condensedByteSlice[:]) 323 324 return 325 } 326 327 func testVerifyFileInodeContents(t *testing.T, testVolumeHandle VolumeHandle, fileInodeNumber InodeNumber) { 328 // Verify written sections of fileInode match inMemoryFileInodeContents (i.e. non-0x00 bytes all match) 329 330 offset := uint64(0) 331 length := uint64(0) 332 currentlyScanningWrittenBytes := false 333 334 for (offset + length) < curFileSize { 335 if currentlyScanningWrittenBytes { 336 if byte(0x00) == inMemoryFileInodeContents[offset+length] { 337 readBuf, err := testVolumeHandle.Read(fileInodeNumber, offset, length, nil) 338 if nil != err { 339 t.Fatalf("Read(fileInodeNumber, offset, length) [case 1] failed: %v", err) 340 } 341 342 if bytes.Compare(readBuf, inMemoryFileInodeContents[offset:(offset+length)]) != 0 { 343 t.Fatalf("Read(fileInodeNumber, offset, length) [case 1] returned unexpected []byte:\n expected %v\n got %v", testCondenseByteSlice(inMemoryFileInodeContents[offset:(offset+length)]), testCondenseByteSlice(readBuf)) 344 } 345 346 offset += length 347 length = uint64(0) 348 currentlyScanningWrittenBytes = false 349 } else { 350 length++ 351 } 352 } else { 353 if byte(0x00) == inMemoryFileInodeContents[offset+length] { 354 offset++ 355 } else { 356 length = uint64(1) 357 currentlyScanningWrittenBytes = true 358 } 359 } 360 } 361 362 if currentlyScanningWrittenBytes { 363 readBuf, err := testVolumeHandle.Read(fileInodeNumber, offset, length, nil) 364 if nil != err { 365 t.Fatalf("Read(fileInodeNumber, offset, length) [case 2] failed: %v", err) 366 } 367 368 if 0 != bytes.Compare(readBuf, inMemoryFileInodeContents[offset:(offset+length)]) { 369 t.Fatalf("Read(fileInodeNumber, offset, length) [case 2] returned unexpected []byte:\n expected %v\n got %v", testCondenseByteSlice(inMemoryFileInodeContents[offset:(offset+length)]), testCondenseByteSlice(readBuf)) 370 } 371 } 372 373 // Walk through entire fileInode verifying entire inMemoryFileInodeContents 374 375 offset = uint64(0) 376 377 for offset < curFileSize { 378 length = testChooseExtentSize(t) 379 380 if offset+length > curFileSize { 381 length = curFileSize - offset 382 } 383 384 readBuf, err := testVolumeHandle.Read(fileInodeNumber, offset, length, nil) 385 if nil != err { 386 t.Fatalf("Read(fileInodeNumber, offset, length) [case 3] failed: %v", err) 387 } 388 389 if 0 != bytes.Compare(readBuf, inMemoryFileInodeContents[offset:(offset+length)]) { 390 t.Fatalf("Read(fileInodeNumber, offset, length) [case 3] returned unexpected []byte:\n expected %v\n got %v", testCondenseByteSlice(inMemoryFileInodeContents[offset:(offset+length)]), testCondenseByteSlice(readBuf)) 391 } 392 393 offset += length 394 } 395 396 // Issue numZeroLengthReads zero-length reads using both Read() & GetReadPlan() for likely valid offsets 397 398 length = uint64(0) 399 400 for i := uint64(0); i < numZeroLengthReads; i++ { 401 offset = testChooseExtentStart(t) 402 403 readBuf, err := testVolumeHandle.Read(fileInodeNumber, offset, length, nil) 404 if nil != err { 405 t.Fatalf("Read(fileInodeNumber, offset, length) [case 4] failed: %v", err) 406 } 407 408 if 0 != len(readBuf) { 409 t.Fatalf("Read(fileInodeNumber, offset, length) [case 4] returned unexpected []byte:\n expected %v\n got %v", testCondenseByteSlice(inMemoryFileInodeContents[offset:(offset+length)]), testCondenseByteSlice(readBuf)) 410 } 411 412 readPlan, err := testVolumeHandle.GetReadPlan(fileInodeNumber, &offset, &length) 413 if nil != err { 414 t.Fatalf("GetReadPlan(fileInodeNumber, offset, length) [case 4] failed: %v", err) 415 } 416 417 if 0 != len(readPlan) { 418 t.Fatalf("Read(fileInodeNumber, offset, length) [case 4] returned unexpected readPlan of length %v", len(readPlan)) 419 } 420 } 421 422 // Issue numZeroLengthReads zero-length reads using both Read() & GetReadPlan() for definitely invalid offsets 423 424 length = uint64(0) 425 426 for i := uint64(0); i < numZeroLengthReads; i++ { 427 offset = testChooseExtentStart(t) + sizeOfTestFile 428 429 readBuf, err := testVolumeHandle.Read(fileInodeNumber, offset, length, nil) 430 if nil != err { 431 t.Fatalf("Read(fileInodeNumber, offset, length) [case 5] failed: %v", err) 432 } 433 434 if 0 != len(readBuf) { 435 t.Fatalf("Read(fileInodeNumber, offset, length) [case 5] returned unexpected []byte:\n expected %v\n got %v", testCondenseByteSlice(inMemoryFileInodeContents[offset:(offset+length)]), testCondenseByteSlice(readBuf)) 436 } 437 438 readPlan, err := testVolumeHandle.GetReadPlan(fileInodeNumber, &offset, &length) 439 if nil != err { 440 t.Fatalf("GetReadPlan(fileInodeNumber, offset, length) [case 5] failed: %v", err) 441 } 442 443 if 0 != len(readPlan) { 444 t.Fatalf("Read(fileInodeNumber, offset, length) [case 5] returned unexpected readPlan of length %v", len(readPlan)) 445 } 446 } 447 } 448 449 func TestFileExtents(t *testing.T) { 450 testSetup(t, false) 451 452 testVolumeHandle, err := FetchVolumeHandle("TestVolume") 453 if nil != err { 454 t.Fatalf("FetchVolumeHandle(\"TestVolume\") should have worked - got error: %v", err) 455 } 456 457 fileInodeNumber, err := testVolumeHandle.CreateFile(PosixModePerm, 0, 0) 458 if nil != err { 459 t.Fatalf("CreateFile() failed: %v", err) 460 } 461 462 inMemoryFileInodeContents = make([]byte, sizeOfTestFile) // Initially all 0x00... meaning no bytes written 463 464 testPopulateFileInode(t, testVolumeHandle, fileInodeNumber) 465 466 testValidateFileInodeBPlusTree(t, testVolumeHandle, fileInodeNumber) 467 468 testVerifyFileInodeBPlusTree(t, testVolumeHandle, fileInodeNumber) 469 470 // One might expect to be able to call `testVerifyFileInodeContents` here, 471 // but we haven't flushed yet. 472 473 err = testVolumeHandle.Flush(fileInodeNumber, false) 474 if nil != err { 475 t.Fatalf("Flush(fileInodeNumber, false) failed: %v", err) 476 } 477 478 testVerifyFileInodeContents(t, testVolumeHandle, fileInodeNumber) 479 480 err = testVolumeHandle.Purge(fileInodeNumber) 481 if nil != err { 482 t.Fatalf("Purge(fileInodeNumber) [case one] failed: %v", err) 483 } 484 485 testVerifyFileInodeContents(t, testVolumeHandle, fileInodeNumber) 486 487 err = testVolumeHandle.Purge(fileInodeNumber) 488 if nil != err { 489 t.Fatalf("Purge(fileInodeNumber) [case two] failed: %v", err) 490 } 491 492 err = testVolumeHandle.Destroy(fileInodeNumber) 493 if nil != err { 494 t.Fatalf("Destroy(fileInodeNumber) failed: %v", err) 495 } 496 497 testTeardown(t) 498 } 499 500 func TestWriteFileExtentAtExtantOffset(t *testing.T) { 501 testSetup(t, false) 502 503 testVolumeHandle, err := FetchVolumeHandle("TestVolume") 504 if nil != err { 505 t.Fatalf("FetchVolumeHandle(\"TestVolume\") should have worked - got error: %v", err) 506 } 507 508 fileInodeNumber, err := testVolumeHandle.CreateFile(PosixModePerm, 0, 0) 509 if nil != err { 510 t.Fatalf("CreateFile() failed: %v", err) 511 } 512 513 fileInode, ok, err := (testVolumeHandle.(*volumeStruct)).fetchInode(fileInodeNumber) 514 if err != nil { 515 t.Fatalf("testVolumeHandle.fetchInode() failed: %v", err) 516 } 517 if !ok { 518 t.Fatalf("testVolumeHandle.fetchInode() returned a free inode") 519 } 520 521 extents := fileInode.payload.(sortedmap.BPlusTree) 522 523 err = testVolumeHandle.Write(fileInodeNumber, 0, make([]byte, 20), nil) 524 if nil != err { 525 t.Fatalf("Write(fileInodeNumber, 0, make([]byte, 20)) failed: %v", err) 526 } 527 528 err = testVolumeHandle.Write(fileInodeNumber, 5, []byte("aaaa"), nil) // 4 bytes 529 if nil != err { 530 t.Fatalf("Write failed: %v", err) 531 } 532 533 // At this point, our file B+-tree should have three extents starting at 534 // file offsets 0, 5, and 5+4=9. 535 536 expectedOffsets := []uint64{0, 5, 9} 537 expectedLengths := []uint64{5, 4, 11} 538 for i := 0; i < 3; i++ { 539 _, value, ok, err := extents.GetByIndex(i) 540 if nil != err { 541 t.Fatal(err) 542 } 543 extantExtent := value.(*fileExtentStruct) 544 if !ok { 545 t.Fatalf("expected to be able to get extent") 546 } 547 if expectedOffsets[i] != extantExtent.FileOffset { 548 t.Fatalf("expected extent to be at offset %v, got %v", expectedOffsets[i], extantExtent.FileOffset) 549 } 550 if expectedLengths[i] != extantExtent.Length { 551 t.Fatalf("expected extent length %v, got %v", expectedLengths[i], extantExtent.Length) 552 } 553 } 554 555 err = testVolumeHandle.Write(fileInodeNumber, 9, []byte("bbb"), nil) 556 if nil != err { 557 t.Fatalf("Overwrite failed: %v", err) 558 } 559 560 err = testVolumeHandle.Flush(fileInodeNumber, false) 561 if nil != err { 562 t.Fatalf("Flush failed: %v", err) 563 } 564 565 testTeardown(t) 566 } 567 568 func TestOverwriteIncludesBeginningOfLastExtent(t *testing.T) { 569 testSetup(t, false) 570 571 testVolumeHandle, err := FetchVolumeHandle("TestVolume") 572 if nil != err { 573 t.Fatalf("FetchVolumeHandle(\"TestVolume\") should have worked - got error: %v", err) 574 } 575 576 fileInodeNumber, err := testVolumeHandle.CreateFile(PosixModePerm, 0, 0) 577 if nil != err { 578 t.Fatalf("CreateFile() failed: %v", err) 579 } 580 581 err = testVolumeHandle.Write(fileInodeNumber, 0, make([]byte, 20), nil) 582 if nil != err { 583 t.Fatalf("Write(fileInodeNumber, 0, make([]byte, 20)) failed: %v", err) 584 } 585 586 err = testVolumeHandle.Write(fileInodeNumber, 5, []byte("aaaa"), nil) // 4 bytes 587 if nil != err { 588 t.Fatalf("Write failed: %v", err) 589 } 590 591 err = testVolumeHandle.Write(fileInodeNumber, 3, []byte("bbbbbbbbbb"), nil) 592 if nil != err { 593 t.Fatalf("Write failed: %v", err) 594 } 595 596 err = testVolumeHandle.Flush(fileInodeNumber, false) 597 if nil != err { 598 t.Fatalf("Flush failed: %v", err) 599 } 600 601 testTeardown(t) 602 } 603 604 func TestReadYourWrite(t *testing.T) { 605 testSetup(t, false) 606 607 testVolumeHandle, err := FetchVolumeHandle("TestVolume") 608 if nil != err { 609 t.Fatalf("FetchVolumeHandle(\"TestVolume\") should have worked - got error: %v", err) 610 } 611 612 fileInodeNumber, err := testVolumeHandle.CreateFile(PosixModePerm, 0, 0) 613 if nil != err { 614 t.Fatalf("CreateFile() failed: %v", err) 615 } 616 617 ourBytes := []byte{1, 2, 3, 4, 5, 6, 7, 8} 618 err = testVolumeHandle.Write(fileInodeNumber, 0, ourBytes, nil) 619 if nil != err { 620 t.Fatalf("Write(fileInodeNumber, 0, []byte{1, 2, 3, 4, 5, 6, 7, 8}) failed: %v", err) 621 } 622 readBuf, err := testVolumeHandle.Read(fileInodeNumber, 0, 8, nil) 623 if err != nil { 624 t.Fatalf("Read(fileInodeNumber, 0, 8) failed: %v", err) 625 } 626 627 if bytes.Compare(ourBytes, readBuf) != 0 { 628 t.Fatalf("read after write didn't work: expected %v, got %v", ourBytes, readBuf) 629 } 630 631 err = testVolumeHandle.Flush(fileInodeNumber, false) 632 if nil != err { 633 t.Fatalf("Flush failed: %v", err) 634 } 635 636 testTeardown(t) 637 }