hoodoo 1.7.0 → 1.8.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.
@@ -0,0 +1,17 @@
1
+ ########################################################################
2
+ # File:: newrelic_rpm.rb
3
+ # (C):: Loyalty New Zealand 2016
4
+ #
5
+ # Purpose:: Override NewRelic 'require "newrelic_rpm"'. The test suite
6
+ # cannot allow "real" NewRelic to be loaded as this would hook
7
+ # into all kinds of things and interfere with test results,
8
+ # especially for tests covering variant behaviour for when
9
+ # NewRelic is present or absent.
10
+ # ----------------------------------------------------------------------
11
+ # 13-Apr-2016 (ADH): Created.
12
+ ########################################################################
13
+
14
+ # Yes, this is empty, just comments. The whole point is to allow code to
15
+ # be able to require what it thinks is NewRelic without a LoadError
16
+ # exception being raised, but not actually define any NewRelic components
17
+ # until the test suite is good and ready to do so (with mock data).
@@ -6,469 +6,18 @@ require 'spec_helper'
6
6
 
7
7
  describe Hoodoo::Services::Middleware do
8
8
 
9
- class RSpecTestServiceExoticStubImplementation < Hoodoo::Services::Implementation
10
- def list( context )
11
- context.response.set_estimated_resources( [], 88 )
12
- context.response.set_resources( [], 99 )
13
- end
14
- end
15
-
16
- class RSpecTestServiceExoticStubInterface < Hoodoo::Services::Interface
17
- interface :Version do
18
- endpoint :version, RSpecTestServiceExoticStubImplementation
19
- version 2
20
- end
21
- end
22
-
23
- class RSpecTestServiceExoticStub < Hoodoo::Services::Service
24
- comprised_of RSpecTestServiceExoticStubInterface
25
- end
26
-
27
9
  context 'on queue' do
28
- before :each do
29
- @old_queue = ENV[ 'AMQ_URI' ]
30
- ENV[ 'AMQ_URI' ] = 'amqp://test:test@127.0.0.1'
31
- @mw = Hoodoo::Services::Middleware.new( RSpecTestServiceExoticStub.new )
32
-
33
- @cvar = false
34
- if Hoodoo::Services::Middleware.class_variable_defined?( '@@alchemy' )
35
- @cvar = true
36
- @cvar_val = Hoodoo::Services::Middleware.class_variable_get( '@@alchemy' )
37
- end
38
-
39
- # Need to blow away the discoverer's local cache or the simulation will
40
- # never attempt to run on queue.
41
-
42
- discoverer = @mw.instance_variable_get( '@discoverer' )
43
- discoverer.instance_variable_set( '@known_local_resources', {} ) # Hack for test!
44
- end
45
-
46
- after :each do
47
- ENV[ 'AMQ_URI' ] = @old_queue
48
-
49
- if Hoodoo::Services::Middleware.class_variable_defined?( '@@alchemy' )
50
- if @cvar == true
51
- Hoodoo::Services::Middleware.class_variable_set( '@@alchemy', @cvar_val )
52
- else
53
- Hoodoo::Services::Middleware.remove_class_variable( '@@alchemy' )
54
- end
55
- end
56
- end
57
-
58
- it 'knows it is on-queue' do
59
- expect( Hoodoo::Services::Middleware.on_queue? ).to eq( true )
60
- end
61
-
62
- # TODO: Weak test! Assumes static mappings. Will need modification
63
- # for real Consul discoverer when implemented.
64
- #
65
- it 'returns known queue endpoint locations' do
66
- location = @mw.instance_variable_get( '@discoverer' ).discover( :Version, 2 )
67
- expect( location ).to be_a( Hoodoo::Services::Discovery::ForAMQP )
68
- expect( location.routing_path ).to eq( '/2/Version' )
10
+ before :all do
11
+ Hoodoo::Monkey.disable( extension_module: Hoodoo::Monkey::Patch::NewRelicTracedAMQP )
69
12
  end
70
13
 
