hoodoo 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (216) hide show
  1. checksums.yaml +7 -0
  2. data/bin/hoodoo +5 -0
  3. data/lib/hoodoo.rb +27 -0
  4. data/lib/hoodoo/active.rb +32 -0
  5. data/lib/hoodoo/active/active_model/uuid_validator.rb +45 -0
  6. data/lib/hoodoo/active/active_record/base.rb +81 -0
  7. data/lib/hoodoo/active/active_record/creator.rb +134 -0
  8. data/lib/hoodoo/active/active_record/dated.rb +343 -0
  9. data/lib/hoodoo/active/active_record/error_mapping.rb +351 -0
  10. data/lib/hoodoo/active/active_record/finder.rb +606 -0
  11. data/lib/hoodoo/active/active_record/search_helper.rb +189 -0
  12. data/lib/hoodoo/active/active_record/secure.rb +431 -0
  13. data/lib/hoodoo/active/active_record/support.rb +106 -0
  14. data/lib/hoodoo/active/active_record/translated.rb +87 -0
  15. data/lib/hoodoo/active/active_record/uuid.rb +80 -0
  16. data/lib/hoodoo/active/active_record/writer.rb +321 -0
  17. data/lib/hoodoo/client.rb +23 -0
  18. data/lib/hoodoo/client/augmented_array.rb +29 -0
  19. data/lib/hoodoo/client/augmented_base.rb +168 -0
  20. data/lib/hoodoo/client/augmented_hash.rb +23 -0
  21. data/lib/hoodoo/client/client.rb +354 -0
  22. data/lib/hoodoo/client/endpoint/endpoint.rb +427 -0
  23. data/lib/hoodoo/client/endpoint/endpoints/amqp.rb +180 -0
  24. data/lib/hoodoo/client/endpoint/endpoints/auto_session.rb +194 -0
  25. data/lib/hoodoo/client/endpoint/endpoints/http.rb +203 -0
  26. data/lib/hoodoo/client/endpoint/endpoints/http_based.rb +367 -0
  27. data/lib/hoodoo/client/endpoint/endpoints/not_found.rb +59 -0
  28. data/lib/hoodoo/client/headers.rb +269 -0
  29. data/lib/hoodoo/communicators.rb +23 -0
  30. data/lib/hoodoo/communicators/fast.rb +44 -0
  31. data/lib/hoodoo/communicators/pool.rb +601 -0
  32. data/lib/hoodoo/communicators/slow.rb +84 -0
  33. data/lib/hoodoo/data.rb +51 -0
  34. data/lib/hoodoo/data/resources/caller.rb +39 -0
  35. data/lib/hoodoo/data/resources/errors.rb +28 -0
  36. data/lib/hoodoo/data/resources/log.rb +31 -0
  37. data/lib/hoodoo/data/resources/session.rb +26 -0
  38. data/lib/hoodoo/data/types/error_primitive.rb +27 -0
  39. data/lib/hoodoo/data/types/permissions.rb +40 -0
  40. data/lib/hoodoo/data/types/permissions_defaults.rb +32 -0
  41. data/lib/hoodoo/data/types/permissions_full.rb +28 -0
  42. data/lib/hoodoo/data/types/permissions_resources.rb +31 -0
  43. data/lib/hoodoo/discovery.rb +20 -0
  44. data/lib/hoodoo/errors.rb +19 -0
  45. data/lib/hoodoo/errors/error_descriptions.rb +229 -0
  46. data/lib/hoodoo/errors/errors.rb +322 -0
  47. data/lib/hoodoo/generator.rb +139 -0
  48. data/lib/hoodoo/logger.rb +23 -0
  49. data/lib/hoodoo/logger/fast_writer.rb +27 -0
  50. data/lib/hoodoo/logger/flattener_mixin.rb +36 -0
  51. data/lib/hoodoo/logger/logger.rb +387 -0
  52. data/lib/hoodoo/logger/slow_writer.rb +49 -0
  53. data/lib/hoodoo/logger/writer_mixin.rb +52 -0
  54. data/lib/hoodoo/logger/writers/file_writer.rb +45 -0
  55. data/lib/hoodoo/logger/writers/log_entries_dot_com_writer.rb +64 -0
  56. data/lib/hoodoo/logger/writers/stream_writer.rb +43 -0
  57. data/lib/hoodoo/middleware.rb +33 -0
  58. data/lib/hoodoo/presenters.rb +45 -0
  59. data/lib/hoodoo/presenters/base.rb +281 -0
  60. data/lib/hoodoo/presenters/base_dsl.rb +519 -0
  61. data/lib/hoodoo/presenters/common_resource_fields.rb +31 -0
  62. data/lib/hoodoo/presenters/embedding.rb +232 -0
  63. data/lib/hoodoo/presenters/types/array.rb +118 -0
  64. data/lib/hoodoo/presenters/types/boolean.rb +26 -0
  65. data/lib/hoodoo/presenters/types/date.rb +26 -0
  66. data/lib/hoodoo/presenters/types/date_time.rb +26 -0
  67. data/lib/hoodoo/presenters/types/decimal.rb +47 -0
  68. data/lib/hoodoo/presenters/types/enum.rb +55 -0
  69. data/lib/hoodoo/presenters/types/field.rb +158 -0
  70. data/lib/hoodoo/presenters/types/float.rb +26 -0
  71. data/lib/hoodoo/presenters/types/hash.rb +361 -0
  72. data/lib/hoodoo/presenters/types/integer.rb +26 -0
  73. data/lib/hoodoo/presenters/types/object.rb +117 -0
  74. data/lib/hoodoo/presenters/types/string.rb +53 -0
  75. data/lib/hoodoo/presenters/types/tags.rb +24 -0
  76. data/lib/hoodoo/presenters/types/text.rb +26 -0
  77. data/lib/hoodoo/presenters/types/uuid.rb +54 -0
  78. data/lib/hoodoo/services.rb +34 -0
  79. data/lib/hoodoo/services/discovery/discoverers/by_consul.rb +66 -0
  80. data/lib/hoodoo/services/discovery/discoverers/by_convention.rb +173 -0
  81. data/lib/hoodoo/services/discovery/discoverers/by_drb/by_drb.rb +195 -0
  82. data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server.rb +166 -0
  83. data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server_start.rb +37 -0
  84. data/lib/hoodoo/services/discovery/discovery.rb +186 -0
  85. data/lib/hoodoo/services/discovery/results/for_amqp.rb +58 -0
  86. data/lib/hoodoo/services/discovery/results/for_http.rb +85 -0
  87. data/lib/hoodoo/services/discovery/results/for_local.rb +85 -0
  88. data/lib/hoodoo/services/discovery/results/for_remote.rb +57 -0
  89. data/lib/hoodoo/services/middleware/amqp_log_message.rb +186 -0
  90. data/lib/hoodoo/services/middleware/amqp_log_writer.rb +119 -0
  91. data/lib/hoodoo/services/middleware/endpoints/inter_resource_local.rb +130 -0
  92. data/lib/hoodoo/services/middleware/endpoints/inter_resource_remote.rb +202 -0
  93. data/lib/hoodoo/services/middleware/exception_reporting/base_reporter.rb +105 -0
  94. data/lib/hoodoo/services/middleware/exception_reporting/exception_reporting.rb +115 -0
  95. data/lib/hoodoo/services/middleware/exception_reporting/reporters/airbrake_reporter.rb +64 -0
  96. data/lib/hoodoo/services/middleware/exception_reporting/reporters/raygun_reporter.rb +63 -0
  97. data/lib/hoodoo/services/middleware/interaction.rb +127 -0
  98. data/lib/hoodoo/services/middleware/middleware.rb +2705 -0
  99. data/lib/hoodoo/services/middleware/rack_monkey_patch.rb +73 -0
  100. data/lib/hoodoo/services/services/context.rb +153 -0
  101. data/lib/hoodoo/services/services/implementation.rb +132 -0
  102. data/lib/hoodoo/services/services/interface.rb +934 -0
  103. data/lib/hoodoo/services/services/permissions.rb +250 -0
  104. data/lib/hoodoo/services/services/request.rb +189 -0
  105. data/lib/hoodoo/services/services/response.rb +316 -0
  106. data/lib/hoodoo/services/services/service.rb +141 -0
  107. data/lib/hoodoo/services/services/session.rb +729 -0
  108. data/lib/hoodoo/utilities.rb +12 -0
  109. data/lib/hoodoo/utilities/string_inquirer.rb +54 -0
  110. data/lib/hoodoo/utilities/utilities.rb +380 -0
  111. data/lib/hoodoo/utilities/uuid.rb +44 -0
  112. data/lib/hoodoo/version.rb +17 -0
  113. data/spec/active/active_record/base_spec.rb +57 -0
  114. data/spec/active/active_record/creator_spec.rb +88 -0
  115. data/spec/active/active_record/dated_spec.rb +248 -0
  116. data/spec/active/active_record/error_mapping_spec.rb +360 -0
  117. data/spec/active/active_record/finder_spec.rb +744 -0
  118. data/spec/active/active_record/search_helper_spec.rb +384 -0
  119. data/spec/active/active_record/secure_spec.rb +435 -0
  120. data/spec/active/active_record/support_spec.rb +225 -0
  121. data/spec/active/active_record/translated_spec.rb +19 -0
  122. data/spec/active/active_record/uuid_spec.rb +72 -0
  123. data/spec/active/active_record/writer_spec.rb +272 -0
  124. data/spec/alchemy/alchemy-amq.rb +33 -0
  125. data/spec/client/augmented_array_spec.rb +15 -0
  126. data/spec/client/augmented_base_spec.rb +50 -0
  127. data/spec/client/augmented_hash_spec.rb +15 -0
  128. data/spec/client/client_spec.rb +955 -0
  129. data/spec/client/endpoint/endpoint_spec.rb +70 -0
  130. data/spec/client/endpoint/endpoints/amqp_spec.rb +16 -0
  131. data/spec/client/endpoint/endpoints/auto_session_spec.rb +9 -0
  132. data/spec/client/endpoint/endpoints/http_based_spec.rb +9 -0
  133. data/spec/client/endpoint/endpoints/http_spec.rb +103 -0
  134. data/spec/client/endpoint/endpoints/not_found_spec.rb +35 -0
  135. data/spec/client/headers_spec.rb +172 -0
  136. data/spec/communicators/fast_spec.rb +9 -0
  137. data/spec/communicators/pool_spec.rb +339 -0
  138. data/spec/communicators/slow_spec.rb +15 -0
  139. data/spec/data/resources/caller_spec.rb +156 -0
  140. data/spec/data/resources/errors_spec.rb +22 -0
  141. data/spec/data/resources/log_spec.rb +20 -0
  142. data/spec/data/resources/session_spec.rb +15 -0
  143. data/spec/data/types/error_primitive_spec.rb +15 -0
  144. data/spec/data/types/permissions_defaults_spec.rb +25 -0
  145. data/spec/data/types/permissions_full_spec.rb +44 -0
  146. data/spec/data/types/permissions_resources_spec.rb +34 -0
  147. data/spec/data/types/permissions_spec.rb +37 -0
  148. data/spec/errors/error_descriptions_spec.rb +98 -0
  149. data/spec/errors/errors_spec.rb +346 -0
  150. data/spec/integration/service_actions_spec.rb +112 -0
  151. data/spec/logger/fast_writer_spec.rb +18 -0
  152. data/spec/logger/logger_spec.rb +259 -0
  153. data/spec/logger/slow_writer_spec.rb +144 -0
  154. data/spec/logger/writers/file_writer_spec.rb +37 -0
  155. data/spec/logger/writers/log_entries_dot_com_writer_spec.rb +29 -0
  156. data/spec/logger/writers/stream_writer_spec.rb +38 -0
  157. data/spec/presenters/base_dsl_spec.rb +111 -0
  158. data/spec/presenters/base_spec.rb +871 -0
  159. data/spec/presenters/common_resource_fields_spec.rb +30 -0
  160. data/spec/presenters/embedding_spec.rb +87 -0
  161. data/spec/presenters/types/array_spec.rb +249 -0
  162. data/spec/presenters/types/boolean_spec.rb +51 -0
  163. data/spec/presenters/types/date_spec.rb +57 -0
  164. data/spec/presenters/types/date_time_spec.rb +59 -0
  165. data/spec/presenters/types/decimal_spec.rb +58 -0
  166. data/spec/presenters/types/enum_spec.rb +71 -0
  167. data/spec/presenters/types/field_spec.rb +77 -0
  168. data/spec/presenters/types/float_spec.rb +50 -0
  169. data/spec/presenters/types/hash_spec.rb +1069 -0
  170. data/spec/presenters/types/integer_spec.rb +50 -0
  171. data/spec/presenters/types/object_spec.rb +177 -0
  172. data/spec/presenters/types/string_spec.rb +65 -0
  173. data/spec/presenters/types/tags_spec.rb +56 -0
  174. data/spec/presenters/types/text_spec.rb +50 -0
  175. data/spec/presenters/types/uuid_spec.rb +46 -0
  176. data/spec/presenters/walk_spec.rb +198 -0
  177. data/spec/services/discovery/discoverers/by_consul_spec.rb +29 -0
  178. data/spec/services/discovery/discoverers/by_convention_spec.rb +67 -0
  179. data/spec/services/discovery/discoverers/by_drb/by_drb_spec.rb +80 -0
  180. data/spec/services/discovery/discoverers/by_drb/drb_server_spec.rb +205 -0
  181. data/spec/services/discovery/discovery_spec.rb +73 -0
  182. data/spec/services/discovery/results/for_amqp_spec.rb +17 -0
  183. data/spec/services/discovery/results/for_http_spec.rb +37 -0
  184. data/spec/services/discovery/results/for_local_spec.rb +21 -0
  185. data/spec/services/discovery/results/for_remote_spec.rb +15 -0
  186. data/spec/services/middleware/amqp_log_message_spec.rb +60 -0
  187. data/spec/services/middleware/amqp_log_writer_spec.rb +95 -0
  188. data/spec/services/middleware/endpoints/inter_resource_local_spec.rb +9 -0
  189. data/spec/services/middleware/endpoints/inter_resource_remote_spec.rb +9 -0
  190. data/spec/services/middleware/exception_reporting/base_reporter_spec.rb +16 -0
  191. data/spec/services/middleware/exception_reporting/exception_reporting_spec.rb +92 -0
  192. data/spec/services/middleware/exception_reporting/reporters/airbrake_reporter_spec.rb +24 -0
  193. data/spec/services/middleware/exception_reporting/reporters/raygun_reporter_spec.rb +23 -0
  194. data/spec/services/middleware/middleware_cors_spec.rb +93 -0
  195. data/spec/services/middleware/middleware_create_update_spec.rb +489 -0
  196. data/spec/services/middleware/middleware_dated_at_spec.rb +186 -0
  197. data/spec/services/middleware/middleware_exotic_communication_spec.rb +560 -0
  198. data/spec/services/middleware/middleware_logging_spec.rb +356 -0
  199. data/spec/services/middleware/middleware_multi_local_spec.rb +1094 -0
  200. data/spec/services/middleware/middleware_multi_remote_spec.rb +1440 -0
  201. data/spec/services/middleware/middleware_permissions_spec.rb +1014 -0
  202. data/spec/services/middleware/middleware_public_spec.rb +238 -0
  203. data/spec/services/middleware/middleware_spec.rb +1569 -0
  204. data/spec/services/middleware/string_inquirer_spec.rb +30 -0
  205. data/spec/services/services/application_spec.rb +74 -0
  206. data/spec/services/services/context_spec.rb +48 -0
  207. data/spec/services/services/implementation_spec.rb +45 -0
  208. data/spec/services/services/interface_spec.rb +262 -0
  209. data/spec/services/services/permissions_spec.rb +249 -0
  210. data/spec/services/services/request_spec.rb +95 -0
  211. data/spec/services/services/response_spec.rb +250 -0
  212. data/spec/services/services/session_spec.rb +432 -0
  213. data/spec/spec_helper.rb +298 -0
  214. data/spec/utilities/utilities_spec.rb +537 -0
  215. data/spec/utilities/uuid_spec.rb +20 -0
  216. metadata +615 -0
