hoodoo 1.14.0 → 1.15.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.
@@ -87,7 +87,7 @@ module Hoodoo
87
87
  #
88
88
  attr_reader :storage_engine
89
89
 
90
- # Read the storage engine insteance for the #storage_engine - this allows
90
+ # Read the storage engine instance for the #storage_engine - this allows
91
91
  # engine-specific configuration to be set where available, though this is
92
92
  # strongly discouraged as it couples client code to the engine in use,
93
93
  # defeating the main rationale behind the TransientStore abstraction.
@@ -256,7 +256,11 @@ module Hoodoo
256
256
  #
257
257
  # _Named_ parameters are:
258
258
  #
259
- # +key+:: Key previously given to #set.
259
+ # +key+:: Key previously given to #set.
260
+ #
261
+ # +allow_throw+:: If +true+, exceptions raised by the underlying storage
262
+ # engine are thrown, else ignored and +nil+ is returned.
263
+ # Optional; default is +false+.
260
264
  #
261
265
  # Returns +nil+ if the item is not found - either the key is wrong, the
262
266
  # stored data has expired or the stored data has been evicted early from
@@ -265,9 +269,14 @@ module Hoodoo
265
269
  # Only non-empty String or Symbol keys are permitted, else an exception
266
270
  # will be raised.
267
271
  #
268
- def get( key: )
272
+ def get( key:, allow_throw: false )
269
273
  key = normalise_key( key, 'get' )
270
- @storage_engine_instance.get( key: key ) rescue nil
274
+
275
+ begin
276
+ @storage_engine_instance.get( key: key )
277
+ rescue
278
+ raise if allow_throw
279
+ end
271
280
  end
272
281
 
273
282
  # Delete data previously stored with #set.
@@ -21,6 +21,14 @@ module Hoodoo
21
21
  #
22
22
  class Memcached < Hoodoo::TransientStore::Base
23
23
 
24
+ # Overrideable access to this object's Dalli::Client instance. It is
25
+ # inadvisable to couple calling code directly into this interface as it
26
+ # is a Hoodoo::TransientStore::Memcached specialisation, but if deemed
27
+ # absolutely necessary the Dalli client can be override with a
28
+ # customised version.
29
+ #
30
+ attr_accessor :client
31
+
24
32
  # See Hoodoo::TransientStore::Base::new for details.
25
33
  #
26
34
  # Do not instantiate this class directly. Use
@@ -12,6 +12,6 @@ module Hoodoo
12
12
  # The Hoodoo gem version. If this changes, ensure that the date in
13
13
  # "hoodoo.gemspec" is correct and run "bundle install" (or "update").
14
14
  #
15
- VERSION = '1.14.0'
15
+ VERSION = '1.15.0'
16
16
 
17
17
  end
@@ -309,7 +309,7 @@ describe Hoodoo::ActiveRecord::Finder do
309
309
  context 'only makes one database call when' do
310
310
 
311
311
  it 'finding on the first attribute' do
312
- count = count_database_calls_in do
312
+ count = spec_helper_count_database_calls_in do
313
313
  found = RSpecModelFinderTest.acquire( @id )
314
314
  expect( found ).to eq(@a)
315
315
  end
@@ -318,7 +318,7 @@ describe Hoodoo::ActiveRecord::Finder do
318
318
  end
319
319
 
320
320
  it 'finding on the second attribute' do
321
- count = count_database_calls_in do
321
+ count = spec_helper_count_database_calls_in do
322
322
  found = RSpecModelFinderTest.acquire( @uuid )
323
323
  expect( found ).to eq(@b)
324
324
  end
@@ -327,7 +327,7 @@ describe Hoodoo::ActiveRecord::Finder do
327
327
  end
328
328
 
329
329
  it 'finding on the third attribute' do
330
- count = count_database_calls_in do
330
+ count = spec_helper_count_database_calls_in do
331
331
  found = RSpecModelFinderTest.acquire( @code )
332
332
  expect( found ).to eq(@c)
333
333
  end
@@ -336,7 +336,7 @@ describe Hoodoo::ActiveRecord::Finder do
336
336
  end
337
337
 
338
338
  it 'checking all three attributes but finding nothing' do
339
- count = count_database_calls_in do
339
+ count = spec_helper_count_database_calls_in do
340
340
  found = RSpecModelFinderTest.acquire( Hoodoo::UUID.generate )
341
341
  expect( found ).to be_nil
342
342
  end
@@ -214,6 +214,10 @@ end
214
214
 
215
215
  describe Hoodoo::Client do
216
216
 
217
+ before :each do
218
+ spec_helper_use_mock_memcached()
219
+ end
220
+
217
221
  before :all do
218
222
  @old_test_session = Hoodoo::Services::Middleware.test_session()
219
223
  @port = spec_helper_start_svc_app_in_thread_for( RSpecClientTestService )
@@ -304,6 +304,8 @@ end
304
304
  describe Hoodoo::Services::Middleware do
305
305
 
306
306
  before :each do
307
+ spec_helper_use_mock_memcached()
308
+
307
309
  @session_id = Hoodoo::UUID.generate
308
310
  @caller_id = Hoodoo::UUID.generate
309
311
  @caller_version = 1
@@ -343,14 +345,8 @@ describe Hoodoo::Services::Middleware do
343
345
  Hoodoo::Services::Permissions::ALLOW
344
346
  )
345
347
 
346
- Hoodoo::TransientStore::Mocks::DalliClient.reset()
347
-
348
- result = @session.save_to_memcached
349
- raise "Can't save to mock Memcached (result = #{result})" unless result == :ok
350
- end
351
-
352
- after :each do
353
- Hoodoo::TransientStore::Mocks::DalliClient.reset()
348
+ result = @session.save_to_store
349
+ raise "Can't save to mock session store (result = #{result})" unless result == :ok
354
350
  end
355
351
 
356
352
  ############################################################################
@@ -398,8 +394,8 @@ describe Hoodoo::Services::Middleware do
398
394
  Hoodoo::Services::Permissions::ALLOW
399
395
  )
400
396
 
401
- result = @session.save_to_memcached
402
- raise "Can't save to mock Memcached (result = #{result})" unless result == :ok
397
+ result = @session.save_to_store
398
+ raise "Can't save to mock session store (result = #{result})" unless result == :ok
403
399
 
404
400
  expect_any_instance_of(RSpecAddPermTestClockCallsDateNoPermsImplementation).to receive( :show ).once.and_call_original
405
401
  expect_any_instance_of(RSpecAddPermTestDateImplementation).to receive( :show ).once.and_call_original
@@ -432,8 +428,8 @@ describe Hoodoo::Services::Middleware do
432
428
  Hoodoo::Services::Permissions::ALLOW
433
429
  )
434
430
 
435
- result = @session.save_to_memcached
436
- raise "Can't save to mock Memcached (result = #{result})" unless result == :ok
431
+ result = @session.save_to_store
432
+ raise "Can't save to mock session store (result = #{result})" unless result == :ok
437
433
 
