etsy 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/.gitignore +8 -0
  2. data/.travis.yml +8 -0
  3. data/Gemfile +10 -0
  4. data/README.md +300 -0
  5. data/Rakefile +2 -30
  6. data/etsy.gemspec +36 -0
  7. data/lib/etsy.rb +46 -17
  8. data/lib/etsy/address.rb +47 -0
  9. data/lib/etsy/basic_client.rb +1 -1
  10. data/lib/etsy/category.rb +84 -0
  11. data/lib/etsy/country.rb +27 -0
  12. data/lib/etsy/image.rb +7 -3
  13. data/lib/etsy/listing.rb +107 -8
  14. data/lib/etsy/model.rb +99 -3
  15. data/lib/etsy/payment_template.rb +33 -0
  16. data/lib/etsy/profile.rb +49 -0
  17. data/lib/etsy/request.rb +85 -17
  18. data/lib/etsy/response.rb +80 -4
  19. data/lib/etsy/section.rb +16 -0
  20. data/lib/etsy/secure_client.rb +49 -4
  21. data/lib/etsy/shipping_template.rb +32 -0
  22. data/lib/etsy/shop.rb +21 -12
  23. data/lib/etsy/transaction.rb +18 -0
  24. data/lib/etsy/user.rb +45 -13
  25. data/lib/etsy/verification_request.rb +2 -2
  26. data/test/fixtures/address/getUserAddresses.json +12 -0
  27. data/test/fixtures/category/findAllSubCategoryChildren.json +78 -0
  28. data/test/fixtures/category/findAllTopCategory.json +347 -0
  29. data/test/fixtures/category/findAllTopCategory.single.json +18 -0
  30. data/test/fixtures/category/findAllTopCategoryChildren.json +308 -0
  31. data/test/fixtures/category/getCategory.multiple.json +28 -0
  32. data/test/fixtures/category/getCategory.single.json +18 -0
  33. data/test/fixtures/country/getCountry.json +1 -0
  34. data/test/fixtures/listing/findAllListingActive.category.json +827 -0
  35. data/test/fixtures/listing/{findAllShopListingsActive.json → findAllShopListings.json} +0 -0
  36. data/test/fixtures/listing/getListing.multiple.json +1 -0
  37. data/test/fixtures/listing/getListing.single.json +1 -0
  38. data/test/fixtures/payment_template/getPaymentTemplate.json +1 -0
  39. data/test/fixtures/profile/new.json +28 -0
  40. data/test/fixtures/section/getShopSection.json +18 -0
  41. data/test/fixtures/shipping_template/getShippingTemplate.json +1 -0
  42. data/test/fixtures/shop/getShop.single.json +4 -3
  43. data/test/fixtures/transaction/findAllShopTransactions.json +1 -0
  44. data/test/fixtures/user/getUser.single.withProfile.json +38 -0
  45. data/test/fixtures/user/getUser.single.withShops.json +41 -0
  46. data/test/test_helper.rb +9 -4
  47. data/test/unit/etsy/address_test.rb +61 -0
  48. data/test/unit/etsy/category_test.rb +106 -0
  49. data/test/unit/etsy/country_test.rb +64 -0
  50. data/test/unit/etsy/listing_test.rb +112 -5
  51. data/test/unit/etsy/model_test.rb +64 -0
  52. data/test/unit/etsy/payment_template_test.rb +68 -0
  53. data/test/unit/etsy/profile_test.rb +111 -0
  54. data/test/unit/etsy/request_test.rb +89 -53
  55. data/test/unit/etsy/response_test.rb +118 -4
  56. data/test/unit/etsy/section_test.rb +28 -0
  57. data/test/unit/etsy/secure_client_test.rb +27 -5
  58. data/test/unit/etsy/shipping_template_test.rb +24 -0
  59. data/test/unit/etsy/shop_test.rb +12 -5
  60. data/test/unit/etsy/transaction_test.rb +52 -0
  61. data/test/unit/etsy/user_test.rb +147 -8
  62. data/test/unit/etsy/verification_request_test.rb +3 -3
  63. data/test/unit/etsy_test.rb +19 -7
  64. metadata +133 -77
  65. data/README.rdoc +0 -208
  66. data/lib/etsy/version.rb +0 -13
@@ -19,15 +19,33 @@ module Etsy
19
19
  2.times { r.to_hash }
20
20
  end
21
21
 
22
- should "have a record count" do
23
- r = Response.new('')
24
- r.expects(:to_hash).with().returns('count' => 1)
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)
25
26
 
26
27
  r.count.should == 1
27
28
  end
28
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
+
29
46
  should "return an array if there are multiple results entries" do
