tailored-etsy 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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