438
434
  expect_any_instance_of(RSpecAddPermTestClockCallsDateNoPermsImplementation).to receive( :show ).once.and_call_original
439
435
  expect_any_instance_of(RSpecAddPermTestDateImplementation).to receive( :show ).once.and_call_original
@@ -488,8 +484,8 @@ describe Hoodoo::Services::Middleware do
488
484
  Hoodoo::Services::Permissions::ALLOW
489
485
  )
490
486
 
491
- result = @session.save_to_memcached
492
- raise "Can't save to mock Memcached (result = #{result})" unless result == :ok
487
+ result = @session.save_to_store
488
+ raise "Can't save to mock session store (result = #{result})" unless result == :ok
493
489
 
494
490
  expect_any_instance_of(RSpecAddPermTestClockCallsDateNoPermsImplementation).to receive( :show ).once.and_call_original
495
491
  expect_any_instance_of(RSpecAddPermTestDateImplementation).to receive( :show ).once.and_call_original
@@ -578,8 +574,8 @@ describe Hoodoo::Services::Middleware do
578
574
  Hoodoo::Services::Permissions::ALLOW
579
575
  )
580
576
 
581
- result = @session.save_to_memcached
582
- raise "Can't save to mock Memcached (result = #{result})" unless result == :ok
577
+ result = @session.save_to_store
578
+ raise "Can't save to mock session store (result = #{result})" unless result == :ok
583
579
 
584
580
  expect_any_instance_of(RSpecAddPermTestClockImplementation).to receive( :list ).once.and_call_original
585
581
  expect_any_instance_of(RSpecAddPermTestDateImplementation).to receive( :show ).once.and_call_original
@@ -646,7 +642,7 @@ describe Hoodoo::Services::Middleware do
646
642
  #
647
643
  it 'can deal with inter-resource session errors (2)' do
648
644
  expect_any_instance_of(RSpecAddPermTestClockImplementation).to receive( :show ).once.and_call_original
649
- expect_any_instance_of(Hoodoo::Services::Session).to receive( :save_to_memcached ).once.and_return( :outdated )
645
+ expect_any_instance_of(Hoodoo::Services::Session).to receive( :save_to_store ).once.and_return( :outdated )
650
646
  expect_any_instance_of(RSpecAddPermTestDateImplementation).to_not receive( :show )
651
647
 
652
648
  get '/v1/rspec_add_perm_test_clocks/any',
@@ -663,7 +659,7 @@ describe Hoodoo::Services::Middleware do
663
659
  #
664
660
  it 'can deal with inter-resource session errors (3)' do
665
661
  expect_any_instance_of(RSpecAddPermTestClockImplementation).to receive( :show ).once.and_call_original
666
- expect_any_instance_of(Hoodoo::Services::Session).to receive( :save_to_memcached ).once.and_return( :fail )
662
+ expect_any_instance_of(Hoodoo::Services::Session).to receive( :save_to_store ).once.and_return( :fail )
667
663
  expect_any_instance_of(RSpecAddPermTestDateImplementation).to_not receive( :show )
668
664
 
669
665
  get '/v1/rspec_add_perm_test_clocks/any',
@@ -683,8 +679,8 @@ describe Hoodoo::Services::Middleware do
683
679
  it 'handles nil permissions' do
684
680
  @session.permissions = nil
685
681
 
686
- result = @session.save_to_memcached
687
- raise "Can't save to mock Memcached (result = #{result})" unless result == :ok
682
+ result = @session.save_to_store
683
+ raise "Can't save to mock session store (result = #{result})" unless result == :ok
688
684
 
689
685
  expect_any_instance_of(RSpecAddPermTestClockImplementation).to_not receive( :show )
690
686
 
@@ -701,8 +697,8 @@ describe Hoodoo::Services::Middleware do
701
697
  it 'handles empty permissions' do
702
698
  @session.permissions = Hoodoo::Services::Permissions.new( {} )
703
699
 
704
- result = @session.save_to_memcached
705
- raise "Can't save to mock Memcached (result = #{result})" unless result == :ok
700
+ result = @session.save_to_store
701
+ raise "Can't save to mock session store (result = #{result})" unless result == :ok
706
702
 
707
703
  expect_any_instance_of(RSpecAddPermTestClockImplementation).to_not receive( :show )
708
704
 
@@ -719,8 +715,8 @@ describe Hoodoo::Services::Middleware do
719
715
  it 'handles default #verify response as deny' do
720
716
  @session.permissions.set_resource( :RSpecAddPermTestClock, :show, Hoodoo::Services::Permissions::ASK )
721
717
 
722
- result = @session.save_to_memcached
723
- raise "Can't save to mock Memcached (result = #{result})" unless result == :ok
718
+ result = @session.save_to_store
719
+ raise "Can't save to mock session store (result = #{result})" unless result == :ok
724
720
 
725
721
  expect_any_instance_of(Hoodoo::Services::Implementation).to receive( :verify ).once.and_call_original
726
722
  expect_any_instance_of(RSpecAddPermTestClockImplementation).to_not receive( :show ).once.and_call_original
@@ -802,8 +798,8 @@ describe Hoodoo::Services::Middleware do
802
798
  Hoodoo::Services::Permissions::ALLOW
803
799
  )
804
800
 
805
- result = @session.save_to_memcached
806
- raise "Can't save to mock Memcached (result = #{result})" unless result == :ok
801
+ result = @session.save_to_store
802
+ raise "Can't save to mock session store (result = #{result})" unless result == :ok
807
803
 
808
804
  expect_any_instance_of(RSpecAddPermTestClockCallsDateNoPermsImplementation).to receive( :show ).once.and_call_original
809
805
  expect_any_instance_of(RSpecAddPermTestDateImplementation).to receive( :show ).once.and_call_original
@@ -834,8 +830,8 @@ describe Hoodoo::Services::Middleware do
834
830
  Hoodoo::Services::Permissions::ALLOW
835
831
  )
836
832
 
837
- result = @session.save_to_memcached
838
- raise "Can't save to mock Memcached (result = #{result})" unless result == :ok
833
+ result = @session.save_to_store
834
+ raise "Can't save to mock session store (result = #{result})" unless result == :ok
839
835
 
840
836
  expect_any_instance_of(RSpecAddPermTestClockCallsDateNoPermsImplementation).to receive( :show ).once.and_call_original
841
837
  expect_any_instance_of(RSpecAddPermTestDateImplementation).to receive( :show ).once.and_call_original
@@ -879,8 +875,8 @@ describe Hoodoo::Services::Middleware do
879
875
  Hoodoo::Services::Permissions::ALLOW
880
876
  )
881
877
 
882
- result = @session.save_to_memcached
883
- raise "Can't save to mock Memcached (result = #{result})" unless result == :ok
878
+ result = @session.save_to_store
879
+ raise "Can't save to mock session store (result = #{result})" unless result == :ok
884
880
 
