13 // A TestableVolumeFactory returns a new TestableVolume. The factory
14 // function, and the TestableVolume it returns, can use "t" to write
15 // logs, fail the current test, etc.
16 type TestableVolumeFactory func(t *testing.T) TestableVolume
18 // DoGenericVolumeTests runs a set of tests that every TestableVolume
19 // is expected to pass. It calls factory to create a new TestableVolume
20 // for each test case, to avoid leaking state between tests.
21 func DoGenericVolumeTests(t *testing.T, factory TestableVolumeFactory) {
23 testGetNoSuchBlock(t, factory)
25 testCompareSameContent(t, factory)
26 testCompareWithDifferentContent(t, factory)
27 testCompareWithBadData(t, factory)
29 testPutBlockWithSameContent(t, factory)
30 testPutBlockWithDifferentContent(t, factory)
31 testPutMultipleBlocks(t, factory)
33 testPutAndTouch(t, factory)
34 testTouchNoSuchBlock(t, factory)
36 testMtimeNoSuchBlock(t, factory)
38 testIndexTo(t, factory)
40 testDeleteNewBlock(t, factory)
41 testDeleteOldBlock(t, factory)
42 testDeleteNoSuchBlock(t, factory)
44 testStatus(t, factory)
46 testString(t, factory)
48 testUpdateReadOnly(t, factory)
50 testGetConcurrent(t, factory)
51 testPutConcurrent(t, factory)
54 // Put a test block, get it and verify content
55 // Test should pass for both writable and read-only volumes
56 func testGet(t *testing.T, factory TestableVolumeFactory) {
60 v.PutRaw(TestHash, TestBlock)
62 buf, err := v.Get(TestHash)
69 if bytes.Compare(buf, TestBlock) != 0 {
70 t.Errorf("expected %s, got %s", string(TestBlock), string(buf))
74 // Invoke get on a block that does not exist in volume; should result in error
75 // Test should pass for both writable and read-only volumes
76 func testGetNoSuchBlock(t *testing.T, factory TestableVolumeFactory) {
80 if _, err := v.Get(TestHash2); err == nil {
81 t.Errorf("Expected error while getting non-existing block %v", TestHash2)
85 // Put a test block and compare the locator with same content
86 // Test should pass for both writable and read-only volumes
87 func testCompareSameContent(t *testing.T, factory TestableVolumeFactory) {
91 v.PutRaw(TestHash, TestBlock)
93 // Compare the block locator with same content
94 err := v.Compare(TestHash, TestBlock)
96 t.Errorf("Got err %q, expected nil", err)
100 // Put a test block and compare the locator with a different content
101 // Expect error due to collision
102 // Test should pass for both writable and read-only volumes
103 func testCompareWithDifferentContent(t *testing.T, factory TestableVolumeFactory) {
107 v.PutRaw(TestHash, TestBlock)
109 // Compare the block locator with different content; collision
110 err := v.Compare(TestHash, []byte("baddata"))
112 t.Errorf("Expected error due to collision")
116 // Put a test block with bad data (hash does not match, but Put does not verify)
117 // Compare the locator with good data whose hash matches with locator
118 // Expect error due to corruption.
119 // Test should pass for both writable and read-only volumes
120 func testCompareWithBadData(t *testing.T, factory TestableVolumeFactory) {
124 v.PutRaw(TestHash, []byte("baddata"))
126 err := v.Compare(TestHash, TestBlock)
128 t.Errorf("Expected error due to corruption")
132 // Put a block and put again with same content
133 // Test is intended for only writable volumes
134 func testPutBlockWithSameContent(t *testing.T, factory TestableVolumeFactory) {
138 if v.Writable() == false {
142 err := v.Put(TestHash, TestBlock)
144 t.Errorf("Got err putting block %q: %q, expected nil", TestBlock, err)
147 err = v.Put(TestHash, TestBlock)
149 t.Errorf("Got err putting block second time %q: %q, expected nil", TestBlock, err)
153 // Put a block and put again with different content
154 // Test is intended for only writable volumes
155 func testPutBlockWithDifferentContent(t *testing.T, factory TestableVolumeFactory) {
159 if v.Writable() == false {
163 err := v.Put(TestHash, TestBlock)
165 t.Errorf("Got err putting block %q: %q, expected nil", TestBlock, err)
168 putErr := v.Put(TestHash, TestBlock2)
169 buf, getErr := v.Get(TestHash)
171 // Put must not return a nil error unless it has
172 // overwritten the existing data.
173 if bytes.Compare(buf, TestBlock2) != 0 {
174 t.Errorf("Put succeeded but Get returned %+v, expected %+v", buf, TestBlock2)
177 // It is permissible for Put to fail, but it must
178 // leave us with either the original data, the new
179 // data, or nothing at all.
180 if getErr == nil && bytes.Compare(buf, TestBlock) != 0 && bytes.Compare(buf, TestBlock2) != 0 {
181 t.Errorf("Put failed but Get returned %+v, which is neither %+v nor %+v", buf, TestBlock, TestBlock2)
189 // Put and get multiple blocks
190 // Test is intended for only writable volumes
191 func testPutMultipleBlocks(t *testing.T, factory TestableVolumeFactory) {
195 if v.Writable() == false {
199 err := v.Put(TestHash, TestBlock)
201 t.Errorf("Got err putting block %q: %q, expected nil", TestBlock, err)
204 err = v.Put(TestHash2, TestBlock2)
206 t.Errorf("Got err putting block %q: %q, expected nil", TestBlock2, err)
209 err = v.Put(TestHash3, TestBlock3)
211 t.Errorf("Got err putting block %q: %q, expected nil", TestBlock3, err)
214 data, err := v.Get(TestHash)
217 } else if bytes.Compare(data, TestBlock) != 0 {
218 t.Errorf("Block present, but content is incorrect: Expected: %v Found: %v", data, TestBlock)
222 data, err = v.Get(TestHash2)
225 } else if bytes.Compare(data, TestBlock2) != 0 {
226 t.Errorf("Block present, but content is incorrect: Expected: %v Found: %v", data, TestBlock2)
230 data, err = v.Get(TestHash3)
233 } else if bytes.Compare(data, TestBlock3) != 0 {
234 t.Errorf("Block present, but content is incorrect: Expected: %v Found: %v", data, TestBlock3)
240 // Test that when applying PUT to a block that already exists,
241 // the block's modification time is updated.
242 // Test is intended for only writable volumes
243 func testPutAndTouch(t *testing.T, factory TestableVolumeFactory) {
247 if v.Writable() == false {
251 if err := v.Put(TestHash, TestBlock); err != nil {
255 // We'll verify { t0 < threshold < t1 }, where t0 is the
256 // existing block's timestamp on disk before Put() and t1 is
257 // its timestamp after Put().
258 threshold := time.Now().Add(-time.Second)
260 // Set the stored block's mtime far enough in the past that we
261 // can see the difference between "timestamp didn't change"
262 // and "timestamp granularity is too low".
263 v.TouchWithDate(TestHash, time.Now().Add(-20*time.Second))
265 // Make sure v.Mtime() agrees the above Utime really worked.
266 if t0, err := v.Mtime(TestHash); err != nil || t0.IsZero() || !t0.Before(threshold) {
267 t.Errorf("Setting mtime failed: %v, %v", t0, err)
270 // Write the same block again.
271 if err := v.Put(TestHash, TestBlock); err != nil {
275 // Verify threshold < t1
276 if t1, err := v.Mtime(TestHash); err != nil {
278 } else if t1.Before(threshold) {
279 t.Errorf("t1 %v should be >= threshold %v after v.Put ", t1, threshold)
283 // Touching a non-existing block should result in error.
284 // Test should pass for both writable and read-only volumes
285 func testTouchNoSuchBlock(t *testing.T, factory TestableVolumeFactory) {
289 if err := v.Touch(TestHash); err == nil {
290 t.Error("Expected error when attempted to touch a non-existing block")
294 // Invoking Mtime on a non-existing block should result in error.
295 // Test should pass for both writable and read-only volumes
296 func testMtimeNoSuchBlock(t *testing.T, factory TestableVolumeFactory) {
300 if _, err := v.Mtime("12345678901234567890123456789012"); err == nil {
301 t.Error("Expected error when updating Mtime on a non-existing block")
305 // Put a few blocks and invoke IndexTo with:
308 // * with no such prefix
309 // Test should pass for both writable and read-only volumes
310 func testIndexTo(t *testing.T, factory TestableVolumeFactory) {
314 v.PutRaw(TestHash, TestBlock)
315 v.PutRaw(TestHash2, TestBlock2)
316 v.PutRaw(TestHash3, TestBlock3)
318 buf := new(bytes.Buffer)
320 indexRows := strings.Split(string(buf.Bytes()), "\n")
321 sort.Strings(indexRows)
322 sortedIndex := strings.Join(indexRows, "\n")
323 m, err := regexp.MatchString(
324 `^\n`+TestHash+`\+\d+ \d+\n`+
325 TestHash3+`\+\d+ \d+\n`+
326 TestHash2+`\+\d+ \d+$`,
331 t.Errorf("Got index %q for empty prefix", sortedIndex)
334 for _, prefix := range []string{"f", "f15", "f15ac"} {
335 buf = new(bytes.Buffer)
336 v.IndexTo(prefix, buf)
338 m, err := regexp.MatchString(`^`+TestHash2+`\+\d+ \d+\n$`, string(buf.Bytes()))
342 t.Errorf("Got index %q for prefix %s", string(buf.Bytes()), prefix)
346 for _, prefix := range []string{"zero", "zip", "zilch"} {
347 buf = new(bytes.Buffer)
348 v.IndexTo(prefix, buf)
350 t.Errorf("Got error on IndexTo with no such prefix %v", err.Error())
351 } else if buf.Len() != 0 {
352 t.Errorf("Expected empty list for IndexTo with no such prefix %s", prefix)
357 // Calling Delete() for a block immediately after writing it (not old enough)
358 // should neither delete the data nor return an error.
359 // Test is intended for only writable volumes
360 func testDeleteNewBlock(t *testing.T, factory TestableVolumeFactory) {
364 if v.Writable() == false {
368 v.Put(TestHash, TestBlock)
370 if err := v.Delete(TestHash); err != nil {
373 data, err := v.Get(TestHash)
376 } else if bytes.Compare(data, TestBlock) != 0 {
377 t.Error("Block still present, but content is incorrect: %+v != %+v", data, TestBlock)
382 // Calling Delete() for a block with a timestamp older than
383 // blob_signature_ttl seconds in the past should delete the data.
384 // Test is intended for only writable volumes
385 func testDeleteOldBlock(t *testing.T, factory TestableVolumeFactory) {
389 if v.Writable() == false {
393 v.Put(TestHash, TestBlock)
394 v.TouchWithDate(TestHash, time.Now().Add(-2*blob_signature_ttl*time.Second))
396 if err := v.Delete(TestHash); err != nil {
399 if _, err := v.Get(TestHash); err == nil || !os.IsNotExist(err) {
400 t.Errorf("os.IsNotExist(%v) should have been true", err.Error())
404 // Calling Delete() for a block that does not exist should result in error.
405 // Test should pass for both writable and read-only volumes
406 func testDeleteNoSuchBlock(t *testing.T, factory TestableVolumeFactory) {
410 if err := v.Delete(TestHash2); err == nil {
411 t.Errorf("Expected error when attempting to delete a non-existing block")
415 // Invoke Status and verify that VolumeStatus is returned
416 // Test should pass for both writable and read-only volumes
417 func testStatus(t *testing.T, factory TestableVolumeFactory) {
421 // Get node status and make a basic sanity check.
423 if status.DeviceNum == 0 {
424 t.Errorf("uninitialized device_num in %v", status)
427 if status.BytesFree == 0 {
428 t.Errorf("uninitialized bytes_free in %v", status)
431 if status.BytesUsed == 0 {
432 t.Errorf("uninitialized bytes_used in %v", status)
436 // Invoke String for the volume; expect non-empty result
437 // Test should pass for both writable and read-only volumes
438 func testString(t *testing.T, factory TestableVolumeFactory) {
442 if id := v.String(); len(id) == 0 {
443 t.Error("Got empty string for v.String()")
447 // Putting, updating, touching, and deleting blocks from a read-only volume result in error.
448 // Test is intended for only read-only volumes
449 func testUpdateReadOnly(t *testing.T, factory TestableVolumeFactory) {
453 if v.Writable() == true {
457 v.PutRaw(TestHash, TestBlock)
459 // Get from read-only volume should succeed
460 _, err := v.Get(TestHash)
462 t.Errorf("got err %v, expected nil", err)
465 // Put a new block to read-only volume should result in error
466 err = v.Put(TestHash2, TestBlock2)
468 t.Errorf("Expected error when putting block in a read-only volume")
470 _, err = v.Get(TestHash2)
472 t.Errorf("Expected error when getting block whose put in read-only volume failed")
475 // Touch a block in read-only volume should result in error
476 err = v.Touch(TestHash)
478 t.Errorf("Expected error when touching block in a read-only volume")
481 // Delete a block from a read-only volume should result in error
482 err = v.Delete(TestHash)
484 t.Errorf("Expected error when deleting block from a read-only volume")
487 // Overwriting an existing block in read-only volume should result in error
488 err = v.Put(TestHash, TestBlock)
490 t.Errorf("Expected error when putting block in a read-only volume")
494 // Launch concurrent Gets
495 // Test should pass for both writable and read-only volumes
496 func testGetConcurrent(t *testing.T, factory TestableVolumeFactory) {
500 v.PutRaw(TestHash, TestBlock)
501 v.PutRaw(TestHash2, TestBlock2)
502 v.PutRaw(TestHash3, TestBlock3)
504 sem := make(chan int)
505 go func(sem chan int) {
506 buf, err := v.Get(TestHash)
508 t.Errorf("err1: %v", err)
511 if bytes.Compare(buf, TestBlock) != 0 {
512 t.Errorf("buf should be %s, is %s", string(TestBlock), string(buf))
517 go func(sem chan int) {
518 buf, err := v.Get(TestHash2)
520 t.Errorf("err2: %v", err)
523 if bytes.Compare(buf, TestBlock2) != 0 {
524 t.Errorf("buf should be %s, is %s", string(TestBlock2), string(buf))
529 go func(sem chan int) {
530 buf, err := v.Get(TestHash3)
532 t.Errorf("err3: %v", err)
535 if bytes.Compare(buf, TestBlock3) != 0 {
536 t.Errorf("buf should be %s, is %s", string(TestBlock3), string(buf))
541 // Wait for all goroutines to finish
542 for done := 0; done < 3; {
547 // Launch concurrent Puts
548 // Test is intended for only writable volumes
549 func testPutConcurrent(t *testing.T, factory TestableVolumeFactory) {
553 if v.Writable() == false {
557 sem := make(chan int)
558 go func(sem chan int) {
559 err := v.Put(TestHash, TestBlock)
561 t.Errorf("err1: %v", err)
566 go func(sem chan int) {
567 err := v.Put(TestHash2, TestBlock2)
569 t.Errorf("err2: %v", err)
574 go func(sem chan int) {
575 err := v.Put(TestHash3, TestBlock3)
577 t.Errorf("err3: %v", err)
582 // Wait for all goroutines to finish
583 for done := 0; done < 3; {
587 // Double check that we actually wrote the blocks we expected to write.
588 buf, err := v.Get(TestHash)
590 t.Errorf("Get #1: %v", err)
593 if bytes.Compare(buf, TestBlock) != 0 {
594 t.Errorf("Get #1: expected %s, got %s", string(TestBlock), string(buf))
597 buf, err = v.Get(TestHash2)
599 t.Errorf("Get #2: %v", err)
602 if bytes.Compare(buf, TestBlock2) != 0 {
603 t.Errorf("Get #2: expected %s, got %s", string(TestBlock2), string(buf))
606 buf, err = v.Get(TestHash3)
608 t.Errorf("Get #3: %v", err)
611 if bytes.Compare(buf, TestBlock3) != 0 {
612 t.Errorf("Get #3: expected %s, got %s", string(TestBlock3), string(buf))