lhs 24.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 (306) hide show
  1. checksums.yaml +7 -0
  2. data/.bundler-version +1 -0
  3. data/.gitignore +39 -0
  4. data/.rubocop.localch.yml +325 -0
  5. data/.rubocop.yml +52 -0
  6. data/.ruby-version +1 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.activesupport4 +5 -0
  9. data/Gemfile.activesupport5 +4 -0
  10. data/LICENSE +674 -0
  11. data/README.md +2836 -0
  12. data/Rakefile +25 -0
  13. data/cider-ci.yml +6 -0
  14. data/cider-ci/bin/bundle +51 -0
  15. data/cider-ci/bin/ruby_install +8 -0
  16. data/cider-ci/bin/ruby_version +25 -0
  17. data/cider-ci/jobs/rspec-activesupport-4.yml +27 -0
  18. data/cider-ci/jobs/rspec-activesupport-5.yml +26 -0
  19. data/cider-ci/jobs/rspec-activesupport-latest.yml +24 -0
  20. data/cider-ci/jobs/rubocop.yml +18 -0
  21. data/cider-ci/task_components/bundle.yml +22 -0
  22. data/cider-ci/task_components/rspec.yml +37 -0
  23. data/cider-ci/task_components/rubocop.yml +29 -0
  24. data/cider-ci/task_components/ruby.yml +15 -0
  25. data/friday.yml +2 -0
  26. data/lhs.gemspec +43 -0
  27. data/lib/lhs.rb +100 -0
  28. data/lib/lhs/collection.rb +84 -0
  29. data/lib/lhs/complex.rb +158 -0
  30. data/lib/lhs/concerns/autoload_records.rb +55 -0
  31. data/lib/lhs/concerns/collection/handle_nested.rb +43 -0
  32. data/lib/lhs/concerns/collection/internal_collection.rb +49 -0
  33. data/lib/lhs/concerns/configuration.rb +20 -0
  34. data/lib/lhs/concerns/data/becomes.rb +18 -0
  35. data/lib/lhs/concerns/data/equality.rb +14 -0
  36. data/lib/lhs/concerns/data/json.rb +14 -0
  37. data/lib/lhs/concerns/data/to_hash.rb +14 -0
  38. data/lib/lhs/concerns/inspect.rb +70 -0
  39. data/lib/lhs/concerns/is_href.rb +15 -0
  40. data/lib/lhs/concerns/item/destroy.rb +38 -0
  41. data/lib/lhs/concerns/item/endpoint_lookup.rb +27 -0
  42. data/lib/lhs/concerns/item/save.rb +55 -0
  43. data/lib/lhs/concerns/item/update.rb +50 -0
  44. data/lib/lhs/concerns/item/validation.rb +61 -0
  45. data/lib/lhs/concerns/o_auth.rb +25 -0
  46. data/lib/lhs/concerns/option_blocks.rb +26 -0
  47. data/lib/lhs/concerns/proxy/accessors.rb +132 -0
  48. data/lib/lhs/concerns/proxy/create.rb +45 -0
  49. data/lib/lhs/concerns/proxy/link.rb +25 -0
  50. data/lib/lhs/concerns/proxy/problems.rb +27 -0
  51. data/lib/lhs/concerns/record/attribute_assignment.rb +25 -0
  52. data/lib/lhs/concerns/record/batch.rb +40 -0
  53. data/lib/lhs/concerns/record/chainable.rb +465 -0
  54. data/lib/lhs/concerns/record/configuration.rb +103 -0
  55. data/lib/lhs/concerns/record/create.rb +24 -0
  56. data/lib/lhs/concerns/record/custom_setters.rb +22 -0
  57. data/lib/lhs/concerns/record/destroy.rb +18 -0
  58. data/lib/lhs/concerns/record/endpoints.rb +108 -0
  59. data/lib/lhs/concerns/record/equality.rb +14 -0
  60. data/lib/lhs/concerns/record/find.rb +86 -0
  61. data/lib/lhs/concerns/record/find_by.rb +38 -0
  62. data/lib/lhs/concerns/record/first.rb +20 -0
  63. data/lib/lhs/concerns/record/href_for.rb +19 -0
  64. data/lib/lhs/concerns/record/last.rb +27 -0
  65. data/lib/lhs/concerns/record/mapping.rb +25 -0
  66. data/lib/lhs/concerns/record/merge.rb +26 -0
  67. data/lib/lhs/concerns/record/model.rb +23 -0
  68. data/lib/lhs/concerns/record/pagination.rb +47 -0
  69. data/lib/lhs/concerns/record/provider.rb +23 -0
  70. data/lib/lhs/concerns/record/relations.rb +26 -0
  71. data/lib/lhs/concerns/record/request.rb +620 -0
  72. data/lib/lhs/concerns/record/scope.rb +25 -0
  73. data/lib/lhs/concerns/record/tracing.rb +24 -0
  74. data/lib/lhs/concerns/record/update.rb +17 -0
  75. data/lib/lhs/config.rb +24 -0
  76. data/lib/lhs/data.rb +165 -0
  77. data/lib/lhs/endpoint.rb +12 -0
  78. data/lib/lhs/interceptors/auto_oauth/interceptor.rb +33 -0
  79. data/lib/lhs/interceptors/auto_oauth/thread_registry.rb +18 -0
  80. data/lib/lhs/interceptors/extended_rollbar/handler.rb +40 -0
  81. data/lib/lhs/interceptors/extended_rollbar/interceptor.rb +20 -0
  82. data/lib/lhs/interceptors/extended_rollbar/thread_registry.rb +19 -0
  83. data/lib/lhs/interceptors/request_cycle_cache/interceptor.rb +41 -0
  84. data/lib/lhs/interceptors/request_cycle_cache/thread_registry.rb +18 -0
  85. data/lib/lhs/item.rb +59 -0
  86. data/lib/lhs/pagination/base.rb +90 -0
  87. data/lib/lhs/pagination/link.rb +21 -0
  88. data/lib/lhs/pagination/offset.rb +22 -0
  89. data/lib/lhs/pagination/page.rb +18 -0
  90. data/lib/lhs/pagination/start.rb +22 -0
  91. data/lib/lhs/problems/base.rb +113 -0
  92. data/lib/lhs/problems/errors.rb +69 -0
  93. data/lib/lhs/problems/nested/base.rb +54 -0
  94. data/lib/lhs/problems/nested/errors.rb +16 -0
  95. data/lib/lhs/problems/nested/warnings.rb +15 -0
  96. data/lib/lhs/problems/warnings.rb +24 -0
  97. data/lib/lhs/proxy.rb +68 -0
  98. data/lib/lhs/railtie.rb +34 -0
  99. data/lib/lhs/record.rb +112 -0
  100. data/lib/lhs/rspec.rb +10 -0
  101. data/lib/lhs/test/stubbable_records.rb +34 -0
  102. data/lib/lhs/unprocessable.rb +6 -0
  103. data/lib/lhs/version.rb +5 -0
  104. data/script/ci/build.sh +18 -0
  105. data/spec/auto_oauth_spec.rb +169 -0
  106. data/spec/autoloading_spec.rb +48 -0
  107. data/spec/collection/accessors_spec.rb +31 -0
  108. data/spec/collection/collection_items_spec.rb +44 -0
  109. data/spec/collection/configurable_spec.rb +43 -0
  110. data/spec/collection/delegate_spec.rb +21 -0
  111. data/spec/collection/enumerable_spec.rb +27 -0
  112. data/spec/collection/href_spec.rb +17 -0
  113. data/spec/collection/meta_data_spec.rb +57 -0
  114. data/spec/collection/respond_to_spec.rb +20 -0
  115. data/spec/collection/to_a_spec.rb +34 -0
  116. data/spec/collection/to_ary_spec.rb +40 -0
  117. data/spec/collection/without_object_items_spec.rb +27 -0
  118. data/spec/complex/reduce_spec.rb +202 -0
  119. data/spec/concerns/record/request_spec.rb +78 -0
  120. data/spec/data/collection_spec.rb +56 -0
  121. data/spec/data/equality_spec.rb +23 -0
  122. data/spec/data/inspect_spec.rb +88 -0
  123. data/spec/data/is_item_or_collection_spec.rb +40 -0
  124. data/spec/data/item_spec.rb +106 -0
  125. data/spec/data/merge_spec.rb +27 -0
  126. data/spec/data/parent_spec.rb +39 -0
  127. data/spec/data/raw_spec.rb +48 -0
  128. data/spec/data/respond_to_spec.rb +26 -0
  129. data/spec/data/root_spec.rb +25 -0
  130. data/spec/data/select_spec.rb +27 -0
  131. data/spec/data/to_ary_spec.rb +28 -0
  132. data/spec/data/to_json_spec.rb +68 -0
  133. data/spec/dummy/Rakefile +8 -0
  134. data/spec/dummy/app/assets/images/.keep +0 -0
  135. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  136. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  137. data/spec/dummy/app/controllers/application_controller.rb +26 -0
  138. data/spec/dummy/app/controllers/automatic_authentication_controller.rb +29 -0
  139. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  140. data/spec/dummy/app/controllers/error_handling_with_chains_controller.rb +36 -0
  141. data/spec/dummy/app/controllers/extended_rollbar_controller.rb +10 -0
  142. data/spec/dummy/app/controllers/option_blocks_controller.rb +15 -0
  143. data/spec/dummy/app/controllers/request_cycle_cache_controller.rb +27 -0
  144. data/spec/dummy/app/helpers/application_helper.rb +4 -0
  145. data/spec/dummy/app/mailers/.keep +0 -0
  146. data/spec/dummy/app/models/.keep +0 -0
  147. data/spec/dummy/app/models/concerns/.keep +0 -0
  148. data/spec/dummy/app/models/dummy_customer.rb +6 -0
  149. data/spec/dummy/app/models/dummy_record.rb +6 -0
  150. data/spec/dummy/app/models/dummy_record_with_auto_oauth_provider.rb +6 -0
  151. data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers1.rb +7 -0
  152. data/spec/dummy/app/models/dummy_record_with_multiple_oauth_providers2.rb +7 -0
  153. data/spec/dummy/app/models/dummy_record_with_multiple_providers_per_endpoint.rb +6 -0
  154. data/spec/dummy/app/models/dummy_record_with_oauth.rb +7 -0
  155. data/spec/dummy/app/models/dummy_user.rb +6 -0
  156. data/spec/dummy/app/models/providers/customer_system.rb +7 -0
  157. data/spec/dummy/app/models/providers/internal_services.rb +7 -0
  158. data/spec/dummy/app/views/error_handling_with_chains/error.html.erb +1 -0
  159. data/spec/dummy/app/views/error_handling_with_chains/show.html.erb +3 -0
  160. data/spec/dummy/app/views/form_for.html.erb +5 -0
  161. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  162. data/spec/dummy/bin/bundle +5 -0
  163. data/spec/dummy/bin/rails +6 -0
  164. data/spec/dummy/bin/rake +6 -0
  165. data/spec/dummy/config.ru +6 -0
  166. data/spec/dummy/config/application.rb +16 -0
  167. data/spec/dummy/config/boot.rb +7 -0
  168. data/spec/dummy/config/environment.rb +7 -0
  169. data/spec/dummy/config/environments/development.rb +36 -0
  170. data/spec/dummy/config/environments/production.rb +77 -0
  171. data/spec/dummy/config/environments/test.rb +40 -0
  172. data/spec/dummy/config/initializers/assets.rb +10 -0
  173. data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
  174. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  175. data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  176. data/spec/dummy/config/initializers/inflections.rb +18 -0
  177. data/spec/dummy/config/initializers/mime_types.rb +6 -0
  178. data/spec/dummy/config/initializers/rollbar.rb +9 -0
  179. data/spec/dummy/config/initializers/session_store.rb +5 -0
  180. data/spec/dummy/config/initializers/wrap_parameters.rb +11 -0
  181. data/spec/dummy/config/locales/en.yml +23 -0
  182. data/spec/dummy/config/routes.rb +27 -0
  183. data/spec/dummy/config/secrets.yml +22 -0
  184. data/spec/dummy/lib/assets/.keep +0 -0
  185. data/spec/dummy/public/404.html +67 -0
  186. data/spec/dummy/public/422.html +67 -0
  187. data/spec/dummy/public/500.html +66 -0
  188. data/spec/dummy/public/favicon.ico +0 -0
  189. data/spec/endpoint/for_url_spec.rb +27 -0
  190. data/spec/extended_rollbar_spec.rb +67 -0
  191. data/spec/item/access_errors_spec.rb +33 -0
  192. data/spec/item/accessors_spec.rb +21 -0
  193. data/spec/item/add_error_spec.rb +21 -0
  194. data/spec/item/becomes_spec.rb +38 -0
  195. data/spec/item/blacklisted_keywords_spec.rb +30 -0
  196. data/spec/item/delegate_spec.rb +32 -0
  197. data/spec/item/destroy_spec.rb +113 -0
  198. data/spec/item/dig_spec.rb +29 -0
  199. data/spec/item/error_codes_spec.rb +55 -0
  200. data/spec/item/errors_spec.rb +324 -0
  201. data/spec/item/fetch_spec.rb +39 -0
  202. data/spec/item/getter_spec.rb +24 -0
  203. data/spec/item/internal_data_structure_spec.rb +37 -0
  204. data/spec/item/map_spec.rb +46 -0
  205. data/spec/item/nested_errors_spec.rb +28 -0
  206. data/spec/item/partial_update_spec.rb +170 -0
  207. data/spec/item/respond_to_spec.rb +31 -0
  208. data/spec/item/save_spec.rb +115 -0
  209. data/spec/item/setter_spec.rb +44 -0
  210. data/spec/item/translate_errors_spec.rb +257 -0
  211. data/spec/item/update_spec.rb +161 -0
  212. data/spec/item/validation_spec.rb +131 -0
  213. data/spec/item/warning_codes_spec.rb +55 -0
  214. data/spec/item/warnings_spec.rb +52 -0
  215. data/spec/option_blocks/ensure_reset_between_requests_spec.rb +23 -0
  216. data/spec/option_blocks/main_spec.rb +55 -0
  217. data/spec/pagination/link/current_page_spec.rb +19 -0
  218. data/spec/pagination/link/pages_left_spec.rb +36 -0
  219. data/spec/pagination/link/parallel_spec.rb +19 -0
  220. data/spec/pagination/link/total_spec.rb +46 -0
  221. data/spec/pagination/offset/pages_left_spec.rb +26 -0
  222. data/spec/pagination/parameters_spec.rb +61 -0
  223. data/spec/proxy/create_sub_resource_spec.rb +182 -0
  224. data/spec/proxy/load_spec.rb +75 -0
  225. data/spec/proxy/record_identification_spec.rb +35 -0
  226. data/spec/rails_helper.rb +13 -0
  227. data/spec/record/all_spec.rb +133 -0
  228. data/spec/record/attribute_assignment_spec.rb +28 -0
  229. data/spec/record/build_spec.rb +26 -0
  230. data/spec/record/cast_nested_data_spec.rb +78 -0
  231. data/spec/record/create_spec.rb +160 -0
  232. data/spec/record/creation_failed_spec.rb +55 -0
  233. data/spec/record/custom_setters_spec.rb +45 -0
  234. data/spec/record/definitions_spec.rb +29 -0
  235. data/spec/record/destroy_spec.rb +38 -0
  236. data/spec/record/dig_configuration_spec.rb +75 -0
  237. data/spec/record/dup_spec.rb +20 -0
  238. data/spec/record/endpoint_inheritance_spec.rb +65 -0
  239. data/spec/record/endpoint_options_spec.rb +52 -0
  240. data/spec/record/endpoint_priorities_spec.rb +26 -0
  241. data/spec/record/endpoints_spec.rb +96 -0
  242. data/spec/record/equality_spec.rb +27 -0
  243. data/spec/record/error_handling_integration_spec.rb +25 -0
  244. data/spec/record/error_handling_spec.rb +40 -0
  245. data/spec/record/expanded_spec.rb +69 -0
  246. data/spec/record/fetch_spec.rb +41 -0
  247. data/spec/record/find_by_chains_spec.rb +21 -0
  248. data/spec/record/find_by_spec.rb +76 -0
  249. data/spec/record/find_each_spec.rb +57 -0
  250. data/spec/record/find_in_batches_spec.rb +122 -0
  251. data/spec/record/find_in_parallel_spec.rb +67 -0
  252. data/spec/record/find_spec.rb +104 -0
  253. data/spec/record/first_spec.rb +39 -0
  254. data/spec/record/force_merge_spec.rb +56 -0
  255. data/spec/record/handle_includes_errors_spec.rb +32 -0
  256. data/spec/record/has_many_spec.rb +120 -0
  257. data/spec/record/has_one_spec.rb +116 -0
  258. data/spec/record/href_for_spec.rb +25 -0
  259. data/spec/record/ignore_errors_spec.rb +139 -0
  260. data/spec/record/immutable_chains_spec.rb +22 -0
  261. data/spec/record/includes_first_page_spec.rb +737 -0
  262. data/spec/record/includes_spec.rb +693 -0
  263. data/spec/record/includes_warning_spec.rb +46 -0
  264. data/spec/record/item_key_spec.rb +81 -0
  265. data/spec/record/items_created_key_configuration_spec.rb +37 -0
  266. data/spec/record/last_spec.rb +68 -0
  267. data/spec/record/loading_twice_spec.rb +19 -0
  268. data/spec/record/mapping_spec.rb +102 -0
  269. data/spec/record/model_name_spec.rb +17 -0
  270. data/spec/record/new_spec.rb +106 -0
  271. data/spec/record/options_getter_spec.rb +26 -0
  272. data/spec/record/options_spec.rb +164 -0
  273. data/spec/record/paginatable_collection_spec.rb +360 -0
  274. data/spec/record/pagination_chain_spec.rb +101 -0
  275. data/spec/record/pagination_links_spec.rb +72 -0
  276. data/spec/record/pagination_spec.rb +71 -0
  277. data/spec/record/persisted_spec.rb +52 -0
  278. data/spec/record/provider_spec.rb +41 -0
  279. data/spec/record/references_spec.rb +53 -0
  280. data/spec/record/relation_caching_spec.rb +121 -0
  281. data/spec/record/reload_by_id_spec.rb +43 -0
  282. data/spec/record/reload_spec.rb +65 -0
  283. data/spec/record/request_spec.rb +90 -0
  284. data/spec/record/save_spec.rb +40 -0
  285. data/spec/record/scope_chains_spec.rb +39 -0
  286. data/spec/record/select_spec.rb +17 -0
  287. data/spec/record/to_ary_spec.rb +65 -0
  288. data/spec/record/to_hash_spec.rb +22 -0
  289. data/spec/record/to_json_spec.rb +22 -0
  290. data/spec/record/tracing_spec.rb +154 -0
  291. data/spec/record/update_spec.rb +62 -0
  292. data/spec/record/where_chains_spec.rb +57 -0
  293. data/spec/record/where_spec.rb +62 -0
  294. data/spec/record/where_values_hash_spec.rb +32 -0
  295. data/spec/request_cycle_cache_spec.rb +106 -0
  296. data/spec/require_lhs_spec.rb +9 -0
  297. data/spec/spec_helper.rb +6 -0
  298. data/spec/stubs/all_spec.rb +72 -0
  299. data/spec/support/fixtures/json/feedback.json +11 -0
  300. data/spec/support/fixtures/json/feedbacks.json +174 -0
  301. data/spec/support/fixtures/json/localina_content_ad.json +23 -0
  302. data/spec/support/load_json.rb +5 -0
  303. data/spec/support/request_cycle_cache.rb +10 -0
  304. data/spec/support/reset.rb +67 -0
  305. data/spec/views/form_for_spec.rb +20 -0
  306. metadata +776 -0
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHS::Record do
6
+ before do
7
+ class Business < LHS::Record
8
+ configuration(
9
+ items_key: [:response, :businesses],
10
+ total_key: [:response, :count],
11
+ limit_key: { body: [:response, :max] },
12
+ pagination_key: { body: [: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: 'localsearch'
31
+ }
32
+ ]
33
+ }
34
+ }.to_json)
35
+ end
36
+
37
+ let(:stub_multiple_businesses_request) do
38
+ stub_request(:get, "http://uberall/businesses?name=localsearch")
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: 'localsearch'
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 'localsearch'
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: 'localsearch')
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 LHS::Record do
6
+ describe '#dup' do
7
+ before do
8
+ class Appointment < LHS::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 LHS::Record do
6
+ context 'inherit endpoints' do
7
+ before do
8
+ class Base < LHS::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 < LHS::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 < LHS::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,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHS::Record do
6
+ context 'set options for an endpoint' do
7
+ before do
8
+ class Record < LHS::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(LHC).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
+
32
+ before do
33
+ class Location < LHS::Record
34
+ endpoint 'http://uberall/locations', headers: { privateKey: '123' }
35
+ end
36
+ end
37
+
38
+ it 'deep merges options to not overwrite endpoint options' do
39
+ stub_request(:get, "http://uberall/locations")
40
+ .with(
41
+ headers: {
42
+ 'Privatekey' => '123',
43
+ 'X-Custom' => '123'
44
+ }
45
+ )
46
+ .to_return(body: [].to_json)
47
+
48
+ Location.options(headers: { 'X-Custom' => '123' }).fetch
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHS::Record do
6
+
7
+ context 'endpoint priorities' do
8
+
9
+ before do
10
+ class Record < LHS::Record
11
+ endpoint 'https://api/v2/feedbacks'
12
+ endpoint 'https://api/v2/reviews'
13
+ endpoint 'https://api/v2/streets/{id}'
14
+ endpoint 'https://api/v2/feedbacks/{id}'
15
+ endpoint 'https://api/v2/reviews/{id}'
16
+ end
17
+ end
18
+
19
+ it 'always takes the first endpoint found' do
20
+ stub_request(:get, "https://api/v2/feedbacks").to_return(status: 200)
21
+ Record.fetch
22
+ stub_request(:get, "https://api/v2/streets/1").to_return(status: 200)
23
+ Record.find(1)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHS::Record do
6
+ context 'endpoints' do
7
+ let(:datastore) { 'http://local.ch/v2' }
8
+
9
+ before do
10
+ LHC.config.placeholder(:datastore, datastore)
11
+ class Record < LHS::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(LHS::Record::Endpoints.all['{+datastore}/entries/{entry_id}/content-ads/{campaign_id}/feedbacks']).to be_present
20
+ expect(LHS::Record::Endpoints.all['{+datastore}/{campaign_id}/feedbacks']).to be_present
21
+ expect(LHS::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 < LHS::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 < LHS::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 < LHS::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
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHS::Record do
6
+ context 'equality' do
7
+ before do
8
+ class Record < LHS::Record
9
+ endpoint 'http://local.ch/records'
10
+ end
11
+ end
12
+
13
+ let(:raw) do
14
+ { name: 'Steve' }
15
+ end
16
+
17
+ def record
18
+ LHS::Record.new LHS::Data.new(raw, nil, Record)
19
+ end
20
+
21
+ it 'is equal when two data objects share the same raw data' do
22
+ expect(
23
+ record
24
+ ).to eq record
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+ require 'lhc/rspec'
5
+
6
+ describe 'Error handling with chains', type: :request do
7
+ let!(:request) do
8
+ stub_request(:get, "http://datastore/v2/records?color=blue")
9
+ .to_return(status: 404)
10
+ end
11
+
12
+ it 'handles errors in rails controllers when query resolved in controller',
13
+ dummy_models: true do
14
+ get '/error_handling_with_chains/fetch_in_controller'
15
+ expect(request).to have_been_made.once
16
+ expect(response.body).to include('Sorry there was an error.')
17
+ end
18
+
19
+ it 'handles errors in rails controllers when query resolved in view',
20
+ dummy_models: true do
21
+ get '/error_handling_with_chains/fetch_in_view'
22
+ expect(request).to have_been_made.once
23
+ expect(response.body).to include('Sorry there was an error.')
24
+ end
25
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHS::Record do
6
+ let(:handler) { spy('handler') }
7
+
8
+ before do
9
+ class Record < LHS::Record
10
+ endpoint 'http://local.ch/v2/records'
11
+ end
12
+ stub_request(:get, "http://local.ch/v2/records?color=blue")
13
+ .to_return(status: 400)
14
+ end
15
+
16
+ it 'allows to chain error handling' do
17
+ expect {
18
+ Record.where(color: 'blue').rescue(LHC::Error, ->(_error) { handler.handle }).first
19
+ }.not_to raise_error
20
+ expect(handler).to have_received(:handle)
21
+ end
22
+
23
+ it 'reraises in case chained error is not matched' do
24
+ expect {
25
+ Record.where(color: 'blue').rescue(LHC::Conflict, ->(_error) { handler.handle }).first
26
+ }.to raise_error(LHC::Error)
27
+ expect(handler).not_to have_received(:handle)
28
+ end
29
+
30
+ it 'calls all the handlers' do
31
+ expect {
32
+ Record.where(color: 'blue')
33
+ .rescue(LHC::Error, ->(_error) { handler.handle_1 })
34
+ .rescue(LHC::Error, ->(_error) { handler.handle_2 })
35
+ .first
36
+ }.not_to raise_error
37
+ expect(handler).to have_received(:handle_1)
38
+ expect(handler).to have_received(:handle_2)
39
+ end
40
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe LHS::Record do
6
+ before do
7
+ class Record < LHS::Record
8
+ endpoint 'http://local.ch/v2/records'
9
+ end
10
+ end
11
+
12
+ let!(:request_collection) do
13
+ stub_request(:get, "http://local.ch/v2/records?color=blue")
14
+ .to_return(body: {
15
+ items: [
16
+ { href: 'http://local.ch/v2/records/1' },
17
+ { href: 'http://local.ch/v2/records/2' }
18
+ ]
19
+ }.to_json)
20
+ end
21
+
22
+ let!(:request_item_1) do
23
+ stub_request(:get, "http://local.ch/v2/records/1?via=collection")
24
+ .to_return(body: {
25
+ name: 'Steve'
26
+ }.to_json)
27
+ end
28
+
29
+ let!(:request_item_2) do
30
+ stub_request(:get, "http://local.ch/v2/records/2?via=collection")
31
+ .to_return(body: {
32
+ name: 'John'
33
+ }.to_json)
34
+ end
35
+
36
+ it 'expands collections that just contains links' do
37
+ records = Record.where(color: 'blue').expanded(params: { via: 'collection' })
38
+ expect(records[0].name).to eq 'Steve'
39
+ expect(records[1].name).to eq 'John'
40
+ assert_requested request_collection
41
+ assert_requested request_item_1
42
+ assert_requested request_item_2
43
+ end
44
+
45
+ context 'without options' do
46
+ let!(:request_item_1) do
47
+ stub_request(:get, "http://local.ch/v2/records/1")
48
+ .to_return(body: {
49
+ name: 'Steve'
50
+ }.to_json)
51
+ end
52
+
53
+ let!(:request_item_2) do
54
+ stub_request(:get, "http://local.ch/v2/records/2")
55
+ .to_return(body: {
56
+ name: 'John'
57
+ }.to_json)
58
+ end
59
+
60
+ it 'works also without options' do
61
+ records = Record.where(color: 'blue').expanded
62
+ expect(records[0].name).to eq 'Steve'
63
+ expect(records[1].name).to eq 'John'
64
+ assert_requested request_collection
65
+ assert_requested request_item_1
66
+ assert_requested request_item_2
67
+ end
68
+ end
69
+ end