885
881
  expect_any_instance_of(RSpecAddPermTestClockCallsDateNoPermsImplementation).to receive( :show ).once.and_call_original
886
882
  expect_any_instance_of(RSpecAddPermTestDateImplementation).to receive( :show ).once.and_call_original
@@ -954,8 +950,8 @@ describe Hoodoo::Services::Middleware do
954
950
  Hoodoo::Services::Permissions::ALLOW
955
951
  )
956
952
 
957
- result = @session.save_to_memcached
958
- raise "Can't save to mock Memcached (result = #{result})" unless result == :ok
953
+ result = @session.save_to_store
954
+ raise "Can't save to mock session store (result = #{result})" unless result == :ok
959
955
 
960
956
  expect_any_instance_of(RSpecAddPermTestClockImplementation).to receive( :list ).once.and_call_original
961
957
  expect_any_instance_of(RSpecAddPermTestDateImplementation).to receive( :show ).once.and_call_original
@@ -1,459 +1,591 @@
1
1
  require 'spec_helper'
2
+ require 'hoodoo/transient_store/mocks/dalli_client'
2
3
 
3
4
  describe Hoodoo::Services::Session do
4
5
 
5
6
  before :each do
6
- Hoodoo::TransientStore::Mocks::DalliClient.reset()
7
+ spec_helper_use_mock_memcached()
7
8
  end
8
9
 
9
- it 'includes a legacy alias to the TransientStore mock back-end' do
10
- expect( Hoodoo::Services::Session::MockDalliClient == Hoodoo::TransientStore::Mocks::DalliClient ).to eql( true )
11
- expect {
12
- Hoodoo::TransientStore::Mocks::DalliClient.reset()
13
- }.to_not raise_error
14
- end
10
+ # ==========================================================================
15
11
 
16
- it 'initialises with default options' do
17
- s = described_class.new()
18
- expect( s.created_at ).to be_a( Time )
19
- expect( Hoodoo::UUID.valid?( s.session_id ) ).to eq( true )
20
- expect( s.memcached_host ).to be_nil
21
- expect( s.caller_id ).to be_nil
22
- expect( s.caller_version ).to eq( 0 )
23
- end
12
+ context 'basics' do
13
+ it 'initialises with default options' do
14
+ s = described_class.new()
15
+ expect( s.created_at ).to be_a( Time )
16
+ expect( Hoodoo::UUID.valid?( s.session_id ) ).to eq( true )
17
+ expect( s.memcached_host ).to be_nil
18
+ expect( s.caller_id ).to be_nil
19
+ expect( s.caller_version ).to eq( 0 )
20
+ end
24
21
 
25
- it 'initialises with given options' do
26
- s = described_class.new(
27
- :session_id => '1234',
28
- :memcached_host => 'abcd',
29
- :caller_id => '0987',
30
- :caller_version => 2
31
- )
32
- expect( s.created_at ).to be_a( Time )
33
- expect( s.session_id ).to eq( '1234' )
34
- expect( s.memcached_host ).to eq( 'abcd' )
35
- expect( s.caller_id ).to eq( '0987' )
36
- expect( s.caller_version ).to eq( 2 )
37
- end
22
+ it 'initialises with given options' do
23
+ s = described_class.new(
24
+ :session_id => '1234',
25
+ :memcached_host => 'abcd',
26
+ :caller_id => '0987',
27
+ :caller_version => 2
28
+ )
29
+ expect( s.created_at ).to be_a( Time )
30
+ expect( s.session_id ).to eq( '1234' )
31
+ expect( s.memcached_host ).to eq( 'abcd' )
32
+ expect( s.caller_id ).to eq( '0987' )
33
+ expect( s.caller_version ).to eq( 2 )
34
+ end
38
35
 
39
- it 'reports not expired when it has no expiry' do
40
- s = described_class.new
41
- expect( s.expired? ).to eq( false )
42
- end
36
+ it 'reports not expired when it has no expiry' do
37
+ s = described_class.new
38
+ expect( s.expired? ).to eq( false )
39
+ end
43
40
 
44
- it 'knows if expired' do
45
- s = described_class.new
46
- s.instance_variable_set( '@expires_at', Time.now - 1 )
47
- expect( s.expired? ).to eq( true )
48
- end
41
+ it 'knows if expired' do
42
+ s = described_class.new
43
+ s.instance_variable_set( '@expires_at', Time.now - 1 )
44
+ expect( s.expired? ).to eq( true )
45
+ end
49
46
 
50
- it 'converts to a Hash' do
51
- s = described_class.new(
52
- :session_id => '1234',
53
- :memcached_host => 'abcd',
54
- :caller_id => '0987',
55
- :caller_version => 2
56
- )
57
- p = Hoodoo::Services::Permissions.new
47
+ it 'converts to a Hash' do
48
+ s = described_class.new(
49
+ :session_id => '1234',
50
+ :memcached_host => 'abcd',
51
+ :caller_id => '0987',
52
+ :caller_version => 2
53
+ )
54
+ p = Hoodoo::Services::Permissions.new
58
55
 
59
- s.permissions = p
60
- s.identity = { 'foo' => 'foo', 'bar' => 'bar' }
61
- s.scoping = { 'baz' => [ 'foo', 'bar', 'baz' ] }
56
+ s.permissions = p
57
+ s.identity = { 'foo' => 'foo', 'bar' => 'bar' }
58
+ s.scoping = { 'baz' => [ 'foo', 'bar', 'baz' ] }
62
59
 
63
- h = s.to_h
60
+ h = s.to_h
64
61
 
65
- expect( h ).to eq( {
66
- 'session_id' => '1234',
67
- 'caller_id' => '0987',
68
- 'caller_version' => 2,
62
+ expect( h ).to eq( {
63
+ 'session_id' => '1234',
64
+ 'caller_id' => '0987',
65
+ 'caller_version' => 2,
69
66
 
70
- 'created_at' => s.created_at.iso8601,
67
+ 'created_at' => s.created_at.iso8601,
71
68
 
72
- 'identity' => { 'foo' => 'foo', 'bar' => 'bar' },
73
- 'scoping' => { 'baz' => [ 'foo', 'bar', 'baz' ] },
74
- 'permissions' => p.to_h()
75
- } )
76
- end
69
+ 'identity' => { 'foo' => 'foo', 'bar' => 'bar' },
70
+ 'scoping' => { 'baz' => [ 'foo', 'bar', 'baz' ] },
71
+ 'permissions' => p.to_h()
72
+ } )
73
+ end
77
74
 
