stockpile 1.0 → 1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +2 -1
- data/History.rdoc +19 -0
- data/Manifest.txt +3 -0
- data/README.rdoc +16 -4
- data/Rakefile +2 -0
- data/lib/stockpile.rb +85 -24
- data/lib/stockpile/base.rb +186 -0
- data/lib/stockpile/memory.rb +170 -0
- data/test/minitest_config.rb +2 -128
- data/test/test_stockpile.rb +85 -9
- data/test/test_stockpile_base.rb +245 -0
- metadata +12 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9285056e00c41c3c09036585e9a8b2d5b517b27b
|
|
4
|
+
data.tar.gz: 84202f9f191b3ee26b30ed7deadef9203b6e5b8c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d0af27d554f66cd6e22006fdcfa75af45dd83305c5061a7fdf7b222e4836525124a9e6ec941dd9a8d95e743c576bb027f089d52be9b1532e78be2c1def10f47b
|
|
7
|
+
data.tar.gz: c60a70effa8e3e76b0b764807308db584543dfe61df6d519f4dd7344003db56298bd0c69b52c2ffbdb20aacedbe91ece8f5bf3d11a8980f2d26bc463d4bd01df
|
data/.travis.yml
CHANGED
data/History.rdoc
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
=== 1.1 / 2015-02-10
|
|
2
|
+
|
|
3
|
+
* 3 minor enhancements
|
|
4
|
+
|
|
5
|
+
* Created a base adapter, Stockpile::Base, that implements the core public
|
|
6
|
+
interface of a connection manager in a consistent way for argument parsing.
|
|
7
|
+
|
|
8
|
+
* Created a memory adapter as an example adapter. (This had previously been
|
|
9
|
+
a test adapter created in the test environment.)
|
|
10
|
+
|
|
11
|
+
* Documented changes to how clients can be specified for Stockpile.new,
|
|
12
|
+
Stockpile#connect, and Stockpile#connection_for.
|
|
13
|
+
|
|
14
|
+
* 1 bugfix
|
|
15
|
+
|
|
16
|
+
* Fix {issue #2}[https://github.com/halostatue/stockpile/issues/2], where
|
|
17
|
+
the use of the cache adapter causes the Stockpile cache manager to
|
|
18
|
+
initialize too early.
|
|
19
|
+
|
|
1
20
|
=== 1.0 / 2015-01-21
|
|
2
21
|
|
|
3
22
|
* 1 major enhancement
|
data/Manifest.txt
CHANGED
data/README.rdoc
CHANGED
|
@@ -14,6 +14,12 @@ implemented connection managers. So far, only Redis has been implemented
|
|
|
14
14
|
Stockpile also provides an adapter so that its functionality can be accessed
|
|
15
15
|
from within a module.
|
|
16
16
|
|
|
17
|
+
Release 1.1 fixes an issue with early initialization of an injected Stockpile
|
|
18
|
+
instance during adaptation
|
|
19
|
+
({stockpile#2}[https://githbub.com/halostatue/stockpile/issues/2]). Several
|
|
20
|
+
small improvements to Stockpile.new, Stockpile#connect, and
|
|
21
|
+
Stockpile#connection_for have been documented.
|
|
22
|
+
|
|
17
23
|
== Features
|
|
18
24
|
|
|
19
25
|
* Stockpile manages key-value store connections. There are two variants:
|
|
@@ -35,7 +41,7 @@ your Gemfile.
|
|
|
35
41
|
|
|
36
42
|
== Synopsis
|
|
37
43
|
|
|
38
|
-
wide = Stockpile.new # A Stockpile
|
|
44
|
+
wide = Stockpile.new # A Stockpile instance.
|
|
39
45
|
wide.connection.set('hello', 'world') # => 'OK'
|
|
40
46
|
wide.connection.get('hello') # => 'world'
|
|
41
47
|
|
|
@@ -51,6 +57,12 @@ your Gemfile.
|
|
|
51
57
|
narrow.connection_for(:resque) != narrow.connection # => true
|
|
52
58
|
narrow.connection_for(:resque).redis == narrow.connection # => true
|
|
53
59
|
|
|
60
|
+
# Standard namespace handling.
|
|
61
|
+
narrow.connection_for(:other, namespace: 'other') !=
|
|
62
|
+
narrow.connection # => true
|
|
63
|
+
narrow.connection_for(:other, namespace: 'other').redis !=
|
|
64
|
+
narrow.connection # => true
|
|
65
|
+
|
|
54
66
|
# Show a Stockpile with no adapter capabilities, but name the method
|
|
55
67
|
# stockpile, not cache. This will still usefully manage connections.
|
|
56
68
|
module Cacher
|
|
@@ -132,10 +144,10 @@ be used in Rails. A link to it will be provided here when it is complete.
|
|
|
132
144
|
== Install
|
|
133
145
|
|
|
134
146
|
Stockpile is not intended to be installed by itself, as it does not implement a
|
|
135
|
-
key-value store specific connection manager. Instead, install
|
|
136
|
-
|
|
147
|
+
key-value store specific connection manager. Instead, install a store-specific
|
|
148
|
+
gem which depends on Stockpile.
|
|
137
149
|
|
|
138
|
-
gem 'stockpile-redis', '~> 1.
|
|
150
|
+
gem 'stockpile-redis', '~> 1.1'
|
|
139
151
|
|
|
140
152
|
Or manually install:
|
|
141
153
|
|
data/Rakefile
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'rubygems'
|
|
4
4
|
require 'hoe'
|
|
5
|
+
require 'rake/clean'
|
|
5
6
|
|
|
6
7
|
Hoe.plugin :doofus
|
|
7
8
|
Hoe.plugin :gemspec2
|
|
@@ -46,6 +47,7 @@ namespace :test do
|
|
|
46
47
|
].join('; ')
|
|
47
48
|
Rake::Task['test'].execute
|
|
48
49
|
end
|
|
50
|
+
CLOBBER << 'coverage'
|
|
49
51
|
end
|
|
50
52
|
|
|
51
53
|
# vim: syntax=ruby
|
data/lib/stockpile.rb
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require 'forwardable'
|
|
4
4
|
|
|
5
|
-
# Stockpile is a thin wrapper around connections to a fast key-value store
|
|
6
|
-
# for caching (currently only supporting Redis).
|
|
5
|
+
# Stockpile is a thin wrapper around connections to a fast key-value store
|
|
6
|
+
# used for caching (currently only supporting Redis).
|
|
7
7
|
#
|
|
8
8
|
# This provides a couple of layers of functionality:
|
|
9
9
|
#
|
|
@@ -14,7 +14,7 @@ require 'forwardable'
|
|
|
14
14
|
class Stockpile
|
|
15
15
|
extend Forwardable
|
|
16
16
|
|
|
17
|
-
VERSION = "1.
|
|
17
|
+
VERSION = "1.1" # :nodoc:
|
|
18
18
|
|
|
19
19
|
@default_manager = nil
|
|
20
20
|
|
|
@@ -79,20 +79,34 @@ class Stockpile
|
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
name = options.fetch(:method, :cache).to_sym
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
mklass = mod.singleton_class
|
|
84
83
|
default = options.fetch(:default_manager, nil)
|
|
85
84
|
|
|
86
|
-
|
|
85
|
+
mklass.send(:define_method, name) do |init_options = {}|
|
|
87
86
|
init_options = init_options.merge(default_manager: default)
|
|
88
87
|
@__stockpile__ ||= ::Stockpile.new(init_options)
|
|
88
|
+
@__stockpile_triggers__ ||= []
|
|
89
|
+
|
|
90
|
+
triggers, @__stockpile_triggers__ = @__stockpile_triggers__, []
|
|
91
|
+
triggers.each(&:call)
|
|
92
|
+
|
|
93
|
+
@__stockpile__
|
|
89
94
|
end
|
|
90
95
|
|
|
91
96
|
if options.fetch(:adaptable, true)
|
|
92
97
|
adapter = :"#{name}_adapter"
|
|
93
|
-
|
|
98
|
+
mklass.send(:define_method, adapter) do |m, k = nil|
|
|
94
99
|
o = self
|
|
95
|
-
|
|
100
|
+
|
|
101
|
+
@__stockpile_triggers__ ||= []
|
|
102
|
+
|
|
103
|
+
trigger = -> { send(name).singleton_class.send(:include, m) }
|
|
104
|
+
|
|
105
|
+
if defined?(@__stockpile__) && @__stockpile__
|
|
106
|
+
trigger.call
|
|
107
|
+
else
|
|
108
|
+
@__stockpile_triggers__ << trigger
|
|
109
|
+
end
|
|
96
110
|
|
|
97
111
|
if k
|
|
98
112
|
mk = k.singleton_class
|
|
@@ -104,7 +118,7 @@ class Stockpile
|
|
|
104
118
|
end
|
|
105
119
|
end
|
|
106
120
|
|
|
107
|
-
|
|
121
|
+
mklass.send(:define_method, :"#{adapter}!") do |m|
|
|
108
122
|
send(adapter, m, m)
|
|
109
123
|
end
|
|
110
124
|
end
|
|
@@ -131,37 +145,46 @@ class Stockpile
|
|
|
131
145
|
# through any means.
|
|
132
146
|
# +clients+:: Connections will be created for the provided list of clients.
|
|
133
147
|
# These connections must be assigned to their appropriate clients
|
|
134
|
-
# after initialization. This may also be called +client+.
|
|
148
|
+
# after initialization. This may also be called +client+. These
|
|
149
|
+
# values may be provided as names (e.g., +:cache+), or as hashes
|
|
150
|
+
# of client name to client options (e.g., <tt>{ cache: {
|
|
151
|
+
# namespace: 'x' } }</tt>). See Stockpile#connect for more
|
|
152
|
+
# details on this latter format.
|
|
135
153
|
#
|
|
136
154
|
# All other options will be passed to the connection provider.
|
|
137
155
|
#
|
|
138
156
|
# === Synopsis
|
|
139
157
|
#
|
|
140
|
-
#
|
|
141
|
-
#
|
|
142
|
-
#
|
|
143
|
-
#
|
|
158
|
+
# # Create and assign a connection to Redis.current, Resque, and Rollout.
|
|
159
|
+
# # Under a narrow connection management width, all three will be the
|
|
160
|
+
# # same client connection.
|
|
161
|
+
# options = {
|
|
162
|
+
# manager: Stockpile::Redis,
|
|
163
|
+
# clients: [ :redis, :resque ]
|
|
164
|
+
# }
|
|
165
|
+
# Stockpile.new(options) do |stockpile|
|
|
144
166
|
# Redis.current = stockpile.connection_for(:redis)
|
|
145
167
|
# Resque.redis = stockpile.connection_for(:resque)
|
|
146
168
|
# # Clients will be created by name if necessary.
|
|
147
169
|
# $rollout = Rollout.new(stockpile.connection_for(:rollout))
|
|
148
170
|
# end
|
|
149
171
|
def initialize(options = {})
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
172
|
+
options = options.dup
|
|
173
|
+
manager = options.delete(:manager)
|
|
174
|
+
default = options.delete(:default_manager) || self.class.default_manager
|
|
153
175
|
|
|
154
|
-
unless manager
|
|
176
|
+
unless manager || default
|
|
155
177
|
raise ArgumentError, "No connection manager provided or set as default."
|
|
156
178
|
end
|
|
157
179
|
|
|
158
|
-
|
|
180
|
+
manager ||= default
|
|
181
|
+
|
|
182
|
+
clients = [
|
|
183
|
+
Array(options.delete(:clients)), Array(options.delete(:client))
|
|
184
|
+
].flatten.uniq
|
|
159
185
|
|
|
160
|
-
|
|
161
|
-
k == :manager || k == :clients || k == :client
|
|
162
|
-
})
|
|
186
|
+
@manager = manager.new({ narrow: Stockpile.narrow? }.merge(options))
|
|
163
187
|
|
|
164
|
-
@manager = manager.new(options)
|
|
165
188
|
connect(*clients)
|
|
166
189
|
yield self if block_given?
|
|
167
190
|
end
|
|
@@ -183,19 +206,57 @@ class Stockpile
|
|
|
183
206
|
#
|
|
184
207
|
# If the connection is using a narrow connection width, the same connection
|
|
185
208
|
# will be shared.
|
|
209
|
+
#
|
|
210
|
+
# === Clients
|
|
211
|
+
#
|
|
212
|
+
# +clients+ may be provided in one of several ways:
|
|
213
|
+
#
|
|
214
|
+
# * A Hash object, mapping client names to client options.
|
|
215
|
+
#
|
|
216
|
+
# connect(redis: nil, rollout: { namespace: 'rollout' })
|
|
217
|
+
# # Transforms into:
|
|
218
|
+
# # connect(redis: {}, rollout: { namespace: 'rollout' })
|
|
219
|
+
#
|
|
220
|
+
# * An (implicit) array of client names, for connections with no options
|
|
221
|
+
# provided.
|
|
222
|
+
#
|
|
223
|
+
# connect(:redis, :resque, :rollout)
|
|
224
|
+
# # Transforms into:
|
|
225
|
+
# # connect(redis: {}, resque: {}, rollout: {})
|
|
226
|
+
#
|
|
227
|
+
# * An array of Hash objects, mapping client names to client options.
|
|
228
|
+
#
|
|
229
|
+
# connect({ redis: nil },
|
|
230
|
+
# { rollout: { namespace: 'rollout' } })
|
|
231
|
+
# # Transforms into:
|
|
232
|
+
# # connect(redis: {}, rollout: { namespace: 'rollout' })
|
|
233
|
+
#
|
|
234
|
+
# * A mix of client names and Hash objects:
|
|
235
|
+
#
|
|
236
|
+
# connect(:redis, { rollout: { namespace: 'rollout' } })
|
|
237
|
+
# # Transforms into:
|
|
238
|
+
# # connect(redis: {}, rollout: { namespace: 'rollout' })
|
|
239
|
+
#
|
|
240
|
+
# ==== Client Options
|
|
241
|
+
#
|
|
242
|
+
# Stockpile cache providers will handle the parsing of options to ensure that
|
|
243
|
+
# only suitable options are passed along (most providers will ignore any
|
|
244
|
+
# options that change the target system).
|
|
186
245
|
def_delegator :@manager, :connect
|
|
187
246
|
|
|
188
247
|
##
|
|
189
248
|
# :method: connection_for
|
|
190
249
|
# :call-seq:
|
|
191
250
|
# connection_for(client_name)
|
|
251
|
+
# connection_for(client_name, options)
|
|
192
252
|
#
|
|
193
253
|
# Returns a connection for a particular client. If the connection manager is
|
|
194
254
|
# using a narrow connection width, this returns the same as #connection.
|
|
195
255
|
#
|
|
196
256
|
# The +client_name+ of +:all+ will always return +nil+.
|
|
197
257
|
#
|
|
198
|
-
# If the requested client does not yet exist, the connection will be created
|
|
258
|
+
# If the requested client does not yet exist, the connection will be created
|
|
259
|
+
# with the provided options.
|
|
199
260
|
def_delegator :@manager, :connection_for
|
|
200
261
|
|
|
201
262
|
##
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'stockpile'
|
|
4
|
+
|
|
5
|
+
class Stockpile
|
|
6
|
+
# The base connection manager, providing some common functionality for
|
|
7
|
+
# connection managers.
|
|
8
|
+
#
|
|
9
|
+
# It is not necessary to implement a connection manager from Stockpile::Base,
|
|
10
|
+
# but it is recommended because it provides all of the core functionality
|
|
11
|
+
# required of all connection managers, and requires only four integration
|
|
12
|
+
# points:
|
|
13
|
+
#
|
|
14
|
+
# * +initialize+: The constructor for the client connection manager. This
|
|
15
|
+
# should call +super+ at the beginning of its own implementation, and use
|
|
16
|
+
# <tt>@options</tt> if further parsing or manipulation of provided options
|
|
17
|
+
# is required.
|
|
18
|
+
# * +client_connect+: The actions necessary to connect clients.
|
|
19
|
+
# * +client_reconnect+: The actions necessary to reconnect clients.
|
|
20
|
+
# * +client_disconnect+: The actions necessary to disconnect clients.
|
|
21
|
+
class Base
|
|
22
|
+
# Create a new connection manager with the provided options.
|
|
23
|
+
#
|
|
24
|
+
# == Options
|
|
25
|
+
#
|
|
26
|
+
# +narrow+:: Use a narrow connection width if true; if not provided,
|
|
27
|
+
# uses the value of ::Stockpile.narrow? in this connection
|
|
28
|
+
# manager.
|
|
29
|
+
def initialize(options = {})
|
|
30
|
+
@options = options.dup
|
|
31
|
+
@narrow = !!@options.fetch(:narrow, ::Stockpile.narrow?)
|
|
32
|
+
@connection = nil
|
|
33
|
+
@clients = {}
|
|
34
|
+
|
|
35
|
+
@options.delete(:narrow)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# The primary connection.
|
|
39
|
+
attr_reader :connection
|
|
40
|
+
|
|
41
|
+
# Indicates if this connection manager is using a narrow connection width.
|
|
42
|
+
def narrow?
|
|
43
|
+
@narrow
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Connect unless already connected. Additional client connections can be
|
|
47
|
+
# specified in the parameters as a shorthand for calls to #connection_for.
|
|
48
|
+
#
|
|
49
|
+
# If #narrow? is true, the same connection will be used for all clients
|
|
50
|
+
# managed by this connection manager.
|
|
51
|
+
#
|
|
52
|
+
# manager.connect
|
|
53
|
+
# manager.connection_for(:bar)
|
|
54
|
+
#
|
|
55
|
+
# # This means the same as above.
|
|
56
|
+
# manager.connect(:bar)
|
|
57
|
+
def connect(*client_names)
|
|
58
|
+
@connection ||= client_connect
|
|
59
|
+
|
|
60
|
+
clients_from(*client_names).each { |client_name, options|
|
|
61
|
+
connection_for(client_name, options || {})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
connection
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Perform a client connection for a specific +client_name+. A +client_name+
|
|
68
|
+
# of +:all+ will always return +nil+. If the requested client does not yet
|
|
69
|
+
# exist, the connection will be created.
|
|
70
|
+
def connection_for(client_name, options = {})
|
|
71
|
+
connect unless connection
|
|
72
|
+
return nil if client_name == :all
|
|
73
|
+
|
|
74
|
+
@clients[client_name] ||= client_connect(client_name, options)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Reconnect some or all clients. The primary connection will always be
|
|
78
|
+
# reconnected; other clients will be reconnected based on the +clients+
|
|
79
|
+
# provided. Only clients actively managed by previous calls to #connect
|
|
80
|
+
# or #connection_for will be reconnected.
|
|
81
|
+
#
|
|
82
|
+
# If #reconnect is called with the value +:all+, all currently managed
|
|
83
|
+
# clients will be reconnected.
|
|
84
|
+
#
|
|
85
|
+
# If #narrow? is true, the primary connection will be reconnected, which
|
|
86
|
+
# reconnects all connections implicitly.
|
|
87
|
+
def reconnect(*client_names)
|
|
88
|
+
return unless connection
|
|
89
|
+
|
|
90
|
+
client_reconnect
|
|
91
|
+
|
|
92
|
+
unless narrow?
|
|
93
|
+
clients_from(*client_names).each { |client_name, _|
|
|
94
|
+
client_reconnect(@clients[client_name])
|
|
95
|
+
}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
connection
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Disconnect for some or all clients. The primary connection will always
|
|
102
|
+
# be disconnected; other clients will be disconnected based on the
|
|
103
|
+
# +clients+ provided. Only clients actively managed by previous calls to
|
|
104
|
+
# #connect or #connection_for will be disconnected.
|
|
105
|
+
#
|
|
106
|
+
# If #disconnect is called with the value +:all+, all currently managed
|
|
107
|
+
# clients will be disconnected.
|
|
108
|
+
#
|
|
109
|
+
# If #narrow? is true, the primary connection will be disconnected,
|
|
110
|
+
# which disconnects all connections implicitly.
|
|
111
|
+
def disconnect(*client_names)
|
|
112
|
+
return unless connection
|
|
113
|
+
|
|
114
|
+
unless narrow?
|
|
115
|
+
clients_from(*client_names).each { |client_name, _|
|
|
116
|
+
client_disconnect(@clients[client_name])
|
|
117
|
+
}
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
client_disconnect
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
private
|
|
124
|
+
# Converts +client_names+ into a hash of client names to options.
|
|
125
|
+
#
|
|
126
|
+
# * A Hash object, mapping client names to client options.
|
|
127
|
+
#
|
|
128
|
+
# connect(redis: nil, rollout: { namespace: 'rollout' })
|
|
129
|
+
# # Transforms into:
|
|
130
|
+
# # connect(redis: {}, rollout: { namespace: 'rollout' })
|
|
131
|
+
#
|
|
132
|
+
# * An (implicit) array of client names, for connections with no options
|
|
133
|
+
# provided.
|
|
134
|
+
#
|
|
135
|
+
# connect(:redis, :resque, :rollout)
|
|
136
|
+
# # Transforms into:
|
|
137
|
+
# # connect(redis: {}, resque: {}, rollout: {})
|
|
138
|
+
#
|
|
139
|
+
# * An array of Hash objects, mapping client names to client options.
|
|
140
|
+
#
|
|
141
|
+
# connect({ redis: nil },
|
|
142
|
+
# { rollout: { namespace: 'rollout' } })
|
|
143
|
+
# # Transforms into:
|
|
144
|
+
# # connect(redis: {}, rollout: { namespace: 'rollout' })
|
|
145
|
+
#
|
|
146
|
+
# * A mix of client names and Hash objects:
|
|
147
|
+
#
|
|
148
|
+
# connect(:redis, { rollout: { namespace: 'rollout' } })
|
|
149
|
+
# # Transforms into:
|
|
150
|
+
# # connect(redis: {}, rollout: { namespace: 'rollout' })
|
|
151
|
+
def clients_from(*client_names)
|
|
152
|
+
clients = if client_names.size == 1
|
|
153
|
+
if client_names.first == :all
|
|
154
|
+
@clients.keys
|
|
155
|
+
else
|
|
156
|
+
client_names
|
|
157
|
+
end
|
|
158
|
+
else
|
|
159
|
+
client_names
|
|
160
|
+
end
|
|
161
|
+
clients.map { |v|
|
|
162
|
+
case v
|
|
163
|
+
when Hash
|
|
164
|
+
v
|
|
165
|
+
else
|
|
166
|
+
{ v => {} }
|
|
167
|
+
end
|
|
168
|
+
}.inject({}, :merge)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Performs a client connect action. Must be implemented by a client.
|
|
172
|
+
def client_connect(name = nil, options = {})
|
|
173
|
+
raise NotImplementedError
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Performs a client reconnect action. Must be implemented by a client.
|
|
177
|
+
def client_reconnect(client = connect())
|
|
178
|
+
raise NotImplementedError
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Performs a client disconnect action. Must be implemented by a client.
|
|
182
|
+
def client_disconnect(client = connect())
|
|
183
|
+
raise NotImplementedError
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# -*- ruby encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'stockpile/base'
|
|
4
|
+
|
|
5
|
+
class Stockpile
|
|
6
|
+
# An in-memory connection manager, providing a complete example of how a
|
|
7
|
+
# Stockpile connection manager could be made.
|
|
8
|
+
class Memory < Stockpile::Base
|
|
9
|
+
class Data # :nodoc:
|
|
10
|
+
class << self
|
|
11
|
+
attr_reader :data
|
|
12
|
+
|
|
13
|
+
def reset
|
|
14
|
+
@data = {}
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
reset
|
|
19
|
+
|
|
20
|
+
attr_reader :options
|
|
21
|
+
|
|
22
|
+
def initialize(options = {})
|
|
23
|
+
@connected = false
|
|
24
|
+
@options = options
|
|
25
|
+
connect
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def connect
|
|
29
|
+
@connected = true
|
|
30
|
+
end
|
|
31
|
+
alias_method :reconnect, :connect
|
|
32
|
+
|
|
33
|
+
def disconnect
|
|
34
|
+
@connected = false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def connected?
|
|
38
|
+
!!@connected
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def get(key)
|
|
42
|
+
check_valid!
|
|
43
|
+
self.class.data[key]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def set(key, value)
|
|
47
|
+
check_valid!
|
|
48
|
+
self.class.data[key] = value
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def hget(key, field)
|
|
52
|
+
raise unless connected?
|
|
53
|
+
valid_hkey!(key)[field]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def hset(key, field, value)
|
|
57
|
+
raise unless connected?
|
|
58
|
+
valid_hkey!(key)[field] = value
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
def check_valid!
|
|
63
|
+
raise unless connected?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def valid_hkey!(key)
|
|
67
|
+
check_valid!
|
|
68
|
+
case h = self.class.data[key]
|
|
69
|
+
when nil
|
|
70
|
+
h = (self.class.data[key] = {})
|
|
71
|
+
when Hash
|
|
72
|
+
nil
|
|
73
|
+
else
|
|
74
|
+
raise
|
|
75
|
+
end
|
|
76
|
+
h
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
##
|
|
81
|
+
# :singleton-method: new
|
|
82
|
+
# :call-seq:
|
|
83
|
+
# new(options = {})
|
|
84
|
+
#
|
|
85
|
+
# Create a new Memory connection manager.
|
|
86
|
+
|
|
87
|
+
##
|
|
88
|
+
# :attr_reader: connection
|
|
89
|
+
#
|
|
90
|
+
# The primary connection.
|
|
91
|
+
|
|
92
|
+
##
|
|
93
|
+
# :method: narrow?
|
|
94
|
+
#
|
|
95
|
+
# Indicates if this connection manager is using a narrow connection width.
|
|
96
|
+
|
|
97
|
+
##
|
|
98
|
+
# :method: connect
|
|
99
|
+
# :call-seq:
|
|
100
|
+
# connect(*client_names)
|
|
101
|
+
#
|
|
102
|
+
# Connect unless already connected. Additional client connections can be
|
|
103
|
+
# specified in the parameters as a shorthand for calls to #connection_for.
|
|
104
|
+
#
|
|
105
|
+
# If #narrow? is true, the same connection will be used for all clients
|
|
106
|
+
# managed by this connection manager.
|
|
107
|
+
#
|
|
108
|
+
# manager.connect
|
|
109
|
+
# manager.connection_for(:bar)
|
|
110
|
+
#
|
|
111
|
+
# # This means the same as above.
|
|
112
|
+
# manager.connect(:bar)
|
|
113
|
+
|
|
114
|
+
##
|
|
115
|
+
# :method: connection_for
|
|
116
|
+
# :call-seq:
|
|
117
|
+
# connection_for(client_name, options = {})
|
|
118
|
+
#
|
|
119
|
+
# Perform a client connection for a specific +client_name+. A +client_name+
|
|
120
|
+
# of +:all+ will always return +nil+. If the requested client does not yet
|
|
121
|
+
# exist, the connection will be created.
|
|
122
|
+
|
|
123
|
+
##
|
|
124
|
+
# :method: reconnect
|
|
125
|
+
# :call-seq:
|
|
126
|
+
# reconnect(*client_names)
|
|
127
|
+
#
|
|
128
|
+
# Reconnect some or all clients. The primary connection will always be
|
|
129
|
+
# reconnected; other clients will be reconnected based on the +clients+
|
|
130
|
+
# provided. Only clients actively managed by previous calls to #connect or
|
|
131
|
+
# #connection_for will be reconnected.
|
|
132
|
+
#
|
|
133
|
+
# If #reconnect is called with the value +:all+, all currently managed
|
|
134
|
+
# clients will be reconnected.
|
|
135
|
+
#
|
|
136
|
+
# If #narrow? is true, the primary connection will be reconnected, which
|
|
137
|
+
# reconnects all connections implicitly.
|
|
138
|
+
|
|
139
|
+
##
|
|
140
|
+
# :method: disconnect
|
|
141
|
+
# :call-seq:
|
|
142
|
+
# disconnect(*client_names)
|
|
143
|
+
#
|
|
144
|
+
# Disconnect for some or all clients. The primary connection will always
|
|
145
|
+
# be disconnected; other clients will be disconnected based on the
|
|
146
|
+
# +clients+ provided. Only clients actively managed by previous calls to
|
|
147
|
+
# #connect or #connection_for will be disconnected.
|
|
148
|
+
#
|
|
149
|
+
# If #disconnect is called with the value +:all+, all currently managed
|
|
150
|
+
# clients will be disconnected.
|
|
151
|
+
#
|
|
152
|
+
# If #narrow? is true, the primary connection will be disconnected,
|
|
153
|
+
# which disconnects all connections implicitly.
|
|
154
|
+
|
|
155
|
+
##
|
|
156
|
+
private
|
|
157
|
+
def client_connect(name = nil, options = {})
|
|
158
|
+
return connection if connection && narrow?
|
|
159
|
+
Data.new(@options.merge(options))
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def client_reconnect(client = connection())
|
|
163
|
+
client.reconnect if client
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def client_disconnect(client = connection())
|
|
167
|
+
client.disconnect if client
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
data/test/minitest_config.rb
CHANGED
|
@@ -7,138 +7,12 @@ require 'minitest/focus'
|
|
|
7
7
|
require 'minitest/moar'
|
|
8
8
|
require 'minitest/bisect'
|
|
9
9
|
|
|
10
|
-
require 'stockpile'
|
|
11
|
-
|
|
12
|
-
class StockpileTestManager
|
|
13
|
-
class Connection
|
|
14
|
-
class << self
|
|
15
|
-
attr_reader :data
|
|
16
|
-
|
|
17
|
-
def reset_data
|
|
18
|
-
@data = Hash.new { |h, k| h[k] = {} }
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
reset_data
|
|
23
|
-
|
|
24
|
-
def initialize
|
|
25
|
-
@connected = false
|
|
26
|
-
connect
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def connect
|
|
30
|
-
@connected = true
|
|
31
|
-
end
|
|
32
|
-
alias_method :reconnect, :connect
|
|
33
|
-
|
|
34
|
-
def disconnect
|
|
35
|
-
@connected = false
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def connected?
|
|
39
|
-
!!@connected
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def get(key)
|
|
43
|
-
raise unless connected?
|
|
44
|
-
self.class.data[key]
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def set(key, value)
|
|
48
|
-
raise unless connected?
|
|
49
|
-
self.class.data[key] = value
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def hget(key, field)
|
|
53
|
-
raise unless connected?
|
|
54
|
-
self.class.data[key][field]
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def hset(key, field, value)
|
|
58
|
-
raise unless connected?
|
|
59
|
-
self.class.data[key][field] = value
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def initialize(options = {})
|
|
64
|
-
@narrow = !!options.fetch(:narrow, ::Stockpile.narrow?)
|
|
65
|
-
@connection = nil
|
|
66
|
-
@clients = {}
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
attr_reader :connection
|
|
70
|
-
|
|
71
|
-
def narrow?
|
|
72
|
-
@narrow
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def connect(*client_names)
|
|
76
|
-
@connection ||= connect_for_any
|
|
77
|
-
|
|
78
|
-
clients_from(*client_names).each { |client_name|
|
|
79
|
-
connection_for(client_name)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
connection
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def connection_for(client_name)
|
|
86
|
-
connect unless connection
|
|
87
|
-
return nil if client_name == :all
|
|
88
|
-
@clients[client_name] ||= connect_for_any
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def reconnect(*client_names)
|
|
92
|
-
return unless connection
|
|
93
|
-
|
|
94
|
-
connection.reconnect
|
|
95
|
-
|
|
96
|
-
unless narrow?
|
|
97
|
-
clients_from(*client_names).each { |client_name|
|
|
98
|
-
client = @clients[client_name]
|
|
99
|
-
client.reconnect if client
|
|
100
|
-
}
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
connection
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def disconnect(*client_names)
|
|
107
|
-
return unless connection
|
|
108
|
-
|
|
109
|
-
unless narrow?
|
|
110
|
-
clients_from(*client_names).each { |client_name|
|
|
111
|
-
client = @clients[client_name]
|
|
112
|
-
client.disconnect if client
|
|
113
|
-
}
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
connection.disconnect
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
private
|
|
120
|
-
def clients_from(*client_names)
|
|
121
|
-
if client_names.size == 1
|
|
122
|
-
if client_names.first == :all
|
|
123
|
-
@clients.keys
|
|
124
|
-
else
|
|
125
|
-
client_names
|
|
126
|
-
end
|
|
127
|
-
else
|
|
128
|
-
client_names
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def connect_for_any
|
|
133
|
-
return connection if connection && narrow?
|
|
134
|
-
Connection.new
|
|
135
|
-
end
|
|
136
|
-
end
|
|
10
|
+
require 'stockpile/memory'
|
|
137
11
|
|
|
138
12
|
module Minitest::ENVStub
|
|
139
13
|
def setup
|
|
140
14
|
super
|
|
141
|
-
|
|
15
|
+
Stockpile::Memory::Data.reset
|
|
142
16
|
end
|
|
143
17
|
|
|
144
18
|
def stub_env env, options = {}, *block_args, &block
|
data/test/test_stockpile.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
require 'minitest_config'
|
|
2
|
-
require 'stockpile'
|
|
3
2
|
require 'time'
|
|
4
3
|
|
|
5
4
|
describe Stockpile do
|
|
@@ -18,6 +17,7 @@ describe Stockpile do
|
|
|
18
17
|
end
|
|
19
18
|
|
|
20
19
|
describe ".inject!" do
|
|
20
|
+
let(:cls) { Class.new }
|
|
21
21
|
let(:mod) { Module.new }
|
|
22
22
|
let(:lrt) {
|
|
23
23
|
Module.new do
|
|
@@ -29,10 +29,24 @@ describe Stockpile do
|
|
|
29
29
|
Time.parse(value) if value
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
|
+
|
|
33
|
+
def job_ran(job, value = nil)
|
|
34
|
+
if value
|
|
35
|
+
connection.set(job, !!value)
|
|
36
|
+
else
|
|
37
|
+
!!connection.get(job)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
32
40
|
end
|
|
33
41
|
}
|
|
34
42
|
|
|
35
|
-
|
|
43
|
+
it "throws an ArgumentError unless it's a class or module" do
|
|
44
|
+
assert_raises ArgumentError do
|
|
45
|
+
::Stockpile.inject!(Object.new)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe "Stockpile.inject!(Module):" do
|
|
36
50
|
before { ::Stockpile.inject!(mod) }
|
|
37
51
|
|
|
38
52
|
it "defines Mod.cache" do
|
|
@@ -84,7 +98,9 @@ describe Stockpile do
|
|
|
84
98
|
end
|
|
85
99
|
|
|
86
100
|
describe "Stockpile.inject!(Mod, method: :stockpile, adaptable: false)" do
|
|
87
|
-
before
|
|
101
|
+
before do
|
|
102
|
+
::Stockpile.inject!(mod, method: :stockpile, adaptable: false)
|
|
103
|
+
end
|
|
88
104
|
|
|
89
105
|
it "defines Mod.stockpile" do
|
|
90
106
|
assert_respond_to mod, :stockpile
|
|
@@ -100,8 +116,29 @@ describe Stockpile do
|
|
|
100
116
|
let(:now) { Time.now }
|
|
101
117
|
let(:iso) { now.utc.iso8601 }
|
|
102
118
|
before do
|
|
103
|
-
::Stockpile.inject!(mod,
|
|
104
|
-
|
|
119
|
+
::Stockpile.inject!(mod, default_manager: Stockpile::Memory)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "queues adaptation until Stockpile has been initialized" do
|
|
123
|
+
stub Stockpile, :new do
|
|
124
|
+
mod.cache_adapter(lrt)
|
|
125
|
+
refute_called Stockpile, :new
|
|
126
|
+
refute_nil mod.instance_variable_get(:@__stockpile_triggers__)
|
|
127
|
+
refute_empty mod.instance_variable_get(:@__stockpile_triggers__)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
assert_equal({ namespace: 'n' },
|
|
131
|
+
mod.cache(namespace: 'n').connection.options)
|
|
132
|
+
assert_respond_to mod.cache, :last_run_time
|
|
133
|
+
assert_respond_to mod.cache, :job_ran
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "adapts an initialized Stockpile immediately" do
|
|
137
|
+
mod.cache
|
|
138
|
+
mod.cache_adapter(lrt)
|
|
139
|
+
assert_respond_to mod.cache, :last_run_time
|
|
140
|
+
assert_respond_to mod.cache, :job_ran
|
|
141
|
+
assert_empty mod.instance_variable_get(:@__stockpile_triggers__)
|
|
105
142
|
end
|
|
106
143
|
|
|
107
144
|
it "adapts the cache with last_run_time" do
|
|
@@ -124,10 +161,49 @@ describe Stockpile do
|
|
|
124
161
|
assert_equal iso, lrt.last_run_time('foo', now)
|
|
125
162
|
assert_equal now.to_i, lrt.last_run_time('foo').to_i
|
|
126
163
|
end
|
|
164
|
+
|
|
165
|
+
it "adapts the cache with job_ran" do
|
|
166
|
+
mod.cache_adapter(lrt)
|
|
167
|
+
refute mod.cache.job_ran('foo')
|
|
168
|
+
assert mod.cache.job_ran('foo', true)
|
|
169
|
+
assert mod.cache.job_ran('foo')
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "adapts the module with last_run_time" do
|
|
173
|
+
mod.cache_adapter(lrt, mod)
|
|
174
|
+
refute mod.job_ran('foo')
|
|
175
|
+
assert mod.job_ran('foo', true)
|
|
176
|
+
assert mod.job_ran('foo')
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it "adapts the lrt module with last_run_time" do
|
|
180
|
+
mod.cache_adapter!(lrt)
|
|
181
|
+
refute lrt.job_ran('foo')
|
|
182
|
+
assert lrt.job_ran('foo', true)
|
|
183
|
+
assert lrt.job_ran('foo')
|
|
184
|
+
end
|
|
127
185
|
end
|
|
128
|
-
end
|
|
129
186
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
187
|
+
describe "Stockpile.inject!(Class):" do
|
|
188
|
+
before { ::Stockpile.inject!(cls) }
|
|
189
|
+
|
|
190
|
+
it "defines cls.cache" do
|
|
191
|
+
assert_respond_to cls, :cache
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it "defines cls.cache_adapter" do
|
|
195
|
+
assert_respond_to cls, :cache_adapter
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it "defines cls.cache_adapter!" do
|
|
199
|
+
assert_respond_to cls, :cache_adapter!
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
it "Fails cache initialization" do
|
|
203
|
+
assert_raises ArgumentError do
|
|
204
|
+
cls.cache
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
133
209
|
end
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
require 'minitest_config'
|
|
2
|
+
|
|
3
|
+
describe Stockpile::Base do
|
|
4
|
+
def assert_clients expected_clients, connector
|
|
5
|
+
actual_clients = connector.instance_variable_get(:@clients).keys
|
|
6
|
+
assert_equal actual_clients.sort, expected_clients.sort
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
let(:mem) {
|
|
10
|
+
stub_env({}) { Stockpile::Memory.new }
|
|
11
|
+
}
|
|
12
|
+
let(:mem_namespace) {
|
|
13
|
+
stub_env({}) { Stockpile::Memory.new(namespace: 'Z') }
|
|
14
|
+
}
|
|
15
|
+
let(:mem_wide) {
|
|
16
|
+
stub_env({}) { Stockpile::Memory.new(narrow: false) }
|
|
17
|
+
}
|
|
18
|
+
let(:mem_narrow) {
|
|
19
|
+
stub_env({}) { Stockpile::Memory.new(narrow: true) }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe 'constructor' do
|
|
23
|
+
it "uses the default connection width by default" do
|
|
24
|
+
stub ::Stockpile, :narrow?, lambda { false } do
|
|
25
|
+
refute Stockpile::Base.new.narrow?,
|
|
26
|
+
"should be narrow, but is not"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
stub ::Stockpile, :narrow?, lambda { true } do
|
|
30
|
+
assert Stockpile::Base.new.narrow?,
|
|
31
|
+
"is not narrow, but should be"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "can be told which connection width to use explicitly" do
|
|
36
|
+
stub ::Stockpile, :narrow?, lambda { false } do
|
|
37
|
+
assert mem_narrow.narrow?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
stub ::Stockpile, :narrow?, lambda { true } do
|
|
41
|
+
refute mem_wide.narrow?
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "passes settings through to the client" do
|
|
46
|
+
options = {
|
|
47
|
+
url: 'test://xyz/'
|
|
48
|
+
}
|
|
49
|
+
mem = ::Stockpile::Memory.new(options)
|
|
50
|
+
assert_equal 'test://xyz/', mem.connect.options[:url]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "has no clients by default" do
|
|
54
|
+
assert_clients [], ::Stockpile::Memory.new
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe "#connect" do
|
|
59
|
+
it "raises NotImplementedError unless #client_connect is implemented" do
|
|
60
|
+
assert_raises NotImplementedError do
|
|
61
|
+
::Stockpile::Base.new.connect
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "creates a connection to the client" do
|
|
66
|
+
assert_nil mem.connection
|
|
67
|
+
refute_nil mem.connect
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "creates a namespaced connection to the client" do
|
|
71
|
+
assert_nil mem_namespace.connection
|
|
72
|
+
refute_nil mem_namespace.connect
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe "with a wide connection width" do
|
|
76
|
+
before do
|
|
77
|
+
mem_wide.connect(:hoge, { quux: {} })
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "connects multiple clients" do
|
|
81
|
+
assert_clients [ :hoge, :quux ], mem_wide
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "connects *different* clients" do
|
|
85
|
+
refute_same mem_wide.connection, mem_wide.connection_for(:hoge)
|
|
86
|
+
refute_same mem_wide.connection, mem_wide.connection_for(:quux)
|
|
87
|
+
refute_same mem_wide.connection_for(:hoge), mem_wide.connection_for(:quux)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
describe "with a narrow connection width" do
|
|
92
|
+
before do
|
|
93
|
+
mem_narrow.connect(:hoge, :quux)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "appears to connect multiple clients" do
|
|
97
|
+
assert_clients [ :hoge, :quux ], mem_narrow
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "returns identical clients" do
|
|
101
|
+
assert_same mem_narrow.connection, mem_narrow.connection_for(:hoge)
|
|
102
|
+
assert_same mem_narrow.connection, mem_narrow.connection_for(:quux)
|
|
103
|
+
assert_same mem_narrow.connection_for(:hoge), mem_narrow.connection_for(:quux)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
describe "#connection_for" do
|
|
109
|
+
it "raises NotImplementedError unless #client_connect is implemented" do
|
|
110
|
+
assert_raises NotImplementedError do
|
|
111
|
+
instance_stub ::Stockpile::Base, :connection, -> { true } do
|
|
112
|
+
::Stockpile::Base.new.connection_for(:foo)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
describe "with a wide connection width" do
|
|
118
|
+
it "connects the main client" do
|
|
119
|
+
mem_wide.connection_for(:global)
|
|
120
|
+
assert mem_wide.connection
|
|
121
|
+
refute_same mem_wide.connection, mem_wide.connection_for(:global)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
describe "with a narrow connection width" do
|
|
126
|
+
it "connects the main client" do
|
|
127
|
+
mem_narrow.connection_for(:global)
|
|
128
|
+
assert mem_narrow.connection
|
|
129
|
+
assert_same mem_narrow.connection, mem_narrow.connection_for(:global)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
let(:connection) { Stockpile::Memory::Data }
|
|
135
|
+
|
|
136
|
+
describe "#disconnect" do
|
|
137
|
+
it "raises NotImplementedError unless #client_disconnect is implemented" do
|
|
138
|
+
base = ::Stockpile::Base.new
|
|
139
|
+
assert_raises NotImplementedError do
|
|
140
|
+
instance_stub ::Stockpile::Base, :connect do
|
|
141
|
+
instance_stub ::Stockpile::Base, :connection, -> { true } do
|
|
142
|
+
base.disconnect
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
describe "with a wide connection width" do
|
|
149
|
+
let(:global) { mem_wide.connection }
|
|
150
|
+
let(:hoge) { mem_wide.connection_for(:hoge) }
|
|
151
|
+
|
|
152
|
+
before do
|
|
153
|
+
mem_wide.connect(:hoge)
|
|
154
|
+
assert hoge.connected? && global.connected?
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it "disconnects the global client" do
|
|
158
|
+
mem_wide.disconnect
|
|
159
|
+
assert hoge.connected? && !global.connected?
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it "disconnects the redis and global clients" do
|
|
163
|
+
mem_wide.disconnect(:hoge)
|
|
164
|
+
refute hoge.connected? || global.connected?
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
describe "with a narrow connection width" do
|
|
169
|
+
let(:global) { mem_narrow.connection }
|
|
170
|
+
let(:hoge) { mem_narrow.connection_for(:hoge) }
|
|
171
|
+
|
|
172
|
+
before do
|
|
173
|
+
mem_narrow.connect(:hoge)
|
|
174
|
+
assert hoge.connected? && global.connected?
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it "#disconnect disconnects all clients" do
|
|
178
|
+
mem_narrow.disconnect
|
|
179
|
+
refute hoge.connected? || global.connected?
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
it "#disconnect(:hoge) disconnects all clients" do
|
|
183
|
+
mem_narrow.disconnect(:hoge)
|
|
184
|
+
refute hoge.connected? || global.connected?
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
describe "#reconnect" do
|
|
190
|
+
it "raises NotImplementedError unless #client_reconnect is implemented" do
|
|
191
|
+
base = ::Stockpile::Base.new
|
|
192
|
+
assert_raises NotImplementedError do
|
|
193
|
+
instance_stub ::Stockpile::Base, :connect do
|
|
194
|
+
instance_stub ::Stockpile::Base, :connection, -> { true } do
|
|
195
|
+
base.reconnect
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
describe "with a wide connection width" do
|
|
202
|
+
let(:global) { mem_wide.connection }
|
|
203
|
+
let(:hoge) { mem_wide.connection_for(:hoge) }
|
|
204
|
+
|
|
205
|
+
before do
|
|
206
|
+
mem_wide.connect(:hoge)
|
|
207
|
+
assert hoge.connected? && global.connected?
|
|
208
|
+
mem_wide.disconnect(:all)
|
|
209
|
+
refute hoge.connected? || global.connected?
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it "reconnects the global client" do
|
|
213
|
+
mem_wide.reconnect
|
|
214
|
+
assert !hoge.connected? && global.connected?
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
it "reconnects the redis and global clients" do
|
|
218
|
+
mem_wide.reconnect(:hoge)
|
|
219
|
+
assert hoge.connected? && global.connected?
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
describe "with a narrow connection width" do
|
|
224
|
+
let(:global) { mem_narrow.connection }
|
|
225
|
+
let(:hoge) { mem_narrow.connection_for(:hoge) }
|
|
226
|
+
|
|
227
|
+
def force_connection
|
|
228
|
+
mem_narrow.connect(:hoge)
|
|
229
|
+
assert hoge.connected? && global.connected?
|
|
230
|
+
mem_wide.disconnect(:all)
|
|
231
|
+
refute hoge.connected? || global.connected?
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
it "#reconnect reconnects the all clients" do
|
|
235
|
+
mem_narrow.reconnect
|
|
236
|
+
assert hoge.connected? && global.connected?
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
it "#reconnect(:hoge:) reconnects all clients" do
|
|
240
|
+
mem_narrow.reconnect(:hoge)
|
|
241
|
+
assert hoge.connected? && global.connected?
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: stockpile
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.1'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Austin Ziegler
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-
|
|
11
|
+
date: 2015-02-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|
|
@@ -228,6 +228,12 @@ description: |-
|
|
|
228
228
|
|
|
229
229
|
Stockpile also provides an adapter so that its functionality can be accessed
|
|
230
230
|
from within a module.
|
|
231
|
+
|
|
232
|
+
Release 1.1 fixes an issue with early initialization of an injected Stockpile
|
|
233
|
+
instance during adaptation
|
|
234
|
+
({stockpile#2}[https://githbub.com/halostatue/stockpile/issues/2]). Several
|
|
235
|
+
small improvements to Stockpile.new, Stockpile#connect, and
|
|
236
|
+
Stockpile#connection_for have been documented.
|
|
231
237
|
email:
|
|
232
238
|
- halostatue@gmail.com
|
|
233
239
|
executables: []
|
|
@@ -251,8 +257,11 @@ files:
|
|
|
251
257
|
- README.rdoc
|
|
252
258
|
- Rakefile
|
|
253
259
|
- lib/stockpile.rb
|
|
260
|
+
- lib/stockpile/base.rb
|
|
261
|
+
- lib/stockpile/memory.rb
|
|
254
262
|
- test/minitest_config.rb
|
|
255
263
|
- test/test_stockpile.rb
|
|
264
|
+
- test/test_stockpile_base.rb
|
|
256
265
|
homepage: https://github.com/halostatue/stockpile/
|
|
257
266
|
licenses:
|
|
258
267
|
- MIT
|
|
@@ -279,5 +288,4 @@ rubygems_version: 2.2.2
|
|
|
279
288
|
signing_key:
|
|
280
289
|
specification_version: 4
|
|
281
290
|
summary: Stockpile is a simple key-value store connection manager framework
|
|
282
|
-
test_files:
|
|
283
|
-
- test/test_stockpile.rb
|
|
291
|
+
test_files: []
|