Merge lp:~niemeyer/goamz/testing-cleanup into lp:~gophers/goamz/trunk

Proposed by Gustavo Niemeyer
Status: Merged
Merged at revision: 27
Proposed branch: lp:~niemeyer/goamz/testing-cleanup
Merge into: lp:~gophers/goamz/trunk
Diff against target: 2514 lines (+427/-1143)
27 files modified
aws/aws_test.go (+5/-0)
aws/suite_test.go (+0/-139)
ec2/ec2.go (+17/-17)
ec2/ec2_test.go (+38/-27)
ec2/ec2i_test.go (+2/-4)
ec2/ec2t_test.go (+5/-8)
ec2/ec2test/filter.go (+2/-2)
ec2/ec2test/server.go (+12/-12)
ec2/sign.go (+4/-4)
ec2/suite_test.go (+0/-118)
exp/mturk/mturk.go (+5/-5)
exp/mturk/mturk_test.go (+15/-4)
exp/mturk/suite_test.go (+0/-120)
exp/sdb/sdb.go (+3/-3)
exp/sdb/sdb_test.go (+21/-10)
exp/sdb/suite_test.go (+0/-139)
exp/sns/sns_test.go (+13/-2)
exp/sns/suite_test.go (+0/-200)
iam/iam_test.go (+18/-7)
iam/iami_test.go (+2/-4)
iam/suite_test.go (+0/-128)
s3/s3.go (+18/-13)
s3/s3_test.go (+25/-14)
s3/s3i_test.go (+18/-24)
s3/suite_test.go (+0/-139)
testutil/http.go (+174/-0)
testutil/suite.go (+30/-0)
To merge this branch: bzr merge lp:~niemeyer/goamz/testing-cleanup
Reviewer Review Type Date Requested Status
The Go Language Gophers Pending
Review via email: mp+145878@code.launchpad.net

Description of the change

testutil: new package for test clean up

Killed all the repetition in suite_test files, and improved the
implementation of the test HTTP server.

A few test bugs were also fixed on the way.

https://codereview.appspot.com/7232065/

To post a comment you must log in.
Revision history for this message
Gustavo Niemeyer (niemeyer) wrote :

Reviewers: mp+145878_code.launchpad.net,

Message:
Please take a look.

Description:
testutil: new package for test clean up

Killed all the repetition in suite_test files, and improved the
implementation of the test HTTP server.

A few test bugs were also fixed on the way.

https://code.launchpad.net/~niemeyer/goamz/testing-cleanup/+merge/145878

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/7232065/

Affected files:
   A [revision details]
   M aws/aws_test.go
   D aws/suite_test.go
   M ec2/ec2.go
   M ec2/ec2_test.go
   M ec2/ec2i_test.go
   M ec2/ec2t_test.go
   M ec2/ec2test/filter.go
   M ec2/ec2test/server.go
   M ec2/sign.go
   D ec2/suite_test.go
   M exp/mturk/mturk.go
   M exp/mturk/mturk_test.go
   D exp/mturk/suite_test.go
   M exp/sdb/sdb.go
   M exp/sdb/sdb_test.go
   D exp/sdb/suite_test.go
   M exp/sns/sns_test.go
   D exp/sns/suite_test.go
   M iam/iam_test.go
   M iam/iami_test.go
   D iam/suite_test.go
   M s3/s3.go
   M s3/s3_test.go
   M s3/s3i_test.go
   D s3/suite_test.go
   A testutil/http.go
   A testutil/suite.go

Revision history for this message
Roger Peppe (rogpeppe) wrote :

LGTM except for the query about the default security group test.

nice to see all that code factored out.

https://codereview.appspot.com/7232065/diff/1/ec2/ec2_test.go
File ec2/ec2_test.go (right):

https://codereview.appspot.com/7232065/diff/1/ec2/ec2_test.go#newcode24
ec2/ec2_test.go:24: testServer.Start()
that makes much more sense, given we're using the global below.

https://codereview.appspot.com/7232065/diff/1/ec2/ec2t_test.go
File ec2/ec2t_test.go (right):

https://codereview.appspot.com/7232065/diff/1/ec2/ec2t_test.go#newcode447
ec2/ec2t_test.go:447: //resp, err :=
s.ec2.SecurityGroups([]ec2.SecurityGroup{{Name: "default"}}, nil)
why commented out? this was testing specific ec2test functionality.

have you tried these tests live? i seem to remember that
i needed to add the "default" group because it was
being returned for some of the filtering requests.

https://codereview.appspot.com/7232065/diff/1/ec2/ec2test/server.go
File ec2/ec2test/server.go (right):

https://codereview.appspot.com/7232065/diff/1/ec2/ec2test/server.go#newcode420
ec2/ec2test/server.go:420: // ImageId: accept anything, we can verify
later
align?
(and below)

https://codereview.appspot.com/7232065/diff/1/ec2/sign.go
File ec2/sign.go (right):

https://codereview.appspot.com/7232065/diff/1/ec2/sign.go#newcode23
ec2/sign.go:23: // be in natural order of the keys. This is distinct
from the
s/in natural/in the natural/
?

https://codereview.appspot.com/7232065/diff/1/exp/mturk/suite_test.go
File exp/mturk/suite_test.go (left):

https://codereview.appspot.com/7232065/diff/1/exp/mturk/suite_test.go#oldcode1
exp/mturk/suite_test.go:1: package mturk_test
great to see all this duplication go away.

https://codereview.appspot.com/7232065/diff/1/s3/s3.go
File s3/s3.go (right):

https://codereview.appspot.com/7232065/diff/1/s3/s3.go#newcode231
s3/s3.go:231: // into different groupings of keys, similar to how
folders would work.
s/would// ?

https://codereview.appspot.com/7232065/

Revision history for this message
Gustavo Niemeyer (niemeyer) wrote :

https://codereview.appspot.com/7232065/diff/1/ec2/ec2t_test.go
File ec2/ec2t_test.go (right):

https://codereview.appspot.com/7232065/diff/1/ec2/ec2t_test.go#newcode447
ec2/ec2t_test.go:447: //resp, err :=
s.ec2.SecurityGroups([]ec2.SecurityGroup{{Name: "default"}}, nil)
On 2013/01/31 15:42:43, rog wrote:
> why commented out? this was testing specific ec2test functionality.

Sorry, it shouldn't be commented out. It should be removed. There's
nothing special about the default group, and the test is broken because
it trusts the system to only have a single group named default, which is
not a given.

> have you tried these tests live? i seem to remember that
> i needed to add the "default" group because it was
> being returned for some of the filtering requests.

Yeah, it was testing it live that forced me to fix it.

https://codereview.appspot.com/7232065/

Revision history for this message
Roger Peppe (rogpeppe) wrote :

On 31 January 2013 15:58, <email address hidden> wrote:
>
> https://codereview.appspot.com/7232065/diff/1/ec2/ec2t_test.go
> File ec2/ec2t_test.go (right):
>
> https://codereview.appspot.com/7232065/diff/1/ec2/ec2t_test.go#newcode447
> ec2/ec2t_test.go:447: //resp, err :=
> s.ec2.SecurityGroups([]ec2.SecurityGroup{{Name: "default"}}, nil)
> On 2013/01/31 15:42:43, rog wrote:
>>
>> why commented out? this was testing specific ec2test functionality.
>
>
> Sorry, it shouldn't be commented out. It should be removed. There's
> nothing special about the default group, and the test is broken because
> it trusts the system to only have a single group named default, which is
> not a given.

The default is created by automatically, can't be removed, and has
default permissions
set up for tcp and udp (which means that it gets selected by some of
the filters)

if you try to create another group called "default", you get a
"The security group 'default' is reserved" error.

That seems fairly special to me - I *think* we're always guaranteed
a single group named default... but maybe that's only true of us-east.

How did the test fail for you? I'd definitely like to understand more about
the problem before changing those tests.

Revision history for this message
Gustavo Niemeyer (niemeyer) wrote :

On 2013/01/31 17:01:29, rog wrote:
> The default is created by automatically, can't be removed, and has
> default permissions set up for tcp and udp (which means that it
> gets selected by some of the filters)

None of that seems relevant for filtering.

> if you try to create another group called "default", you get a
> "The security group 'default' is reserved" error.

I have two groups named "default" in my account, and that's breaking the
test case. One of them comes from VPC. Amazon created it.

> That seems fairly special to me - I *think* we're always guaranteed
> a single group named default... but maybe that's only true of us-east.

I'm not lying, promise.

https://codereview.appspot.com/7232065/

lp:~niemeyer/goamz/testing-cleanup updated
28. By Gustavo Niemeyer

Review by Roger.

Revision history for this message
Gustavo Niemeyer (niemeyer) wrote :

Please take a look.

https://codereview.appspot.com/7232065/diff/1/ec2/ec2test/server.go
File ec2/ec2test/server.go (right):

https://codereview.appspot.com/7232065/diff/1/ec2/ec2test/server.go#newcode420
ec2/ec2test/server.go:420: // ImageId: accept anything, we can verify
later
On 2013/01/31 15:42:43, rog wrote:
> align?
> (and below)

Done.

https://codereview.appspot.com/7232065/diff/1/ec2/sign.go
File ec2/sign.go (right):

https://codereview.appspot.com/7232065/diff/1/ec2/sign.go#newcode23
ec2/sign.go:23: // be in natural order of the keys. This is distinct
from the
On 2013/01/31 15:42:43, rog wrote:
> s/in natural/in the natural/
> ?

Done.

https://codereview.appspot.com/7232065/diff/1/s3/s3.go
File s3/s3.go (right):

https://codereview.appspot.com/7232065/diff/1/s3/s3.go#newcode231
s3/s3.go:231: // into different groupings of keys, similar to how
folders would work.
On 2013/01/31 15:42:43, rog wrote:
> s/would// ?

That's how they would work if S3 used the concept of folders. It
doesn't, so it doesn't work quite that way.

https://codereview.appspot.com/7232065/

Revision history for this message
Gustavo Niemeyer (niemeyer) wrote :

*** Submitted:

testutil: new package for test clean up

Killed all the repetition in suite_test files, and improved the
implementation of the test HTTP server.

A few test bugs were also fixed on the way.

R=rog
CC=
https://codereview.appspot.com/7232065