78
- it 'reads from a Hash' do
79
- s = described_class.new
80
- p = Hoodoo::Services::Permissions.new
81
- c = Time.now.utc
82
- e = Time.now.utc + 10
83
- h = {
84
- 'session_id' => '1234',
85
- 'caller_id' => '0987',
86
- 'caller_version' => 2,
87
-
88
- 'created_at' => c.iso8601,
89
- 'expires_at' => e.iso8601,
90
-
91
- 'identity' => { 'foo' => 'foo', 'bar' => 'bar' },
92
- 'scoping' => { 'baz' => [ 'foo', 'bar', 'baz' ] },
93
- 'permissions' => p.to_h()
94
- }
95
-
96
- s.from_h!( h )
97
-
98
- expect( s.session_id ).to eq( '1234' )
99
- expect( s.caller_id ).to eq( '0987' )
100
- expect( s.caller_version ).to eq( 2 )
101
- expect( s.created_at ).to eq( Time.parse( c.iso8601 ) )
102
- expect( s.expires_at ).to eq( Time.parse( e.iso8601 ) )
103
- expect( s.identity.foo ).to eq( 'foo' )
104
- expect( s.identity.bar ).to eq( 'bar' )
105
- expect( s.scoping.baz ).to eq( [ 'foo', 'bar', 'baz' ] )
106
- expect( s.permissions.to_h ).to eq( p.to_h )
107
- end
75
+ it 'reads from a Hash' do
76
+ s = described_class.new
77
+ p = Hoodoo::Services::Permissions.new
78
+ c = Time.now.utc
79
+ e = Time.now.utc + 10
80
+ h = {
81
+ 'session_id' => '1234',
82
+ 'caller_id' => '0987',
83
+ 'caller_version' => 2,
84
+
85
+ 'created_at' => c.iso8601,
86
+ 'expires_at' => e.iso8601,
87
+
88
+ 'identity' => { 'foo' => 'foo', 'bar' => 'bar' },
89
+ 'scoping' => { 'baz' => [ 'foo', 'bar', 'baz' ] },
90
+ 'permissions' => p.to_h()
91
+ }
92
+
93
+ s.from_h!( h )
94
+
95
+ expect( s.session_id ).to eq( '1234' )
96
+ expect( s.caller_id ).to eq( '0987' )
97
+ expect( s.caller_version ).to eq( 2 )
98
+ expect( s.created_at ).to eq( Time.parse( c.iso8601 ) )
99
+ expect( s.expires_at ).to eq( Time.parse( e.iso8601 ) )
100
+ expect( s.identity.foo ).to eq( 'foo' )
101
+ expect( s.identity.bar ).to eq( 'bar' )
102
+ expect( s.scoping.baz ).to eq( [ 'foo', 'bar', 'baz' ] )
103
+ expect( s.permissions.to_h ).to eq( p.to_h )
104
+ end
108
105
 
109
- it 'saves/loads to/from Memcached' do
110
- s1 = described_class.new(
111
- :session_id => '1234',
112
- :memcached_host => 'abcd',
113
- :caller_id => '0987',
114
- :caller_version => 2
115
- )
116
-
117
- expect( s1.save_to_memcached ).to eq( :ok )
118
-
119
- store = Hoodoo::TransientStore::Mocks::DalliClient.store()
120
- expect( store[ '1234' ] ).to_not be_nil
121
- expect( store[ '0987' ] ).to eq( { :expires_at => nil, :value => { 'version' => 2 } } )
122
-
123
- # Check that session gains an expiry time when saved.
124
- #
125
- expect( s1.expires_at ).to be_a( Time )
126
-
127
- # Ensure "created_at" is significantly different in the next session.
128
- # This is important to reliably detect session load failures in testing
129
- # given "#iso8601()" time resolution limits and so-on.
130
- #
131
- sleep( 0.2 )
132
-
133
- s2 = described_class.new
134
- expect( s2.load_from_memcached!( s1.session_id ) ).to eq( :ok )
135
-
136
- expect( s2.created_at ).to eq( Time.parse( s1.created_at.iso8601 ) )
137
- expect( s2.expires_at ).to eq( Time.parse( s1.expires_at.iso8601 ) )
138
- expect( s2.session_id ).to eq( s1.session_id )
139
- expect( s2.memcached_host ).to be_nil
140
- expect( s2.caller_id ).to eq( s1.caller_id )
141
- expect( s2.caller_version ).to eq( s1.caller_version )
142
- end
106
+ it 'saves/loads to/from Memcached' do
107
+ s1 = described_class.new(
108
+ :session_id => '1234',
109
+ :memcached_host => 'abcd',
110
+ :caller_id => '0987',
111
+ :caller_version => 2
112
+ )
113
+
114
+ expect( s1.save_to_store ).to eq( :ok )
115
+
116
+ store = Hoodoo::TransientStore::Mocks::DalliClient.store()
117
+ expect( store[ '1234' ] ).to_not be_nil
118
+ expect( store[ '0987' ] ).to include( { :value => { 'version' => 2 } } )
119
+ expect( store[ '0987' ] ).to have_key( :expires_at )
120
+ expect( store[ '0987' ][ :expires_at ] ).to be_a( Time )
121
+
122
+ # Check that session gains an expiry time when saved.
123
+ #
124
+ expect( s1.expires_at ).to be_a( Time )
125
+
126
+ # Ensure "created_at" is significantly different in the next session.
127
+ # This is important to reliably detect session load failures in testing
128
+ # given "#iso8601()" time resolution limits and so-on.
129
+ #
130
+ sleep( 0.2 )
131
+
132
+ s2 = described_class.new
133
+ expect( s2.load_from_store!( s1.session_id ) ).to eq( :ok )
134
+
135
+ expect( s2.created_at ).to eq( Time.parse( s1.created_at.iso8601 ) )
136
+ expect( s2.expires_at ).to eq( Time.parse( s1.expires_at.iso8601 ) )
137
+ expect( s2.session_id ).to eq( s1.session_id )
138
+ expect( s2.memcached_host ).to be_nil
139
+ expect( s2.caller_id ).to eq( s1.caller_id )
140
+ expect( s2.caller_version ).to eq( s1.caller_version )
141
+ end
143
142
 
144
- it 'refuses to save if a newer caller version is present' do
145
- expect( described_class ).to receive( :connect_to_memcached ).twice.and_return( Hoodoo::TransientStore::Mocks::DalliClient.new )
143
+ it 'can be deleted' do
144
+ s = described_class.new(
145
+ :session_id => '1234',
146
+ :memcached_host => 'abcd',
147
+ :caller_id => '0987',
148
+ :caller_version => 1
149
+ )
146
150
 
147
- # Save a session with a high caller version
151
+ s.save_to_store
148
152
 
149
- s1 = described_class.new(
150
- :session_id => '1234',
151
- :memcached_host => 'abcd',
152
- :caller_id => '0987',
153
- :caller_version => 4
154
- )
153
+ expect{ s.delete_from_store }.to change{ s.load_from_store!( s.session_id ) }.from( :ok ).to( :not_found )
154
+ end
155
155
 
156
- expect( s1.save_to_memcached ).to eq( :ok )
156
+ it 'handles attempts to delete not-found things' do
157
+ s = described_class.new(
158
+ :session_id => '1234',
159
+ :memcached_host => 'abcd',
160
+ :caller_id => '0987',
161
+ :caller_version => 1
162
+ )
157
163
 
