12 func TempUnixVolume(t *testing.T, serialize bool) UnixVolume {
13 d, err := ioutil.TempDir("", "volume_test")
17 return MakeUnixVolume(d, serialize)
20 func _teardown(v UnixVolume) {
27 // store writes a Keep block directly into a UnixVolume, for testing
28 // UnixVolume methods.
30 func _store(t *testing.T, vol UnixVolume, filename string, block []byte) {
31 blockdir := fmt.Sprintf("%s/%s", vol.root, filename[:3])
32 if err := os.MkdirAll(blockdir, 0755); err != nil {
36 blockpath := fmt.Sprintf("%s/%s", blockdir, filename)
37 if f, err := os.Create(blockpath); err == nil {
45 func TestGet(t *testing.T) {
46 v := TempUnixVolume(t, false)
48 _store(t, v, TEST_HASH, TEST_BLOCK)
50 buf, err := v.Get(TEST_HASH)
54 if bytes.Compare(buf, TEST_BLOCK) != 0 {
55 t.Errorf("expected %s, got %s", string(TEST_BLOCK), string(buf))
59 func TestGetNotFound(t *testing.T) {
60 v := TempUnixVolume(t, false)
62 _store(t, v, TEST_HASH, TEST_BLOCK)
64 buf, err := v.Get(TEST_HASH_2)
66 case os.IsNotExist(err):
69 t.Errorf("Read should have failed, returned %s", string(buf))
71 t.Errorf("Read expected ErrNotExist, got: %s", err)
75 func TestPut(t *testing.T) {
76 v := TempUnixVolume(t, false)
79 err := v.Put(TEST_HASH, TEST_BLOCK)
83 p := fmt.Sprintf("%s/%s/%s", v.root, TEST_HASH[:3], TEST_HASH)
84 if buf, err := ioutil.ReadFile(p); err != nil {
86 } else if bytes.Compare(buf, TEST_BLOCK) != 0 {
87 t.Errorf("Write should have stored %s, did store %s",
88 string(TEST_BLOCK), string(buf))
92 func TestPutBadVolume(t *testing.T) {
93 v := TempUnixVolume(t, false)
97 err := v.Put(TEST_HASH, TEST_BLOCK)
99 t.Error("Write should have failed")
103 // Serialization tests: launch a bunch of concurrent
105 // TODO(twp): show that the underlying Read/Write operations executed
106 // serially and not concurrently. The easiest way to do this is
107 // probably to activate verbose or debug logging, capture log output
108 // and examine it to confirm that Reads and Writes did not overlap.
110 // TODO(twp): a proper test of I/O serialization requires that a
111 // second request start while the first one is still underway.
112 // Guaranteeing that the test behaves this way requires some tricky
113 // synchronization and mocking. For now we'll just launch a bunch of
114 // requests simultaenously in goroutines and demonstrate that they
115 // return accurate results.
117 func TestGetSerialized(t *testing.T) {
118 // Create a volume with I/O serialization enabled.
119 v := TempUnixVolume(t, true)
122 _store(t, v, TEST_HASH, TEST_BLOCK)
123 _store(t, v, TEST_HASH_2, TEST_BLOCK_2)
124 _store(t, v, TEST_HASH_3, TEST_BLOCK_3)
126 sem := make(chan int)
127 go func(sem chan int) {
128 buf, err := v.Get(TEST_HASH)
130 t.Errorf("err1: %v", err)
132 if bytes.Compare(buf, TEST_BLOCK) != 0 {
133 t.Errorf("buf should be %s, is %s", string(TEST_BLOCK), string(buf))
138 go func(sem chan int) {
139 buf, err := v.Get(TEST_HASH_2)
141 t.Errorf("err2: %v", err)
143 if bytes.Compare(buf, TEST_BLOCK_2) != 0 {
144 t.Errorf("buf should be %s, is %s", string(TEST_BLOCK_2), string(buf))
149 go func(sem chan int) {
150 buf, err := v.Get(TEST_HASH_3)
152 t.Errorf("err3: %v", err)
154 if bytes.Compare(buf, TEST_BLOCK_3) != 0 {
155 t.Errorf("buf should be %s, is %s", string(TEST_BLOCK_3), string(buf))
160 // Wait for all goroutines to finish
161 for done := 0; done < 3; {
166 func TestPutSerialized(t *testing.T) {
167 // Create a volume with I/O serialization enabled.
168 v := TempUnixVolume(t, true)
171 sem := make(chan int)
172 go func(sem chan int) {
173 err := v.Put(TEST_HASH, TEST_BLOCK)
175 t.Errorf("err1: %v", err)
180 go func(sem chan int) {
181 err := v.Put(TEST_HASH_2, TEST_BLOCK_2)
183 t.Errorf("err2: %v", err)
188 go func(sem chan int) {
189 err := v.Put(TEST_HASH_3, TEST_BLOCK_3)
191 t.Errorf("err3: %v", err)
196 // Wait for all goroutines to finish
197 for done := 0; done < 2; {
201 // Double check that we actually wrote the blocks we expected to write.
202 buf, err := v.Get(TEST_HASH)
204 t.Errorf("Get #1: %v", err)
206 if bytes.Compare(buf, TEST_BLOCK) != 0 {
207 t.Errorf("Get #1: expected %s, got %s", string(TEST_BLOCK), string(buf))
210 buf, err = v.Get(TEST_HASH_2)
212 t.Errorf("Get #2: %v", err)
214 if bytes.Compare(buf, TEST_BLOCK_2) != 0 {
215 t.Errorf("Get #2: expected %s, got %s", string(TEST_BLOCK_2), string(buf))
218 buf, err = v.Get(TEST_HASH_3)
220 t.Errorf("Get #3: %v", err)
222 if bytes.Compare(buf, TEST_BLOCK_3) != 0 {
223 t.Errorf("Get #3: expected %s, got %s", string(TEST_BLOCK_3), string(buf))
227 func TestIsFull(t *testing.T) {
228 v := TempUnixVolume(t, false)
231 full_path := v.root + "/full"
232 now := fmt.Sprintf("%d", time.Now().Unix())
233 os.Symlink(now, full_path)
235 t.Errorf("%s: claims not to be full", v)
239 // Test with an expired /full link.
240 expired := fmt.Sprintf("%d", time.Now().Unix()-3605)
241 os.Symlink(expired, full_path)
243 t.Errorf("%s: should no longer be full", v)