hoodoo 1.14.0 → 1.15.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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