30
47
  r = Response.new('')
48
+ r.expects(:code).with().returns('200')
31
49
  r.expects(:count).with().returns(2)
32
50
  r.expects(:to_hash).with().returns('results' => %w(one two))
33
51
 
@@ -36,14 +54,110 @@ module Etsy
36
54
 
37
55
  should "return a single value for results if there is only 1 result" do
38
56
  r = Response.new('')
57
+ r.expects(:code).with().returns('200')
39
58
  r.expects(:count).with().returns(1)
40
59
  r.expects(:to_hash).with().returns('results' => ['foo'])
41
60
 
42
61
  r.result.should == 'foo'
43
62
  end
44
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")
75
+ r = Response.new(raw_response)
76
+
77
+ lambda { r.to_hash }.should raise_error(Etsy::EtsyJSONInvalid)
78
+ end
79
+
80
+ should "raise OAuthTokenRevoked" do
81
+ raw_response = mock
82
+ raw_response.stubs(:body => "oauth_problem=token_revoked")
83
+ r = Response.new(raw_response)
84
+
85
+ lambda { r.to_hash }.should raise_error(Etsy::OAuthTokenRevoked)
86
+ end
87
+
88
+ should "raise MissingShopID" do
89
+ raw_response = mock
90
+ raw_response.stubs(:body => "something Shop with PK shop_id something")
91
+ r = Response.new(raw_response)
92
+
93
+ lambda { r.to_hash }.should raise_error(Etsy::MissingShopID)
94
+ end
95
+
96
+ should "raise InvalidUserID" do
97
+ raw_response = mock
98
+ raw_response.stubs(:body => "'someguy' is not a valid user_id")
99
+ r = Response.new(raw_response)
100
+
101
+ lambda { r.to_hash }.should raise_error(Etsy::InvalidUserID)
102
+ end
103
+
104
+ should "raise TemporaryIssue" do
105
+ raw_response = mock
106
+ raw_response.stubs(:body => "something Temporary Etsy issue something")
107
+ r = Response.new(raw_response)
108
+
109
+ lambda { r.to_hash }.should raise_error(Etsy::TemporaryIssue)
110
+
111
+ raw_response = mock
112
+ raw_response.stubs(:body => "something Resource temporarily unavailable something")
113
+ r = Response.new(raw_response)
114
+
115
+ lambda { r.to_hash }.should raise_error(Etsy::TemporaryIssue)
116
+
117
+ raw_response = mock
118
+ raw_response.stubs(:body => "something You have exceeded your API limit something")
119
+ r = Response.new(raw_response)
120
+
121
+ lambda { r.to_hash }.should raise_error(Etsy::TemporaryIssue)
122
+ end
123
+
124
+ should "provide the code" do
125
+ raw_response = mock
126
+ raw_response.expects(:code => "400")
127
+ r = Response.new(raw_response)
128
+
129
+ r.code.should == '400'
130
+ end
131
+
132
+ should "consider a code of 2xx successful" do
133
+ raw_response = mock
134
+
135
+ raw_response.expects(:code => "200")
136
+ r = Response.new(raw_response)
137
+ r.should be_success
138
+
139
+ raw_response.expects(:code => "201")
140
+ r = Response.new(raw_response)
141
+ r.should be_success
142
+ end
143
+
144
+ should "consider a code of 4xx unsuccessful" do
145
+ raw_response = mock
146
+
147
+ raw_response.expects(:code => "404")
148
+ r = Response.new(raw_response)
149
+ r.should_not be_success
150
+ end
151
+
152
+ should "consider a code of 5xx unsuccessful" do
153
+ raw_response = mock
154
+
155
+ raw_response.expects(:code => "500")
156
+ r = Response.new(raw_response)
157
+ r.should_not be_success
158
+ end
45
159
  end
46
160
 
47
161
 
48
162
  end
49
- end
163
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module Etsy
4
+ class SectionTest < Test::Unit::TestCase
5
+ context "An instance of the Section class" do
6
+ setup do
7
+ data = read_fixture('section/getShopSection.json')
8
+ @section = Section.new(data.first)
9
+ end
10
+
11
+ should "have an id" do
12
+ @section.id.should == 11045327
13
+ end
14
+
15
+ should "have an title" do
16
+ @section.title.should == "Blue Items"
17
+ end
18
+
19
+ should "have an user_id" do
20
+ @section.user_id.should == 9569349
21
+ end
22
+
23
+ should "have an active_listing_count" do
24
+ @section.active_listing_count.should == 7
25
+ end
26
+ end
27
+ end
28
+ end
@@ -5,15 +5,17 @@ module Etsy
5
5
 
