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 writable
20 // TestableVolume for each test case, to avoid leaking state between
22 func DoGenericVolumeTests(t *testing.T, factory TestableVolumeFactory) {
24 testGetNoSuchBlock(t, factory)
26 testCompareSameContent(t, factory)
27 testCompareWithDifferentContent(t, factory)
28 testCompareWithBadData(t, factory)
30 testPutBlockWithSameContent(t, factory)
31 testPutBlockWithDifferentContent(t, factory)
32 testPutMultipleBlocks(t, factory)
34 testPutAndTouch(t, factory)
35 testTouchNoSuchBlock(t, factory)
37 testMtimeNoSuchBlock(t, factory)
39 testIndexTo(t, factory)
41 testDeleteNewBlock(t, factory)
42 testDeleteOldBlock(t, factory)
43 testDeleteNoSuchBlock(t, factory)
45 testStatus(t, factory)
47 testString(t, factory)
49 testWritableTrue(t, factory)
51 testGetSerialized(t, factory)
52 testPutSerialized(t, factory)
55 // DoGenericReadOnlyVolumeTests runs a set of tests that every
56 // read-only TestableVolume is expected to pass. It calls factory
57 // to create a new read-only TestableVolume for each test case,
58 // to avoid leaking state between tests.
59 func DoGenericReadOnlyVolumeTests(t *testing.T, factory TestableVolumeFactory) {
60 testWritableFalse(t, factory)
61 testUpdateReadOnly(t, factory)
64 // Put a test block, get it and verify content
65 func testGet(t *testing.T, factory TestableVolumeFactory) {
68 v.Put(TEST_HASH, TEST_BLOCK)
70 buf, err := v.Get(TEST_HASH)
74 if bytes.Compare(buf, TEST_BLOCK) != 0 {
75 t.Errorf("expected %s, got %s", string(TEST_BLOCK), string(buf))
79 // Invoke get on a block that does not exist in volume; should result in error
80 func testGetNoSuchBlock(t *testing.T, factory TestableVolumeFactory) {
83 v.Put(TEST_HASH, TEST_BLOCK)
85 if _, err := v.Get(TEST_HASH_2); err == nil {
86 t.Errorf("Expected error while getting non-existing block %v", TEST_HASH_2)
90 // Put a test block and compare the locator with same content
91 func testCompareSameContent(t *testing.T, factory TestableVolumeFactory) {
95 v.Put(TEST_HASH, TEST_BLOCK)
97 // Compare the block locator with same content
98 err := v.Compare(TEST_HASH, TEST_BLOCK)
100 t.Errorf("Got err %q, expected nil", err)
104 // Put a test block and compare the locator with a different content
105 // Expect error due to collision
106 func testCompareWithDifferentContent(t *testing.T, factory TestableVolumeFactory) {
110 v.Put(TEST_HASH, TEST_BLOCK)
112 // Compare the block locator with different content; collision
113 err := v.Compare(TEST_HASH, []byte("baddata"))
115 t.Errorf("Expected error due to collision")
119 // Put a test block with bad data (hash does not match, but Put does not verify)
120 // Compare the locator with good data whose has matches with locator
121 // Expect error due to corruption.
122 func testCompareWithBadData(t *testing.T, factory TestableVolumeFactory) {
126 v.Put(TEST_HASH, []byte("baddata"))
128 err := v.Compare(TEST_HASH, TEST_BLOCK)
130 t.Errorf("Expected error due to corruption")
134 // Put a block and put again with same content
135 func testPutBlockWithSameContent(t *testing.T, factory TestableVolumeFactory) {
139 err := v.Put(TEST_HASH, TEST_BLOCK)
141 t.Errorf("Got err putting block %q: %q, expected nil", TEST_BLOCK, err)
144 err = v.Put(TEST_HASH, TEST_BLOCK)
146 t.Errorf("Got err putting block second time %q: %q, expected nil", TEST_BLOCK, err)
150 // Put a block and put again with different content
151 func testPutBlockWithDifferentContent(t *testing.T, factory TestableVolumeFactory) {
155 err := v.Put(TEST_HASH, TEST_BLOCK)
157 t.Errorf("Got err putting block %q: %q, expected nil", TEST_BLOCK, err)
160 putErr := v.Put(TEST_HASH, TEST_BLOCK_2)
161 buf, getErr := v.Get(TEST_HASH)
163 // Put must not return a nil error unless it has
164 // overwritten the existing data.
165 if bytes.Compare(buf, TEST_BLOCK_2) != 0 {
166 t.Errorf("Put succeeded but Get returned %+v, expected %+v", buf, TEST_BLOCK_2)
169 // It is permissible for Put to fail, but it must
170 // leave us with either the original data, the new
171 // data, or nothing at all.
172 if getErr == nil && bytes.Compare(buf, TEST_BLOCK) != 0 && bytes.Compare(buf, TEST_BLOCK_2) != 0 {
173 t.Errorf("Put failed but Get returned %+v, which is neither %+v nor %+v", buf, TEST_BLOCK, TEST_BLOCK_2)
181 // Put and get multiple blocks
182 func testPutMultipleBlocks(t *testing.T, factory TestableVolumeFactory) {
186 err := v.Put(TEST_HASH, TEST_BLOCK)
188 t.Errorf("Got err putting block %q: %q, expected nil", TEST_BLOCK, err)
191 err = v.Put(TEST_HASH_2, TEST_BLOCK_2)
193 t.Errorf("Got err putting block %q: %q, expected nil", TEST_BLOCK_2, err)
196 err = v.Put(TEST_HASH_3, TEST_BLOCK_3)
198 t.Errorf("Got err putting block %q: %q, expected nil", TEST_BLOCK_3, err)
201 if data, err := v.Get(TEST_HASH); err != nil {
203 } else if bytes.Compare(data, TEST_BLOCK) != 0 {
204 t.Errorf("Block present, but content is incorrect: Expected: %v Found: %v", data, TEST_BLOCK)
207 if data, err := v.Get(TEST_HASH_2); err != nil {
209 } else if bytes.Compare(data, TEST_BLOCK_2) != 0 {
210 t.Errorf("Block present, but content is incorrect: Expected: %v Found: %v", data, TEST_BLOCK_2)
213 if data, err := v.Get(TEST_HASH_3); err != nil {
215 } else if bytes.Compare(data, TEST_BLOCK_3) != 0 {
216 t.Errorf("Block present, but content is incorrect: Expected: %v Found: %v", data, TEST_BLOCK_3)
221 // Test that when applying PUT to a block that already exists,
222 // the block's modification time is updated.
223 func testPutAndTouch(t *testing.T, factory TestableVolumeFactory) {
227 if err := v.Put(TEST_HASH, TEST_BLOCK); err != nil {
231 // We'll verify { t0 < threshold < t1 }, where t0 is the
232 // existing block's timestamp on disk before Put() and t1 is
233 // its timestamp after Put().
234 threshold := time.Now().Add(-time.Second)
236 // Set the stored block's mtime far enough in the past that we
237 // can see the difference between "timestamp didn't change"
238 // and "timestamp granularity is too low".
239 v.TouchWithDate(TEST_HASH, time.Now().Add(-20*time.Second))
241 // Make sure v.Mtime() agrees the above Utime really worked.
242 if t0, err := v.Mtime(TEST_HASH); err != nil || t0.IsZero() || !t0.Before(threshold) {
243 t.Errorf("Setting mtime failed: %v, %v", t0, err)
246 // Write the same block again.
247 if err := v.Put(TEST_HASH, TEST_BLOCK); err != nil {
251 // Verify threshold < t1
252 if t1, err := v.Mtime(TEST_HASH); err != nil {
254 } else if t1.Before(threshold) {
255 t.Errorf("t1 %v should be >= threshold %v after v.Put ", t1, threshold)
259 // Touching a non-existing block should result in error.
260 func testTouchNoSuchBlock(t *testing.T, factory TestableVolumeFactory) {
264 if err := v.Put(TEST_HASH, TEST_BLOCK); err != nil {
268 if err := v.Touch(TEST_HASH); err != nil {
269 t.Error("Expected error when attempted to touch a non-existing block")
273 // Invoking Mtime on a non-existing block should result in error.
274 func testMtimeNoSuchBlock(t *testing.T, factory TestableVolumeFactory) {
278 if _, err := v.Mtime("12345678901234567890123456789012"); err == nil {
279 t.Error("Expected error when updating Mtime on a non-existing block")
283 // Put a few blocks and invoke IndexTo with:
286 // * with no such prefix
287 func testIndexTo(t *testing.T, factory TestableVolumeFactory) {
291 v.Put(TEST_HASH, TEST_BLOCK)
292 v.Put(TEST_HASH_2, TEST_BLOCK_2)
293 v.Put(TEST_HASH_3, TEST_BLOCK_3)
295 buf := new(bytes.Buffer)
297 index_rows := strings.Split(string(buf.Bytes()), "\n")
298 sort.Strings(index_rows)
299 sorted_index := strings.Join(index_rows, "\n")
300 m, err := regexp.MatchString(
301 `^\n`+TEST_HASH+`\+\d+ \d+\n`+
302 TEST_HASH_3+`\+\d+ \d+\n`+
303 TEST_HASH_2+`\+\d+ \d+$`,
308 t.Errorf("Got index %q for empty prefix", sorted_index)
311 for _, prefix := range []string{"f", "f15", "f15ac"} {
312 buf = new(bytes.Buffer)
313 v.IndexTo(prefix, buf)
315 m, err := regexp.MatchString(`^`+TEST_HASH_2+`\+\d+ \d+\n$`, string(buf.Bytes()))
319 t.Errorf("Got index %q for prefix %s", string(buf.Bytes()), prefix)
323 for _, prefix := range []string{"zero", "zip", "zilch"} {
324 buf = new(bytes.Buffer)
325 v.IndexTo(prefix, buf)
327 t.Errorf("Got error on IndexTo with no such prefix %v", err.Error())
328 } else if buf.Len() != 0 {
329 t.Errorf("Expected empty list for IndexTo with no such prefix %s", prefix)
334 // Calling Delete() for a block immediately after writing it (not old enough)
335 // should neither delete the data nor return an error.
336 func testDeleteNewBlock(t *testing.T, factory TestableVolumeFactory) {
339 v.Put(TEST_HASH, TEST_BLOCK)
341 if err := v.Delete(TEST_HASH); err != nil {
344 if data, err := v.Get(TEST_HASH); err != nil {
346 } else if bytes.Compare(data, TEST_BLOCK) != 0 {
347 t.Error("Block still present, but content is incorrect: %+v != %+v", data, TEST_BLOCK)
351 // Calling Delete() for a block with a timestamp older than
352 // blob_signature_ttl seconds in the past should delete the data.
353 func testDeleteOldBlock(t *testing.T, factory TestableVolumeFactory) {
356 v.Put(TEST_HASH, TEST_BLOCK)
357 v.TouchWithDate(TEST_HASH, time.Now().Add(-2*blob_signature_ttl*time.Second))
359 if err := v.Delete(TEST_HASH); err != nil {
362 if _, err := v.Get(TEST_HASH); err == nil || !os.IsNotExist(err) {
363 t.Errorf("os.IsNotExist(%v) should have been true", err.Error())
367 // Calling Delete() for a block that does not exist should result in error.
368 func testDeleteNoSuchBlock(t *testing.T, factory TestableVolumeFactory) {
371 v.Put(TEST_HASH, TEST_BLOCK)
373 if err := v.Delete(TEST_HASH_2); err == nil {
374 t.Errorf("Expected error when attempting to delete a non-existing block")
378 // Invoke Status and verify that VolumeStatus is returned
379 func testStatus(t *testing.T, factory TestableVolumeFactory) {
383 // Get node status and make a basic sanity check.
385 if status.DeviceNum == 0 {
386 t.Errorf("uninitialized device_num in %v", status)
389 if status.BytesFree == 0 {
390 t.Errorf("uninitialized bytes_free in %v", status)
393 if status.BytesUsed == 0 {
394 t.Errorf("uninitialized bytes_used in %v", status)
398 // Invoke String for the volume; expect non-empty result
399 func testString(t *testing.T, factory TestableVolumeFactory) {
403 if id := v.String(); len(id) == 0 {
404 t.Error("Got empty string for v.String()")
408 // Verify Writable is true on a writable volume
409 func testWritableTrue(t *testing.T, factory TestableVolumeFactory) {
413 if v.Writable() == false {
414 t.Errorf("Expected writable to be true on a writable volume")
418 // Verify Writable is false on a read-only volume
419 func testWritableFalse(t *testing.T, factory TestableVolumeFactory) {
423 if v.Writable() != false {
424 t.Errorf("Expected writable to be false on a read-only volume")
428 // Updating, touching, and deleting blocks from a read-only volume result in error.
429 func testUpdateReadOnly(t *testing.T, factory TestableVolumeFactory) {
433 v.PutRaw(TEST_HASH, TEST_BLOCK)
435 _, err := v.Get(TEST_HASH)
437 t.Errorf("got err %v, expected nil", err)
440 err = v.Put(TEST_HASH, TEST_BLOCK)
442 t.Errorf("Expected error when putting block in a read-only volume")
445 err = v.Touch(TEST_HASH)
447 t.Errorf("Expected error when touching block in a read-only volume")
450 err = v.Delete(TEST_HASH)
452 t.Errorf("Expected error when deleting block from a read-only volume")
456 // Serialization tests: launch a bunch of concurrent
458 // TODO(twp): show that the underlying Read/Write operations executed
459 // serially and not concurrently. The easiest way to do this is
460 // probably to activate verbose or debug logging, capture log output
461 // and examine it to confirm that Reads and Writes did not overlap.
463 // TODO(twp): a proper test of I/O serialization requires that a
464 // second request start while the first one is still underway.
465 // Guaranteeing that the test behaves this way requires some tricky
466 // synchronization and mocking. For now we'll just launch a bunch of
467 // requests simultaenously in goroutines and demonstrate that they
468 // return accurate results.
471 func testGetSerialized(t *testing.T, factory TestableVolumeFactory) {
475 v.Put(TEST_HASH, TEST_BLOCK)
476 v.Put(TEST_HASH_2, TEST_BLOCK_2)
477 v.Put(TEST_HASH_3, TEST_BLOCK_3)
479 sem := make(chan int)
480 go func(sem chan int) {
481 buf, err := v.Get(TEST_HASH)
483 t.Errorf("err1: %v", err)
485 if bytes.Compare(buf, TEST_BLOCK) != 0 {
486 t.Errorf("buf should be %s, is %s", string(TEST_BLOCK), string(buf))
491 go func(sem chan int) {
492 buf, err := v.Get(TEST_HASH_2)
494 t.Errorf("err2: %v", err)
496 if bytes.Compare(buf, TEST_BLOCK_2) != 0 {
497 t.Errorf("buf should be %s, is %s", string(TEST_BLOCK_2), string(buf))
502 go func(sem chan int) {
503 buf, err := v.Get(TEST_HASH_3)
505 t.Errorf("err3: %v", err)
507 if bytes.Compare(buf, TEST_BLOCK_3) != 0 {
508 t.Errorf("buf should be %s, is %s", string(TEST_BLOCK_3), string(buf))
513 // Wait for all goroutines to finish
514 for done := 0; done < 3; {
519 func testPutSerialized(t *testing.T, factory TestableVolumeFactory) {
523 sem := make(chan int)
524 go func(sem chan int) {
525 err := v.Put(TEST_HASH, TEST_BLOCK)
527 t.Errorf("err1: %v", err)
532 go func(sem chan int) {
533 err := v.Put(TEST_HASH_2, TEST_BLOCK_2)
535 t.Errorf("err2: %v", err)
540 go func(sem chan int) {
541 err := v.Put(TEST_HASH_3, TEST_BLOCK_3)
543 t.Errorf("err3: %v", err)
548 // Wait for all goroutines to finish
549 for done := 0; done < 3; {
553 // Double check that we actually wrote the blocks we expected to write.
554 buf, err := v.Get(TEST_HASH)
556 t.Errorf("Get #1: %v", err)
558 if bytes.Compare(buf, TEST_BLOCK) != 0 {
559 t.Errorf("Get #1: expected %s, got %s", string(TEST_BLOCK), string(buf))
562 buf, err = v.Get(TEST_HASH_2)
564 t.Errorf("Get #2: %v", err)
566 if bytes.Compare(buf, TEST_BLOCK_2) != 0 {
567 t.Errorf("Get #2: expected %s, got %s", string(TEST_BLOCK_2), string(buf))
570 buf, err = v.Get(TEST_HASH_3)
572 t.Errorf("Get #3: %v", err)
574 if bytes.Compare(buf, TEST_BLOCK_3) != 0 {
575 t.Errorf("Get #3: expected %s, got %s", string(TEST_BLOCK_3), string(buf))