hoodoo 1.0.2

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 (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,346 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hoodoo::Errors do
4
+ before do
5
+ @desc = Hoodoo::ErrorDescriptions.new( :test_domain ) do
6
+ error 'http_345_no_references', status: 345, 'message' => '345 message'
7
+ error 'http_456_has_reference', status: 456, 'message' => '456 message', 'reference' => [ :ref1 ]
8
+ error 'http_567_has_references', status: 567, 'message' => '567 message', 'reference' => [ :ref2, :ref3, :ref4 ]
9
+ end
10
+
11
+ @errors = Hoodoo::Errors.new(@desc)
12
+ end
13
+
14
+ describe '#initialize' do
15
+ it 'should have correct descriptions' do
16
+
17
+ # Read the ivars to compare objects. The "@descriptions" variable in an
18
+ # ErrorDescriptions instance gives its descriptions hash. The same-named
19
+ # variable in the Errors instance gives the ErrorDescriptions instances,
20
+ # so the chained "instance_variable_get" call in the second and third
21
+ # test is correct.
22
+
23
+ expect(Hoodoo::Errors::DEFAULT_ERROR_DESCRIPTIONS.instance_variable_get('@descriptions')).to eq(Hoodoo::ErrorDescriptions.new().instance_variable_get('@descriptions'))
24
+ expect(Hoodoo::Errors.new().instance_variable_get('@descriptions').instance_variable_get('@descriptions')).to eq(Hoodoo::ErrorDescriptions.new().instance_variable_get('@descriptions'))
25
+ expect(@errors.instance_variable_get('@descriptions').instance_variable_get('@descriptions')).to eq(@desc.instance_variable_get('@descriptions'))
26
+ end
27
+
28
+ it 'should have a UUID, empty errors and a 200 code' do
29
+ expect(@errors.uuid.size).to eq(32)
30
+ expect(@errors.errors).to be_empty
31
+ expect(@errors.http_status_code).to eq(200)
32
+ end
33
+
34
+ it 'should inspect elegantly' do
35
+ @errors.add_error('platform.malformed')
36
+ expect(@errors.inspect).to eq( '[{"code"=>"platform.malformed", "message"=>"Malformed request"}]' )
37
+ end
38
+ end
39
+
40
+ describe '#add_error, #has_errors?' do
41
+ it 'should let me add a generic error and tell me it was added' do
42
+ expect(@errors.has_errors?).to eq(false)
43
+ @errors.add_error('platform.malformed')
44
+ expect(@errors.has_errors?).to eq(true)
45
+ expect(@errors.errors).to_not be_empty
46
+ end
47
+
48
+ it 'should complain about unknown error codes' do
49
+ expect {
50
+ @errors.add_error('imaginary')
51
+ }.to raise_error(Hoodoo::Errors::UnknownCode, "In \#add_error: Unknown error code 'imaginary'")
52
+ end
53
+
54
+ it 'should let me add simple custom errors' do
55
+ expect {
56
+ @errors.add_error('test_domain.http_345_no_references')
57
+ @errors.add_error('test_domain.http_345_no_references', 'message' => 'foo 1')
58
+ @errors.add_error('test_domain.http_345_no_references', 'message' => 'foo 2', 'reference' => { :bar => 'baz', :baz => 'foo' })
59
+ }.to_not raise_error
60
+
61
+ expect(@errors.errors[-3]).to eq({'code' => 'test_domain.http_345_no_references', 'message' => '345 message'})
62
+ expect(@errors.errors[-2]).to eq({'code' => 'test_domain.http_345_no_references', 'message' => 'foo 1'})
63
+ expect(@errors.errors[-1]).to eq({'code' => 'test_domain.http_345_no_references', 'message' => 'foo 2', 'reference' => 'baz,foo'})
64
+ end
65
+
66
+ it 'should complain about missing fields' do
67
+ expect {
68
+ @errors.add_error('test_domain.http_456_has_reference')
69
+ }.to raise_error(Hoodoo::Errors::MissingReferenceData, "In \#add_error: Reference hash missing required keys: 'ref1'")
70
+
71
+ expect {
72
+ @errors.add_error('test_domain.http_567_has_references')
73
+ }.to raise_error(Hoodoo::Errors::MissingReferenceData, "In \#add_error: Reference hash missing required keys: 'ref2, ref3, ref4'")
74
+
75
+ expect {
76
+ @errors.add_error('test_domain.http_567_has_references', 'reference' => {:ref3 => "hello"})
77
+ }.to raise_error(Hoodoo::Errors::MissingReferenceData, "In \#add_error: Reference hash missing required keys: 'ref2, ref4'")
78
+ end
79
+
80
+ it 'should let me specify mandatory reference data' do
81
+ expect {
82
+ @errors.add_error('test_domain.http_456_has_reference', 'reference' => {:ref1 => 'ref1-data'})
83
+ }.to_not raise_error
84
+
85
+ expect(@errors.errors[-1]).to eq({'code' => 'test_domain.http_456_has_reference', 'message' => '456 message', 'reference' => 'ref1-data'})
86
+
87
+ expect {
88
+ @errors.add_error('test_domain.http_456_has_reference', 'message' => 'ref1-test', 'reference' => {:ref1 => 'ref1-data'})
89
+ }.to_not raise_error
90
+
91
+ expect(@errors.errors[-1]).to eq({'code' => 'test_domain.http_456_has_reference', 'message' => 'ref1-test', 'reference' => 'ref1-data'})
92
+
93
+ expect {
94
+ @errors.add_error('test_domain.http_567_has_references', 'reference' => {:ref2 => 'ref2-data', :ref3 => 'ref3-data', :ref4 => 'ref4-data'})
95
+ }.to_not raise_error
96
+
97
+ expect(@errors.errors[-1]).to eq({'code' => 'test_domain.http_567_has_references', 'message' => '567 message', 'reference' => 'ref2-data,ref3-data,ref4-data'})
98
+ end
99
+
100
+ it 'should let me specify additional reference data and list it after mandatory data' do
101
+ expect {
102
+ @errors.add_error('test_domain.http_567_has_references', 'reference' => {:add2 => 'add2-data', :ref2 => 'ref2-data', :add1 => 'add1-data', :ref3 => 'ref3-data', :ref4 => 'ref4-data'})
103
+ }.to_not raise_error
104
+
105
+ expect(@errors.errors[-1]).to eq({'code' => 'test_domain.http_567_has_references', 'message' => '567 message', 'reference' => 'ref2-data,ref3-data,ref4-data,add2-data,add1-data'})
106
+ end
107
+ end
108
+
109
+ describe '#clear_errors' do
110
+ it 'should correctly clear errors' do
111
+ @errors.clear_errors
112
+ expect(@errors.has_errors?).to eq(false)
113
+ expect(@errors.errors).to be_empty
114
+
115
+ @errors.add_error('platform.malformed')
116
+ expect(@errors.has_errors?).to eq(true)
117
+ expect(@errors.errors).to_not be_empty
118
+
119
+ @errors.clear_errors
120
+ expect(@errors.has_errors?).to eq(false)
121
+ expect(@errors.errors).to be_empty
122
+ end
123
+ end
124
+
125
+ describe '#add_precompiled_error' do
126
+ it 'should let me add precompiled errors' do
127
+ expect {
128
+ @errors.add_precompiled_error('test_domain.http_345_no_references 1', 'message 1', 'baz, foo 1')
129
+ @errors.add_precompiled_error('test_domain.http_345_no_references 2', 'message 2', 'baz, foo 2')
130
+ @errors.add_precompiled_error('test_domain.http_345_no_references 3', 'message 3', 'baz, foo 3')
131
+ }.to_not raise_error
132
+
133
+ expect(@errors.errors[0]).to eq({'code' => 'test_domain.http_345_no_references 1', 'message' => 'message 1', 'reference' => 'baz, foo 1'})
134
+ expect(@errors.errors[1]).to eq({'code' => 'test_domain.http_345_no_references 2', 'message' => 'message 2', 'reference' => 'baz, foo 2'})
135
+ expect(@errors.errors[2]).to eq({'code' => 'test_domain.http_345_no_references 3', 'message' => 'message 3', 'reference' => 'baz, foo 3'})
136
+ end
137
+ end
138
+
139
+ describe '#render' do
140
+ it 'complains about invalid Interaction IDs' do
141
+ expect {
142
+ @errors.render( nil )
143
+ }.to raise_error( RuntimeError, "Hoodoo::Errors\#render must be given a valid Interaction ID (got 'nil')" )
144
+
145
+ expect {
146
+ @errors.render( 12345 )
147
+ }.to raise_error( RuntimeError, "Hoodoo::Errors\#render must be given a valid Interaction ID (got '12345')" )
148
+
149
+ expect {
150
+ @errors.render( 'hello' )
151
+ }.to raise_error( RuntimeError, "Hoodoo::Errors\#render must be given a valid Interaction ID (got '\"hello\"')" )
152
+ end
153
+
154
+ it 'renders' do
155
+ @errors.clear_errors
156
+ @errors.add_error('platform.malformed')
157
+
158
+ data = @errors.render(Hoodoo::UUID.generate())
159
+ expect(data['errors']).to be_a(Array)
160
+ expect(data['errors'].count).to eq(1)
161
+ expect(data['errors'][0]['code']).to eq('platform.malformed')
162
+ expect(data['errors'][0]['message']).to be_a(String)
163
+ expect(data['errors'][0]['message'].size).to_not eq(0)
164
+ expect(data['errors'][0]['reference']).to be_nil
165
+ expect(data['id']).to be_a(String)
166
+ expect(data['id'].size).to eq(32)
167
+ expect(data['kind']).to eq('Errors')
168
+ expect(data['created_at']).to be_a(String)
169
+ expect {
170
+ raise "Broken or missing created_at" if Date.parse(data['created_at']).nil?
171
+ }.to_not raise_error
172
+ end
173
+ end
174
+
175
+ describe '#add_precompiled_error' do
176
+ it 'should not complain about random data' do
177
+ @errors.clear_errors
178
+ @errors.add_precompiled_error( 'code', 'message', 'reference' )
179
+ expect(@errors.errors).to eq([
180
+ {
181
+ 'code' => 'code',
182
+ 'message' => 'message',
183
+ 'reference' => 'reference'
184
+ }
185
+ ])
186
+ end
187
+
188
+ it 'should not store empty references' do
189
+ @errors.clear_errors
190
+ @errors.add_precompiled_error( 'code', 'message', '' )
191
+ expect(@errors.errors).to eq([
192
+ {
193
+ 'code' => 'code',
194
+ 'message' => 'message'
195
+ }
196
+ ])
197
+ end
198
+
199
+ it 'should not store nil references' do
200
+ @errors.clear_errors
201
+ @errors.add_precompiled_error( 'code', 'message', nil )
202
+ expect(@errors.errors).to eq([
203
+ {
204
+ 'code' => 'code',
205
+ 'message' => 'message'
206
+ }
207
+ ])
208
+ end
209
+ end
210
+
211
+ describe '#merge' do
212
+ it 'should merge when neither have errors' do
213
+ @errors.clear_errors
214
+ source = Hoodoo::Errors.new
215
+ expect(@errors.merge!(source)).to eq(false)
216
+ expect(@errors.errors).to eq([])
217
+ end
218
+
219
+ it 'should merge when only the source has errors' do
220
+ @errors.clear_errors
221
+ source = Hoodoo::Errors.new
222
+ source.add_error('platform.method_not_allowed', 'message' => 'Method not allowed 1', 'reference' => { :data => '1' })
223
+ source.add_error('platform.malformed', 'message' => 'Malformed request 1', 'reference' => { :data => '1' })
224
+ expect(@errors.merge!(source)).to eq(true)
225
+
226
+ expect(@errors.errors).to eq([
227
+ {
228
+ 'code' => 'platform.method_not_allowed',
229
+ 'message' => 'Method not allowed 1',
230
+ 'reference' => '1'
231
+ },
232
+ {
233
+ 'code' => 'platform.malformed',
234
+ 'message' => 'Malformed request 1',
235
+ 'reference' => '1'
236
+ }
237
+ ])
238
+ end
239
+
240
+ it 'should merge when only the destination has errors' do
241
+ @errors.clear_errors
242
+ source = Hoodoo::Errors.new
243
+ @errors.add_error('platform.method_not_allowed', 'message' => 'Method not allowed 2', 'reference' => { :data => '2' })
244
+ @errors.add_error('platform.malformed', 'message' => 'Malformed request 2', 'reference' => { :data => '2' })
245
+ @errors.merge!( source )
246
+
247
+ expect(@errors.errors).to eq([
248
+ {
249
+ 'code' => 'platform.method_not_allowed',
250
+ 'message' => 'Method not allowed 2',
251
+ 'reference' => '2'
252
+ },
253
+ {
254
+ 'code' => 'platform.malformed',
255
+ 'message' => 'Malformed request 2',
256
+ 'reference' => '2'
257
+ }
258
+ ])
259
+ end
260
+
261
+ it 'should merge when both have errors' do
262
+ @errors.clear_errors
263
+ source = Hoodoo::Errors.new
264
+ source.add_error('platform.method_not_allowed', 'message' => 'Method not allowed 1', 'reference' => { :data => '1' })
265
+ source.add_error('platform.malformed', 'message' => 'Malformed request 1', 'reference' => { :data => '1' })
266
+ @errors.add_error('platform.method_not_allowed', 'message' => 'Method not allowed 2', 'reference' => { :data => '2' })
267
+ @errors.add_error('platform.malformed', 'message' => 'Malformed request 2', 'reference' => { :data => '2' })
268
+ @errors.merge!( source )
269
+
270
+ expect(@errors.errors).to eq([
271
+ {
272
+ 'code' => 'platform.method_not_allowed',
273
+ 'message' => 'Method not allowed 2',
274
+ 'reference' => '2'
275
+ },
276
+ {
277
+ 'code' => 'platform.malformed',
278
+ 'message' => 'Malformed request 2',
279
+ 'reference' => '2'
280
+ },
281
+ {
282
+ 'code' => 'platform.method_not_allowed',
283
+ 'message' => 'Method not allowed 1',
284
+ 'reference' => '1'
285
+ },
286
+ {
287
+ 'code' => 'platform.malformed',
288
+ 'message' => 'Malformed request 1',
289
+ 'reference' => '1'
290
+ }
291
+ ])
292
+ end
293
+
294
+ it 'should acquire the source status code when it has none itself' do
295
+ @errors.clear_errors
296
+ expect(@errors.http_status_code).to eq(200) # Default; collection is empty
297
+
298
+ source = Hoodoo::Errors.new
299
+ source.add_error('platform.method_not_allowed')
300
+ expect(source.http_status_code).to eq(405)
301
+
302
+ @errors.merge!(source)
303
+ expect(@errors.http_status_code).to eq(405) # Acquires the 405 from the merged collection
304
+ end
305
+
306
+ it 'should keep its original status code when it has one' do
307
+ @errors.clear_errors
308
+ @errors.add_error( 'platform.not_found', 'reference' => { :entity_name => 'something' } )
309
+ source = Hoodoo::Errors.new
310
+ source.add_error('platform.method_not_allowed')
311
+ expect(@errors.http_status_code).to eq(404) # Non-default; collection has an error recorded
312
+ expect(source.http_status_code).to eq(405)
313
+ @errors.merge!(source)
314
+ expect(@errors.http_status_code).to eq(404) # Keeps the 404 from its original collection
315
+ end
316
+ end
317
+
318
+ describe 'comma escaping' do
319
+ it 'should escape commas' do
320
+ str = @errors.send(:escape_commas, "This, that, one \\ another")
321
+ expect(str).to eq("This\\, that\\, one \\\\ another")
322
+ end
323
+
324
+ it 'should unescape commas' do
325
+ str = @errors.send(:escape_commas, "This, that, one \\ another")
326
+ str = @errors.send(:unescape_commas, str)
327
+ expect(str).to eq("This, that, one \\ another")
328
+ end
329
+
330
+ it 'should unpack an escaped comma separated list' do
331
+ ary = [ 'this, that', 'one \\ another' ]
332
+ str = @errors.send(:escape_commas, ary[0])
333
+ str << ',' << @errors.send(:escape_commas, ary[1])
334
+ expect(@errors.unjoin_and_unescape_commas(str)).to eq(ary)
335
+ end
336
+
337
+ it 'should escape reference data, which should be recoverable' do
338
+ @errors.clear_errors
339
+ @errors.add_error('test_domain.http_567_has_references', 'reference' => {:ref2 => 'ref \\ 2 data', :ref3 => 'ref, 3, data', :ref4 => 'ref4-data'})
340
+
341
+ rendered = @errors.render(Hoodoo::UUID.generate())
342
+ ary = @errors.unjoin_and_unescape_commas(rendered['errors'][0]['reference'])
343
+ expect(ary).to eq(['ref \\ 2 data', 'ref, 3, data', 'ref4-data'])
344
+ end
345
+ end
346
+ end
@@ -0,0 +1,112 @@
1
+ # This is a sort-of-integration test that ad hoc tests different elements of
2
+ # the stack already exercised elsewhere, especially in the middleware tests
3
+ # from service_middleware_spec.rb. It's just a different "angle" on everthing
4
+ # for a belt and braces approach.
5
+
6
+ require 'spec_helper'
7
+
8
+ class RSpecTestServiceAImplementation < Hoodoo::Services::Implementation
9
+ def list( context )
10
+ raise self.class.name + ' list'
11
+ end
12
+
13
+ def show( context )
14
+ raise self.class.name + ' show'
15
+ end
16
+
17
+ def create( context )
18
+ raise self.class.name + ' create'
19
+ end
20
+
21
+ def update( context )
22
+ raise self.class.name + ' update'
23
+ end
24
+
25
+ def delete( context )
26
+ raise self.class.name + ' delete'
27
+ end
28
+ end
29
+
30
+ class RSpecTestServiceAInterface < Hoodoo::Services::Interface
31
+ interface :RSpecTestService do
32
+ endpoint :rspec_test_service_a, RSpecTestServiceAImplementation
33
+ end
34
+ end
35
+
36
+ class RSpecTestServiceA < Hoodoo::Services::Service
37
+ comprised_of RSpecTestServiceAInterface
38
+ end
39
+
40
+ describe RSpecTestServiceA do
41
+ describe 'when badly configured' do
42
+ context 'with no middleware' do
43
+ def app
44
+ Rack::Builder.new do
45
+ # The deliberate mistake - no 'use ...' telling Rack about
46
+ # the service middleware...
47
+ run RSpecTestServiceA.new
48
+ end
49
+ end
50
+
51
+ it 'should complain about being called directly' do
52
+ expect {
53
+ get '/v1/rspec_test_service_a'
54
+ }.to raise_error(RuntimeError)
55
+ end
56
+ end
57
+ end
58
+
59
+ describe 'when well configured' do
60
+ def app
61
+ Rack::Builder.new do
62
+ use Hoodoo::Services::Middleware
63
+ run RSpecTestServiceA.new
64
+ end
65
+ end
66
+
67
+ # This batch of tests doesn't worry about middleware-level rejection of
68
+ # bad requests and so-on as the middleware specs catch that. It just wants
69
+ # to make sure that a top-end get/post/patch/delete gets routed down to
70
+ # the correct action method in the correct implementation.
71
+
72
+ it 'should list items' do
73
+ get '/v1/rspec_test_service_a', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
74
+ expect(last_response.status).to eq(500)
75
+ result = JSON.parse(last_response.body)
76
+ expect(result['errors'][0]['code']).to eq('platform.fault')
77
+ expect(result['errors'][0]['message']).to eq('RSpecTestServiceAImplementation list')
78
+ end
79
+
80
+ it 'should show an item' do
81
+ get '/v1/rspec_test_service_a/foo', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
82
+ expect(last_response.status).to eq(500)
83
+ result = JSON.parse(last_response.body)
84
+ expect(result['errors'][0]['code']).to eq('platform.fault')
85
+ expect(result['errors'][0]['message']).to eq('RSpecTestServiceAImplementation show')
86
+ end
87
+
88
+ it 'should create an item' do
89
+ post '/v1/rspec_test_service_a/', "{}", { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
90
+ expect(last_response.status).to eq(500)
91
+ result = JSON.parse(last_response.body)
92
+ expect(result['errors'][0]['code']).to eq('platform.fault')
93
+ expect(result['errors'][0]['message']).to eq('RSpecTestServiceAImplementation create')
94
+ end
95
+
96
+ it 'should update an item' do
97
+ patch '/v1/rspec_test_service_a/foo', "{}", { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
98
+ expect(last_response.status).to eq(500)
99
+ result = JSON.parse(last_response.body)
100
+ expect(result['errors'][0]['code']).to eq('platform.fault')
101
+ expect(result['errors'][0]['message']).to eq('RSpecTestServiceAImplementation update')
102
+ end
103
+
104
+ it 'should delete an item' do
105
+ delete '/v1/rspec_test_service_a/foo', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
106
+ expect(last_response.status).to eq(500)
107
+ result = JSON.parse(last_response.body)
108
+ expect(result['errors'][0]['code']).to eq('platform.fault')
109
+ expect(result['errors'][0]['message']).to eq('RSpecTestServiceAImplementation delete')
110
+ end
111
+ end
112
+ end