17 type TestableUnixVolume struct {
22 func NewTestableUnixVolume(t *testing.T, serialize bool, readonly bool) *TestableUnixVolume {
23 d, err := ioutil.TempDir("", "volume_test")
27 var locker sync.Locker
29 locker = &sync.Mutex{}
31 return &TestableUnixVolume{
32 UnixVolume: UnixVolume{
41 // PutRaw writes a Keep block directly into a UnixVolume, even if
42 // the volume is readonly.
43 func (v *TestableUnixVolume) PutRaw(locator string, data []byte) {
44 defer func(orig bool) {
48 err := v.Put(locator, data)
54 func (v *TestableUnixVolume) TouchWithDate(locator string, lastPut time.Time) {
55 err := syscall.Utime(v.blockPath(locator), &syscall.Utimbuf{lastPut.Unix(), lastPut.Unix()})
61 func (v *TestableUnixVolume) Teardown() {
62 if err := os.RemoveAll(v.root); err != nil {
67 func TestUnixVolumeWithGenericTests(t *testing.T) {
68 DoGenericVolumeTests(t, func(t *testing.T) TestableVolume {
69 return NewTestableUnixVolume(t, false, false)
73 func TestUnixVolumeWithGenericTestsSerialized(t *testing.T) {
74 DoGenericVolumeTests(t, func(t *testing.T) TestableVolume {
75 return NewTestableUnixVolume(t, true, false)
79 func TestUnixReadOnlyVolumeWithGenericTests(t *testing.T) {
80 DoGenericReadOnlyVolumeTests(t, func(t *testing.T) TestableVolume {
81 return NewTestableUnixVolume(t, false, true)
85 func TestUnixReadOnlyVolumeWithGenericTestsSerialized(t *testing.T) {
86 DoGenericReadOnlyVolumeTests(t, func(t *testing.T) TestableVolume {
87 return NewTestableUnixVolume(t, true, true)
91 func TestGetNotFound(t *testing.T) {
92 v := NewTestableUnixVolume(t, false, false)
94 v.Put(TEST_HASH, TEST_BLOCK)
96 buf, err := v.Get(TEST_HASH_2)
98 case os.IsNotExist(err):
101 t.Errorf("Read should have failed, returned %s", string(buf))
103 t.Errorf("Read expected ErrNotExist, got: %s", err)
107 func TestPut(t *testing.T) {
108 v := NewTestableUnixVolume(t, false, false)
111 err := v.Put(TEST_HASH, TEST_BLOCK)
115 p := fmt.Sprintf("%s/%s/%s", v.root, TEST_HASH[:3], TEST_HASH)
116 if buf, err := ioutil.ReadFile(p); err != nil {
118 } else if bytes.Compare(buf, TEST_BLOCK) != 0 {
119 t.Errorf("Write should have stored %s, did store %s",
120 string(TEST_BLOCK), string(buf))
124 func TestPutBadVolume(t *testing.T) {
125 v := NewTestableUnixVolume(t, false, false)
128 os.Chmod(v.root, 000)
129 err := v.Put(TEST_HASH, TEST_BLOCK)
131 t.Error("Write should have failed")
135 func TestUnixVolumeReadonly(t *testing.T) {
136 v := NewTestableUnixVolume(t, false, true)
139 v.PutRaw(TEST_HASH, TEST_BLOCK)
141 _, err := v.Get(TEST_HASH)
143 t.Errorf("got err %v, expected nil", err)
146 err = v.Put(TEST_HASH, TEST_BLOCK)
147 if err != MethodDisabledError {
148 t.Errorf("got err %v, expected MethodDisabledError", err)
151 err = v.Touch(TEST_HASH)
152 if err != MethodDisabledError {
153 t.Errorf("got err %v, expected MethodDisabledError", err)
156 err = v.Delete(TEST_HASH)
157 if err != MethodDisabledError {
158 t.Errorf("got err %v, expected MethodDisabledError", err)
162 func TestIsFull(t *testing.T) {
163 v := NewTestableUnixVolume(t, false, false)
166 fullPath := v.root + "/full"
167 now := fmt.Sprintf("%d", time.Now().Unix())
168 os.Symlink(now, fullPath)
170 t.Errorf("%s: claims not to be full", v)
174 // Test with an expired /full link.
175 expired := fmt.Sprintf("%d", time.Now().Unix()-3605)
176 os.Symlink(expired, fullPath)
178 t.Errorf("%s: should no longer be full", v)
182 func TestNodeStatus(t *testing.T) {
183 v := NewTestableUnixVolume(t, false, false)
186 // Get node status and make a basic sanity check.
187 volinfo := v.Status()
188 if volinfo.MountPoint != v.root {
189 t.Errorf("GetNodeStatus mount_point %s, expected %s", volinfo.MountPoint, v.root)
191 if volinfo.DeviceNum == 0 {
192 t.Errorf("uninitialized device_num in %v", volinfo)
194 if volinfo.BytesFree == 0 {
195 t.Errorf("uninitialized bytes_free in %v", volinfo)
197 if volinfo.BytesUsed == 0 {
198 t.Errorf("uninitialized bytes_used in %v", volinfo)
202 func TestUnixVolumeGetFuncWorkerError(t *testing.T) {
203 v := NewTestableUnixVolume(t, false, false)
206 v.Put(TEST_HASH, TEST_BLOCK)
207 mockErr := errors.New("Mock error")
208 err := v.getFunc(v.blockPath(TEST_HASH), func(rdr io.Reader) error {
212 t.Errorf("Got %v, expected %v", err, mockErr)
216 func TestUnixVolumeGetFuncFileError(t *testing.T) {
217 v := NewTestableUnixVolume(t, false, false)
221 err := v.getFunc(v.blockPath(TEST_HASH), func(rdr io.Reader) error {
226 t.Errorf("Expected error opening non-existent file")
229 t.Errorf("Worker func should not have been called")
233 func TestUnixVolumeGetFuncWorkerWaitsOnMutex(t *testing.T) {
234 v := NewTestableUnixVolume(t, false, false)
237 v.Put(TEST_HASH, TEST_BLOCK)
239 mtx := NewMockMutex()
242 funcCalled := make(chan struct{})
243 go v.getFunc(v.blockPath(TEST_HASH), func(rdr io.Reader) error {
244 funcCalled <- struct{}{}
248 case mtx.AllowLock <- struct{}{}:
250 t.Fatal("Function was called before mutex was acquired")
251 case <-time.After(5 * time.Second):
252 t.Fatal("Timed out before mutex was acquired")
256 case mtx.AllowUnlock <- struct{}{}:
257 t.Fatal("Mutex was released before function was called")
258 case <-time.After(5 * time.Second):
259 t.Fatal("Timed out waiting for funcCalled")
262 case mtx.AllowUnlock <- struct{}{}:
263 case <-time.After(5 * time.Second):
264 t.Fatal("Timed out waiting for getFunc() to release mutex")
268 func TestUnixVolumeCompare(t *testing.T) {
269 v := NewTestableUnixVolume(t, false, false)
272 v.Put(TEST_HASH, TEST_BLOCK)
273 err := v.Compare(TEST_HASH, TEST_BLOCK)
275 t.Errorf("Got err %q, expected nil", err)
278 err = v.Compare(TEST_HASH, []byte("baddata"))
279 if err != CollisionError {
280 t.Errorf("Got err %q, expected %q", err, CollisionError)
283 v.Put(TEST_HASH, []byte("baddata"))
284 err = v.Compare(TEST_HASH, TEST_BLOCK)
285 if err != DiskHashError {
286 t.Errorf("Got err %q, expected %q", err, DiskHashError)
289 p := fmt.Sprintf("%s/%s/%s", v.root, TEST_HASH[:3], TEST_HASH)
291 err = v.Compare(TEST_HASH, TEST_BLOCK)
292 if err == nil || strings.Index(err.Error(), "permission denied") < 0 {
293 t.Errorf("Got err %q, expected %q", err, "permission denied")
297 // TODO(twp): show that the underlying Read/Write operations executed
298 // serially and not concurrently. The easiest way to do this is
299 // probably to activate verbose or debug logging, capture log output
300 // and examine it to confirm that Reads and Writes did not overlap.
302 // TODO(twp): a proper test of I/O serialization requires that a
303 // second request start while the first one is still underway.
304 // Guaranteeing that the test behaves this way requires some tricky
305 // synchronization and mocking. For now we'll just launch a bunch of
306 // requests simultaenously in goroutines and demonstrate that they
307 // return accurate results.