tailored-etsy 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. data/.gitignore +8 -0
  2. data/.travis.yml +8 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE +9 -0
  5. data/README.md +280 -0
  6. data/Rakefile +12 -0
  7. data/etsy.gemspec +28 -0
  8. data/lib/etsy.rb +172 -0
  9. data/lib/etsy/address.rb +47 -0
  10. data/lib/etsy/basic_client.rb +26 -0
  11. data/lib/etsy/category.rb +84 -0
  12. data/lib/etsy/country.rb +27 -0
  13. data/lib/etsy/image.rb +34 -0
  14. data/lib/etsy/listing.rb +178 -0
  15. data/lib/etsy/model.rb +123 -0
  16. data/lib/etsy/payment_template.rb +33 -0
  17. data/lib/etsy/profile.rb +49 -0
  18. data/lib/etsy/request.rb +148 -0
  19. data/lib/etsy/response.rb +112 -0
  20. data/lib/etsy/section.rb +16 -0
  21. data/lib/etsy/secure_client.rb +128 -0
  22. data/lib/etsy/shipping_template.rb +32 -0
  23. data/lib/etsy/shop.rb +83 -0
  24. data/lib/etsy/transaction.rb +18 -0
  25. data/lib/etsy/user.rb +91 -0
  26. data/lib/etsy/verification_request.rb +17 -0
  27. data/lib/etsy/version.rb +3 -0
  28. data/test/fixtures/address/getUserAddresses.json +12 -0
  29. data/test/fixtures/category/findAllSubCategoryChildren.json +78 -0
  30. data/test/fixtures/category/findAllTopCategory.json +347 -0
  31. data/test/fixtures/category/findAllTopCategory.single.json +18 -0
  32. data/test/fixtures/category/findAllTopCategoryChildren.json +308 -0
  33. data/test/fixtures/category/getCategory.multiple.json +28 -0
  34. data/test/fixtures/category/getCategory.single.json +18 -0
  35. data/test/fixtures/country/getCountry.json +1 -0
  36. data/test/fixtures/image/findAllListingImages.json +102 -0
  37. data/test/fixtures/listing/findAllListingActive.category.json +827 -0
  38. data/test/fixtures/listing/findAllShopListings.json +69 -0
  39. data/test/fixtures/listing/getListing.multiple.json +1 -0
  40. data/test/fixtures/listing/getListing.single.json +1 -0
  41. data/test/fixtures/payment_template/getPaymentTemplate.json +1 -0
  42. data/test/fixtures/profile/new.json +28 -0
  43. data/test/fixtures/section/getShopSection.json +18 -0
  44. data/test/fixtures/shipping_template/getShippingTemplate.json +1 -0
  45. data/test/fixtures/shop/findAllShop.json +1 -0
  46. data/test/fixtures/shop/findAllShop.single.json +1 -0
  47. data/test/fixtures/shop/getShop.multiple.json +1 -0
  48. data/test/fixtures/shop/getShop.single.json +33 -0
  49. data/test/fixtures/transaction/findAllShopTransactions.json +1 -0
  50. data/test/fixtures/user/getUser.multiple.json +29 -0
  51. data/test/fixtures/user/getUser.single.json +13 -0
  52. data/test/fixtures/user/getUser.single.private.json +18 -0
  53. data/test/fixtures/user/getUser.single.withProfile.json +38 -0
  54. data/test/fixtures/user/getUser.single.withShops.json +41 -0
  55. data/test/test_helper.rb +44 -0
  56. data/test/unit/etsy/address_test.rb +61 -0
  57. data/test/unit/etsy/basic_client_test.rb +28 -0
  58. data/test/unit/etsy/category_test.rb +106 -0
  59. data/test/unit/etsy/country_test.rb +64 -0
  60. data/test/unit/etsy/image_test.rb +43 -0
  61. data/test/unit/etsy/listing_test.rb +217 -0
  62. data/test/unit/etsy/model_test.rb +64 -0
  63. data/test/unit/etsy/payment_template_test.rb +68 -0
  64. data/test/unit/etsy/profile_test.rb +111 -0
  65. data/test/unit/etsy/request_test.rb +192 -0
  66. data/test/unit/etsy/response_test.rb +164 -0
  67. data/test/unit/etsy/section_test.rb +28 -0
  68. data/test/unit/etsy/secure_client_test.rb +132 -0
  69. data/test/unit/etsy/shipping_template_test.rb +24 -0
  70. data/test/unit/etsy/shop_test.rb +104 -0
  71. data/test/unit/etsy/transaction_test.rb +52 -0
  72. data/test/unit/etsy/user_test.rb +218 -0
  73. data/test/unit/etsy/verification_request_test.rb +26 -0
  74. data/test/unit/etsy_test.rb +114 -0
  75. metadata +269 -0
