hoodoo 1.14.0 → 1.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/hoodoo/services/middleware/endpoints/inter_resource_remote.rb +1 -1
- data/lib/hoodoo/services/middleware/middleware.rb +2 -2
- data/lib/hoodoo/services/services/session.rb +205 -144
- data/lib/hoodoo/transient_store/transient_store.rb +13 -4
- data/lib/hoodoo/transient_store/transient_store/memcached.rb +8 -0
- data/lib/hoodoo/version.rb +1 -1
- data/spec/active/active_record/finder_spec.rb +4 -4
- data/spec/client/client_spec.rb +4 -0
- data/spec/services/middleware/middleware_permissions_spec.rb +28 -32
- data/spec/services/services/session_spec.rb +485 -353
- data/spec/spec_helper.rb +31 -10
- data/spec/transient_store/transient_store/memcached_redis_mirror_spec.rb +3 -13
- data/spec/transient_store/transient_store/memcached_spec.rb +15 -0
- data/spec/transient_store/transient_store_spec.rb +11 -1
- metadata +2 -2
@@ -87,7 +87,7 @@ module Hoodoo
|
|
87
87
|
#
|
88
88
|
attr_reader :storage_engine
|
89
89
|
|
90
|
-
# Read the storage engine
|
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+::
|
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
|
-
|
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
|
data/lib/hoodoo/version.rb
CHANGED
@@ -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 =
|
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 =
|
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 =
|
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 =
|
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
|
data/spec/client/client_spec.rb
CHANGED
@@ -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
|
-
|
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.
|
402
|
-
raise "Can't save to mock
|
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.
|
436
|
-
raise "Can't save to mock
|
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.
|
492
|
-
raise "Can't save to mock
|
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.
|
582
|
-
raise "Can't save to mock
|
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( :
|
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( :
|
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.
|
687
|
-
raise "Can't save to mock
|
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.
|
705
|
-
raise "Can't save to mock
|
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.
|
723
|
-
raise "Can't save to mock
|
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.
|
806
|
-
raise "Can't save to mock
|
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.
|
838
|
-
raise "Can't save to mock
|
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.
|
883
|
-
raise "Can't save to mock
|
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.
|
958
|
-
raise "Can't save to mock
|
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
|
-
|
7
|
+
spec_helper_use_mock_memcached()
|
7
8
|
end
|
8
9
|
|
9
|
-
|
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
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
60
|
-
|
61
|
-
|
56
|
+
s.permissions = p
|
57
|
+
s.identity = { 'foo' => 'foo', 'bar' => 'bar' }
|
58
|
+
s.scoping = { 'baz' => [ 'foo', 'bar', 'baz' ] }
|
62
59
|
|
63
|
-
|
60
|
+
h = s.to_h
|
64
61
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
62
|
+
expect( h ).to eq( {
|
63
|
+
'session_id' => '1234',
|
64
|
+
'caller_id' => '0987',
|
65
|
+
'caller_version' => 2,
|
69
66
|
|
70
|
-
|
67
|
+
'created_at' => s.created_at.iso8601,
|
71
68
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
69
|
+
'identity' => { 'foo' => 'foo', 'bar' => 'bar' },
|
70
|
+
'scoping' => { 'baz' => [ 'foo', 'bar', 'baz' ] },
|
71
|
+
'permissions' => p.to_h()
|
72
|
+
} )
|
73
|
+
end
|
77
74
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
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
|
-
|
145
|
-
|
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
|
-
|
151
|
+
s.save_to_store
|
148
152
|
|
149
|
-
|
150
|
-
|
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
|
-
|
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
|
-
|
159
|
-
|
164
|
+
expect( s.delete_from_store ).to eq( :ok )
|
165
|
+
end
|
166
|
+
end
|
160
167
|
|
161
|
-
|
162
|
-
:session_id => '2345',
|
163
|
-
:memcached_host => 'abcd',
|
164
|
-
:caller_id => '0987',
|
165
|
-
:caller_version => 3
|
166
|
-
)
|
168
|
+
# ==========================================================================
|
167
169
|
|
168
|
-
|
169
|
-
|
170
|
+
context 'version manager' do
|
171
|
+
it 'refuses to save if a newer caller version is present' do
|
170
172
|
|
171
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
189
|
-
|
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
|
-
|
197
|
+
it 'invalidates a session if the caller version advances during its lifetime' do
|
198
|
+
loader = described_class.new
|
196
199
|
|
197
|
-
|
200
|
+
# Save a session with a low caller version.
|
198
201
|
|
199
|
-
|
200
|
-
|
201
|
-
|
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
|
-
|
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
|
-
|
211
|
+
# Save another with a higher caller version.
|
208
212
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
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
|
-
|
220
|
+
expect( s2.save_to_store ).to eq( :ok )
|
217
221
|
|
218
|
-
|
222
|
+
# Should not be able to load the first one anymore.
|
219
223
|
|
220
|
-
|
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
|
-
|
228
|
+
it 'refuses to load session if the caller version is outdated' do
|
229
|
+
loader = described_class.new
|
223
230
|
|
224
|
-
|
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
|
-
|
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
|
-
|
240
|
+
expect( s1.save_to_store ).to eq( :ok )
|
234
241
|
|
235
|
-
|
242
|
+
# Should be able to load it back.
|
236
243
|
|
237
|
-
|
244
|
+
expect( loader.load_from_store!( '1234' ) ).to eq( :ok )
|
238
245
|
|
239
|
-
|
240
|
-
end
|
246
|
+
# Save another with a higher caller version.
|
241
247
|
|
242
|
-
|
243
|
-
|
244
|
-
|
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
|
-
|
255
|
+
expect( s2.save_to_store ).to eq( :ok )
|
247
256
|
|
248
|
-
|
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
|
-
|
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
|
-
|
262
|
-
|
263
|
-
|
261
|
+
# The newer one should load OK.
|
262
|
+
|
263
|
+
expect( loader.load_from_store!( '2345' ) ).to eq( :ok )
|
264
|
+
end
|
264
265
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
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
|
-
|
311
|
+
it 'refuses to load session if the session itself is expired' do
|
312
|
+
loader = described_class.new
|
274
313
|
|
275
|
-
|
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
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
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
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
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
|
-
|
290
|
-
|
291
|
-
|
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
|
-
|
297
|
-
loader = described_class.new
|
334
|
+
# ==========================================================================
|
298
335
|
|
299
|
-
|
300
|
-
|
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
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
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
|
-
|
311
|
-
|
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
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
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
|
-
|
320
|
-
|
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
|
-
|
323
|
-
|
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
|
-
|
327
|
-
|
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
|
-
|
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
|
-
|
337
|
-
s = described_class.new(
|
338
|
-
:caller_id => '0987',
|
339
|
-
:caller_version => 1
|
340
|
-
)
|
380
|
+
# ==========================================================================
|
341
381
|
|
342
|
-
|
343
|
-
|
344
|
-
|
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
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
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
|
-
|
355
|
-
|
395
|
+
it 'logs Memcached exceptions when loading' do
|
396
|
+
loader = described_class.new
|
356
397
|
|
357
|
-
|
358
|
-
|
359
|
-
|
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
|
-
|
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
|
-
|
368
|
-
|
409
|
+
expect( loader.load_from_store!( '1234' ) ).to eq( :fail )
|
410
|
+
end
|
369
411
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
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
|
-
|
379
|
-
|
418
|
+
# The first 'set' call is an attempt to update the caller version before
|
419
|
+
# the updated session is saved.
|
380
420
|
|
381
|
-
|
382
|
-
|
383
|
-
|
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
|
-
|
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
|
-
|
393
|
-
|
394
|
-
}
|
432
|
+
expect( s.save_to_store() ).to eq( :fail )
|
433
|
+
end
|
395
434
|
|
396
|
-
|
397
|
-
|
398
|
-
|
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
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
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
|
-
|
411
|
-
|
412
|
-
|
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
|
-
|
415
|
-
|
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
|
-
|
420
|
-
|
421
|
-
|
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 '
|
425
|
-
|
426
|
-
|
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 '
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
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
|
-
|
437
|
-
|
438
|
-
|
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
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
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
|
-
|
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
|
-
|
450
|
-
|
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
|
-
|
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
|
-
|
456
|
-
described_class.
|
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
|