6
6
  context "An instance of the SecureClient class" do
7
7
 
8
- should "be able to generate an OAuth consumer" do
8
+ should "be able to generate an OAuth consumer for the sandbox" do
9
+ Etsy.stubs(:environment).returns :sandbox
10
+ Etsy.stubs(:host).returns 'sandbox'
9
11
  Etsy.stubs(:api_key).returns('key')
10
12
  Etsy.stubs(:api_secret).returns('secret')
13
+ Etsy.stubs(:permission_scopes).returns(['scope_one', 'scope_two'])
11
14
 
12
15
  OAuth::Consumer.stubs(:new).with('key', 'secret', {
13
- :site => 'http://openapi.etsy.com',
14
- :request_token_path => '/v2/sandbox/oauth/request_token',
15
- :access_token_path => '/v2/sandbox/oauth/access_token',
16
- :authorize_url => 'https://www.etsy.com/oauth/signin'
16
+ :site => 'http://sandbox',
17
+ :request_token_path => '/v2/oauth/request_token?scope=scope_one+scope_two',
18
+ :access_token_path => '/v2/oauth/access_token',
17
19
  }).returns('consumer')
18
20
 
19
21
  client = SecureClient.new
@@ -21,6 +23,26 @@ module Etsy
21
23
  client.consumer.should == 'consumer'
22
24
  end
23
25
 
26
+ should "be able to generate an OAuth consumer in production" do
27
+ Etsy.stubs(:environment).returns :production
28
+ Etsy.stubs(:host).returns 'production'
29
+ Etsy.stubs(:api_key).returns('key')
30
+ Etsy.stubs(:api_secret).returns('secret')
31
+ Etsy.stubs(:permission_scopes).returns(['scope_one', 'scope_two'])
32
+
33
+ OAuth::Consumer.stubs(:new).with('key', 'secret', {
34
+ :site => 'http://production',
35
+ :request_token_path => '/v2/oauth/request_token?scope=scope_one+scope_two',
36
+ :access_token_path => '/v2/oauth/access_token',
37
+ }).returns('consumer')
38
+
39
+ client = SecureClient.new
40
+
41
+ client.consumer.should == 'consumer'
42
+ end
43
+
44
+
45
+
24
46
  should "be able to generate a request token" do
25
47
  Etsy.stubs(:callback_url).with().returns('callback_url')
26
48
  consumer = stub() {|c| c.stubs(:get_request_token).with(:oauth_callback => 'callback_url').returns('toke') }
@@ -0,0 +1,24 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module Etsy
4
+ class ShippingTemplateTest < Test::Unit::TestCase
5
+ context "An instance of the ShippingTemplate class" do
6
+ setup do
7
+ data = read_fixture('shipping_template/getShippingTemplate.json')
8
+ @shipping_template = ShippingTemplate.new(data.first)
9
+ end
10
+
11
+ should "have an id" do
12
+ @shipping_template.id.should == 212
13
+ end
14
+
15
+ should "have an title" do
16
+ @shipping_template.title.should == "Small Items"
17
+ end
18
+
19
+ should "have an user_id" do
20
+ @shipping_template.user_id.should == 14888443
21
+ end
22
+ end
23
+ end
24
+ end
@@ -26,7 +26,7 @@ module Etsy
26
26
  end
27
27
 
28
28
  should "allow a configurable limit when finding all shops" do
29
- shops = mock_request('/shops', {:limit => 100}, 'Shop', 'findAllShop.json')
29
+ shops = mock_request('/shops', {:limit => 100, :offset => 0}, 'Shop', 'findAllShop.json')
30
30
  Shop.all(:limit => 100).should == shops
31
31
  end
32
32
 
@@ -49,7 +49,15 @@ module Etsy
49
49
  end
50
50
 
51
51
  should "have a value for :image_url" do
52
- @shop.image_url.should == "http://ny-image2.etsy.com/iusb_760x100.7358402.jpg"
52
+ @shop.image_url.should == "http://ny-image3.etsy.com/iusb_760x100.8484779.jpg"
53
+ end
54
+
55
+ should "have a value for :url" do
56
+ @shop.url.should == "http://www.etsy.com/shop/littletjane"
57
+ end
58
+
59
+ should "have a value for :favorers_count" do
60
+ @shop.favorers_count.should == 684
53
61
  end
54
62
 
55
63
  should "have a value for :active_listings_count" do
@@ -86,12 +94,11 @@ module Etsy
86
94
  shop = Shop.new
87
95
  shop.stubs(:id).with().returns(1)
88
96
 