158
- # Save another with, initially, a lower caller version. The idea here
159
- # is that session creation is underway when a caller gets updated.
164
+ expect( s.delete_from_store ).to eq( :ok )
165
+ end
166
+ end
160
167
 
161
- s2 = described_class.new(
162
- :session_id => '2345',
163
- :memcached_host => 'abcd',
164
- :caller_id => '0987',
165
- :caller_version => 3
166
- )
168
+ # ==========================================================================
167
169
 
168
- expect( s2.save_to_memcached ).to eq( :outdated )
169
- end
170
+ context 'version manager' do
171
+ it 'refuses to save if a newer caller version is present' do
170
172
 
171
- it 'invalidates a session if the client ID advances during its lifetime' do
172
- expect( described_class ).to receive( :connect_to_memcached ).exactly( 4 ).times.and_return( Hoodoo::TransientStore::Mocks::DalliClient.new )
173
- loader = described_class.new
173
+ # Save a session with a high caller version
174
174
 
175
- # Save a session with a low caller version.
175
+ s1 = described_class.new(
176
+ :session_id => '1234',
177
+ :memcached_host => 'abcd',
178
+ :caller_id => '0987',
179
+ :caller_version => 4
180
+ )
176
181
 
177
- s1 = described_class.new(
178
- :session_id => '1234',
179
- :memcached_host => 'abcd',
180
- :caller_id => '0987',
181
- :caller_version => 1
182
- )
182
+ expect( s1.save_to_store ).to eq( :ok )
183
183
 
184
- expect( s1.save_to_memcached ).to eq( :ok )
184
+ # Save another with, initially, a lower caller version. The idea here
185
+ # is that session creation is underway when a caller gets updated.
185
186
 
186
- # Save another with a higher caller version.
187
+ s2 = described_class.new(
188
+ :session_id => '2345',
189
+ :memcached_host => 'abcd',
190
+ :caller_id => '0987',
191
+ :caller_version => 3
192
+ )
187
193
 
188
- s2 = described_class.new(
189
- :session_id => '2345',
190
- :memcached_host => 'abcd',
191
- :caller_id => '0987',
192
- :caller_version => 2
193
- )
194
+ expect( s2.save_to_store ).to eq( :outdated )
195
+ end
194
196
 
195
- expect( s2.save_to_memcached ).to eq( :ok )
197
+ it 'invalidates a session if the caller version advances during its lifetime' do
198
+ loader = described_class.new
196
199
 
197
- # Should not be able to load the first one anymore.
200
+ # Save a session with a low caller version.
198
201
 
199
- expect( loader.load_from_memcached!( '1234' ) ).to eq( :outdated )
200
- expect( loader.load_from_memcached!( '2345' ) ).to eq( :ok )
201
- end
202
+ s1 = described_class.new(
203
+ :session_id => '1234',
204
+ :memcached_host => 'abcd',
205
+ :caller_id => '0987',
206
+ :caller_version => 1
207
+ )
202
208
 
203
- it 'refuses to load if the caller version is outdated' do
204
- expect( described_class ).to receive( :connect_to_memcached ).exactly( 5 ).times.and_return( Hoodoo::TransientStore::Mocks::DalliClient.new )
205
- loader = described_class.new
209
+ expect( s1.save_to_store ).to eq( :ok )
206
210
 
207
- # Save a session with a low caller version
211
+ # Save another with a higher caller version.
208
212
 
209
- s1 = described_class.new(
210
- :session_id => '1234',
211
- :memcached_host => 'abcd',
212
- :caller_id => '0987',
213
- :caller_version => 1
214
- )
213
+ s2 = described_class.new(
214
+ :session_id => '2345',
215
+ :memcached_host => 'abcd',
216
+ :caller_id => '0987',
217
+ :caller_version => 2
218
+ )
215
219
 
216
- expect( s1.save_to_memcached ).to eq( :ok )
220
+ expect( s2.save_to_store ).to eq( :ok )
217
221
 
218
- # Should be able to load it back.
222
+ # Should not be able to load the first one anymore.
219
223
 
220
- expect( loader.load_from_memcached!( '1234' ) ).to eq( :ok )
224
+ expect( loader.load_from_store!( '1234' ) ).to eq( :outdated )
225
+ expect( loader.load_from_store!( '2345' ) ).to eq( :ok )
226
+ end
221
227
 
222
- # Save another with a higher caller version.
228
+ it 'refuses to load session if the caller version is outdated' do
229
+ loader = described_class.new
223
230
 
224
- s2 = described_class.new(
225
- :session_id => '2345',
226
- :memcached_host => 'abcd',
227
- :caller_id => '0987',
228
- :caller_version => 2
229
- )
231
+ # Save a session with a low caller version
230
232
 
231
- expect( s2.save_to_memcached ).to eq( :ok )
233
+ s1 = described_class.new(
234
+ :session_id => '1234',
235
+ :memcached_host => 'abcd',
236
+ :caller_id => '0987',
237
+ :caller_version => 1
238
+ )
232
239
 
233
- # Try to load the first one again; should fail.
240
+ expect( s1.save_to_store ).to eq( :ok )
234
241
 
235
- expect( loader.load_from_memcached!( '1234' ) ).to eq( :outdated )
242
+ # Should be able to load it back.
236
243
 
237
- # The newer one should load OK.
244
+ expect( loader.load_from_store!( '1234' ) ).to eq( :ok )
238
245
 
239
- expect( loader.load_from_memcached!( '2345' ) ).to eq( :ok )
240
- end
246
+ # Save another with a higher caller version.
241
247
 
242
- it 'refuses to load if expired' do
243
- expect( described_class ).to receive( :connect_to_memcached ).twice.and_return( Hoodoo::TransientStore::Mocks::DalliClient.new )
244
- loader = described_class.new
248
+ s2 = described_class.new(
249
+ :session_id => '2345',
250
+ :memcached_host => 'abcd',
251
+ :caller_id => '0987',
252
+ :caller_version => 2
253
+ )
245
254
 
246
- # Save a session with a high caller version
255
+ expect( s2.save_to_store ).to eq( :ok )
247
256
 
248
- s = described_class.new(
249
- :session_id => '1234',
250
- :memcached_host => 'abcd',
251
- :caller_id => '0987',
252
- :caller_version => 1
253
- )
257
+ # Try to load the first one again; should fail.
254
258
 
255
- expect( s ).to receive( :to_h ).and_wrap_original do | obj, args |
256
- h = obj.call( *args )
257
- h[ 'expires_at' ] = ( Time.now - 1 ).utc.iso8601
258
- h
259
- end
259
+ expect( loader.load_from_store!( '1234' ) ).to eq( :outdated )
260
260
 