@@ -0,0 +1,68 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module Etsy
4
+ class PaymentTemplateTest < Test::Unit::TestCase
5
+ context "An instance of the PaymentTemplate class" do
6
+ setup do
7
+ data = read_fixture('payment_template/getPaymentTemplate.json')
8
+ @payment_template = PaymentTemplate.new(data.first)
9
+ end
10
+
11
+ should "have an id" do
12
+ @payment_template.id.should == 51
13
+ end
14
+
15
+ should "have attribute: allow_check" do
16
+ @payment_template.allow_check.should == false
17
+ end
18
+
19
+ should "have attribute: allow_mo" do
20
+ @payment_template.allow_mo.should == false
21
+ end
22
+
23
+ should "have attribute: allow_other" do
24
+ @payment_template.allow_other.should == true
25
+ end
26
+
27
+ should "have attribute: allow_paypal" do
28
+ @payment_template.allow_paypal.should == true
29
+ end
30
+
31
+ should "have attribute: allow_cc" do
32
+ @payment_template.allow_cc.should == false
33
+ end
34
+
35
+ should "have attribute: paypal_email" do
36
+ @payment_template.paypal_email.should == "user@example.com"
37
+ end
38
+
39
+ should "have attribute: name" do
40
+ @payment_template.name.should == "Example Template"
41
+ end
42
+
43
+ should "have attribute: first_line" do
44
+ @payment_template.first_line.should == nil
45
+ end
46
+
47
+ should "have attribute: second_line" do
48
+ @payment_template.second_line.should == nil
49
+ end
50
+
51
+ should "have attribute: city" do
52
+ @payment_template.city.should == "Chicago"
53
+ end
54
+
55
+ should "have attribute: state" do
56
+ @payment_template.state.should == "IL"
57
+ end
58
+
59
+ should "have attribute: zip" do
60
+ @payment_template.zip.should == "60605"
61
+ end
62
+
63
+ should "have attribute: country_id" do
64
+ @payment_template.country_id.should == 4
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,111 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module Etsy
4
+ class ProfileTest < Test::Unit::TestCase
5
+
6
+ # The Etsy profile can only be accessed as an association through other resources.
7
+ # There are no finders.
8
+ context "An instance of the Profile class" do
9
+
10
+ context "with response data" do
11
+ setup do
12
+ data = read_fixture('profile/new.json')
13
+ @profile = Profile.new(data)
14
+ end
15
+
16
+ should "have a value for :id" do
17
+ @profile.id.should == 123
18
+ end
19
+
20
+ should "have a value for :user_id" do
21
+ @profile.user_id.should == 5327518
22
+ end
23
+
24
+ should "have a value for :username" do
25
+ @profile.username.should == "littletjane"
26
+ end
27
+
28
+ should "have a value for :bio" do
29
+ @profile.bio.should == "I make stuff"
30
+ end
31
+
32
+ should "have a value for :gender" do
33
+ @profile.gender.should == "female"
34
+ end
35
+
36
+ should "have a value for :birth_day" do
37
+ @profile.birth_day.should == "01"
38
+ end
39
+
40
+ should "have a value for :birth_month" do
41
+ @profile.birth_month.should == "01"
42
+ end
43
+
44
+ should "have a value for :birth_year" do
45
+ @profile.birth_year.should == "1970"
46
+ end
47
+
48
+ should "have a value for :joined_at" do
49
+ @profile.joined_at.should == Time.at(1225392413)
50
+ end
51
+
52
+ should "have a value for :materials" do
53
+ @profile.materials.should == []
54
+ end
55
+
56
+ should "have a value for :country_id" do
57
+ @profile.country_id.should == 209
58
+ end
59
+
60
+ should "have a value for :city" do
61
+ @profile.city.should == "BigCity"
62
+ end
63
+
64
+ should "have a value for :avatar_id" do
65
+ @profile.avatar_id.should == 345
66
+ end
67
+
68
+ should "have a value for :location" do
69
+ @profile.location.should == "HQ"
70
+ end
71
+
72
+ should "have a value for :region" do
73
+ @profile.region.should == "The Desert"
74
+ end
75
+
76
+ should "have a value for :lat" do
77
+ @profile.lat.should == 39.5304
78
+ end
79
+
80
+ should "have a value for :lon" do
81
+ @profile.lon.should == -119.8144
82
+ end
83
+
84
+ should "have a value for :transaction_buy_count" do
85
+ @profile.transaction_buy_count.should == 19
86
+ end
87
+
88
+ should "have a value for :transaction_sold_count" do
89
+ @profile.transaction_sold_count.should == 16
90
+ end
91
+
92
+ should "have a value for :seller?" do
93
+ @profile.seller?.should == true
94
+ end
95
+
96
+ should "have a value for :image" do
97
+ @profile.image.should == 'some_image.jpg'
98
+ end
99
+
100
+ should "have a value for :first_name" do
101
+ @profile.first_name.should == 'Tinker'
102
+ end
103
+
104
+ should "have a value for :last_name" do
105
+ @profile.last_name.should == 'Bell'
106
+ end
107
+ end
108
+
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,192 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module Etsy
4
+ class RequestTest < Test::Unit::TestCase
5
+
6
+ context "The Request class" do
7
+
8
+ should "be able to retrieve a response" do
9
+ http_response = stub()
10
+ response = stub()
11
+
12
+ Response.expects(:new).with(http_response).returns(response)
13
+
14
+ request = mock {|m| m.expects(:get).with().returns(http_response) }
15
+ Request.expects(:new).with('/user', :one => 'two').returns(request)
16
+
17
+ Request.get('/user', :one => 'two').should == response
18
+ end
19
+
20
+ should "require OAuth credentials if :require_secure is set" do
21
+ lambda do
22
+ Request.new('/path', :require_secure => true)
23
+ end.should raise_error(/Secure connection required/)
24
+ end
25
+ end
26
+
27
+ context "An instance of the Request class" do
28
+
29
+ should "know the base path" do
30
+ Request.new('').base_path.should == '/v2'
31
+ end
32
+
33
+ should "append the api_key to the parameters in basic mode" do
34
+ Etsy.expects(:api_key).with().returns('key')
35
+ Request.stubs(:secure?).returns(false)
36
+
37
+ r = Request.new('/user', :limit => '1')
38
+ r.parameters.should == {:limit => '1', :api_key => 'key'}
39
+ end
40
+
41
+ should "not append the api_key to the parameters in secure mode" do
42
+ Etsy.stubs(:access_mode).returns(:authenticated)
43
+
44
+ r = Request.new('/user', :limit => '1', :access_token => 'token', :access_secret => 'secret')
45
+ r.parameters.should == {:limit => '1'}
46
+ end
47
+
48
+
49
+ should "be able to generate query parameters" do
50
+ r = Request.new('/user')
51
+ r.expects(:parameters).with().returns(:api_key => 'foo')
52
+ r.query.should == 'api_key=foo'
53
+ end
54
+
55
+ should "be able to join multiple query parameters" do
56
+ params = {:limit => '1', :other => 'yes'}
57
+
58
+ r = Request.new('/user', params)
59
+ r.stubs(:parameters).with().returns(params)
60
+
61
+ r.query.split('&').sort.should == %w(limit=1 other=yes)
62
+ end
63
+
64
+ should "be able to request a single association" do
65
+ r = Request.new('/foo', {:includes => 'Thunder'})
66
+ r.stubs(:parameters).with().returns({:a => :b})
67
+ CGI.parse(r.query).should == { "a" => ["b"], "includes" => ["Thunder"] }
68
+ end
69
+
70
+ should "be able make simplified association requests" do
71
+ r = Request.new('/foo', {:includes => ['Thunder', 'Lightning']})
72
+ r.stubs(:parameters).with().returns({:a => :b})
73
+ CGI.parse(r.query).should == { "a" => ["b"], "includes" => ["Thunder,Lightning"] }
74
+ end
75
+
76
+ should "be able to generate detailed association queries" do
77
+ r = Request.new('/foo')
78
+ r.association(:resource => 'Lightning').should == 'Lightning'
79
+ end
80
+
81
+ should "be able to specify fields in association query" do
82
+ r = Request.new('/foo')
83
+ params = {:resource => 'Lightning', :fields => ['one', 'two']}
84
+ r.association(params).should == 'Lightning(one,two)'
85
+ end
86
+
87
+ should "be able to specify limit in association query" do
88
+ r = Request.new('/foo')
89
+ params = {:resource => 'Lightning', :limit => 3}
90
+ r.association(params).should == 'Lightning:3:0'
91
+ end
92
+
93
+ should "be able to specify offset in association query" do
94
+ r = Request.new('/foo')
95
+ params = {:resource => 'Lightning', :offset => 7}
96
+ r.association(params).should == 'Lightning:25:7'
97
+ end
98
+
99
+ should "be able to join multiple resources in association query" do
100
+ params = {
101
+ :a => 'b',
102
+ :includes => [
103
+ {:resource => 'Lightning'},
104
+ {:resource => 'Thunder'}
105
+ ]
106
+ }
107
+ r = Request.new('/foo', params)
108
+ r.stubs(:base_path).with().returns('/base')
109
+ r.stubs(:parameters).with().returns(:a => 'b')
110
+ uri = URI.parse(r.endpoint_url)
111
+ uri.path.should == '/base/foo'
112
+ CGI.parse(uri.query).should == { "a" => ["b"], "includes" => ["Lightning,Thunder"] }
113
+ end
114
+
115
+ should "be able to determine the endpoint URI when in read-only mode" do
116
+ r = Request.new('/user')
117
+ r.stubs(:base_path).with().returns('/base')
118
+ r.stubs(:query).with().returns('a=b')
119
+
120
+ r.endpoint_url.should == '/base/user?a=b'
121
+ end
122
+
123
+ should "be able to determine the endpoint URI when in authenticated mode" do
124
+ Etsy.stubs(:access_mode).returns(:authenticated)
125
+
126
+ r = Request.new('/user', :access_token => 'toke', :access_secret => 'secret')
127
+ r.stubs(:base_path).with().returns('/base')
128
+ r.stubs(:query).with().returns('a=b')
129
+
130
+ r.endpoint_url.should == '/base/user?a=b'
131
+ end
132
+
133
+ should "know the client for read-only mode" do
134
+ Etsy.stubs(:access_mode).returns(:read_only)
135
+ Etsy.stubs(:host).returns('example.com')
136
+
137
+ BasicClient.stubs(:new).with('example.com').returns('client')
138
+
139
+ r = Request.new('')
140
+
141
+ r.client.should == 'client'
142
+ end
143
+
144
+ should "know the client for authenticated mode when there is no access token information" do
145
+ Etsy.stubs(:access_mode).returns(:authenticated)
146
+ Etsy.stubs(:host).returns('example.com')
147
+
148
+ BasicClient.stubs(:new).with('example.com').returns('client')
149
+
150
+ r = Request.new('')
151
+
152
+ r.client.should == 'client'
153
+ end
154
+
155
+ should "know the client for authenticated mode when there is access token information" do
156
+ Etsy.stubs(:access_mode).returns(:authenticated)
157
+ SecureClient.stubs(:new).with(:access_token => 'toke', :access_secret => 'secret').returns('client')
158
+
159
+ r = Request.new('', :access_token => 'toke', :access_secret => 'secret')
160
+ r.client.should == 'client'
161
+ end
162
+
163
+ should "be able to make a successful request" do
164
+ client = stub()
165
+ client.stubs(:get).with('endpoint_url').returns('response')
166
+
167
+ r = Request.new('/user')
168
+ r.stubs(:endpoint_url).with().returns('endpoint_url')
169
+ r.stubs(:client).returns(client)
170
+
171
+ r.get.should == 'response'
172
+ end
173
+
174
+ should "not modify the options hash passed to it" do
175
+ options = { :includes => 'Lightning',
176
+ :access_token => 'token',
177
+ :access_secret => 'secret',
178
+ :fields => [:id],
179
+ :limit => 100,
180
+ :offset => 100 }
181
+ options_copy = options.dup
182
+
183
+ Request.new('', options)
184
+
185
+ options.should == options_copy
186
+ end
187
+
188
+ end
189
+
190
+
191
+ end
192
+ end
@@ -0,0 +1,164 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module Etsy
4
+ class ResponseTest < Test::Unit::TestCase
5
+
6
+ context "An instance of the Response class" do
7
+
8
+ should "be able to decode the JSON data to a hash" do
9
+ data = '{ "foo":"bar" }'
10
+
11
+ r = Response.new(stub(:body => data))
12
+ r.to_hash.should == {'foo' => 'bar'}
13
+ end
14
+
15
+ should "only decode the JSON data once" do
16
+ JSON.expects(:parse).once.returns({})
17
+
18
+ r = Response.new(stub(:body => '{ "foo":"bar" }'))
19
+ 2.times { r.to_hash }
20
+ end
21
+
22
+ should "have a record count when the response is not paginated" do
23
+ raw_response = mock
24
+ raw_response.stubs(:body => '{ "count": 1 }')
25
+ r = Response.new(raw_response)
26
+
27
+ r.count.should == 1
28
+ end
29
+
30
+ should "have a record count when the response is paginated" do
31
+ raw_response = mock
32
+ raw_response.stubs(:body => '{ "count": 100, "results": [{},{}], "pagination": {} }')
33
+ r = Response.new(raw_response)
34
+
35
+ r.count.should == 2
36
+ end
37
+
38
+ should "return a count of 0 when the response is paginated and the results are empty" do
39
+ raw_response = mock
40
+ raw_response.stubs(:body => '{ "count": 100, "results": null, "pagination": {} }')
41
+ r = Response.new(raw_response)
42
+
43
+ r.count.should == 0
44
+ end
45
+
46
+ should "return an array if there are multiple results entries" do
47
+ r = Response.new('')
48
+ r.expects(:code).with().returns('200')
49
+ r.expects(:count).with().returns(2)
50
+ r.expects(:to_hash).with().returns('results' => %w(one two))
51
+
52
+ r.result.should == %w(one two)
53
+ end
54
+
55
+ should "return a single value for results if there is only 1 result" do
56
+ r = Response.new('')
57
+ r.expects(:code).with().returns('200')
58
+ r.expects(:count).with().returns(1)
59
+ r.expects(:to_hash).with().returns('results' => ['foo'])
60
+
61
+ r.result.should == 'foo'
62
+ end
63
+
64
+ should "provide the complete raw body" do
65
+ raw_response = mock
66
+ raw_response.stubs(:body => "I am not JSON")
67
+ r = Response.new(raw_response)
68
+
69
+ r.body.should == 'I am not JSON'
70
+ end
71
+
72
+ should "raise an invalid JSON exception if the response is not json" do
73
+ raw_response = mock
74
+ raw_response.stubs(:body => "I am not JSON", :code => 500)
75
+ r = Response.new(raw_response)
76
+
77
+ lambda { r.to_hash }.should raise_error(Etsy::EtsyJSONInvalid)
78
+ lambda { r.to_hash }.should raise_error("CODE: 500, BODY: I am not JSON")
79
+ end
80
+
81
+ should "raise OAuthTokenRevoked" do
82
+ raw_response = mock
83
+ raw_response.stubs(:body => "oauth_problem=token_revoked")
84
+ r = Response.new(raw_response)
85
+
86
+ lambda { r.to_hash }.should raise_error(Etsy::OAuthTokenRevoked)
87
+ end
88
+
89
+ should "raise MissingShopID" do
90
+ raw_response = mock
91
+ raw_response.stubs(:body => "something Shop with PK shop_id something")
92
+ r = Response.new(raw_response)
93
+
94
+ lambda { r.to_hash }.should raise_error(Etsy::MissingShopID)
95
+ end
96
+
97
+ should "raise InvalidUserID" do
98
+ raw_response = mock
99
+ raw_response.stubs(:body => "'someguy' is not a valid user_id")
100
+ r = Response.new(raw_response)
101
+
102
+ lambda { r.to_hash }.should raise_error(Etsy::InvalidUserID)
103
+ end
104
+
105
+ should "raise TemporaryIssue" do
106
+ raw_response = mock
107
+ raw_response.stubs(:body => "something Temporary Etsy issue something")
108
+ r = Response.new(raw_response)
109
+
110
+ lambda { r.to_hash }.should raise_error(Etsy::TemporaryIssue)
111
+
112
+ raw_response = mock
113
+ raw_response.stubs(:body => "something Resource temporarily unavailable something")
114
+ r = Response.new(raw_response)
115
+
116
+ lambda { r.to_hash }.should raise_error(Etsy::TemporaryIssue)
117
+
118
+ raw_response = mock
119
+ raw_response.stubs(:body => "something You have exceeded your API limit something")
120
+ r = Response.new(raw_response)
121
+
122
+ lambda { r.to_hash }.should raise_error(Etsy::TemporaryIssue)
123
+ end
124
+
125
+ should "provide the code" do
126
+ raw_response = mock
127
+ raw_response.expects(:code => "400")
128
+ r = Response.new(raw_response)
129
+
130
+ r.code.should == '400'
131
+ end
132
+
133
+ should "consider a code of 2xx successful" do
134
+ raw_response = mock
135
+
136
+ raw_response.expects(:code => "200")
137
+ r = Response.new(raw_response)
138
+ r.should be_success
139
+
140
+ raw_response.expects(:code => "201")
141
+ r = Response.new(raw_response)
142
+ r.should be_success
143
+ end
144
+
145
+ should "consider a code of 4xx unsuccessful" do
146
+ raw_response = mock
147
+
148
+ raw_response.expects(:code => "404")
149
+ r = Response.new(raw_response)
150
+ r.should_not be_success
151
+ end
152
+
153
+ should "consider a code of 5xx unsuccessful" do
154
+ raw_response = mock
155
+
156
+ raw_response.expects(:code => "500")
157
+ r = Response.new(raw_response)
158
+ r.should_not be_success
159
+ end
160
+ end
161
+
162
+
163
+ end
164
+ end