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
1=== modified file 'aws/aws_test.go'
2--- aws/aws_test.go 2012-07-02 23:36:49 +0000
3+++ aws/aws_test.go 2013-01-31 17:09:20 +0000
4@@ -5,8 +5,13 @@
5 . "launchpad.net/gocheck"
6 "os"
7 "strings"
8+ "testing"
9 )
10
11+func Test(t *testing.T) {
12+ TestingT(t)
13+}
14+
15 var _ = Suite(&S{})
16
17 type S struct {
18
19=== removed file 'aws/suite_test.go'
20--- aws/suite_test.go 2012-05-03 17:12:28 +0000
21+++ aws/suite_test.go 1970-01-01 00:00:00 +0000
22@@ -1,139 +0,0 @@
23-package aws_test
24-
25-import (
26- "flag"
27- "fmt"
28- "launchpad.net/goamz/aws"
29- . "launchpad.net/gocheck"
30- "net/http"
31- "net/url"
32- "os"
33- "testing"
34- "time"
35-)
36-
37-func Test(t *testing.T) {
38- TestingT(t)
39-}
40-
41-var integration = flag.Bool("i", false, "Enable integration tests")
42-
43-type SuiteI struct {
44- auth aws.Auth
45-}
46-
47-func (s *SuiteI) SetUpSuite(c *C) {
48- if !*integration {
49- c.Skip("Integration tests not enabled (-int flag)")
50- }
51- auth, err := aws.EnvAuth()
52- if err != nil {
53- c.Fatal(err)
54- }
55- s.auth = auth
56-}
57-
58-type HTTPSuite struct{}
59-
60-var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
61-
62-func (s *HTTPSuite) SetUpSuite(c *C) {
63- testServer.Start()
64-}
65-
66-func (s *HTTPSuite) TearDownTest(c *C) {
67- testServer.FlushRequests()
68-}
69-
70-type TestHTTPServer struct {
71- URL string
72- Timeout time.Duration
73- started bool
74- request chan *http.Request
75- response chan *testResponse
76- pending chan bool
77-}
78-
79-type testResponse struct {
80- Status int
81- Headers map[string]string
82- Body string
83-}
84-
85-func NewTestHTTPServer(url_ string, timeout time.Duration) *TestHTTPServer {
86- return &TestHTTPServer{URL: url_, Timeout: timeout}
87-}
88-
89-func (s *TestHTTPServer) Start() {
90- if s.started {
91- return
92- }
93- s.started = true
94-
95- s.request = make(chan *http.Request, 64)
96- s.response = make(chan *testResponse, 64)
97- s.pending = make(chan bool, 64)
98-
99- url, _ := url.Parse(s.URL)
100- go http.ListenAndServe(url.Host, s)
101-
102- s.PrepareResponse(123, nil, "")
103- for {
104- // Wait for it to be up.
105- resp, err := http.Get(s.URL)
106- if err == nil && resp.StatusCode == 123 {
107- break
108- }
109- fmt.Fprintf(os.Stderr, "\nWaiting for fake server to be up... ")
110- time.Sleep(1e8)
111- }
112- fmt.Fprintf(os.Stderr, "done\n\n")
113- s.WaitRequest() // Consume dummy request.
114-}
115-
116-// FlushRequests discards requests which were not yet consumed by WaitRequest.
117-func (s *TestHTTPServer) FlushRequests() {
118- for {
119- select {
120- case <-s.request:
121- default:
122- return
123- }
124- }
125-}
126-
127-func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
128- s.request <- req
129- var resp *testResponse
130- select {
131- case resp = <-s.response:
132- case <-time.After(s.Timeout):
133- fmt.Fprintf(os.Stderr, "ERROR: Timeout waiting for test to provide response\n")
134- resp = &testResponse{500, nil, ""}
135- }
136- h := w.Header()
137- if resp.Headers != nil {
138- for k, v := range resp.Headers {
139- h.Set(k, v)
140- }
141- }
142- if resp.Status != 0 {
143- w.WriteHeader(resp.Status)
144- }
145- w.Write([]byte(resp.Body))
146-}
147-
148-func (s *TestHTTPServer) WaitRequest() *http.Request {
149- select {
150- case req := <-s.request:
151- req.ParseForm()
152- return req
153- case <-time.After(s.Timeout):
154- panic("Timeout waiting for goamz request")
155- }
156- panic("unreached")
157-}
158-
159-func (s *TestHTTPServer) PrepareResponse(status int, headers map[string]string, body string) {
160- s.response <- &testResponse{status, headers, body}
161-}
162
163=== modified file 'ec2/ec2.go'
164--- ec2/ec2.go 2012-10-28 16:05:46 +0000
165+++ ec2/ec2.go 2013-01-31 17:09:20 +0000
166@@ -86,7 +86,7 @@
167 // ----------------------------------------------------------------------------
168 // Request dispatching logic.
169
170-// Error encapsulates an error returned by EC2.
171+// Error encapsulates an error returned by EC2.
172 //
173 // See http://goo.gl/VZGuC for more details.
174 type Error struct {
175@@ -425,15 +425,15 @@
176 //
177 // See http://goo.gl/wnDBf for more details.
178 type BlockDeviceMapping struct {
179- DeviceName string `xml:"deviceName"`
180- VirtualName string `xml:"virtualName"`
181- SnapshotId string `xml:"ebs>snapshotId"`
182- VolumeType string `xml:"ebs>volumeType"`
183- VolumeSize int64 `xml:"ebs>volumeSize"`
184- DeleteOnTermination bool `xml:"ebs>deleteOnTermination"`
185+ DeviceName string `xml:"deviceName"`
186+ VirtualName string `xml:"virtualName"`
187+ SnapshotId string `xml:"ebs>snapshotId"`
188+ VolumeType string `xml:"ebs>volumeType"`
189+ VolumeSize int64 `xml:"ebs>volumeSize"`
190+ DeleteOnTermination bool `xml:"ebs>deleteOnTermination"`
191
192 // The number of I/O operations per second (IOPS) that the volume supports.
193- IOPS int64 `xml:"ebs>iops"`
194+ IOPS int64 `xml:"ebs>iops"`
195 }
196
197 // Image represents details about an image.
198@@ -467,7 +467,7 @@
199 // For example, to get all the private images associated with this account set
200 // the boolean filter "is-private" to true.
201 //
202-// Note: calling this function with nil ids and filter parameters will result in
203+// Note: calling this function with nil ids and filter parameters will result in
204 // a very large number of images being returned.
205 //
206 // See http://goo.gl/SRBhW for more details.
207@@ -512,11 +512,11 @@
208
209 // DeleteSnapshots deletes the volume snapshots with the given ids.
210 //
211-// Note: If you make periodic snapshots of a volume, the snapshots are
212-// incremental so that only the blocks on the device that have changed
213-// since your last snapshot are incrementally saved in the new snapshot.
214-// Even though snapshots are saved incrementally, the snapshot deletion
215-// process is designed so that you need to retain only the most recent
216+// Note: If you make periodic snapshots of a volume, the snapshots are
217+// incremental so that only the blocks on the device that have changed
218+// since your last snapshot are incrementally saved in the new snapshot.
219+// Even though snapshots are saved incrementally, the snapshot deletion
220+// process is designed so that you need to retain only the most recent
221 // snapshot in order to restore the volume.
222 //
223 // See http://goo.gl/vwU1y for more details.
224@@ -558,7 +558,7 @@
225 Tags []Tag `xml:"tagSet>item"`
226 }
227
228-// Snapshots returns details about volume snapshots available to the user.
229+// Snapshots returns details about volume snapshots available to the user.
230 // The ids and filter parameters, if provided, limit the snapshots returned.
231 //
232 // See http://goo.gl/ogJL4 for more details.
233@@ -620,7 +620,7 @@
234 Groups []SecurityGroupInfo `xml:"securityGroupInfo>item"`
235 }
236
237-// SecurityGroup encapsulates details for a security group in EC2.
238+// SecurityGroup encapsulates details for a security group in EC2.
239 //
240 // See http://goo.gl/CIdyP for more details.
241 type SecurityGroupInfo struct {
242@@ -785,7 +785,7 @@
243 }
244
245 // CreateTags adds or overwrites one or more tags for the specified instance ids.
246-//
247+//
248 // See http://goo.gl/Vmkqc for more details
249 func (ec2 *EC2) CreateTags(instIds []string, tags []Tag) (resp *SimpleResp, err error) {
250 params := makeParams("CreateTags")
251
252=== modified file 'ec2/ec2_test.go'
253--- ec2/ec2_test.go 2012-10-18 18:56:09 +0000
254+++ ec2/ec2_test.go 2013-01-31 17:09:20 +0000
255@@ -3,24 +3,35 @@
256 import (
257 "launchpad.net/goamz/aws"
258 "launchpad.net/goamz/ec2"
259+ "launchpad.net/goamz/testutil"
260 . "launchpad.net/gocheck"
261+ "testing"
262 )
263
264+func Test(t *testing.T) {
265+ TestingT(t)
266+}
267+
268 var _ = Suite(&S{})
269
270 type S struct {
271- HTTPSuite
272 ec2 *ec2.EC2
273 }
274
275+var testServer = testutil.NewHTTPServer()
276+
277 func (s *S) SetUpSuite(c *C) {
278- s.HTTPSuite.SetUpSuite(c)
279+ testServer.Start()
280 auth := aws.Auth{"abc", "123"}
281 s.ec2 = ec2.New(auth, aws.Region{EC2Endpoint: testServer.URL})
282 }
283
284+func (s *S) TearDownTest(c *C) {
285+ testServer.Flush()
286+}
287+
288 func (s *S) TestRunInstancesErrorDump(c *C) {
289- testServer.PrepareResponse(400, nil, ErrorDump)
290+ testServer.Response(400, nil, ErrorDump)
291
292 options := ec2.RunInstances{
293 ImageId: "ami-a6f504cf", // Ubuntu Maverick, i386, instance store
294@@ -45,7 +56,7 @@
295 }
296
297 func (s *S) TestRunInstancesErrorWithoutXML(c *C) {
298- testServer.PrepareResponse(500, nil, "")
299+ testServer.Response(500, nil, "")
300 options := ec2.RunInstances{ImageId: "image-id"}
301
302 resp, err := s.ec2.RunInstances(&options)
303@@ -64,7 +75,7 @@
304 }
305
306 func (s *S) TestRunInstancesExample(c *C) {
307- testServer.PrepareResponse(200, nil, RunInstancesExample)
308+ testServer.Response(200, nil, RunInstancesExample)
309
310 options := ec2.RunInstances{
311 KeyName: "my-keys",
312@@ -145,7 +156,7 @@
313 }
314
315 func (s *S) TestTerminateInstancesExample(c *C) {
316- testServer.PrepareResponse(200, nil, TerminateInstancesExample)
317+ testServer.Response(200, nil, TerminateInstancesExample)
318
319 resp, err := s.ec2.TerminateInstances([]string{"i-1", "i-2"})
320
321@@ -175,7 +186,7 @@
322 }
323
324 func (s *S) TestDescribeInstancesExample1(c *C) {
325- testServer.PrepareResponse(200, nil, DescribeInstancesExample1)
326+ testServer.Response(200, nil, DescribeInstancesExample1)
327
328 filter := ec2.NewFilter()
329 filter.Add("key1", "value1")
330@@ -207,7 +218,7 @@
331 }
332
333 func (s *S) TestDescribeInstancesExample2(c *C) {
334- testServer.PrepareResponse(200, nil, DescribeInstancesExample2)
335+ testServer.Response(200, nil, DescribeInstancesExample2)
336
337 filter := ec2.NewFilter()
338 filter.Add("key1", "value1")
339@@ -244,7 +255,7 @@
340 }
341
342 func (s *S) TestDescribeImagesExample(c *C) {
343- testServer.PrepareResponse(200, nil, DescribeImagesExample)
344+ testServer.Response(200, nil, DescribeImagesExample)
345
346 filter := ec2.NewFilter()
347 filter.Add("key1", "value1")
348@@ -292,7 +303,7 @@
349 }
350
351 func (s *S) TestCreateSnapshotExample(c *C) {
352- testServer.PrepareResponse(200, nil, CreateSnapshotExample)
353+ testServer.Response(200, nil, CreateSnapshotExample)
354
355 resp, err := s.ec2.CreateSnapshot("vol-4d826724", "Daily Backup")
356
357@@ -314,7 +325,7 @@
358 }
359
360 func (s *S) TestDeleteSnapshotsExample(c *C) {
361- testServer.PrepareResponse(200, nil, DeleteSnapshotExample)
362+ testServer.Response(200, nil, DeleteSnapshotExample)
363
364 resp, err := s.ec2.DeleteSnapshots([]string{"snap-78a54011"})
365
366@@ -327,7 +338,7 @@
367 }
368
369 func (s *S) TestDescribeSnapshotsExample(c *C) {
370- testServer.PrepareResponse(200, nil, DescribeSnapshotsExample)
371+ testServer.Response(200, nil, DescribeSnapshotsExample)
372
373 filter := ec2.NewFilter()
374 filter.Add("key1", "value1")
375@@ -366,7 +377,7 @@
376 }
377
378 func (s *S) TestCreateSecurityGroupExample(c *C) {
379- testServer.PrepareResponse(200, nil, CreateSecurityGroupExample)
380+ testServer.Response(200, nil, CreateSecurityGroupExample)
381
382 resp, err := s.ec2.CreateSecurityGroup("websrv", "Web Servers")
383
384@@ -382,7 +393,7 @@
385 }
386
387 func (s *S) TestDescribeSecurityGroupsExample(c *C) {
388- testServer.PrepareResponse(200, nil, DescribeSecurityGroupsExample)
389+ testServer.Response(200, nil, DescribeSecurityGroupsExample)
390
391 resp, err := s.ec2.SecurityGroups([]ec2.SecurityGroup{{Name: "WebServers"}, {Name: "RangedPortsBySource"}}, nil)
392
393@@ -423,7 +434,7 @@
394 }
395
396 func (s *S) TestDescribeSecurityGroupsExampleWithFilter(c *C) {
397- testServer.PrepareResponse(200, nil, DescribeSecurityGroupsExample)
398+ testServer.Response(200, nil, DescribeSecurityGroupsExample)
399
400 filter := ec2.NewFilter()
401 filter.Add("ip-permission.protocol", "tcp")
402@@ -449,7 +460,7 @@
403 }
404
405 func (s *S) TestDescribeSecurityGroupsDumpWithGroup(c *C) {
406- testServer.PrepareResponse(200, nil, DescribeSecurityGroupsDump)
407+ testServer.Response(200, nil, DescribeSecurityGroupsDump)
408
409 resp, err := s.ec2.SecurityGroups(nil, nil)
410
411@@ -477,7 +488,7 @@
412 }
413
414 func (s *S) TestDeleteSecurityGroupExample(c *C) {
415- testServer.PrepareResponse(200, nil, DeleteSecurityGroupExample)
416+ testServer.Response(200, nil, DeleteSecurityGroupExample)
417
418 resp, err := s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: "websrv"})
419 req := testServer.WaitRequest()
420@@ -490,7 +501,7 @@
421 }
422
423 func (s *S) TestDeleteSecurityGroupExampleWithId(c *C) {
424- testServer.PrepareResponse(200, nil, DeleteSecurityGroupExample)
425+ testServer.Response(200, nil, DeleteSecurityGroupExample)
426
427 // ignore return and error - we're only want to check the parameter handling.
428 s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Id: "sg-67ad940e", Name: "ignored"})
429@@ -501,7 +512,7 @@
430 }
431
432 func (s *S) TestAuthorizeSecurityGroupExample1(c *C) {
433- testServer.PrepareResponse(200, nil, AuthorizeSecurityGroupIngressExample)
434+ testServer.Response(200, nil, AuthorizeSecurityGroupIngressExample)
435
436 perms := []ec2.IPPerm{{
437 Protocol: "tcp",
438@@ -526,7 +537,7 @@
439 }
440
441 func (s *S) TestAuthorizeSecurityGroupExample1WithId(c *C) {
442- testServer.PrepareResponse(200, nil, AuthorizeSecurityGroupIngressExample)
443+ testServer.Response(200, nil, AuthorizeSecurityGroupIngressExample)
444
445 perms := []ec2.IPPerm{{
446 Protocol: "tcp",
447@@ -544,7 +555,7 @@
448 }
449
450 func (s *S) TestAuthorizeSecurityGroupExample2(c *C) {
451- testServer.PrepareResponse(200, nil, AuthorizeSecurityGroupIngressExample)
452+ testServer.Response(200, nil, AuthorizeSecurityGroupIngressExample)
453
454 perms := []ec2.IPPerm{{
455 Protocol: "tcp",
456@@ -577,7 +588,7 @@
457 func (s *S) TestRevokeSecurityGroupExample(c *C) {
458 // RevokeSecurityGroup is implemented by the same code as AuthorizeSecurityGroup
459 // so there's no need to duplicate all the tests.
460- testServer.PrepareResponse(200, nil, RevokeSecurityGroupIngressExample)
461+ testServer.Response(200, nil, RevokeSecurityGroupIngressExample)
462
463 resp, err := s.ec2.RevokeSecurityGroup(ec2.SecurityGroup{Name: "websrv"}, nil)
464
465@@ -590,7 +601,7 @@
466 }
467
468 func (s *S) TestCreateTags(c *C) {
469- testServer.PrepareResponse(200, nil, CreateTagsExample)
470+ testServer.Response(200, nil, CreateTagsExample)
471
472 resp, err := s.ec2.CreateTags([]string{"ami-1a2b3c4d", "i-7f4d3a2b"}, []ec2.Tag{{"webserver", ""}, {"stack", "Production"}})
473
474@@ -607,7 +618,7 @@
475 }
476
477 func (s *S) TestStartInstances(c *C) {
478- testServer.PrepareResponse(200, nil, StartInstancesExample)
479+ testServer.Response(200, nil, StartInstancesExample)
480
481 resp, err := s.ec2.StartInstances("i-10a64379")
482 req := testServer.WaitRequest()
483@@ -627,7 +638,7 @@
484 }
485
486 func (s *S) TestStopInstances(c *C) {
487- testServer.PrepareResponse(200, nil, StopInstancesExample)
488+ testServer.Response(200, nil, StopInstancesExample)
489
490 resp, err := s.ec2.StopInstances("i-10a64379")
491 req := testServer.WaitRequest()
492@@ -647,7 +658,7 @@
493 }
494
495 func (s *S) TestRebootInstances(c *C) {
496- testServer.PrepareResponse(200, nil, RebootInstancesExample)
497+ testServer.Response(200, nil, RebootInstancesExample)
498
499 resp, err := s.ec2.RebootInstances("i-10a64379")
500 req := testServer.WaitRequest()
501@@ -663,7 +674,7 @@
502 ec2.FakeTime(true)
503 defer ec2.FakeTime(false)
504
505- testServer.PrepareResponse(200, nil, RebootInstancesExample)
506+ testServer.Response(200, nil, RebootInstancesExample)
507
508 // https://bugs.launchpad.net/goamz/+bug/1022749
509 ec2 := ec2.New(s.ec2.Auth, aws.Region{EC2Endpoint: testServer.URL + "/services/Cloud"})
510
511=== modified file 'ec2/ec2i_test.go'
512--- ec2/ec2i_test.go 2012-10-28 16:05:46 +0000
513+++ ec2/ec2i_test.go 2013-01-31 17:09:20 +0000
514@@ -2,15 +2,13 @@
515
516 import (
517 "crypto/rand"
518- "flag"
519 "fmt"
520 "launchpad.net/goamz/aws"
521 "launchpad.net/goamz/ec2"
522+ "launchpad.net/goamz/testutil"
523 . "launchpad.net/gocheck"
524 )
525
526-var amazon = flag.Bool("amazon", false, "Enable tests against amazon server")
527-
528 // AmazonServer represents an Amazon EC2 server.
529 type AmazonServer struct {
530 auth aws.Auth
531@@ -34,7 +32,7 @@
532 }
533
534 func (s *AmazonClientSuite) SetUpSuite(c *C) {
535- if !*amazon {
536+ if !testutil.Amazon {
537 c.Skip("AmazonClientSuite tests not enabled")
538 }
539 s.srv.SetUp(c)
540
541=== modified file 'ec2/ec2t_test.go'
542--- ec2/ec2t_test.go 2012-10-28 16:05:46 +0000
543+++ ec2/ec2t_test.go 2013-01-31 17:09:20 +0000
544@@ -5,6 +5,7 @@
545 "launchpad.net/goamz/aws"
546 "launchpad.net/goamz/ec2"
547 "launchpad.net/goamz/ec2/ec2test"
548+ "launchpad.net/goamz/testutil"
549 . "launchpad.net/gocheck"
550 "regexp"
551 "sort"
552@@ -88,7 +89,7 @@
553 var _ = Suite(&AmazonServerSuite{})
554
555 func (s *AmazonServerSuite) SetUpSuite(c *C) {
556- if !*amazon {
557+ if !testutil.Amazon {
558 c.Skip("AmazonServerSuite tests not enabled")
559 }
560 s.srv.SetUp(c)
561@@ -435,17 +436,13 @@
562
563 func (s *ServerTests) TestGroupFiltering(c *C) {
564 g := make([]ec2.SecurityGroup, 4)
565- for i := range g[0:3] {
566+ for i := range g {
567 resp, err := s.ec2.CreateSecurityGroup(sessionName(fmt.Sprintf("testgroup%d", i)), fmt.Sprintf("testdescription%d", i))
568 c.Assert(err, IsNil)
569 g[i] = resp.SecurityGroup
570 c.Logf("group %d: %v", i, g[i])
571 defer s.ec2.DeleteSecurityGroup(g[i])
572 }
573- // Get the default group.
574- resp, err := s.ec2.SecurityGroups([]ec2.SecurityGroup{{Name: "default"}}, nil)
575- c.Assert(err, IsNil)
576- g[3] = resp.Groups[0].SecurityGroup
577
578 perms := [][]ec2.IPPerm{
579 {{
580@@ -536,7 +533,7 @@
581 filterCheck("group-name", g[2].Name, groups(2)),
582 filterCheck("ip-permission.cidr", "1.2.3.4/32", groups(0)),
583 filterCheck("ip-permission.group-name", g[1].Name, groups(1, 2)),
584- filterCheck("ip-permission.protocol", "udp", groups(2, 3)),
585+ filterCheck("ip-permission.protocol", "udp", groups(2)),
586 filterCheck("ip-permission.from-port", "200", groups(1, 2)),
587 filterCheck("ip-permission.to-port", "200", groups(0)),
588 // TODO owner-id
589@@ -568,7 +565,7 @@
590 if t.allowExtra {
591 namePat := regexp.MustCompile(sessionName("testgroup[0-9]"))
592 for id, g := range groups {
593- if g.Name != "default" && !namePat.MatchString(g.Name) {
594+ if !namePat.MatchString(g.Name) {
595 delete(groups, id)
596 }
597 }
598
599=== modified file 'ec2/ec2test/filter.go'
600--- ec2/ec2test/filter.go 2012-03-09 14:02:34 +0000
601+++ ec2/ec2test/filter.go 2013-01-31 17:09:20 +0000
602@@ -13,13 +13,13 @@
603 type filter map[string][]string
604
605 // newFilter creates a new filter from the Filter fields in the url form.
606-//
607+//
608 // The filtering is specified through a map of name=>values, where the
609 // name is a well-defined key identifying the data to be matched,
610 // and the list of values holds the possible values the filtered
611 // item can take for the key to be included in the
612 // result set. For example:
613-//
614+//
615 // Filter.1.Name=instance-type
616 // Filter.1.Value.1=m1.small
617 // Filter.1.Value.2=m1.large
618
619=== modified file 'ec2/ec2test/server.go'
620--- ec2/ec2test/server.go 2012-09-11 14:10:43 +0000
621+++ ec2/ec2test/server.go 2013-01-31 17:09:20 +0000
622@@ -417,18 +417,18 @@
623 }
624
625 // TODO attributes still to consider:
626- // ImageId: accept anything, we can verify later
627- // KeyName ?
628- // InstanceType ?
629- // KernelId ?
630- // RamdiskId ?
631- // AvailZone ?
632- // GroupName tag
633- // Monitoring ignore?
634- // SubnetId ?
635- // DisableAPITermination bool
636- // ShutdownBehavior string
637- // PrivateIPAddress string
638+ // ImageId: accept anything, we can verify later
639+ // KeyName ?
640+ // InstanceType ?
641+ // KernelId ?
642+ // RamdiskId ?
643+ // AvailZone ?
644+ // GroupName tag
645+ // Monitoring ignore?
646+ // SubnetId ?
647+ // DisableAPITermination bool
648+ // ShutdownBehavior string
649+ // PrivateIPAddress string
650
651 srv.mu.Lock()
652 defer srv.mu.Unlock()
653
654=== modified file 'ec2/sign.go'
655--- ec2/sign.go 2012-10-28 16:04:45 +0000
656+++ ec2/sign.go 2013-01-31 17:09:20 +0000
657@@ -19,10 +19,10 @@
658 params["SignatureVersion"] = "2"
659 params["SignatureMethod"] = "HmacSHA256"
660
661- // AWS specifies that the parameters in a signed request must
662- // be in natural order of the keys. This is distinct from the
663- // natural order of the encoded value of key=value. Basically
664- // percent and equals affect the sorting order.
665+ // AWS specifies that the parameters in a signed request must
666+ // be provided in the natural order of the keys. This is distinct
667+ // from the natural order of the encoded value of key=value.
668+ // Percent and equals affect the sorting order.
669 var keys, sarray []string
670 for k, _ := range params {
671 keys = append(keys, k)
672
673=== removed file 'ec2/suite_test.go'
674--- ec2/suite_test.go 2012-08-31 08:11:21 +0000
675+++ ec2/suite_test.go 1970-01-01 00:00:00 +0000
676@@ -1,118 +0,0 @@
677-package ec2_test
678-
679-import (
680- "fmt"
681- . "launchpad.net/gocheck"
682- "net/http"
683- "net/url"
684- "os"
685- "testing"
686- "time"
687-)
688-
689-func Test(t *testing.T) {
690- TestingT(t)
691-}
692-
693-type HTTPSuite struct{}
694-
695-var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
696-
697-func (s *HTTPSuite) SetUpSuite(c *C) {
698- testServer.Start()
699-}
700-
701-func (s *HTTPSuite) TearDownTest(c *C) {
702- testServer.FlushRequests()
703-}
704-
705-type TestHTTPServer struct {
706- URL string
707- Timeout time.Duration
708- started bool
709- request chan *http.Request
710- response chan *testResponse
711- pending chan bool
712-}
713-
714-type testResponse struct {
715- Status int
716- Headers map[string]string
717- Body string
718-}
719-
720-func NewTestHTTPServer(url string, timeout time.Duration) *TestHTTPServer {
721- return &TestHTTPServer{URL: url, Timeout: timeout}
722-}
723-
724-func (s *TestHTTPServer) Start() {
725- if s.started {
726- return
727- }
728- s.started = true
729-
730- s.request = make(chan *http.Request, 64)
731- s.response = make(chan *testResponse, 64)
732- s.pending = make(chan bool, 64)
733-
734- url, _ := url.Parse(s.URL)
735- go http.ListenAndServe(url.Host, s)
736-
737- s.PrepareResponse(202, nil, "Nothing.")
738- for {
739- // Wait for it to be up.
740- resp, err := http.Get(s.URL)
741- if err == nil && resp.StatusCode == 202 {
742- break
743- }
744- time.Sleep(1e8)
745- }
746- s.WaitRequest() // Consume dummy request.
747-}
748-
749-// FlushRequests discards requests which were not yet consumed by WaitRequest.
750-func (s *TestHTTPServer) FlushRequests() {
751- for {
752- select {
753- case <-s.request:
754- default:
755- return
756- }
757- }
758-}
759-
760-func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
761- s.request <- req
762- var resp *testResponse
763- select {
764- case resp = <-s.response:
765- case <-time.After(s.Timeout):
766- fmt.Fprintf(os.Stderr, "ERROR: Timeout waiting for test to provide response\n")
767- resp = &testResponse{500, nil, ""}
768- }
769- if resp.Headers != nil {
770- h := w.Header()
771- for k, v := range resp.Headers {
772- h.Set(k, v)
773- }
774- }
775- if resp.Status != 0 {
776- w.WriteHeader(resp.Status)
777- }
778- w.Write([]byte(resp.Body))
779-}
780-
781-func (s *TestHTTPServer) WaitRequest() *http.Request {
782- select {
783- case req := <-s.request:
784- req.ParseForm()
785- return req
786- case <-time.After(s.Timeout):
787- panic("Timeout waiting for goamz request")
788- }
789- panic("unreached")
790-}
791-
792-func (s *TestHTTPServer) PrepareResponse(status int, headers map[string]string, body string) {
793- s.response <- &testResponse{status, headers, body}
794-}
795
796=== modified file 'exp/mturk/mturk.go'
797--- exp/mturk/mturk.go 2012-05-03 17:12:28 +0000
798+++ exp/mturk/mturk.go 2013-01-31 17:09:20 +0000
799@@ -43,7 +43,7 @@
800 // ----------------------------------------------------------------------------
801 // Request dispatching logic.
802
803-// Error encapsulates an error returned by MTurk.
804+// Error encapsulates an error returned by MTurk.
805 type Error struct {
806 StatusCode int // HTTP status code (200, 403, ...)
807 Code string // EC2 error code ("UnsupportedOperation", ...)
808@@ -150,7 +150,7 @@
809 // Corresponds to the "CreateHIT" operation of the Mechanical Turk
810 // API. http://goo.gl/cDBRc Currently only supports "external"
811 // questions (see "HIT" struct above). If "keywords", "maxAssignments",
812-// "qualificationRequirement" or "requesterAnnotation" are the zero
813+// "qualificationRequirement" or "requesterAnnotation" are the zero
814 // value for their types, they will not be included in the request.
815 func (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) {
816 params := make(map[string]string)
817@@ -191,8 +191,8 @@
818
819 // Corresponds to the "CreateHIT" operation of the Mechanical Turk
820 // API, using an existing "hit type". http://goo.gl/cDBRc Currently only
821-// supports "external" questions (see "HIT" struct above). If
822-// "maxAssignments" or "requesterAnnotation" are the zero value for
823+// supports "external" questions (see "HIT" struct above). If
824+// "maxAssignments" or "requesterAnnotation" are the zero value for
825 // their types, they will not be included in the request.
826 func (mt *MTurk) CreateHITOfType(hitTypeId string, q ExternalQuestion, lifetimeInSeconds uint, maxAssignments uint, requesterAnnotation string) (h *HIT, err error) {
827 params := make(map[string]string)
828@@ -217,7 +217,7 @@
829 return
830 }
831
832-// Corresponds to "SearchHITs" operation of Mechanical Turk. http://goo.gl/PskcX
833+// Corresponds to "SearchHITs" operation of Mechanical Turk. http://goo.gl/PskcX
834 // Currenlty supports none of the optional parameters.
835 func (mt *MTurk) SearchHITs() (s *SearchHITsResult, err error) {
836 params := make(map[string]string)
837
838=== modified file 'exp/mturk/mturk_test.go'
839--- exp/mturk/mturk_test.go 2012-05-03 17:12:28 +0000
840+++ exp/mturk/mturk_test.go 2013-01-31 17:09:20 +0000
841@@ -3,19 +3,26 @@
842 import (
843 "launchpad.net/goamz/aws"
844 "launchpad.net/goamz/exp/mturk"
845+ "launchpad.net/goamz/testutil"
846 . "launchpad.net/gocheck"
847 "net/url"
848+ "testing"
849 )
850
851+func Test(t *testing.T) {
852+ TestingT(t)
853+}
854+
855 var _ = Suite(&S{})
856
857 type S struct {
858- HTTPSuite
859 mturk *mturk.MTurk
860 }
861
862+var testServer = testutil.NewHTTPServer()
863+
864 func (s *S) SetUpSuite(c *C) {
865- s.HTTPSuite.SetUpSuite(c)
866+ testServer.Start()
867 auth := aws.Auth{"abc", "123"}
868 u, err := url.Parse(testServer.URL)
869 if err != nil {
870@@ -28,8 +35,12 @@
871 }
872 }
873
874+func (s *S) TearDownTest(c *C) {
875+ testServer.Flush()
876+}
877+
878 func (s *S) TestCreateHIT(c *C) {
879- testServer.PrepareResponse(200, nil, BasicHitResponse)
880+ testServer.Response(200, nil, BasicHitResponse)
881
882 question := mturk.ExternalQuestion{
883 ExternalURL: "http://www.amazon.com",
884@@ -51,7 +62,7 @@
885 }
886
887 func (s *S) TestSearchHITs(c *C) {
888- testServer.PrepareResponse(200, nil, SearchHITResponse)
889+ testServer.Response(200, nil, SearchHITResponse)
890
891 hitResult, err := s.mturk.SearchHITs()
892
893
894=== removed file 'exp/mturk/suite_test.go'
895--- exp/mturk/suite_test.go 2012-03-09 15:34:56 +0000
896+++ exp/mturk/suite_test.go 1970-01-01 00:00:00 +0000
897@@ -1,120 +0,0 @@
898-package mturk_test
899-
900-import (
901- "fmt"
902- . "launchpad.net/gocheck"
903- "net/http"
904- "net/url"
905- "os"
906- "testing"
907- "time"
908-)
909-
910-func Test(t *testing.T) {
911- TestingT(t)
912-}
913-
914-type HTTPSuite struct{}
915-
916-var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
917-
918-func (s *HTTPSuite) SetUpSuite(c *C) {
919- testServer.Start()
920-}
921-
922-func (s *HTTPSuite) TearDownTest(c *C) {
923- testServer.FlushRequests()
924-}
925-
926-type TestHTTPServer struct {
927- URL string
928- Timeout time.Duration
929- started bool
930- request chan *http.Request
931- response chan *testResponse
932- pending chan bool
933-}
934-
935-type testResponse struct {
936- Status int
937- Headers map[string]string
938- Body string
939-}
940-
941-func NewTestHTTPServer(url string, timeout time.Duration) *TestHTTPServer {
942- return &TestHTTPServer{URL: url, Timeout: timeout}
943-}
944-
945-func (s *TestHTTPServer) Start() {
946- if s.started {
947- return
948- }
949- s.started = true
950-
951- s.request = make(chan *http.Request, 64)
952- s.response = make(chan *testResponse, 64)
953- s.pending = make(chan bool, 64)
954-
955- url, _ := url.Parse(s.URL)
956- go http.ListenAndServe(url.Host, s)
957-
958- s.PrepareResponse(202, nil, "Nothing.")
959- for {
960- // Wait for it to be up.
961- resp, err := http.Get(s.URL)
962- if err == nil && resp.StatusCode == 202 {
963- break
964- }
965- fmt.Fprintf(os.Stderr, "\nWaiting for fake server to be up... ")
966- time.Sleep(1e8)
967- }
968- fmt.Fprintf(os.Stderr, "done\n\n")
969- s.WaitRequest() // Consume dummy request.
970-}
971-
972-// FlushRequests discards requests which were not yet consumed by WaitRequest.
973-func (s *TestHTTPServer) FlushRequests() {
974- for {
975- select {
976- case <-s.request:
977- default:
978- return
979- }
980- }
981-}
982-
983-func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
984- s.request <- req
985- var resp *testResponse
986- select {
987- case resp = <-s.response:
988- case <-time.After(s.Timeout):
989- fmt.Fprintf(os.Stderr, "ERROR: Timeout waiting for test to provide response\n")
990- resp = &testResponse{500, nil, ""}
991- }
992- if resp.Headers != nil {
993- h := w.Header()
994- for k, v := range resp.Headers {
995- h.Set(k, v)
996- }
997- }
998- if resp.Status != 0 {
999- w.WriteHeader(resp.Status)
1000- }
1001- w.Write([]byte(resp.Body))
1002-}
1003-
1004-func (s *TestHTTPServer) WaitRequest() *http.Request {
1005- select {
1006- case req := <-s.request:
1007- req.ParseForm()
1008- return req
1009- case <-time.After(s.Timeout):
1010- panic("Timeout waiting for goamz request")
1011- }
1012- panic("unreached")
1013-}
1014-
1015-func (s *TestHTTPServer) PrepareResponse(status int, headers map[string]string, body string) {
1016- s.response <- &testResponse{status, headers, body}
1017-}
1018
1019=== modified file 'exp/sdb/sdb.go'
1020--- exp/sdb/sdb.go 2012-03-09 15:34:56 +0000
1021+++ exp/sdb/sdb.go 2013-01-31 17:09:20 +0000
1022@@ -18,7 +18,7 @@
1023
1024 // BUG: SelectResp isn't properly organized. It must change.
1025
1026-//
1027+//
1028
1029 import (
1030 "encoding/xml"
1031@@ -129,7 +129,7 @@
1032
1033 // Select returns a set of items and attributes that match expr.
1034 // Select is similar to the standard SQL SELECT statement.
1035-//
1036+//
1037 // See http://goo.gl/GTsSZ for more details.
1038 func (sdb *SDB) Select(expr string, consistent bool) (resp *SelectResp, err error) {
1039 resp = &SelectResp{}
1040@@ -206,7 +206,7 @@
1041 pa.missing[name] = true
1042 }
1043
1044-// PutAttrs adds attrs to item.
1045+// PutAttrs adds attrs to item.
1046 //
1047 // See http://goo.gl/yTAV4 for more details.
1048 func (item *Item) PutAttrs(attrs *PutAttrs) (resp *SimpleResp, err error) {
1049
1050=== modified file 'exp/sdb/sdb_test.go'
1051--- exp/sdb/sdb_test.go 2012-03-09 15:34:56 +0000
1052+++ exp/sdb/sdb_test.go 2013-01-31 17:09:20 +0000
1053@@ -3,24 +3,35 @@
1054 import (
1055 "launchpad.net/goamz/aws"
1056 "launchpad.net/goamz/exp/sdb"
1057+ "launchpad.net/goamz/testutil"
1058 . "launchpad.net/gocheck"
1059+ "testing"
1060 )
1061
1062+func Test(t *testing.T) {
1063+ TestingT(t)
1064+}
1065+
1066 var _ = Suite(&S{})
1067
1068 type S struct {
1069- HTTPSuite
1070 sdb *sdb.SDB
1071 }
1072
1073+var testServer = testutil.NewHTTPServer()
1074+
1075 func (s *S) SetUpSuite(c *C) {
1076- s.HTTPSuite.SetUpSuite(c)
1077+ testServer.Start()
1078 auth := aws.Auth{"abc", "123"}
1079 s.sdb = sdb.New(auth, aws.Region{SDBEndpoint: testServer.URL})
1080 }
1081
1082+func (s *S) TearDownTest(c *C) {
1083+ testServer.Flush()
1084+}
1085+
1086 func (s *S) TestCreateDomainOK(c *C) {
1087- testServer.PrepareResponse(200, nil, TestCreateDomainXmlOK)
1088+ testServer.Response(200, nil, TestCreateDomainXmlOK)
1089
1090 domain := s.sdb.Domain("domain")
1091 resp, err := domain.CreateDomain()
1092@@ -37,7 +48,7 @@
1093 }
1094
1095 func (s *S) TestListDomainsOK(c *C) {
1096- testServer.PrepareResponse(200, nil, TestListDomainsXmlOK)
1097+ testServer.Response(200, nil, TestListDomainsXmlOK)
1098
1099 resp, err := s.sdb.ListDomains()
1100 req := testServer.WaitRequest()
1101@@ -54,7 +65,7 @@
1102 }
1103
1104 func (s *S) TestListDomainsWithNextTokenXmlOK(c *C) {
1105- testServer.PrepareResponse(200, nil, TestListDomainsWithNextTokenXmlOK)
1106+ testServer.Response(200, nil, TestListDomainsWithNextTokenXmlOK)
1107
1108 resp, err := s.sdb.ListDomains()
1109 req := testServer.WaitRequest()
1110@@ -72,7 +83,7 @@
1111 }
1112
1113 func (s *S) TestDeleteDomainOK(c *C) {
1114- testServer.PrepareResponse(200, nil, TestDeleteDomainXmlOK)
1115+ testServer.Response(200, nil, TestDeleteDomainXmlOK)
1116
1117 domain := s.sdb.Domain("domain")
1118 resp, err := domain.DeleteDomain()
1119@@ -89,7 +100,7 @@
1120 }
1121
1122 func (s *S) TestPutAttrsOK(c *C) {
1123- testServer.PrepareResponse(200, nil, TestPutAttrsXmlOK)
1124+ testServer.Response(200, nil, TestPutAttrsXmlOK)
1125
1126 domain := s.sdb.Domain("MyDomain")
1127 item := domain.Item("Item123")
1128@@ -128,7 +139,7 @@
1129 }
1130
1131 func (s *S) TestAttrsOK(c *C) {
1132- testServer.PrepareResponse(200, nil, TestAttrsXmlOK)
1133+ testServer.Response(200, nil, TestAttrsXmlOK)
1134
1135 domain := s.sdb.Domain("MyDomain")
1136 item := domain.Item("Item123")
1137@@ -155,7 +166,7 @@
1138 }
1139
1140 func (s *S) TestAttrsSelectOK(c *C) {
1141- testServer.PrepareResponse(200, nil, TestAttrsXmlOK)
1142+ testServer.Response(200, nil, TestAttrsXmlOK)
1143
1144 domain := s.sdb.Domain("MyDomain")
1145 item := domain.Item("Item123")
1146@@ -184,7 +195,7 @@
1147 }
1148
1149 func (s *S) TestSelectOK(c *C) {
1150- testServer.PrepareResponse(200, nil, TestSelectXmlOK)
1151+ testServer.Response(200, nil, TestSelectXmlOK)
1152
1153 resp, err := s.sdb.Select("select Color from MyDomain where Color like 'Blue%'", true)
1154 req := testServer.WaitRequest()
1155
1156=== removed file 'exp/sdb/suite_test.go'
1157--- exp/sdb/suite_test.go 2012-03-09 15:34:56 +0000
1158+++ exp/sdb/suite_test.go 1970-01-01 00:00:00 +0000
1159@@ -1,139 +0,0 @@
1160-package sdb_test
1161-
1162-import (
1163- "flag"
1164- "fmt"
1165- "launchpad.net/goamz/aws"
1166- "launchpad.net/gocheck"
1167- "net/http"
1168- "net/url"
1169- "os"
1170- "testing"
1171- "time"
1172-)
1173-
1174-func Test(t *testing.T) {
1175- gocheck.TestingT(t)
1176-}
1177-
1178-var integration = flag.Bool("i", false, "Enable integration tests")
1179-
1180-type SuiteI struct {
1181- auth aws.Auth
1182-}
1183-
1184-func (s *SuiteI) SetUpSuite(c *gocheck.C) {
1185- if !*integration {
1186- c.Skip("Integration tests not enabled (-int flag)")
1187- }
1188- auth, err := aws.EnvAuth()
1189- if err != nil {
1190- c.Fatal(err)
1191- }
1192- s.auth = auth
1193-}
1194-
1195-type HTTPSuite struct{}
1196-
1197-var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
1198-
1199-func (s *HTTPSuite) SetUpSuite(c *gocheck.C) {
1200- testServer.Start()
1201-}
1202-
1203-func (s *HTTPSuite) TearDownTest(c *gocheck.C) {
1204- testServer.FlushRequests()
1205-}
1206-
1207-type TestHTTPServer struct {
1208- URL string
1209- Timeout time.Duration
1210- started bool
1211- request chan *http.Request
1212- response chan *testResponse
1213- pending chan bool
1214-}
1215-
1216-type testResponse struct {
1217- Status int
1218- Headers map[string]string
1219- Body string
1220-}
1221-
1222-func NewTestHTTPServer(url_ string, timeout time.Duration) *TestHTTPServer {
1223- return &TestHTTPServer{URL: url_, Timeout: timeout}
1224-}
1225-
1226-func (s *TestHTTPServer) Start() {
1227- if s.started {
1228- return
1229- }
1230- s.started = true
1231-
1232- s.request = make(chan *http.Request, 64)
1233- s.response = make(chan *testResponse, 64)
1234- s.pending = make(chan bool, 64)
1235-
1236- url_, _ := url.Parse(s.URL)
1237- go http.ListenAndServe(url_.Host, s)
1238-
1239- s.PrepareResponse(202, nil, "Nothing.")
1240- for {
1241- // Wait for it to be up.
1242- resp, err := http.Get(s.URL)
1243- if err == nil && resp.StatusCode == 202 {
1244- break
1245- }
1246- fmt.Fprintf(os.Stderr, "\nWaiting for fake server to be up... ")
1247- time.Sleep(1e8)
1248- }
1249- fmt.Fprintf(os.Stderr, "done\n\n")
1250- s.WaitRequest() // Consume dummy request.
1251-}
1252-
1253-// FlushRequests discards requests which were not yet consumed by WaitRequest.
1254-func (s *TestHTTPServer) FlushRequests() {
1255- for {
1256- select {
1257- case <-s.request:
1258- default:
1259- return
1260- }
1261- }
1262-}
1263-
1264-func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
1265- s.request <- req
1266- var resp *testResponse
1267- select {
1268- case resp = <-s.response:
1269- case <-time.After(s.Timeout):
1270- fmt.Fprintf(os.Stderr, "ERROR: Timeout waiting for test to provide response\n")
1271- resp = &testResponse{500, nil, ""}
1272- }
1273- if resp.Headers != nil {
1274- h := w.Header()
1275- for k, v := range resp.Headers {
1276- h.Set(k, v)
1277- }
1278- }
1279- if resp.Status != 0 {
1280- w.WriteHeader(resp.Status)
1281- }
1282- w.Write([]byte(resp.Body))
1283-}
1284-
1285-func (s *TestHTTPServer) WaitRequest() *http.Request {
1286- select {
1287- case req := <-s.request:
1288- req.ParseForm()
1289- return req
1290- case <-time.After(s.Timeout):
1291- panic("Timeout waiting for goamz request")
1292- }
1293- panic("unreached")
1294-}
1295-
1296-func (s *TestHTTPServer) PrepareResponse(status int, headers map[string]string, body string) {
1297- s.response <- &testResponse{status, headers, body}
1298-}
1299
1300=== modified file 'exp/sns/sns_test.go'
1301--- exp/sns/sns_test.go 2012-05-03 17:12:28 +0000
1302+++ exp/sns/sns_test.go 2013-01-31 17:09:20 +0000
1303@@ -3,22 +3,33 @@
1304 import (
1305 "launchpad.net/goamz/aws"
1306 "launchpad.net/goamz/exp/sns"
1307+ "launchpad.net/goamz/testutil"
1308 . "launchpad.net/gocheck"
1309+ "testing"
1310 )
1311
1312+func Test(t *testing.T) {
1313+ TestingT(t)
1314+}
1315+
1316 var _ = Suite(&S{})
1317
1318 type S struct {
1319- HTTPSuite
1320 sns *sns.SNS
1321 }
1322
1323+var testServer = testutil.NewHTTPServer()
1324+
1325 func (s *S) SetUpSuite(c *C) {
1326- s.HTTPSuite.SetUpSuite(c)
1327+ testServer.Start()
1328 auth := aws.Auth{"abc", "123"}
1329 s.sns = sns.New(auth, aws.Region{SNSEndpoint: testServer.URL})
1330 }
1331
1332+func (s *S) TearDownTest(c *C) {
1333+ testServer.Flush()
1334+}
1335+
1336 func (s *S) TestListTopicsOK(c *C) {
1337 testServer.Response(200, nil, TestListTopicsXmlOK)
1338
1339
1340=== removed file 'exp/sns/suite_test.go'
1341--- exp/sns/suite_test.go 2012-03-09 15:34:56 +0000
1342+++ exp/sns/suite_test.go 1970-01-01 00:00:00 +0000
1343@@ -1,200 +0,0 @@
1344-package sns_test
1345-
1346-import (
1347- "bytes"
1348- "flag"
1349- "fmt"
1350- "io/ioutil"
1351- . "launchpad.net/gocheck"
1352- "net/http"
1353- "net/url"
1354- "os"
1355- "testing"
1356- "time"
1357-)
1358-
1359-func Test(t *testing.T) {
1360- TestingT(t)
1361-}
1362-
1363-var integration = flag.Bool("i", false, "Enable integration tests")
1364-
1365-type SuiteI struct{}
1366-
1367-func (s *SuiteI) SetUpSuite(c *C) {
1368- if !*integration {
1369- c.Skip("Integration tests not enabled (-i flag)")
1370- }
1371-}
1372-
1373-type HTTPSuite struct{}
1374-
1375-var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
1376-
1377-func (s *HTTPSuite) SetUpSuite(c *C) {
1378- testServer.Start()
1379-}
1380-
1381-func (s *HTTPSuite) TearDownTest(c *C) {
1382- testServer.Flush()
1383-}
1384-
1385-type TestHTTPServer struct {
1386- URL string
1387- Timeout time.Duration
1388- started bool
1389- request chan *http.Request
1390- response chan ResponseFunc
1391- pending chan bool
1392-}
1393-
1394-func NewTestHTTPServer(url_ string, timeout time.Duration) *TestHTTPServer {
1395- return &TestHTTPServer{URL: url_, Timeout: timeout}
1396-}
1397-
1398-type Response struct {
1399- Status int
1400- Headers map[string]string
1401- Body string
1402-}
1403-
1404-type ResponseFunc func(path string) Response
1405-
1406-func (s *TestHTTPServer) Start() {
1407- if s.started {
1408- return
1409- }
1410- s.started = true
1411-
1412- s.request = make(chan *http.Request, 64)
1413- s.response = make(chan ResponseFunc, 64)
1414- s.pending = make(chan bool, 64)
1415-
1416- url_, _ := url.Parse(s.URL)
1417- go http.ListenAndServe(url_.Host, s)
1418-
1419- s.Response(203, nil, "")
1420- for {
1421- // Wait for it to be up.
1422- resp, err := http.Get(s.URL)
1423- if err == nil && resp.StatusCode == 203 {
1424- break
1425- }
1426- fmt.Fprintf(os.Stderr, "\nWaiting for fake server to be up... ")
1427- time.Sleep(1e8)
1428- }
1429- fmt.Fprintf(os.Stderr, "done\n\n")
1430- s.WaitRequest() // Consume dummy request.
1431-}
1432-
1433-// FlushRequests discards requests which were not yet consumed by WaitRequest.
1434-func (s *TestHTTPServer) Flush() {
1435- for {
1436- select {
1437- case <-s.request:
1438- case <-s.response:
1439- default:
1440- return
1441- }
1442- }
1443-}
1444-
1445-func body(req *http.Request) string {
1446- data, err := ioutil.ReadAll(req.Body)
1447- if err != nil {
1448- panic(err)
1449- }
1450- return string(data)
1451-}
1452-
1453-func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
1454- req.ParseMultipartForm(1e6)
1455- data, err := ioutil.ReadAll(req.Body)
1456- if err != nil {
1457- panic(err)
1458- }
1459- req.Body = ioutil.NopCloser(bytes.NewBuffer(data))
1460- s.request <- req
1461- var resp Response
1462- select {
1463- case respFunc := <-s.response:
1464- resp = respFunc(req.URL.Path)
1465- case <-time.After(s.Timeout):
1466- const msg = "ERROR: Timeout waiting for test to prepare a response\n"
1467- fmt.Fprintf(os.Stderr, msg)
1468- resp = Response{500, nil, msg}
1469- }
1470- if resp.Headers != nil {
1471- h := w.Header()
1472- for k, v := range resp.Headers {
1473- h.Set(k, v)
1474- }
1475- }
1476- if resp.Status != 0 {
1477- w.WriteHeader(resp.Status)
1478- }
1479- w.Write([]byte(resp.Body))
1480-}
1481-
1482-// WaitRequests returns the next n requests made to the http server from
1483-// the queue. If not enough requests were previously made, it waits until
1484-// the timeout value for them to be made.
1485-func (s *TestHTTPServer) WaitRequests(n int) []*http.Request {
1486- reqs := make([]*http.Request, 0, n)
1487- for i := 0; i < n; i++ {
1488- select {
1489- case req := <-s.request:
1490- reqs = append(reqs, req)
1491- case <-time.After(s.Timeout):
1492- panic("Timeout waiting for request")
1493- }
1494- }
1495- return reqs
1496-}
1497-
1498-// WaitRequest returns the next request made to the http server from
1499-// the queue. If no requests were previously made, it waits until the
1500-// timeout value for one to be made.
1501-func (s *TestHTTPServer) WaitRequest() *http.Request {
1502- return s.WaitRequests(1)[0]
1503-}
1504-
1505-// ResponseFunc prepares the test server to respond the following n
1506-// requests using f to build each response.
1507-func (s *TestHTTPServer) ResponseFunc(n int, f ResponseFunc) {
1508- for i := 0; i < n; i++ {
1509- s.response <- f
1510- }
1511-}
1512-
1513-// ResponseMap maps request paths to responses.
1514-type ResponseMap map[string]Response
1515-
1516-// ResponseMap prepares the test server to respond the following n
1517-// requests using the m to obtain the responses.
1518-func (s *TestHTTPServer) ResponseMap(n int, m ResponseMap) {
1519- f := func(path string) Response {
1520- for rpath, resp := range m {
1521- if rpath == path {
1522- return resp
1523- }
1524- }
1525- return Response{Status: 500, Body: "Path not found in response map: " + path}
1526- }
1527- s.ResponseFunc(n, f)
1528-}
1529-
1530-// Responses prepares the test server to respond the following n requests
1531-// using the provided response parameters.
1532-func (s *TestHTTPServer) Responses(n int, status int, headers map[string]string, body string) {
1533- f := func(path string) Response {
1534- return Response{status, headers, body}
1535- }
1536- s.ResponseFunc(n, f)
1537-}
1538-
1539-// Response prepares the test server to respond the following request
1540-// using the provided response parameters.
1541-func (s *TestHTTPServer) Response(status int, headers map[string]string, body string) {
1542- s.Responses(1, status, headers, body)
1543-}
1544
1545=== modified file 'iam/iam_test.go'
1546--- iam/iam_test.go 2012-10-10 20:16:54 +0000
1547+++ iam/iam_test.go 2013-01-31 17:09:20 +0000
1548@@ -3,24 +3,35 @@
1549 import (
1550 "launchpad.net/goamz/aws"
1551 "launchpad.net/goamz/iam"
1552+ "launchpad.net/goamz/testutil"
1553 . "launchpad.net/gocheck"
1554+ "testing"
1555 )
1556
1557+func Test(t *testing.T) {
1558+ TestingT(t)
1559+}
1560+
1561 type S struct {
1562- HTTPSuite
1563 iam *iam.IAM
1564 }
1565
1566 var _ = Suite(&S{})
1567
1568+var testServer = testutil.NewHTTPServer()
1569+
1570 func (s *S) SetUpSuite(c *C) {
1571- s.HTTPSuite.SetUpSuite(c)
1572+ testServer.Start()
1573 auth := aws.Auth{"abc", "123"}
1574 s.iam = iam.New(auth, aws.Region{IAMEndpoint: testServer.URL})
1575 }
1576
1577+func (s *S) TearDownTest(c *C) {
1578+ testServer.Flush()
1579+}
1580+
1581 func (s *S) TestCreateUser(c *C) {
1582- testServer.PrepareResponse(200, nil, CreateUserExample)
1583+ testServer.Response(200, nil, CreateUserExample)
1584 resp, err := s.iam.CreateUser("Bob", "/division_abc/subdivision_xyz/")
1585 values := testServer.WaitRequest().URL.Query()
1586 c.Assert(values.Get("Action"), Equals, "CreateUser")
1587@@ -38,7 +49,7 @@
1588 }
1589
1590 func (s *S) TestCreateUserConflict(c *C) {
1591- testServer.PrepareResponse(409, nil, DuplicateUserExample)
1592+ testServer.Response(409, nil, DuplicateUserExample)
1593 resp, err := s.iam.CreateUser("Bob", "/division_abc/subdivision_xyz/")
1594 testServer.WaitRequest()
1595 c.Assert(resp, IsNil)
1596@@ -50,7 +61,7 @@
1597 }
1598
1599 func (s *S) TestGetUser(c *C) {
1600- testServer.PrepareResponse(200, nil, GetUserExample)
1601+ testServer.Response(200, nil, GetUserExample)
1602 resp, err := s.iam.GetUser("Bob")
1603 values := testServer.WaitRequest().URL.Query()
1604 c.Assert(values.Get("Action"), Equals, "GetUser")
1605@@ -67,7 +78,7 @@
1606 }
1607
1608 func (s *S) TestDeleteUser(c *C) {
1609- testServer.PrepareResponse(200, nil, RequestIdExample)
1610+ testServer.Response(200, nil, RequestIdExample)
1611 resp, err := s.iam.DeleteUser("Bob")
1612 values := testServer.WaitRequest().URL.Query()
1613 c.Assert(values.Get("Action"), Equals, "DeleteUser")
1614@@ -77,7 +88,7 @@
1615 }
1616
1617 func (s *S) TestCreateAccessKey(c *C) {
1618- testServer.PrepareResponse(200, nil, CreateAccessKeyExample)
1619+ testServer.Response(200, nil, CreateAccessKeyExample)
1620 resp, err := s.iam.CreateAccessKey("Bob")
1621 values := testServer.WaitRequest().URL.Query()
1622 c.Assert(values.Get("Action"), Equals, "CreateAccessKey")
1623
1624=== modified file 'iam/iami_test.go'
1625--- iam/iami_test.go 2012-10-10 20:21:55 +0000
1626+++ iam/iami_test.go 2013-01-31 17:09:20 +0000
1627@@ -1,14 +1,12 @@
1628 package iam_test
1629
1630 import (
1631- "flag"
1632 "launchpad.net/goamz/aws"
1633 "launchpad.net/goamz/iam"
1634+ "launchpad.net/goamz/testutil"
1635 . "launchpad.net/gocheck"
1636 )
1637
1638-var amazon = flag.Bool("amazon", false, "Enable tests against amazon server")
1639-
1640 // AmazonServer represents an Amazon AWS server.
1641 type AmazonServer struct {
1642 auth aws.Auth
1643@@ -31,7 +29,7 @@
1644 }
1645
1646 func (s *AmazonClientSuite) SetUpSuite(c *C) {
1647- if !*amazon {
1648+ if !testutil.Amazon {
1649 c.Skip("AmazonClientSuite tests not enabled")
1650 }
1651 s.srv.SetUp(c)
1652
1653=== removed file 'iam/suite_test.go'
1654--- iam/suite_test.go 2012-10-05 22:45:47 +0000
1655+++ iam/suite_test.go 1970-01-01 00:00:00 +0000
1656@@ -1,128 +0,0 @@
1657-package iam_test
1658-
1659-import (
1660- "bytes"
1661- "fmt"
1662- "io/ioutil"
1663- . "launchpad.net/gocheck"
1664- "net/http"
1665- "net/url"
1666- "os"
1667- "testing"
1668- "time"
1669-)
1670-
1671-func Test(t *testing.T) {
1672- TestingT(t)
1673-}
1674-
1675-type HTTPSuite struct{}
1676-
1677-var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
1678-
1679-func (s *HTTPSuite) SetUpSuite(c *C) {
1680- testServer.Start()
1681-}
1682-
1683-func (s *HTTPSuite) TearDownTest(c *C) {
1684- testServer.FlushRequests()
1685-}
1686-
1687-type TestHTTPServer struct {
1688- URL string
1689- Timeout time.Duration
1690- started bool
1691- body chan []byte
1692- request chan *http.Request
1693- response chan *testResponse
1694- pending chan bool
1695-}
1696-
1697-type testResponse struct {
1698- Status int
1699- Headers map[string]string
1700- Body string
1701-}
1702-
1703-func NewTestHTTPServer(url string, timeout time.Duration) *TestHTTPServer {
1704- return &TestHTTPServer{URL: url, Timeout: timeout}
1705-}
1706-
1707-func (s *TestHTTPServer) Start() {
1708- if s.started {
1709- return
1710- }
1711- s.started = true
1712-
1713- s.body = make(chan []byte, 64)
1714- s.request = make(chan *http.Request, 64)
1715- s.response = make(chan *testResponse, 64)
1716- s.pending = make(chan bool, 64)
1717-
1718- url, _ := url.Parse(s.URL)
1719- go http.ListenAndServe(url.Host, s)
1720-
1721- s.PrepareResponse(202, nil, "Nothing.")
1722- for {
1723- // Wait for it to be up.
1724- resp, err := http.Get(s.URL)
1725- if err == nil && resp.StatusCode == 202 {
1726- break
1727- }
1728- fmt.Fprintf(os.Stderr, "\nWaiting for fake server to be up... ")
1729- time.Sleep(1e8)
1730- }
1731- fmt.Fprintf(os.Stderr, "done\n\n")
1732- s.WaitRequest() // Consume dummy request.
1733-}
1734-
1735-// FlushRequests discards requests which were not yet consumed by WaitRequest.
1736-func (s *TestHTTPServer) FlushRequests() {
1737- for {
1738- select {
1739- case <-s.request:
1740- default:
1741- return
1742- }
1743- }
1744-}
1745-
1746-func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
1747- b, _ := ioutil.ReadAll(req.Body)
1748- s.body <- b
1749- s.request <- req
1750- var resp *testResponse
1751- select {
1752- case resp = <-s.response:
1753- case <-time.After(s.Timeout):
1754- fmt.Fprintf(os.Stderr, "ERROR: Timeout waiting for test to provide response\n")
1755- resp = &testResponse{500, nil, ""}
1756- }
1757- if resp.Headers != nil {
1758- h := w.Header()
1759- for k, v := range resp.Headers {
1760- h.Set(k, v)
1761- }
1762- }
1763- if resp.Status != 0 {
1764- w.WriteHeader(resp.Status)
1765- }
1766- w.Write([]byte(resp.Body))
1767-}
1768-
1769-func (s *TestHTTPServer) WaitRequest() *http.Request {
1770- select {
1771- case req := <-s.request:
1772- body := <-s.body
1773- req.Body = ioutil.NopCloser(bytes.NewReader(body))
1774- req.ParseForm()
1775- return req
1776- case <-time.After(s.Timeout):
1777- panic("Timeout waiting for goamz request")
1778- }
1779- panic("unreached")
1780-}
1781-
1782-func (s *TestHTTPServer) PrepareResponse(status int, headers map[string]string, body string) {
1783- s.response <- &testResponse{status, headers, body}
1784-}
1785
1786=== modified file 's3/s3.go'
1787--- s3/s3.go 2012-12-10 05:30:05 +0000
1788+++ s3/s3.go 2013-01-31 17:09:20 +0000
1789@@ -67,7 +67,7 @@
1790 // locationConstraint returns an io.Reader specifying a LocationConstraint if
1791 // required for the region.
1792 //
1793-// See http://goo.gl/bh9Kq for more details.
1794+// See http://goo.gl/bh9Kq for details.
1795 func (s3 *S3) locationConstraint() io.Reader {
1796 constraint := ""
1797 if s3.Region.S3LocationConstraint {
1798@@ -89,7 +89,7 @@
1799
1800 // PutBucket creates a new bucket.
1801 //
1802-// See http://goo.gl/ndjnR for more details.
1803+// See http://goo.gl/ndjnR for details.
1804 func (b *Bucket) PutBucket(perm ACL) error {
1805 headers := map[string][]string{
1806 "x-amz-acl": {string(perm)},
1807@@ -107,7 +107,7 @@
1808 // DelBucket removes an existing S3 bucket. All objects in the bucket must
1809 // be removed before the bucket itself can be removed.
1810 //
1811-// See http://goo.gl/GoBrY for more details.
1812+// See http://goo.gl/GoBrY for details.
1813 func (b *Bucket) DelBucket() error {
1814 req := &request{
1815 method: "DELETE",
1816@@ -117,9 +117,14 @@
1817 return b.S3.query(req, nil)
1818 }
1819
1820+func hasCode(err error, code string) bool {
1821+ s3err, ok := err.(*Error)
1822+ return ok && s3err.Code == code
1823+}
1824+
1825 // Get retrieves an object from an S3 bucket.
1826 //
1827-// See http://goo.gl/isCO7 for more details.
1828+// See http://goo.gl/isCO7 for details.
1829 func (b *Bucket) Get(path string) (data []byte, err error) {
1830 body, err := b.GetReader(path)
1831 if err != nil {
1832@@ -151,7 +156,7 @@
1833
1834 // Put inserts an object into the S3 bucket.
1835 //
1836-// See http://goo.gl/FEBPD for more details.
1837+// See http://goo.gl/FEBPD for details.
1838 func (b *Bucket) Put(path string, data []byte, contType string, perm ACL) error {
1839 body := bytes.NewBuffer(data)
1840 return b.PutReader(path, body, int64(len(data)), contType, perm)
1841@@ -177,7 +182,7 @@
1842
1843 // Del removes an object from the S3 bucket.
1844 //
1845-// See http://goo.gl/APeTt for more details.
1846+// See http://goo.gl/APeTt for details.
1847 func (b *Bucket) Del(path string) error {
1848 req := &request{
1849 method: "DELETE",
1850@@ -215,15 +220,15 @@
1851 Owner Owner
1852 }
1853
1854-// List returns a information about objects in an S3 bucket.
1855+// List returns information about objects in an S3 bucket.
1856 //
1857 // The prefix parameter limits the response to keys that begin with the
1858-// specified prefix. You can use prefixes to separate a bucket into different
1859-// groupings of keys (e.g. to get a feeling of folders).
1860+// specified prefix.
1861 //
1862-// The delimited parameter causes the response to group all of the keys that
1863-// share a common prefix up to the next delimiter to be grouped in a single
1864-// entry within the CommonPrefixes field.
1865+// The delim parameter causes the response to group all of the keys that
1866+// share a common prefix up to the next delimiter in a single entry within
1867+// the CommonPrefixes field. You can use delimiters to separate a bucket
1868+// into different groupings of keys, similar to how folders would work.
1869 //
1870 // The marker parameter specifies the key to start with when listing objects
1871 // in a bucket. Amazon S3 lists objects in alphabetical order and
1872@@ -270,7 +275,7 @@
1873 // },
1874 // }
1875 //
1876-// See http://goo.gl/YjQTc for more details.
1877+// See http://goo.gl/YjQTc for details.
1878 func (b *Bucket) List(prefix, delim, marker string, max int) (result *ListResp, err error) {
1879 params := map[string][]string{
1880 "prefix": {prefix},
1881
1882=== modified file 's3/s3_test.go'
1883--- s3/s3_test.go 2012-07-05 05:47:52 +0000
1884+++ s3/s3_test.go 2013-01-31 17:09:20 +0000
1885@@ -4,29 +4,40 @@
1886 "bytes"
1887 "io/ioutil"
1888 "net/http"
1889+ "testing"
1890
1891 "launchpad.net/goamz/aws"
1892 "launchpad.net/goamz/s3"
1893+ "launchpad.net/goamz/testutil"
1894 . "launchpad.net/gocheck"
1895 )
1896
1897-var _ = Suite(&S{})
1898+func Test(t *testing.T) {
1899+ TestingT(t)
1900+}
1901
1902 type S struct {
1903- HTTPSuite
1904 s3 *s3.S3
1905 }
1906
1907+var _ = Suite(&S{})
1908+
1909+var testServer = testutil.NewHTTPServer()
1910+
1911 func (s *S) SetUpSuite(c *C) {
1912- s.HTTPSuite.SetUpSuite(c)
1913+ testServer.Start()
1914 auth := aws.Auth{"abc", "123"}
1915 s.s3 = s3.New(auth, aws.Region{Name: "faux-region-1", S3Endpoint: testServer.URL})
1916 }
1917
1918+func (s *S) TearDownTest(c *C) {
1919+ testServer.Flush()
1920+}
1921+
1922 // PutBucket docs: http://goo.gl/kBTCu
1923
1924 func (s *S) TestPutBucket(c *C) {
1925- testServer.PrepareResponse(200, nil, "")
1926+ testServer.Response(200, nil, "")
1927
1928 b := s.s3.Bucket("bucket")
1929 err := b.PutBucket(s3.Private)
1930@@ -41,7 +52,7 @@
1931 // DeleteBucket docs: http://goo.gl/GoBrY
1932
1933 func (s *S) TestDelBucket(c *C) {
1934- testServer.PrepareResponse(204, nil, "")
1935+ testServer.Response(204, nil, "")
1936
1937 b := s.s3.Bucket("bucket")
1938 err := b.DelBucket()
1939@@ -56,7 +67,7 @@
1940 // GetObject docs: http://goo.gl/isCO7
1941
1942 func (s *S) TestGet(c *C) {
1943- testServer.PrepareResponse(200, nil, "content")
1944+ testServer.Response(200, nil, "content")
1945
1946 b := s.s3.Bucket("bucket")
1947 data, err := b.Get("name")
1948@@ -71,7 +82,7 @@
1949 }
1950
1951 func (s *S) TestURL(c *C) {
1952- testServer.PrepareResponse(200, nil, "content")
1953+ testServer.Response(200, nil, "content")
1954
1955 b := s.s3.Bucket("bucket")
1956 url := b.URL("name")
1957@@ -88,7 +99,7 @@
1958 }
1959
1960 func (s *S) TestGetReader(c *C) {
1961- testServer.PrepareResponse(200, nil, "content")
1962+ testServer.Response(200, nil, "content")
1963
1964 b := s.s3.Bucket("bucket")
1965 rc, err := b.GetReader("name")
1966@@ -105,7 +116,7 @@
1967 }
1968
1969 func (s *S) TestGetNotFound(c *C) {
1970- testServer.PrepareResponse(404, nil, GetObjectErrorDump)
1971+ testServer.Response(404, nil, GetObjectErrorDump)
1972
1973 b := s.s3.Bucket("non-existent-bucket")
1974 data, err := b.Get("non-existent")
1975@@ -130,7 +141,7 @@
1976 // PutObject docs: http://goo.gl/FEBPD
1977
1978 func (s *S) TestPutObject(c *C) {
1979- testServer.PrepareResponse(200, nil, "")
1980+ testServer.Response(200, nil, "")
1981
1982 b := s.s3.Bucket("bucket")
1983 err := b.Put("name", []byte("content"), "content-type", s3.Private)
1984@@ -147,7 +158,7 @@
1985 }
1986
1987 func (s *S) TestPutReader(c *C) {
1988- testServer.PrepareResponse(200, nil, "")
1989+ testServer.Response(200, nil, "")
1990
1991 b := s.s3.Bucket("bucket")
1992 buf := bytes.NewBufferString("content")
1993@@ -167,7 +178,7 @@
1994 // DelObject docs: http://goo.gl/APeTt
1995
1996 func (s *S) TestDelObject(c *C) {
1997- testServer.PrepareResponse(200, nil, "")
1998+ testServer.Response(200, nil, "")
1999
2000 b := s.s3.Bucket("bucket")
2001 err := b.Del("name")
2002@@ -182,7 +193,7 @@
2003 // Bucket List Objects docs: http://goo.gl/YjQTc
2004
2005 func (s *S) TestList(c *C) {
2006- testServer.PrepareResponse(200, nil, GetListResultDump1)
2007+ testServer.Response(200, nil, GetListResultDump1)
2008
2009 b := s.s3.Bucket("quotes")
2010
2011@@ -221,7 +232,7 @@
2012 }
2013
2014 func (s *S) TestListWithDelimiter(c *C) {
2015- testServer.PrepareResponse(200, nil, GetListResultDump2)
2016+ testServer.Response(200, nil, GetListResultDump2)
2017
2018 b := s.s3.Bucket("quotes")
2019
2020
2021=== modified file 's3/s3i_test.go'
2022--- s3/s3i_test.go 2013-01-28 13:30:10 +0000
2023+++ s3/s3i_test.go 2013-01-31 17:09:20 +0000
2024@@ -10,6 +10,7 @@
2025
2026 "launchpad.net/goamz/aws"
2027 "launchpad.net/goamz/s3"
2028+ "launchpad.net/goamz/testutil"
2029 . "launchpad.net/gocheck"
2030 "time"
2031 )
2032@@ -45,7 +46,7 @@
2033 }
2034
2035 func (s *AmazonClientSuite) SetUpSuite(c *C) {
2036- if !*amazon {
2037+ if !testutil.Amazon {
2038 c.Skip("live tests against AWS disabled (no -amazon)")
2039 }
2040 s.srv.SetUp(c)
2041@@ -62,7 +63,7 @@
2042 }
2043
2044 func (s *AmazonDomainClientSuite) SetUpSuite(c *C) {
2045- if !*amazon {
2046+ if !testutil.Amazon {
2047 c.Skip("live tests against AWS disabled (no -amazon)")
2048 }
2049 s.srv.SetUp(c)
2050@@ -102,12 +103,15 @@
2051
2052 func (s *ClientTests) TestBasicFunctionality(c *C) {
2053 b := s.Bucket(testBucket)
2054+ b.DelBucket()
2055+
2056 err := b.PutBucket(s3.PublicRead)
2057 c.Assert(err, IsNil)
2058 defer b.DelBucket()
2059
2060 err = b.Put("name", []byte("yo!"), "text/plain", s3.PublicRead)
2061 c.Assert(err, IsNil)
2062+ defer b.Del("name")
2063
2064 data, err := b.Get("name")
2065 c.Assert(err, IsNil)
2066@@ -120,6 +124,7 @@
2067 buf := bytes.NewBufferString("hey!")
2068 err = b.PutReader("name2", buf, int64(buf.Len()), "text/plain", s3.Private)
2069 c.Assert(err, IsNil)
2070+ defer b.Del("name2")
2071
2072 rc, err := b.GetReader("name2")
2073 c.Assert(err, IsNil)
2074@@ -225,16 +230,13 @@
2075 // normal list.
2076 {
2077 Contents: keys(objectNames...),
2078- },
2079- {
2080+ }, {
2081 Marker: objectNames[0],
2082 Contents: keys(objectNames[1:]...),
2083- },
2084- {
2085+ }, {
2086 Marker: objectNames[0] + "a",
2087 Contents: keys(objectNames[1:]...),
2088- },
2089- {
2090+ }, {
2091 Marker: "z",
2092 },
2093
2094@@ -243,14 +245,12 @@
2095 MaxKeys: 2,
2096 Contents: keys(objectNames[0:2]...),
2097 IsTruncated: true,
2098- },
2099- {
2100+ }, {
2101 MaxKeys: 2,
2102 Marker: objectNames[0],
2103 Contents: keys(objectNames[1:3]...),
2104 IsTruncated: true,
2105- },
2106- {
2107+ }, {
2108 MaxKeys: 2,
2109 Marker: objectNames[len(objectNames)-2],
2110 Contents: keys(objectNames[len(objectNames)-1:]...),
2111@@ -261,38 +261,32 @@
2112 Delimiter: "/",
2113 CommonPrefixes: []string{"photos/", "test/"},
2114 Contents: keys("index.html", "index2.html"),
2115- },
2116- {
2117+ }, {
2118 Delimiter: "/",
2119 Prefix: "photos/2006/",
2120 CommonPrefixes: []string{"photos/2006/February/", "photos/2006/January/"},
2121- },
2122- {
2123+ }, {
2124 Delimiter: "/",
2125 Prefix: "t",
2126 CommonPrefixes: []string{"test/"},
2127- },
2128- {
2129+ }, {
2130 Delimiter: "/",
2131 MaxKeys: 1,
2132 Contents: keys("index.html"),
2133 IsTruncated: true,
2134- },
2135- {
2136+ }, {
2137 Delimiter: "/",
2138 MaxKeys: 1,
2139 Marker: "index2.html",
2140 CommonPrefixes: []string{"photos/"},
2141 IsTruncated: true,
2142- },
2143- {
2144+ }, {
2145 Delimiter: "/",
2146 MaxKeys: 1,
2147 Marker: "photos/",
2148 CommonPrefixes: []string{"test/"},
2149 IsTruncated: false,
2150- },
2151- {
2152+ }, {
2153 Delimiter: "Feb",
2154 CommonPrefixes: []string{"photos/2006/Feb"},
2155 Contents: keys("index.html", "index2.html", "photos/2006/January/sample.jpg", "test/bar", "test/foo"),
2156
2157=== removed file 's3/suite_test.go'
2158--- s3/suite_test.go 2012-05-02 15:22:53 +0000
2159+++ s3/suite_test.go 1970-01-01 00:00:00 +0000
2160@@ -1,139 +0,0 @@
2161-package s3_test
2162-
2163-import (
2164- "flag"
2165- "fmt"
2166- "launchpad.net/goamz/aws"
2167- . "launchpad.net/gocheck"
2168- "net/http"
2169- "net/url"
2170- "os"
2171- "testing"
2172- "time"
2173-)
2174-
2175-func Test(t *testing.T) {
2176- TestingT(t)
2177-}
2178-
2179-var amazon = flag.Bool("amazon", false, "Enable tests against amazon server")
2180-
2181-type SuiteI struct {
2182- auth aws.Auth
2183-}
2184-
2185-func (s *SuiteI) SetUpSuite(c *C) {
2186- if !*amazon {
2187- c.Skip("amazon tests not enabled (-amazon flag)")
2188- }
2189- auth, err := aws.EnvAuth()
2190- if err != nil {
2191- c.Fatal(err.Error())
2192- }
2193- s.auth = auth
2194-}
2195-
2196-type HTTPSuite struct{}
2197-
2198-var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
2199-
2200-func (s *HTTPSuite) SetUpSuite(c *C) {
2201- testServer.Start()
2202-}
2203-
2204-func (s *HTTPSuite) TearDownTest(c *C) {
2205- testServer.FlushRequests()
2206-}
2207-
2208-type TestHTTPServer struct {
2209- URL string
2210- Timeout time.Duration
2211- started bool
2212- request chan *http.Request
2213- response chan *testResponse
2214- pending chan bool
2215-}
2216-
2217-type testResponse struct {
2218- Status int
2219- Headers map[string]string
2220- Body string
2221-}
2222-
2223-func NewTestHTTPServer(url string, timeout time.Duration) *TestHTTPServer {
2224- return &TestHTTPServer{URL: url, Timeout: timeout}
2225-}
2226-
2227-func (s *TestHTTPServer) Start() {
2228- if s.started {
2229- return
2230- }
2231- s.started = true
2232-
2233- s.request = make(chan *http.Request, 64)
2234- s.response = make(chan *testResponse, 64)
2235- s.pending = make(chan bool, 64)
2236-
2237- url, _ := url.Parse(s.URL)
2238- go http.ListenAndServe(url.Host, s)
2239-
2240- s.PrepareResponse(202, nil, "Nothing.")
2241- for {
2242- // Wait for it to be up.
2243- resp, err := http.Get(s.URL)
2244- if err == nil && resp.StatusCode == 202 {
2245- break
2246- }
2247- fmt.Fprintf(os.Stderr, "\nWaiting for fake server to be up... ")
2248- time.Sleep(1e8)
2249- }
2250- fmt.Fprintf(os.Stderr, "done\n\n")
2251- s.WaitRequest() // Consume dummy request.
2252-}
2253-
2254-// FlushRequests discards requests which were not yet consumed by WaitRequest.
2255-func (s *TestHTTPServer) FlushRequests() {
2256- for {
2257- select {
2258- case <-s.request:
2259- default:
2260- return
2261- }
2262- }
2263-}
2264-
2265-func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
2266- s.request <- req
2267- var resp *testResponse
2268- select {
2269- case resp = <-s.response:
2270- case <-time.After(s.Timeout):
2271- fmt.Fprintf(os.Stderr, "ERROR: Timeout waiting for test to provide response\n")
2272- resp = &testResponse{500, nil, ""}
2273- }
2274- if resp.Headers != nil {
2275- h := w.Header()
2276- for k, v := range resp.Headers {
2277- h.Set(k, v)
2278- }
2279- }
2280- if resp.Status != 0 {
2281- w.WriteHeader(resp.Status)
2282- }
2283- w.Write([]byte(resp.Body))
2284-}
2285-
2286-func (s *TestHTTPServer) WaitRequest() *http.Request {
2287- select {
2288- case req := <-s.request:
2289- req.ParseForm()
2290- return req
2291- case <-time.After(s.Timeout):
2292- panic("Timeout waiting for goamz request")
2293- }
2294- panic("unreached")
2295-}
2296-
2297-func (s *TestHTTPServer) PrepareResponse(status int, headers map[string]string, body string) {
2298- s.response <- &testResponse{status, headers, body}
2299-}
2300
2301=== added directory 'testutil'
2302=== added file 'testutil/http.go'
2303--- testutil/http.go 1970-01-01 00:00:00 +0000
2304+++ testutil/http.go 2013-01-31 17:09:20 +0000
2305@@ -0,0 +1,174 @@
2306+package testutil
2307+
2308+import (
2309+ "bytes"
2310+ "fmt"
2311+ "io/ioutil"
2312+ "net"
2313+ "net/http"
2314+ "net/url"
2315+ "os"
2316+ "time"
2317+)
2318+
2319+type HTTPServer struct {
2320+ URL string
2321+ Timeout time.Duration
2322+ started bool
2323+ request chan *http.Request
2324+ response chan ResponseFunc
2325+}
2326+
2327+type Response struct {
2328+ Status int
2329+ Headers map[string]string
2330+ Body string
2331+}
2332+
2333+func NewHTTPServer() *HTTPServer {
2334+ return &HTTPServer{URL: "http://localhost:4444", Timeout: 5 * time.Second}
2335+}
2336+
2337+type ResponseFunc func(path string) Response
2338+
2339+func (s *HTTPServer) Start() {
2340+ if s.started {
2341+ return
2342+ }
2343+ s.started = true
2344+ s.request = make(chan *http.Request, 64)
2345+ s.response = make(chan ResponseFunc, 64)
2346+ u, err := url.Parse(s.URL)
2347+ if err != nil {
2348+ panic(err)
2349+ }
2350+ l, err := net.Listen("tcp", u.Host)
2351+ if err != nil {
2352+ panic(err)
2353+ }
2354+ go http.Serve(l, s)
2355+
2356+ s.Response(203, nil, "")
2357+ for {
2358+ // Wait for it to be up.
2359+ resp, err := http.Get(s.URL)
2360+ if err == nil && resp.StatusCode == 203 {
2361+ break
2362+ }
2363+ time.Sleep(1e8)
2364+ }
2365+ s.WaitRequest() // Consume dummy request.
2366+}
2367+
2368+// Flush discards all pending requests and responses.
2369+func (s *HTTPServer) Flush() {
2370+ for {
2371+ select {
2372+ case <-s.request:
2373+ case <-s.response:
2374+ default:
2375+ return
2376+ }
2377+ }
2378+}
2379+
2380+func body(req *http.Request) string {
2381+ data, err := ioutil.ReadAll(req.Body)
2382+ if err != nil {
2383+ panic(err)
2384+ }
2385+ return string(data)
2386+}
2387+
2388+func (s *HTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
2389+ req.ParseMultipartForm(1e6)
2390+ data, err := ioutil.ReadAll(req.Body)
2391+ if err != nil {
2392+ panic(err)
2393+ }
2394+ req.Body = ioutil.NopCloser(bytes.NewBuffer(data))
2395+ s.request <- req
2396+ var resp Response
2397+ select {
2398+ case respFunc := <-s.response:
2399+ resp = respFunc(req.URL.Path)
2400+ case <-time.After(s.Timeout):
2401+ const msg = "ERROR: Timeout waiting for test to prepare a response\n"
2402+ fmt.Fprintf(os.Stderr, msg)
2403+ resp = Response{500, nil, msg}
2404+ }
2405+ if resp.Headers != nil {
2406+ h := w.Header()
2407+ for k, v := range resp.Headers {
2408+ h.Set(k, v)
2409+ }
2410+ }
2411+ if resp.Status != 0 {
2412+ w.WriteHeader(resp.Status)
2413+ }
2414+ w.Write([]byte(resp.Body))
2415+}
2416+
2417+// WaitRequests returns the next n requests made to the http server from
2418+// the queue. If not enough requests were previously made, it waits until
2419+// the timeout value for them to be made.
2420+func (s *HTTPServer) WaitRequests(n int) []*http.Request {
2421+ reqs := make([]*http.Request, 0, n)
2422+ for i := 0; i < n; i++ {
2423+ select {
2424+ case req := <-s.request:
2425+ reqs = append(reqs, req)
2426+ case <-time.After(s.Timeout):
2427+ panic("Timeout waiting for request")
2428+ }
2429+ }
2430+ return reqs
2431+}
2432+
2433+// WaitRequest returns the next request made to the http server from
2434+// the queue. If no requests were previously made, it waits until the
2435+// timeout value for one to be made.
2436+func (s *HTTPServer) WaitRequest() *http.Request {
2437+ return s.WaitRequests(1)[0]
2438+}
2439+
2440+// ResponseFunc prepares the test server to respond the following n
2441+// requests using f to build each response.
2442+func (s *HTTPServer) ResponseFunc(n int, f ResponseFunc) {
2443+ for i := 0; i < n; i++ {
2444+ s.response <- f
2445+ }
2446+}
2447+
2448+// ResponseMap maps request paths to responses.
2449+type ResponseMap map[string]Response
2450+
2451+// ResponseMap prepares the test server to respond the following n
2452+// requests using the m to obtain the responses.
2453+func (s *HTTPServer) ResponseMap(n int, m ResponseMap) {
2454+ f := func(path string) Response {
2455+ for rpath, resp := range m {
2456+ if rpath == path {
2457+ return resp
2458+ }
2459+ }
2460+ body := "Path not found in response map: " + path
2461+ return Response{Status: 500, Body: body}
2462+ }
2463+ s.ResponseFunc(n, f)
2464+}
2465+
2466+// Responses prepares the test server to respond the following n requests
2467+// using the provided response parameters.
2468+func (s *HTTPServer) Responses(n int, status int, headers map[string]string, body string) {
2469+ f := func(path string) Response {
2470+ return Response{status, headers, body}
2471+ }
2472+ s.ResponseFunc(n, f)
2473+}
2474+
2475+// Response prepares the test server to respond the following request
2476+// using the provided response parameters.
2477+func (s *HTTPServer) Response(status int, headers map[string]string, body string) {
2478+ s.Responses(1, status, headers, body)
2479+}
2480
2481=== added file 'testutil/suite.go'
2482--- testutil/suite.go 1970-01-01 00:00:00 +0000
2483+++ testutil/suite.go 2013-01-31 17:09:20 +0000
2484@@ -0,0 +1,30 @@
2485+package testutil
2486+
2487+import (
2488+ "flag"
2489+ "launchpad.net/goamz/aws"
2490+ . "launchpad.net/gocheck"
2491+)
2492+
2493+// Amazon must be used by all tested packages to determine whether to
2494+// run functional tests against the real AWS servers.
2495+var Amazon bool
2496+
2497+func init() {
2498+ flag.BoolVar(&Amazon, "amazon", false, "Enable tests against amazon server")
2499+}
2500+
2501+type LiveSuite struct {
2502+ auth aws.Auth
2503+}
2504+
2505+func (s *LiveSuite) SetUpSuite(c *C) {
2506+ if !Amazon {
2507+ c.Skip("amazon tests not enabled (-amazon flag)")
2508+ }
2509+ auth, err := aws.EnvAuth()
2510+ if err != nil {
2511+ c.Fatal(err.Error())
2512+ }
2513+ s.auth = auth
2514+}

Subscribers

People subscribed via source and target branches