261
- expect( s.save_to_memcached ).to eq( :ok )
262
- expect( loader.load_from_memcached!( '1234' ) ).to eq( :outdated )
263
- end
261
+ # The newer one should load OK.
262
+
263
+ expect( loader.load_from_store!( '2345' ) ).to eq( :ok )
264
+ end
264
265
 
265
- it 'can explicitly update a caller' do
266
- s = described_class.new(
267
- :session_id => '1234',
268
- :memcached_host => 'abcd',
269
- :caller_id => '0987',
270
- :caller_version => 1
271
- )
266
+ it 'refuses to load session if the caller version is missing/expired' do
267
+ loader = described_class.new
268
+
269
+ # Save a session for caller ID '0987'.
270
+ #
271
+ s1 = described_class.new(
272
+ :session_id => '1234',
273
+ :memcached_host => 'abcd',
274
+ :caller_id => '0987',
275
+ :caller_version => 1
276
+ )
277
+
278
+ expect( s1.save_to_store ).to eq( :ok )
279
+
280
+ # Should be able to load it back.
281
+ #
282
+ expect( loader.load_from_store!( '1234' ) ).to eq( :ok )
283
+
284
+ # Manually wipe the caller version record, simulating expiry.
285
+ #
286
+ store = Hoodoo::TransientStore::Mocks::DalliClient.store()
287
+ store.delete( '0987' )
288
+
289
+ # Create a new session for some random other caller, reaffirming
290
+ # that we can still create new sessions for previously unrecorded
291
+ # caller IDs/versions.
292
+
293
+ s2 = described_class.new(
294
+ :session_id => '2345',
295
+ :memcached_host => 'abcd',
296
+ :caller_id => Hoodoo::UUID.generate(),
297
+ :caller_version => 1
298
+ )
299
+
300
+ expect( s2.save_to_store ).to eq( :ok )
301
+
302
+ # Try to load the first one again; should fail.
303
+ #
304
+ expect( loader.load_from_store!( '1234' ) ).to eq( :outdated )
305
+
306
+ # The newer one should load OK.
307
+ #
308
+ expect( loader.load_from_store!( '2345' ) ).to eq( :ok )
309
+ end
272
310
 
273
- expect( described_class ).to receive( :connect_to_memcached ).once.and_return( Hoodoo::TransientStore::Mocks::DalliClient.new )
311
+ it 'refuses to load session if the session itself is expired' do
312
+ loader = described_class.new
274
313
 
275
- expect( s.update_caller_version_in_memcached( '9944', 23 ) ).to eq( :ok )
276
- expect( s.update_caller_version_in_memcached( 'abcd', 2, Hoodoo::TransientStore::Mocks::DalliClient.new ) ).to eq( :ok )
314
+ # Save a session with a high caller version
277
315
 
278
- store = Hoodoo::TransientStore::Mocks::DalliClient.store()
279
- expect( store[ '9944' ] ).to eq( { :expires_at => nil, :value => { 'version' => 23 } } )
280
- expect( store[ 'abcd' ] ).to eq( { :expires_at => nil, :value => { 'version' => 2 } } )
281
- end
316
+ s = described_class.new(
317
+ :session_id => '1234',
318
+ :memcached_host => 'abcd',
319
+ :caller_id => '0987',
320
+ :caller_version => 1
321
+ )
282
322
 
283
- it 'handles invalid session IDs when loading' do
284
- expect( described_class ).to receive( :connect_to_memcached ).once.and_return( Hoodoo::TransientStore::Mocks::DalliClient.new )
285
- loader = described_class.new
286
- expect( loader.load_from_memcached!( '1234' ) ).to eq( :not_found )
287
- end
323
+ expect( s ).to receive( :to_h ).and_wrap_original do | obj, args |
324
+ h = obj.call( *args )
325
+ h[ 'expires_at' ] = ( Time.now - 1 ).utc.iso8601
326
+ h
327
+ end
288
328
 
289
- it 'complains if there is no caller ID' do
290
- s = described_class.new
291
- expect {
292
- s.save_to_memcached()
293
- }.to raise_error RuntimeError
329
+ expect( s.save_to_store ).to eq( :ok )
330
+ expect( loader.load_from_store!( '1234' ) ).to eq( :outdated )
331
+ end
294
332
  end
295
333
 
296
- it 'logs Memcached exceptions when loading' do
297
- loader = described_class.new
334
+ # ==========================================================================
298
335
 
299
- expect_any_instance_of( Hoodoo::TransientStore::Mocks::DalliClient ).to receive( :get ).once do
300
- raise 'Mock Memcached connection failure'
336
+ context 'can explicitly update a caller' do
337
+ before :each do
338
+ @session = described_class.new(
339
+ :session_id => '1234',
340
+ :memcached_host => 'abcd',
341
+ :caller_id => '0987',
342
+ :caller_version => 1
343
+ )
301
344
  end
302
345
 
303
- expect( Hoodoo::Services::Middleware.logger ).to(
304
- receive( :warn ).once.with(
305
- 'Hoodoo::Services::Session\\#load_from_memcached!: Session loading failed - connection fault or session corrupt',
306
- 'Mock Memcached connection failure'
307
- ).and_call_original
308
- )
346
+ after :each do
347
+ store = Hoodoo::TransientStore::Mocks::DalliClient.store()
348
+ expect( store[ '0987' ] ).to include( { :value => { 'version' => 23 } } )
349
+ expect( store[ 'efgh' ] ).to include( { :value => { 'version' => 3 } } )
350
+ end
309
351
 
310
- expect( loader.load_from_memcached!( '1234' ) ).to eq( :fail )
311
- end
352
+ it 'with modern interface and no caller-supplied client' do
353
+ expect( @session.update_caller_version_in_store( '0987', 23 ) ).to eq( :ok )
354
+ expect( @session.update_caller_version_in_store( 'efgh', 3 ) ).to eq( :ok )
355
+ end
312
356
 
313
- it 'logs Memcached exceptions when updating caller version during session saving' do
314
- s = described_class.new(
315
- :caller_id => '0987',
316
- :caller_version => 1
317
- )
357
+ it 'with modern interface and caller-supplied Hoodoo::TransientStore instance' do
358
+ local_store = Hoodoo::TransientStore.new(
359
+ storage_engine: :memcached,
360
+ storage_host_uri: 'abcd'
361
+ )
318
362
 
319
- # The first 'set' call is an attempt to update the caller version before
320
- # the updated session is saved.
363
+ expect( @session.update_caller_version_in_store( '0987', 23, local_store ) ).to eq( :ok )
364
+ expect( @session.update_caller_version_in_store( 'efgh', 3, local_store ) ).to eq( :ok )
365
+ end
321
366
 
322
- expect_any_instance_of( Hoodoo::TransientStore::Mocks::DalliClient ).to receive( :set ).once do
323
- raise 'Mock Memcached connection failure'
367
+ it 'with deprecated interface and no caller-supplied client' do
368
+ expect( @session.update_caller_version_in_memcached( '0987', 23 ) ).to eq( :ok )
369
+ expect( @session.update_caller_version_in_memcached( 'efgh', 3 ) ).to eq( :ok )
324
370
  end