89
- Listing.stubs(:find_all_by_shop_id).with(1).returns('listings')
97
+ Listing.stubs(:find_all_by_shop_id).with(1, {}).returns('listings')
90
98
 
91
99
  shop.listings.should == 'listings'
92
100
  end
93
-
94
101
  end
95
102
 
96
103
  end
97
- end
104
+ end
@@ -0,0 +1,52 @@
1
+ require File.expand_path('../../../test_helper', __FILE__)
2
+
3
+ module Etsy
4
+ class TransactionTest < Test::Unit::TestCase
5
+
6
+ context "The Transaction class" do
7
+
8
+ should "be able to find transactions for a shop" do
9
+ transactions = mock_request('/shops/1/transactions', {'key' => 'value'}, 'Transaction', 'findAllShopTransactions.json')
10
+ Transaction.find_all_by_shop_id(1, {'key' => 'value'}).should == transactions
11
+ end
12
+
13
+ end
14
+
15
+ context "An instance of the Transaction class" do
16
+
17
+ context "with response data" do
18
+ setup do
19
+ data = read_fixture('transaction/findAllShopTransactions.json')
20
+ @transaction = Transaction.new(data.first)
21
+ end
22
+
23
+ should "have a value for :id" do
24
+ @transaction.id.should == 27230877
25
+ end
26
+
27
+ should "have a value for :quantity" do
28
+ @transaction.quantity.should == 1
29
+ end
30
+
31
+ should "have a value for :buyer_id" do
32
+ @transaction.buyer_id.should == 9641557
33
+ end
34
+
35
+ should "have a value for :listing_id" do
36
+ @transaction.listing_id.should == 41680579
37
+ end
38
+ end
39
+
40
+ should "know the buyer" do
41
+ User.stubs(:find).with(1).returns('user')
42
+
43
+ transaction = Transaction.new
44
+ transaction.stubs(:buyer_id).with().returns(1)
45
+
46
+ transaction.buyer.should == 'user'
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+ end
@@ -15,15 +15,42 @@ module Etsy
15
15
  User.find('littletjane', 'reagent').should == users
16
16
  end
17
17
 
18
- should "be able to find the current logged in user" do
19
- oauth_keys = {:access_token => 'token', :access_secret => 'secret'}
20
- users = mock_request('/users/__SELF__', oauth_keys, 'User', 'getUser.single.json')
21
- User.myself('token', 'secret').should == users.first
18
+ should "be able to pass options when finding a user" do
19
+ options = {:limit => 90, :offset => 90}
20
+ users = mock_request('/users/littletjane', options, 'User', 'getUser.single.json')
21
+ User.find('littletjane', options).should == users.first
22
+ end
23
+
24
+ should "be able to find the authenticated user" do
25
+ options = {:access_token => 'token', :access_secret => 'secret'}
26
+ users = mock_request('/users/__SELF__', options, 'User', 'getUser.single.json')
27
+ User.myself('token', 'secret', options).should == users.first
22
28
  end
23
29
  end
24
30
 
25
31
  context "An instance of the User class" do
26
32
 
33
+ context "requested with oauth access token" do
34
+ setup do
35
+ options = {:access_token => 'token', :access_secret => 'secret'}
36
+
37
+ data = read_fixture('user/getUser.single.json')
38
+ response = 'response'
39
+ response.stubs(:result).with().returns [data]
40
+ Request.stubs(:get).with('/users/__SELF__', options).returns response
41
+
42
+ @user = User.find('__SELF__', options)
43
+ end
44
+
45
+ should "persist the token" do
46
+ @user.token.should == 'token'
47
+ end
48
+
49
+ should "persist the secret" do
50
+ @user.secret.should == 'secret'
51
+ end
52
+ end
53
+
27
54
  context "with public response data" do
28
55
  setup do
29
56
  data = read_fixture('user/getUser.single.json')
@@ -50,7 +77,7 @@ module Etsy
50
77
  context "with private response data" do
51
78
  setup do
52
79
  data = read_fixture('user/getUser.single.private.json')
53
- @user = User.new(data.first)
80
+ @user = User.new(data.first, 'token', 'secret')
54
81
  end
55
82
 
56
83
  should "have an email address" do
@@ -58,6 +85,118 @@ module Etsy
58
85
  end
59
86
  end
60
87
 
