dhs 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 (301) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/rubocop.yml +27 -0
  3. data/.github/workflows/test.yml +27 -0
  4. data/.gitignore +39 -0
  5. data/.rubocop.yml +186 -0
  6. data/.ruby-version +1 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE +674 -0
  9. data/README.md +2807 -0
  10. data/Rakefile +26 -0
  11. data/dhs.gemspec +44 -0
  12. data/docs/accessing-data.png +0 -0
  13. data/lib/dhs.rb +67 -0
  14. data/lib/dhs/collection.rb +84 -0
  15. data/lib/dhs/complex.rb +158 -0
  16. data/lib/dhs/concerns/autoload_records.rb +57 -0
  17. data/lib/dhs/concerns/collection/handle_nested.rb +43 -0
  18. data/lib/dhs/concerns/collection/internal_collection.rb +74 -0
  19. data/lib/dhs/concerns/configuration.rb +20 -0
  20. data/lib/dhs/concerns/data/becomes.rb +18 -0
  21. data/lib/dhs/concerns/data/equality.rb +14 -0
  22. data/lib/dhs/concerns/data/extend.rb +87 -0
  23. data/lib/dhs/concerns/data/json.rb +14 -0
  24. data/lib/dhs/concerns/data/to_hash.rb +14 -0
  25. data/lib/dhs/concerns/inspect.rb +70 -0
  26. data/lib/dhs/concerns/is_href.rb +15 -0
  27. data/lib/dhs/concerns/item/destroy.rb +38 -0
  28. data/lib/dhs/concerns/item/endpoint_lookup.rb +27 -0
  29. data/lib/dhs/concerns/item/save.rb +55 -0
  30. data/lib/dhs/concerns/item/update.rb +50 -0
  31. data/lib/dhs/concerns/item/validation.rb +61 -0
  32. data/lib/dhs/concerns/o_auth.rb +25 -0
  33. data/lib/dhs/concerns/option_blocks.rb +26 -0
  34. data/lib/dhs/concerns/proxy/accessors.rb +132 -0
  35. data/lib/dhs/concerns/proxy/create.rb +45 -0
  36. data/lib/dhs/concerns/proxy/link.rb +25 -0
  37. data/lib/dhs/concerns/proxy/problems.rb +27 -0
  38. data/lib/dhs/concerns/record/attribute_assignment.rb +25 -0
  39. data/lib/dhs/concerns/record/batch.rb +40 -0
  40. data/lib/dhs/concerns/record/chainable.rb +465 -0
  41. data/lib/dhs/concerns/record/configuration.rb +103 -0
  42. data/lib/dhs/concerns/record/create.rb +24 -0
  43. data/lib/dhs/concerns/record/custom_setters.rb +22 -0
  44. data/lib/dhs/concerns/record/destroy.rb +18 -0
  45. data/lib/dhs/concerns/record/endpoints.rb +108 -0
  46. data/lib/dhs/concerns/record/equality.rb +14 -0
  47. data/lib/dhs/concerns/record/find.rb +86 -0
  48. data/lib/dhs/concerns/record/find_by.rb +38 -0
  49. data/lib/dhs/concerns/record/first.rb +20 -0
  50. data/lib/dhs/concerns/record/href_for.rb +19 -0
  51. data/lib/dhs/concerns/record/last.rb +27 -0
  52. data/lib/dhs/concerns/record/mapping.rb +25 -0
  53. data/lib/dhs/concerns/record/merge.rb +26 -0
  54. data/lib/dhs/concerns/record/model.rb +23 -0
  55. data/lib/dhs/concerns/record/pagination.rb +49 -0
  56. data/lib/dhs/concerns/record/provider.rb +23 -0
  57. data/lib/dhs/concerns/record/relations.rb +26 -0
  58. data/lib/dhs/concerns/record/request.rb +581 -0
  59. data/lib/dhs/concerns/record/scope.rb +25 -0
  60. data/lib/dhs/concerns/record/tracing.rb +24 -0
  61. data/lib/dhs/concerns/record/update.rb +17 -0
  62. data/lib/dhs/config.rb +24 -0
  63. data/lib/dhs/data.rb +180 -0
  64. data/lib/dhs/endpoint.rb +12 -0
  65. data/lib/dhs/interceptors/auto_oauth/interceptor.rb +33 -0
  66. data/lib/dhs/interceptors/auto_oauth/thread_registry.rb +18 -0
  67. data/lib/dhs/interceptors/extended_rollbar/handler.rb +40 -0
  68. data/lib/dhs/interceptors/extended_rollbar/interceptor.rb +20 -0
  69. data/lib/dhs/interceptors/extended_rollbar/thread_registry.rb +19 -0
  70. data/lib/dhs/interceptors/request_cycle_cache/interceptor.rb +41 -0
  71. data/lib/dhs/interceptors/request_cycle_cache/thread_registry.rb +18 -0
  72. data/lib/dhs/item.rb +59 -0
  73. data/lib/dhs/pagination/base.rb +90 -0
  74. data/lib/dhs/pagination/link.rb +21 -0
  75. data/lib/dhs/pagination/offset.rb +22 -0
  76. data/lib/dhs/pagination/page.rb +18 -0
  77. data/lib/dhs/pagination/start.rb +22 -0
  78. data/lib/dhs/pagination/total_pages.rb +9 -0
  79. data/lib/dhs/problems/base.rb +113 -0
  80. data/lib/dhs/problems/errors.rb +69 -0
  81. data/lib/dhs/problems/nested/base.rb +54 -0
  82. data/lib/dhs/problems/nested/errors.rb +16 -0
  83. data/lib/dhs/problems/nested/warnings.rb +15 -0
  84. data/lib/dhs/problems/warnings.rb +24 -0
  85. data/lib/dhs/proxy.rb +69 -0
  86. data/lib/dhs/railtie.rb +34 -0
  87. data/lib/dhs/record.rb +112 -0
  88. data/lib/dhs/rspec.rb +10 -0
  89. data/lib/dhs/test/stubbable_records.rb +34 -0
  90. data/lib/dhs/unprocessable.rb +6 -0
  91. data/lib/dhs/version.rb +5 -0
  92. data/script/ci/build.sh +18 -0
  93. data/spec/auto_oauth_spec.rb +163 -0
  94. data/spec/autoloading_spec.rb +45 -0
  95. data/spec/collection/accessors_spec.rb +31 -0
  96. data/spec/collection/collection_items_spec.rb +44 -0
  97. data/spec/collection/configurable_spec.rb +43 -0
  98. data/spec/collection/delegate_spec.rb +21 -0
  99. data/spec/collection/enumerable_spec.rb +27 -0
  100. data/spec/collection/href_spec.rb +17 -0
  101. data/spec/collection/meta_data_spec.rb +58 -0
  102. data/spec/collection/respond_to_spec.rb +20 -0
  103. data/spec/collection/to_a_spec.rb +34 -0
  104. data/spec/collection/to_ary_spec.rb +40 -0
  105. data/spec/collection/without_object_items_spec.rb +27 -0
  106. data/spec/complex/reduce_spec.rb +202 -0
  107. data/spec/concerns/record/request_spec.rb +78 -0
  108. data/spec/data/collection_spec.rb +56 -0
  109. data/spec/data/equality_spec.rb +23 -0
  110. data/spec/data/inspect_spec.rb +88 -0
  111. data/spec/data/is_item_or_collection_spec.rb +40 -0
  112. data/spec/data/item_spec.rb +106 -0
  113. data/spec/data/merge_spec.rb +27 -0
  114. data/spec/data/parent_spec.rb +39 -0
  115. data/spec/data/raw_spec.rb +48 -0
  116. data/spec/data/respond_to_spec.rb +26 -0
  117. data/spec/data/root_spec.rb +25 -0
  118. data/spec/data/select_spec.rb +27 -0
  119. data/spec/data/to_ary_spec.rb +28 -0
  120. data/spec/data/to_json_spec.rb +68 -0
  121. data/spec/dummy/Rakefile +8 -0
  122. data/spec/dummy/app/assets/images/.keep +0 -0
  123. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  124. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  125. data/spec/dummy/app/controllers/application_controller.rb +26 -0
  126. data/spec/dummy/app/controllers/automatic_authentication_controller.rb +29 -0
  127. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  128. data/spec/dummy/app/controllers/error_handling_with_chains_controller.rb +36 -0
  129. data/spec/dummy/app/controllers/extended_rollbar_controller.rb +10 -0
  130. data/spec/dummy/app/controllers/option_blocks_controller.rb +15 -0
  131. data/spec/dummy/app/controllers/request_cycle_cache_controller.rb +27 -0
  132. data/spec/dummy/app/helpers/application_helper.rb +4 -0
  133. data/spec/dummy/app/mailers/.keep +0 -0
  134. data/spec/dummy/app/models/.keep +0 -0
  135. data/spec/dummy/app/models/concerns/.keep +0 -0
  136. data/spec/dummy/app/models/concerns/dummy_customer/some_concern.rb +9 -0
  137. data/spec/dummy/app/models/dummy_customer.rb +7 -0
  138. data/spec/dummy/app/models/dummy_record.rb +6 -0
  139. data/spec/dummy/app/models/dummy_record_with_auto_oauth_provider.rb +6 -0
  140. data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers1.rb +7 -0
  141. data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers2.rb +7 -0
  142. data/spec/dummy/app/models/dummy_record_with_multiple_providers_per_endpoint.rb +6 -0
  143. data/spec/dummy/app/models/dummy_record_with_oauth.rb +7 -0
  144. data/spec/dummy/app/models/dummy_user.rb +6 -0
  145. data/spec/dummy/app/models/providers/customer_system.rb +7 -0
  146. data/spec/dummy/app/models/providers/internal_services.rb +7 -0
  147. data/spec/dummy/app/views/error_handling_with_chains/error.html.erb +1 -0
  148. data/spec/dummy/app/views/error_handling_with_chains/show.html.erb +3 -0
  149. data/spec/dummy/app/views/form_for.html.erb +5 -0
  150. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  151. data/spec/dummy/bin/bundle +5 -0
  152. data/spec/dummy/bin/rails +6 -0
  153. data/spec/dummy/bin/rake +6 -0
  154. data/spec/dummy/config.ru +6 -0
  155. data/spec/dummy/config/application.rb +16 -0
  156. data/spec/dummy/config/boot.rb +7 -0
  157. data/spec/dummy/config/environment.rb +7 -0
  158. data/spec/dummy/config/environments/development.rb +36 -0
  159. data/spec/dummy/config/environments/production.rb +77 -0
  160. data/spec/dummy/config/environments/test.rb +40 -0
  161. data/spec/dummy/config/initializers/assets.rb +10 -0
  162. data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
  163. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  164. data/spec/dummy/config/initializers/dhs.rb +5 -0
  165. data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  166. data/spec/dummy/config/initializers/inflections.rb +18 -0
  167. data/spec/dummy/config/initializers/mime_types.rb +6 -0
  168. data/spec/dummy/config/initializers/rollbar.rb +9 -0
  169. data/spec/dummy/config/initializers/session_store.rb +5 -0
  170. data/spec/dummy/config/initializers/wrap_parameters.rb +11 -0
  171. data/spec/dummy/config/locales/en.yml +23 -0
  172. data/spec/dummy/config/routes.rb +27 -0
  173. data/spec/dummy/config/secrets.yml +22 -0
  174. data/spec/dummy/lib/assets/.keep +0 -0
  175. data/spec/dummy/public/404.html +67 -0
  176. data/spec/dummy/public/422.html +67 -0
  177. data/spec/dummy/public/500.html +66 -0
  178. data/spec/dummy/public/favicon.ico +0 -0
  179. data/spec/endpoint/for_url_spec.rb +27 -0
  180. data/spec/extended_rollbar_spec.rb +67 -0
  181. data/spec/item/access_errors_spec.rb +31 -0
  182. data/spec/item/accessors_spec.rb +21 -0
  183. data/spec/item/add_error_spec.rb +21 -0
  184. data/spec/item/becomes_spec.rb +38 -0
  185. data/spec/item/blacklisted_keywords_spec.rb +28 -0
  186. data/spec/item/delegate_spec.rb +32 -0
  187. data/spec/item/destroy_spec.rb +113 -0
  188. data/spec/item/dig_spec.rb +29 -0
  189. data/spec/item/error_codes_spec.rb +55 -0
  190. data/spec/item/errors_spec.rb +324 -0
  191. data/spec/item/fetch_spec.rb +39 -0
  192. data/spec/item/getter_spec.rb +24 -0
  193. data/spec/item/internal_data_structure_spec.rb +37 -0
  194. data/spec/item/map_spec.rb +46 -0
  195. data/spec/item/nested_errors_spec.rb +27 -0
  196. data/spec/item/partial_update_spec.rb +168 -0
  197. data/spec/item/respond_to_spec.rb +31 -0
  198. data/spec/item/save_spec.rb +115 -0
  199. data/spec/item/setter_spec.rb +44 -0
  200. data/spec/item/translate_errors_spec.rb +257 -0
  201. data/spec/item/update_spec.rb +161 -0
  202. data/spec/item/validation_spec.rb +131 -0
  203. data/spec/item/warning_codes_spec.rb +55 -0
  204. data/spec/item/warnings_spec.rb +51 -0
  205. data/spec/option_blocks/ensure_reset_between_requests_spec.rb +23 -0
  206. data/spec/option_blocks/main_spec.rb +54 -0
  207. data/spec/pagination/link/current_page_spec.rb +19 -0
  208. data/spec/pagination/link/pages_left_spec.rb +36 -0
  209. data/spec/pagination/link/parallel_spec.rb +19 -0
  210. data/spec/pagination/link/total_spec.rb +45 -0
  211. data/spec/pagination/offset/pages_left_spec.rb +26 -0
  212. data/spec/pagination/parameters_spec.rb +59 -0
  213. data/spec/pagination/total_pages_spec.rb +51 -0
  214. data/spec/proxy/create_sub_resource_spec.rb +182 -0
  215. data/spec/proxy/load_spec.rb +75 -0
  216. data/spec/proxy/record_identification_spec.rb +35 -0
  217. data/spec/rails_helper.rb +13 -0
  218. data/spec/record/all_spec.rb +133 -0
  219. data/spec/record/attribute_assignment_spec.rb +28 -0
  220. data/spec/record/build_spec.rb +26 -0
  221. data/spec/record/cast_nested_data_spec.rb +80 -0
  222. data/spec/record/compact_spec.rb +93 -0
  223. data/spec/record/create_spec.rb +160 -0
  224. data/spec/record/creation_failed_spec.rb +55 -0
  225. data/spec/record/custom_setters_spec.rb +42 -0
  226. data/spec/record/definitions_spec.rb +29 -0
  227. data/spec/record/destroy_spec.rb +38 -0
  228. data/spec/record/dig_configuration_spec.rb +75 -0
  229. data/spec/record/dup_spec.rb +20 -0
  230. data/spec/record/endpoint_inheritance_spec.rb +65 -0
  231. data/spec/record/endpoint_options_spec.rb +51 -0
  232. data/spec/record/endpoint_priorities_spec.rb +24 -0
  233. data/spec/record/endpoints_spec.rb +96 -0
  234. data/spec/record/equality_spec.rb +27 -0
  235. data/spec/record/error_handling_integration_spec.rb +25 -0
  236. data/spec/record/error_handling_spec.rb +40 -0
  237. data/spec/record/expanded_spec.rb +69 -0
  238. data/spec/record/fetch_spec.rb +40 -0
  239. data/spec/record/find_by_chains_spec.rb +21 -0
  240. data/spec/record/find_by_spec.rb +76 -0
  241. data/spec/record/find_each_spec.rb +57 -0
  242. data/spec/record/find_in_batches_spec.rb +122 -0
  243. data/spec/record/find_in_parallel_spec.rb +67 -0
  244. data/spec/record/find_spec.rb +103 -0
  245. data/spec/record/first_spec.rb +39 -0
  246. data/spec/record/force_merge_spec.rb +55 -0
  247. data/spec/record/handle_includes_errors_spec.rb +33 -0
  248. data/spec/record/has_many_spec.rb +118 -0
  249. data/spec/record/has_one_spec.rb +114 -0
  250. data/spec/record/href_for_spec.rb +24 -0
  251. data/spec/record/ignore_errors_spec.rb +137 -0
  252. data/spec/record/immutable_chains_spec.rb +22 -0
  253. data/spec/record/includes_after_expansion_spec.rb +70 -0
  254. data/spec/record/includes_expanded_spec.rb +37 -0
  255. data/spec/record/includes_first_page_spec.rb +738 -0
  256. data/spec/record/includes_missing_spec.rb +57 -0
  257. data/spec/record/includes_spec.rb +690 -0
  258. data/spec/record/includes_warning_spec.rb +46 -0
  259. data/spec/record/item_key_spec.rb +81 -0
  260. data/spec/record/items_created_key_configuration_spec.rb +37 -0
  261. data/spec/record/last_spec.rb +64 -0
  262. data/spec/record/loading_twice_spec.rb +19 -0
  263. data/spec/record/mapping_spec.rb +103 -0
  264. data/spec/record/model_name_spec.rb +17 -0
  265. data/spec/record/new_spec.rb +106 -0
  266. data/spec/record/options_getter_spec.rb +25 -0
  267. data/spec/record/options_spec.rb +164 -0
  268. data/spec/record/paginatable_collection_spec.rb +360 -0
  269. data/spec/record/pagination_chain_spec.rb +101 -0
  270. data/spec/record/pagination_links_spec.rb +72 -0
  271. data/spec/record/pagination_spec.rb +71 -0
  272. data/spec/record/persisted_spec.rb +52 -0
  273. data/spec/record/provider_spec.rb +40 -0
  274. data/spec/record/references_spec.rb +95 -0
  275. data/spec/record/relation_caching_spec.rb +120 -0
  276. data/spec/record/reload_by_id_spec.rb +43 -0
  277. data/spec/record/reload_spec.rb +64 -0
  278. data/spec/record/request_spec.rb +90 -0
  279. data/spec/record/save_spec.rb +40 -0
  280. data/spec/record/scope_chains_spec.rb +39 -0
  281. data/spec/record/select_spec.rb +17 -0
  282. data/spec/record/to_ary_spec.rb +65 -0
  283. data/spec/record/to_hash_spec.rb +22 -0
  284. data/spec/record/to_json_spec.rb +22 -0
  285. data/spec/record/tracing_spec.rb +149 -0
  286. data/spec/record/update_spec.rb +61 -0
  287. data/spec/record/where_chains_spec.rb +57 -0
  288. data/spec/record/where_spec.rb +62 -0
  289. data/spec/record/where_values_hash_spec.rb +32 -0
  290. data/spec/request_cycle_cache_spec.rb +106 -0
  291. data/spec/require_dhs_spec.rb +9 -0
  292. data/spec/spec_helper.rb +6 -0
  293. data/spec/stubs/all_spec.rb +69 -0
  294. data/spec/support/fixtures/json/feedback.json +11 -0
  295. data/spec/support/fixtures/json/feedbacks.json +174 -0
  296. data/spec/support/fixtures/json/localina_content_ad.json +23 -0
  297. data/spec/support/load_json.rb +5 -0
  298. data/spec/support/request_cycle_cache.rb +10 -0
  299. data/spec/support/reset.rb +67 -0
  300. data/spec/views/form_for_spec.rb +20 -0
  301. metadata +783 -0
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ context 'creation failed' do
7
+ let(:datastore) { 'http://depay.fi/v2' }
8
+
9
+ before do
10
+ DHC.config.placeholder(:datastore, datastore)
11
+ class Record < DHS::Record
12
+ endpoint '{+datastore}/{campaign_id}/feedbacks'
13
+ endpoint '{+datastore}/feedbacks'
14
+ end
15
+ end
16
+
17
+ let(:error_message) { 'ratings must be set when review or name or review_title is set | The property value is required; it cannot be null, empty, or blank.' }
18
+
19
+ let(:creation_error) do
20
+ {
21
+ 'status' => 400,
22
+ 'message' => error_message,
23
+ 'fields' => [
24
+ {
25
+ 'name' => 'ratings',
26
+ 'details' => [{ 'code' => 'REQUIRED_PROPERTY_VALUE' }]
27
+ }, {
28
+ 'name' => 'recommended',
29
+ 'details' => [{ 'code' => 'REQUIRED_PROPERTY_VALUE' }]
30
+ }
31
+ ]
32
+ }
33
+ end
34
+
35
+ it 'provides errors when creation failed' do
36
+ stub_request(:post, "#{datastore}/feedbacks")
37
+ .to_return(status: 400, body: creation_error.to_json)
38
+ record = Record.create(name: 'Steve')
39
+ expect(record).to be_kind_of Record
40
+ expect(record.errors).to be_present
41
+ expect(record.name).to eq 'Steve'
42
+ expect(record.errors.include?(:ratings)).to eq true
43
+ expect(record.errors.include?(:recommended)).to eq true
44
+ expect(record.errors[:ratings]).to eq ['REQUIRED_PROPERTY_VALUE']
45
+ expect(record.errors.messages).to eq('ratings' => ['REQUIRED_PROPERTY_VALUE'], 'recommended' => ['REQUIRED_PROPERTY_VALUE'])
46
+ expect(record.errors.message).to eq error_message
47
+ end
48
+
49
+ it 'doesnt fail when no fields are provided by the backend' do
50
+ stub_request(:post, "#{datastore}/feedbacks")
51
+ .to_return(status: 400, body: {}.to_json)
52
+ Record.create(name: 'Steve')
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ context 'custom setters' do
7
+ context 'assigning values directly to other attributes' do
8
+ before do
9
+ Object.send(:remove_const, :Booking) if Object.const_defined?(:Booking) # make sure there is no other booking from previous tests around
10
+ class Booking < DHS::Record
11
+ endpoint 'https://bookings'
12
+
13
+ def appointment_attributes=(params)
14
+ self.appointments = params.map { |item| item[:id] }
15
+ end
16
+ end
17
+ end
18
+
19
+ it 'allows to change raw in custom setters' do
20
+ booking = Booking.new(appointment_attributes: [{ id: 1 }])
21
+ expect(booking.appointments.to_a).to eq [1]
22
+ end
23
+ end
24
+
25
+ context 'assign values directly by using square brackets' do
26
+ before do
27
+ class Booking < DHS::Record
28
+ endpoint 'https://bookings'
29
+
30
+ def appointment_attributes=(params)
31
+ self[:appointments] = params.map { |item| item[:id] }
32
+ end
33
+ end
34
+ end
35
+
36
+ it 'allows to change raw in custom setters' do
37
+ booking = Booking.new(appointment_attributes: [{ id: 1 }])
38
+ expect(booking.appointments.to_a).to eq [1]
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ context 'definitions' do
7
+ let(:datastore) { 'http://depay.fi/v2' }
8
+
9
+ before do
10
+ DHC.config.placeholder('datastore', datastore)
11
+ class LocalEntry < DHS::Record
12
+ endpoint '{+datastore}/local-entries'
13
+ endpoint '{+datastore}/local-entries/{id}'
14
+ end
15
+ end
16
+
17
+ it 'allows mappings in all functions/defitions' do
18
+ class LocalEntry < DHS::Record
19
+ def name
20
+ addresses.first.business.identities.first.name
21
+ end
22
+ end
23
+ stub_request(:get, "#{datastore}/local-entries/1")
24
+ .to_return(status: 200, body: { addresses: [{ business: { identities: [{ name: 'Löwenzorn' }] } }] }.to_json)
25
+ entry = LocalEntry.find(1)
26
+ expect(entry.name).to eq 'Löwenzorn'
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ context 'destroy' do
7
+ before do
8
+ class Record < DHS::Record
9
+ endpoint 'http://datastore/history'
10
+ endpoint 'http://datastore/history/{id}'
11
+ end
12
+ end
13
+
14
+ let(:entry) { { what: 'Cafe', where: 'Zurich' } }
15
+
16
+ it 'allows to destroy by parameters directly' do
17
+ stub_request(:delete, 'http://datastore/history?what=Cafe&where=Zurich')
18
+ .to_return(body: [entry].to_json)
19
+ deleted_entries = Record.destroy(what: 'Cafe', where: 'Zurich')
20
+ expect(deleted_entries.first.to_h).to eq entry
21
+ end
22
+
23
+ it 'allows to destroy by id' do
24
+ stub_request(:delete, 'http://datastore/history/1')
25
+ .to_return(body: entry.to_json)
26
+ deleted_entry = Record.destroy(1)
27
+ expect(deleted_entry.to_h).to eq entry
28
+ end
29
+
30
+ it 'chains' do
31
+ stub_request(:delete, 'http://datastore/history/1')
32
+ .with(headers: { 'Authorization' => 'Bearer 123' })
33
+ .to_return(body: entry.to_json)
34
+ deleted_entry = Record.options(headers: { 'Authorization' => 'Bearer 123' }).destroy(1)
35
+ expect(deleted_entry.to_h).to eq entry
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ before do
7
+ class Business < DHS::Record
8
+ configuration(
9
+ items_key: %i[response businesses],
10
+ total_key: %i[response count],
11
+ limit_key: { body: %i[response max] },
12
+ pagination_key: { body: %i[response offset] },
13
+ pagination_strategy: :offset
14
+ )
15
+ endpoint 'http://uberall/businesses'
16
+ end
17
+ end
18
+
19
+ let(:stub_single_business_request) do
20
+ stub_request(:get, 'http://uberall/businesses?identifier=ABC123&limit=1')
21
+ .to_return(body: {
22
+ status: 'SUCCESS',
23
+ response: {
24
+ offset: 0,
25
+ max: 50,
26
+ count: 1,
27
+ businesses: [
28
+ {
29
+ identifier: 'ABC123',
30
+ name: 'depay'
31
+ }
32
+ ]
33
+ }
34
+ }.to_json)
35
+ end
36
+
37
+ let(:stub_multiple_businesses_request) do
38
+ stub_request(:get, 'http://uberall/businesses?name=depay')
39
+ .to_return(body: {
40
+ status: 'SUCCESS',
41
+ response: {
42
+ offset: 0,
43
+ max: 50,
44
+ count: 2,
45
+ businesses: [
46
+ {
47
+ identifier: 'ABC123',
48
+ name: 'depay'
49
+ },
50
+ {
51
+ identifier: 'ABC121',
52
+ name: 'Swisscom'
53
+ }
54
+ ]
55
+ }
56
+ }.to_json)
57
+ end
58
+
59
+ context 'access nested keys for configuration' do
60
+ it 'uses paths from configuration to access nested values' do
61
+ stub_single_business_request
62
+ business = Business.find_by(identifier: 'ABC123')
63
+ expect(business.identifier).to eq 'ABC123'
64
+ expect(business.name).to eq 'depay'
65
+ end
66
+
67
+ it 'digs for meta data when meta information is nested' do
68
+ stub_multiple_businesses_request
69
+ businesses = Business.where(name: 'depay')
70
+ expect(businesses.length).to eq 2
71
+ expect(businesses.count).to eq 2
72
+ expect(businesses.offset).to eq 0
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ describe '#dup' do
7
+ before do
8
+ class Appointment < DHS::Record
9
+ end
10
+ end
11
+
12
+ it 'returns a copy of an object' do
13
+ appointment = Appointment.new
14
+ copy = appointment.dup
15
+ expect(copy.inspect).to match(/Appointment/)
16
+ expect(copy).to be_kind_of(Appointment)
17
+ expect(copy.object_id).not_to eql(appointment.object_id)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ context 'inherit endpoints' do
7
+ before do
8
+ class Base < DHS::Record
9
+ endpoint 'records/{id}'
10
+ end
11
+
12
+ class Example < Base
13
+ end
14
+ end
15
+
16
+ it 'inherits endpoints based on ruby class_attribute behaviour' do
17
+ request = stub_request(:get, 'http://records/1').to_return(body: [].to_json)
18
+ Example.find(1)
19
+ Base.find(1)
20
+ assert_requested(request, times: 2)
21
+ end
22
+ end
23
+
24
+ context 'define endpoints in subclass' do
25
+ before do
26
+ class Base < DHS::Record
27
+ endpoint 'records/{id}'
28
+ end
29
+
30
+ class Example < Base
31
+ endpoint 'records'
32
+ end
33
+ end
34
+
35
+ it 'inherits endpoints based on ruby class_attribute behaviour' do
36
+ stub_request(:get, 'http://records?color=blue').to_return(body: [].to_json)
37
+ Example.where(color: 'blue')
38
+ expect(
39
+ -> { Base.all.first }
40
+ ).to raise_error(RuntimeError, 'Compilation incomplete. Unable to find value for id.')
41
+ end
42
+ end
43
+
44
+ context 'ambiguous endpoints between super and subclass' do
45
+ before do
46
+ class Base < DHS::Record
47
+ endpoint 'records'
48
+ end
49
+
50
+ class Example < Base
51
+ endpoint 'examples/{id}'
52
+ end
53
+ end
54
+
55
+ it 'inherits endpoints based on ruby class_attribute behaviour' do
56
+ request = stub_request(:get, 'http://records?limit=100').to_return(body: [].to_json)
57
+ Base.all.first
58
+ assert_requested(request)
59
+
60
+ request = stub_request(:get, 'http://examples/1').to_return(body: {}.to_json)
61
+ Example.find(1)
62
+ assert_requested(request)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ context 'set options for an endpoint' do
7
+ before do
8
+ class Record < DHS::Record
9
+ endpoint 'backend/v2/feedbacks/{id}', cache_expires_in: 1.day, retry: 2, cache: true
10
+ end
11
+ end
12
+
13
+ it 'stores endpoints with options' do
14
+ expect(Record.endpoints[0].options).to eq(cache_expires_in: 86400, retry: 2, cache: true)
15
+ end
16
+
17
+ it 'uses the options that are configured for an endpoint' do
18
+ expect(DHC).to receive(:request)
19
+ .with(
20
+ cache_expires_in: 1.day,
21
+ retry: 2,
22
+ cache: true,
23
+ url: 'backend/v2/feedbacks/1'
24
+ ).and_call_original
25
+
26
+ stub_request(:get, 'http://backend/v2/feedbacks/1').to_return(status: 200)
27
+ Record.find(1)
28
+ end
29
+
30
+ context 'deep merge endpoint options' do
31
+ before do
32
+ class Location < DHS::Record
33
+ endpoint 'http://uberall/locations', headers: { privateKey: '123' }
34
+ end
35
+ end
36
+
37
+ it 'deep merges options to not overwrite endpoint options' do
38
+ stub_request(:get, 'http://uberall/locations')
39
+ .with(
40
+ headers: {
41
+ 'Privatekey' => '123',
42
+ 'X-Custom' => '123'
43
+ }
44
+ )
45
+ .to_return(body: [].to_json)
46
+
47
+ Location.options(headers: { 'X-Custom' => '123' }).fetch
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ context 'endpoint priorities' do
7
+ before do
8
+ class Record < DHS::Record
9
+ endpoint 'https://api/v2/feedbacks'
10
+ endpoint 'https://api/v2/reviews'
11
+ endpoint 'https://api/v2/streets/{id}'
12
+ endpoint 'https://api/v2/feedbacks/{id}'
13
+ endpoint 'https://api/v2/reviews/{id}'
14
+ end
15
+ end
16
+
17
+ it 'always takes the first endpoint found' do
18
+ stub_request(:get, 'https://api/v2/feedbacks').to_return(status: 200)
19
+ Record.fetch
20
+ stub_request(:get, 'https://api/v2/streets/1').to_return(status: 200)
21
+ Record.find(1)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHS::Record do
6
+ context 'endpoints' do
7
+ let(:datastore) { 'http://depay.fi/v2' }
8
+
9
+ before do
10
+ DHC.config.placeholder(:datastore, datastore)
11
+ class Record < DHS::Record
12
+ endpoint '{+datastore}/entries/{entry_id}/content-ads/{campaign_id}/feedbacks'
13
+ endpoint '{+datastore}/{campaign_id}/feedbacks'
14
+ endpoint '{+datastore}/feedbacks'
15
+ end
16
+ end
17
+
18
+ it 'stores all the endpoints by url' do
19
+ expect(DHS::Record::Endpoints.all['{+datastore}/entries/{entry_id}/content-ads/{campaign_id}/feedbacks']).to be_present
20
+ expect(DHS::Record::Endpoints.all['{+datastore}/{campaign_id}/feedbacks']).to be_present
21
+ expect(DHS::Record::Endpoints.all['{+datastore}/feedbacks']).to be_present
22
+ end
23
+
24
+ it 'stores the endpoints of the service' do
25
+ expect(Record.endpoints.count).to eq 3
26
+ expect(Record.endpoints[0].url).to eq '{+datastore}/entries/{entry_id}/content-ads/{campaign_id}/feedbacks'
27
+ expect(Record.endpoints[1].url).to eq '{+datastore}/{campaign_id}/feedbacks'
28
+ expect(Record.endpoints[2].url).to eq '{+datastore}/feedbacks'
29
+ end
30
+
31
+ it 'finds the endpoint by the one with the most route param hits' do
32
+ expect(
33
+ Record.find_endpoint(campaign_id: '12345').url
34
+ ).to eq '{+datastore}/{campaign_id}/feedbacks'
35
+ expect(
36
+ Record.find_endpoint(campaign_id: '12345', entry_id: '123').url
37
+ ).to eq '{+datastore}/entries/{entry_id}/content-ads/{campaign_id}/feedbacks'
38
+ end
39
+
40
+ it 'finds the base endpoint (endpoint with least amount of route params)' do
41
+ expect(
42
+ Record.find_endpoint.url
43
+ ).to eq '{+datastore}/feedbacks'
44
+ end
45
+
46
+ context 'compute url from endpoint' do
47
+ before do
48
+ class Feedback < DHS::Record
49
+ endpoint '{+datastore}/feedbacks'
50
+ endpoint '{+datastore}/feedbacks/{id}'
51
+ end
52
+ end
53
+
54
+ it 'computes urls WITHOUT handling id separate' do
55
+ stub_request(:get, "#{datastore}/feedbacks/1").to_return(status: 200)
56
+ Feedback.find(1)
57
+ end
58
+ end
59
+
60
+ context 'unsorted endpoints' do
61
+ before do
62
+ class AnotherRecord < DHS::Record
63
+ endpoint '{+datastore}/feedbacks'
64
+ endpoint '{+datastore}/{campaign_id}/feedbacks'
65
+ endpoint '{+datastore}/entries/{entry_id}/content-ads/{campaign_id}/feedbacks'
66
+ end
67
+ end
68
+
69
+ it 'sorts endpoints before trying to find the best endpoint' do
70
+ stub_request(:get, "#{datastore}/entries/123/content-ads/123/feedbacks").to_return(status: 200)
71
+ AnotherRecord.where(campaign_id: 123, entry_id: 123)
72
+ end
73
+ end
74
+
75
+ context 'includes data without considering base endpoint of parent record if url is present' do
76
+ before do
77
+ class Contract < DHS::Record
78
+ endpoint '{+datastore}/contracts/:id'
79
+ endpoint '{+datastore}/entry/{entry_id}/contracts'
80
+ end
81
+ end
82
+
83
+ it 'uses urls instead of trying to find base endpoint of parent class' do
84
+ stub_request(:get, "#{datastore}/entry/123/contracts?limit=100")
85
+ .to_return(body: [{ product: { href: "#{datastore}/products/LBC" } }].to_json)
86
+ stub_request(:get, "#{datastore}/entry/123/contracts?limit=100&offset=100")
87
+ .to_return(body: [].to_json)
88
+ stub_request(:get, "#{datastore}/products/LBC")
89
+ .to_return(body: { name: 'Local Business Card' }.to_json)
90
+ expect(lambda {
91
+ Contract.includes_first_page(:product).where(entry_id: '123').all.first
92
+ }).not_to raise_error # Multiple base endpoints found
93
+ end
94
+ end
95
+ end
96
+ end