325
371
 
326
- expect( Hoodoo::Services::Middleware.logger ).to(
327
- receive( :warn ).once.with(
328
- 'Hoodoo::Services::Session\\#update_caller_version_in_memcached: Client version update - connection fault or corrupt record',
329
- 'Mock Memcached connection failure'
330
- ).and_call_original
331
- )
372
+ it 'with deprecated interface and caller-supplied Dalli::Client instance' do
373
+ local_store = Hoodoo::TransientStore::Mocks::DalliClient.new
332
374
 
333
- expect( s.save_to_memcached() ).to eq( :fail )
375
+ expect( @session.update_caller_version_in_memcached( '0987', 23, local_store ) ).to eq( :ok )
376
+ expect( @session.update_caller_version_in_memcached( 'efgh', 3, local_store ) ).to eq( :ok )
377
+ end
334
378
  end
335
379
 
336
- it 'logs Memcached exceptions when saving session' do
337
- s = described_class.new(
338
- :caller_id => '0987',
339
- :caller_version => 1
340
- )
380
+ # ==========================================================================
341
381
 
342
- expect_any_instance_of( Hoodoo::TransientStore::Mocks::DalliClient ).to receive( :set ).once.and_call_original
343
- expect_any_instance_of( Hoodoo::TransientStore::Mocks::DalliClient ).to receive( :set ).once do
344
- raise 'Mock Memcached connection failure'
382
+ context 'error handling code' do
383
+ it 'handles invalid session IDs when loading' do
384
+ loader = described_class.new
385
+ expect( loader.load_from_store!( '1234' ) ).to eq( :not_found )
345
386
  end
346
387
 
347
- expect( Hoodoo::Services::Middleware.logger ).to(
348
- receive( :warn ).once.with(
349
- 'Hoodoo::Services::Session\\#save_to_memcached: Session saving failed - connection fault or session corrupt',
350
- 'Mock Memcached connection failure'
351
- ).and_call_original
352
- )
388
+ it 'complains if there is no caller ID' do
389
+ s = described_class.new
390
+ expect {
391
+ s.save_to_store()
392
+ }.to raise_error RuntimeError
393
+ end
353
394
 
354
- expect( s.save_to_memcached() ).to eq( :fail )
355
- end
395
+ it 'logs Memcached exceptions when loading' do
396
+ loader = described_class.new
356
397
 
357
- it 'can be deleted' do
358
- s = described_class.new(
359
- :session_id => '1234',
360
- :memcached_host => 'abcd',
361
- :caller_id => '0987',
362
- :caller_version => 1
363
- )
398
+ expect_any_instance_of( Hoodoo::TransientStore::Mocks::DalliClient ).to receive( :get ).once do
399
+ raise 'Mock Memcached connection failure'
400
+ end
364
401
 
365
- s.save_to_memcached
402
+ expect( Hoodoo::Services::Middleware.logger ).to(
403
+ receive( :warn ).once.with(
404
+ 'Hoodoo::Services::Session\\#load_from_store!: Session loading failed - connection fault or session corrupt',
405
+ 'Mock Memcached connection failure'
406
+ ).and_call_original
407
+ )
366
408
 
367
- expect{ s.delete_from_memcached }.to change{ s.load_from_memcached!( s.session_id ) }.from( :ok ).to( :not_found )
368
- end
409
+ expect( loader.load_from_store!( '1234' ) ).to eq( :fail )
410
+ end
369
411
 
370
- it 'handles attempts to delete not-found things' do
371
- s = described_class.new(
372
- :session_id => '1234',
373
- :memcached_host => 'abcd',
374
- :caller_id => '0987',
375
- :caller_version => 1
376
- )
412
+ it 'logs Memcached exceptions when updating caller version during session saving' do
413
+ s = described_class.new(
414
+ :caller_id => '0987',
415
+ :caller_version => 1
416
+ )
377
417
 
378
- expect( s.delete_from_memcached ).to eq( :not_found )
379
- end
418
+ # The first 'set' call is an attempt to update the caller version before
419
+ # the updated session is saved.
380
420
 
381
- it 'logs and reports deletion exceptions' do
382
- fdc = Hoodoo::TransientStore::Mocks::DalliClient.new
383
- s = described_class.new(
384
- :session_id => '1234',
385
- :memcached_host => 'abcd',
386
- :caller_id => '0987',
387
- :caller_version => 1
388
- )
421
+ expect_any_instance_of( Hoodoo::TransientStore::Mocks::DalliClient ).to receive( :set ).once do
422
+ raise 'Mock Memcached connection failure'
423
+ end
389
424
 
390
- s.save_to_memcached
425
+ expect( Hoodoo::Services::Middleware.logger ).to(
426
+ receive( :warn ).once.with(
427
+ 'Hoodoo::Services::Session\\#update_caller_version_in_store: Client version update - connection fault or corrupt record',
428
+ 'Mock Memcached connection failure'
429
+ ).and_call_original
430
+ )
391
431
 
392
- allow( described_class ).to receive( :connect_to_memcached ) {
393
- raise 'Intentional exception'
394
- }
432
+ expect( s.save_to_store() ).to eq( :fail )
433
+ end
395
434
 
396
- expect( Hoodoo::Services::Middleware.logger ).to receive( :warn )
397
- expect( s.delete_from_memcached ).to eq( :fail )
398
- end
435
+ it 'logs Memcached exceptions when saving session' do
436
+ s = described_class.new(
437
+ :caller_id => '0987',
438
+ :caller_version => 1
439
+ )
399
440
 
400
- # We really can't do this without insisting on testers having a
401
- # Memcached instance; instead, assume Dalli works (!) and mock it.
402
- #
403
- context 'real Memcached connection code test coverage' do
404
- before :example do
405
- # Clear the connection cache for each test
406
- Hoodoo::Services::Session.class_variable_set( '@@dalli_clients', nil ) # Hack for test!
407
- Hoodoo::TransientStore::Mocks::DalliClient.bypass( true )
408
- end
441
+ expect_any_instance_of( Hoodoo::TransientStore::Mocks::DalliClient ).to receive( :set ).once.and_call_original
442
+ expect_any_instance_of( Hoodoo::TransientStore::Mocks::DalliClient ).to receive( :set ).once do
443
+ raise 'Mock Memcached connection failure'
444
+ end
409
445
 
410
- after :example do
411
- Hoodoo::TransientStore::Mocks::DalliClient.bypass( false )
412
- end
446
+ expect( Hoodoo::Services::Middleware.logger ).to(
447
+ receive( :warn ).once.with(
448
+ 'Hoodoo::Services::Session\\#save_to_store: Session saving failed - connection fault or session corrupt',
449
+ 'Mock Memcached connection failure'
450
+ ).and_call_original
451
+ )
413
452
 
