8555: Move checkRaceWindow out to a func, tweak comments
[arvados.git] / services / keepstore / s3_volume_test.go
1 package main
2
3 import (
4         "bytes"
5         "fmt"
6         "log"
7         "time"
8
9         "github.com/AdRoll/goamz/aws"
10         "github.com/AdRoll/goamz/s3"
11         "github.com/AdRoll/goamz/s3/s3test"
12         check "gopkg.in/check.v1"
13 )
14
15 type TestableS3Volume struct {
16         *S3Volume
17         server      *s3test.Server
18         c           *check.C
19         serverClock *fakeClock
20 }
21
22 const (
23         TestBucketName = "testbucket"
24 )
25
26 type fakeClock struct {
27         now *time.Time
28 }
29
30 func (c *fakeClock) Now() time.Time {
31         if c.now == nil {
32                 return time.Now()
33         }
34         return *c.now
35 }
36
37 func init() {
38         // Deleting isn't safe from races, but if it's turned on
39         // anyway we do expect it to pass the generic volume tests.
40         s3UnsafeDelete = true
41 }
42
43 func NewTestableS3Volume(c *check.C, raceWindow time.Duration, readonly bool, replication int) *TestableS3Volume {
44         clock := &fakeClock{}
45         srv, err := s3test.NewServer(&s3test.Config{Clock: clock})
46         c.Assert(err, check.IsNil)
47         auth := aws.Auth{}
48         region := aws.Region{
49                 Name:                 "test-region-1",
50                 S3Endpoint:           srv.URL(),
51                 S3LocationConstraint: true,
52         }
53         bucket := &s3.Bucket{
54                 S3:   s3.New(auth, region),
55                 Name: TestBucketName,
56         }
57         err = bucket.PutBucket(s3.ACL("private"))
58         c.Assert(err, check.IsNil)
59
60         return &TestableS3Volume{
61                 S3Volume:    NewS3Volume(auth, region, TestBucketName, raceWindow, readonly, replication),
62                 server:      srv,
63                 serverClock: clock,
64         }
65 }
66
67 var _ = check.Suite(&StubbedS3Suite{})
68
69 type StubbedS3Suite struct {
70         volumes []*TestableS3Volume
71 }
72
73 func (s *StubbedS3Suite) TestGeneric(c *check.C) {
74         DoGenericVolumeTests(c, func(t TB) TestableVolume {
75                 // Use a negative raceWindow so s3test's 1-second
76                 // timestamp precision doesn't confuse fixRace.
77                 return NewTestableS3Volume(c, -time.Second, false, 2)
78         })
79 }
80
81 func (s *StubbedS3Suite) TestGenericReadOnly(c *check.C) {
82         DoGenericVolumeTests(c, func(t TB) TestableVolume {
83                 return NewTestableS3Volume(c, -time.Second, true, 2)
84         })
85 }
86
87 func (s *StubbedS3Suite) TestIndex(c *check.C) {
88         v := NewTestableS3Volume(c, 0, false, 2)
89         v.indexPageSize = 3
90         for i := 0; i < 256; i++ {
91                 v.PutRaw(fmt.Sprintf("%02x%030x", i, i), []byte{102, 111, 111})
92         }
93         for _, spec := range []struct {
94                 prefix      string
95                 expectMatch int
96         }{
97                 {"", 256},
98                 {"c", 16},
99                 {"bc", 1},
100                 {"abc", 0},
101         } {
102                 buf := new(bytes.Buffer)
103                 err := v.IndexTo(spec.prefix, buf)
104                 c.Check(err, check.IsNil)
105
106                 idx := bytes.SplitAfter(buf.Bytes(), []byte{10})
107                 c.Check(len(idx), check.Equals, spec.expectMatch+1)
108                 c.Check(len(idx[len(idx)-1]), check.Equals, 0)
109         }
110 }
111
112 // PutRaw skips the ContentMD5 test
113 func (v *TestableS3Volume) PutRaw(loc string, block []byte) {
114         err := v.Bucket.Put(loc, block, "application/octet-stream", s3ACL, s3.Options{})
115         if err != nil {
116                 log.Printf("PutRaw: %+v", err)
117         }
118 }
119
120 // TouchWithDate turns back the clock while doing a Touch(). We assume
121 // there are no other operations happening on the same s3test server
122 // while we do this.
123 func (v *TestableS3Volume) TouchWithDate(locator string, lastPut time.Time) {
124         v.serverClock.now = &lastPut
125         err := v.Bucket.Put("recent/"+locator, nil, "application/octet-stream", s3ACL, s3.Options{})
126         if err != nil {
127                 panic(err)
128         }
129         v.serverClock.now = nil
130 }
131
132 func (v *TestableS3Volume) Teardown() {
133         v.server.Quit()
134 }