Merge branch '6997-keepstore-mem' refs #6997
[arvados.git] / services / keepstore / volume_test.go
index 66e0810c972a86c59603f3ab40498e264081072a..c5a7491b3d542951983ad67e7eec29baa972f966 100644 (file)
@@ -22,13 +22,23 @@ type MockVolume struct {
        // Readonly volumes return an error for Put, Delete, and
        // Touch.
        Readonly bool
-       called   map[string]int
-       mutex    sync.Mutex
+       // 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
+       // Gate. Sending one value unblocks one operation; closing the
+       // 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{}
+       called map[string]int
+       mutex  sync.Mutex
 }
 
 // CreateMockVolume returns a non-Bad, non-Readonly, Touchable mock
 // volume.
 func CreateMockVolume() *MockVolume {
+       gate := make(chan struct{})
+       close(gate)
        return &MockVolume{
                Store:      make(map[string][]byte),
                Timestamps: make(map[string]time.Time),
@@ -36,6 +46,7 @@ func CreateMockVolume() *MockVolume {
                Touchable:  true,
                Readonly:   false,
                called:     map[string]int{},
+               Gate:       gate,
        }
 }
 
@@ -62,16 +73,20 @@ func (v *MockVolume) gotCall(method string) {
 
 func (v *MockVolume) Get(loc string) ([]byte, error) {
        v.gotCall("Get")
+       <-v.Gate
        if v.Bad {
                return nil, errors.New("Bad volume")
        } else if block, ok := v.Store[loc]; ok {
-               return block, nil
+               buf := bufs.Get(len(block))
+               copy(buf, block)
+               return buf, nil
        }
        return nil, os.ErrNotExist
 }
 
 func (v *MockVolume) Put(loc string, block []byte) error {
        v.gotCall("Put")
+       <-v.Gate
        if v.Bad {
                return errors.New("Bad volume")
        }
@@ -84,6 +99,7 @@ func (v *MockVolume) Put(loc string, block []byte) error {
 
 func (v *MockVolume) Touch(loc string) error {
        v.gotCall("Touch")
+       <-v.Gate
        if v.Readonly {
                return MethodDisabledError
        }
@@ -96,6 +112,7 @@ func (v *MockVolume) Touch(loc string) error {
 
 func (v *MockVolume) Mtime(loc string) (time.Time, error) {
        v.gotCall("Mtime")
+       <-v.Gate
        var mtime time.Time
        var err error
        if v.Bad {
@@ -110,6 +127,7 @@ func (v *MockVolume) Mtime(loc string) (time.Time, error) {
 
 func (v *MockVolume) IndexTo(prefix string, w io.Writer) error {
        v.gotCall("IndexTo")
+       <-v.Gate
        for loc, block := range v.Store {
                if !IsValidLocator(loc) || !strings.HasPrefix(loc, prefix) {
                        continue
@@ -125,6 +143,7 @@ func (v *MockVolume) IndexTo(prefix string, w io.Writer) error {
 
 func (v *MockVolume) Delete(loc string) error {
        v.gotCall("Delete")
+       <-v.Gate
        if v.Readonly {
                return MethodDisabledError
        }