hoodoo 1.13.0 → 1.14.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.rb +1 -0
- data/lib/hoodoo/services/services/session.rb +8 -104
- data/lib/hoodoo/transient_store.rb +19 -0
- data/lib/hoodoo/transient_store/mocks/dalli_client.rb +148 -0
- data/lib/hoodoo/transient_store/mocks/redis.rb +138 -0
- data/lib/hoodoo/transient_store/transient_store.rb +344 -0
- data/lib/hoodoo/transient_store/transient_store/base.rb +81 -0
- data/lib/hoodoo/transient_store/transient_store/memcached.rb +116 -0
- data/lib/hoodoo/transient_store/transient_store/memcached_redis_mirror.rb +181 -0
- data/lib/hoodoo/transient_store/transient_store/redis.rb +126 -0
- data/lib/hoodoo/version.rb +1 -1
- data/spec/active/active_record/support_spec.rb +3 -9
- data/spec/active/active_record/translated_spec.rb +2 -5
- data/spec/logger/writers/file_writer_spec.rb +1 -4
- data/spec/logger/writers/stream_writer_spec.rb +2 -9
- data/spec/services/middleware/middleware_logging_spec.rb +1 -4
- data/spec/services/middleware/middleware_permissions_spec.rb +2 -2
- data/spec/services/services/interface_spec.rb +2 -2
- data/spec/services/services/session_spec.rb +26 -19
- data/spec/transient_store/transient_store/base_spec.rb +52 -0
- data/spec/transient_store/transient_store/memcached_redis_mirror_spec.rb +380 -0
- data/spec/transient_store/transient_store/memcached_spec.rb +244 -0
- data/spec/transient_store/transient_store/mocks/dalli_client_spec.rb +44 -0
- data/spec/transient_store/transient_store/mocks/redis_spec.rb +28 -0
- data/spec/transient_store/transient_store/redis_spec.rb +242 -0
- data/spec/transient_store/transient_store_spec.rb +448 -0
- metadata +31 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f2eb0d49452cfe11be6f7953e2915139a799389
|
4
|
+
data.tar.gz: 2d9ca68a6fc2f064c7e8c1a3473ef3028369ff02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3091aedf879cae316a5bbf757bca8f6a01967bd41608359d7ab01f8b54330d2faf482ac0d5d80e222d88ffa9425d15fec98e02e6c976aa9223adbd1ff536816
|
7
|
+
data.tar.gz: 2194d4e534790c220d2bdfadc2b9efc42a8ba408741b1933a6f0c66edd47e2e40103aa04a6a7a22e66e78576395d035a70e111425aad4c0bf59030590ff50019
|
data/lib/hoodoo.rb
CHANGED
@@ -10,6 +10,7 @@
|
|
10
10
|
|
11
11
|
require 'ostruct'
|
12
12
|
require 'dalli'
|
13
|
+
require 'hoodoo/transient_store/mocks/dalli_client'
|
13
14
|
|
14
15
|
module Hoodoo
|
15
16
|
module Services
|
@@ -634,111 +635,14 @@ module Hoodoo
|
|
634
635
|
)
|
635
636
|
end
|
636
637
|
|
637
|
-
#
|
638
|
-
#
|
639
|
-
#
|
638
|
+
# Before Hoodoo::TransientStore was created, the Session system was
|
639
|
+
# directly tied into Memcached and had a mock backend used for tests
|
640
|
+
# without a Redis dependency. This now lives in
|
641
|
+
# Hoodoo::TransientStore::Mocks::DalliClient, but for any code out in
|
642
|
+
# the wild which might use the old Session namespace version, we add
|
643
|
+
# what amounts to a class alias here.
|
640
644
|
#
|
641
|
-
|
642
|
-
#
|
643
|
-
# ...whenever you need to stub out real Memcached. You will
|
644
|
-
# probably want to add:
|
645
|
-
#
|
646
|
-
# before :all do # (or ":each")
|
647
|
-
# Hoodoo::Services::Session::MockDalliClient.reset()
|
648
|
-
# end
|
649
|
-
#
|
650
|
-
# ...to "clean out Memcached" before or between tests. You can
|
651
|
-
# check the contents of mock Memcached by examining ::store's
|
652
|
-
# hash of data.
|
653
|
-
#
|
654
|
-
class MockDalliClient
|
655
|
-
@@store = {}
|
656
|
-
|
657
|
-
# For test analysis, return the hash of 'memcached' mock data.
|
658
|
-
#
|
659
|
-
# Entries are referenced by the key you used to originally
|
660
|
-
# store them; values are hashes with ":expires_at" giving an
|
661
|
-
# expiry time or "nil" and ":value" giving your stored value.
|
662
|
-
#
|
663
|
-
def self.store
|
664
|
-
@@store
|
665
|
-
end
|
666
|
-
|
667
|
-
# Wipe out all saved data.
|
668
|
-
#
|
669
|
-
def self.reset
|
670
|
-
@@store = {}
|
671
|
-
end
|
672
|
-
|
673
|
-
# Pass +true+ to bypass the mock client (subject to the caller
|
674
|
-
# reading ::bypass?) to e.g. get test code coverage on real
|
675
|
-
# Memcached. Pass +false+ otherwise.
|
676
|
-
#
|
677
|
-
def self.bypass( bypass_boolean )
|
678
|
-
@@bypass = bypass_boolean
|
679
|
-
end
|
680
|
-
|
681
|
-
@@bypass = false
|
682
|
-
|
683
|
-
# If +true+, bypass this class and use real Dalli::Client; else
|
684
|
-
# don't. Default return value is +false+.
|
685
|
-
#
|
686
|
-
def self.bypass?
|
687
|
-
@@bypass
|
688
|
-
end
|
689
|
-
|
690
|
-
# Get the data stored under the given key. Returns +nil+ if
|
691
|
-
# not found / expired.
|
692
|
-
#
|
693
|
-
# +key+:: Key to look up (see #set).
|
694
|
-
#
|
695
|
-
def get( key )
|
696
|
-
data = @@store[ key ]
|
697
|
-
return nil if data.nil?
|
698
|
-
|
699
|
-
expires_at = data[ :expires_at ]
|
700
|
-
return nil unless expires_at.nil? || Time.now < expires_at
|
701
|
-
|
702
|
-
return data[ :value ]
|
703
|
-
end
|
704
|
-
|
705
|
-
# Set data for a given key.
|
706
|
-
#
|
707
|
-
# +key+:: Key under which to store data.
|
708
|
-
#
|
709
|
-
# +value+:: Data to store.
|
710
|
-
#
|
711
|
-
# +ttl+:: (Optional) time-to-live ('live' as in living, not as in
|
712
|
-
# 'live TV') - a value in seconds, after which the data is
|
713
|
-
# considered expired. If omitted, the data does not expire.
|
714
|
-
#
|
715
|
-
def set( key, value, ttl = nil )
|
716
|
-
data = {
|
717
|
-
:expires_at => ttl.nil? ? nil : Time.now.utc + ttl,
|
718
|
-
:value => value
|
719
|
-
}
|
720
|
-
|
721
|
-
@@store[ key ] = data
|
722
|
-
true
|
723
|
-
end
|
724
|
-
|
725
|
-
# Remove data for the given key.
|
726
|
-
#
|
727
|
-
def delete( key )
|
728
|
-
if @@store.has_key?( key )
|
729
|
-
@@store.delete( key )
|
730
|
-
true
|
731
|
-
else
|
732
|
-
false
|
733
|
-
end
|
734
|
-
end
|
735
|
-
|
736
|
-
# Mock 'stats' health check.
|
737
|
-
#
|
738
|
-
def stats
|
739
|
-
true
|
740
|
-
end
|
741
|
-
end
|
645
|
+
MockDalliClient = Hoodoo::TransientStore::Mocks::DalliClient
|
742
646
|
end
|
743
647
|
end
|
744
648
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
########################################################################
|
2
|
+
# File:: transient_store.rb
|
3
|
+
# (C):: Loyalty New Zealand 2017
|
4
|
+
#
|
5
|
+
# Purpose:: Include temporary/transient storage abstraction layers.
|
6
|
+
# ----------------------------------------------------------------------
|
7
|
+
# 01-Feb-2017 (ADH): Created
|
8
|
+
########################################################################
|
9
|
+
|
10
|
+
# Core abstraction
|
11
|
+
|
12
|
+
require 'hoodoo/transient_store/transient_store'
|
13
|
+
require 'hoodoo/transient_store/transient_store/base'
|
14
|
+
|
15
|
+
# Storage engine plugins
|
16
|
+
|
17
|
+
require 'hoodoo/transient_store/transient_store/memcached'
|
18
|
+
require 'hoodoo/transient_store/transient_store/redis'
|
19
|
+
require 'hoodoo/transient_store/transient_store/memcached_redis_mirror'
|
@@ -0,0 +1,148 @@
|
|
1
|
+
########################################################################
|
2
|
+
# File:: dalli_client.rb
|
3
|
+
# (C):: Loyalty New Zealand 2017
|
4
|
+
#
|
5
|
+
# Purpose:: A mock/fake Dalli::Client minimal implementation as an
|
6
|
+
# alternative test back-end for Memcached-independent tests.
|
7
|
+
# ----------------------------------------------------------------------
|
8
|
+
# 02-Feb-2017 (ADH): Created.
|
9
|
+
########################################################################
|
10
|
+
|
11
|
+
module Hoodoo
|
12
|
+
class TransientStore
|
13
|
+
|
14
|
+
# Mock back-end code used by tests to allow them to run without a
|
15
|
+
# dependency on the real engine (though the real engine is always
|
16
|
+
# recommended and Hoodoo core tests always cover both).
|
17
|
+
#
|
18
|
+
class Mocks
|
19
|
+
|
20
|
+
# Mock known uses of Dalli::Client with test implementations.
|
21
|
+
# Use explicitly, or as an RSpec implicit mock via something like
|
22
|
+
# this:
|
23
|
+
#
|
24
|
+
# allow( Dalli::Client ).to(
|
25
|
+
# receive( :new ).
|
26
|
+
# and_return( Hoodoo::TransientStore::Mocks::DalliClient.new )
|
27
|
+
# )
|
28
|
+
#
|
29
|
+
# ...whenever you need to stub out real Memcached. You will
|
30
|
+
# probably want to add:
|
31
|
+
#
|
32
|
+
# before :all do # (or ":each")
|
33
|
+
# Hoodoo::TransientStore::Mocks::DalliClient.reset()
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# ...to "clean out Memcached" before or between tests. You can
|
37
|
+
# check the contents of mock Memcached by examining ::store's
|
38
|
+
# hash of data.
|
39
|
+
#
|
40
|
+
# The test coverage for Hoodoo::TransientStore selects this backend in
|
41
|
+
# passing. Generally speaking you should favour Hoodoo::TransientStore
|
42
|
+
# over hard-coding to a storage engine available by the Hoodoo
|
43
|
+
# abstraction and, as a result, may never need this mock class at all.
|
44
|
+
#
|
45
|
+
class DalliClient
|
46
|
+
@@store = {}
|
47
|
+
|
48
|
+
# For test analysis, return the hash of 'memcached' mock data.
|
49
|
+
#
|
50
|
+
# Entries are referenced by the key you used to originally
|
51
|
+
# store them; values are hashes with ":expires_at" giving an
|
52
|
+
# expiry time or "nil" and ":value" giving your stored value.
|
53
|
+
#
|
54
|
+
def self.store
|
55
|
+
@@store
|
56
|
+
end
|
57
|
+
|
58
|
+
# Wipe out all saved data.
|
59
|
+
#
|
60
|
+
def self.reset
|
61
|
+
@@store = {}
|
62
|
+
end
|
63
|
+
|
64
|
+
# Pass +true+ to bypass the mock client (subject to the caller
|
65
|
+
# reading ::bypass?) to e.g. get test code coverage on real
|
66
|
+
# Memcached. Pass +false+ otherwise.
|
67
|
+
#
|
68
|
+
# (Deprecated, but indefinitely maintained).
|
69
|
+
#
|
70
|
+
def self.bypass( bypass_boolean )
|
71
|
+
@@bypass = bypass_boolean
|
72
|
+
end
|
73
|
+
|
74
|
+
@@bypass = false
|
75
|
+
|
76
|
+
# If +true+, bypass this class and use real Dalli::Client; else
|
77
|
+
# don't. Default return value is +false+.
|
78
|
+
#
|
79
|
+
# (Deprecated, but indefinitely maintained).
|
80
|
+
#
|
81
|
+
def self.bypass?
|
82
|
+
@@bypass
|
83
|
+
end
|
84
|
+
|
85
|
+
# Get the data stored under the given key. Returns +nil+ if
|
86
|
+
# not found / expired.
|
87
|
+
#
|
88
|
+
# +key+:: Key to look up (see #set).
|
89
|
+
#
|
90
|
+
def get( key )
|
91
|
+
data = @@store[ key ]
|
92
|
+
return nil if data.nil?
|
93
|
+
|
94
|
+
expires_at = data[ :expires_at ]
|
95
|
+
return nil unless expires_at.nil? || Time.now < expires_at
|
96
|
+
|
97
|
+
return data[ :value ]
|
98
|
+
end
|
99
|
+
|
100
|
+
# Set data for a given key.
|
101
|
+
#
|
102
|
+
# +key+:: Key under which to store data.
|
103
|
+
#
|
104
|
+
# +value+:: Data to store.
|
105
|
+
#
|
106
|
+
# +ttl+:: (Optional) time-to-live ('live' as in living, not as in
|
107
|
+
# 'live TV') - a value in seconds, after which the data is
|
108
|
+
# considered expired. If omitted, the data does not expire.
|
109
|
+
#
|
110
|
+
def set( key, value, ttl = nil )
|
111
|
+
data = {
|
112
|
+
:expires_at => ttl.nil? ? nil : Time.now.utc + ttl,
|
113
|
+
:value => value
|
114
|
+
}
|
115
|
+
|
116
|
+
@@store[ key ] = data
|
117
|
+
true
|
118
|
+
end
|
119
|
+
|
120
|
+
# Remove data for the given key.
|
121
|
+
#
|
122
|
+
def delete( key )
|
123
|
+
if @@store.has_key?( key )
|
124
|
+
@@store.delete( key )
|
125
|
+
true
|
126
|
+
else
|
127
|
+
false
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Stub for 'closing' a connection.
|
132
|
+
#
|
133
|
+
def close; end
|
134
|
+
|
135
|
+
# Mock 'stats' health check.
|
136
|
+
#
|
137
|
+
def stats
|
138
|
+
|
139
|
+
# Should really be a Hash, but kept as 'true' in case any existing
|
140
|
+
# client depends on this; it isn't too important either way.
|
141
|
+
#
|
142
|
+
true
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
########################################################################
|
2
|
+
# File:: redis.rb
|
3
|
+
# (C):: Loyalty New Zealand 2017
|
4
|
+
#
|
5
|
+
# Purpose:: A mock/fake Redis client minimal implementation as an
|
6
|
+
# alternative test back-end for Redis-independent tests.
|
7
|
+
# ----------------------------------------------------------------------
|
8
|
+
# 02-Feb-2017 (ADH): Created.
|
9
|
+
########################################################################
|
10
|
+
|
11
|
+
module Hoodoo
|
12
|
+
class TransientStore
|
13
|
+
class Mocks
|
14
|
+
|
15
|
+
# Mock known uses of Redis with test implementations. Use explicitly,
|
16
|
+
# or as an RSpec implicit mock via something like this:
|
17
|
+
#
|
18
|
+
# allow( Redis ).to(
|
19
|
+
# receive( :new ).
|
20
|
+
# and_return( Hoodoo::TransientStore::Mocks::Redis.new )
|
21
|
+
# )
|
22
|
+
#
|
23
|
+
# ...whenever you need to stub out real Memcached. You will
|
24
|
+
# probably want to add:
|
25
|
+
#
|
26
|
+
# before :all do # (or ":each")
|
27
|
+
# Hoodoo::TransientStore::Mocks::Redis.reset()
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# ...to "clean out Memcached" before or between tests. You can
|
31
|
+
# check the contents of mock Memcached by examining ::store's
|
32
|
+
# hash of data.
|
33
|
+
#
|
34
|
+
# The test coverage for Hoodoo::TransientStore selects this backend in
|
35
|
+
# passing. Generally speaking you should favour Hoodoo::TransientStore
|
36
|
+
# over hard-coding to a storage engine available by the Hoodoo
|
37
|
+
# abstraction and, as a result, may never need this mock class at all.
|
38
|
+
#
|
39
|
+
class Redis
|
40
|
+
@@store = {}
|
41
|
+
|
42
|
+
# For test analysis, return the hash of 'memcached' mock data.
|
43
|
+
#
|
44
|
+
# Entries are referenced by the key you used to originally
|
45
|
+
# store them; values are hashes with ":expires_at" giving an
|
46
|
+
# expiry time or "nil" and ":value" giving your stored value.
|
47
|
+
#
|
48
|
+
def self.store
|
49
|
+
@@store
|
50
|
+
end
|
51
|
+
|
52
|
+
# Wipe out all saved data.
|
53
|
+
#
|
54
|
+
def self.reset
|
55
|
+
@@store = {}
|
56
|
+
end
|
57
|
+
|
58
|
+
# Get the data stored under the given key. Returns +nil+ if
|
59
|
+
# not found / expired.
|
60
|
+
#
|
61
|
+
# +key+:: Key to look up (see #set).
|
62
|
+
#
|
63
|
+
def get( key )
|
64
|
+
data = @@store[ key ]
|
65
|
+
return nil if data.nil?
|
66
|
+
|
67
|
+
expires_at = data[ :expires_at ]
|
68
|
+
return nil unless expires_at.nil? || Time.now < expires_at
|
69
|
+
|
70
|
+
return data[ :value ]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Alias for #get.
|
74
|
+
#
|
75
|
+
def []( key )
|
76
|
+
get( key )
|
77
|
+
end
|
78
|
+
|
79
|
+
# Set data for a given key.
|
80
|
+
#
|
81
|
+
# +key+:: Key under which to store data.
|
82
|
+
#
|
83
|
+
# +value+:: Data to store.
|
84
|
+
#
|
85
|
+
# +ttl+:: (Optional) time-to-live ('live' as in living, not as in
|
86
|
+
# 'live TV') - a value in seconds, after which the data is
|
87
|
+
# considered expired. If omitted, the data does not expire.
|
88
|
+
#
|
89
|
+
def set( key, value, ttl = nil )
|
90
|
+
@@store[ key ] = { :value => value }
|
91
|
+
'OK'
|
92
|
+
end
|
93
|
+
|
94
|
+
# Alias for #set.
|
95
|
+
#
|
96
|
+
def []=( key, value )
|
97
|
+
set( key, value )
|
98
|
+
end
|
99
|
+
|
100
|
+
# Set expiry time for a given key, which must exist.
|
101
|
+
#
|
102
|
+
# +ttl+:: time-to-live ('live' as in living, not as in 'live TV').
|
103
|
+
# A value in seconds, after which the data is considered
|
104
|
+
# expired.
|
105
|
+
#
|
106
|
+
def expire( key, ttl )
|
107
|
+
unless @@store.has_key?( key )
|
108
|
+
raise "Hoodoo::TransientStore::Mocks::Redis\#expire: Cannot find key '#{ key }'"
|
109
|
+
end
|
110
|
+
|
111
|
+
@@store[ key ][ :expires_at ] = Time.now.utc + ttl
|
112
|
+
true
|
113
|
+
end
|
114
|
+
|
115
|
+
# Remove data for the given key.
|
116
|
+
#
|
117
|
+
def del( key )
|
118
|
+
if @@store.has_key?( key )
|
119
|
+
@@store.delete( key )
|
120
|
+
1
|
121
|
+
else
|
122
|
+
0
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Stub for 'closing' a connection.
|
127
|
+
#
|
128
|
+
def quit; end
|
129
|
+
|
130
|
+
# Mock 'info' health check.
|
131
|
+
#
|
132
|
+
def info( command )
|
133
|
+
{ :alive => command }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|