https://codereview.appspot.com/7232065/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'aws/aws_test.go'
--- aws/aws_test.go 2012-07-02 23:36:49 +0000
+++ aws/aws_test.go 2013-01-31 17:09:20 +0000
@@ -5,8 +5,13 @@
5 . "launchpad.net/gocheck"5 . "launchpad.net/gocheck"
6 "os"6 "os"
7 "strings"7 "strings"
8 "testing"
8)9)
910
11func Test(t *testing.T) {
12 TestingT(t)
13}
14
10var _ = Suite(&S{})15var _ = Suite(&S{})
1116
12type S struct {17type S struct {
1318
=== removed file 'aws/suite_test.go'
--- aws/suite_test.go 2012-05-03 17:12:28 +0000
+++ aws/suite_test.go 1970-01-01 00:00:00 +0000
@@ -1,139 +0,0 @@
1package aws_test
2
3import (
4 "flag"
5 "fmt"
6 "launchpad.net/goamz/aws"
7 . "launchpad.net/gocheck"
8 "net/http"
9 "net/url"
10 "os"
11 "testing"
12 "time"
13)
14
15func Test(t *testing.T) {
16 TestingT(t)
17}
18
19var integration = flag.Bool("i", false, "Enable integration tests")
20
21type SuiteI struct {
22 auth aws.Auth
23}
24
25func (s *SuiteI) SetUpSuite(c *C) {
26 if !*integration {
27 c.Skip("Integration tests not enabled (-int flag)")
28 }
29 auth, err := aws.EnvAuth()
30 if err != nil {
31 c.Fatal(err)
32 }
33 s.auth = auth
34}
35
36type HTTPSuite struct{}
37
38var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
39
40func (s *HTTPSuite) SetUpSuite(c *C) {
41 testServer.Start()
42}
43
44func (s *HTTPSuite) TearDownTest(c *C) {
45 testServer.FlushRequests()
46}
47
48type TestHTTPServer struct {
49 URL string
50 Timeout time.Duration
51 started bool
52 request chan *http.Request
53 response chan *testResponse
54 pending chan bool
55}
56
57type testResponse struct {
58 Status int
59 Headers map[string]string
60 Body string
61}
62
63func NewTestHTTPServer(url_ string, timeout time.Duration) *TestHTTPServer {
64 return &TestHTTPServer{URL: url_, Timeout: timeout}
65}
66
67func (s *TestHTTPServer) Start() {
68 if s.started {
69 return
70 }
71 s.started = true
72
73 s.request = make(chan *http.Request, 64)
74 s.response = make(chan *testResponse, 64)
75 s.pending = make(chan bool, 64)
76
77 url, _ := url.Parse(s.URL)
78 go http.ListenAndServe(url.Host, s)
79
80 s.PrepareResponse(123, nil, "")
81 for {
82 // Wait for it to be up.
83 resp, err := http.Get(s.URL)
84 if err == nil && resp.StatusCode == 123 {
85 break
86 }
87 fmt.Fprintf(os.Stderr, "\nWaiting for fake server to be up... ")
88 time.Sleep(1e8)
89 }
90 fmt.Fprintf(os.Stderr, "done\n\n")
91 s.WaitRequest() // Consume dummy request.
92}
93
94// FlushRequests discards requests which were not yet consumed by WaitRequest.
95func (s *TestHTTPServer) FlushRequests() {
96 for {
97 select {
98 case <-s.request:
99 default:
100 return
101 }
102 }
103}
104
105func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
106 s.request <- req
107 var resp *testResponse
108 select {
109 case resp = <-s.response:
110 case <-time.After(s.Timeout):
111 fmt.Fprintf(os.Stderr, "ERROR: Timeout waiting for test to provide response\n")
112 resp = &testResponse{500, nil, ""}
113 }
114 h := w.Header()
115 if resp.Headers != nil {
116 for k, v := range resp.Headers {
117 h.Set(k, v)
118 }
119 }
120 if resp.Status != 0 {
121 w.WriteHeader(resp.Status)
122 }
123 w.Write([]byte(resp.Body))
124}
125
126func (s *TestHTTPServer) WaitRequest() *http.Request {
127 select {
128 case req := <-s.request:
129 req.ParseForm()
130 return req
131 case <-time.After(s.Timeout):
132 panic("Timeout waiting for goamz request")
133 }
134 panic("unreached")
135}
136
137func (s *TestHTTPServer) PrepareResponse(status int, headers map[string]string, body string) {
138 s.response <- &testResponse{status, headers, body}
139}
1400
=== modified file 'ec2/ec2.go'
--- ec2/ec2.go 2012-10-28 16:05:46 +0000
+++ ec2/ec2.go 2013-01-31 17:09:20 +0000
@@ -86,7 +86,7 @@
86// ----------------------------------------------------------------------------86// ----------------------------------------------------------------------------
87// Request dispatching logic.87// Request dispatching logic.
8888
89// Error encapsulates an error returned by EC2. 89// Error encapsulates an error returned by EC2.
90//90//
91// See http://goo.gl/VZGuC for more details.91// See http://goo.gl/VZGuC for more details.
92type Error struct {92type Error struct {
@@ -425,15 +425,15 @@
425//425//
426// See http://goo.gl/wnDBf for more details.426// See http://goo.gl/wnDBf for more details.
427type BlockDeviceMapping struct {427type BlockDeviceMapping struct {
428 DeviceName string `xml:"deviceName"`428 DeviceName string `xml:"deviceName"`
429 VirtualName string `xml:"virtualName"`429 VirtualName string `xml:"virtualName"`
430 SnapshotId string `xml:"ebs>snapshotId"`430 SnapshotId string `xml:"ebs>snapshotId"`
431 VolumeType string `xml:"ebs>volumeType"`431 VolumeType string `xml:"ebs>volumeType"`
432 VolumeSize int64 `xml:"ebs>volumeSize"`432 VolumeSize int64 `xml:"ebs>volumeSize"`
433 DeleteOnTermination bool `xml:"ebs>deleteOnTermination"`433 DeleteOnTermination bool `xml:"ebs>deleteOnTermination"`
434434
435 // The number of I/O operations per second (IOPS) that the volume supports.435 // The number of I/O operations per second (IOPS) that the volume supports.
436 IOPS int64 `xml:"ebs>iops"`436 IOPS int64 `xml:"ebs>iops"`
437}437}
438438
439// Image represents details about an image.439// Image represents details about an image.
@@ -467,7 +467,7 @@
467// For example, to get all the private images associated with this account set467// For example, to get all the private images associated with this account set
468// the boolean filter "is-private" to true.468// the boolean filter "is-private" to true.
469//469//
470// Note: calling this function with nil ids and filter parameters will result in 470// Note: calling this function with nil ids and filter parameters will result in
471// a very large number of images being returned.471// a very large number of images being returned.
472//472//
473// See http://goo.gl/SRBhW for more details.473// See http://goo.gl/SRBhW for more details.
@@ -512,11 +512,11 @@
512512
513// DeleteSnapshots deletes the volume snapshots with the given ids.513// DeleteSnapshots deletes the volume snapshots with the given ids.
514//514//
515// Note: If you make periodic snapshots of a volume, the snapshots are 515// Note: If you make periodic snapshots of a volume, the snapshots are
516// incremental so that only the blocks on the device that have changed 516// incremental so that only the blocks on the device that have changed
517// since your last snapshot are incrementally saved in the new snapshot. 517// since your last snapshot are incrementally saved in the new snapshot.
518// Even though snapshots are saved incrementally, the snapshot deletion 518// Even though snapshots are saved incrementally, the snapshot deletion
519// process is designed so that you need to retain only the most recent 519// process is designed so that you need to retain only the most recent
520// snapshot in order to restore the volume.520// snapshot in order to restore the volume.
521//521//
522// See http://goo.gl/vwU1y for more details.522// See http://goo.gl/vwU1y for more details.
@@ -558,7 +558,7 @@
558 Tags []Tag `xml:"tagSet>item"`558 Tags []Tag `xml:"tagSet>item"`
559}559}
560560
561// Snapshots returns details about volume snapshots available to the user. 561// Snapshots returns details about volume snapshots available to the user.
562// The ids and filter parameters, if provided, limit the snapshots returned.562// The ids and filter parameters, if provided, limit the snapshots returned.
563//563//
564// See http://goo.gl/ogJL4 for more details.564// See http://goo.gl/ogJL4 for more details.
@@ -620,7 +620,7 @@
620 Groups []SecurityGroupInfo `xml:"securityGroupInfo>item"`620 Groups []SecurityGroupInfo `xml:"securityGroupInfo>item"`
621}621}
622622
623// SecurityGroup encapsulates details for a security group in EC2. 623// SecurityGroup encapsulates details for a security group in EC2.
624//624//
625// See http://goo.gl/CIdyP for more details.625// See http://goo.gl/CIdyP for more details.
626type SecurityGroupInfo struct {626type SecurityGroupInfo struct {
@@ -785,7 +785,7 @@
785}785}
786786
787// CreateTags adds or overwrites one or more tags for the specified instance ids.787// CreateTags adds or overwrites one or more tags for the specified instance ids.
788// 788//
789// See http://goo.gl/Vmkqc for more details789// See http://goo.gl/Vmkqc for more details
790func (ec2 *EC2) CreateTags(instIds []string, tags []Tag) (resp *SimpleResp, err error) {790func (ec2 *EC2) CreateTags(instIds []string, tags []Tag) (resp *SimpleResp, err error) {
791 params := makeParams("CreateTags")791 params := makeParams("CreateTags")
792792
=== modified file 'ec2/ec2_test.go'
--- ec2/ec2_test.go 2012-10-18 18:56:09 +0000
+++ ec2/ec2_test.go 2013-01-31 17:09:20 +0000
@@ -3,24 +3,35 @@
3import (3import (
4 "launchpad.net/goamz/aws"4 "launchpad.net/goamz/aws"
5 "launchpad.net/goamz/ec2"5 "launchpad.net/goamz/ec2"
6 "launchpad.net/goamz/testutil"
6 . "launchpad.net/gocheck"7 . "launchpad.net/gocheck"
8 "testing"
7)9)
810
11func Test(t *testing.T) {
12 TestingT(t)
13}
14
9var _ = Suite(&S{})15var _ = Suite(&S{})
1016
11type S struct {17type S struct {
12 HTTPSuite
13 ec2 *ec2.EC218 ec2 *ec2.EC2
14}19}
1520
21var testServer = testutil.NewHTTPServer()
22
16func (s *S) SetUpSuite(c *C) {23func (s *S) SetUpSuite(c *C) {
17 s.HTTPSuite.SetUpSuite(c)24 testServer.Start()
18 auth := aws.Auth{"abc", "123"}25 auth := aws.Auth{"abc", "123"}
19 s.ec2 = ec2.New(auth, aws.Region{EC2Endpoint: testServer.URL})26 s.ec2 = ec2.New(auth, aws.Region{EC2Endpoint: testServer.URL})
20}27}
2128
29func (s *S) TearDownTest(c *C) {
30 testServer.Flush()
31}
32
22func (s *S) TestRunInstancesErrorDump(c *C) {33func (s *S) TestRunInstancesErrorDump(c *C) {
23 testServer.PrepareResponse(400, nil, ErrorDump)34 testServer.Response(400, nil, ErrorDump)
2435
25 options := ec2.RunInstances{36 options := ec2.RunInstances{
26 ImageId: "ami-a6f504cf", // Ubuntu Maverick, i386, instance store37 ImageId: "ami-a6f504cf", // Ubuntu Maverick, i386, instance store
@@ -45,7 +56,7 @@
45}56}
4657
47func (s *S) TestRunInstancesErrorWithoutXML(c *C) {58func (s *S) TestRunInstancesErrorWithoutXML(c *C) {
48 testServer.PrepareResponse(500, nil, "")59 testServer.Response(500, nil, "")
49 options := ec2.RunInstances{ImageId: "image-id"}60 options := ec2.RunInstances{ImageId: "image-id"}
5061
51 resp, err := s.ec2.RunInstances(&options)62 resp, err := s.ec2.RunInstances(&options)
@@ -64,7 +75,7 @@
64}75}
6576
66func (s *S) TestRunInstancesExample(c *C) {77func (s *S) TestRunInstancesExample(c *C) {
67 testServer.PrepareResponse(200, nil, RunInstancesExample)78 testServer.Response(200, nil, RunInstancesExample)
6879
69 options := ec2.RunInstances{80 options := ec2.RunInstances{
70 KeyName: "my-keys",81 KeyName: "my-keys",
@@ -145,7 +156,7 @@
145}156}
146157
147func (s *S) TestTerminateInstancesExample(c *C) {158func (s *S) TestTerminateInstancesExample(c *C) {
148 testServer.PrepareResponse(200, nil, TerminateInstancesExample)159 testServer.Response(200, nil, TerminateInstancesExample)
149160
150 resp, err := s.ec2.TerminateInstances([]string{"i-1", "i-2"})161 resp, err := s.ec2.TerminateInstances([]string{"i-1", "i-2"})
151162
@@ -175,7 +186,7 @@
175}186}
176187
177func (s *S) TestDescribeInstancesExample1(c *C) {188func (s *S) TestDescribeInstancesExample1(c *C) {
178 testServer.PrepareResponse(200, nil, DescribeInstancesExample1)189 testServer.Response(200, nil, DescribeInstancesExample1)
179190
180 filter := ec2.NewFilter()191 filter := ec2.NewFilter()
181 filter.Add("key1", "value1")192 filter.Add("key1", "value1")
@@ -207,7 +218,7 @@
207}218}
208219
209func (s *S) TestDescribeInstancesExample2(c *C) {220func (s *S) TestDescribeInstancesExample2(c *C) {
210 testServer.PrepareResponse(200, nil, DescribeInstancesExample2)221 testServer.Response(200, nil, DescribeInstancesExample2)
211222
212 filter := ec2.NewFilter()223 filter := ec2.NewFilter()
213 filter.Add("key1", "value1")224 filter.Add("key1", "value1")
@@ -244,7 +255,7 @@
244}255}
245256
246func (s *S) TestDescribeImagesExample(c *C) {257func (s *S) TestDescribeImagesExample(c *C) {
247 testServer.PrepareResponse(200, nil, DescribeImagesExample)258 testServer.Response(200, nil, DescribeImagesExample)
248259
249 filter := ec2.NewFilter()260 filter := ec2.NewFilter()
250 filter.Add("key1", "value1")261 filter.Add("key1", "value1")
@@ -292,7 +303,7 @@
292}303}
293304
294func (s *S) TestCreateSnapshotExample(c *C) {305func (s *S) TestCreateSnapshotExample(c *C) {
295 testServer.PrepareResponse(200, nil, CreateSnapshotExample)306 testServer.Response(200, nil, CreateSnapshotExample)
296307
297 resp, err := s.ec2.CreateSnapshot("vol-4d826724", "Daily Backup")308 resp, err := s.ec2.CreateSnapshot("vol-4d826724", "Daily Backup")
298309
@@ -314,7 +325,7 @@
314}325}
315326
316func (s *S) TestDeleteSnapshotsExample(c *C) {327func (s *S) TestDeleteSnapshotsExample(c *C) {
317 testServer.PrepareResponse(200, nil, DeleteSnapshotExample)328 testServer.Response(200, nil, DeleteSnapshotExample)
318329
319 resp, err := s.ec2.DeleteSnapshots([]string{"snap-78a54011"})330 resp, err := s.ec2.DeleteSnapshots([]string{"snap-78a54011"})
320331
@@ -327,7 +338,7 @@
327}338}
328339
329func (s *S) TestDescribeSnapshotsExample(c *C) {340func (s *S) TestDescribeSnapshotsExample(c *C) {
330 testServer.PrepareResponse(200, nil, DescribeSnapshotsExample)341 testServer.Response(200, nil, DescribeSnapshotsExample)
331342
332 filter := ec2.NewFilter()343 filter := ec2.NewFilter()
333 filter.Add("key1", "value1")344 filter.Add("key1", "value1")
@@ -366,7 +377,7 @@
366}377}
367378
368func (s *S) TestCreateSecurityGroupExample(c *C) {379func (s *S) TestCreateSecurityGroupExample(c *C) {
369 testServer.PrepareResponse(200, nil, CreateSecurityGroupExample)380 testServer.Response(200, nil, CreateSecurityGroupExample)
370381
371 resp, err := s.ec2.CreateSecurityGroup("websrv", "Web Servers")382 resp, err := s.ec2.CreateSecurityGroup("websrv", "Web Servers")
372383
@@ -382,7 +393,7 @@
382}393}
383394
384func (s *S) TestDescribeSecurityGroupsExample(c *C) {395func (s *S) TestDescribeSecurityGroupsExample(c *C) {
385 testServer.PrepareResponse(200, nil, DescribeSecurityGroupsExample)396 testServer.Response(200, nil, DescribeSecurityGroupsExample)
386397
387 resp, err := s.ec2.SecurityGroups([]ec2.SecurityGroup{{Name: "WebServers"}, {Name: "RangedPortsBySource"}}, nil)398 resp, err := s.ec2.SecurityGroups([]ec2.SecurityGroup{{Name: "WebServers"}, {Name: "RangedPortsBySource"}}, nil)
388399
@@ -423,7 +434,7 @@
423}434}
424435
425func (s *S) TestDescribeSecurityGroupsExampleWithFilter(c *C) {436func (s *S) TestDescribeSecurityGroupsExampleWithFilter(c *C) {
426 testServer.PrepareResponse(200, nil, DescribeSecurityGroupsExample)437 testServer.Response(200, nil, DescribeSecurityGroupsExample)
427438
428 filter := ec2.NewFilter()439 filter := ec2.NewFilter()
429 filter.Add("ip-permission.protocol", "tcp")440 filter.Add("ip-permission.protocol", "tcp")
@@ -449,7 +460,7 @@
449}460}
450461
451func (s *S) TestDescribeSecurityGroupsDumpWithGroup(c *C) {462func (s *S) TestDescribeSecurityGroupsDumpWithGroup(c *C) {
452 testServer.PrepareResponse(200, nil, DescribeSecurityGroupsDump)463 testServer.Response(200, nil, DescribeSecurityGroupsDump)
453464
454 resp, err := s.ec2.SecurityGroups(nil, nil)465 resp, err := s.ec2.SecurityGroups(nil, nil)
455466
@@ -477,7 +488,7 @@
477}488}
478489
479func (s *S) TestDeleteSecurityGroupExample(c *C) {490func (s *S) TestDeleteSecurityGroupExample(c *C) {
480 testServer.PrepareResponse(200, nil, DeleteSecurityGroupExample)491 testServer.Response(200, nil, DeleteSecurityGroupExample)
481492
482 resp, err := s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: "websrv"})493 resp, err := s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: "websrv"})
483 req := testServer.WaitRequest()494 req := testServer.WaitRequest()
@@ -490,7 +501,7 @@
490}501}
491502
492func (s *S) TestDeleteSecurityGroupExampleWithId(c *C) {503func (s *S) TestDeleteSecurityGroupExampleWithId(c *C) {
493 testServer.PrepareResponse(200, nil, DeleteSecurityGroupExample)504 testServer.Response(200, nil, DeleteSecurityGroupExample)
494505
495 // ignore return and error - we're only want to check the parameter handling.506 // ignore return and error - we're only want to check the parameter handling.
496 s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Id: "sg-67ad940e", Name: "ignored"})507 s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Id: "sg-67ad940e", Name: "ignored"})
@@ -501,7 +512,7 @@
501}512}
502513
503func (s *S) TestAuthorizeSecurityGroupExample1(c *C) {514func (s *S) TestAuthorizeSecurityGroupExample1(c *C) {
504 testServer.PrepareResponse(200, nil, AuthorizeSecurityGroupIngressExample)515 testServer.Response(200, nil, AuthorizeSecurityGroupIngressExample)
505516
506 perms := []ec2.IPPerm{{517 perms := []ec2.IPPerm{{
507 Protocol: "tcp",518 Protocol: "tcp",
@@ -526,7 +537,7 @@
526}537}
527538
528func (s *S) TestAuthorizeSecurityGroupExample1WithId(c *C) {539func (s *S) TestAuthorizeSecurityGroupExample1WithId(c *C) {
529 testServer.PrepareResponse(200, nil, AuthorizeSecurityGroupIngressExample)540 testServer.Response(200, nil, AuthorizeSecurityGroupIngressExample)
530541
531 perms := []ec2.IPPerm{{542 perms := []ec2.IPPerm{{
532 Protocol: "tcp",543 Protocol: "tcp",
@@ -544,7 +555,7 @@
544}555}
545556
546func (s *S) TestAuthorizeSecurityGroupExample2(c *C) {557func (s *S) TestAuthorizeSecurityGroupExample2(c *C) {
547 testServer.PrepareResponse(200, nil, AuthorizeSecurityGroupIngressExample)558 testServer.Response(200, nil, AuthorizeSecurityGroupIngressExample)
548559
549 perms := []ec2.IPPerm{{560 perms := []ec2.IPPerm{{
550 Protocol: "tcp",561 Protocol: "tcp",
@@ -577,7 +588,7 @@
577func (s *S) TestRevokeSecurityGroupExample(c *C) {588func (s *S) TestRevokeSecurityGroupExample(c *C) {
578 // RevokeSecurityGroup is implemented by the same code as AuthorizeSecurityGroup589 // RevokeSecurityGroup is implemented by the same code as AuthorizeSecurityGroup
579 // so there's no need to duplicate all the tests.590 // so there's no need to duplicate all the tests.
580 testServer.PrepareResponse(200, nil, RevokeSecurityGroupIngressExample)591 testServer.Response(200, nil, RevokeSecurityGroupIngressExample)
581592
582 resp, err := s.ec2.RevokeSecurityGroup(ec2.SecurityGroup{Name: "websrv"}, nil)593 resp, err := s.ec2.RevokeSecurityGroup(ec2.SecurityGroup{Name: "websrv"}, nil)
583594
@@ -590,7 +601,7 @@
590}601}
591602
592func (s *S) TestCreateTags(c *C) {603func (s *S) TestCreateTags(c *C) {
593 testServer.PrepareResponse(200, nil, CreateTagsExample)604 testServer.Response(200, nil, CreateTagsExample)
594605
595 resp, err := s.ec2.CreateTags([]string{"ami-1a2b3c4d", "i-7f4d3a2b"}, []ec2.Tag{{"webserver", ""}, {"stack", "Production"}})606 resp, err := s.ec2.CreateTags([]string{"ami-1a2b3c4d", "i-7f4d3a2b"}, []ec2.Tag{{"webserver", ""}, {"stack", "Production"}})
596607
@@ -607,7 +618,7 @@
607}618}
608619
609func (s *S) TestStartInstances(c *C) {620func (s *S) TestStartInstances(c *C) {
610 testServer.PrepareResponse(200, nil, StartInstancesExample)621 testServer.Response(200, nil, StartInstancesExample)
611622
612 resp, err := s.ec2.StartInstances("i-10a64379")623 resp, err := s.ec2.StartInstances("i-10a64379")
613 req := testServer.WaitRequest()624 req := testServer.WaitRequest()
@@ -627,7 +638,7 @@
627}638}
628639
629func (s *S) TestStopInstances(c *C) {640func (s *S) TestStopInstances(c *C) {
630 testServer.PrepareResponse(200, nil, StopInstancesExample)641 testServer.Response(200, nil, StopInstancesExample)
631642
632 resp, err := s.ec2.StopInstances("i-10a64379")643 resp, err := s.ec2.StopInstances("i-10a64379")
633 req := testServer.WaitRequest()644 req := testServer.WaitRequest()
@@ -647,7 +658,7 @@
647}658}
648659
649func (s *S) TestRebootInstances(c *C) {660func (s *S) TestRebootInstances(c *C) {
650 testServer.PrepareResponse(200, nil, RebootInstancesExample)661 testServer.Response(200, nil, RebootInstancesExample)
651662
652 resp, err := s.ec2.RebootInstances("i-10a64379")663 resp, err := s.ec2.RebootInstances("i-10a64379")
653 req := testServer.WaitRequest()664 req := testServer.WaitRequest()
@@ -663,7 +674,7 @@
663 ec2.FakeTime(true)674 ec2.FakeTime(true)
664 defer ec2.FakeTime(false)675 defer ec2.FakeTime(false)
665676
666 testServer.PrepareResponse(200, nil, RebootInstancesExample)677 testServer.Response(200, nil, RebootInstancesExample)
667678
668 // https://bugs.launchpad.net/goamz/+bug/1022749679 // https://bugs.launchpad.net/goamz/+bug/1022749
669 ec2 := ec2.New(s.ec2.Auth, aws.Region{EC2Endpoint: testServer.URL + "/services/Cloud"})680 ec2 := ec2.New(s.ec2.Auth, aws.Region{EC2Endpoint: testServer.URL + "/services/Cloud"})
670681
=== modified file 'ec2/ec2i_test.go'
--- ec2/ec2i_test.go 2012-10-28 16:05:46 +0000
+++ ec2/ec2i_test.go 2013-01-31 17:09:20 +0000
@@ -2,15 +2,13 @@
22
3import (3import (
4 "crypto/rand"4 "crypto/rand"
5 "flag"
6 "fmt"5 "fmt"
7 "launchpad.net/goamz/aws"6 "launchpad.net/goamz/aws"
8 "launchpad.net/goamz/ec2"7 "launchpad.net/goamz/ec2"
8 "launchpad.net/goamz/testutil"
9 . "launchpad.net/gocheck"9 . "launchpad.net/gocheck"
10)10)
1111
12var amazon = flag.Bool("amazon", false, "Enable tests against amazon server")
13
14// AmazonServer represents an Amazon EC2 server.12// AmazonServer represents an Amazon EC2 server.
15type AmazonServer struct {13type AmazonServer struct {
16 auth aws.Auth14 auth aws.Auth
@@ -34,7 +32,7 @@
34}32}
3533
36func (s *AmazonClientSuite) SetUpSuite(c *C) {34func (s *AmazonClientSuite) SetUpSuite(c *C) {
37 if !*amazon {35 if !testutil.Amazon {
38 c.Skip("AmazonClientSuite tests not enabled")36 c.Skip("AmazonClientSuite tests not enabled")
39 }37 }
40 s.srv.SetUp(c)38 s.srv.SetUp(c)
4139
=== modified file 'ec2/ec2t_test.go'
--- ec2/ec2t_test.go 2012-10-28 16:05:46 +0000
+++ ec2/ec2t_test.go 2013-01-31 17:09:20 +0000
@@ -5,6 +5,7 @@
5 "launchpad.net/goamz/aws"5 "launchpad.net/goamz/aws"
6 "launchpad.net/goamz/ec2"6 "launchpad.net/goamz/ec2"
7 "launchpad.net/goamz/ec2/ec2test"7 "launchpad.net/goamz/ec2/ec2test"
8 "launchpad.net/goamz/testutil"
8 . "launchpad.net/gocheck"9 . "launchpad.net/gocheck"
9 "regexp"10 "regexp"
10 "sort"11 "sort"
@@ -88,7 +89,7 @@
88var _ = Suite(&AmazonServerSuite{})89var _ = Suite(&AmazonServerSuite{})
8990
90func (s *AmazonServerSuite) SetUpSuite(c *C) {91func (s *AmazonServerSuite) SetUpSuite(c *C) {
91 if !*amazon {92 if !testutil.Amazon {
92 c.Skip("AmazonServerSuite tests not enabled")93 c.Skip("AmazonServerSuite tests not enabled")
93 }94 }
94 s.srv.SetUp(c)95 s.srv.SetUp(c)
@@ -435,17 +436,13 @@
435436
436func (s *ServerTests) TestGroupFiltering(c *C) {437func (s *ServerTests) TestGroupFiltering(c *C) {
437 g := make([]ec2.SecurityGroup, 4)438 g := make([]ec2.SecurityGroup, 4)
438 for i := range g[0:3] {439 for i := range g {
439 resp, err := s.ec2.CreateSecurityGroup(sessionName(fmt.Sprintf("testgroup%d", i)), fmt.Sprintf("testdescription%d", i))440 resp, err := s.ec2.CreateSecurityGroup(sessionName(fmt.Sprintf("testgroup%d", i)), fmt.Sprintf("testdescription%d", i))
440 c.Assert(err, IsNil)441 c.Assert(err, IsNil)
441 g[i] = resp.SecurityGroup442 g[i] = resp.SecurityGroup
442 c.Logf("group %d: %v", i, g[i])443 c.Logf("group %d: %v", i, g[i])
443 defer s.ec2.DeleteSecurityGroup(g[i])444 defer s.ec2.DeleteSecurityGroup(g[i])
444 }445 }
445 // Get the default group.
446 resp, err := s.ec2.SecurityGroups([]ec2.SecurityGroup{{Name: "default"}}, nil)
447 c.Assert(err, IsNil)
448 g[3] = resp.Groups[0].SecurityGroup
449446
450 perms := [][]ec2.IPPerm{447 perms := [][]ec2.IPPerm{
451 {{448 {{
@@ -536,7 +533,7 @@
536 filterCheck("group-name", g[2].Name, groups(2)),533 filterCheck("group-name", g[2].Name, groups(2)),
537 filterCheck("ip-permission.cidr", "1.2.3.4/32", groups(0)),534 filterCheck("ip-permission.cidr", "1.2.3.4/32", groups(0)),
538 filterCheck("ip-permission.group-name", g[1].Name, groups(1, 2)),535 filterCheck("ip-permission.group-name", g[1].Name, groups(1, 2)),
539 filterCheck("ip-permission.protocol", "udp", groups(2, 3)),536 filterCheck("ip-permission.protocol", "udp", groups(2)),
540 filterCheck("ip-permission.from-port", "200", groups(1, 2)),537 filterCheck("ip-permission.from-port", "200", groups(1, 2)),
541 filterCheck("ip-permission.to-port", "200", groups(0)),538 filterCheck("ip-permission.to-port", "200", groups(0)),
542 // TODO owner-id539 // TODO owner-id
@@ -568,7 +565,7 @@
568 if t.allowExtra {565 if t.allowExtra {
569 namePat := regexp.MustCompile(sessionName("testgroup[0-9]"))566 namePat := regexp.MustCompile(sessionName("testgroup[0-9]"))
570 for id, g := range groups {567 for id, g := range groups {
571 if g.Name != "default" && !namePat.MatchString(g.Name) {568 if !namePat.MatchString(g.Name) {
572 delete(groups, id)569 delete(groups, id)
573 }570 }
574 }571 }
575572
=== modified file 'ec2/ec2test/filter.go'
--- ec2/ec2test/filter.go 2012-03-09 14:02:34 +0000
+++ ec2/ec2test/filter.go 2013-01-31 17:09:20 +0000
@@ -13,13 +13,13 @@
13type filter map[string][]string13type filter map[string][]string
1414
15// newFilter creates a new filter from the Filter fields in the url form.15// newFilter creates a new filter from the Filter fields in the url form.
16// 16//
17// The filtering is specified through a map of name=>values, where the17// The filtering is specified through a map of name=>values, where the
18// name is a well-defined key identifying the data to be matched,18// name is a well-defined key identifying the data to be matched,
19// and the list of values holds the possible values the filtered19// and the list of values holds the possible values the filtered
20// item can take for the key to be included in the20// item can take for the key to be included in the
21// result set. For example:21// result set. For example:
22// 22//
23// Filter.1.Name=instance-type23// Filter.1.Name=instance-type
24// Filter.1.Value.1=m1.small24// Filter.1.Value.1=m1.small
25// Filter.1.Value.2=m1.large25// Filter.1.Value.2=m1.large
2626
=== modified file 'ec2/ec2test/server.go'
--- ec2/ec2test/server.go 2012-09-11 14:10:43 +0000
+++ ec2/ec2test/server.go 2013-01-31 17:09:20 +0000
@@ -417,18 +417,18 @@
417 }417 }
418418
419 // TODO attributes still to consider:419 // TODO attributes still to consider:
420 // ImageId: accept anything, we can verify later420 // ImageId: accept anything, we can verify later
421 // KeyName ?421 // KeyName ?
422 // InstanceType ?422 // InstanceType ?
423 // KernelId ?423 // KernelId ?
424 // RamdiskId ?424 // RamdiskId ?
425 // AvailZone ?425 // AvailZone ?
426 // GroupName tag426 // GroupName tag
427 // Monitoring ignore?427 // Monitoring ignore?
428 // SubnetId ? 428 // SubnetId ?
429 // DisableAPITermination bool429 // DisableAPITermination bool
430 // ShutdownBehavior string430 // ShutdownBehavior string
431 // PrivateIPAddress string431 // PrivateIPAddress string
432432
433 srv.mu.Lock()433 srv.mu.Lock()
434 defer srv.mu.Unlock()434 defer srv.mu.Unlock()
435435
=== modified file 'ec2/sign.go'
--- ec2/sign.go 2012-10-28 16:04:45 +0000
+++ ec2/sign.go 2013-01-31 17:09:20 +0000
@@ -19,10 +19,10 @@
19 params["SignatureVersion"] = "2"19 params["SignatureVersion"] = "2"
20 params["SignatureMethod"] = "HmacSHA256"20 params["SignatureMethod"] = "HmacSHA256"
2121
22 // AWS specifies that the parameters in a signed request must 22 // AWS specifies that the parameters in a signed request must
23 // be in natural order of the keys. This is distinct from the 23 // be provided in the natural order of the keys. This is distinct
24 // natural order of the encoded value of key=value. Basically24 // from the natural order of the encoded value of key=value.
25 // percent and equals affect the sorting order.25 // Percent and equals affect the sorting order.
26 var keys, sarray []string26 var keys, sarray []string
27 for k, _ := range params {27 for k, _ := range params {
28 keys = append(keys, k)28 keys = append(keys, k)
2929
=== removed file 'ec2/suite_test.go'
--- ec2/suite_test.go 2012-08-31 08:11:21 +0000
+++ ec2/suite_test.go 1970-01-01 00:00:00 +0000
@@ -1,118 +0,0 @@
1package ec2_test
2
3import (
4 "fmt"
5 . "launchpad.net/gocheck"
6 "net/http"
7 "net/url"
8 "os"
9 "testing"
10 "time"
11)
12
13func Test(t *testing.T) {
14 TestingT(t)
15}
16
17type HTTPSuite struct{}
18
19var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
20
21func (s *HTTPSuite) SetUpSuite(c *C) {
22 testServer.Start()
23}
24
25func (s *HTTPSuite) TearDownTest(c *C) {
26 testServer.FlushRequests()
27}
28
29type TestHTTPServer struct {
30 URL string
31 Timeout time.Duration
32 started bool
33 request chan *http.Request
34 response chan *testResponse
35 pending chan bool
36}
37
38type testResponse struct {
39 Status int
40 Headers map[string]string
41 Body string
42}
43
44func NewTestHTTPServer(url string, timeout time.Duration) *TestHTTPServer {
45 return &TestHTTPServer{URL: url, Timeout: timeout}
46}
47
48func (s *TestHTTPServer) Start() {
49 if s.started {
50 return
51 }
52 s.started = true
53
54 s.request = make(chan *http.Request, 64)
55 s.response = make(chan *testResponse, 64)
56 s.pending = make(chan bool, 64)
57
58 url, _ := url.Parse(s.URL)
59 go http.ListenAndServe(url.Host, s)
60
61 s.PrepareResponse(202, nil, "Nothing.")
62 for {
63 // Wait for it to be up.
64 resp, err := http.Get(s.URL)
65 if err == nil && resp.StatusCode == 202 {
66 break
67 }
68 time.Sleep(1e8)
69 }
70 s.WaitRequest() // Consume dummy request.
71}
72
73// FlushRequests discards requests which were not yet consumed by WaitRequest.
74func (s *TestHTTPServer) FlushRequests() {
75 for {
76 select {
77 case <-s.request:
78 default:
79 return
80 }
81 }
82}
83
84func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
85 s.request <- req
86 var resp *testResponse
87 select {
88 case resp = <-s.response:
89 case <-time.After(s.Timeout):
90 fmt.Fprintf(os.Stderr, "ERROR: Timeout waiting for test to provide response\n")
91 resp = &testResponse{500, nil, ""}
92 }
93 if resp.Headers != nil {
94 h := w.Header()
95 for k, v := range resp.Headers {
96 h.Set(k, v)
97 }
98 }
99 if resp.Status != 0 {
100 w.WriteHeader(resp.Status)
101 }
102 w.Write([]byte(resp.Body))
103}
104
105func (s *TestHTTPServer) WaitRequest() *http.Request {
106 select {
107 case req := <-s.request:
108 req.ParseForm()
109 return req
110 case <-time.After(s.Timeout):
111 panic("Timeout waiting for goamz request")
112 }
113 panic("unreached")
114}
115
116func (s *TestHTTPServer) PrepareResponse(status int, headers map[string]string, body string) {
117 s.response <- &testResponse{status, headers, body}
118}
1190
=== modified file 'exp/mturk/mturk.go'
--- exp/mturk/mturk.go 2012-05-03 17:12:28 +0000
+++ exp/mturk/mturk.go 2013-01-31 17:09:20 +0000
@@ -43,7 +43,7 @@
43// ----------------------------------------------------------------------------43// ----------------------------------------------------------------------------
44// Request dispatching logic.44// Request dispatching logic.
4545
46// Error encapsulates an error returned by MTurk. 46// Error encapsulates an error returned by MTurk.
47type Error struct {47type Error struct {
48 StatusCode int // HTTP status code (200, 403, ...)48 StatusCode int // HTTP status code (200, 403, ...)
49 Code string // EC2 error code ("UnsupportedOperation", ...)49 Code string // EC2 error code ("UnsupportedOperation", ...)
@@ -150,7 +150,7 @@
150// Corresponds to the "CreateHIT" operation of the Mechanical Turk150// Corresponds to the "CreateHIT" operation of the Mechanical Turk
151// API. http://goo.gl/cDBRc Currently only supports "external"151// API. http://goo.gl/cDBRc Currently only supports "external"
152// questions (see "HIT" struct above). If "keywords", "maxAssignments",152// questions (see "HIT" struct above). If "keywords", "maxAssignments",
153// "qualificationRequirement" or "requesterAnnotation" are the zero 153// "qualificationRequirement" or "requesterAnnotation" are the zero
154// value for their types, they will not be included in the request.154// value for their types, they will not be included in the request.
155func (mt *MTurk) CreateHIT(title, description string, question ExternalQuestion, reward Price, assignmentDurationInSeconds, lifetimeInSeconds uint, keywords string, maxAssignments uint, qualificationRequirement *QualificationRequirement, requesterAnnotation string) (h *HIT, err error) {155func (mt *MTurk) CreateHIT(title, description string, question ExternalQuestion, reward Price, assignmentDurationInSeconds, lifetimeInSeconds uint, keywords string, maxAssignments uint, qualificationRequirement *QualificationRequirement, requesterAnnotation string) (h *HIT, err error) {
156 params := make(map[string]string)156 params := make(map[string]string)
@@ -191,8 +191,8 @@
191191
192// Corresponds to the "CreateHIT" operation of the Mechanical Turk192// Corresponds to the "CreateHIT" operation of the Mechanical Turk
193// API, using an existing "hit type". http://goo.gl/cDBRc Currently only193// API, using an existing "hit type". http://goo.gl/cDBRc Currently only
194// supports "external" questions (see "HIT" struct above). If 194// supports "external" questions (see "HIT" struct above). If
195// "maxAssignments" or "requesterAnnotation" are the zero value for 195// "maxAssignments" or "requesterAnnotation" are the zero value for
196// their types, they will not be included in the request.196// their types, they will not be included in the request.
197func (mt *MTurk) CreateHITOfType(hitTypeId string, q ExternalQuestion, lifetimeInSeconds uint, maxAssignments uint, requesterAnnotation string) (h *HIT, err error) {197func (mt *MTurk) CreateHITOfType(hitTypeId string, q ExternalQuestion, lifetimeInSeconds uint, maxAssignments uint, requesterAnnotation string) (h *HIT, err error) {
198 params := make(map[string]string)198 params := make(map[string]string)
@@ -217,7 +217,7 @@
217 return217 return
218}218}
219219
220// Corresponds to "SearchHITs" operation of Mechanical Turk. http://goo.gl/PskcX 220// Corresponds to "SearchHITs" operation of Mechanical Turk. http://goo.gl/PskcX
221// Currenlty supports none of the optional parameters.221// Currenlty supports none of the optional parameters.
222func (mt *MTurk) SearchHITs() (s *SearchHITsResult, err error) {222func (mt *MTurk) SearchHITs() (s *SearchHITsResult, err error) {
223 params := make(map[string]string)223 params := make(map[string]string)
224224
=== modified file 'exp/mturk/mturk_test.go'
--- exp/mturk/mturk_test.go 2012-05-03 17:12:28 +0000
+++ exp/mturk/mturk_test.go 2013-01-31 17:09:20 +0000
@@ -3,19 +3,26 @@
3import (3import (
4 "launchpad.net/goamz/aws"4 "launchpad.net/goamz/aws"
5 "launchpad.net/goamz/exp/mturk"5 "launchpad.net/goamz/exp/mturk"
6 "launchpad.net/goamz/testutil"
6 . "launchpad.net/gocheck"7 . "launchpad.net/gocheck"
7 "net/url"8 "net/url"
9 "testing"
8)10)
911
12func Test(t *testing.T) {
13 TestingT(t)
14}
15
10var _ = Suite(&S{})16var _ = Suite(&S{})
1117
12type S struct {18type S struct {
13 HTTPSuite
14 mturk *mturk.MTurk19 mturk *mturk.MTurk
15}20}
1621
22var testServer = testutil.NewHTTPServer()
23
17func (s *S) SetUpSuite(c *C) {24func (s *S) SetUpSuite(c *C) {
18 s.HTTPSuite.SetUpSuite(c)25 testServer.Start()
19 auth := aws.Auth{"abc", "123"}26 auth := aws.Auth{"abc", "123"}
20 u, err := url.Parse(testServer.URL)27 u, err := url.Parse(testServer.URL)
21 if err != nil {28 if err != nil {
@@ -28,8 +35,12 @@
28 }35 }
29}36}
3037
38func (s *S) TearDownTest(c *C) {
39 testServer.Flush()
40}
41
31func (s *S) TestCreateHIT(c *C) {42func (s *S) TestCreateHIT(c *C) {
32 testServer.PrepareResponse(200, nil, BasicHitResponse)43 testServer.Response(200, nil, BasicHitResponse)
3344
34 question := mturk.ExternalQuestion{45 question := mturk.ExternalQuestion{
35 ExternalURL: "http://www.amazon.com",46 ExternalURL: "http://www.amazon.com",
@@ -51,7 +62,7 @@
51}62}
5263
53func (s *S) TestSearchHITs(c *C) {64func (s *S) TestSearchHITs(c *C) {
54 testServer.PrepareResponse(200, nil, SearchHITResponse)65 testServer.Response(200, nil, SearchHITResponse)
5566
56 hitResult, err := s.mturk.SearchHITs()67 hitResult, err := s.mturk.SearchHITs()
5768
5869
=== removed file 'exp/mturk/suite_test.go'
--- exp/mturk/suite_test.go 2012-03-09 15:34:56 +0000
+++ exp/mturk/suite_test.go 1970-01-01 00:00:00 +0000
@@ -1,120 +0,0 @@
1package mturk_test
2
3import (
4 "fmt"
5 . "launchpad.net/gocheck"
6 "net/http"
7 "net/url"
8 "os"
9 "testing"
10 "time"
11)
12
13func Test(t *testing.T) {
14 TestingT(t)
15}
16
17type HTTPSuite struct{}
18
19var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
20
21func (s *HTTPSuite) SetUpSuite(c *C) {
22 testServer.Start()
23}
24
25func (s *HTTPSuite) TearDownTest(c *C) {
26 testServer.FlushRequests()
27}
28
29type TestHTTPServer struct {
30 URL string
31 Timeout time.Duration
32 started bool
33 request chan *http.Request
34 response chan *testResponse
35 pending chan bool
36}
37
38type testResponse struct {
39 Status int
40 Headers map[string]string
41 Body string
42}
43
44func NewTestHTTPServer(url string, timeout time.Duration) *TestHTTPServer {
45 return &TestHTTPServer{URL: url, Timeout: timeout}
46}
47
48func (s *TestHTTPServer) Start() {
49 if s.started {
50 return
51 }
52 s.started = true
53
54 s.request = make(chan *http.Request, 64)
55 s.response = make(chan *testResponse, 64)
56 s.pending = make(chan bool, 64)
57
58 url, _ := url.Parse(s.URL)
59 go http.ListenAndServe(url.Host, s)
60
61 s.PrepareResponse(202, nil, "Nothing.")
62 for {
63 // Wait for it to be up.
64 resp, err := http.Get(s.URL)
65 if err == nil && resp.StatusCode == 202 {
66 break
67 }
68 fmt.Fprintf(os.Stderr, "\nWaiting for fake server to be up... ")
69 time.Sleep(1e8)
70 }
71 fmt.Fprintf(os.Stderr, "done\n\n")
72 s.WaitRequest() // Consume dummy request.
73}
74
75// FlushRequests discards requests which were not yet consumed by WaitRequest.
76func (s *TestHTTPServer) FlushRequests() {
77 for {
78 select {
79 case <-s.request:
80 default:
81 return
82 }
83 }
84}
85
86func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
87 s.request <- req
88 var resp *testResponse
89 select {
90 case resp = <-s.response:
91 case <-time.After(s.Timeout):
92 fmt.Fprintf(os.Stderr, "ERROR: Timeout waiting for test to provide response\n")
93 resp = &testResponse{500, nil, ""}
94 }
95 if resp.Headers != nil {
96 h := w.Header()
97 for k, v := range resp.Headers {
98 h.Set(k, v)
99 }
100 }
101 if resp.Status != 0 {
102 w.WriteHeader(resp.Status)
103 }
104 w.Write([]byte(resp.Body))
105}
106
107func (s *TestHTTPServer) WaitRequest() *http.Request {
108 select {
109 case req := <-s.request:
110 req.ParseForm()
111 return req
112 case <-time.After(s.Timeout):
113 panic("Timeout waiting for goamz request")
114 }
115 panic("unreached")
116}
117
118func (s *TestHTTPServer) PrepareResponse(status int, headers map[string]string, body string) {
119 s.response <- &testResponse{status, headers, body}
120}
1210
=== modified file 'exp/sdb/sdb.go'
--- exp/sdb/sdb.go 2012-03-09 15:34:56 +0000
+++ exp/sdb/sdb.go 2013-01-31 17:09:20 +0000
@@ -18,7 +18,7 @@
1818
19// BUG: SelectResp isn't properly organized. It must change.19// BUG: SelectResp isn't properly organized. It must change.
2020
21// 21//
2222
23import (23import (
24 "encoding/xml"24 "encoding/xml"
@@ -129,7 +129,7 @@
129129
130// Select returns a set of items and attributes that match expr.130// Select returns a set of items and attributes that match expr.
131// Select is similar to the standard SQL SELECT statement.131// Select is similar to the standard SQL SELECT statement.
132// 132//
133// See http://goo.gl/GTsSZ for more details.133// See http://goo.gl/GTsSZ for more details.
134func (sdb *SDB) Select(expr string, consistent bool) (resp *SelectResp, err error) {134func (sdb *SDB) Select(expr string, consistent bool) (resp *SelectResp, err error) {
135 resp = &SelectResp{}135 resp = &SelectResp{}
@@ -206,7 +206,7 @@
206 pa.missing[name] = true206 pa.missing[name] = true
207}207}
208208
209// PutAttrs adds attrs to item. 209// PutAttrs adds attrs to item.
210//210//
211// See http://goo.gl/yTAV4 for more details.211// See http://goo.gl/yTAV4 for more details.
212func (item *Item) PutAttrs(attrs *PutAttrs) (resp *SimpleResp, err error) {212func (item *Item) PutAttrs(attrs *PutAttrs) (resp *SimpleResp, err error) {
213213
=== modified file 'exp/sdb/sdb_test.go'
--- exp/sdb/sdb_test.go 2012-03-09 15:34:56 +0000
+++ exp/sdb/sdb_test.go 2013-01-31 17:09:20 +0000
@@ -3,24 +3,35 @@
3import (3import (
4 "launchpad.net/goamz/aws"4 "launchpad.net/goamz/aws"
5 "launchpad.net/goamz/exp/sdb"5 "launchpad.net/goamz/exp/sdb"
6 "launchpad.net/goamz/testutil"
6 . "launchpad.net/gocheck"7 . "launchpad.net/gocheck"
8 "testing"
7)9)
810
11func Test(t *testing.T) {
12 TestingT(t)
13}
14
9var _ = Suite(&S{})15var _ = Suite(&S{})
1016
11type S struct {17type S struct {
12 HTTPSuite
13 sdb *sdb.SDB18 sdb *sdb.SDB
14}19}
1520
21var testServer = testutil.NewHTTPServer()
22
16func (s *S) SetUpSuite(c *C) {23func (s *S) SetUpSuite(c *C) {
17 s.HTTPSuite.SetUpSuite(c)24 testServer.Start()
18 auth := aws.Auth{"abc", "123"}25 auth := aws.Auth{"abc", "123"}
19 s.sdb = sdb.New(auth, aws.Region{SDBEndpoint: testServer.URL})26 s.sdb = sdb.New(auth, aws.Region{SDBEndpoint: testServer.URL})
20}27}
2128
29func (s *S) TearDownTest(c *C) {
30 testServer.Flush()
31}
32
22func (s *S) TestCreateDomainOK(c *C) {33func (s *S) TestCreateDomainOK(c *C) {
23 testServer.PrepareResponse(200, nil, TestCreateDomainXmlOK)34 testServer.Response(200, nil, TestCreateDomainXmlOK)
2435
25 domain := s.sdb.Domain("domain")36 domain := s.sdb.Domain("domain")
26 resp, err := domain.CreateDomain()37 resp, err := domain.CreateDomain()
@@ -37,7 +48,7 @@
37}48}
3849
39func (s *S) TestListDomainsOK(c *C) {50func (s *S) TestListDomainsOK(c *C) {
40 testServer.PrepareResponse(200, nil, TestListDomainsXmlOK)51 testServer.Response(200, nil, TestListDomainsXmlOK)
4152
42 resp, err := s.sdb.ListDomains()53 resp, err := s.sdb.ListDomains()
43 req := testServer.WaitRequest()54 req := testServer.WaitRequest()
@@ -54,7 +65,7 @@
54}65}
5566
56func (s *S) TestListDomainsWithNextTokenXmlOK(c *C) {67func (s *S) TestListDomainsWithNextTokenXmlOK(c *C) {
57 testServer.PrepareResponse(200, nil, TestListDomainsWithNextTokenXmlOK)68 testServer.Response(200, nil, TestListDomainsWithNextTokenXmlOK)
5869
59 resp, err := s.sdb.ListDomains()70 resp, err := s.sdb.ListDomains()
60 req := testServer.WaitRequest()71 req := testServer.WaitRequest()
@@ -72,7 +83,7 @@
72}83}
7384
74func (s *S) TestDeleteDomainOK(c *C) {85func (s *S) TestDeleteDomainOK(c *C) {
75 testServer.PrepareResponse(200, nil, TestDeleteDomainXmlOK)86 testServer.Response(200, nil, TestDeleteDomainXmlOK)
7687
77 domain := s.sdb.Domain("domain")88 domain := s.sdb.Domain("domain")
78 resp, err := domain.DeleteDomain()89 resp, err := domain.DeleteDomain()
@@ -89,7 +100,7 @@
89}100}
90101
91func (s *S) TestPutAttrsOK(c *C) {102func (s *S) TestPutAttrsOK(c *C) {
92 testServer.PrepareResponse(200, nil, TestPutAttrsXmlOK)103 testServer.Response(200, nil, TestPutAttrsXmlOK)
93104
94 domain := s.sdb.Domain("MyDomain")105 domain := s.sdb.Domain("MyDomain")
95 item := domain.Item("Item123")106 item := domain.Item("Item123")
@@ -128,7 +139,7 @@
128}139}
129140
130func (s *S) TestAttrsOK(c *C) {141func (s *S) TestAttrsOK(c *C) {
131 testServer.PrepareResponse(200, nil, TestAttrsXmlOK)142 testServer.Response(200, nil, TestAttrsXmlOK)
132143
133 domain := s.sdb.Domain("MyDomain")144 domain := s.sdb.Domain("MyDomain")
134 item := domain.Item("Item123")145 item := domain.Item("Item123")
@@ -155,7 +166,7 @@
155}166}
156167
157func (s *S) TestAttrsSelectOK(c *C) {168func (s *S) TestAttrsSelectOK(c *C) {
158 testServer.PrepareResponse(200, nil, TestAttrsXmlOK)169 testServer.Response(200, nil, TestAttrsXmlOK)
159170
160 domain := s.sdb.Domain("MyDomain")171 domain := s.sdb.Domain("MyDomain")
161 item := domain.Item("Item123")172 item := domain.Item("Item123")
@@ -184,7 +195,7 @@
184}195}
185196
186func (s *S) TestSelectOK(c *C) {197func (s *S) TestSelectOK(c *C) {
187 testServer.PrepareResponse(200, nil, TestSelectXmlOK)198 testServer.Response(200, nil, TestSelectXmlOK)
188199
189 resp, err := s.sdb.Select("select Color from MyDomain where Color like 'Blue%'", true)200 resp, err := s.sdb.Select("select Color from MyDomain where Color like 'Blue%'", true)
190 req := testServer.WaitRequest()201 req := testServer.WaitRequest()
191202
=== removed file 'exp/sdb/suite_test.go'
--- exp/sdb/suite_test.go 2012-03-09 15:34:56 +0000
+++ exp/sdb/suite_test.go 1970-01-01 00:00:00 +0000
@@ -1,139 +0,0 @@
1package sdb_test
2
3import (
4 "flag"
5 "fmt"
6 "launchpad.net/goamz/aws"
7 "launchpad.net/gocheck"
8 "net/http"
9 "net/url"
10 "os"
11 "testing"
12 "time"
13)
14
15func Test(t *testing.T) {
16 gocheck.TestingT(t)
17}
18
19var integration = flag.Bool("i", false, "Enable integration tests")
20
21type SuiteI struct {
22 auth aws.Auth
23}
24
25func (s *SuiteI) SetUpSuite(c *gocheck.C) {
26 if !*integration {
27 c.Skip("Integration tests not enabled (-int flag)")
28 }
29 auth, err := aws.EnvAuth()
30 if err != nil {
31 c.Fatal(err)
32 }
33 s.auth = auth
34}
35
36type HTTPSuite struct{}
37
38var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
39
40func (s *HTTPSuite) SetUpSuite(c *gocheck.C) {
41 testServer.Start()
42}
43
44func (s *HTTPSuite) TearDownTest(c *gocheck.C) {
45 testServer.FlushRequests()
46}
47
48type TestHTTPServer struct {
49 URL string
50 Timeout time.Duration
51 started bool
52 request chan *http.Request
53 response chan *testResponse
54 pending chan bool
55}
56
57type testResponse struct {
58 Status int
59 Headers map[string]string
60 Body string
61}
62
63func NewTestHTTPServer(url_ string, timeout time.Duration) *TestHTTPServer {
64 return &TestHTTPServer{URL: url_, Timeout: timeout}
65}
66
67func (s *TestHTTPServer) Start() {
68 if s.started {
69 return
70 }
71 s.started = true
72
73 s.request = make(chan *http.Request, 64)
74 s.response = make(chan *testResponse, 64)
75 s.pending = make(chan bool, 64)
76
77 url_, _ := url.Parse(s.URL)
78 go http.ListenAndServe(url_.Host, s)
79
80 s.PrepareResponse(202, nil, "Nothing.")
81 for {
82 // Wait for it to be up.
83 resp, err := http.Get(s.URL)
84 if err == nil && resp.StatusCode == 202 {
85 break
86 }
87 fmt.Fprintf(os.Stderr, "\nWaiting for fake server to be up... ")
88 time.Sleep(1e8)
89 }
90 fmt.Fprintf(os.Stderr, "done\n\n")
91 s.WaitRequest() // Consume dummy request.
92}
93
94// FlushRequests discards requests which were not yet consumed by WaitRequest.
95func (s *TestHTTPServer) FlushRequests() {
96 for {
97 select {
98 case <-s.request:
99 default:
100 return
101 }
102 }
103}
104
105func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
106 s.request <- req
107 var resp *testResponse
108 select {
109 case resp = <-s.response:
110 case <-time.After(s.Timeout):
111 fmt.Fprintf(os.Stderr, "ERROR: Timeout waiting for test to provide response\n")
112 resp = &testResponse{500, nil, ""}
113 }
114 if resp.Headers != nil {
115 h := w.Header()
116 for k, v := range resp.Headers {
117 h.Set(k, v)
118 }
119 }
120 if resp.Status != 0 {
121 w.WriteHeader(resp.Status)
122 }
123 w.Write([]byte(resp.Body))
124}
125
126func (s *TestHTTPServer) WaitRequest() *http.Request {
127 select {
128 case req := <-s.request:
129 req.ParseForm()
130 return req
131 case <-time.After(s.Timeout):
132 panic("Timeout waiting for goamz request")
133 }
134 panic("unreached")
135}
136
137func (s *TestHTTPServer) PrepareResponse(status int, headers map[string]string, body string) {
138 s.response <- &testResponse{status, headers, body}
139}
1400
=== modified file 'exp/sns/sns_test.go'
--- exp/sns/sns_test.go 2012-05-03 17:12:28 +0000
+++ exp/sns/sns_test.go 2013-01-31 17:09:20 +0000
@@ -3,22 +3,33 @@
3import (3import (
4 "launchpad.net/goamz/aws"4 "launchpad.net/goamz/aws"
5 "launchpad.net/goamz/exp/sns"5 "launchpad.net/goamz/exp/sns"
6 "launchpad.net/goamz/testutil"
6 . "launchpad.net/gocheck"7 . "launchpad.net/gocheck"
8 "testing"
7)9)
810
11func Test(t *testing.T) {
12 TestingT(t)
13}
14
9var _ = Suite(&S{})15var _ = Suite(&S{})
1016
11type S struct {17type S struct {
12 HTTPSuite
13 sns *sns.SNS18 sns *sns.SNS
14}19}
1520
21var testServer = testutil.NewHTTPServer()
22
16func (s *S) SetUpSuite(c *C) {23func (s *S) SetUpSuite(c *C) {
17 s.HTTPSuite.SetUpSuite(c)24 testServer.Start()
18 auth := aws.Auth{"abc", "123"}25 auth := aws.Auth{"abc", "123"}
19 s.sns = sns.New(auth, aws.Region{SNSEndpoint: testServer.URL})26 s.sns = sns.New(auth, aws.Region{SNSEndpoint: testServer.URL})
20}27}
2128
29func (s *S) TearDownTest(c *C) {
30 testServer.Flush()
31}
32
22func (s *S) TestListTopicsOK(c *C) {33func (s *S) TestListTopicsOK(c *C) {
23 testServer.Response(200, nil, TestListTopicsXmlOK)34 testServer.Response(200, nil, TestListTopicsXmlOK)
2435
2536
=== removed file 'exp/sns/suite_test.go'
--- exp/sns/suite_test.go 2012-03-09 15:34:56 +0000
+++ exp/sns/suite_test.go 1970-01-01 00:00:00 +0000
@@ -1,200 +0,0 @@
1package sns_test
2
3import (
4 "bytes"
5 "flag"
6 "fmt"
7 "io/ioutil"
8 . "launchpad.net/gocheck"
9 "net/http"
10 "net/url"
11 "os"
12 "testing"
13 "time"
14)
15
16func Test(t *testing.T) {
17 TestingT(t)
18}
19
20var integration = flag.Bool("i", false, "Enable integration tests")
21
22type SuiteI struct{}
23
24func (s *SuiteI) SetUpSuite(c *C) {
25 if !*integration {
26 c.Skip("Integration tests not enabled (-i flag)")
27 }
28}
29
30type HTTPSuite struct{}
31
32var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
33
34func (s *HTTPSuite) SetUpSuite(c *C) {
35 testServer.Start()
36}
37
38func (s *HTTPSuite) TearDownTest(c *C) {
39 testServer.Flush()
40}
41
42type TestHTTPServer struct {
43 URL string
44 Timeout time.Duration
45 started bool
46 request chan *http.Request
47 response chan ResponseFunc
48 pending chan bool
49}
50
51func NewTestHTTPServer(url_ string, timeout time.Duration) *TestHTTPServer {
52 return &TestHTTPServer{URL: url_, Timeout: timeout}
53}
54
55type Response struct {
56 Status int
57 Headers map[string]string
58 Body string
59}
60
61type ResponseFunc func(path string) Response
62
63func (s *TestHTTPServer) Start() {
64 if s.started {
65 return
66 }
67 s.started = true
68
69 s.request = make(chan *http.Request, 64)
70 s.response = make(chan ResponseFunc, 64)
71 s.pending = make(chan bool, 64)
72
73 url_, _ := url.Parse(s.URL)
74 go http.ListenAndServe(url_.Host, s)
75
76 s.Response(203, nil, "")
77 for {
78 // Wait for it to be up.
79 resp, err := http.Get(s.URL)
80 if err == nil && resp.StatusCode == 203 {
81 break
82 }
83 fmt.Fprintf(os.Stderr, "\nWaiting for fake server to be up... ")
84 time.Sleep(1e8)
85 }
86 fmt.Fprintf(os.Stderr, "done\n\n")
87 s.WaitRequest() // Consume dummy request.
88}
89
90// FlushRequests discards requests which were not yet consumed by WaitRequest.
91func (s *TestHTTPServer) Flush() {
92 for {
93 select {
94 case <-s.request:
95 case <-s.response:
96 default:
97 return
98 }
99 }
100}
101
102func body(req *http.Request) string {
103 data, err := ioutil.ReadAll(req.Body)
104 if err != nil {
105 panic(err)
106 }
107 return string(data)
108}
109
110func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
111 req.ParseMultipartForm(1e6)
112 data, err := ioutil.ReadAll(req.Body)
113 if err != nil {
114 panic(err)
115 }
116 req.Body = ioutil.NopCloser(bytes.NewBuffer(data))
117 s.request <- req
118 var resp Response
119 select {
120 case respFunc := <-s.response:
121 resp = respFunc(req.URL.Path)
122 case <-time.After(s.Timeout):
123 const msg = "ERROR: Timeout waiting for test to prepare a response\n"
124 fmt.Fprintf(os.Stderr, msg)
125 resp = Response{500, nil, msg}
126 }
127 if resp.Headers != nil {
128 h := w.Header()
129 for k, v := range resp.Headers {
130 h.Set(k, v)
131 }
132 }
133 if resp.Status != 0 {
134 w.WriteHeader(resp.Status)
135 }
136 w.Write([]byte(resp.Body))
137}
138
139// WaitRequests returns the next n requests made to the http server from
140// the queue. If not enough requests were previously made, it waits until
141// the timeout value for them to be made.
142func (s *TestHTTPServer) WaitRequests(n int) []*http.Request {
143 reqs := make([]*http.Request, 0, n)
144 for i := 0; i < n; i++ {
145 select {
146 case req := <-s.request:
147 reqs = append(reqs, req)
148 case <-time.After(s.Timeout):
149 panic("Timeout waiting for request")
150 }
151 }
152 return reqs
153}
154
155// WaitRequest returns the next request made to the http server from
156// the queue. If no requests were previously made, it waits until the
157// timeout value for one to be made.
158func (s *TestHTTPServer) WaitRequest() *http.Request {
159 return s.WaitRequests(1)[0]
160}
161
162// ResponseFunc prepares the test server to respond the following n
163// requests using f to build each response.
164func (s *TestHTTPServer) ResponseFunc(n int, f ResponseFunc) {
165 for i := 0; i < n; i++ {
166 s.response <- f
167 }
168}
169
170// ResponseMap maps request paths to responses.
171type ResponseMap map[string]Response
172
173// ResponseMap prepares the test server to respond the following n
174// requests using the m to obtain the responses.
175func (s *TestHTTPServer) ResponseMap(n int, m ResponseMap) {
176 f := func(path string) Response {
177 for rpath, resp := range m {
178 if rpath == path {
179 return resp
180 }
181 }
182 return Response{Status: 500, Body: "Path not found in response map: " + path}
183 }
184 s.ResponseFunc(n, f)
185}
186
187// Responses prepares the test server to respond the following n requests
188// using the provided response parameters.
189func (s *TestHTTPServer) Responses(n int, status int, headers map[string]string, body string) {
190 f := func(path string) Response {
191 return Response{status, headers, body}
192 }
193 s.ResponseFunc(n, f)
194}
195
196// Response prepares the test server to respond the following request
197// using the provided response parameters.
198func (s *TestHTTPServer) Response(status int, headers map[string]string, body string) {
199 s.Responses(1, status, headers, body)
200}
2010
=== modified file 'iam/iam_test.go'
--- iam/iam_test.go 2012-10-10 20:16:54 +0000
+++ iam/iam_test.go 2013-01-31 17:09:20 +0000
@@ -3,24 +3,35 @@
3import (3import (
4 "launchpad.net/goamz/aws"4 "launchpad.net/goamz/aws"
5 "launchpad.net/goamz/iam"5 "launchpad.net/goamz/iam"
6 "launchpad.net/goamz/testutil"
6 . "launchpad.net/gocheck"7 . "launchpad.net/gocheck"
8 "testing"
7)9)
810
11func Test(t *testing.T) {
12 TestingT(t)
13}
14
9type S struct {15type S struct {
10 HTTPSuite
11 iam *iam.IAM16 iam *iam.IAM
12}17}
1318
14var _ = Suite(&S{})19var _ = Suite(&S{})
1520
21var testServer = testutil.NewHTTPServer()
22
16func (s *S) SetUpSuite(c *C) {23func (s *S) SetUpSuite(c *C) {
17 s.HTTPSuite.SetUpSuite(c)24 testServer.Start()
18 auth := aws.Auth{"abc", "123"}25 auth := aws.Auth{"abc", "123"}
19 s.iam = iam.New(auth, aws.Region{IAMEndpoint: testServer.URL})26 s.iam = iam.New(auth, aws.Region{IAMEndpoint: testServer.URL})
20}27}
2128
29func (s *S) TearDownTest(c *C) {
30 testServer.Flush()
31}
32
22func (s *S) TestCreateUser(c *C) {33func (s *S) TestCreateUser(c *C) {
23 testServer.PrepareResponse(200, nil, CreateUserExample)34 testServer.Response(200, nil, CreateUserExample)
24 resp, err := s.iam.CreateUser("Bob", "/division_abc/subdivision_xyz/")35 resp, err := s.iam.CreateUser("Bob", "/division_abc/subdivision_xyz/")
25 values := testServer.WaitRequest().URL.Query()36 values := testServer.WaitRequest().URL.Query()
26 c.Assert(values.Get("Action"), Equals, "CreateUser")37 c.Assert(values.Get("Action"), Equals, "CreateUser")
@@ -38,7 +49,7 @@
38}49}
3950
40func (s *S) TestCreateUserConflict(c *C) {51func (s *S) TestCreateUserConflict(c *C) {
41 testServer.PrepareResponse(409, nil, DuplicateUserExample)52 testServer.Response(409, nil, DuplicateUserExample)
42 resp, err := s.iam.CreateUser("Bob", "/division_abc/subdivision_xyz/")53 resp, err := s.iam.CreateUser("Bob", "/division_abc/subdivision_xyz/")
43 testServer.WaitRequest()54 testServer.WaitRequest()
44 c.Assert(resp, IsNil)55 c.Assert(resp, IsNil)
@@ -50,7 +61,7 @@
50}61}
5162
52func (s *S) TestGetUser(c *C) {63func (s *S) TestGetUser(c *C) {
53 testServer.PrepareResponse(200, nil, GetUserExample)64 testServer.Response(200, nil, GetUserExample)
54 resp, err := s.iam.GetUser("Bob")65 resp, err := s.iam.GetUser("Bob")
55 values := testServer.WaitRequest().URL.Query()66 values := testServer.WaitRequest().URL.Query()
56 c.Assert(values.Get("Action"), Equals, "GetUser")67 c.Assert(values.Get("Action"), Equals, "GetUser")
@@ -67,7 +78,7 @@
67}78}
6879
69func (s *S) TestDeleteUser(c *C) {80func (s *S) TestDeleteUser(c *C) {
70 testServer.PrepareResponse(200, nil, RequestIdExample)81 testServer.Response(200, nil, RequestIdExample)
71 resp, err := s.iam.DeleteUser("Bob")82 resp, err := s.iam.DeleteUser("Bob")
72 values := testServer.WaitRequest().URL.Query()83 values := testServer.WaitRequest().URL.Query()
73 c.Assert(values.Get("Action"), Equals, "DeleteUser")84 c.Assert(values.Get("Action"), Equals, "DeleteUser")
@@ -77,7 +88,7 @@
77}88}
7889
79func (s *S) TestCreateAccessKey(c *C) {90func (s *S) TestCreateAccessKey(c *C) {
80 testServer.PrepareResponse(200, nil, CreateAccessKeyExample)91 testServer.Response(200, nil, CreateAccessKeyExample)
81 resp, err := s.iam.CreateAccessKey("Bob")92 resp, err := s.iam.CreateAccessKey("Bob")
82 values := testServer.WaitRequest().URL.Query()93 values := testServer.WaitRequest().URL.Query()
83 c.Assert(values.Get("Action"), Equals, "CreateAccessKey")94 c.Assert(values.Get("Action"), Equals, "CreateAccessKey")
8495
=== modified file 'iam/iami_test.go'
--- iam/iami_test.go 2012-10-10 20:21:55 +0000
+++ iam/iami_test.go 2013-01-31 17:09:20 +0000
@@ -1,14 +1,12 @@
1package iam_test1package iam_test
22
3import (3import (
4 "flag"
5 "launchpad.net/goamz/aws"4 "launchpad.net/goamz/aws"
6 "launchpad.net/goamz/iam"5 "launchpad.net/goamz/iam"
6 "launchpad.net/goamz/testutil"
7 . "launchpad.net/gocheck"7 . "launchpad.net/gocheck"
8)8)
99
10var amazon = flag.Bool("amazon", false, "Enable tests against amazon server")
11
12// AmazonServer represents an Amazon AWS server.10// AmazonServer represents an Amazon AWS server.
13type AmazonServer struct {11type AmazonServer struct {
14 auth aws.Auth12 auth aws.Auth
@@ -31,7 +29,7 @@
31}29}
3230
33func (s *AmazonClientSuite) SetUpSuite(c *C) {31func (s *AmazonClientSuite) SetUpSuite(c *C) {
34 if !*amazon {32 if !testutil.Amazon {
35 c.Skip("AmazonClientSuite tests not enabled")33 c.Skip("AmazonClientSuite tests not enabled")
36 }34 }
37 s.srv.SetUp(c)35 s.srv.SetUp(c)
3836
=== removed file 'iam/suite_test.go'
--- iam/suite_test.go 2012-10-05 22:45:47 +0000
+++ iam/suite_test.go 1970-01-01 00:00:00 +0000
@@ -1,128 +0,0 @@
1package iam_test
2
3import (
4 "bytes"
5 "fmt"
6 "io/ioutil"
7 . "launchpad.net/gocheck"
8 "net/http"
9 "net/url"
10 "os"
11 "testing"
12 "time"
13)
14
15func Test(t *testing.T) {
16 TestingT(t)
17}
18
19type HTTPSuite struct{}
20
21var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
22
23func (s *HTTPSuite) SetUpSuite(c *C) {
24 testServer.Start()
25}
26
27func (s *HTTPSuite) TearDownTest(c *C) {
28 testServer.FlushRequests()
29}
30
31type TestHTTPServer struct {
32 URL string
33 Timeout time.Duration
34 started bool
35 body chan []byte
36 request chan *http.Request
37 response chan *testResponse
38 pending chan bool
39}
40
41type testResponse struct {
42 Status int
43 Headers map[string]string
44 Body string
45}
46
47func NewTestHTTPServer(url string, timeout time.Duration) *TestHTTPServer {
48 return &TestHTTPServer{URL: url, Timeout: timeout}
49}
50
51func (s *TestHTTPServer) Start() {
52 if s.started {
53 return
54 }
55 s.started = true
56
57 s.body = make(chan []byte, 64)
58 s.request = make(chan *http.Request, 64)
59 s.response = make(chan *testResponse, 64)
60 s.pending = make(chan bool, 64)
61
62 url, _ := url.Parse(s.URL)
63 go http.ListenAndServe(url.Host, s)
64
65 s.PrepareResponse(202, nil, "Nothing.")
66 for {
67 // Wait for it to be up.
68 resp, err := http.Get(s.URL)
69 if err == nil && resp.StatusCode == 202 {
70 break
71 }
72 fmt.Fprintf(os.Stderr, "\nWaiting for fake server to be up... ")
73 time.Sleep(1e8)
74 }
75 fmt.Fprintf(os.Stderr, "done\n\n")
76 s.WaitRequest() // Consume dummy request.
77}
78
79// FlushRequests discards requests which were not yet consumed by WaitRequest.
80func (s *TestHTTPServer) FlushRequests() {
81 for {
82 select {
83 case <-s.request:
84 default:
85 return
86 }
87 }
88}
89
90func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
91 b, _ := ioutil.ReadAll(req.Body)
92 s.body <- b
93 s.request <- req
94 var resp *testResponse
95 select {
96 case resp = <-s.response:
97 case <-time.After(s.Timeout):
98 fmt.Fprintf(os.Stderr, "ERROR: Timeout waiting for test to provide response\n")
99 resp = &testResponse{500, nil, ""}
100 }
101 if resp.Headers != nil {
102 h := w.Header()
103 for k, v := range resp.Headers {
104 h.Set(k, v)
105 }
106 }
107 if resp.Status != 0 {
108 w.WriteHeader(resp.Status)
109 }
110 w.Write([]byte(resp.Body))
111}
112
113func (s *TestHTTPServer) WaitRequest() *http.Request {
114 select {
115 case req := <-s.request:
116 body := <-s.body
117 req.Body = ioutil.NopCloser(bytes.NewReader(body))
118 req.ParseForm()
119 return req
120 case <-time.After(s.Timeout):
121 panic("Timeout waiting for goamz request")
122 }
123 panic("unreached")
124}
125
126func (s *TestHTTPServer) PrepareResponse(status int, headers map[string]string, body string) {
127 s.response <- &testResponse{status, headers, body}
128}
1290
=== modified file 's3/s3.go'
--- s3/s3.go 2012-12-10 05:30:05 +0000
+++ s3/s3.go 2013-01-31 17:09:20 +0000
@@ -67,7 +67,7 @@
67// locationConstraint returns an io.Reader specifying a LocationConstraint if67// locationConstraint returns an io.Reader specifying a LocationConstraint if
68// required for the region.68// required for the region.
69//69//
70// See http://goo.gl/bh9Kq for more details.70// See http://goo.gl/bh9Kq for details.
71func (s3 *S3) locationConstraint() io.Reader {71func (s3 *S3) locationConstraint() io.Reader {
72 constraint := ""72 constraint := ""
73 if s3.Region.S3LocationConstraint {73 if s3.Region.S3LocationConstraint {
@@ -89,7 +89,7 @@
8989
90// PutBucket creates a new bucket.90// PutBucket creates a new bucket.
91//91//
92// See http://goo.gl/ndjnR for more details.92// See http://goo.gl/ndjnR for details.
93func (b *Bucket) PutBucket(perm ACL) error {93func (b *Bucket) PutBucket(perm ACL) error {
94 headers := map[string][]string{94 headers := map[string][]string{
95 "x-amz-acl": {string(perm)},95 "x-amz-acl": {string(perm)},
@@ -107,7 +107,7 @@
107// DelBucket removes an existing S3 bucket. All objects in the bucket must107// DelBucket removes an existing S3 bucket. All objects in the bucket must
108// be removed before the bucket itself can be removed.108// be removed before the bucket itself can be removed.
109//109//
110// See http://goo.gl/GoBrY for more details.110// See http://goo.gl/GoBrY for details.
111func (b *Bucket) DelBucket() error {111func (b *Bucket) DelBucket() error {
112 req := &request{112 req := &request{
113 method: "DELETE",113 method: "DELETE",
@@ -117,9 +117,14 @@
117 return b.S3.query(req, nil)117 return b.S3.query(req, nil)
118}118}
119119
120func hasCode(err error, code string) bool {
121 s3err, ok := err.(*Error)
122 return ok && s3err.Code == code
123}
124
120// Get retrieves an object from an S3 bucket.125// Get retrieves an object from an S3 bucket.
121//126//
122// See http://goo.gl/isCO7 for more details.127// See http://goo.gl/isCO7 for details.
123func (b *Bucket) Get(path string) (data []byte, err error) {128func (b *Bucket) Get(path string) (data []byte, err error) {
124 body, err := b.GetReader(path)129 body, err := b.GetReader(path)
125 if err != nil {130 if err != nil {
@@ -151,7 +156,7 @@
151156
152// Put inserts an object into the S3 bucket.157// Put inserts an object into the S3 bucket.
153//158//
154// See http://goo.gl/FEBPD for more details.159// See http://goo.gl/FEBPD for details.
155func (b *Bucket) Put(path string, data []byte, contType string, perm ACL) error {160func (b *Bucket) Put(path string, data []byte, contType string, perm ACL) error {
156 body := bytes.NewBuffer(data)161 body := bytes.NewBuffer(data)
157 return b.PutReader(path, body, int64(len(data)), contType, perm)162 return b.PutReader(path, body, int64(len(data)), contType, perm)
@@ -177,7 +182,7 @@
177182
178// Del removes an object from the S3 bucket.183// Del removes an object from the S3 bucket.
179//184//
180// See http://goo.gl/APeTt for more details.185// See http://goo.gl/APeTt for details.
181func (b *Bucket) Del(path string) error {186func (b *Bucket) Del(path string) error {
182 req := &request{187 req := &request{
183 method: "DELETE",188 method: "DELETE",
@@ -215,15 +220,15 @@
215 Owner Owner220 Owner Owner
216}221}
217222
218// List returns a information about objects in an S3 bucket.223// List returns information about objects in an S3 bucket.
219//224//
220// The prefix parameter limits the response to keys that begin with the225// The prefix parameter limits the response to keys that begin with the
221// specified prefix. You can use prefixes to separate a bucket into different226// specified prefix.
222// groupings of keys (e.g. to get a feeling of folders).
223//227//
224// The delimited parameter causes the response to group all of the keys that228// The delim parameter causes the response to group all of the keys that
225// share a common prefix up to the next delimiter to be grouped in a single229// share a common prefix up to the next delimiter in a single entry within
226// entry within the CommonPrefixes field.230// the CommonPrefixes field. You can use delimiters to separate a bucket
231// into different groupings of keys, similar to how folders would work.
227//232//
228// The marker parameter specifies the key to start with when listing objects233// The marker parameter specifies the key to start with when listing objects
229// in a bucket. Amazon S3 lists objects in alphabetical order and234// in a bucket. Amazon S3 lists objects in alphabetical order and
@@ -270,7 +275,7 @@
270// },275// },
271// }276// }
272//277//
273// See http://goo.gl/YjQTc for more details.278// See http://goo.gl/YjQTc for details.
274func (b *Bucket) List(prefix, delim, marker string, max int) (result *ListResp, err error) {279func (b *Bucket) List(prefix, delim, marker string, max int) (result *ListResp, err error) {
275 params := map[string][]string{280 params := map[string][]string{
276 "prefix": {prefix},281 "prefix": {prefix},
277282
=== modified file 's3/s3_test.go'
--- s3/s3_test.go 2012-07-05 05:47:52 +0000
+++ s3/s3_test.go 2013-01-31 17:09:20 +0000
@@ -4,29 +4,40 @@
4 "bytes"4 "bytes"
5 "io/ioutil"5 "io/ioutil"
6 "net/http"6 "net/http"
7 "testing"
78
8 "launchpad.net/goamz/aws"9 "launchpad.net/goamz/aws"
9 "launchpad.net/goamz/s3"10 "launchpad.net/goamz/s3"
11 "launchpad.net/goamz/testutil"
10 . "launchpad.net/gocheck"12 . "launchpad.net/gocheck"
11)13)
1214
13var _ = Suite(&S{})15func Test(t *testing.T) {
16 TestingT(t)
17}
1418
15type S struct {19type S struct {
16 HTTPSuite
17 s3 *s3.S320 s3 *s3.S3
18}21}
1922
23var _ = Suite(&S{})
24
25var testServer = testutil.NewHTTPServer()
26
20func (s *S) SetUpSuite(c *C) {27func (s *S) SetUpSuite(c *C) {
21 s.HTTPSuite.SetUpSuite(c)28 testServer.Start()
22 auth := aws.Auth{"abc", "123"}29 auth := aws.Auth{"abc", "123"}
23 s.s3 = s3.New(auth, aws.Region{Name: "faux-region-1", S3Endpoint: testServer.URL})30 s.s3 = s3.New(auth, aws.Region{Name: "faux-region-1", S3Endpoint: testServer.URL})
24}31}
2532
33func (s *S) TearDownTest(c *C) {
34 testServer.Flush()
35}
36
26// PutBucket docs: http://goo.gl/kBTCu37// PutBucket docs: http://goo.gl/kBTCu
2738
28func (s *S) TestPutBucket(c *C) {39func (s *S) TestPutBucket(c *C) {
29 testServer.PrepareResponse(200, nil, "")40 testServer.Response(200, nil, "")
3041
31 b := s.s3.Bucket("bucket")42 b := s.s3.Bucket("bucket")
32 err := b.PutBucket(s3.Private)43 err := b.PutBucket(s3.Private)
@@ -41,7 +52,7 @@
41// DeleteBucket docs: http://goo.gl/GoBrY52// DeleteBucket docs: http://goo.gl/GoBrY
4253
43func (s *S) TestDelBucket(c *C) {54func (s *S) TestDelBucket(c *C) {
44 testServer.PrepareResponse(204, nil, "")55 testServer.Response(204, nil, "")
4556
46 b := s.s3.Bucket("bucket")57 b := s.s3.Bucket("bucket")
47 err := b.DelBucket()58 err := b.DelBucket()
@@ -56,7 +67,7 @@
56// GetObject docs: http://goo.gl/isCO767// GetObject docs: http://goo.gl/isCO7
5768
58func (s *S) TestGet(c *C) {69func (s *S) TestGet(c *C) {
59 testServer.PrepareResponse(200, nil, "content")70 testServer.Response(200, nil, "content")
6071
61 b := s.s3.Bucket("bucket")72 b := s.s3.Bucket("bucket")
62 data, err := b.Get("name")73 data, err := b.Get("name")
@@ -71,7 +82,7 @@
71}82}
7283
73func (s *S) TestURL(c *C) {84func (s *S) TestURL(c *C) {
74 testServer.PrepareResponse(200, nil, "content")85 testServer.Response(200, nil, "content")
7586
76 b := s.s3.Bucket("bucket")87 b := s.s3.Bucket("bucket")
77 url := b.URL("name")88 url := b.URL("name")
@@ -88,7 +99,7 @@
88}99}
89100
90func (s *S) TestGetReader(c *C) {101func (s *S) TestGetReader(c *C) {
91 testServer.PrepareResponse(200, nil, "content")102 testServer.Response(200, nil, "content")
92103
93 b := s.s3.Bucket("bucket")104 b := s.s3.Bucket("bucket")
94 rc, err := b.GetReader("name")105 rc, err := b.GetReader("name")
@@ -105,7 +116,7 @@
105}116}
106117
107func (s *S) TestGetNotFound(c *C) {118func (s *S) TestGetNotFound(c *C) {
108 testServer.PrepareResponse(404, nil, GetObjectErrorDump)119 testServer.Response(404, nil, GetObjectErrorDump)
109120
110 b := s.s3.Bucket("non-existent-bucket")121 b := s.s3.Bucket("non-existent-bucket")
111 data, err := b.Get("non-existent")122 data, err := b.Get("non-existent")
@@ -130,7 +141,7 @@
130// PutObject docs: http://goo.gl/FEBPD141// PutObject docs: http://goo.gl/FEBPD
131142
132func (s *S) TestPutObject(c *C) {143func (s *S) TestPutObject(c *C) {
133 testServer.PrepareResponse(200, nil, "")144 testServer.Response(200, nil, "")
134145
135 b := s.s3.Bucket("bucket")146 b := s.s3.Bucket("bucket")
136 err := b.Put("name", []byte("content"), "content-type", s3.Private)147 err := b.Put("name", []byte("content"), "content-type", s3.Private)
@@ -147,7 +158,7 @@
147}158}
148159
149func (s *S) TestPutReader(c *C) {160func (s *S) TestPutReader(c *C) {
150 testServer.PrepareResponse(200, nil, "")161 testServer.Response(200, nil, "")
151162
152 b := s.s3.Bucket("bucket")163 b := s.s3.Bucket("bucket")
153 buf := bytes.NewBufferString("content")164 buf := bytes.NewBufferString("content")
@@ -167,7 +178,7 @@
167// DelObject docs: http://goo.gl/APeTt178// DelObject docs: http://goo.gl/APeTt
168179
169func (s *S) TestDelObject(c *C) {180func (s *S) TestDelObject(c *C) {
170 testServer.PrepareResponse(200, nil, "")181 testServer.Response(200, nil, "")
171182
172 b := s.s3.Bucket("bucket")183 b := s.s3.Bucket("bucket")
173 err := b.Del("name")184 err := b.Del("name")
@@ -182,7 +193,7 @@
182// Bucket List Objects docs: http://goo.gl/YjQTc193// Bucket List Objects docs: http://goo.gl/YjQTc
183194
184func (s *S) TestList(c *C) {195func (s *S) TestList(c *C) {
185 testServer.PrepareResponse(200, nil, GetListResultDump1)196 testServer.Response(200, nil, GetListResultDump1)
186197
187 b := s.s3.Bucket("quotes")198 b := s.s3.Bucket("quotes")
188199
@@ -221,7 +232,7 @@
221}232}
222233
223func (s *S) TestListWithDelimiter(c *C) {234func (s *S) TestListWithDelimiter(c *C) {
224 testServer.PrepareResponse(200, nil, GetListResultDump2)235 testServer.Response(200, nil, GetListResultDump2)
225236
226 b := s.s3.Bucket("quotes")237 b := s.s3.Bucket("quotes")
227238
228239
=== modified file 's3/s3i_test.go'
--- s3/s3i_test.go 2013-01-28 13:30:10 +0000
+++ s3/s3i_test.go 2013-01-31 17:09:20 +0000
@@ -10,6 +10,7 @@
1010
11 "launchpad.net/goamz/aws"11 "launchpad.net/goamz/aws"
12 "launchpad.net/goamz/s3"12 "launchpad.net/goamz/s3"
13 "launchpad.net/goamz/testutil"
13 . "launchpad.net/gocheck"14 . "launchpad.net/gocheck"
14 "time"15 "time"
15)16)
@@ -45,7 +46,7 @@
45}46}
4647
47func (s *AmazonClientSuite) SetUpSuite(c *C) {48func (s *AmazonClientSuite) SetUpSuite(c *C) {
48 if !*amazon {49 if !testutil.Amazon {
49 c.Skip("live tests against AWS disabled (no -amazon)")50 c.Skip("live tests against AWS disabled (no -amazon)")
50 }51 }
51 s.srv.SetUp(c)52 s.srv.SetUp(c)
@@ -62,7 +63,7 @@
62}63}
6364
64func (s *AmazonDomainClientSuite) SetUpSuite(c *C) {65func (s *AmazonDomainClientSuite) SetUpSuite(c *C) {
65 if !*amazon {66 if !testutil.Amazon {
66 c.Skip("live tests against AWS disabled (no -amazon)")67 c.Skip("live tests against AWS disabled (no -amazon)")
67 }68 }
68 s.srv.SetUp(c)69 s.srv.SetUp(c)
@@ -102,12 +103,15 @@
102103
103func (s *ClientTests) TestBasicFunctionality(c *C) {104func (s *ClientTests) TestBasicFunctionality(c *C) {
104 b := s.Bucket(testBucket)105 b := s.Bucket(testBucket)
106 b.DelBucket()
107
105 err := b.PutBucket(s3.PublicRead)108 err := b.PutBucket(s3.PublicRead)
106 c.Assert(err, IsNil)109 c.Assert(err, IsNil)
107 defer b.DelBucket()110 defer b.DelBucket()
108111
109 err = b.Put("name", []byte("yo!"), "text/plain", s3.PublicRead)112 err = b.Put("name", []byte("yo!"), "text/plain", s3.PublicRead)
110 c.Assert(err, IsNil)113 c.Assert(err, IsNil)
114 defer b.Del("name")
111115
112 data, err := b.Get("name")116 data, err := b.Get("name")
113 c.Assert(err, IsNil)117 c.Assert(err, IsNil)
@@ -120,6 +124,7 @@
120 buf := bytes.NewBufferString("hey!")124 buf := bytes.NewBufferString("hey!")
121 err = b.PutReader("name2", buf, int64(buf.Len()), "text/plain", s3.Private)125 err = b.PutReader("name2", buf, int64(buf.Len()), "text/plain", s3.Private)
122 c.Assert(err, IsNil)126 c.Assert(err, IsNil)
127 defer b.Del("name2")
123128
124 rc, err := b.GetReader("name2")129 rc, err := b.GetReader("name2")
125 c.Assert(err, IsNil)130 c.Assert(err, IsNil)
@@ -225,16 +230,13 @@
225 // normal list.230 // normal list.
226 {231 {
227 Contents: keys(objectNames...),232 Contents: keys(objectNames...),
228 },233 }, {
229 {
230 Marker: objectNames[0],234 Marker: objectNames[0],
231 Contents: keys(objectNames[1:]...),235 Contents: keys(objectNames[1:]...),
232 },236 }, {
233 {
234 Marker: objectNames[0] + "a",237 Marker: objectNames[0] + "a",
235 Contents: keys(objectNames[1:]...),238 Contents: keys(objectNames[1:]...),
236 },239 }, {
237 {
238 Marker: "z",240 Marker: "z",
239 },241 },
240242
@@ -243,14 +245,12 @@
243 MaxKeys: 2,245 MaxKeys: 2,
244 Contents: keys(objectNames[0:2]...),246 Contents: keys(objectNames[0:2]...),
245 IsTruncated: true,247 IsTruncated: true,
246 },248 }, {
247 {
248 MaxKeys: 2,249 MaxKeys: 2,
249 Marker: objectNames[0],250 Marker: objectNames[0],
250 Contents: keys(objectNames[1:3]...),251 Contents: keys(objectNames[1:3]...),
251 IsTruncated: true,252 IsTruncated: true,
252 },253 }, {
253 {
254 MaxKeys: 2,254 MaxKeys: 2,
255 Marker: objectNames[len(objectNames)-2],255 Marker: objectNames[len(objectNames)-2],
256 Contents: keys(objectNames[len(objectNames)-1:]...),256 Contents: keys(objectNames[len(objectNames)-1:]...),
@@ -261,38 +261,32 @@
261 Delimiter: "/",261 Delimiter: "/",
262 CommonPrefixes: []string{"photos/", "test/"},262 CommonPrefixes: []string{"photos/", "test/"},
263 Contents: keys("index.html", "index2.html"),263 Contents: keys("index.html", "index2.html"),
264 },264 }, {
265 {
266 Delimiter: "/",265 Delimiter: "/",
267 Prefix: "photos/2006/",266 Prefix: "photos/2006/",
268 CommonPrefixes: []string{"photos/2006/February/", "photos/2006/January/"},267 CommonPrefixes: []string{"photos/2006/February/", "photos/2006/January/"},
269 },268 }, {
270 {
271 Delimiter: "/",269 Delimiter: "/",
272 Prefix: "t",270 Prefix: "t",
273 CommonPrefixes: []string{"test/"},271 CommonPrefixes: []string{"test/"},
274 },272 }, {
275 {
276 Delimiter: "/",273 Delimiter: "/",
277 MaxKeys: 1,274 MaxKeys: 1,
278 Contents: keys("index.html"),275 Contents: keys("index.html"),
279 IsTruncated: true,276 IsTruncated: true,
280 },277 }, {
281 {
282 Delimiter: "/",278 Delimiter: "/",
283 MaxKeys: 1,279 MaxKeys: 1,
284 Marker: "index2.html",280 Marker: "index2.html",
285 CommonPrefixes: []string{"photos/"},281 CommonPrefixes: []string{"photos/"},
286 IsTruncated: true,282 IsTruncated: true,
287 },283 }, {
288 {
289 Delimiter: "/",284 Delimiter: "/",
290 MaxKeys: 1,285 MaxKeys: 1,
291 Marker: "photos/",286 Marker: "photos/",
292 CommonPrefixes: []string{"test/"},287 CommonPrefixes: []string{"test/"},
293 IsTruncated: false,288 IsTruncated: false,
294 },289 }, {
295 {
296 Delimiter: "Feb",290 Delimiter: "Feb",
297 CommonPrefixes: []string{"photos/2006/Feb"},291 CommonPrefixes: []string{"photos/2006/Feb"},
298 Contents: keys("index.html", "index2.html", "photos/2006/January/sample.jpg", "test/bar", "test/foo"),292 Contents: keys("index.html", "index2.html", "photos/2006/January/sample.jpg", "test/bar", "test/foo"),
299293
=== removed file 's3/suite_test.go'
--- s3/suite_test.go 2012-05-02 15:22:53 +0000
+++ s3/suite_test.go 1970-01-01 00:00:00 +0000
@@ -1,139 +0,0 @@
1package s3_test
2
3import (
4 "flag"
5 "fmt"
6 "launchpad.net/goamz/aws"
7 . "launchpad.net/gocheck"
8 "net/http"
9 "net/url"
10 "os"
11 "testing"
12 "time"
13)
14
15func Test(t *testing.T) {
16 TestingT(t)
17}
18
19var amazon = flag.Bool("amazon", false, "Enable tests against amazon server")
20
21type SuiteI struct {
22 auth aws.Auth
23}
24
25func (s *SuiteI) SetUpSuite(c *C) {
26 if !*amazon {
27 c.Skip("amazon tests not enabled (-amazon flag)")
28 }
29 auth, err := aws.EnvAuth()
30 if err != nil {
31 c.Fatal(err.Error())
32 }
33 s.auth = auth
34}
35
36type HTTPSuite struct{}
37
38var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
39
40func (s *HTTPSuite) SetUpSuite(c *C) {
41 testServer.Start()
42}
43
44func (s *HTTPSuite) TearDownTest(c *C) {
45 testServer.FlushRequests()
46}
47
48type TestHTTPServer struct {
49 URL string
50 Timeout time.Duration
51 started bool
52 request chan *http.Request
53 response chan *testResponse
54 pending chan bool
55}
56
57type testResponse struct {
58 Status int
59 Headers map[string]string
60 Body string
61}
62
63func NewTestHTTPServer(url string, timeout time.Duration) *TestHTTPServer {
64 return &TestHTTPServer{URL: url, Timeout: timeout}
65}
66
67func (s *TestHTTPServer) Start() {
68 if s.started {
69 return
70 }
71 s.started = true
72
73 s.request = make(chan *http.Request, 64)
74 s.response = make(chan *testResponse, 64)
75 s.pending = make(chan bool, 64)
76
77 url, _ := url.Parse(s.URL)
78 go http.ListenAndServe(url.Host, s)
79
80 s.PrepareResponse(202, nil, "Nothing.")
81 for {
82 // Wait for it to be up.
83 resp, err := http.Get(s.URL)
84 if err == nil && resp.StatusCode == 202 {
85 break
86 }
87 fmt.Fprintf(os.Stderr, "\nWaiting for fake server to be up... ")
88 time.Sleep(1e8)
89 }
90 fmt.Fprintf(os.Stderr, "done\n\n")
91 s.WaitRequest() // Consume dummy request.
92}
93
94// FlushRequests discards requests which were not yet consumed by WaitRequest.
95func (s *TestHTTPServer) FlushRequests() {
96 for {
97 select {
98 case <-s.request:
99 default:
100 return
101 }
102 }
103}
104
105func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
106 s.request <- req
107 var resp *testResponse
108 select {
109 case resp = <-s.response:
110 case <-time.After(s.Timeout):
111 fmt.Fprintf(os.Stderr, "ERROR: Timeout waiting for test to provide response\n")
112 resp = &testResponse{500, nil, ""}
113 }
114 if resp.Headers != nil {
115 h := w.Header()
116 for k, v := range resp.Headers {
117 h.Set(k, v)
118 }
119 }
120 if resp.Status != 0 {
121 w.WriteHeader(resp.Status)
122 }
123 w.Write([]byte(resp.Body))
124}
125
126func (s *TestHTTPServer) WaitRequest() *http.Request {
127 select {
128 case req := <-s.request:
129 req.ParseForm()
130 return req
131 case <-time.After(s.Timeout):
132 panic("Timeout waiting for goamz request")
133 }
134 panic("unreached")
135}
136
137func (s *TestHTTPServer) PrepareResponse(status int, headers map[string]string, body string) {
138 s.response <- &testResponse{status, headers, body}
139}
1400
=== added directory 'testutil'
=== added file 'testutil/http.go'
--- testutil/http.go 1970-01-01 00:00:00 +0000
+++ testutil/http.go 2013-01-31 17:09:20 +0000
@@ -0,0 +1,174 @@
1package testutil
2
3import (
4 "bytes"
5 "fmt"
6 "io/ioutil"
7 "net"
8 "net/http"
9 "net/url"
10 "os"
11 "time"
12)
13
14type HTTPServer struct {
15 URL string
16 Timeout time.Duration
17 started bool
18 request chan *http.Request
19 response chan ResponseFunc
20}
21
22type Response struct {
23 Status int
24 Headers map[string]string
25 Body string
26}
27
28func NewHTTPServer() *HTTPServer {
29 return &HTTPServer{URL: "http://localhost:4444", Timeout: 5 * time.Second}
30}
31
32type ResponseFunc func(path string) Response
33
34func (s *HTTPServer) Start() {
35 if s.started {
36 return
37 }
38 s.started = true
39 s.request = make(chan *http.Request, 64)
40 s.response = make(chan ResponseFunc, 64)
41 u, err := url.Parse(s.URL)
42 if err != nil {
43 panic(err)
44 }
45 l, err := net.Listen("tcp", u.Host)
46 if err != nil {
47 panic(err)
48 }
49 go http.Serve(l, s)
50
51 s.Response(203, nil, "")
52 for {
53 // Wait for it to be up.
54 resp, err := http.Get(s.URL)
55 if err == nil && resp.StatusCode == 203 {
56 break
57 }
58 time.Sleep(1e8)
59 }
60 s.WaitRequest() // Consume dummy request.
61}
62
63// Flush discards all pending requests and responses.
64func (s *HTTPServer) Flush() {
65 for {
66 select {
67 case <-s.request:
68 case <-s.response:
69 default:
70 return
71 }
72 }
73}
74
75func body(req *http.Request) string {
76 data, err := ioutil.ReadAll(req.Body)
77 if err != nil {
78 panic(err)
79 }
80 return string(data)
81}
82
83func (s *HTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
84 req.ParseMultipartForm(1e6)
85 data, err := ioutil.ReadAll(req.Body)
86 if err != nil {
87 panic(err)
88 }
89 req.Body = ioutil.NopCloser(bytes.NewBuffer(data))
90 s.request <- req
91 var resp Response
92 select {
93 case respFunc := <-s.response:
94 resp = respFunc(req.URL.Path)
95 case <-time.After(s.Timeout):
96 const msg = "ERROR: Timeout waiting for test to prepare a response\n"
97 fmt.Fprintf(os.Stderr, msg)
98 resp = Response{500, nil, msg}
99 }
100 if resp.Headers != nil {
101 h := w.Header()
102 for k, v := range resp.Headers {
103 h.Set(k, v)
104 }
105 }
106 if resp.Status != 0 {
107 w.WriteHeader(resp.Status)
108 }
109 w.Write([]byte(resp.Body))
110}
111
112// WaitRequests returns the next n requests made to the http server from
113// the queue. If not enough requests were previously made, it waits until
114// the timeout value for them to be made.
115func (s *HTTPServer) WaitRequests(n int) []*http.Request {
116 reqs := make([]*http.Request, 0, n)
117 for i := 0; i < n; i++ {
118 select {
119 case req := <-s.request:
120 reqs = append(reqs, req)
121 case <-time.After(s.Timeout):
122 panic("Timeout waiting for request")
123 }
124 }
125 return reqs
126}
127
128// WaitRequest returns the next request made to the http server from
129// the queue. If no requests were previously made, it waits until the
130// timeout value for one to be made.
131func (s *HTTPServer) WaitRequest() *http.Request {
132 return s.WaitRequests(1)[0]
133}
134
135// ResponseFunc prepares the test server to respond the following n
136// requests using f to build each response.
137func (s *HTTPServer) ResponseFunc(n int, f ResponseFunc) {
138 for i := 0; i < n; i++ {
139 s.response <- f
140 }
141}
142
143// ResponseMap maps request paths to responses.
144type ResponseMap map[string]Response
145
146// ResponseMap prepares the test server to respond the following n
147// requests using the m to obtain the responses.
148func (s *HTTPServer) ResponseMap(n int, m ResponseMap) {
149 f := func(path string) Response {
150 for rpath, resp := range m {
151 if rpath == path {
152 return resp
153 }
154 }
155 body := "Path not found in response map: " + path
156 return Response{Status: 500, Body: body}
157 }
158 s.ResponseFunc(n, f)
159}
160
161// Responses prepares the test server to respond the following n requests
162// using the provided response parameters.
163func (s *HTTPServer) Responses(n int, status int, headers map[string]string, body string) {
164 f := func(path string) Response {
165 return Response{status, headers, body}
166 }
167 s.ResponseFunc(n, f)
168}
169
170// Response prepares the test server to respond the following request
171// using the provided response parameters.
172func (s *HTTPServer) Response(status int, headers map[string]string, body string) {
173 s.Responses(1, status, headers, body)
174}
0175
=== added file 'testutil/suite.go'
--- testutil/suite.go 1970-01-01 00:00:00 +0000
+++ testutil/suite.go 2013-01-31 17:09:20 +0000
@@ -0,0 +1,30 @@
1package testutil
2
3import (
4 "flag"
5 "launchpad.net/goamz/aws"
6 . "launchpad.net/gocheck"
7)
8
9// Amazon must be used by all tested packages to determine whether to
10// run functional tests against the real AWS servers.
11var Amazon bool
12
13func init() {
14 flag.BoolVar(&Amazon, "amazon", false, "Enable tests against amazon server")
15}
16
17type LiveSuite struct {
18 auth aws.Auth
19}
20
21func (s *LiveSuite) SetUpSuite(c *C) {
22 if !Amazon {
23 c.Skip("amazon tests not enabled (-amazon flag)")
24 }
25 auth, err := aws.EnvAuth()
26 if err != nil {
27 c.Fatal(err.Error())
28 }
29 s.auth = auth
30}

Subscribers

People subscribed via source and target branches