[ARVADOS] updated: 241f0bcdacbf83b587bff9ff45985e720bde9f0b

git at public.curoverse.com git at public.curoverse.com
Fri Sep 11 12:00:19 EDT 2015


Summary of changes:
 services/keepstore/handlers.go            |   7 -
 services/keepstore/volume.go              |  14 +-
 services/keepstore/volume_generic_test.go | 564 +++++++++++++++++++++++++++---
 services/keepstore/volume_unix_test.go    | 217 +-----------
 4 files changed, 531 insertions(+), 271 deletions(-)

       via  241f0bcdacbf83b587bff9ff45985e720bde9f0b (commit)
      from  fbeca60ad61f0ef846a026b288a3bc5104383da7 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit 241f0bcdacbf83b587bff9ff45985e720bde9f0b
Author: radhika <radhika at curoverse.com>
Date:   Fri Sep 11 11:59:05 2015 -0400

    7179: add generic volume test; as part of this exercise, moved some "generic" tests from volume_unix_test.go
    into volume_generic_test.go so that we do not repeat these in all storage device related testing.

diff --git a/services/keepstore/handlers.go b/services/keepstore/handlers.go
index e6129a7..3dcc6e1 100644
--- a/services/keepstore/handlers.go
+++ b/services/keepstore/handlers.go
@@ -177,13 +177,6 @@ func IndexHandler(resp http.ResponseWriter, req *http.Request) {
 //            * device_num (an integer identifying the underlying filesystem)
 //            * bytes_free
 //            * bytes_used
-//
-type VolumeStatus struct {
-	MountPoint string `json:"mount_point"`
-	DeviceNum  uint64 `json:"device_num"`
-	BytesFree  uint64 `json:"bytes_free"`
-	BytesUsed  uint64 `json:"bytes_used"`
-}
 
 type PoolStatus struct {
 	Alloc uint64 `json:"BytesAllocated"`
diff --git a/services/keepstore/volume.go b/services/keepstore/volume.go
index f57df24..e5964e2 100644
--- a/services/keepstore/volume.go
+++ b/services/keepstore/volume.go
@@ -122,7 +122,7 @@ type Volume interface {
 	//
 	//   - size is the number of bytes of content, given as a
 	//     decimal number with one or more digits
-	//     
+	//
 	//   - timestamp is the timestamp stored for the locator,
 	//     given as a decimal number of seconds after January 1,
 	//     1970 UTC.
@@ -251,3 +251,15 @@ func (vm *RRVolumeManager) NextWritable() Volume {
 
 func (vm *RRVolumeManager) Close() {
 }
+
+// VolumeStatus
+//   * mount_point
+//   * device_num (an integer identifying the underlying storage system)
+//   * bytes_free
+//   * bytes_used
+type VolumeStatus struct {
+	MountPoint string `json:"mount_point"`
+	DeviceNum  uint64 `json:"device_num"`
+	BytesFree  uint64 `json:"bytes_free"`
+	BytesUsed  uint64 `json:"bytes_used"`
+}
diff --git a/services/keepstore/volume_generic_test.go b/services/keepstore/volume_generic_test.go
index 24ebc35..f1b27be 100644
--- a/services/keepstore/volume_generic_test.go
+++ b/services/keepstore/volume_generic_test.go
@@ -3,6 +3,9 @@ package main
 import (
 	"bytes"
 	"os"
+	"regexp"
+	"sort"
+	"strings"
 	"testing"
 	"time"
 )
@@ -13,64 +16,313 @@ import (
 type TestableVolumeFactory func(t *testing.T) TestableVolume
 
 // DoGenericVolumeTests runs a set of tests that every TestableVolume
-// is expected to pass. It calls factory to create a new
+// is expected to pass. It calls factory to create a new writable
 // TestableVolume for each test case, to avoid leaking state between
 // tests.
 func DoGenericVolumeTests(t *testing.T, factory TestableVolumeFactory) {
-	/*
-		testGetBlock(t, factory)
-		testGetNoSuchBlock(t, factory)
-		testGetSystemError(t, factory)
-
-		testCompareSameContent(t, factory)
-		testCompareWithCollisionError(t, factory)
-		testCompareWithCorruptError(t, factory)
-		testCompareSystemError(t, factory)
-
-		testPutBlock(t, factory)
-		testPutMultipleBlocks(t, factory)
-		testPutBlockWithSameContent(t, factory)
-		testPutBlockWithDifferentContent(t, factory)
-		testPutBlockSystemError(t, factory)
-
-		testTouch(t, factory)
-		testTouchNoSuchBlock(t, factory)
-		testTouchSystemError(t, factory)
-
-		testMtime(t, factory)
-		testMtimeNoSuchBlock(t, factory)
-		testMtimeSystemError(t, factory)
-
-		testIndexToWithNoPrefix(t, factory)
-		testIndexToWithPrefix(t, factory)
-		testIndexToWithNoSuchPrefix(t, factory)
-		testIndexToOnEmptyVolume(t, factory)
-		testIndexToSystemError(t, factory)
-
-		testDeleteNewBlock(t, factory)
-		testDeleteOldWithOnlyBlockInVol(t, factory)
-		testDeleteOldWithOtherBlocksInVol(t, factory)
-		testDeleteNoSuchBlock(t, factory)
-		testDeleteSystemError(t, factory)
-
-		testStatus(t, factory)
-		testStatusWithError(t, factory)
-		testStatusSystemError(t, factory)
-
-		testString(t, factory)
-		testStringSystemError(t, factory)
-
-		testWritableTrue(t, factory)
-		testWritableFalse(t, factory)
-		testWritableSystemError(t, factory)
-	*/
+	testGet(t, factory)
+	testGetNoSuchBlock(t, factory)
+
+	testCompareSameContent(t, factory)
+	testCompareWithDifferentContent(t, factory)
+	testCompareWithBadData(t, factory)
+
+	testPutBlockWithSameContent(t, factory)
+	testPutBlockWithDifferentContent(t, factory)
+	testPutMultipleBlocks(t, factory)
+
+	testPutAndTouch(t, factory)
+	testTouchNoSuchBlock(t, factory)
+
+	testMtimeNoSuchBlock(t, factory)
+
+	testIndexTo(t, factory)
 
 	testDeleteNewBlock(t, factory)
 	testDeleteOldBlock(t, factory)
+	testDeleteNoSuchBlock(t, factory)
+
+	testStatus(t, factory)
+
+	testString(t, factory)
+
+	testWritableTrue(t, factory)
+
+	testGetSerialized(t, factory)
+	testPutSerialized(t, factory)
+}
+
+// DoGenericReadOnlyVolumeTests runs a set of tests that every
+// read-only TestableVolume is expected to pass. It calls factory
+// to create a new read-only TestableVolume for each test case,
+// to avoid leaking state between tests.
+func DoGenericReadOnlyVolumeTests(t *testing.T, factory TestableVolumeFactory) {
+	testWritableFalse(t, factory)
+	testUpdateReadOnly(t, factory)
+}
+
+// Put a test block, get it and verify content
+func testGet(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+	v.Put(TEST_HASH, TEST_BLOCK)
+
+	buf, err := v.Get(TEST_HASH)
+	if err != nil {
+		t.Error(err)
+	}
+	if bytes.Compare(buf, TEST_BLOCK) != 0 {
+		t.Errorf("expected %s, got %s", string(TEST_BLOCK), string(buf))
+	}
+}
+
+// Invoke get on a block that does not exist in volume; should result in error
+func testGetNoSuchBlock(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+	v.Put(TEST_HASH, TEST_BLOCK)
+
+	if _, err := v.Get(TEST_HASH_2); err == nil {
+		t.Errorf("Expected error while getting non-existing block %v", TEST_HASH_2)
+	}
+}
+
+// Put a test block and compare the locator with same content
+func testCompareSameContent(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	v.Put(TEST_HASH, TEST_BLOCK)
+
+	// Compare the block locator with same content
+	err := v.Compare(TEST_HASH, TEST_BLOCK)
+	if err != nil {
+		t.Errorf("Got err %q, expected nil", err)
+	}
+}
+
+// Put a test block and compare the locator with a different content
+// Expect error due to collision
+func testCompareWithDifferentContent(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	v.Put(TEST_HASH, TEST_BLOCK)
+
+	// Compare the block locator with different content; collision
+	err := v.Compare(TEST_HASH, []byte("baddata"))
+	if err == nil {
+		t.Errorf("Expected error due to collision")
+	}
+}
+
+// Put a test block with bad data (hash does not match, but Put does not verify)
+// Compare the locator with good data whose has matches with locator
+// Expect error due to corruption.
+func testCompareWithBadData(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	v.Put(TEST_HASH, []byte("baddata"))
+
+	err := v.Compare(TEST_HASH, TEST_BLOCK)
+	if err == nil {
+		t.Errorf("Expected error due to corruption")
+	}
+}
+
+// Put a block and put again with same content
+func testPutBlockWithSameContent(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	err := v.Put(TEST_HASH, TEST_BLOCK)
+	if err != nil {
+		t.Errorf("Got err putting block %q: %q, expected nil", TEST_BLOCK, err)
+	}
+
+	err = v.Put(TEST_HASH, TEST_BLOCK)
+	if err != nil {
+		t.Errorf("Got err putting block second time %q: %q, expected nil", TEST_BLOCK, err)
+	}
+}
+
+// Put a block and put again with different content
+func testPutBlockWithDifferentContent(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	err := v.Put(TEST_HASH, TEST_BLOCK)
+	if err != nil {
+		t.Errorf("Got err putting block %q: %q, expected nil", TEST_BLOCK, err)
+	}
+
+	// Whether Put with the same loc with different content fails or succeeds
+	// is implementation dependent. So, just check loc exists after overwriting.
+	// We also do not want to see if loc has block1 or block2, for the same reason.
+	if err = v.Put(TEST_HASH, TEST_BLOCK_2); err != nil {
+		t.Errorf("Got err putting block with different content %q: %q, expected nil", TEST_BLOCK, err)
+	}
+	if _, err := v.Get(TEST_HASH); err != nil {
+		t.Errorf("Got err getting block %q: %q, expected nil", TEST_BLOCK, err)
+	}
+}
+
+// Put and get multiple blocks
+func testPutMultipleBlocks(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	err := v.Put(TEST_HASH, TEST_BLOCK)
+	if err != nil {
+		t.Errorf("Got err putting block %q: %q, expected nil", TEST_BLOCK, err)
+	}
+
+	err = v.Put(TEST_HASH_2, TEST_BLOCK_2)
+	if err != nil {
+		t.Errorf("Got err putting block %q: %q, expected nil", TEST_BLOCK_2, err)
+	}
+
+	err = v.Put(TEST_HASH_3, TEST_BLOCK_3)
+	if err != nil {
+		t.Errorf("Got err putting block %q: %q, expected nil", TEST_BLOCK_3, err)
+	}
+
+	if data, err := v.Get(TEST_HASH); err != nil {
+		t.Error(err)
+	} else if bytes.Compare(data, TEST_BLOCK) != 0 {
+		t.Errorf("Block present, but content is incorrect: Expected: %v  Found: %v", data, TEST_BLOCK)
+	}
+
+	if data, err := v.Get(TEST_HASH_2); err != nil {
+		t.Error(err)
+	} else if bytes.Compare(data, TEST_BLOCK_2) != 0 {
+		t.Errorf("Block present, but content is incorrect: Expected: %v  Found: %v", data, TEST_BLOCK_2)
+	}
+
+	if data, err := v.Get(TEST_HASH_3); err != nil {
+		t.Error(err)
+	} else if bytes.Compare(data, TEST_BLOCK_3) != 0 {
+		t.Errorf("Block present, but content is incorrect: Expected: %v  Found: %v", data, TEST_BLOCK_3)
+	}
+}
+
+// testPutAndTouch
+//   Test that when applying PUT to a block that already exists,
+//   the block's modification time is updated.
+func testPutAndTouch(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	if err := v.Put(TEST_HASH, TEST_BLOCK); err != nil {
+		t.Error(err)
+	}
+
+	// We'll verify { t0 < threshold < t1 }, where t0 is the
+	// existing block's timestamp on disk before Put() and t1 is
+	// its timestamp after Put().
+	threshold := time.Now().Add(-time.Second)
+
+	// Set the stored block's mtime far enough in the past that we
+	// can see the difference between "timestamp didn't change"
+	// and "timestamp granularity is too low".
+	v.TouchWithDate(TEST_HASH, time.Now().Add(-20*time.Second))
+
+	// Make sure v.Mtime() agrees the above Utime really worked.
+	if t0, err := v.Mtime(TEST_HASH); err != nil || t0.IsZero() || !t0.Before(threshold) {
+		t.Errorf("Setting mtime failed: %v, %v", t0, err)
+	}
+
+	// Write the same block again.
+	if err := v.Put(TEST_HASH, TEST_BLOCK); err != nil {
+		t.Error(err)
+	}
+
+	// Verify threshold < t1
+	if t1, err := v.Mtime(TEST_HASH); err != nil {
+		t.Error(err)
+	} else if t1.Before(threshold) {
+		t.Errorf("t1 %v should be >= threshold %v after v.Put ", t1, threshold)
+	}
+}
+
+// Touching a non-existing block should result in error.
+func testTouchNoSuchBlock(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	if err := v.Put(TEST_HASH, TEST_BLOCK); err != nil {
+		t.Error(err)
+	}
+
+	if err := v.Touch(TEST_HASH); err != nil {
+		t.Error("Expected error when attempted to touch a non-existing block")
+	}
+}
+
+// Invoking Mtime on a non-existing block should result in error.
+func testMtimeNoSuchBlock(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	if _, err := v.Mtime("12345678901234567890123456789012"); err == nil {
+		t.Error("Expected error when updating Mtime on a non-existing block")
+	}
 }
 
-// Calling Delete() for a block immediately after writing it should
-// neither delete the data nor return an error.
+// Put a few blocks and invoke IndexTo with:
+// * no prefix
+// * with a prefix
+// * with no such prefix
+func testIndexTo(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	v.Put(TEST_HASH, TEST_BLOCK)
+	v.Put(TEST_HASH_2, TEST_BLOCK_2)
+	v.Put(TEST_HASH_3, TEST_BLOCK_3)
+
+	buf := new(bytes.Buffer)
+	v.IndexTo("", buf)
+	index_rows := strings.Split(string(buf.Bytes()), "\n")
+	sort.Strings(index_rows)
+	sorted_index := strings.Join(index_rows, "\n")
+	m, err := regexp.MatchString(
+		`^\n`+TEST_HASH+`\+\d+ \d+\n`+
+			TEST_HASH_3+`\+\d+ \d+\n`+
+			TEST_HASH_2+`\+\d+ \d+$`,
+		sorted_index)
+	if err != nil {
+		t.Error(err)
+	} else if !m {
+		t.Errorf("Got index %q for empty prefix", sorted_index)
+	}
+
+	for _, prefix := range []string{"f", "f15", "f15ac"} {
+		buf = new(bytes.Buffer)
+		v.IndexTo(prefix, buf)
+
+		m, err := regexp.MatchString(`^`+TEST_HASH_2+`\+\d+ \d+\n$`, string(buf.Bytes()))
+		if err != nil {
+			t.Error(err)
+		} else if !m {
+			t.Errorf("Got index %q for prefix %s", string(buf.Bytes()), prefix)
+		}
+	}
+
+	for _, prefix := range []string{"zero", "zip", "zilch"} {
+		buf = new(bytes.Buffer)
+		v.IndexTo(prefix, buf)
+		if err != nil {
+			t.Errorf("Got error on IndexTo with no such prefix %v", err.Error())
+		} else if buf.Len() != 0 {
+			t.Errorf("Expected empty list for IndexTo with no such prefix %s", prefix)
+		}
+	}
+}
+
+// Calling Delete() for a block immediately after writing it (not old enough)
+// should neither delete the data nor return an error.
 func testDeleteNewBlock(t *testing.T, factory TestableVolumeFactory) {
 	v := factory(t)
 	defer v.Teardown()
@@ -101,3 +353,215 @@ func testDeleteOldBlock(t *testing.T, factory TestableVolumeFactory) {
 		t.Errorf("os.IsNotExist(%v) should have been true", err.Error())
 	}
 }
+
+// Calling Delete() for a block that does not exist should result in error.
+func testDeleteNoSuchBlock(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+	v.Put(TEST_HASH, TEST_BLOCK)
+
+	if err := v.Delete(TEST_HASH_2); err == nil {
+		t.Errorf("Expected error when attempting to delete a non-existing block")
+	}
+}
+
+// Invoke Status and verify that VolumeStatus is returned
+func testStatus(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	// Get node status and make a basic sanity check.
+	status := v.Status()
+	if status.DeviceNum == 0 {
+		t.Errorf("uninitialized device_num in %v", status)
+	}
+
+	if status.BytesFree == 0 {
+		t.Errorf("uninitialized bytes_free in %v", status)
+	}
+
+	if status.BytesUsed == 0 {
+		t.Errorf("uninitialized bytes_used in %v", status)
+	}
+}
+
+// Invoke String for the volume; expect non-empty result
+func testString(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	if id := v.String(); len(id) == 0 {
+		t.Error("Got empty string for v.String()")
+	}
+}
+
+// Verify Writable is true on a writable volume
+func testWritableTrue(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	if v.Writable() == false {
+		t.Errorf("Expected writable to be true on a writable volume")
+	}
+}
+
+// Verify Writable is false on a read-only volume
+func testWritableFalse(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	if v.Writable() != false {
+		t.Errorf("Expected writable to be false on a read-only volume")
+	}
+}
+
+// Updating, touching, and deleting blocks from a read-only volume result in error.
+func testUpdateReadOnly(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	v.PutRaw(TEST_HASH, TEST_BLOCK)
+
+	_, err := v.Get(TEST_HASH)
+	if err != nil {
+		t.Errorf("got err %v, expected nil", err)
+	}
+
+	err = v.Put(TEST_HASH, TEST_BLOCK)
+	if err == nil {
+		t.Errorf("Expected error when putting block in a read-only volume")
+	}
+
+	err = v.Touch(TEST_HASH)
+	if err == nil {
+		t.Errorf("Expected error when touching block in a read-only volume")
+	}
+
+	err = v.Delete(TEST_HASH)
+	if err == nil {
+		t.Errorf("Expected error when deleting block from a read-only volume")
+	}
+}
+
+// Serialization tests: launch a bunch of concurrent
+//
+// TODO(twp): show that the underlying Read/Write operations executed
+// serially and not concurrently. The easiest way to do this is
+// probably to activate verbose or debug logging, capture log output
+// and examine it to confirm that Reads and Writes did not overlap.
+//
+// TODO(twp): a proper test of I/O serialization requires that a
+// second request start while the first one is still underway.
+// Guaranteeing that the test behaves this way requires some tricky
+// synchronization and mocking.  For now we'll just launch a bunch of
+// requests simultaenously in goroutines and demonstrate that they
+// return accurate results.
+//
+
+func testGetSerialized(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	v.Put(TEST_HASH, TEST_BLOCK)
+	v.Put(TEST_HASH_2, TEST_BLOCK_2)
+	v.Put(TEST_HASH_3, TEST_BLOCK_3)
+
+	sem := make(chan int)
+	go func(sem chan int) {
+		buf, err := v.Get(TEST_HASH)
+		if err != nil {
+			t.Errorf("err1: %v", err)
+		}
+		if bytes.Compare(buf, TEST_BLOCK) != 0 {
+			t.Errorf("buf should be %s, is %s", string(TEST_BLOCK), string(buf))
+		}
+		sem <- 1
+	}(sem)
+
+	go func(sem chan int) {
+		buf, err := v.Get(TEST_HASH_2)
+		if err != nil {
+			t.Errorf("err2: %v", err)
+		}
+		if bytes.Compare(buf, TEST_BLOCK_2) != 0 {
+			t.Errorf("buf should be %s, is %s", string(TEST_BLOCK_2), string(buf))
+		}
+		sem <- 1
+	}(sem)
+
+	go func(sem chan int) {
+		buf, err := v.Get(TEST_HASH_3)
+		if err != nil {
+			t.Errorf("err3: %v", err)
+		}
+		if bytes.Compare(buf, TEST_BLOCK_3) != 0 {
+			t.Errorf("buf should be %s, is %s", string(TEST_BLOCK_3), string(buf))
+		}
+		sem <- 1
+	}(sem)
+
+	// Wait for all goroutines to finish
+	for done := 0; done < 3; {
+		done += <-sem
+	}
+}
+
+func testPutSerialized(t *testing.T, factory TestableVolumeFactory) {
+	v := factory(t)
+	defer v.Teardown()
+
+	sem := make(chan int)
+	go func(sem chan int) {
+		err := v.Put(TEST_HASH, TEST_BLOCK)
+		if err != nil {
+			t.Errorf("err1: %v", err)
+		}
+		sem <- 1
+	}(sem)
+
+	go func(sem chan int) {
+		err := v.Put(TEST_HASH_2, TEST_BLOCK_2)
+		if err != nil {
+			t.Errorf("err2: %v", err)
+		}
+		sem <- 1
+	}(sem)
+
+	go func(sem chan int) {
+		err := v.Put(TEST_HASH_3, TEST_BLOCK_3)
+		if err != nil {
+			t.Errorf("err3: %v", err)
+		}
+		sem <- 1
+	}(sem)
+
+	// Wait for all goroutines to finish
+	for done := 0; done < 3; {
+		done += <-sem
+	}
+
+	// Double check that we actually wrote the blocks we expected to write.
+	buf, err := v.Get(TEST_HASH)
+	if err != nil {
+		t.Errorf("Get #1: %v", err)
+	}
+	if bytes.Compare(buf, TEST_BLOCK) != 0 {
+		t.Errorf("Get #1: expected %s, got %s", string(TEST_BLOCK), string(buf))
+	}
+
+	buf, err = v.Get(TEST_HASH_2)
+	if err != nil {
+		t.Errorf("Get #2: %v", err)
+	}
+	if bytes.Compare(buf, TEST_BLOCK_2) != 0 {
+		t.Errorf("Get #2: expected %s, got %s", string(TEST_BLOCK_2), string(buf))
+	}
+
+	buf, err = v.Get(TEST_HASH_3)
+	if err != nil {
+		t.Errorf("Get #3: %v", err)
+	}
+	if bytes.Compare(buf, TEST_BLOCK_3) != 0 {
+		t.Errorf("Get #3: expected %s, got %s", string(TEST_BLOCK_3), string(buf))
+	}
+}
diff --git a/services/keepstore/volume_unix_test.go b/services/keepstore/volume_unix_test.go
index 9f37042..7fea560 100644
--- a/services/keepstore/volume_unix_test.go
+++ b/services/keepstore/volume_unix_test.go
@@ -7,8 +7,6 @@ import (
 	"io"
 	"io/ioutil"
 	"os"
-	"regexp"
-	"sort"
 	"strings"
 	"sync"
 	"syscall"
@@ -72,18 +70,10 @@ func TestUnixVolumeWithGenericTests(t *testing.T) {
 	})
 }
 
-func TestGet(t *testing.T) {
-	v := NewTestableUnixVolume(t, false, false)
-	defer v.Teardown()
-	v.Put(TEST_HASH, TEST_BLOCK)
-
-	buf, err := v.Get(TEST_HASH)
-	if err != nil {
-		t.Error(err)
-	}
-	if bytes.Compare(buf, TEST_BLOCK) != 0 {
-		t.Errorf("expected %s, got %s", string(TEST_BLOCK), string(buf))
-	}
+func TestUnixReadOnlyVolumeWithGenericTests(t *testing.T) {
+	DoGenericReadOnlyVolumeTests(t, func(t *testing.T) TestableVolume {
+		return NewTestableUnixVolume(t, false, true)
+	})
 }
 
 func TestGetNotFound(t *testing.T) {
@@ -102,42 +92,6 @@ func TestGetNotFound(t *testing.T) {
 	}
 }
 
-func TestIndexTo(t *testing.T) {
-	v := NewTestableUnixVolume(t, false, false)
-	defer v.Teardown()
-
-	v.Put(TEST_HASH, TEST_BLOCK)
-	v.Put(TEST_HASH_2, TEST_BLOCK_2)
-	v.Put(TEST_HASH_3, TEST_BLOCK_3)
-
-	buf := new(bytes.Buffer)
-	v.IndexTo("", buf)
-	index_rows := strings.Split(string(buf.Bytes()), "\n")
-	sort.Strings(index_rows)
-	sorted_index := strings.Join(index_rows, "\n")
-	m, err := regexp.MatchString(
-		`^\n`+TEST_HASH+`\+\d+ \d+\n`+
-			TEST_HASH_3+`\+\d+ \d+\n`+
-			TEST_HASH_2+`\+\d+ \d+$`,
-		sorted_index)
-	if err != nil {
-		t.Error(err)
-	} else if !m {
-		t.Errorf("Got index %q for empty prefix", sorted_index)
-	}
-
-	for _, prefix := range []string{"f", "f15", "f15ac"} {
-		buf = new(bytes.Buffer)
-		v.IndexTo(prefix, buf)
-		m, err := regexp.MatchString(`^`+TEST_HASH_2+`\+\d+ \d+\n$`, string(buf.Bytes()))
-		if err != nil {
-			t.Error(err)
-		} else if !m {
-			t.Errorf("Got index %q for prefix %q", string(buf.Bytes()), prefix)
-		}
-	}
-}
-
 func TestPut(t *testing.T) {
 	v := NewTestableUnixVolume(t, false, false)
 	defer v.Teardown()
@@ -193,169 +147,6 @@ func TestUnixVolumeReadonly(t *testing.T) {
 	}
 }
 
-// TestPutTouch
-//     Test that when applying PUT to a block that already exists,
-//     the block's modification time is updated.
-func TestPutTouch(t *testing.T) {
-	v := NewTestableUnixVolume(t, false, false)
-	defer v.Teardown()
-
-	if err := v.Put(TEST_HASH, TEST_BLOCK); err != nil {
-		t.Error(err)
-	}
-
-	// We'll verify { t0 < threshold < t1 }, where t0 is the
-	// existing block's timestamp on disk before Put() and t1 is
-	// its timestamp after Put().
-	threshold := time.Now().Add(-time.Second)
-
-	// Set the stored block's mtime far enough in the past that we
-	// can see the difference between "timestamp didn't change"
-	// and "timestamp granularity is too low".
-	v.TouchWithDate(TEST_HASH, time.Now().Add(-20*time.Second))
-
-	// Make sure v.Mtime() agrees the above Utime really worked.
-	if t0, err := v.Mtime(TEST_HASH); err != nil || t0.IsZero() || !t0.Before(threshold) {
-		t.Errorf("Setting mtime failed: %v, %v", t0, err)
-	}
-
-	// Write the same block again.
-	if err := v.Put(TEST_HASH, TEST_BLOCK); err != nil {
-		t.Error(err)
-	}
-
-	// Verify threshold < t1
-	if t1, err := v.Mtime(TEST_HASH); err != nil {
-		t.Error(err)
-	} else if t1.Before(threshold) {
-		t.Errorf("t1 %v should be >= threshold %v after v.Put ", t1, threshold)
-	}
-}
-
-// Serialization tests: launch a bunch of concurrent
-//
-// TODO(twp): show that the underlying Read/Write operations executed
-// serially and not concurrently. The easiest way to do this is
-// probably to activate verbose or debug logging, capture log output
-// and examine it to confirm that Reads and Writes did not overlap.
-//
-// TODO(twp): a proper test of I/O serialization requires that a
-// second request start while the first one is still underway.
-// Guaranteeing that the test behaves this way requires some tricky
-// synchronization and mocking.  For now we'll just launch a bunch of
-// requests simultaenously in goroutines and demonstrate that they
-// return accurate results.
-//
-func TestGetSerialized(t *testing.T) {
-	// Create a volume with I/O serialization enabled.
-	v := NewTestableUnixVolume(t, true, false)
-	defer v.Teardown()
-
-	v.Put(TEST_HASH, TEST_BLOCK)
-	v.Put(TEST_HASH_2, TEST_BLOCK_2)
-	v.Put(TEST_HASH_3, TEST_BLOCK_3)
-
-	sem := make(chan int)
-	go func(sem chan int) {
-		buf, err := v.Get(TEST_HASH)
-		if err != nil {
-			t.Errorf("err1: %v", err)
-		}
-		if bytes.Compare(buf, TEST_BLOCK) != 0 {
-			t.Errorf("buf should be %s, is %s", string(TEST_BLOCK), string(buf))
-		}
-		sem <- 1
-	}(sem)
-
-	go func(sem chan int) {
-		buf, err := v.Get(TEST_HASH_2)
-		if err != nil {
-			t.Errorf("err2: %v", err)
-		}
-		if bytes.Compare(buf, TEST_BLOCK_2) != 0 {
-			t.Errorf("buf should be %s, is %s", string(TEST_BLOCK_2), string(buf))
-		}
-		sem <- 1
-	}(sem)
-
-	go func(sem chan int) {
-		buf, err := v.Get(TEST_HASH_3)
-		if err != nil {
-			t.Errorf("err3: %v", err)
-		}
-		if bytes.Compare(buf, TEST_BLOCK_3) != 0 {
-			t.Errorf("buf should be %s, is %s", string(TEST_BLOCK_3), string(buf))
-		}
-		sem <- 1
-	}(sem)
-
-	// Wait for all goroutines to finish
-	for done := 0; done < 3; {
-		done += <-sem
-	}
-}
-
-func TestPutSerialized(t *testing.T) {
-	// Create a volume with I/O serialization enabled.
-	v := NewTestableUnixVolume(t, true, false)
-	defer v.Teardown()
-
-	sem := make(chan int)
-	go func(sem chan int) {
-		err := v.Put(TEST_HASH, TEST_BLOCK)
-		if err != nil {
-			t.Errorf("err1: %v", err)
-		}
-		sem <- 1
-	}(sem)
-
-	go func(sem chan int) {
-		err := v.Put(TEST_HASH_2, TEST_BLOCK_2)
-		if err != nil {
-			t.Errorf("err2: %v", err)
-		}
-		sem <- 1
-	}(sem)
-
-	go func(sem chan int) {
-		err := v.Put(TEST_HASH_3, TEST_BLOCK_3)
-		if err != nil {
-			t.Errorf("err3: %v", err)
-		}
-		sem <- 1
-	}(sem)
-
-	// Wait for all goroutines to finish
-	for done := 0; done < 3; {
-		done += <-sem
-	}
-
-	// Double check that we actually wrote the blocks we expected to write.
-	buf, err := v.Get(TEST_HASH)
-	if err != nil {
-		t.Errorf("Get #1: %v", err)
-	}
-	if bytes.Compare(buf, TEST_BLOCK) != 0 {
-		t.Errorf("Get #1: expected %s, got %s", string(TEST_BLOCK), string(buf))
-	}
-
-	buf, err = v.Get(TEST_HASH_2)
-	if err != nil {
-		t.Errorf("Get #2: %v", err)
-	}
-	if bytes.Compare(buf, TEST_BLOCK_2) != 0 {
-		t.Errorf("Get #2: expected %s, got %s", string(TEST_BLOCK_2), string(buf))
-	}
-
-	buf, err = v.Get(TEST_HASH_3)
-	if err != nil {
-		t.Errorf("Get #3: %v", err)
-	}
-	if bytes.Compare(buf, TEST_BLOCK_3) != 0 {
-		t.Errorf("Get #3: expected %s, got %s", string(TEST_BLOCK_3), string(buf))
-	}
-}
-
 func TestIsFull(t *testing.T) {
 	v := NewTestableUnixVolume(t, false, false)
 	defer v.Teardown()

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list