X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/f69d2824c997c53caa11d30ba816768bad52e12b..d07162cf2fddaafaa4ea0775d396d77f01083501:/services/keepstore/volume_test.go diff --git a/services/keepstore/volume_test.go b/services/keepstore/volume_test.go index e93bb03726..c5a7491b3d 100644 --- a/services/keepstore/volume_test.go +++ b/services/keepstore/volume_test.go @@ -3,6 +3,7 @@ package main import ( "errors" "fmt" + "io" "os" "strings" "sync" @@ -14,20 +15,30 @@ type MockVolume struct { Store map[string][]byte Timestamps map[string]time.Time // Bad volumes return an error for every operation. - Bad bool + Bad bool // Touchable volumes' Touch() method succeeds for a locator // that has been Put(). - Touchable bool + Touchable bool // Readonly volumes return an error for Put, Delete, and // Touch. - Readonly bool - called map[string]int - mutex sync.Mutex + 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 + // 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), @@ -35,6 +46,7 @@ func CreateMockVolume() *MockVolume { Touchable: true, Readonly: false, called: map[string]int{}, + Gate: gate, } } @@ -61,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") } @@ -83,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 } @@ -95,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 { @@ -107,25 +125,30 @@ func (v *MockVolume) Mtime(loc string) (time.Time, error) { return mtime, err } -func (v *MockVolume) Index(prefix string) string { - v.gotCall("Index") - var result string +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) { - result = result + fmt.Sprintf("%s+%d %d\n", - loc, len(block), 123456789) + if !IsValidLocator(loc) || !strings.HasPrefix(loc, prefix) { + continue + } + _, err := fmt.Fprintf(w, "%s+%d %d\n", + loc, len(block), 123456789) + if err != nil { + return err } } - return result + return nil } func (v *MockVolume) Delete(loc string) error { v.gotCall("Delete") + <-v.Gate if v.Readonly { return MethodDisabledError } if _, ok := v.Store[loc]; ok { - if time.Since(v.Timestamps[loc]) < permission_ttl { + if time.Since(v.Timestamps[loc]) < blob_signature_ttl { return nil } delete(v.Store, loc)