7241: Add AzureBlobVolume
[arvados.git] / services / keepstore / volume_test.go
index 34dcbdc8cfb867f92147360a0eaaec647392a5c3..f272c84c837676b12cc45ad3b2e962f635e746b1 100644 (file)
@@ -1,6 +1,8 @@
 package main
 
 import (
+       "bytes"
+       "crypto/md5"
        "errors"
        "fmt"
        "io"
@@ -18,9 +20,11 @@ type TestableVolume interface {
        // [Over]write content for a locator with the given data,
        // bypassing all constraints like readonly and serialize.
        PutRaw(locator string, data []byte)
+
        // Specify the value Mtime() should return, until the next
        // call to Touch, TouchWithDate, or Put.
        TouchWithDate(locator string, lastPut time.Time)
+
        // Clean up, delete temporary files.
        Teardown()
 }
@@ -29,14 +33,18 @@ type TestableVolume interface {
 type MockVolume struct {
        Store      map[string][]byte
        Timestamps map[string]time.Time
+
        // Bad volumes return an error for every operation.
        Bad bool
+
        // Touchable volumes' Touch() method succeeds for a locator
        // that has been Put().
        Touchable bool
+
        // Readonly volumes return an error for Put, Delete, and
        // Touch.
        Readonly bool
+
        // Gate is a "starting gate", allowing test cases to pause
        // volume operations long enough to inspect state. Every
        // operation (except Status) starts by receiving from
@@ -44,7 +52,8 @@ type MockVolume struct {
        // channel unblocks all operations. By default, Gate is a
        // closed channel, so all operations proceed without
        // blocking. See trash_worker_test.go for an example.
-       Gate   chan struct{}
+       Gate chan struct{}
+
        called map[string]int
        mutex  sync.Mutex
 }
@@ -69,11 +78,11 @@ func CreateMockVolume() *MockVolume {
 func (v *MockVolume) CallCount(method string) int {
        v.mutex.Lock()
        defer v.mutex.Unlock()
-       if c, ok := v.called[method]; !ok {
+       c, ok := v.called[method]
+       if !ok {
                return 0
-       } else {
-               return c
        }
+       return c
 }
 
 func (v *MockVolume) gotCall(method string) {
@@ -86,6 +95,24 @@ func (v *MockVolume) gotCall(method string) {
        }
 }
 
+func (v *MockVolume) Compare(loc string, buf []byte) error {
+       v.gotCall("Compare")
+       <-v.Gate
+       if v.Bad {
+               return errors.New("Bad volume")
+       } else if block, ok := v.Store[loc]; ok {
+               if fmt.Sprintf("%x", md5.Sum(block)) != loc {
+                       return DiskHashError
+               }
+               if bytes.Compare(buf, block) != 0 {
+                       return CollisionError
+               }
+               return nil
+       } else {
+               return NotFoundError
+       }
+}
+
 func (v *MockVolume) Get(loc string) ([]byte, error) {
        v.gotCall("Get")
        <-v.Gate
@@ -163,7 +190,7 @@ func (v *MockVolume) Delete(loc string) error {
                return MethodDisabledError
        }
        if _, ok := v.Store[loc]; ok {
-               if time.Since(v.Timestamps[loc]) < blob_signature_ttl {
+               if time.Since(v.Timestamps[loc]) < blobSignatureTTL {
                        return nil
                }
                delete(v.Store, loc)