414
- it 'complains about a missing host' do
415
- expect {
416
- described_class.connect_to_memcached( nil )
417
- }.to raise_error RuntimeError
453
+ expect( s.save_to_store() ).to eq( :fail )
454
+ end
418
455
 
419
- expect {
420
- described_class.connect_to_memcached( '' )
421
- }.to raise_error RuntimeError
456
+ it 'handles unknown Hoodoo::TransientStore engine failures' do
457
+ s = described_class.new(
458
+ :session_id => '1234',
459
+ :memcached_host => 'abcd',
460
+ :caller_id => '0987',
461
+ :caller_version => 1
462
+ )
463
+
464
+ s.save_to_store
465
+ allow_any_instance_of( Hoodoo::TransientStore ).to(
466
+ receive( :delete ).
467
+ and_return( false )
468
+ )
469
+
470
+ expect( Hoodoo::Services::Middleware.logger ).to receive( :warn )
471
+ expect( s.delete_from_store ).to eq( :fail )
422
472
  end
423
473
 
424
- it 'tries to connect' do
425
- expect_any_instance_of( Dalli::Client ).to receive( :stats ).and_return( {} )
426
- expect( described_class.connect_to_memcached( '256.2.3.4:0' ) ).to be_a( Dalli::Client )
474
+ it 'handles unknown Hoodoo::TransientStore engine returned exceptions' do
475
+ s = described_class.new(
476
+ :session_id => '1234',
477
+ :memcached_host => 'abcd',
478
+ :caller_id => '0987',
479
+ :caller_version => 1
480
+ )
481
+
482
+ s.save_to_store
483
+ allow_any_instance_of( Hoodoo::TransientStore ).to(
484
+ receive( :delete ).
485
+ and_return( RuntimeError.new( 'Intentional exception' ) )
486
+ )
487
+
488
+ expect( Hoodoo::Services::Middleware.logger ).to receive( :warn )
489
+ expect( s.delete_from_store ).to eq( :fail )
427
490
  end
428
491
 
429
- it 'handles connection failures' do
430
- expect_any_instance_of( Dalli::Client ).to receive( :stats ).and_return( nil )
431
- expect {
432
- described_class.connect_to_memcached( '256.2.3.4:0' )
433
- }.to raise_error RuntimeError
492
+ it 'logs and reports internal deletion exceptions' do
493
+ s = described_class.new(
494
+ :session_id => '1234',
495
+ :memcached_host => 'abcd',
496
+ :caller_id => '0987',
497
+ :caller_version => 1
498
+ )
499
+
500
+ s.save_to_store
501
+
502
+ allow_any_instance_of( described_class ).to(
503
+ receive( :get_store ).
504
+ and_raise( 'Intentional exception' )
505
+ )
506
+
507
+ expect( Hoodoo::Services::Middleware.logger ).to receive( :warn )
508
+ expect( s.delete_from_store ).to eq( :fail )
434
509
  end
510
+ end
435
511
 
436
- it 'handles connection exceptions' do
437
- expect_any_instance_of( Dalli::Client ).to receive( :initialize ) do
438
- raise 'Mock Memcached connection failure'
512
+ # ==========================================================================
513
+
514
+ context 'legacy' do
515
+ context 'Memcached-bound code' do
516
+ before :example do
517
+
518
+ # Clear the connection cache for each test
519
+ #
520
+ Hoodoo::Services::Session.class_variable_set( '@@stores', nil ) # Hack for test!
521
+
522
+ @instance = described_class.new(
523
+ :session_id => '1234',
524
+ :memcached_host => 'abcd',
525
+ :caller_id => '0987',
526
+ :caller_version => 1
527
+ )
439
528
  end
440
529
 
441
- expect {
442
- described_class.connect_to_memcached( '256.2.3.4:0' )
443
- }.to raise_error RuntimeError
444
- end
530
+ it 'tries to connect' do
531
+ expect_any_instance_of( Hoodoo::TransientStore::Mocks::DalliClient ).to receive( :stats ).and_return( {} )
532
+ expect( @instance.send( :get_store ) ).to be_a( Hoodoo::TransientStore )
533
+ end
534
+
535
+ it 'handles connection failures' do
536
+ expect_any_instance_of( Hoodoo::TransientStore::Mocks::DalliClient ).to receive( :stats ).and_return( nil )
537
+ expect {
538
+ @instance.send( :get_store )
539
+ }.to raise_error RuntimeError
540
+ end
541
+
542
+ it 'handles connection exceptions' do
543
+ expect_any_instance_of( Hoodoo::TransientStore ).to receive( :initialize ) do
544
+ raise 'Mock TransientStore constructor failure'
545
+ end
546
+
547
+ expect {
548
+ @instance.send( :get_store )
549
+ }.to raise_error RuntimeError
550
+ end
551
+
552
+ it 'only initialises once for one given host' do
553
+ expect( Hoodoo::TransientStore::Memcached ).to receive( :new ).once.and_call_original()
554
+
555
+ @instance.memcached_host = 'one'
556
+ 1.upto( 3 ) do
557
+ @instance.send( :get_store )
558
+ end
445
559
 
446
- it 'only initialises once for one given host' do
447
- expect( Dalli::Client ).to receive( :new ).once.and_return( Hoodoo::TransientStore::Mocks::DalliClient.new )
560
+ expect( Hoodoo::TransientStore::Memcached ).to receive( :new ).once.and_call_original()
448
561
 
449
- 1.upto( 3 ) do
450
- described_class.connect_to_memcached( 'one' )
562
+ @instance.memcached_host = 'two'
563
+ 1.upto( 3 ) do
564
+ @instance.send( :get_store )
565
+ end
451
566
  end
567
+ end
452
568
 
453
- expect( Dalli::Client ).to receive( :new ).once.and_return( Hoodoo::TransientStore::Mocks::DalliClient.new )
569
+ context 'compatibility' do
570
+ it 'via alias to the TransientStore mock back-end' do
571
+ expect( Hoodoo::Services::Session::MockDalliClient == Hoodoo::TransientStore::Mocks::DalliClient ).to eql( true )
572
+ expect {
573
+ Hoodoo::TransientStore::Mocks::DalliClient.reset()
574
+ }.to_not raise_error
575
+ end
454
576
 
455
- 1.upto( 3 ) do
456
- described_class.connect_to_memcached( 'two' )
577
+ it 'via aliases for deprecated methods' do
578
+ s = described_class.new(
579
+ :session_id => '1234',
580
+ :memcached_host => 'abcd',
581
+ :caller_id => '0987',
582
+ :caller_version => 2
583
+ )
584
+
585
+ expect( s ).to respond_to( :save_to_memcached )
586
+ expect( s ).to respond_to( :load_from_memcached! )
587
+ expect( s ).to respond_to( :update_caller_version_in_memcached )
588
+ expect( s ).to respond_to( :delete_from_memcached )
457
589
  end
458
590
  end
459
591
  end