88
+ context "requested with associated shops" do
89
+ setup do
90
+ data = read_fixture('user/getUser.single.withShops.json')
91
+ @user = User.new(data.first)
92
+ end
93
+
94
+ should "have shops" do
95
+ @user.shops.each do |shop|
96
+ shop.class.should == Shop
97
+ end
98
+ end
99
+
100
+ # This assumes for now that a user can have only one shop belonging to them
101
+ should "return the first shop belonging to the user" do
102
+ @user.shop.should == @user.shops.first
103
+ end
104
+ end
105
+
106
+ context "requested without associated shops" do
107
+ setup do
108
+ @data_without_shops = read_fixture('user/getUser.single.json')
109
+ @data_with_shops = read_fixture('user/getUser.single.withShops.json')
110
+ @options = {:fields => 'user_id', :includes => 'Shops'}
111
+
112
+ @user_without_shops = User.new(@data_without_shops.first)
113
+ @user_with_shops = User.new(@data_with_shops.first)
114
+ end
115
+
116
+ should "make a call to the API to retrieve it if requested" do
117
+ User.expects(:find).with('littletjane', @options).returns @user_with_shops
118
+ @user_without_shops.shops
119
+ end
120
+
121
+ should "not call the api twice" do
122
+ User.expects(:find).once.with('littletjane', @options).returns @user_with_shops
123
+ @user_without_shops.shops
124
+ @user_without_shops.shops
125
+ end
126
+
127
+ should "return a list of populated shop instances" do
128
+ User.stubs(:find).with('littletjane', @options).returns @user_with_shops
129
+ @user_without_shops.shops.first.name.should == 'LittleJane'
130
+ end
131
+
132
+ should "make the call with authentication if oauth is used" do
133
+ user = User.new(@data_without_shops.first, 'token', 'secret')
134
+ oauth = {:access_token => 'token', :access_secret => 'secret'}
135
+ User.expects(:find).with('littletjane', @options.merge(oauth)).returns @user_with_shops
136
+ user.shops
137
+ end
138
+ end
139
+
140
+ context "requested with an associated profile" do
141
+ setup do
142
+ data = read_fixture('user/getUser.single.withProfile.json')
143
+ @user = User.new(data.first)
144
+ end
145
+
146
+ should "have a profile" do
147
+ @user.profile.class.should == Profile
148
+ end
149
+ end
150
+
151
+ context "requested without an associated profile" do
152
+ setup do
153
+ @data_without_profile = read_fixture('user/getUser.single.json')
154
+ @data_with_profile = read_fixture('user/getUser.single.withProfile.json')
155
+ @options = {:fields => 'user_id', :includes => 'Profile'}
156
+
157
+ @user_without_profile = User.new(@data_without_profile.first)
158
+ @user_with_profile = User.new(@data_with_profile.first)
159
+ end
160
+
161
+ should "make a call to the API to retrieve it if requested" do
162
+ User.expects(:find).with('littletjane', @options).returns @user_with_profile
163
+ @user_without_profile.profile
164
+ end
165
+
166
+ should "not call the api twice" do
167
+ User.expects(:find).once.with('littletjane', @options).returns @user_with_profile
168
+ @user_without_profile.profile
169
+ @user_without_profile.profile
170
+ end
171
+
172
+ should "return a populated profile instance" do
173
+ User.stubs(:find).with('littletjane', @options).returns @user_with_profile
174
+ @user_without_profile.profile.bio.should == 'I make stuff'
175
+ end
176
+
177
+ should "make the call with authentication if oauth is used" do
178
+ user = User.new(@data_without_profile.first, 'token', 'secret')
179
+ oauth = {:access_token => 'token', :access_secret => 'secret'}
180
+ User.expects(:find).with('littletjane', @options.merge(oauth)).returns @user_with_profile
181
+ user.profile
182
+ end
183
+ end
184
+
185
+ context "instantiated with oauth token" do
186
+ setup do
187
+ @user = User.new(nil, 'token', 'secret')
188
+ end
189
+
190
+ should "have the token" do
191
+ @user.token.should == 'token'
192
+ end
193
+
194
+ should "have the secret" do
195
+ @user.secret.should == 'secret'
196
+ end
197
+
198
+ end
199
+
61
200
  should "know when the user was created" do
62
201
  user = User.new
63
202
  user.stubs(:created).returns(1)
@@ -66,13 +205,13 @@ module Etsy
66
205
  end
67
206
  end
68
207
 
69
- should "know the shop for a user" do
208
+ should "know the addresses for a user" do
70
209
  user = User.new
71
210
  user.stubs(:username).with().returns('username')
72
211
 
73
- Shop.stubs(:find).with('username').returns('shop')
212
+ Address.stubs(:find).with('username', {}).returns('addresses')
74
213
 
75
- user.shop.should == 'shop'
214
+ user.addresses.should == 'addresses'
76
215
  end
77
216
 
78
217
  end