duodealer_api 1.0.0

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 (322) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +13 -0
  4. data/.rubocop.yml +8 -0
  5. data/.travis.yml +23 -0
  6. data/Gemfile +5 -0
  7. data/Gemfile_ar41 +5 -0
  8. data/Gemfile_ar50 +5 -0
  9. data/Gemfile_ar51 +5 -0
  10. data/Gemfile_ar_master +5 -0
  11. data/RELEASING +13 -0
  12. data/Rakefile +44 -0
  13. data/docker-compose.yml +13 -0
  14. data/docs/graphql.md +191 -0
  15. data/duodealer_api.gemspec +38 -0
  16. data/lib/active_resource/connection_ext.rb +10 -0
  17. data/lib/active_resource/detailed_log_subscriber.rb +52 -0
  18. data/lib/active_resource/json_errors.rb +31 -0
  19. data/lib/duodealer_api.rb +33 -0
  20. data/lib/duodealer_api/api_version.rb +205 -0
  21. data/lib/duodealer_api/connection.rb +35 -0
  22. data/lib/duodealer_api/countable.rb +14 -0
  23. data/lib/duodealer_api/disable_prefix_check.rb +31 -0
  24. data/lib/duodealer_api/events.rb +7 -0
  25. data/lib/duodealer_api/graphql.rb +79 -0
  26. data/lib/duodealer_api/graphql/http_client.rb +22 -0
  27. data/lib/duodealer_api/graphql/railtie.rb +17 -0
  28. data/lib/duodealer_api/graphql/task.rake +97 -0
  29. data/lib/duodealer_api/limits.rb +76 -0
  30. data/lib/duodealer_api/message_enricher.rb +23 -0
  31. data/lib/duodealer_api/meta.rb +15 -0
  32. data/lib/duodealer_api/metafields.rb +20 -0
  33. data/lib/duodealer_api/paginated_collection.rb +69 -0
  34. data/lib/duodealer_api/pagination_link_headers.rb +33 -0
  35. data/lib/duodealer_api/resources.rb +3 -0
  36. data/lib/duodealer_api/resources/abandoned_checkout.rb +7 -0
  37. data/lib/duodealer_api/resources/access_scope.rb +10 -0
  38. data/lib/duodealer_api/resources/access_token.rb +8 -0
  39. data/lib/duodealer_api/resources/address.rb +4 -0
  40. data/lib/duodealer_api/resources/announcement.rb +4 -0
  41. data/lib/duodealer_api/resources/api_permission.rb +9 -0
  42. data/lib/duodealer_api/resources/application_charge.rb +15 -0
  43. data/lib/duodealer_api/resources/application_credit.rb +4 -0
  44. data/lib/duodealer_api/resources/array_base.rb +13 -0
  45. data/lib/duodealer_api/resources/article.rb +21 -0
  46. data/lib/duodealer_api/resources/asset.rb +100 -0
  47. data/lib/duodealer_api/resources/assigned_fulfillment_order.rb +16 -0
  48. data/lib/duodealer_api/resources/base.rb +162 -0
  49. data/lib/duodealer_api/resources/billing_address.rb +4 -0
  50. data/lib/duodealer_api/resources/blog.rb +10 -0
  51. data/lib/duodealer_api/resources/carrier_service.rb +4 -0
  52. data/lib/duodealer_api/resources/cart.rb +4 -0
  53. data/lib/duodealer_api/resources/checkout.rb +30 -0
  54. data/lib/duodealer_api/resources/collect.rb +6 -0
  55. data/lib/duodealer_api/resources/collection.rb +14 -0
  56. data/lib/duodealer_api/resources/collection_listing.rb +18 -0
  57. data/lib/duodealer_api/resources/collection_publication.rb +10 -0
  58. data/lib/duodealer_api/resources/comment.rb +9 -0
  59. data/lib/duodealer_api/resources/country.rb +4 -0
  60. data/lib/duodealer_api/resources/currency.rb +6 -0
  61. data/lib/duodealer_api/resources/custom_collection.rb +19 -0
  62. data/lib/duodealer_api/resources/customer.rb +29 -0
  63. data/lib/duodealer_api/resources/customer_group.rb +5 -0
  64. data/lib/duodealer_api/resources/customer_invite.rb +4 -0
  65. data/lib/duodealer_api/resources/customer_saved_search.rb +11 -0
  66. data/lib/duodealer_api/resources/discount_code.rb +9 -0
  67. data/lib/duodealer_api/resources/draft_order.rb +14 -0
  68. data/lib/duodealer_api/resources/draft_order_invoice.rb +4 -0
  69. data/lib/duodealer_api/resources/event.rb +8 -0
  70. data/lib/duodealer_api/resources/fulfillment.rb +47 -0
  71. data/lib/duodealer_api/resources/fulfillment_event.rb +15 -0
  72. data/lib/duodealer_api/resources/fulfillment_order.rb +137 -0
  73. data/lib/duodealer_api/resources/fulfillment_order_locations_for_move.rb +4 -0
  74. data/lib/duodealer_api/resources/fulfillment_request.rb +15 -0
  75. data/lib/duodealer_api/resources/fulfillment_service.rb +4 -0
  76. data/lib/duodealer_api/resources/fulfillment_v2.rb +20 -0
  77. data/lib/duodealer_api/resources/gift_card.rb +7 -0
  78. data/lib/duodealer_api/resources/image.rb +16 -0
  79. data/lib/duodealer_api/resources/inventory_item.rb +6 -0
  80. data/lib/duodealer_api/resources/inventory_level.rb +55 -0
  81. data/lib/duodealer_api/resources/line_item.rb +14 -0
  82. data/lib/duodealer_api/resources/location.rb +8 -0
  83. data/lib/duodealer_api/resources/marketing_event.rb +10 -0
  84. data/lib/duodealer_api/resources/metafield.rb +13 -0
  85. data/lib/duodealer_api/resources/note_attribute.rb +4 -0
  86. data/lib/duodealer_api/resources/option.rb +4 -0
  87. data/lib/duodealer_api/resources/order.rb +43 -0
  88. data/lib/duodealer_api/resources/order_risk.rb +8 -0
  89. data/lib/duodealer_api/resources/page.rb +6 -0
  90. data/lib/duodealer_api/resources/payment.rb +7 -0
  91. data/lib/duodealer_api/resources/payment_details.rb +4 -0
  92. data/lib/duodealer_api/resources/ping.rb +3 -0
  93. data/lib/duodealer_api/resources/policy.rb +7 -0
  94. data/lib/duodealer_api/resources/price_rule.rb +8 -0
  95. data/lib/duodealer_api/resources/product.rb +35 -0
  96. data/lib/duodealer_api/resources/product_listing.rb +16 -0
  97. data/lib/duodealer_api/resources/product_publication.rb +10 -0
  98. data/lib/duodealer_api/resources/province.rb +5 -0
  99. data/lib/duodealer_api/resources/publication.rb +5 -0
  100. data/lib/duodealer_api/resources/receipt.rb +4 -0
  101. data/lib/duodealer_api/resources/recurring_application_charge.rb +31 -0
  102. data/lib/duodealer_api/resources/redirect.rb +4 -0
  103. data/lib/duodealer_api/resources/refund.rb +14 -0
  104. data/lib/duodealer_api/resources/report.rb +4 -0
  105. data/lib/duodealer_api/resources/resource_feedback.rb +19 -0
  106. data/lib/duodealer_api/resources/rule.rb +4 -0
  107. data/lib/duodealer_api/resources/script_tag.rb +4 -0
  108. data/lib/duodealer_api/resources/shipping_address.rb +4 -0
  109. data/lib/duodealer_api/resources/shipping_line.rb +4 -0
  110. data/lib/duodealer_api/resources/shipping_rate.rb +7 -0
  111. data/lib/duodealer_api/resources/shipping_zone.rb +4 -0
  112. data/lib/duodealer_api/resources/shop.rb +25 -0
  113. data/lib/duodealer_api/resources/smart_collection.rb +19 -0
  114. data/lib/duodealer_api/resources/storefront_access_token.rb +4 -0
  115. data/lib/duodealer_api/resources/tax_line.rb +4 -0
  116. data/lib/duodealer_api/resources/tax_service.rb +4 -0
  117. data/lib/duodealer_api/resources/tender_transaction.rb +6 -0
  118. data/lib/duodealer_api/resources/theme.rb +4 -0
  119. data/lib/duodealer_api/resources/transaction.rb +5 -0
  120. data/lib/duodealer_api/resources/usage_charge.rb +5 -0
  121. data/lib/duodealer_api/resources/user.rb +4 -0
  122. data/lib/duodealer_api/resources/variant.rb +8 -0
  123. data/lib/duodealer_api/resources/webhook.rb +4 -0
  124. data/lib/duodealer_api/session.rb +171 -0
  125. data/lib/duodealer_api/version.rb +3 -0
  126. data/shipit.rubygems.yml +1 -0
  127. data/test/abandoned_checkouts_test.rb +29 -0
  128. data/test/access_scope_test.rb +23 -0
  129. data/test/access_token_test.rb +19 -0
  130. data/test/active_resource/json_errors_test.rb +19 -0
  131. data/test/api_permission_test.rb +9 -0
  132. data/test/api_version_test.rb +157 -0
  133. data/test/application_charge_test.rb +79 -0
  134. data/test/application_credit_test.rb +35 -0
  135. data/test/article_test.rb +73 -0
  136. data/test/asset_test.rb +18 -0
  137. data/test/assigned_fulfillment_order_test.rb +77 -0
  138. data/test/base_test.rb +198 -0
  139. data/test/blog_test.rb +8 -0
  140. data/test/carrier_service_test.rb +17 -0
  141. data/test/cart_test.rb +13 -0
  142. data/test/checkouts_test.rb +77 -0
  143. data/test/collect_test.rb +9 -0
  144. data/test/collection_listing_test.rb +79 -0
  145. data/test/collection_publication_test.rb +40 -0
  146. data/test/collection_test.rb +49 -0
  147. data/test/countable_test.rb +13 -0
  148. data/test/currency_test.rb +21 -0
  149. data/test/custom_collection_test.rb +9 -0
  150. data/test/customer_saved_search_test.rb +27 -0
  151. data/test/customer_test.rb +50 -0
  152. data/test/detailed_log_subscriber_test.rb +139 -0
  153. data/test/discount_code_test.rb +53 -0
  154. data/test/draft_order_test.rb +151 -0
  155. data/test/fixtures/abandoned_checkout.json +184 -0
  156. data/test/fixtures/abandoned_checkouts.json +186 -0
  157. data/test/fixtures/access_scopes.json +10 -0
  158. data/test/fixtures/access_token_delegate.json +4 -0
  159. data/test/fixtures/api_versions.json +38 -0
  160. data/test/fixtures/apis.json +42 -0
  161. data/test/fixtures/application_charge.json +16 -0
  162. data/test/fixtures/application_charges.json +57 -0
  163. data/test/fixtures/application_credit.json +12 -0
  164. data/test/fixtures/application_credits.json +24 -0
  165. data/test/fixtures/article.json +15 -0
  166. data/test/fixtures/articles.json +39 -0
  167. data/test/fixtures/asset.json +9 -0
  168. data/test/fixtures/assets.json +136 -0
  169. data/test/fixtures/assigned_fulfillment_orders.json +78 -0
  170. data/test/fixtures/authors.json +1 -0
  171. data/test/fixtures/blog.json +13 -0
  172. data/test/fixtures/blogs.json +13 -0
  173. data/test/fixtures/carrier_service.json +9 -0
  174. data/test/fixtures/carts.json +43 -0
  175. data/test/fixtures/checkout.json +160 -0
  176. data/test/fixtures/checkouts.json +162 -0
  177. data/test/fixtures/collect.json +12 -0
  178. data/test/fixtures/collection.json +17 -0
  179. data/test/fixtures/collection_listing.json +11 -0
  180. data/test/fixtures/collection_listing_product_ids.json +1 -0
  181. data/test/fixtures/collection_listing_product_ids2.json +1 -0
  182. data/test/fixtures/collection_listings.json +13 -0
  183. data/test/fixtures/collection_products.json +47 -0
  184. data/test/fixtures/collection_publication.json +11 -0
  185. data/test/fixtures/collection_publications.json +13 -0
  186. data/test/fixtures/currencies.json +25 -0
  187. data/test/fixtures/custom_collection.json +17 -0
  188. data/test/fixtures/customer_invite.json +9 -0
  189. data/test/fixtures/customer_saved_search.json +9 -0
  190. data/test/fixtures/customer_saved_search_customers.json +60 -0
  191. data/test/fixtures/customers.json +59 -0
  192. data/test/fixtures/customers_account_activation_url.json +3 -0
  193. data/test/fixtures/customers_search.json +60 -0
  194. data/test/fixtures/discount_code.json +10 -0
  195. data/test/fixtures/discount_codes.json +12 -0
  196. data/test/fixtures/draft_order.json +159 -0
  197. data/test/fixtures/draft_order_completed.json +159 -0
  198. data/test/fixtures/draft_order_invoice.json +9 -0
  199. data/test/fixtures/draft_orders.json +161 -0
  200. data/test/fixtures/engagement.json +15 -0
  201. data/test/fixtures/events.json +31 -0
  202. data/test/fixtures/fulfillment.json +49 -0
  203. data/test/fixtures/fulfillment_event.json +12 -0
  204. data/test/fixtures/fulfillment_order.json +38 -0
  205. data/test/fixtures/fulfillment_order_locations_for_move.json +18 -0
  206. data/test/fixtures/fulfillment_orders.json +78 -0
  207. data/test/fixtures/fulfillment_request.json +28 -0
  208. data/test/fixtures/fulfillment_service.json +10 -0
  209. data/test/fixtures/fulfillments.json +53 -0
  210. data/test/fixtures/gift_card.json +20 -0
  211. data/test/fixtures/gift_card_disabled.json +20 -0
  212. data/test/fixtures/graphql/2019-10.json +1083 -0
  213. data/test/fixtures/graphql/dummy_schema.rb +16 -0
  214. data/test/fixtures/graphql/unstable.json +1083 -0
  215. data/test/fixtures/image.json +10 -0
  216. data/test/fixtures/images.json +20 -0
  217. data/test/fixtures/inventory_level.json +7 -0
  218. data/test/fixtures/inventory_levels.json +24 -0
  219. data/test/fixtures/marketing_event.json +28 -0
  220. data/test/fixtures/marketing_events.json +54 -0
  221. data/test/fixtures/metafield.json +12 -0
  222. data/test/fixtures/metafields.json +34 -0
  223. data/test/fixtures/order.json +297 -0
  224. data/test/fixtures/order_risk.json +14 -0
  225. data/test/fixtures/order_risks.json +28 -0
  226. data/test/fixtures/order_with_properties.json +373 -0
  227. data/test/fixtures/orders.json +299 -0
  228. data/test/fixtures/payment.json +7 -0
  229. data/test/fixtures/payments.json +9 -0
  230. data/test/fixtures/ping/conversation.json +1 -0
  231. data/test/fixtures/ping/failed_delivery_confirmation.json +1 -0
  232. data/test/fixtures/ping/message.json +1 -0
  233. data/test/fixtures/ping/successful_delivery_confirmation.json +1 -0
  234. data/test/fixtures/policies.json +8 -0
  235. data/test/fixtures/price_rule.json +27 -0
  236. data/test/fixtures/price_rules.json +28 -0
  237. data/test/fixtures/product.json +116 -0
  238. data/test/fixtures/product_listing.json +86 -0
  239. data/test/fixtures/product_listing_product_ids.json +1 -0
  240. data/test/fixtures/product_listing_product_ids2.json +1 -0
  241. data/test/fixtures/product_listings.json +174 -0
  242. data/test/fixtures/product_publication.json +11 -0
  243. data/test/fixtures/product_publications.json +13 -0
  244. data/test/fixtures/publications.json +9 -0
  245. data/test/fixtures/recurring_application_charge.json +22 -0
  246. data/test/fixtures/recurring_application_charge_adjustment.json +5 -0
  247. data/test/fixtures/recurring_application_charges.json +106 -0
  248. data/test/fixtures/redirect.json +7 -0
  249. data/test/fixtures/refund.json +112 -0
  250. data/test/fixtures/report.json +9 -0
  251. data/test/fixtures/reports.json +11 -0
  252. data/test/fixtures/script_tag.json +10 -0
  253. data/test/fixtures/script_tags.json +18 -0
  254. data/test/fixtures/shipping_rates.json +12 -0
  255. data/test/fixtures/shipping_zones.json +315 -0
  256. data/test/fixtures/shop.json +26 -0
  257. data/test/fixtures/smart_collection.json +21 -0
  258. data/test/fixtures/smart_collection_products.json +155 -0
  259. data/test/fixtures/storefront_access_token.json +9 -0
  260. data/test/fixtures/storefront_access_tokens.json +18 -0
  261. data/test/fixtures/tags.json +1 -0
  262. data/test/fixtures/tax_service.json +9 -0
  263. data/test/fixtures/tender_transactions.json +52 -0
  264. data/test/fixtures/transaction.json +29 -0
  265. data/test/fixtures/usage_charge.json +11 -0
  266. data/test/fixtures/usage_charges.json +23 -0
  267. data/test/fixtures/user.json +21 -0
  268. data/test/fixtures/users.json +42 -0
  269. data/test/fixtures/variant.json +23 -0
  270. data/test/fixtures/variants.json +88 -0
  271. data/test/fixtures/webhook.json +10 -0
  272. data/test/fixtures/webhooks.json +18 -0
  273. data/test/fulfillment_event_test.rb +69 -0
  274. data/test/fulfillment_order_test.rb +462 -0
  275. data/test/fulfillment_order_test_helper.rb +7 -0
  276. data/test/fulfillment_request_test.rb +33 -0
  277. data/test/fulfillment_service_test.rb +17 -0
  278. data/test/fulfillment_test.rb +224 -0
  279. data/test/fulfillment_v2_test.rb +62 -0
  280. data/test/gift_card_test.rb +22 -0
  281. data/test/graphql/http_client_test.rb +26 -0
  282. data/test/graphql_test.rb +147 -0
  283. data/test/image_test.rb +39 -0
  284. data/test/inventory_level_test.rb +59 -0
  285. data/test/lib/webmock_extensions/last_request.rb +16 -0
  286. data/test/limits_test.rb +38 -0
  287. data/test/location_test.rb +14 -0
  288. data/test/marketing_event_test.rb +68 -0
  289. data/test/message_enricher_test.rb +45 -0
  290. data/test/meta_test.rb +49 -0
  291. data/test/metafield_test.rb +46 -0
  292. data/test/order_risk_test.rb +46 -0
  293. data/test/order_test.rb +125 -0
  294. data/test/pagination_test.rb +257 -0
  295. data/test/payment_test.rb +19 -0
  296. data/test/policy_test.rb +19 -0
  297. data/test/price_rule_test.rb +65 -0
  298. data/test/product_listing_test.rb +97 -0
  299. data/test/product_publication_test.rb +40 -0
  300. data/test/product_test.rb +60 -0
  301. data/test/publication_test.rb +12 -0
  302. data/test/recurring_application_charge_test.rb +142 -0
  303. data/test/redirect_test.rb +9 -0
  304. data/test/refund_test.rb +32 -0
  305. data/test/report_test.rb +35 -0
  306. data/test/resource_feedback_test.rb +42 -0
  307. data/test/script_tag_test.rb +30 -0
  308. data/test/session_test.rb +366 -0
  309. data/test/shipping_rate_test.rb +17 -0
  310. data/test/shipping_zone_test.rb +10 -0
  311. data/test/shop_test.rb +68 -0
  312. data/test/smart_collection_test.rb +35 -0
  313. data/test/storefront_access_token_test.rb +32 -0
  314. data/test/tax_service_test.rb +9 -0
  315. data/test/tender_transaction_test.rb +18 -0
  316. data/test/test_helper.rb +124 -0
  317. data/test/transaction_test.rb +17 -0
  318. data/test/usage_charge_test.rb +21 -0
  319. data/test/user_test.rb +17 -0
  320. data/test/variant_test.rb +46 -0
  321. data/test/webhook_test.rb +21 -0
  322. metadata +541 -0
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+ require 'test_helper'
3
+
4
+ class ProductPublicationTest < Test::Unit::TestCase
5
+ def test_get_all_product_publications
6
+ fake 'publications/55650051/product_publications', body: load_fixture('product_publications')
7
+ product_publications = DuodealerAPI::ProductPublication.find(:all, params: { publication_id: 55650051 })
8
+
9
+ assert_equal 647162527768, product_publications.first.id
10
+ assert_equal 55650051, product_publications.first.publication_id
11
+ end
12
+
13
+ def test_get_product_publication
14
+ fake 'publications/55650051/product_publications/647162527768', body: load_fixture('product_publication')
15
+ product_publication = DuodealerAPI::ProductPublication.find(647162527768, params: { publication_id: 55650051 })
16
+
17
+ assert_equal 647162527768, product_publication.id
18
+ assert_equal 55650051, product_publication.publication_id
19
+ end
20
+
21
+ def test_create_product_publication
22
+ fake 'publications/55650051/product_publications', method: :post, body: load_fixture('product_publication')
23
+ DuodealerAPI::ProductPublication.create(
24
+ publication_id: 55650051,
25
+ published_at: "2018-01-29T14:06:08-05:00",
26
+ published: true,
27
+ product_id: 8267093571
28
+ )
29
+
30
+ expected_body = {
31
+ product_publication: {
32
+ published_at: "2018-01-29T14:06:08-05:00",
33
+ published: true,
34
+ product_id: 8267093571,
35
+ },
36
+ }.to_json
37
+
38
+ assert_equal expected_body, WebMock.last_request.body
39
+ end
40
+ end
@@ -0,0 +1,60 @@
1
+ require 'test_helper'
2
+
3
+ class ProductTest < Test::Unit::TestCase
4
+ def setup
5
+ super
6
+
7
+ fake "products/632910392", :body => load_fixture('product')
8
+ @product = DuodealerAPI::Product.find(632910392)
9
+ end
10
+
11
+ def test_add_metafields_to_product
12
+ fake "products/632910392/metafields", :method => :post, :status => 201, :body => load_fixture('metafield')
13
+
14
+ field = @product.add_metafield(DuodealerAPI::Metafield.new(:namespace => "contact", :key => "email", :value => "123@example.com", :value_type => "string"))
15
+ assert_equal ActiveSupport::JSON.decode('{"metafield":{"namespace":"contact","key":"email","value":"123@example.com","value_type":"string"}}'), ActiveSupport::JSON.decode(WebMock.last_request.body)
16
+ assert !field.new_record?
17
+ assert_equal "contact", field.namespace
18
+ assert_equal "email", field.key
19
+ assert_equal "123@example.com", field.value
20
+ end
21
+
22
+ def test_get_all_metafields_for_product
23
+ fake "products/632910392/metafields", :body => load_fixture('metafields')
24
+
25
+ metafields = @product.metafields
26
+
27
+ assert_equal 3, metafields.length
28
+ assert metafields.all?{ |m| m.is_a? DuodealerAPI::Metafield }
29
+ end
30
+
31
+ def test_get_2_metafields_for_product
32
+ body = ActiveSupport::JSON.decode load_fixture 'metafields'
33
+ body['metafields'].slice! 2, 1
34
+
35
+ fake 'products/632910392/metafields.json?limit=2', body: body.to_json, extension: false
36
+
37
+ metafields = @product.metafields limit: 2
38
+
39
+ assert_equal 2, metafields.length
40
+ assert metafields.all?{ |m| m.is_a? DuodealerAPI::Metafield }
41
+ end
42
+
43
+ def test_update_loaded_variant
44
+ fake "products/632910392/variants/808950810", :method => :put, :status => 200, :body => load_fixture('variant')
45
+
46
+ variant = @product.variants.first
47
+ variant.price = "0.50"
48
+ variant.save
49
+ end
50
+
51
+ def test_price_range
52
+ assert_equal('199.00', @product.price_range)
53
+ end
54
+
55
+ def test_price_range_when_has_different_price
56
+ @product.variants[0].price = '100.00'
57
+
58
+ assert_equal('100.00 - 199.00', @product.price_range)
59
+ end
60
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ require 'test_helper'
3
+
4
+ class PublicationTest < Test::Unit::TestCase
5
+ def test_find_all_publications
6
+ fake 'publications'
7
+ publications = DuodealerAPI::Publication.find(:all)
8
+
9
+ assert_equal 55650051, publications.first.id
10
+ assert_equal "Buy Button", publications.first.name
11
+ end
12
+ end
@@ -0,0 +1,142 @@
1
+ require 'test_helper'
2
+
3
+ class RecurringApplicationChargeTest < Test::Unit::TestCase
4
+
5
+ def test_recurring_application_charges_create
6
+ fake "recurring_application_charges", method: :post, status: 201, body: load_fixture('recurring_application_charge')
7
+
8
+ charge = DuodealerAPI::RecurringApplicationCharge.create(
9
+ name: "Default Plan",
10
+ price: 10.0,
11
+ return_url: "http://test.com/confirm"
12
+ )
13
+
14
+ assert_equal 'http://apple.duodealer.com/admin/charges/654381177/confirm_recurring_application_charge?signature=BAhpBHkQASc%3D--419fc7424f8c290ac2b21b9004ed223e35b52164', charge.confirmation_url
15
+ end
16
+
17
+ def test_get_recurring_application_charges
18
+ fake "recurring_application_charges/654381177", method: :get, status: 201, body: load_fixture('recurring_application_charge')
19
+
20
+ charge = DuodealerAPI::RecurringApplicationCharge.find(654381177)
21
+
22
+ assert_equal "Super Duper Plan", charge.name
23
+ end
24
+
25
+ def test_list_recurring_application_charges
26
+ fake "recurring_application_charges", method: :get, status: 201, body: load_fixture('recurring_application_charges')
27
+
28
+ charge = DuodealerAPI::RecurringApplicationCharge.find(:all)
29
+
30
+ assert_equal "Super Mega Plan", charge.last.name
31
+ end
32
+
33
+ def test_list_since_recurring_application_charges
34
+ fake "recurring_application_charges.json?since_id=64512345",extension: false, method: :get, status: 201, body: load_fixture('recurring_application_charges')
35
+
36
+ charge = DuodealerAPI::RecurringApplicationCharge.find(:all, params: { since_id: '64512345' })
37
+
38
+ assert_equal "Super Mega Plan", charge.last.name
39
+ end
40
+
41
+ def test_list_fields_recurring_application_charges
42
+ fake "recurring_application_charges.json?fields=name",extension: false, method: :get, status: 201, body: load_fixture('recurring_application_charges')
43
+
44
+ charge = DuodealerAPI::RecurringApplicationCharge.find(:all, params: { fields: 'name' })
45
+
46
+ assert_equal "Super Mega Plan", charge.last.name
47
+ end
48
+
49
+ def test_pending_recurring_application_charge
50
+ fake "recurring_application_charges", method: :get, status: 201, body: load_fixture('recurring_application_charges')
51
+
52
+ charge = DuodealerAPI::RecurringApplicationCharge.pending
53
+
54
+ assert_equal "Super Mega Plan2", charge.last.name
55
+ end
56
+
57
+ def test_cancelled_recurring_application_charge
58
+ fake "recurring_application_charges", method: :get, status: 201, body: load_fixture('recurring_application_charges')
59
+
60
+ charge = DuodealerAPI::RecurringApplicationCharge.cancelled
61
+
62
+ assert_equal "Super Mega Plan3", charge.last.name
63
+ end
64
+
65
+ def test_accepted_recurring_application_charge
66
+ fake "recurring_application_charges", method: :get, status: 201, body: load_fixture('recurring_application_charges')
67
+
68
+ charge = DuodealerAPI::RecurringApplicationCharge.accepted
69
+
70
+ assert_equal "Super Mega Plan4", charge.first.name
71
+ assert_equal "Super Mega Plan", charge.last.name
72
+ end
73
+
74
+ def test_declined_recurring_application_charge
75
+ fake "recurring_application_charges", method: :get, status: 201, body: load_fixture('recurring_application_charges')
76
+
77
+ charge = DuodealerAPI::RecurringApplicationCharge.declined
78
+
79
+ assert_equal "Super Mega Plan5", charge.last.name
80
+ end
81
+
82
+ def test_activate_recurring_application_charge
83
+ fake "recurring_application_charges", method: :get, status: 201, body: load_fixture('recurring_application_charges')
84
+ fake "recurring_application_charges/455696199/activate", method: :post, status: 200, body: "{}"
85
+
86
+ charge = DuodealerAPI::RecurringApplicationCharge.accepted
87
+
88
+ assert charge.last.activate
89
+ end
90
+
91
+ def test_adjust_recurring_application_charge
92
+ fake "recurring_application_charges/654381177", method: :get, status: 201, body: load_fixture('recurring_application_charge')
93
+ fake "recurring_application_charges/654381177/customize.json?recurring_application_charge%5Bcapped_amount%5D=200", method: :put, body: load_fixture('recurring_application_charge_adjustment'), extension: false
94
+
95
+ charge = DuodealerAPI::RecurringApplicationCharge.find(654381177)
96
+
97
+ assert charge.customize(capped_amount: 200)
98
+ end
99
+
100
+ def test_cancel_recurring_application_charge
101
+ fake "recurring_application_charges", method: :get, status: 201, body: load_fixture('recurring_application_charges')
102
+ fake "recurring_application_charges/455696194", method: :delete, status: 200, body: "{}"
103
+
104
+ charge = DuodealerAPI::RecurringApplicationCharge.current
105
+ assert charge.cancel
106
+ end
107
+
108
+ def test_usage_charges_recurring_application_charge_found
109
+ fake "recurring_application_charges/654381177", method: :get, status: 201, body: load_fixture('recurring_application_charge')
110
+ fake "recurring_application_charges/654381177/usage_charges", method: :get, status: 201, body: load_fixture('usage_charges')
111
+
112
+ charge = DuodealerAPI::RecurringApplicationCharge.find(654381177)
113
+ usage_charges = charge.usage_charges
114
+
115
+ assert_equal 2, usage_charges.length
116
+ end
117
+
118
+ def test_usage_charges_recurring_application_charge_not_found
119
+ fake "recurring_application_charges/654381177", method: :get, status: 201, body: load_fixture('recurring_application_charge')
120
+ fake "recurring_application_charges/654381177/usage_charges", method: :get, status: 201, body: "[]"
121
+
122
+ charge = DuodealerAPI::RecurringApplicationCharge.find(654381177)
123
+ usage_charges = charge.usage_charges
124
+
125
+ assert_equal 0, usage_charges.length
126
+ end
127
+
128
+ def test_no_recurring_application_charge_found
129
+ fake "recurring_application_charges", body: {recurring_application_charges: []}.to_json
130
+
131
+ assert_equal 0, DuodealerAPI::RecurringApplicationCharge.all.count
132
+ assert_nil DuodealerAPI::RecurringApplicationCharge.current
133
+ assert_equal [], DuodealerAPI::RecurringApplicationCharge.pending
134
+ end
135
+
136
+ def test_recurring_application_charge_not_found_error
137
+ fake "recurring_application_charges", body: '{"errors":"Not Found"}', status: 404
138
+ assert_nil DuodealerAPI::RecurringApplicationCharge.all
139
+ assert_nil DuodealerAPI::RecurringApplicationCharge.current
140
+ assert_equal([], DuodealerAPI::RecurringApplicationCharge.pending)
141
+ end
142
+ end
@@ -0,0 +1,9 @@
1
+ require 'test_helper'
2
+
3
+ class RedirectTest < Test::Unit::TestCase
4
+ test "#create should create a redirect" do
5
+ fake "redirects", :method => :post, :status => 201, :body => load_fixture('redirect')
6
+ redirect = DuodealerAPI::Redirect.create(:path => "/ipod", :target => "/pages/itunes")
7
+ assert_equal 979034150, redirect.id
8
+ end
9
+ end
@@ -0,0 +1,32 @@
1
+ require 'test_helper'
2
+
3
+ class RefundTest < Test::Unit::TestCase
4
+
5
+ test '#create should create a refund' do
6
+ fake "orders/450789469/refunds", :method => :post, :status => 201, :body => load_fixture('refund')
7
+ refund = DuodealerAPI::Refund.create(
8
+ :order_id => 450789469,
9
+ :restock => true,
10
+ :note => "wrong size",
11
+ :shipping => { :full_refund => true },
12
+ :refund_line_items => [{ :line_item_id => 518995019, :quantity => 1 }]
13
+ )
14
+ assert_equal 703073504, refund.refund_line_items.first.line_item_id
15
+ end
16
+
17
+ test '#find should return a refund' do
18
+ fake "orders/450789469/refunds/509562969.json?order_id=450789469", :extension => false, :method => :get, :body => load_fixture('refund')
19
+ fake "orders/450789469/refunds/509562969", :method => :get, :body => load_fixture('refund')
20
+ refund = DuodealerAPI::Refund.find(509562969, :params => {:order_id => 450789469})
21
+ assert_equal 509562969, refund.id
22
+ end
23
+
24
+ test '#calculate a refund' do
25
+ fake "orders/450789469/refunds/calculate", :method => :post, :body => load_fixture('refund')
26
+ data = { :shipping => { :amount => 0 } }
27
+
28
+ refund = DuodealerAPI::Refund.calculate(data, :params => {:order_id => 450789469})
29
+ assert_equal 2, refund.refund_line_items.count
30
+ assert_equal 703073504, refund.refund_line_items.first.line_item_id
31
+ end
32
+ end
@@ -0,0 +1,35 @@
1
+ require 'test_helper'
2
+
3
+ class ReportTest < Test::Unit::TestCase
4
+ test 'get should get a report' do
5
+ fake 'reports/987', method: :get, status: 200, body: load_fixture('report')
6
+
7
+ report = DuodealerAPI::Report.find(987)
8
+ assert_equal 987, report.id
9
+ end
10
+
11
+ test 'get all should get all reports' do
12
+ fake 'reports', method: :get, status: 200, body: load_fixture('reports')
13
+
14
+ reports = DuodealerAPI::Report.all
15
+ assert_equal 'custom_app_reports', reports.first.category
16
+ end
17
+
18
+ test 'create should create a report' do
19
+ fake 'reports', method: :post, status: 201, body: load_fixture('report')
20
+
21
+ report = DuodealerAPI::Report.create(
22
+ name: 'Custom App Report',
23
+ duodealer_ql: 'SHOW quantity_count, total_sales BY product_type, vendor, product_title FROM products SINCE -1m UNTIL -0m ORDER BY total_sales DESC'
24
+ )
25
+ assert_equal 'custom_app_reports', report.category
26
+ end
27
+
28
+ test 'delete should delete report' do
29
+ fake 'reports/987', method: :get, status: 200, body: load_fixture('report')
30
+ fake 'reports/987', method: :delete, status: 200, body: '[]'
31
+
32
+ report = DuodealerAPI::Report.find(987)
33
+ assert report.destroy
34
+ end
35
+ end
@@ -0,0 +1,42 @@
1
+ class ResourceFeedbackTest < Test::Unit::TestCase
2
+ def test_get_resource_feedback
3
+ body = { resource_feedback: [ { resource_type: 'Shop' } ] }.to_json
4
+ fake 'resource_feedback', method: :get, body: body
5
+ resource_feedback = DuodealerAPI::ResourceFeedback.find(:all)
6
+ assert_equal 'Shop', resource_feedback.first.resource_type
7
+ end
8
+
9
+ def test_save_with_resource_feedback_endpoint
10
+ body = { resource_feedback: {} }.to_json
11
+ fake 'resource_feedback', method: :post, body: body
12
+ DuodealerAPI::ResourceFeedback.new.save
13
+ assert_request_body body
14
+ end
15
+
16
+ def test_get_resource_feedback_with_product_id
17
+ body = { resource_feedback: [ { resource_type: 'Product' } ] }.to_json
18
+ fake 'products/42/resource_feedback', method: :get, body: body
19
+ resource_feedback = DuodealerAPI::ResourceFeedback.find(:all, params: { product_id: 42 })
20
+ assert_equal 'Product', resource_feedback.first.resource_type
21
+ end
22
+
23
+ def test_save_with_product_id_resource_feedback_endpoint
24
+ body = { resource_feedback: {} }.to_json
25
+ fake 'products/42/resource_feedback', method: :post, body: body
26
+ DuodealerAPI::ResourceFeedback.new(product_id: 42).save
27
+ assert_request_body body
28
+ end
29
+
30
+ def test_save_raises_exception_when_already_persisted
31
+ body = { resource_feedback: {} }.to_json
32
+ fake 'resource_feedback', method: :post, body: body
33
+ resource_feedback = DuodealerAPI::ResourceFeedback.new
34
+ resource_feedback.save
35
+ assert_request_body body
36
+
37
+ DuodealerAPI::ResourceFeedback.any_instance.expects(:persisted?).returns(true)
38
+ assert_raises DuodealerAPI::ResourceFeedback::ExistingFeedbackSaved do
39
+ resource_feedback.save
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+
3
+ class ScriptTagTest < Test::Unit::TestCase
4
+ test "get all should get all script tags" do
5
+ fake 'script_tags', :method => :get, :status => 200, :body => load_fixture('script_tags')
6
+ script_tags = DuodealerAPI::ScriptTag.all
7
+ assert_equal "http://js-aplenty.com/bar.js", script_tags.first.src
8
+ end
9
+
10
+ test "get should get a script tag" do
11
+ fake 'script_tags/421379493', :method => :get, :status => 200, :body => load_fixture('script_tag')
12
+ script_tag = DuodealerAPI::ScriptTag.find(421379493)
13
+ assert_equal "http://js-aplenty.com/bar.js", script_tag.src
14
+ end
15
+
16
+ test "create should create a new script tag" do
17
+ fake 'script_tags', :method => :post, :status => 201, :body => load_fixture('script_tag')
18
+ script_tag = DuodealerAPI::ScriptTag.create(event: "onload", src: "http://js-aplenty.com/bar.js")
19
+ assert_equal "http://js-aplenty.com/bar.js", script_tag.src
20
+ end
21
+
22
+ test "editing script tag should update script tag" do
23
+ fake 'script_tags/421379493', :method => :get, :status => 200, :body => load_fixture('script_tag')
24
+ script_tag = DuodealerAPI::ScriptTag.find(421379493)
25
+ script_tag.src = "http://js-aplenty.com/bar.js"
26
+ fake 'script_tags/421379493', :method => :put, :status => 200, :body => load_fixture('script_tag')
27
+ script_tag.save
28
+ assert_equal "http://js-aplenty.com/bar.js", script_tag.src
29
+ end
30
+ end
@@ -0,0 +1,366 @@
1
+ require 'test_helper'
2
+ require 'timecop'
3
+
4
+ class SessionTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ super
8
+ DuodealerAPI::Session.secret = 'secret'
9
+ end
10
+
11
+ test "not be valid without a url" do
12
+ session = DuodealerAPI::Session.new(domain: nil, token: "any-token", api_version: any_api_version)
13
+ assert_not session.valid?
14
+ end
15
+
16
+ test "not be valid without token" do
17
+ session = DuodealerAPI::Session.new(domain: "testshop.duodealer.com", token: nil, api_version: any_api_version)
18
+ assert_not session.valid?
19
+ end
20
+
21
+ test "not be valid without an api version" do
22
+ session = DuodealerAPI::Session.new(domain: "testshop.duodealer.com", token: "any-token", api_version: nil)
23
+ assert_not session.valid?
24
+
25
+ session = DuodealerAPI::Session.new(domain: "testshop.duodealer.com", token: "any-token", api_version: DuodealerAPI::ApiVersion::NullVersion)
26
+ assert_not session.valid?
27
+ end
28
+
29
+ test "be valid with any token, any url and version" do
30
+ session = DuodealerAPI::Session.new(
31
+ domain: "testshop.duodealer.com",
32
+ token: "any-token",
33
+ api_version: any_api_version
34
+ )
35
+ assert session.valid?
36
+ end
37
+
38
+ test "not raise error without params" do
39
+ assert_nothing_raised do
40
+ DuodealerAPI::Session.new(domain: "testshop.duodealer.com", token: "any-token", api_version: any_api_version)
41
+ end
42
+ end
43
+
44
+ test "ignore everything but the subdomain in the shop" do
45
+ assert_equal(
46
+ "https://testshop.duodealer.com",
47
+ DuodealerAPI::Session.new(
48
+ domain: "http://user:pass@testshop.notduodealer.net/path",
49
+ token: "any-token",
50
+ api_version: any_api_version
51
+ ).site
52
+ )
53
+ end
54
+
55
+ test "append the duodealer domain if not given" do
56
+ assert_equal(
57
+ "https://testshop.duodealer.com",
58
+ DuodealerAPI::Session.new(domain: "testshop", token: "any-token", api_version: any_api_version).site
59
+ )
60
+ end
61
+
62
+ test "not raise error without params" do
63
+ assert_nothing_raised do
64
+ DuodealerAPI::Session.new(domain: "testshop.duodealer.com", token: "any-token", api_version: any_api_version)
65
+ end
66
+ end
67
+
68
+ test "raise error if params passed but signature omitted" do
69
+ assert_raises(DuodealerAPI::ValidationException) do
70
+ session = DuodealerAPI::Session.new(domain: "testshop.duodealer.com", token: nil, api_version: any_api_version)
71
+ session.request_token({'code' => 'any-code'})
72
+ end
73
+ end
74
+
75
+ test "setup api_key and secret for all sessions" do
76
+ DuodealerAPI::Session.setup(:api_key => "My test key", :secret => "My test secret")
77
+ assert_equal "My test key", DuodealerAPI::Session.api_key
78
+ assert_equal "My test secret", DuodealerAPI::Session.secret
79
+ end
80
+
81
+ test "#temp reset DuodealerAPI::Base.site to original value" do
82
+ session1 = DuodealerAPI::Session.new(domain: 'fakeshop.duodealer.com', token: 'token1', api_version: '2019-01')
83
+ DuodealerAPI::Base.activate_session(session1)
84
+
85
+ DuodealerAPI::Session.temp(domain: "testshop.duodealer.com", token: "any-token", api_version: :unstable) do
86
+ @assigned_site = DuodealerAPI::Base.site
87
+ @assigned_version = DuodealerAPI::Base.api_version
88
+ end
89
+
90
+ assert_equal('https://testshop.duodealer.com', @assigned_site.to_s)
91
+ assert_equal('https://fakeshop.duodealer.com', DuodealerAPI::Base.site.to_s)
92
+
93
+ assert_equal(DuodealerAPI::ApiVersion.new(handle: :unstable), @assigned_version)
94
+ assert_equal(DuodealerAPI::ApiVersion.new(handle: '2019-01'), DuodealerAPI::Base.api_version)
95
+ end
96
+
97
+ test "#with_session activates the session for the duration of the block" do
98
+ session1 = DuodealerAPI::Session.new(domain: 'fakeshop.duodealer.com', token: 'token1', api_version: '2019-01')
99
+ DuodealerAPI::Base.activate_session(session1)
100
+
101
+ other_session = DuodealerAPI::Session.new(
102
+ domain: "testshop.duodealer.com",
103
+ token: "any-token",
104
+ api_version: :unstable
105
+ )
106
+
107
+ DuodealerAPI::Session.with_session(other_session) do
108
+ @assigned_site = DuodealerAPI::Base.site
109
+ @assigned_version = DuodealerAPI::Base.api_version
110
+ end
111
+
112
+ assert_equal('https://testshop.duodealer.com', @assigned_site.to_s)
113
+ assert_equal('https://fakeshop.duodealer.com', DuodealerAPI::Base.site.to_s)
114
+
115
+ assert_equal(DuodealerAPI::ApiVersion.new(handle: :unstable), @assigned_version)
116
+ assert_equal(DuodealerAPI::ApiVersion.new(handle: '2019-01'), DuodealerAPI::Base.api_version)
117
+ end
118
+
119
+ test "#with_session resets the activated session even if there an exception during the block" do
120
+ session1 = DuodealerAPI::Session.new(domain: 'fakeshop.duodealer.com', token: 'token1', api_version: '2019-01')
121
+ DuodealerAPI::Base.activate_session(session1)
122
+
123
+ other_session = DuodealerAPI::Session.new(
124
+ domain: "testshop.duodealer.com",
125
+ token: "any-token",
126
+ api_version: :unstable
127
+ )
128
+
129
+ assert_raises StandardError do
130
+ DuodealerAPI::Session.with_session(other_session) { raise StandardError, "" }
131
+ end
132
+
133
+ assert_equal('https://fakeshop.duodealer.com', DuodealerAPI::Base.site.to_s)
134
+ assert_equal(DuodealerAPI::ApiVersion.new(handle: '2019-01'), DuodealerAPI::Base.api_version)
135
+ end
136
+
137
+ test "#with_version will adjust the actvated api version for the duration of the block" do
138
+ session1 = DuodealerAPI::Session.new(domain: 'fakeshop.duodealer.com', token: 'token1', api_version: '2019-01')
139
+ DuodealerAPI::Base.activate_session(session1)
140
+
141
+ DuodealerAPI::Session.with_version(:unstable) do
142
+ @assigned_site = DuodealerAPI::Base.site
143
+ @assigned_version = DuodealerAPI::Base.api_version
144
+ end
145
+
146
+ assert_equal('https://fakeshop.duodealer.com', @assigned_site.to_s)
147
+ assert_equal('https://fakeshop.duodealer.com', DuodealerAPI::Base.site.to_s)
148
+
149
+ assert_equal(DuodealerAPI::ApiVersion.new(handle: :unstable), @assigned_version)
150
+ assert_equal(DuodealerAPI::ApiVersion.new(handle: '2019-01'), DuodealerAPI::Base.api_version)
151
+ end
152
+
153
+ test "create_permission_url requires redirect_uri" do
154
+ DuodealerAPI::Session.setup(api_key: "My_test_key", secret: "My test secret")
155
+ session = DuodealerAPI::Session.new(
156
+ domain: 'http://localhost.duodealer.com',
157
+ token: 'any-token',
158
+ api_version: any_api_version
159
+ )
160
+ scope = ["write_products"]
161
+ assert_raises(ArgumentError) do
162
+ session.create_permission_url(scope)
163
+ end
164
+ end
165
+
166
+ test "create_permission_url returns correct url with single scope and redirect uri" do
167
+ DuodealerAPI::Session.setup(api_key: "My_test_key", secret: "My test secret")
168
+ session = DuodealerAPI::Session.new(
169
+ domain: 'http://localhost.duodealer.com',
170
+ token: 'any-token',
171
+ api_version: any_api_version
172
+ )
173
+ scope = ["write_products"]
174
+ permission_url = session.create_permission_url(scope, "http://my_redirect_uri.com")
175
+ assert_equal "https://localhost.duodealer.com/admin/oauth/authorize?client_id=My_test_key&scope=write_products&redirect_uri=http://my_redirect_uri.com", permission_url
176
+ end
177
+
178
+ test "create_permission_url returns correct url with dual scope" do
179
+ DuodealerAPI::Session.setup(api_key: "My_test_key", secret: "My test secret")
180
+ session = DuodealerAPI::Session.new(
181
+ domain: 'http://localhost.duodealer.com',
182
+ token: 'any-token',
183
+ api_version: any_api_version
184
+ )
185
+ scope = ["write_products","write_customers"]
186
+ permission_url = session.create_permission_url(scope, "http://my_redirect_uri.com")
187
+ assert_equal "https://localhost.duodealer.com/admin/oauth/authorize?client_id=My_test_key&scope=write_products,write_customers&redirect_uri=http://my_redirect_uri.com", permission_url
188
+ end
189
+
190
+ test "create_permission_url returns correct url with no scope" do
191
+ DuodealerAPI::Session.setup(api_key: "My_test_key", secret: "My test secret")
192
+ session = DuodealerAPI::Session.new(
193
+ domain: 'http://localhost.duodealer.com',
194
+ token: 'any-token',
195
+ api_version: any_api_version
196
+ )
197
+ scope = []
198
+ permission_url = session.create_permission_url(scope, "http://my_redirect_uri.com")
199
+ assert_equal "https://localhost.duodealer.com/admin/oauth/authorize?client_id=My_test_key&scope=&redirect_uri=http://my_redirect_uri.com", permission_url
200
+ end
201
+
202
+ test "create_permission_url returns correct url with state" do
203
+ DuodealerAPI::Session.setup(api_key: "My_test_key", secret: "My test secret")
204
+ session = DuodealerAPI::Session.new(
205
+ domain: 'http://localhost.duodealer.com',
206
+ token: 'any-token',
207
+ api_version: any_api_version
208
+ )
209
+ scope = []
210
+ permission_url = session.create_permission_url(scope, "http://my_redirect_uri.com", state: "My nonce")
211
+ assert_equal "https://localhost.duodealer.com/admin/oauth/authorize?client_id=My_test_key&scope=&redirect_uri=http://my_redirect_uri.com&state=My%20nonce", permission_url
212
+ end
213
+
214
+ test "raise exception if code invalid in request token" do
215
+ DuodealerAPI::Session.setup(:api_key => "My test key", :secret => "My test secret")
216
+ session = DuodealerAPI::Session.new(
217
+ domain: 'http://localhost.duodealer.com',
218
+ token: nil,
219
+ api_version: any_api_version
220
+ )
221
+ fake(
222
+ nil,
223
+ url: 'https://localhost.duodealer.com/admin/oauth/access_token',
224
+ method: :post,
225
+ status: 404,
226
+ body: '{"error" : "invalid_request"}'
227
+ )
228
+ assert_raises(DuodealerAPI::ValidationException) do
229
+ session.request_token(code: "bad-code")
230
+ end
231
+ assert_equal false, session.valid?
232
+ end
233
+
234
+ test "return site for session" do
235
+ session = DuodealerAPI::Session.new(
236
+ domain: "testshop.duodealer.com",
237
+ token: "any-token",
238
+ api_version: any_api_version
239
+ )
240
+ assert_equal "https://testshop.duodealer.com", session.site
241
+ end
242
+
243
+ test "return_token_if_signature_is_valid" do
244
+ api_version = any_api_version
245
+ fake nil,
246
+ url: "https://testshop.duodealer.com/admin/oauth/access_token",
247
+ method: :post,
248
+ body: '{"access_token":"any-token"}'
249
+ session = DuodealerAPI::Session.new(domain: "testshop.duodealer.com", token: nil, api_version: api_version)
250
+
251
+ params = { code: 'any-code', timestamp: Time.now }
252
+ token = session.request_token(params.merge(hmac: generate_signature(params)))
253
+
254
+ assert_equal "any-token", token
255
+ assert_equal "any-token", session.token
256
+ end
257
+
258
+ test "extra parameters are stored in session" do
259
+ api_version = DuodealerAPI::ApiVersion.new(handle: :unstable)
260
+ fake nil,
261
+ url: "https://testshop.duodealer.com/admin/oauth/access_token",
262
+ method: :post,
263
+ body: '{"access_token":"any-token","foo":"example"}'
264
+ session = DuodealerAPI::Session.new(domain: "testshop.duodealer.com", token: nil, api_version: api_version)
265
+
266
+ params = { code: 'any-code', timestamp: Time.now }
267
+ assert session.request_token(params.merge(hmac: generate_signature(params)))
268
+
269
+ assert_equal ({ "foo" => "example" }), session.extra
270
+ end
271
+
272
+ test "expires_in is automatically converted in expires_at" do
273
+ api_version = any_api_version
274
+ fake nil,
275
+ url: "https://testshop.duodealer.com/admin/oauth/access_token",
276
+ method: :post,
277
+ body: '{"access_token":"any-token","expires_in":86393}'
278
+ session = DuodealerAPI::Session.new(domain: "testshop.duodealer.com", token: nil, api_version: api_version)
279
+
280
+ Timecop.freeze do
281
+ params = { code: 'any-code', timestamp: Time.now }
282
+ assert session.request_token(params.merge(hmac: generate_signature(params)))
283
+
284
+ expires_at = Time.now.utc + 86393
285
+ assert_equal ({ "expires_at" => expires_at.to_i }), session.extra
286
+ assert session.expires_at.is_a?(Time)
287
+ assert_equal expires_at.to_i, session.expires_at.to_i
288
+ assert_equal 86393, session.expires_in
289
+ assert_equal false, session.expired?
290
+
291
+ Timecop.travel(session.expires_at) do
292
+ assert_equal true, session.expired?
293
+ end
294
+ end
295
+ end
296
+
297
+ test "raise error if signature does not match expected" do
298
+ params = {:code => "any-code", :timestamp => Time.now}
299
+ signature = generate_signature(params)
300
+ params[:foo] = 'world'
301
+ assert_raises(DuodealerAPI::ValidationException) do
302
+ session = DuodealerAPI::Session.new(domain: "testshop.duodealer.com", token: nil, api_version: any_api_version)
303
+ session.request_token(params.merge(:hmac => signature))
304
+ end
305
+ end
306
+
307
+ test "raise error if timestamp is too old" do
308
+ params = {:code => "any-code", :timestamp => Time.now - 2.days}
309
+ signature = generate_signature(params)
310
+ params[:foo] = 'world'
311
+ assert_raises(DuodealerAPI::ValidationException) do
312
+ session = DuodealerAPI::Session.new(domain: "testshop.duodealer.com", token: nil, api_version: any_api_version)
313
+ session.request_token(params.merge(:hmac => signature))
314
+ end
315
+ end
316
+
317
+ test "return true when the signature is valid and the keys of params are strings" do
318
+ params = { 'code' => 'any-code', 'timestamp' => Time.now }
319
+ params[:hmac] = generate_signature(params)
320
+ assert_equal true, DuodealerAPI::Session.validate_signature(params)
321
+ end
322
+
323
+ test "return true when validating signature of params with ampersand and equal sign characters" do
324
+ DuodealerAPI::Session.secret = 'secret'
325
+ params = { 'a' => '1&b=2', 'c=3&d' => '4' }
326
+ to_sign = 'a=1%26b=2&c%3D3%26d=4'
327
+ params[:hmac] = generate_signature(to_sign)
328
+ assert_equal true, DuodealerAPI::Session.validate_signature(params)
329
+ end
330
+
331
+ test "return true when validating signature of params with percent sign characters" do
332
+ DuodealerAPI::Session.secret = 'secret'
333
+ params = { 'a%3D1%26b' => '2%26c%3D3' }
334
+ to_sign = 'a%253D1%2526b=2%2526c%253D3'
335
+ params[:hmac] = generate_signature(to_sign)
336
+ assert_equal true, DuodealerAPI::Session.validate_signature(params)
337
+ end
338
+
339
+ test "url is aliased to domain to minimize the upgrade changes" do
340
+ session = DuodealerAPI::Session.new(
341
+ domain: "http://testshop.duodealer.com",
342
+ token: "any-token",
343
+ api_version: any_api_version
344
+ )
345
+
346
+ assert_equal('testshop.duodealer.com', session.url)
347
+ end
348
+
349
+ private
350
+
351
+ def make_sorted_params(params)
352
+ params.with_indifferent_access.except(
353
+ :signature, :hmac, :action, :controller
354
+ ).collect { |k, v| "#{k}=#{v}" }.sort.join('&')
355
+ end
356
+
357
+ def generate_signature(params)
358
+ params = make_sorted_params(params) if params.is_a?(Hash)
359
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, DuodealerAPI::Session.secret, params)
360
+ end
361
+
362
+ def any_api_version
363
+ version_name = ['2019-01', :unstable].sample(1).first
364
+ DuodealerAPI::ApiVersion.find_version(version_name)
365
+ end
366
+ end