@@ -0,0 +1,17 @@
1
+ ########################################################################
2
+ # File:: version.rb
3
+ # (C):: Loyalty New Zealand 2015
4
+ #
5
+ # Purpose:: Declare this gem's version number.
6
+ # ----------------------------------------------------------------------
7
+ # 27-Jan-2015 (ADH): Created (for gem under name Hoodoo).
8
+ ########################################################################
9
+
10
+ module Hoodoo
11
+
12
+ # The Hoodoo gem version. If this changes, ensure that the date in
13
+ # "hoodoo.gemspec" is correct and run "bundle install" (or "update").
14
+ #
15
+ VERSION = '1.0.2'
16
+
17
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+ require 'active_record'
3
+
4
+ describe Hoodoo::ActiveRecord::Base do
5
+ before :all do
6
+ spec_helper_silence_stdout() do
7
+ tblname = :r_spec_model_base_tests
8
+
9
+ ActiveRecord::Migration.create_table( tblname, :id => false ) do | t |
10
+ t.string( :id, :limit => 32, :null => false )
11
+ end
12
+
13
+ ActiveRecord::Migration.add_index( tblname, :id, :unique => true )
14
+
15
+ class RSpecModelBaseTest < Hoodoo::ActiveRecord::Base
16
+ end
17
+ end
18
+ end
19
+
20
+ it 'has security capability' do
21
+ expect( RSpecModelBaseTest ).to respond_to( :secure )
22
+ end
23
+
24
+ it 'has dating capability' do
25
+ expect( RSpecModelBaseTest ).to respond_to( :dated )
26
+ end
27
+
28
+ it 'has internationalisation capability' do
29
+ expect( RSpecModelBaseTest ).to respond_to( :translated )
30
+ end
31
+
32
+ it 'finds things' do
33
+ m = RSpecModelBaseTest.new
34
+ m.save
35
+ expect( RSpecModelBaseTest.acquire( m.id ) ).to_not be_nil
36
+ end
37
+
38
+ it 'gains a UUID' do
39
+ m = RSpecModelBaseTest.new
40
+ m.save
41
+
42
+ expect( m.id ).to_not be_nil
43
+ expect( Hoodoo::UUID.valid?( m.id ) ).to eq( true )
44
+ end
45
+
46
+ it 'has creator capability' do
47
+ expect( RSpecModelBaseTest ).to respond_to( :new_in )
48
+ end
49
+
50
+ it 'has writer capability' do
51
+ expect( RSpecModelBaseTest ).to respond_to( :persist_in )
52
+ end
53
+
54
+ it 'supports error mapping' do
55
+ expect( RSpecModelBaseTest.new.platform_errors.has_errors? ).to eq( false )
56
+ end
57
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+ require 'active_record'
3
+
4
+ describe Hoodoo::ActiveRecord::Creator do
5
+ before :all do
6
+ spec_helper_silence_stdout() do
7
+ ActiveRecord::Migration.create_table( :r_spec_model_creator_tests, :id => :string ) do | t |
8
+ t.text :code
9
+ t.text :field_one
10
+
11
+ t.timestamps
12
+ end
13
+ end
14
+
15
+ class RSpecModelCreatorTest < ActiveRecord::Base
16
+ include Hoodoo::ActiveRecord::Creator
17
+ include Hoodoo::ActiveRecord::Dated
18
+ end
19
+ end
20
+
21
+ # ==========================================================================
22
+
23
+ context 'new_in' do
24
+ before :each do
25
+
26
+ # Get a good-enough-for-test interaction which has a context
27
+ # that contains a Session we can modify.
28
+
29
+ @interaction = Hoodoo::Services::Middleware::Interaction.new( {}, nil )
30
+ @interaction.context = Hoodoo::Services::Context.new(
31
+ Hoodoo::Services::Session.new,
32
+ @interaction.context.request,
33
+ @interaction.context.response,
34
+ @interaction
35
+ )
36
+
37
+ @context = @interaction.context
38
+ @session = @interaction.context.session
39
+ end
40
+
41
+ it 'creates with no special values' do
42
+ instance = RSpecModelCreatorTest.new_in( @context )
43
+
44
+ expect( instance.created_at ).to be_nil
45
+ expect( instance.updated_at ).to be_nil
46
+ end
47
+
48
+ it 'creates with specified dated-from value' do
49
+ time = Time.now.iso8601
50
+ @context.request.dated_from = time
51
+
52
+ instance = RSpecModelCreatorTest.new_in( @context )
53
+
54
+ expect( instance.created_at.iso8601 ).to eq( time )
55
+ expect( instance.updated_at.iso8601 ).to eq( time )
56
+ end
57
+
58
+ it 'creates with provided attributes' do
59
+ instance = RSpecModelCreatorTest.new_in( @context, code: 'code', field_one: 'one' )
60
+
61
+ expect( instance.code ).to eq( 'code' )
62
+ expect( instance.field_one ).to eq( 'one' )
63
+ end
64
+
65
+ it 'creates with a block' do
66
+ instance = RSpecModelCreatorTest.new_in( @context ) do | i |
67
+ i.code = 'code'
68
+ i.field_one = 'one'
69
+ end
70
+
71
+ expect( instance.code ).to eq( 'code' )
72
+ expect( instance.field_one ).to eq( 'one' )
73
+ end
74
+
75
+ # Technically ActiveRecord documentation seems to indicate this is an
76
+ # either-or choice, but the code certainly supports both and it isn't
77
+ # *explicitly* stated as such, so we assume both can be mixed here.
78
+ #
79
+ it 'creates with provided attributes and a block' do
80
+ instance = RSpecModelCreatorTest.new_in( @context, code: 'code' ) do | i |
81
+ i.field_one = 'one'
82
+ end
83
+
84
+ expect( instance.code ).to eq( 'code' )
85
+ expect( instance.field_one ).to eq( 'one' )
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,248 @@
1
+ require 'spec_helper'
2
+ require 'active_record'
3
+
4
+ describe Hoodoo::ActiveRecord::Dated do
5
+
6
+ before :all do
7
+ spec_helper_silence_stdout() do
8
+
9
+ ActiveRecord::Migration.create_table( :r_spec_model_effective_date_tests, :id => false ) do | t |
10
+ t.text :id, :null => false
11
+ t.text :data
12
+ t.timestamps
13
+ end
14
+
15
+ ActiveRecord::Migration.create_table( :r_spec_model_effective_date_tests_history_entries, :id => false ) do | t |
16
+ t.text :id, :null => false
17
+ t.text :uuid, :null => false
18
+ t.text :data
19
+ t.datetime :effective_start, :null => false
20
+ t.datetime :effective_end, :null => false
21
+ t.timestamps
22
+ end
23
+
24
+ class RSpecModelEffectiveDateTest < ActiveRecord::Base
25
+ include Hoodoo::ActiveRecord::Dated
26
+ dating_enabled()
27
+ end
28
+
29
+ ActiveRecord::Migration.create_table( :r_spec_model_effective_date_test_overrides, :id => false ) do | t |
30
+ t.text :id, :null => false
31
+ t.text :data
32
+ t.timestamps
33
+ end
34
+
35
+ ActiveRecord::Migration.create_table( :r_spec_model_effective_date_history_entries, :id => false ) do | t |
36
+ t.text :id, :null => false
37
+ t.text :uuid, :null => false
38
+ t.text :data
39
+ t.datetime :effective_start, :null => false
40
+ t.datetime :effective_end, :null => false
41
+ t.timestamps
42
+ end
43
+
44
+ class RSpecModelEffectiveDateTestOverride < ActiveRecord::Base
45
+ include Hoodoo::ActiveRecord::Dated
46
+
47
+ dating_enabled( :history_table_name => :r_spec_model_effective_date_history_entries )
48
+ end
49
+ end
50
+ end
51
+
52
+ shared_examples Hoodoo::ActiveRecord::Dated do
53
+
54
+ before( :all ) do
55
+
56
+ # Create some examples data for finding. The data has two different UUIDs
57
+ # which I'll referer to as A and B. The following tables contain the
58
+ # historical and current records separately with their attributes.
59
+ #
60
+ # Historical:
61
+ # -------------------------------------------------------------------
62
+ # uuid | data | created_at | effective_end | effective_start |
63
+ # -------------------------------------------------------------------
64
+ # A | "one" | now - 5 hours | now - 3 hours | now - 5 hours |
65
+ # B | "two" | now - 4 hours | now - 2 hours | now - 4 hours |
66
+ # A | "three" | now - 5 hours | now - 1 hour | now - 3 hours |
67
+ # B | "four" | now - 4 hours | now | now - 2 hour |
68
+ #
69
+ # Current:
70
+ # --------------------------------
71
+ # uuid | data | created_at |
72
+ # --------------------------------
73
+ # B | "five" | now - 4 hours |
74
+ # A | "six" | now - 5 hours |
75
+ #
76
+
77
+ @uuid_a = Hoodoo::UUID.generate
78
+ @uuid_b = Hoodoo::UUID.generate
79
+
80
+ @now = Time.now.utc
81
+
82
+ # uuid, data, created_at, effective_end, effective_start
83
+ [
84
+ [ @uuid_a, "one", @now - 5.hours, @now - 3.hours, @now - 5.hours ],
85
+ [ @uuid_b, "two", @now - 4.hours, @now - 2.hours, @now - 4.hours ],
86
+ [ @uuid_a, "three", @now - 5.hours, @now - 1.hour, @now - 3.hours ],
87
+ [ @uuid_b, "four", @now - 4.hours, @now, @now - 2.hours ]
88
+ ].each do | row_data |
89
+ model_klass.dated_with.new( {
90
+ :id => row_data[ 0 ] + "-" + row_data[ 3 ].iso8601,
91
+ :uuid => row_data[ 0 ],
92
+ :data => row_data[ 1 ],
93
+ :created_at => row_data[ 2 ],
94
+ :effective_end => row_data[ 3 ],
95
+ :effective_start => row_data[ 4 ]
96
+ } ).save!
97
+ end
98
+
99
+ # uuid, data, created_at, updated_at
100
+ [
101
+ [ @uuid_b, "five", @now - 4.hours, @now ],
102
+ [ @uuid_a, "six", @now - 5.hours, @now - 1.hour ]
103
+ ].each do | row_data |
104
+ model_klass.new( {
105
+ :id => row_data[ 0 ],
106
+ :data => row_data[ 1 ],
107
+ :created_at => row_data[ 2 ],
108
+ :updated_at => row_data[ 3 ]
109
+ } ).save!
110
+ end
111
+
112
+ end
113
+
114
+ context '.dated_at' do
115
+ it 'returns counts correctly' do
116
+ expect( model_klass.dated_at( @now - 10.hours ).count ).to be 0
117
+ expect( model_klass.dated_at( @now ).count ).to be 2
118
+ end
119
+
120
+ def test_expectation( time, expected_data )
121
+ expect( model_klass.dated_at( time ).pluck( :data ) ).to match_array( expected_data )
122
+ end
123
+
124
+ it 'returns no records before any were effective' do
125
+ test_expectation( @now - 10.hours, [] )
126
+ end
127
+
128
+ it 'returns records that used to be effective starting at past time' do
129
+ test_expectation( @now - 5.hours, [ "one" ] )
130
+ test_expectation( @now - 4.hours, [ "one", "two" ] )
131
+ test_expectation( @now - 3.hours, [ "two", "three" ] )
132
+ test_expectation( @now - 2.hours, [ "three", "four" ] )
133
+ test_expectation( @now - 1.hour, [ "four", "six" ] )
134
+ end
135
+
136
+ it 'returns records that are effective now' do
137
+ test_expectation( @now, [ "five", "six" ] )
138
+ end
139
+
140
+ it 'works with further filtering' do
141
+ expect( model_klass.dated_at( @now ).where( :id => @uuid_a ).pluck( :data ) ).to eq( [ "six" ] )
142
+ end
143
+
144
+ end
145
+
146
+ context '.dated' do
147
+ it 'returns counts correctly' do
148
+ # The contents of the Context are irrelevant aside from the fact that it
149
+ # needs a request to store the dated_at value.
150
+ request = Hoodoo::Services::Request.new
151
+ context = Hoodoo::Services::Context.new( nil, request, nil, nil )
152
+
153
+ context.request.dated_at = @now - 10.hours
154
+ expect( model_klass.dated( context ).count ).to be 0
155
+
156
+ context.request.dated_at = @now
157
+ expect( model_klass.dated( context ).count ).to be 2
158
+ end
159
+
160
+ def test_expectation( time, expected_data )
161
+ # The contents of the Context are irrelevant aside from the fact that it
162
+ # needs a request to store the dated_at value.
163
+ request = Hoodoo::Services::Request.new
164
+ context = Hoodoo::Services::Context.new( nil, request, nil, nil )
165
+ context.request.dated_at = time
166
+
167
+ expect( model_klass.dated( context ).pluck( :data ) ).to match_array( expected_data )
168
+ end
169
+
170
+ it 'returns no records before any were effective' do
171
+ test_expectation( @now - 10.hours, [] )
172
+ end
173
+
174
+ it 'returns records that used to be effective starting at past time' do
175
+ test_expectation( @now - 5.hours, [ "one" ] )
176
+ test_expectation( @now - 4.hours, [ "one", "two" ] )
177
+ test_expectation( @now - 3.hours, [ "two", "three" ] )
178
+ test_expectation( @now - 2.hours, [ "three", "four" ] )
179
+ test_expectation( @now - 1.hour, [ "four", "six" ] )
180
+ end
181
+
182
+ it 'returns records that are effective now' do
183
+ test_expectation( @now, [ "five", "six" ] )
184
+ end
185
+
186
+ it 'works with further filtering' do
187
+
188
+ # The contents of the Context are irrelevant aside from the fact that it
189
+ # needs a request to store the dated_at value.
190
+ request = Hoodoo::Services::Request.new
191
+ context = Hoodoo::Services::Context.new( nil, request, nil, nil )
192
+ context.request.dated_at = @now
193
+
194
+ expect( model_klass.dated( context ).where( :id => @uuid_a ).pluck( :data ) ).to eq( [ "six" ] )
195
+ end
196
+
197
+ it 'works with dating last' do
198
+
199
+ # The contents of the Context are irrelevant aside from the fact that it
200
+ # needs a request to store the dated_at value.
201
+ request = Hoodoo::Services::Request.new
202
+ context = Hoodoo::Services::Context.new( nil, request, nil, nil )
203
+ context.request.dated_at = @now
204
+
205
+ expect( model_klass.where( :id => @uuid_a ).dated( context ).pluck( :data ) ).to eq( [ "six" ] )
206
+ end
207
+
208
+ end
209
+
210
+ context '.dated_historical_and_current' do
211
+
212
+ it 'returns counts correctly' do
213
+ expect( model_klass.dated_historical_and_current.count ).to be 6
214
+ end
215
+
216
+ it 'lists all historical and current records' do
217
+ expect( model_klass.dated_historical_and_current.pluck( :data ) ).to match_array( [ 'one', 'two', 'three', 'four', 'five', 'six' ] )
218
+ end
219
+
220
+ end
221
+
222
+ end
223
+
224
+ context "using default effective dating config" do
225
+
226
+ # Must be defined as a method rather than using a let statement as let
227
+ # statement values cannot be used in before blocks.
228
+ def model_klass
229
+ RSpecModelEffectiveDateTest
230
+ end
231
+
232
+ it_behaves_like Hoodoo::ActiveRecord::Dated
233
+
234
+ end
235
+
236
+ context "overriding history table name" do
237
+
238
+ # Must be defined as a method rather than using a let statement as let
239
+ # statement values cannot be used in before blocks.
240
+ def model_klass
241
+ RSpecModelEffectiveDateTestOverride
242
+ end
243
+
244
+ it_behaves_like Hoodoo::ActiveRecord::Dated
245
+
246
+ end
247
+
248
+ end
@@ -0,0 +1,360 @@
1
+ require 'spec_helper'
2
+ require 'active_record'
3
+
4
+ describe Hoodoo::ActiveRecord::ErrorMapping do
5
+ before :all do
6
+ spec_helper_silence_stdout() do
7
+ ActiveRecord::Migration.create_table( :r_spec_model_error_mapping_tests ) do | t |
8
+ t.string :uuid
9
+ t.boolean :boolean
10
+ t.date :date
11
+ t.datetime :datetime
12
+ t.decimal :decimal, :precision => 5, :scale => 2
13
+ t.float :float
14
+ t.integer :integer
15
+ t.string :string, :limit => 16
16
+ t.text :text
17
+ t.time :time
18
+ t.text :array, :array => true
19
+ end
20
+
21
+ ActiveRecord::Migration.create_table( :r_spec_model_associated_error_mapping_tests ) do | t |
22
+ t.string :other_string
23
+
24
+ # For 'has_many' - can't use "t.reference" as the generated
25
+ # column name is too long!
26
+ #
27
+ t.integer :many_id
28
+ t.index :many_id
29
+ end
30
+
31
+ class RSpecModelErrorMappingTest < ActiveRecord::Base
32
+ include Hoodoo::ActiveRecord::ErrorMapping
33
+
34
+ has_many :r_spec_model_associated_error_mapping_tests,
35
+ :foreign_key => :many_id,
36
+ :class_name => :RSpecModelAssociatedErrorMappingTest
37
+
38
+ accepts_nested_attributes_for :r_spec_model_associated_error_mapping_tests
39
+
40
+ validates_presence_of :boolean,
41
+ :date,
42
+ :datetime,
43
+ :decimal,
44
+ :float,
45
+ :integer,
46
+ :string,
47
+ :text,
48
+ :time,
49
+ :array
50
+
51
+ validates_uniqueness_of :integer
52
+ validates :string, :length => { :maximum => 16 }
53
+ validates :uuid, :uuid => true
54
+
55
+ validate do
56
+ if string == 'magic'
57
+ errors.add( 'this.thing', 'is not a column' )
58
+ end
59
+ end
60
+ end
61
+
62
+ class RSpecModelAssociatedErrorMappingTest < ActiveRecord::Base
63
+ belongs_to :r_spec_model_error_mapping_test,
64
+ :foreign_key => :many_id,
65
+ :class_name => :RSpecModelErrorMappingTest
66
+
67
+ validates :other_string, :length => { :maximum => 6 }
68
+ end
69
+
70
+ class RSpecModelErrorMappingTestBase < ActiveRecord::Base
71
+ self.table_name = RSpecModelErrorMappingTest.table_name
72
+
73
+ include Hoodoo::ActiveRecord::ErrorMapping
74
+
75
+ validate do | instance |
76
+ instance.errors.add( :base, 'this is a test' )
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ before :each do
83
+ @errors = Hoodoo::Errors.new( Hoodoo::ErrorDescriptions.new )
84
+ end
85
+
86
+ let( :valid_model ) {
87
+ RSpecModelErrorMappingTest.new( {
88
+ :uuid => Hoodoo::UUID.generate(),
89
+ :boolean => true,
90
+ :date => Time.now,
91
+ :datetime => Time.now,
92
+ :decimal => 2.3,
93
+ :float => 2.3,
94
+ :integer => 42,
95
+ :string => "hello",
96
+ :text => "hello",
97
+ :time => Time.now,
98
+ :array => [ 'hello' ]
99
+ } )
100
+ }
101
+
102
+ it 'auto-validates and maps errors correctly' do
103
+
104
+ m = RSpecModelErrorMappingTest.new( :uuid => 'not a valid UUID' )
105
+ expect( m.adds_errors_to?( @errors ) ).to eq( true )
106
+
107
+ expect( @errors.errors ).to eq( [
108
+ {
109
+ "code" => "generic.invalid_boolean",
110
+ "message" => "can't be blank",
111
+ "reference" => "boolean"
112
+ },
113
+ {
114
+ "code" => "generic.invalid_date",
115
+ "message" => "can't be blank",
116
+ "reference" => "date"
117
+ },
118
+ {
119
+ "code" => "generic.invalid_datetime",
120
+ "message" => "can't be blank",
121
+ "reference" => "datetime"
122
+ },
123
+ {
124
+ "code" => "generic.invalid_decimal",
125
+ "message" => "can't be blank",
126
+ "reference" => "decimal"
127
+ },
128
+ {
129
+ "code" => "generic.invalid_float",
130
+ "message" => "can't be blank",
131
+ "reference" => "float"
132
+ },
133
+ {
134
+ "code" => "generic.invalid_integer",
135
+ "message" => "can't be blank",
136
+ "reference" => "integer"
137
+ },
138
+ {
139
+ "code" => "generic.invalid_string",
140
+ "message" => "can't be blank",
141
+ "reference" => "string"
142
+ },
143
+ {
144
+ "code" => "generic.invalid_string",
145
+ "message" => "can't be blank",
146
+ "reference" => "text"
147
+ },
148
+ {
149
+ "code" => "generic.invalid_time",
150
+ "message" => "can't be blank",
151
+ "reference" => "time"
152
+ },
153
+ {
154
+ "code" => "generic.invalid_array",
155
+ "message" => "can't be blank",
156
+ "reference" => "array"
157
+ },
158
+
159
+ # Checks that custom UUID validator is working.
160
+
161
+ {
162
+ "code" => "generic.invalid_uuid",
163
+ "message" => "is invalid",
164
+ "reference" => "uuid"
165
+ }
166
+ ] )
167
+ end
168
+
169
+ it 'maps "base" errors correctly' do
170
+ m = RSpecModelErrorMappingTestBase.new
171
+
172
+ expect( m.adds_errors_to?( @errors ) ).to eq( true )
173
+ expect( @errors.errors ).to eq( [
174
+ {
175
+ "code" => "generic.invalid_parameters",
176
+ "message" => "this is a test",
177
+ "reference" => "model instance"
178
+ }
179
+ ] )
180
+ end
181
+
182
+ it 'handles varying validation types' do
183
+ m = RSpecModelErrorMappingTest.new( {
184
+ :boolean => true,
185
+ :date => Time.now,
186
+ :datetime => Time.now,
187
+ :decimal => 2.3,
188
+ :float => 2.3,
189
+ :integer => 42,
190
+ :string => "hello - this is far too long for the maximum field length",
191
+ :text => "hello",
192
+ :time => Time.now,
193
+ :array => [ 'hello' ]
194
+ } )
195
+
196
+ m.adds_errors_to?( @errors )
197
+ expect( @errors.errors ).to eq( [
198
+ {
199
+ "code" => "generic.invalid_string",
200
+ "message" => "is too long (maximum is 16 characters)",
201
+ "reference" => "string"
202
+ }
203
+ ] )
204
+ end
205
+
206
+ it 'handles varying validation types via the alternative interface' do
207
+ m = RSpecModelErrorMappingTest.new( {
208
+ :boolean => true,
209
+ :date => Time.now,
210
+ :datetime => Time.now,
211
+ :decimal => 2.3,
212
+ :float => 2.3,
213
+ :integer => 42,
214
+ :string => "hello - this is far too long for the maximum field length",
215
+ :text => "hello",
216
+ :time => Time.now,
217
+ :array => [ 'hello' ]
218
+ } )
219
+
220
+ errors = m.platform_errors
221
+ expect( errors.errors ).to eq( [
222
+ {
223
+ "code" => "generic.invalid_string",
224
+ "message" => "is too long (maximum is 16 characters)",
225
+ "reference" => "string"
226
+ }
227
+ ] )
228
+ end
229
+
230
+ it 'handles arrays' do
231
+ m = RSpecModelErrorMappingTest.new( {
232
+ :boolean => true,
233
+ :date => Time.now,
234
+ :datetime => Time.now,
235
+ :decimal => 2.3,
236
+ :float => 2.3,
237
+ :integer => 42,
238
+ :string => 'hello',
239
+ :text => 'world',
240
+ :time => Time.now,
241
+ :array => []
242
+ } )
243
+
244
+ array_col = RSpecModelErrorMappingTest.columns_hash[ 'array' ]
245
+ expect( array_col ).to receive( :array ).once.and_return( true )
246
+
247
+ m.adds_errors_to?( @errors )
248
+
249
+ expect( @errors.errors ).to eq( [
250
+ {
251
+ "code" => "generic.invalid_array",
252
+ "message" => "can't be blank",
253
+ "reference" => "array"
254
+ }
255
+ ] )
256
+ end
257
+
258
+ it 'maps duplicates' do
259
+ m = valid_model
260
+
261
+ m.adds_errors_to?( @errors )
262
+ expect( @errors.errors ).to eq( [] )
263
+ m.save!
264
+
265
+ n = m.dup
266
+ n.adds_errors_to?( @errors )
267
+ expect( @errors.errors ).to eq( [
268
+ {
269
+ "code" => "generic.invalid_duplication",
270
+ "message" => "has already been taken",
271
+ "reference" => "integer"
272
+ }
273
+ ] )
274
+ end
275
+
276
+ it 'handles downgrade to generic error code' do
277
+
278
+ class LocalHackableErrors < Hoodoo::ErrorDescriptions
279
+ end
280
+
281
+ @errors = Hoodoo::Errors.new( Hoodoo::ErrorDescriptions.new )
282
+
283
+ # We have to hack to test this...
284
+ #
285
+ desc = @errors.descriptions.instance_variable_get( '@descriptions' )
286
+ desc.delete( 'generic.invalid_boolean' )
287
+ desc.delete( 'generic.invalid_date' )
288
+
289
+ m = RSpecModelErrorMappingTest.new( {
290
+ :datetime => Time.now,
291
+ :decimal => 2.3,
292
+ :float => 2.3,
293
+ :integer => 42,
294
+ :string => "hello",
295
+ :text => "hello",
296
+ :time => Time.now,
297
+ :array => [ 'hello' ]
298
+ } )
299
+
300
+ m.adds_errors_to?( @errors )
301
+
302
+ expect( @errors.errors ).to eq( [
303
+ {
304
+ "code" => "generic.invalid_parameters",
305
+ "message" => "can't be blank",
306
+ "reference" => "boolean"
307
+ },
308
+ {
309
+ "code" => "generic.invalid_parameters",
310
+ "message" => "can't be blank",
311
+ "reference" => "date"
312
+ }
313
+ ] )
314
+ end
315
+
316
+ it 'adds nothing if the model is valid' do
317
+ m = valid_model
318
+
319
+ expect( m.adds_errors_to?( @errors ) ).to eq( false )
320
+ expect( @errors.errors ).to eq( [] )
321
+
322
+ expect { m.save! }.to_not raise_error
323
+ end
324
+
325
+ it 'has-many associations are dereferenced' do
326
+ attrs = valid_model.attributes
327
+ attrs[ 'r_spec_model_associated_error_mapping_tests_attributes' ] = [
328
+ { :other_string => 'ok 1' },
329
+ { :other_string => 'ok 2' },
330
+ { :other_string => 'too long, so fails validation' }
331
+ ]
332
+
333
+ m = RSpecModelErrorMappingTest.new( attrs )
334
+
335
+ m.adds_errors_to?( @errors )
336
+
337
+ expect( @errors.errors ).to eq( [
338
+ {
339
+ "code" => "generic.invalid_string",
340
+ "message" => "is too long (maximum is 6 characters)",
341
+ "reference" => "r_spec_model_associated_error_mapping_tests.other_string"
342
+ }
343
+ ] )
344
+ end
345
+
346
+ it 'works with dot-separated non-attribute paths' do
347
+ m = valid_model
348
+ m.string = 'magic'
349
+
350
+ m.adds_errors_to?( @errors )
351
+
352
+ expect( @errors.errors ).to eq( [
353
+ {
354
+ "code" => "generic.invalid_parameters",
355
+ "message" => "is not a column",
356
+ "reference" => "this.thing"
357
+ }
358
+ ] )
359
+ end
360
+ end