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")
104 // Test that when applying PUT to a block that already exists,
105 // the block's modification time is updated.
106 func TestPutTouch(t *testing.T) {
107 v := TempUnixVolume(t, false)
110 if err := v.Put(TEST_HASH, TEST_BLOCK); err != nil {
113 old_mtime, err := v.Mtime(TEST_HASH)
117 if old_mtime.IsZero() {
118 t.Errorf("v.Mtime(%s) returned a zero mtime\n", TEST_HASH)
120 // Sleep for 1s, then put the block again. The volume
121 // should report a more recent mtime.
123 // TODO(twp): this would be better handled with a mock Time object.
124 // Alternatively, set the mtime manually to some moment in the past
125 // (maybe a v.SetMtime method?)
127 time.Sleep(time.Second)
128 if err := v.Put(TEST_HASH, TEST_BLOCK); err != nil {
131 new_mtime, err := v.Mtime(TEST_HASH)
136 if !new_mtime.After(old_mtime) {
137 t.Errorf("v.Put did not update the block mtime:\nold_mtime = %v\nnew_mtime = %v\n",
138 old_mtime, new_mtime)
142 // Serialization tests: launch a bunch of concurrent
144 // TODO(twp): show that the underlying Read/Write operations executed
145 // serially and not concurrently. The easiest way to do this is
146 // probably to activate verbose or debug logging, capture log output
147 // and examine it to confirm that Reads and Writes did not overlap.
149 // TODO(twp): a proper test of I/O serialization requires that a
150 // second request start while the first one is still underway.
151 // Guaranteeing that the test behaves this way requires some tricky
152 // synchronization and mocking. For now we'll just launch a bunch of
153 // requests simultaenously in goroutines and demonstrate that they
154 // return accurate results.
156 func TestGetSerialized(t *testing.T) {
157 // Create a volume with I/O serialization enabled.
158 v := TempUnixVolume(t, true)
161 _store(t, v, TEST_HASH, TEST_BLOCK)
162 _store(t, v, TEST_HASH_2, TEST_BLOCK_2)
163 _store(t, v, TEST_HASH_3, TEST_BLOCK_3)
165 sem := make(chan int)
166 go func(sem chan int) {
167 buf, err := v.Get(TEST_HASH)
169 t.Errorf("err1: %v", err)
171 if bytes.Compare(buf, TEST_BLOCK) != 0 {
172 t.Errorf("buf should be %s, is %s", string(TEST_BLOCK), string(buf))
177 go func(sem chan int) {
178 buf, err := v.Get(TEST_HASH_2)
180 t.Errorf("err2: %v", err)
182 if bytes.Compare(buf, TEST_BLOCK_2) != 0 {
183 t.Errorf("buf should be %s, is %s", string(TEST_BLOCK_2), string(buf))
188 go func(sem chan int) {
189 buf, err := v.Get(TEST_HASH_3)
191 t.Errorf("err3: %v", err)
193 if bytes.Compare(buf, TEST_BLOCK_3) != 0 {
194 t.Errorf("buf should be %s, is %s", string(TEST_BLOCK_3), string(buf))
199 // Wait for all goroutines to finish
200 for done := 0; done < 3; {
205 func TestPutSerialized(t *testing.T) {
206 // Create a volume with I/O serialization enabled.
207 v := TempUnixVolume(t, true)
210 sem := make(chan int)
211 go func(sem chan int) {
212 err := v.Put(TEST_HASH, TEST_BLOCK)
214 t.Errorf("err1: %v", err)
219 go func(sem chan int) {
220 err := v.Put(TEST_HASH_2, TEST_BLOCK_2)
222 t.Errorf("err2: %v", err)
227 go func(sem chan int) {
228 err := v.Put(TEST_HASH_3, TEST_BLOCK_3)
230 t.Errorf("err3: %v", err)
235 // Wait for all goroutines to finish
236 for done := 0; done < 2; {
240 // Double check that we actually wrote the blocks we expected to write.
241 buf, err := v.Get(TEST_HASH)
243 t.Errorf("Get #1: %v", err)
245 if bytes.Compare(buf, TEST_BLOCK) != 0 {
246 t.Errorf("Get #1: expected %s, got %s", string(TEST_BLOCK), string(buf))
249 buf, err = v.Get(TEST_HASH_2)
251 t.Errorf("Get #2: %v", err)
253 if bytes.Compare(buf, TEST_BLOCK_2) != 0 {
254 t.Errorf("Get #2: expected %s, got %s", string(TEST_BLOCK_2), string(buf))
257 buf, err = v.Get(TEST_HASH_3)
259 t.Errorf("Get #3: %v", err)
261 if bytes.Compare(buf, TEST_BLOCK_3) != 0 {
262 t.Errorf("Get #3: expected %s, got %s", string(TEST_BLOCK_3), string(buf))
266 func TestIsFull(t *testing.T) {
267 v := TempUnixVolume(t, false)
270 full_path := v.root + "/full"
271 now := fmt.Sprintf("%d", time.Now().Unix())
272 os.Symlink(now, full_path)
274 t.Errorf("%s: claims not to be full", v)
278 // Test with an expired /full link.
279 expired := fmt.Sprintf("%d", time.Now().Unix()-3605)
280 os.Symlink(expired, full_path)
282 t.Errorf("%s: should no longer be full", v)