71
- # TODO: Update for real Consul discoverer when implemented.
72
- #
73
- # it 'returns "nil" for unknown queue endpoint locations' do
74
- # location = @mw.instance_variable_get( '@discoverer' ).discover( :NotAKnownResource, 2 )
75
- # expect( location ).to be_nil
76
- # end
77
-
78
- context 'calling Alchemy' do
79
- before :each do
80
- mw = Hoodoo::Services::Middleware.new( RSpecTestServiceExoticStub.new )
81
- @interaction = Hoodoo::Services::Middleware::Interaction.new(
82
- {},
83
- mw,
84
- Hoodoo::Services::Middleware.test_session()
85
- )
86
- @interaction.target_interface = OpenStruct.new
87
- @interaction.context.request.locale = 'fr'
88
-
89
- @mock_alchemy = OpenStruct.new
90
- Hoodoo::Services::Middleware.class_variable_set( '@@alchemy', @mock_alchemy )
91
- end
92
-
93
- def run_expectations( action, full_path, mock_method, mock_query, mock_remote, mock_response )
94
- expect_any_instance_of( Hoodoo::Services::Discovery::ByFlux ).to receive(
95
- :discover_remote
96
- ).and_return(
97
- mock_remote
98
- )
99
-
100
- if mock_query
101
- mock_query = Hoodoo::Utilities.stringify( mock_query )
102
- mock_query[ 'search' ] = URI.encode_www_form( mock_query[ 'search' ] ) if ( mock_query[ 'search' ].is_a?( ::Hash ) )
103
- mock_query[ 'filter' ] = URI.encode_www_form( mock_query[ 'filter' ] ) if ( mock_query[ 'filter' ].is_a?( ::Hash ) )
104
- end
105
-
106
- expect( @mock_alchemy ).to receive( :send_request_to_resource ).once do | message |
107
- expect( message ).to eq( {
108
- 'scheme' => 'http',
109
- 'verb' => mock_method,
110
-
111
- 'host' => 'localhost',
112
- 'port' => 80,
113
- 'path' => full_path,
114
- 'query' => mock_query,
115
-
116
- 'session_id' => @interaction.context.session.session_id,
117
- 'body' => action == :create || action == :update ? '{}' : '',
118
- 'headers' => {
119
- 'Content-Type' => 'application/json; charset=utf-8',
120
- 'Content-Language' => 'fr',
121
- 'Accept-Language' => 'fr',
122
- 'X-Interaction-ID' => @interaction.interaction_id,
123
- 'X-Session-ID' => @interaction.context.session.session_id
124
- },
125
- } )
126
- end.and_return( mock_response )
127
- end
128
-
129
- # All the other tests in this section run with @mw having no
130
- # local services "as far as it is concerned" via the before-each
131
- # code above. We want to make sure that service announcement when
132
- # on-queue *does* announce locally (because at one point it did
133
- # not, which was a bug) so this test provides that coverage.
134
- #
135
- it 'runs local discovery unless that is knocked out' do
136
-
137
- # @mw has local discovery knocked out, so build a new
138
- # one that doesn't. This will have the local discovery data
139
- # available still.
140
- #
141
- @mw = Hoodoo::Services::Middleware.new( RSpecTestServiceExoticStub.new )
142
-
143
- mock_path = '/2/Version/'
144
- mock_remote = Hoodoo::Services::Discovery::ForAMQP.new(
145
- resource: 'Version',
146
- version: 2
147
- )
148
-
149
- # We expect local discovery, so no discover_remote call.
150
-
151
- expect_any_instance_of( Hoodoo::Services::Discovery::ByFlux ).to_not receive( :discover_remote )
152
- endpoint = @mw.inter_resource_endpoint_for( 'Version', 2, @interaction )
153
-
154
- # The endpoint should've been called locally; the implementation at
155
- # the top of this file sets an empty array with dataset size 99 *and*
156
- # an estimated dataset size of 88.
157
-
158
- mock_result = endpoint.list()
159
- expect( mock_result ).to be_empty
160
- expect( mock_result.dataset_size ).to eq( 99 )
161
- expect( mock_result.estimated_dataset_size ).to eq( 88 )
162
- end
163
-
164
- it 'complains about a missing Alchemy instance' do
165
- mock_path = '/2/Version/'
166
-
167
- mock_remote = Hoodoo::Services::Discovery::ForAMQP.new(
168
- resource: 'Version',
169
- version: 2
170
- )
171
-
172
- expect_any_instance_of( Hoodoo::Services::Discovery::ByFlux ).to receive(
173
- :discover_remote
174
- ).and_return(
175
- mock_remote
176
- )
177
-
178
- endpoint = @mw.inter_resource_endpoint_for( 'Version', 2, @interaction )
179
-
180
- # Fragile! Hack for test only.
181
- endpoint.instance_variable_get( '@wrapped_endpoint' ).alchemy = nil
182
-
183
- mock_response = {
184
- 'status_code' => 200,
185
- 'body' => '{"_data":[]}'
186
- }
187
-
188
- expect {
189
- mock_result = endpoint.list()
190
- }.to raise_error( RuntimeError, 'Hoodoo::Client::Endpoint::AMQP cannot be used unless an Alchemy instance has been provided' )
191
- end
192
-
193
- it 'calls #list over Alchemy and handles 200' do
194
- mock_path = '/2/Version'
195
- mock_method = 'GET'
196
- mock_query = { :search => { :foo => :bar } }
197
-
198
- mock_remote = Hoodoo::Services::Discovery::ForAMQP.new(
199
- resource: 'Version',
200
- version: 2
201
- )
202
-
203
- mock_response = {
204
- 'status_code' => 200,
205
- 'body' => '{"_data":[]}'
206
- }
207
-
208
- run_expectations( :list, mock_path + '/', mock_method, mock_query, mock_remote, mock_response )
209
-
210
- endpoint = @mw.inter_resource_endpoint_for( 'Version', 2, @interaction )
211
- mock_result = endpoint.list( mock_query )
212
-
213
- expect( mock_result ).to eq( Hoodoo::Client::AugmentedArray.new )
214
- end
215
-
216
- it 'calls #show over Alchemy and handles 200' do
217
- mock_path = '/2/Version'
218
- mock_method = 'GET'
219
- mock_query = { :search => { :foo => :bar } }
220
-
221
- mock_remote = Hoodoo::Services::Discovery::ForAMQP.new(
222
- resource: 'Version',
223
- version: 2
224
- )
225
-
226
- mock_response = {
227
- 'status_code' => 200,
228
- 'body' => '{}'
229
- }
230
-
231
- run_expectations( :show, mock_path + '/ident', mock_method, mock_query, mock_remote, mock_response )
232
-
233
- endpoint = @mw.inter_resource_endpoint_for( 'Version', 2, @interaction )
234
- mock_result = endpoint.show( 'ident', mock_query )
235
-
236
- expect( mock_result ).to eq( Hoodoo::Client::AugmentedHash.new )
237
- end
238
-
239
- it 'calls #create over Alchemy and handles 200' do
240
- mock_path = '/2/Version'
241
- mock_method = 'POST'
242
- mock_query = { :search => { :foo => :bar } }
243
-
244
- mock_remote = Hoodoo::Services::Discovery::ForAMQP.new(
245
- resource: 'Version',
246
- version: 2
247
- )
248
-
249
- mock_response = {
250
- 'status_code' => 200,
251
- 'body' => '{}'
252
- }
253
-
254
- run_expectations( :create, mock_path + '/', mock_method, mock_query, mock_remote, mock_response )
255
-
256
- endpoint = @mw.inter_resource_endpoint_for( 'Version', 2, @interaction )
257
- mock_result = endpoint.create( {}, mock_query )
258
-
259
- expect( mock_result ).to eq( Hoodoo::Client::AugmentedHash.new )
260
- end
261
-
262
- it 'calls #update over Alchemy and handles 200' do
263
- mock_path = '/2/Version'
264
- mock_method = 'PATCH'
265
- mock_query = { :search => { :foo => :bar } }
266
-
267
- mock_remote = Hoodoo::Services::Discovery::ForAMQP.new(
268
- resource: 'Version',
269
- version: 2
270
- )
271
-
272
- mock_response = {
273
- 'status_code' => 200,
274
- 'body' => '{}'
275
- }
276
-
277
- run_expectations( :update, mock_path + '/ident', mock_method, mock_query, mock_remote, mock_response )
278
-
279
- endpoint = @mw.inter_resource_endpoint_for( 'Version', 2, @interaction )
280
- mock_result = endpoint.update( 'ident', {}, mock_query )
281
-
282
- expect( mock_result ).to eq( Hoodoo::Client::AugmentedHash.new )
283
- end
284
-
285
- it 'calls #delete over Alchemy and handles 200' do
286
- mock_path = '/2/Version'
287
- mock_method = 'DELETE'
288
- mock_query = { :search => { :foo => :bar } }
289
-
290
- mock_remote = Hoodoo::Services::Discovery::ForAMQP.new(
291
- resource: 'Version',
292
- version: 2
293
- )
294
-
295
- mock_response = {
296
- 'status_code' => 200,
297
- 'body' => '{}'
298
- }
299
-
300
- run_expectations( :delete, mock_path + '/ident', mock_method, mock_query, mock_remote, mock_response )
301
-
302
- endpoint = @mw.inter_resource_endpoint_for( 'Version', 2, @interaction )
303
- mock_result = endpoint.delete( 'ident', mock_query )
304
-
305
- expect( mock_result ).to eq( Hoodoo::Client::AugmentedHash.new )
306
- end
307
-
308
- it 'calls #show over Alchemy and handles 408' do
309
- mock_path = '/2/Version'
310
- mock_method = 'GET'
311
- mock_query = { :search => { :foo => :bar } }
312
-
313
- mock_remote = Hoodoo::Services::Discovery::ForAMQP.new(
314
- resource: 'Version',
315
- version: 2
316
- )
317
-
318
- mock_response = AlchemyFlux::TimeoutError
319
-
320
- run_expectations( :show, mock_path + '/ident', mock_method, mock_query, mock_remote, mock_response )
321
-
322
- endpoint = @mw.inter_resource_endpoint_for( 'Version', 2, @interaction )
323
- mock_result = endpoint.show( 'ident', mock_query )
324
-
325
- expect( mock_result ).to be_a( Hoodoo::Client::AugmentedHash )
326
- expect( mock_result.platform_errors ).to_not be_nil
327
-
328
- errors = mock_result.platform_errors.render( Hoodoo::UUID.generate )
329
-
330
- expect( errors ).to have_key( 'errors' )
331
- expect( errors[ 'errors' ] ).to be_a( Array )
332
- expect( errors[ 'errors' ][ 0 ] ).to have_key( 'code' )
333
- expect( errors[ 'errors' ][ 0 ][ 'code' ] ).to eq( 'platform.timeout' )
334
- end
335
-
336
- it 'calls #show over Alchemy and handles 404' do
337
- mock_path = '/2/Version'
338
- mock_method = 'GET'
339
- mock_query = { :search => { :foo => :bar } }
340
-
341
- mock_remote = Hoodoo::Services::Discovery::ForAMQP.new(
342
- resource: 'Version',
343
- version: 2
344
- )
345
-
346
- mock_response = AlchemyFlux::MessageNotDeliveredError
347
-
348
- run_expectations( :show, mock_path + '/ident', mock_method, mock_query, mock_remote, mock_response )
349
-
350
- endpoint = @mw.inter_resource_endpoint_for( 'Version', 2, @interaction )
351
- mock_result = endpoint.show( 'ident', mock_query )
352
-
353
- expect( mock_result ).to be_a( Hoodoo::Client::AugmentedHash )
354
- expect( mock_result.platform_errors ).to_not be_nil
355
-
356
- errors = mock_result.platform_errors.render( Hoodoo::UUID.generate )
357
-
358
- expect( errors ).to have_key( 'errors' )
359
- expect( errors[ 'errors' ] ).to be_a( Array )
360
- expect( errors[ 'errors' ][ 0 ] ).to have_key( 'code' )
361
- expect( errors[ 'errors' ][ 0 ][ 'code' ] ).to eq( 'platform.not_found' )
362
- end
363
-
364
- it 'calls #show over Alchemy and handles unusual HTTP status codes' do
365
- mock_path = '/2/Version'
366
- mock_method = 'GET'
367
- mock_query = { :search => { :foo => :bar } }
368
-
369
- mock_remote = Hoodoo::Services::Discovery::ForAMQP.new(
370
- resource: 'Version',
371
- version: 2
372
- )
373
-
374
- bad_body_data = '499 Unusual Code'
375
- mock_response = {
376
- 'status_code' => 499,
377
- 'body' => bad_body_data
378
- }
379
-
380
- run_expectations( :show, mock_path + '/ident', mock_method, mock_query, mock_remote, mock_response )
381
-
382
- endpoint = @mw.inter_resource_endpoint_for( 'Version', 2, @interaction )
383
- mock_result = endpoint.show( 'ident', mock_query )
384
-
385
- expect( mock_result ).to be_a( Hoodoo::Client::AugmentedHash )
386
- expect( mock_result.platform_errors ).to_not be_nil
387
-
388
- errors = mock_result.platform_errors.render( Hoodoo::UUID.generate )
389
-
390
- expect( errors ).to have_key( 'errors' )
391
- expect( errors[ 'errors' ] ).to be_a( Array )
392
- expect( errors[ 'errors' ][ 0 ] ).to_not be_nil
393
-
394
- expect( errors[ 'errors' ][ 0 ][ 'code' ] ).to eq( 'platform.fault' )
395
- expect( errors[ 'errors' ][ 0 ][ 'message' ] ).to eq( 'Unexpected raw HTTP status code 499 with non-JSON response' )
396
- expect( errors[ 'errors' ][ 0 ][ 'reference' ] ).to eq( "#{ bad_body_data }" )
397
- end
398
-
399
- it 'calls #show over Alchemy and handles unrecognised return types' do
400
- mock_path = '/2/Version'
401
- mock_method = 'GET'
402
- mock_query = { :search => { :foo => :bar } }
403
-
404
- mock_remote = Hoodoo::Services::Discovery::ForAMQP.new(
405
- resource: 'Version',
406
- version: 2
407
- )
408
-
409
- bad_body_data = '500 Internal Server Error'
410
- mock_response = Object.new
411
-
412
- run_expectations( :show, mock_path + '/ident', mock_method, mock_query, mock_remote, mock_response )
413
-
414
- endpoint = @mw.inter_resource_endpoint_for( 'Version', 2, @interaction )
415
- mock_result = endpoint.show( 'ident', mock_query )
416
-
417
- expect( mock_result ).to be_a( Hoodoo::Client::AugmentedHash )
418
- expect( mock_result.platform_errors ).to_not be_nil
419
-
420
- errors = mock_result.platform_errors.render( Hoodoo::UUID.generate )
421
-
422
- expect( errors ).to have_key( 'errors' )
423
- expect( errors[ 'errors' ] ).to be_a( Array )
424
- expect( errors[ 'errors' ][ 0 ] ).to_not be_nil
425
-
426
- expect( errors[ 'errors' ][ 0 ][ 'code' ] ).to eq( 'platform.fault' )
427
- expect( errors[ 'errors' ][ 0 ][ 'message' ] ).to eq( 'Unexpected raw HTTP status code 500 with non-JSON response' )
428
- expect( errors[ 'errors' ][ 0 ][ 'reference' ] ).to eq( "#{ bad_body_data }" )
429
- end
430
-
431
- it 'calls #show over Alchemy and handles 200 status but bad JSON' do
432
- mock_path = '/2/Version'
433
- mock_method = 'GET'
434
- mock_query = { :search => { :foo => :bar } }
435
-
436
- mock_remote = Hoodoo::Services::Discovery::ForAMQP.new(
437
- resource: 'Version',
438
- version: 2
439
- )
440
-
441
- bad_body_data = 'Not JSON'
442
- mock_response = {
443
- 'status_code' => 200,
444
- 'body' => bad_body_data
445
- }
446
-
447
- run_expectations( :show, mock_path + '/ident', mock_method, mock_query, mock_remote, mock_response )
448
-
449
- endpoint = @mw.inter_resource_endpoint_for( 'Version', 2, @interaction )
450
- mock_result = endpoint.show( 'ident', mock_query )
451
-
452
- expect( mock_result ).to be_a( Hoodoo::Client::AugmentedHash )
453
- expect( mock_result.platform_errors ).to_not be_nil
454
-
455
- errors = mock_result.platform_errors.render( Hoodoo::UUID.generate )
456
-
457
- expect( errors ).to have_key( 'errors' )
458
- expect( errors[ 'errors' ] ).to be_a( Array )
459
- expect( errors[ 'errors' ][ 0 ] ).to_not be_nil
460
-
461
- expect( errors[ 'errors' ][ 0 ][ 'code' ] ).to eq( 'platform.fault' )
462
- expect( errors[ 'errors' ][ 0 ][ 'message' ] ).to eq( 'Could not parse retrieved body data despite receiving HTTP status code 200' )
463
- expect( errors[ 'errors' ][ 0 ][ 'reference' ] ).to eq( "#{ bad_body_data }" )
464
- end
465
- end
14
+ it_behaves_like 'an AMQP-based middleware/client endpoint'
466
15
  end
467
16
 
468
17
  context 'over HTTPS' do
469
18
  before :all do
470
19
  @port = spec_helper_start_svc_app_in_thread_for(
471
- RSpecTestServiceExoticStub,
20
+ RSpecTestServiceExoticStub, # See shared_examples/middleware_amqp.rb
472
21
  true # Use SSL
473
22
  )
474
23
  end
@@ -510,7 +59,7 @@ describe Hoodoo::Services::Middleware do
510
59
 
511
60
  # Set up a middleware instance and mock interaction
512
61
 
513
- mw = Hoodoo::Services::Middleware.new( RSpecTestServiceExoticStub.new )
62
+ mw = Hoodoo::Services::Middleware.new( RSpecTestServiceExoticStub.new ) # See shared_examples/middleware_amqp.rb
514
63
  interaction = Hoodoo::Services::Middleware::Interaction.new(
515
64
  {},
516
65
  mw,