diff options
Diffstat (limited to 'vendor/github.com/goamz/goamz/exp/sdb')
-rw-r--r-- | vendor/github.com/goamz/goamz/exp/sdb/export_test.go | 9 | ||||
-rw-r--r-- | vendor/github.com/goamz/goamz/exp/sdb/responses_test.go | 120 | ||||
-rw-r--r-- | vendor/github.com/goamz/goamz/exp/sdb/sdb.go | 413 | ||||
-rw-r--r-- | vendor/github.com/goamz/goamz/exp/sdb/sdb_test.go | 219 | ||||
-rw-r--r-- | vendor/github.com/goamz/goamz/exp/sdb/sign.go | 54 | ||||
-rw-r--r-- | vendor/github.com/goamz/goamz/exp/sdb/sign_test.go | 29 |
6 files changed, 844 insertions, 0 deletions
diff --git a/vendor/github.com/goamz/goamz/exp/sdb/export_test.go b/vendor/github.com/goamz/goamz/exp/sdb/export_test.go new file mode 100644 index 000000000..7807a914a --- /dev/null +++ b/vendor/github.com/goamz/goamz/exp/sdb/export_test.go @@ -0,0 +1,9 @@ +package sdb + +import ( + "github.com/goamz/goamz/aws" +) + +func Sign(auth aws.Auth, method, path string, params map[string][]string, headers map[string][]string) { + sign(auth, method, path, params, headers) +} diff --git a/vendor/github.com/goamz/goamz/exp/sdb/responses_test.go b/vendor/github.com/goamz/goamz/exp/sdb/responses_test.go new file mode 100644 index 000000000..034c2b31c --- /dev/null +++ b/vendor/github.com/goamz/goamz/exp/sdb/responses_test.go @@ -0,0 +1,120 @@ +package sdb_test + +var TestCreateDomainXmlOK = ` +<?xml version="1.0"?> +<CreateDomainResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/"> + <ResponseMetadata> + <RequestId>63264005-7a5f-e01a-a224-395c63b89f6d</RequestId> + <BoxUsage>0.0055590279</BoxUsage> + </ResponseMetadata> +</CreateDomainResponse> +` + +var TestListDomainsXmlOK = ` +<?xml version="1.0"?> +<ListDomainsResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/"> + <ListDomainsResult> + <DomainName>Account</DomainName> + <DomainName>Domain</DomainName> + <DomainName>Record</DomainName> + </ListDomainsResult> + <ResponseMetadata> + <RequestId>15fcaf55-9914-63c2-21f3-951e31193790</RequestId> + <BoxUsage>0.0000071759</BoxUsage> + </ResponseMetadata> +</ListDomainsResponse> +` + +var TestListDomainsWithNextTokenXmlOK = ` +<?xml version="1.0"?> +<ListDomainsResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/"> + <ListDomainsResult> + <DomainName>Domain1-200706011651</DomainName> + <DomainName>Domain2-200706011652</DomainName> + <NextToken>TWV0ZXJpbmdUZXN0RG9tYWluMS0yMDA3MDYwMTE2NTY=</NextToken> + </ListDomainsResult> + <ResponseMetadata> + <RequestId>eb13162f-1b95-4511-8b12-489b86acfd28</RequestId> + <BoxUsage>0.0000219907</BoxUsage> + </ResponseMetadata> +</ListDomainsResponse> +` + +var TestDeleteDomainXmlOK = ` +<?xml version="1.0"?> +<DeleteDomainResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/"> + <ResponseMetadata> + <RequestId>039e1e25-9a64-2a74-93da-2fda36122a97</RequestId> + <BoxUsage>0.0055590278</BoxUsage> + </ResponseMetadata> +</DeleteDomainResponse> +` + +var TestDomainMetadataXmlNoSuchDomain = ` +<?xml version="1.0"?> +<Response xmlns="http://sdb.amazonaws.com/doc/2009-04-15/"> + <Errors> + <Error> + <Code>NoSuchDomain</Code> + <Message>The specified domain does not exist.</Message> + <BoxUsage>0.0000071759</BoxUsage> + </Error> + </Errors> + <RequestID>e050cea2-a772-f90e-2cb0-98ebd42c2898</RequestID> +</Response> +` + +var TestPutAttrsXmlOK = ` +<?xml version="1.0"?> +<PutAttributesResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/"> + <ResponseMetadata> + <RequestId>490206ce-8292-456c-a00f-61b335eb202b</RequestId> + <BoxUsage>0.0000219907</BoxUsage> + </ResponseMetadata> +</PutAttributesResponse> +` + +var TestAttrsXmlOK = ` +<?xml version="1.0"?> +<GetAttributesResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/"> + <GetAttributesResult> + <Attribute><Name>Color</Name><Value>Blue</Value></Attribute> + <Attribute><Name>Size</Name><Value>Med</Value></Attribute> + </GetAttributesResult> + <ResponseMetadata> + <RequestId>b1e8f1f7-42e9-494c-ad09-2674e557526d</RequestId> + <BoxUsage>0.0000219942</BoxUsage> + </ResponseMetadata> +</GetAttributesResponse> +` + +var TestSelectXmlOK = ` +<?xml version="1.0"?> +<SelectResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/"> + <SelectResult> + <Item> + <Name>Item_03</Name> + <Attribute><Name>Category</Name><Value>Clothes</Value></Attribute> + <Attribute><Name>Subcategory</Name><Value>Pants</Value></Attribute> + <Attribute><Name>Name</Name><Value>Sweatpants</Value></Attribute> + <Attribute><Name>Color</Name><Value>Blue</Value></Attribute> + <Attribute><Name>Color</Name><Value>Yellow</Value></Attribute> + <Attribute><Name>Color</Name><Value>Pink</Value></Attribute> + <Attribute><Name>Size</Name><Value>Large</Value></Attribute> + </Item> + <Item> + <Name>Item_06</Name> + <Attribute><Name>Category</Name><Value>Motorcycle Parts</Value></Attribute> + <Attribute><Name>Subcategory</Name><Value>Bodywork</Value></Attribute> + <Attribute><Name>Name</Name><Value>Fender Eliminator</Value></Attribute> + <Attribute><Name>Color</Name><Value>Blue</Value></Attribute> + <Attribute><Name>Make</Name><Value>Yamaha</Value></Attribute> + <Attribute><Name>Model</Name><Value>R1</Value></Attribute> + </Item> + </SelectResult> + <ResponseMetadata> + <RequestId>b1e8f1f7-42e9-494c-ad09-2674e557526d</RequestId> + <BoxUsage>0.0000219907</BoxUsage> + </ResponseMetadata> +</SelectResponse> +` diff --git a/vendor/github.com/goamz/goamz/exp/sdb/sdb.go b/vendor/github.com/goamz/goamz/exp/sdb/sdb.go new file mode 100644 index 000000000..0d13f4a9e --- /dev/null +++ b/vendor/github.com/goamz/goamz/exp/sdb/sdb.go @@ -0,0 +1,413 @@ +// +// goamz - Go packages to interact with the Amazon Web Services. +// +// https://wiki.ubuntu.com/goamz +// +// Copyright (c) 2011 AppsAttic Ltd. +// +// sdb package written by: +// +// Andrew Chilton <chilts@appsattic.com> +// Brad Rydzewski <brad.rydzewski@gmail.com> + +// This package is in an experimental state, and does not currently +// follow conventions and style of the rest of goamz or common +// Go conventions. It must be polished before it's considered a +// first-class package in goamz. +package sdb + +// BUG: SelectResp isn't properly organized. It must change. + +// + +import ( + "encoding/xml" + "github.com/goamz/goamz/aws" + "log" + "net/http" + "net/http/httputil" + "net/url" + "strconv" + "time" +) + +const debug = false + +// The SDB type encapsulates operations with a specific SimpleDB region. +type SDB struct { + aws.Auth + aws.Region + private byte // Reserve the right of using private data. +} + +// New creates a new SDB. +func New(auth aws.Auth, region aws.Region) *SDB { + return &SDB{auth, region, 0} +} + +// The Domain type represents a collection of items that are described +// by name-value attributes. +type Domain struct { + *SDB + Name string +} + +// Domain returns a Domain with the given name. +func (sdb *SDB) Domain(name string) *Domain { + return &Domain{sdb, name} +} + +// The Item type represent individual objects that contain one or more +// name-value attributes stored within a SDB Domain as rows. +type Item struct { + *SDB + *Domain + Name string +} + +// Item returns an Item with the given name. +func (domain *Domain) Item(name string) *Item { + return &Item{domain.SDB, domain, name} +} + +// The Attr type represent categories of data that can be assigned to items. +type Attr struct { + Name string + Value string +} + +// ---------------------------------------------------------------------------- +// Service-level operations. + +// --- ListDomains + +// Response to a ListDomains request. +// +// See http://goo.gl/3u0Cf for more details. +type ListDomainsResp struct { + Domains []string `xml:"ListDomainsResult>DomainName"` + NextToken string `xml:"ListDomainsResult>NextToken"` + ResponseMetadata ResponseMetadata +} + +// ListDomains lists all domains in sdb. +// +// See http://goo.gl/Dsw15 for more details. +func (sdb *SDB) ListDomains() (resp *ListDomainsResp, err error) { + return sdb.ListDomainsN(0, "") +} + +// ListDomainsN lists domains in sdb up to maxDomains. +// If nextToken is not empty, domains listed will start at the given token. +// +// See http://goo.gl/Dsw15 for more details. +func (sdb *SDB) ListDomainsN(maxDomains int, nextToken string) (resp *ListDomainsResp, err error) { + params := makeParams("ListDomains") + if maxDomains != 0 { + params["MaxNumberOfDomains"] = []string{strconv.Itoa(maxDomains)} + } + if nextToken != "" { + params["NextToken"] = []string{nextToken} + } + resp = &ListDomainsResp{} + err = sdb.query(nil, nil, params, nil, resp) + return +} + +// --- SelectExpression + +// Response to a Select request. +// +// See http://goo.gl/GTsSZ for more details. +type SelectResp struct { + Items []struct { + Name string + Attrs []Attr `xml:"Attribute"` + } `xml:"SelectResult>Item"` + ResponseMetadata ResponseMetadata +} + +// Select returns a set of items and attributes that match expr. +// Select is similar to the standard SQL SELECT statement. +// +// See http://goo.gl/GTsSZ for more details. +func (sdb *SDB) Select(expr string, consistent bool) (resp *SelectResp, err error) { + resp = &SelectResp{} + params := makeParams("Select") + params["SelectExpression"] = []string{expr} + if consistent { + params["ConsistentRead"] = []string{"true"} + } + err = sdb.query(nil, nil, params, nil, resp) + return +} + +// ---------------------------------------------------------------------------- +// Domain-level operations. + +// --- CreateDomain + +// CreateDomain creates a new domain. +// +// See http://goo.gl/jDjGH for more details. +func (domain *Domain) CreateDomain() (resp *SimpleResp, err error) { + params := makeParams("CreateDomain") + resp = &SimpleResp{} + err = domain.SDB.query(domain, nil, params, nil, resp) + return +} + +// DeleteDomain deletes an existing domain. +// +// See http://goo.gl/S0dCL for more details. +func (domain *Domain) DeleteDomain() (resp *SimpleResp, err error) { + params := makeParams("DeleteDomain") + resp = &SimpleResp{} + err = domain.SDB.query(domain, nil, params, nil, resp) + return +} + +// ---------------------------------------------------------------------------- +// Item-level operations. + +type PutAttrs struct { + attrs []Attr + expected []Attr + replace map[string]bool + missing map[string]bool +} + +func (pa *PutAttrs) Add(name, value string) { + pa.attrs = append(pa.attrs, Attr{name, value}) +} + +func (pa *PutAttrs) Replace(name, value string) { + pa.Add(name, value) + if pa.replace == nil { + pa.replace = make(map[string]bool) + } + pa.replace[name] = true +} + +// The PutAttrs request will only succeed if the existing +// item in SimpleDB contains a matching name / value pair. +func (pa *PutAttrs) IfValue(name, value string) { + pa.expected = append(pa.expected, Attr{name, value}) +} + +// Flag to test the existence of an attribute while performing +// conditional updates. X can be any positive integer or 0. +// +// This should set Expected.N.Name=name and Expected.N.Exists=false +func (pa *PutAttrs) IfMissing(name string) { + if pa.missing == nil { + pa.missing = make(map[string]bool) + } + pa.missing[name] = true +} + +// PutAttrs adds attrs to item. +// +// See http://goo.gl/yTAV4 for more details. +func (item *Item) PutAttrs(attrs *PutAttrs) (resp *SimpleResp, err error) { + params := makeParams("PutAttributes") + resp = &SimpleResp{} + + // copy these attrs over to the parameters + itemNum := 1 + for _, attr := range attrs.attrs { + itemNumStr := strconv.Itoa(itemNum) + + // do the name, value and replace + params["Attribute."+itemNumStr+".Name"] = []string{attr.Name} + params["Attribute."+itemNumStr+".Value"] = []string{attr.Value} + + if _, ok := attrs.replace[attr.Name]; ok { + params["Attribute."+itemNumStr+".Replace"] = []string{"true"} + } + + itemNum++ + } + + //append expected values to params + expectedNum := 1 + for _, attr := range attrs.expected { + expectedNumStr := strconv.Itoa(expectedNum) + params["Expected."+expectedNumStr+".Name"] = []string{attr.Name} + params["Expected."+expectedNumStr+".Value"] = []string{attr.Value} + + if attrs.missing[attr.Name] { + params["Expected."+expectedNumStr+".Exists"] = []string{"false"} + } + expectedNum++ + } + + err = item.query(params, nil, resp) + if err != nil { + return nil, err + } + return +} + +// Response to an Attrs request. +// +// See http://goo.gl/45X1M for more details. +type AttrsResp struct { + Attrs []Attr `xml:"GetAttributesResult>Attribute"` + ResponseMetadata ResponseMetadata +} + +// Attrs returns one or more of the named attributes, or +// all of item's attributes if names is nil. +// If consistent is true, previous writes will necessarily +// be observed. +// +// See http://goo.gl/45X1M for more details. +func (item *Item) Attrs(names []string, consistent bool) (resp *AttrsResp, err error) { + params := makeParams("GetAttributes") + params["ItemName"] = []string{item.Name} + if consistent { + params["ConsistentRead"] = []string{"true"} + } + + // Copy these attributes over to the parameters + for i, name := range names { + params["AttributeName."+strconv.Itoa(i+1)] = []string{name} + } + + resp = &AttrsResp{} + err = item.query(params, nil, resp) + if err != nil { + return nil, err + } + return +} + +// ---------------------------------------------------------------------------- +// Generic data structures for all requests/responses. + +// Error encapsulates an error returned by SDB. +type Error struct { + StatusCode int // HTTP status code (200, 403, ...) + StatusMsg string // HTTP status message ("Service Unavailable", "Bad Request", ...) + Code string // SimpleDB error code ("InvalidParameterValue", ...) + Message string // The human-oriented error message + RequestId string // A unique ID for this request + BoxUsage float64 // The measure of machine utilization for this request. +} + +func (err *Error) Error() string { + return err.Message +} + +// SimpleResp represents a response to an SDB request which on success +// will return no other information besides ResponseMetadata. +type SimpleResp struct { + ResponseMetadata ResponseMetadata +} + +// ResponseMetadata +type ResponseMetadata struct { + RequestId string // A unique ID for tracking the request + BoxUsage float64 // The measure of machine utilization for this request. +} + +func buildError(r *http.Response) error { + err := Error{} + err.StatusCode = r.StatusCode + err.StatusMsg = r.Status + xml.NewDecoder(r.Body).Decode(&err) + return &err +} + +// ---------------------------------------------------------------------------- +// Request dispatching logic. + +func (item *Item) query(params url.Values, headers http.Header, resp interface{}) error { + return item.Domain.SDB.query(item.Domain, item, params, headers, resp) +} + +func (domain *Domain) query(item *Item, params url.Values, headers http.Header, resp interface{}) error { + return domain.SDB.query(domain, item, params, headers, resp) +} + +func (sdb *SDB) query(domain *Domain, item *Item, params url.Values, headers http.Header, resp interface{}) error { + // all SimpleDB operations have path="/" + method := "GET" + path := "/" + + // if we have been given no headers or params, create them + if headers == nil { + headers = map[string][]string{} + } + if params == nil { + params = map[string][]string{} + } + + // setup some default parameters + params["Version"] = []string{"2009-04-15"} + params["Timestamp"] = []string{time.Now().UTC().Format(time.RFC3339)} + + // set the DomainName param (every request must have one) + if domain != nil { + params["DomainName"] = []string{domain.Name} + } + + // set the ItemName if we have one + if item != nil { + params["ItemName"] = []string{item.Name} + } + + // check the endpoint URL + u, err := url.Parse(sdb.Region.SDBEndpoint) + if err != nil { + return err + } + headers["Host"] = []string{u.Host} + sign(sdb.Auth, method, path, params, headers) + + u.Path = path + if len(params) > 0 { + u.RawQuery = params.Encode() + } + req := http.Request{ + URL: u, + Method: method, + ProtoMajor: 1, + ProtoMinor: 1, + Close: true, + Header: headers, + } + + if v, ok := headers["Content-Length"]; ok { + req.ContentLength, _ = strconv.ParseInt(v[0], 10, 64) + delete(headers, "Content-Length") + } + + r, err := http.DefaultClient.Do(&req) + if err != nil { + return err + } + defer r.Body.Close() + + if debug { + dump, _ := httputil.DumpResponse(r, true) + log.Printf("response:\n") + log.Printf("%v\n}\n", string(dump)) + } + + // status code is always 200 when successful (since we're always doing a GET) + if r.StatusCode != 200 { + return buildError(r) + } + + // everything was fine, so unmarshal the XML and return what it's err is (if any) + err = xml.NewDecoder(r.Body).Decode(resp) + return err +} + +func makeParams(action string) map[string][]string { + params := make(map[string][]string) + params["Action"] = []string{action} + return params +} diff --git a/vendor/github.com/goamz/goamz/exp/sdb/sdb_test.go b/vendor/github.com/goamz/goamz/exp/sdb/sdb_test.go new file mode 100644 index 000000000..83e7f9f86 --- /dev/null +++ b/vendor/github.com/goamz/goamz/exp/sdb/sdb_test.go @@ -0,0 +1,219 @@ +package sdb_test + +import ( + "testing" + + "github.com/goamz/goamz/aws" + "github.com/goamz/goamz/exp/sdb" + "github.com/goamz/goamz/testutil" + . "gopkg.in/check.v1" +) + +func Test(t *testing.T) { + TestingT(t) +} + +var _ = Suite(&S{}) + +type S struct { + sdb *sdb.SDB +} + +var testServer = testutil.NewHTTPServer() + +func (s *S) SetUpSuite(c *C) { + testServer.Start() + auth := aws.Auth{AccessKey: "abc", SecretKey: "123"} + s.sdb = sdb.New(auth, aws.Region{SDBEndpoint: testServer.URL}) +} + +func (s *S) TearDownTest(c *C) { + testServer.Flush() +} + +func (s *S) TestCreateDomainOK(c *C) { + testServer.Response(200, nil, TestCreateDomainXmlOK) + + domain := s.sdb.Domain("domain") + resp, err := domain.CreateDomain() + req := testServer.WaitRequest() + + c.Assert(req.Method, Equals, "GET") + c.Assert(req.URL.Path, Equals, "/") + c.Assert(req.Header["Date"], Not(Equals), "") + + c.Assert(resp.ResponseMetadata.RequestId, Equals, "63264005-7a5f-e01a-a224-395c63b89f6d") + c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0055590279) + + c.Assert(err, IsNil) +} + +func (s *S) TestListDomainsOK(c *C) { + testServer.Response(200, nil, TestListDomainsXmlOK) + + resp, err := s.sdb.ListDomains() + req := testServer.WaitRequest() + + c.Assert(req.Method, Equals, "GET") + c.Assert(req.URL.Path, Equals, "/") + c.Assert(req.Header["Date"], Not(Equals), "") + + c.Assert(resp.ResponseMetadata.RequestId, Equals, "15fcaf55-9914-63c2-21f3-951e31193790") + c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0000071759) + c.Assert(resp.Domains, DeepEquals, []string{"Account", "Domain", "Record"}) + + c.Assert(err, IsNil) +} + +func (s *S) TestListDomainsWithNextTokenXmlOK(c *C) { + testServer.Response(200, nil, TestListDomainsWithNextTokenXmlOK) + + resp, err := s.sdb.ListDomains() + req := testServer.WaitRequest() + + c.Assert(req.Method, Equals, "GET") + c.Assert(req.URL.Path, Equals, "/") + c.Assert(req.Header["Date"], Not(Equals), "") + + c.Assert(resp.ResponseMetadata.RequestId, Equals, "eb13162f-1b95-4511-8b12-489b86acfd28") + c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0000219907) + c.Assert(resp.Domains, DeepEquals, []string{"Domain1-200706011651", "Domain2-200706011652"}) + c.Assert(resp.NextToken, Equals, "TWV0ZXJpbmdUZXN0RG9tYWluMS0yMDA3MDYwMTE2NTY=") + + c.Assert(err, IsNil) +} + +func (s *S) TestDeleteDomainOK(c *C) { + testServer.Response(200, nil, TestDeleteDomainXmlOK) + + domain := s.sdb.Domain("domain") + resp, err := domain.DeleteDomain() + req := testServer.WaitRequest() + + c.Assert(req.Method, Equals, "GET") + c.Assert(req.URL.Path, Equals, "/") + c.Assert(req.Header["Date"], Not(Equals), "") + + c.Assert(resp.ResponseMetadata.RequestId, Equals, "039e1e25-9a64-2a74-93da-2fda36122a97") + c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0055590278) + + c.Assert(err, IsNil) +} + +func (s *S) TestPutAttrsOK(c *C) { + testServer.Response(200, nil, TestPutAttrsXmlOK) + + domain := s.sdb.Domain("MyDomain") + item := domain.Item("Item123") + + putAttrs := new(sdb.PutAttrs) + putAttrs.Add("FirstName", "john") + putAttrs.Add("LastName", "smith") + putAttrs.Replace("MiddleName", "jacob") + + putAttrs.IfValue("FirstName", "john") + putAttrs.IfMissing("FirstName") + + resp, err := item.PutAttrs(putAttrs) + req := testServer.WaitRequest() + c.Assert(req.Method, Equals, "GET") + c.Assert(req.URL.Path, Equals, "/") + c.Assert(req.Form["Action"], DeepEquals, []string{"PutAttributes"}) + c.Assert(req.Form["ItemName"], DeepEquals, []string{"Item123"}) + c.Assert(req.Form["DomainName"], DeepEquals, []string{"MyDomain"}) + c.Assert(req.Form["Attribute.1.Name"], DeepEquals, []string{"FirstName"}) + c.Assert(req.Form["Attribute.1.Value"], DeepEquals, []string{"john"}) + c.Assert(req.Form["Attribute.2.Name"], DeepEquals, []string{"LastName"}) + c.Assert(req.Form["Attribute.2.Value"], DeepEquals, []string{"smith"}) + c.Assert(req.Form["Attribute.3.Name"], DeepEquals, []string{"MiddleName"}) + c.Assert(req.Form["Attribute.3.Value"], DeepEquals, []string{"jacob"}) + c.Assert(req.Form["Attribute.3.Replace"], DeepEquals, []string{"true"}) + + c.Assert(req.Form["Expected.1.Name"], DeepEquals, []string{"FirstName"}) + c.Assert(req.Form["Expected.1.Value"], DeepEquals, []string{"john"}) + c.Assert(req.Form["Expected.1.Exists"], DeepEquals, []string{"false"}) + + c.Assert(err, IsNil) + c.Assert(resp.ResponseMetadata.RequestId, Equals, "490206ce-8292-456c-a00f-61b335eb202b") + c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0000219907) + +} + +func (s *S) TestAttrsOK(c *C) { + testServer.Response(200, nil, TestAttrsXmlOK) + + domain := s.sdb.Domain("MyDomain") + item := domain.Item("Item123") + + resp, err := item.Attrs(nil, true) + req := testServer.WaitRequest() + + c.Assert(req.Method, Equals, "GET") + c.Assert(req.URL.Path, Equals, "/") + c.Assert(req.Header["Date"], Not(Equals), "") + c.Assert(req.Form["Action"], DeepEquals, []string{"GetAttributes"}) + c.Assert(req.Form["ItemName"], DeepEquals, []string{"Item123"}) + c.Assert(req.Form["DomainName"], DeepEquals, []string{"MyDomain"}) + c.Assert(req.Form["ConsistentRead"], DeepEquals, []string{"true"}) + + c.Assert(resp.Attrs[0].Name, Equals, "Color") + c.Assert(resp.Attrs[0].Value, Equals, "Blue") + c.Assert(resp.Attrs[1].Name, Equals, "Size") + c.Assert(resp.Attrs[1].Value, Equals, "Med") + c.Assert(resp.ResponseMetadata.RequestId, Equals, "b1e8f1f7-42e9-494c-ad09-2674e557526d") + c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0000219942) + + c.Assert(err, IsNil) +} + +func (s *S) TestAttrsSelectOK(c *C) { + testServer.Response(200, nil, TestAttrsXmlOK) + + domain := s.sdb.Domain("MyDomain") + item := domain.Item("Item123") + + resp, err := item.Attrs([]string{"Color", "Size"}, true) + req := testServer.WaitRequest() + + c.Assert(req.Method, Equals, "GET") + c.Assert(req.URL.Path, Equals, "/") + c.Assert(req.Header["Date"], Not(Equals), "") + c.Assert(req.Form["Action"], DeepEquals, []string{"GetAttributes"}) + c.Assert(req.Form["ItemName"], DeepEquals, []string{"Item123"}) + c.Assert(req.Form["DomainName"], DeepEquals, []string{"MyDomain"}) + c.Assert(req.Form["ConsistentRead"], DeepEquals, []string{"true"}) + c.Assert(req.Form["AttributeName.1"], DeepEquals, []string{"Color"}) + c.Assert(req.Form["AttributeName.2"], DeepEquals, []string{"Size"}) + + c.Assert(resp.Attrs[0].Name, Equals, "Color") + c.Assert(resp.Attrs[0].Value, Equals, "Blue") + c.Assert(resp.Attrs[1].Name, Equals, "Size") + c.Assert(resp.Attrs[1].Value, Equals, "Med") + c.Assert(resp.ResponseMetadata.RequestId, Equals, "b1e8f1f7-42e9-494c-ad09-2674e557526d") + c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0000219942) + + c.Assert(err, IsNil) +} + +func (s *S) TestSelectOK(c *C) { + testServer.Response(200, nil, TestSelectXmlOK) + + resp, err := s.sdb.Select("select Color from MyDomain where Color like 'Blue%'", true) + req := testServer.WaitRequest() + + c.Assert(req.Method, Equals, "GET") + c.Assert(req.URL.Path, Equals, "/") + c.Assert(req.Header["Date"], Not(Equals), "") + c.Assert(req.Form["Action"], DeepEquals, []string{"Select"}) + c.Assert(req.Form["ConsistentRead"], DeepEquals, []string{"true"}) + + c.Assert(resp.ResponseMetadata.RequestId, Equals, "b1e8f1f7-42e9-494c-ad09-2674e557526d") + c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0000219907) + c.Assert(len(resp.Items), Equals, 2) + c.Assert(resp.Items[0].Name, Equals, "Item_03") + c.Assert(resp.Items[1].Name, Equals, "Item_06") + c.Assert(resp.Items[0].Attrs[0].Name, Equals, "Category") + c.Assert(resp.Items[0].Attrs[0].Value, Equals, "Clothes") + + c.Assert(err, IsNil) +} diff --git a/vendor/github.com/goamz/goamz/exp/sdb/sign.go b/vendor/github.com/goamz/goamz/exp/sdb/sign.go new file mode 100644 index 000000000..040ed5385 --- /dev/null +++ b/vendor/github.com/goamz/goamz/exp/sdb/sign.go @@ -0,0 +1,54 @@ +package sdb + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/base64" + "github.com/goamz/goamz/aws" + "net/http" + "net/url" + "sort" + "strings" +) + +var b64 = base64.StdEncoding + +// ---------------------------------------------------------------------------- +// SimpleDB signing (http://goo.gl/CaY81) + +func sign(auth aws.Auth, method, path string, params url.Values, headers http.Header) { + var host string + for k, v := range headers { + k = strings.ToLower(k) + switch k { + case "host": + host = v[0] + } + } + + // set up some defaults used for signing the request + params["AWSAccessKeyId"] = []string{auth.AccessKey} + params["SignatureVersion"] = []string{"2"} + params["SignatureMethod"] = []string{"HmacSHA256"} + if auth.Token() != "" { + params["SecurityToken"] = []string{auth.Token()} + } + + // join up all the incoming params + var sarray []string + for k, v := range params { + sarray = append(sarray, aws.Encode(k)+"="+aws.Encode(v[0])) + } + sort.StringSlice(sarray).Sort() + joined := strings.Join(sarray, "&") + + // create the payload, sign it and create the signature + payload := strings.Join([]string{method, host, "/", joined}, "\n") + hash := hmac.New(sha256.New, []byte(auth.SecretKey)) + hash.Write([]byte(payload)) + signature := make([]byte, b64.EncodedLen(hash.Size())) + b64.Encode(signature, hash.Sum(nil)) + + // add the signature to the outgoing params + params["Signature"] = []string{string(signature)} +} diff --git a/vendor/github.com/goamz/goamz/exp/sdb/sign_test.go b/vendor/github.com/goamz/goamz/exp/sdb/sign_test.go new file mode 100644 index 000000000..f45ad15e1 --- /dev/null +++ b/vendor/github.com/goamz/goamz/exp/sdb/sign_test.go @@ -0,0 +1,29 @@ +package sdb_test + +import ( + "github.com/goamz/goamz/aws" + "github.com/goamz/goamz/exp/sdb" + . "gopkg.in/check.v1" +) + +// SimpleDB ReST authentication docs: http://goo.gl/CaY81 + +var testAuth = aws.Auth{AccessKey: "access-key-id-s8eBOWuU", SecretKey: "secret-access-key-UkQjTLd9"} + +func (s *S) TestSignExampleDomainCreate(c *C) { + method := "GET" + params := map[string][]string{ + "Action": {"CreateDomain"}, + "DomainName": {"MyDomain"}, + "Timestamp": {"2011-08-20T07:23:57+12:00"}, + "Version": {"2009-04-15"}, + } + headers := map[string][]string{ + "Host": {"sdb.amazonaws.com"}, + } + sdb.Sign(testAuth, method, "", params, headers) + expected := "ot2JaeeqMRJqgAqW67hkzUlffgxdOz4RykbrECB+tDU=" + c.Assert(params["Signature"], DeepEquals, []string{expected}) +} + +// Do a few test methods which takes combinations of params |