aesop 1.1.0.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 +15 -0
- data/.gitignore +19 -0
- data/.rspec +3 -0
- data/.travis.yml +21 -0
- data/Gemfile +13 -0
- data/LICENSE +0 -0
- data/README.md +8 -0
- data/Rakefile +20 -0
- data/aesop.gemspec +29 -0
- data/config/init.rb +24 -0
- data/lib/aesop.rb +27 -0
- data/lib/aesop/aesop.rb +135 -0
- data/lib/aesop/bootloader.rb +76 -0
- data/lib/aesop/configuration.rb +13 -0
- data/lib/aesop/dispatcher.rb +49 -0
- data/lib/aesop/dispatchers/log_dispatcher.rb +7 -0
- data/lib/aesop/exceptions.rb +7 -0
- data/lib/aesop/logger.rb +41 -0
- data/lib/aesop/merb/merb_boot_loader.rb +8 -0
- data/lib/aesop/rails/middleware.rb +18 -0
- data/lib/aesop/rails/railtie.rb +18 -0
- data/lib/aesop/recipes.rb +20 -0
- data/lib/aesop/version.rb +10 -0
- data/recipes/aesop.rb +6 -0
- data/spec/aesop/aesop_spec.rb +276 -0
- data/spec/aesop/bootloader_spec.rb +138 -0
- data/spec/aesop/dispatcher_spec.rb +76 -0
- data/spec/aesop/dispatchers/log_dispatcher_spec.rb +19 -0
- data/spec/aesop/hooks_spec.rb +79 -0
- data/spec/aesop/logger_spec.rb +72 -0
- data/spec/aesop/merb/merb_boot_loader_spec.rb +25 -0
- data/spec/aesop/rails/middleware_spec.rb +13 -0
- data/spec/aesop/rails/railtie_spec.rb +62 -0
- data/spec/aesop/recipes_spec.rb +47 -0
- data/spec/spec_helper.rb +47 -0
- metadata +188 -0
data/lib/aesop/logger.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
|
3
|
+
module Aesop
|
4
|
+
module Logger
|
5
|
+
DEBUG = 1
|
6
|
+
INFO = 2
|
7
|
+
WARN = 3
|
8
|
+
ERROR = 4
|
9
|
+
FATAL = 5
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
DEFAULT_OUTPUT = 'stdout'
|
14
|
+
|
15
|
+
def log
|
16
|
+
@logger ||= setup
|
17
|
+
end
|
18
|
+
|
19
|
+
def setup
|
20
|
+
logger = Log4r::Logger.new(configuration.name)
|
21
|
+
logger.level = configuration.level
|
22
|
+
logger.outputters = configuration.outputters
|
23
|
+
logger
|
24
|
+
end
|
25
|
+
|
26
|
+
def reset
|
27
|
+
@logger = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
# makes this respond like a Log4r::Logger
|
31
|
+
def method_missing(sym, *args, &block)
|
32
|
+
log.send sym, *args, &block
|
33
|
+
end
|
34
|
+
|
35
|
+
def configuration
|
36
|
+
configatron.logger
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Aesop
|
2
|
+
module Rails
|
3
|
+
class Middleware
|
4
|
+
def initialize( app )
|
5
|
+
@app = app
|
6
|
+
end
|
7
|
+
|
8
|
+
def call( env )
|
9
|
+
begin
|
10
|
+
response = @app.call(env)
|
11
|
+
rescue Exception => e
|
12
|
+
Aesop::Aesop.instance.catch_exception(e)
|
13
|
+
end
|
14
|
+
response
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Aesop
|
2
|
+
class Railtie < ::Rails::Railtie
|
3
|
+
|
4
|
+
initializer "aesop.start_plugin" do |app|
|
5
|
+
Aesop::Aesop.instance.init
|
6
|
+
|
7
|
+
middleware = if defined?(ActionDispatch::DebugExceptions)
|
8
|
+
# Rails >= 3.2.0
|
9
|
+
"ActionDispatch::DebugExceptions"
|
10
|
+
else
|
11
|
+
# Rails < 3.2.0
|
12
|
+
"ActionDispatch::ShowExceptions"
|
13
|
+
end
|
14
|
+
|
15
|
+
app.config.middleware.insert_after middleware, "Aesop::Rails::Middleware"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Aesop
|
2
|
+
module Capistrano
|
3
|
+
def self.load_into(configuration)
|
4
|
+
configuration.load do
|
5
|
+
after "deploy:finalize_update", "aesop:record_deployment"
|
6
|
+
namespace :aesop do
|
7
|
+
desc "Record the current time into a file called DEPLOY_TIME"
|
8
|
+
task :record_deployment, :roles => :app do
|
9
|
+
set :deployment_time, Time.now.to_i.to_s
|
10
|
+
put fetch(:deployment_time), "#{configuration.fetch(:release_path)}/DEPLOY_TIME"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
if cap_config = Capistrano::Configuration.instance
|
19
|
+
Aesop::Capistrano.load_into(cap_config)
|
20
|
+
end
|
data/recipes/aesop.rb
ADDED
@@ -0,0 +1,276 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe Aesop::Aesop do
|
4
|
+
subject{ Aesop::Aesop.instance }
|
5
|
+
|
6
|
+
context 'configuration' do
|
7
|
+
it 'calls load configuration on initialization' do
|
8
|
+
subject.should_receive(:load_configuration)
|
9
|
+
bootloader_double = double
|
10
|
+
bootloader_double.stub(:boot)
|
11
|
+
Aesop::Bootloader.stub(:new).and_return(bootloader_double)
|
12
|
+
Aesop::Aesop.instance.init
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'loads default config when no config file exists' do
|
16
|
+
File.stub(:exist?).and_return(false)
|
17
|
+
config_location = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'config', 'init.rb'))
|
18
|
+
subject.should_receive(:load).with(config_location)
|
19
|
+
subject.load_configuration
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'loads config file when it exists' do
|
23
|
+
File.stub(:exist?).and_return(true)
|
24
|
+
config_location = File.expand_path('config/aesop.rb')
|
25
|
+
subject.should_receive(:load).with(config_location)
|
26
|
+
subject.load_configuration
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'can receive a block' do
|
30
|
+
expect do |block|
|
31
|
+
Aesop.configuration(&block)
|
32
|
+
end.to yield_with_args(configatron)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns the configuration if no block is given' do
|
36
|
+
Aesop.configuration.should == configatron
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'exists' do
|
41
|
+
subject.should_not be_nil
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'initialization' do
|
45
|
+
it 'boots using the bootloader' do
|
46
|
+
Aesop::Bootloader.any_instance.should_receive(:boot)
|
47
|
+
subject.init
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'merges the redis password when it is given' do
|
51
|
+
password = "pa55word"
|
52
|
+
redis_conf = double
|
53
|
+
redis_conf.stub(:host)
|
54
|
+
redis_conf.stub(:port)
|
55
|
+
redis_conf.should_receive(:password).and_return(password)
|
56
|
+
subject.configuration.stub(:redis).and_return(redis_conf)
|
57
|
+
redis_options = subject.redis_options
|
58
|
+
redis_options.should have_key(:password)
|
59
|
+
redis_options[:password].should == password
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'exceptions' do
|
64
|
+
before :all do
|
65
|
+
create_deploy_file(Time.now)
|
66
|
+
Aesop::Aesop.instance.init
|
67
|
+
end
|
68
|
+
|
69
|
+
let(:exception){ Exception.new }
|
70
|
+
let(:internal_exception){ Aesop::RedisConnectionException.new }
|
71
|
+
|
72
|
+
before :each do
|
73
|
+
subject.redis.stub(:get).and_return(nil)
|
74
|
+
subject.redis.stub(:set)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'raises an RedisConnectionException when a redis exception occurs' do
|
78
|
+
subject.instance_variable_set(:@redis, nil)
|
79
|
+
Redis.stub(:new){ raise RuntimeError.new }
|
80
|
+
lambda{subject.redis}.should raise_error( Aesop::RedisConnectionException )
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'reconnectes when not connected to redis anymore' do
|
84
|
+
subject.redis.stub(:connected?).and_return(false)
|
85
|
+
expect(Redis).to receive(:new).and_call_original
|
86
|
+
subject.redis
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'dispatches each and every exception when an array is provided' do
|
90
|
+
exceptions = []
|
91
|
+
5.times do
|
92
|
+
exceptions << exception
|
93
|
+
end
|
94
|
+
subject.should_receive(:catch_exception).with(exception).exactly(5).times
|
95
|
+
subject.catch_exceptions( exceptions )
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'throws an error when #catch_exceptions is not called with an array' do
|
99
|
+
lambda{ subject.catch_exceptions( exception )}.should raise_error( Aesop::IllegalArgumentException )
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'has a method to to register exceptions' do
|
103
|
+
subject.public_methods.map{|m| m.to_s}.should include 'catch_exception'
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'checks to see if an exception should be dispatched' do
|
107
|
+
subject.should_receive(:should_dispatch?).with(exception)
|
108
|
+
subject.catch_exception( exception )
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'checks if an exception is excluded from dispatching' do
|
112
|
+
subject.should_receive(:is_excluded?).with(exception)
|
113
|
+
subject.catch_exception( exception )
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'does not dispatch when the exception is excluded' do
|
117
|
+
subject.stub(:is_excluded?).and_return(true)
|
118
|
+
subject.should_dispatch?(exception).should be_false
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'does dispatch when the exception is not excluded' do
|
122
|
+
subject.stub(:is_excluded?).and_return(false)
|
123
|
+
subject.should_receive(:within_window?).with(exception).and_return(true)
|
124
|
+
subject.should_receive(:retrieve_exception_count).with(exception).and_return(11)
|
125
|
+
subject.should_receive(:exception_count_threshold).with(exception).and_return(10)
|
126
|
+
subject.should_dispatch?(exception).should be_true
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'reads the excluded exceptions from the configuration' do
|
130
|
+
config_double = double("Configuration")
|
131
|
+
config_double.should_receive(:excluded_exceptions)
|
132
|
+
subject.stub(:configuration){ config_double }
|
133
|
+
subject.is_excluded?(exception)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'ignores exceptions from the excluded list' do
|
137
|
+
config_double = double("Configuration")
|
138
|
+
config_double.should_receive(:excluded_exceptions).and_return( [ArgumentError] )
|
139
|
+
subject.stub(:configuration){ config_double }
|
140
|
+
subject.is_excluded?( ArgumentError.new ).should be_true
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'checks if an exception is an internal exception' do
|
144
|
+
subject.should_receive(:internal_exception?).with(exception)
|
145
|
+
subject.catch_exception( exception )
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'knows when an exception is internal' do
|
149
|
+
subject.internal_exception?(exception).should be_false
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'knows when an exception is external' do
|
153
|
+
subject.internal_exception?( internal_exception ).should be_true
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'always dispatches Aesop exceptions' do
|
157
|
+
subject.stub(:exception_already_dispatched?).and_return(false)
|
158
|
+
subject.should_receive(:dispatch_exception).with( internal_exception )
|
159
|
+
subject.catch_exception(internal_exception)
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'checks if the exception already occurred' do
|
163
|
+
subject.should_receive(:retrieve_exception_count).with(exception)
|
164
|
+
subject.should_dispatch?( exception )
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'uses the exception threshold to determine whether the window is open' do
|
168
|
+
subject.should_receive(:exception_time_threshold).with(exception).and_return(3600)
|
169
|
+
subject.within_window?(exception)
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'checks if the time window is open to dispatch' do
|
173
|
+
subject.should_receive(:within_window?).with(exception)
|
174
|
+
subject.should_dispatch?( exception )
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'retrieves the deployment time to determine if the exception should be dispatched' do
|
178
|
+
subject.should_receive(:retrieve_deployment_time)
|
179
|
+
subject.should_dispatch?( exception )
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'uses the exception_prefix when retrieving the exception' do
|
183
|
+
subject.should_receive(:exception_prefix).and_return("aesop:exceptions")
|
184
|
+
subject.retrieve_exception_count(exception)
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'uses the exception_prefix when storing the exception occurrence' do
|
188
|
+
subject.should_receive(:exception_prefix).and_return("aesop:exceptions")
|
189
|
+
subject.store_exception_occurrence(exception)
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'uses the exception count threshould when determining whether the occurrence should be dispatched' do
|
193
|
+
subject.stub(:within_window?).and_return(true)
|
194
|
+
subject.stub(:retrieve_exception_count).and_return(5)
|
195
|
+
subject.should_receive(:exception_count_threshold).with(exception).and_return(10)
|
196
|
+
subject.should_dispatch?(exception)
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'does not dispatch when the amount of occurrences is smaller than the threshold' do
|
200
|
+
subject.should_not_receive(:dispatch_exception)
|
201
|
+
subject.should_receive(:within_window?).with(exception).and_return(true)
|
202
|
+
subject.should_receive(:retrieve_exception_count).with(exception).and_return(5)
|
203
|
+
subject.should_receive(:exception_count_threshold).with(exception).and_return(10)
|
204
|
+
subject.catch_exception(exception)
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'dispatches when the amount of occurrences is greater then the threshold' do
|
208
|
+
subject.should_receive(:dispatch_exception).with(exception)
|
209
|
+
subject.should_receive(:within_window?).with(exception).and_return(true)
|
210
|
+
subject.should_receive(:retrieve_exception_count).with(exception).and_return(11)
|
211
|
+
subject.should_receive(:exception_count_threshold).with(exception).and_return(10)
|
212
|
+
subject.catch_exception(exception)
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'looks up the exception in redis' do
|
216
|
+
subject.redis.should_receive(:get).with("aesop:exceptions:#{exception.class.to_s}:count")
|
217
|
+
subject.retrieve_exception_count( exception )
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'records the occurrence of the exception while within the window' do
|
221
|
+
subject.should_receive(:within_window?).with(exception).and_return(false)
|
222
|
+
subject.should_receive(:store_exception_occurrence).with(exception)
|
223
|
+
subject.catch_exception(exception)
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'records the occorrence of the exception while outside the window' do
|
227
|
+
subject.should_receive(:within_window?).with(exception).and_return(true)
|
228
|
+
subject.should_receive(:store_exception_occurrence).with(exception)
|
229
|
+
subject.catch_exception(exception)
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'increments the number of occurrences of an exception when stored' do
|
233
|
+
subject.redis.should_receive(:incr).with("aesop:exceptions:#{exception.class.to_s}:count")
|
234
|
+
subject.catch_exception(exception)
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'checks if the exception has been dispatched yet' do
|
238
|
+
subject.stub(:within_window?).and_return(true)
|
239
|
+
subject.stub(:retrieve_exception_count).and_return(100)
|
240
|
+
subject.stub(:exception_count_treshold).and_return(10)
|
241
|
+
|
242
|
+
subject.should_receive(:exception_already_dispatched?).with(exception)
|
243
|
+
subject.should_dispatch?(exception)
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'does not dispatch the exception when it has already been dispatched' do
|
247
|
+
subject.stub(:within_window?).and_return(true)
|
248
|
+
subject.stub(:retrieve_exception_count).and_return(100)
|
249
|
+
subject.stub(:exception_count_treshold).and_return(10)
|
250
|
+
|
251
|
+
subject.stub(:exception_already_dispatched?).and_return(true)
|
252
|
+
subject.should_dispatch?(exception).should be_false
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'dispatches the exception when it should be dispatched' do
|
256
|
+
subject.should_receive(:should_dispatch?).with(exception).and_return(true)
|
257
|
+
subject.should_receive(:dispatch_exception).with(exception)
|
258
|
+
subject.catch_exception(exception)
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'records the dispatching of the exception' do
|
262
|
+
subject.should_receive(:record_exception_dispatch).with(exception)
|
263
|
+
subject.dispatch_exception(exception)
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'stores the time of dispatch when an exception is dispatched' do
|
267
|
+
subject.redis.should_receive(:set).with("aesop:exceptions:#{exception.class.to_s}:dispatched", anything())
|
268
|
+
subject.dispatch_exception(exception)
|
269
|
+
end
|
270
|
+
|
271
|
+
it 'invokes the dispatcher when the exception should be dispatched' do
|
272
|
+
Aesop::Dispatcher.instance.should_receive(:dispatch_exception).with(exception)
|
273
|
+
subject.dispatch_exception(exception)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe Aesop::Bootloader do
|
4
|
+
it 'exists' do
|
5
|
+
subject.should_not be_nil
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'initialization' do
|
9
|
+
it 'attempts to read a DEPLOY file when boot is called' do
|
10
|
+
subject.should_receive :read_deploy_time
|
11
|
+
subject.boot
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'calls load_dispatchers on boot' do
|
15
|
+
subject.should_receive :load_dispatchers
|
16
|
+
subject.boot
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'loads all files in the dispatchers directory' do
|
20
|
+
dirname = File.dirname( File.join( File.dirname(__FILE__), '..', '..', 'lib', 'aesop', 'dispatchers' ) )
|
21
|
+
Dir["#{dirname}/dispatchers/**/*.rb"].each do |file|
|
22
|
+
subject.should_receive(:require).with( File.expand_path(file) )
|
23
|
+
end
|
24
|
+
subject.boot
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'raises an BootloaderException when an exception occurs during bootloading' do
|
28
|
+
subject.stub(:determine_latest_deploy_time){ raise RuntimeError.new }
|
29
|
+
lambda{ subject.boot }.should raise_error( Aesop::BootloaderException )
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'raises an DispatcherLoadException when an exception occurs during dispatch loading' do
|
33
|
+
subject.stub(:require){ raise RuntimeError.new }
|
34
|
+
lambda{ subject.load_dispatchers }.should raise_error( Aesop::DispatcherLoadException )
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'reading DEPLOY file' do
|
39
|
+
it 'reads the configuration' do
|
40
|
+
subject.should_receive(:configuration).at_least(1).and_return(config)
|
41
|
+
subject.boot
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'can retrieve the location of the deployment file' do
|
45
|
+
subject.deployment_file
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'does not complain when the file does not exist' do
|
49
|
+
remove_deploy_file
|
50
|
+
deploy_time = subject.read_deploy_time
|
51
|
+
deploy_time.should be_nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'reads a timestamp from redis' do
|
55
|
+
subject.should_receive(:read_current_timestamp)
|
56
|
+
subject.boot
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'reads the timestamp from the file' do
|
60
|
+
now = Time.now
|
61
|
+
create_deploy_file(now)
|
62
|
+
subject.read_deploy_time.to_i.should == now.to_i
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'uses #determine_latest_deploy_time to determine the latest deploy time' do
|
66
|
+
subject.should_receive(:determine_latest_deploy_time)
|
67
|
+
subject.boot
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'determines the latest deploy time by reading deploy file and redis' do
|
71
|
+
subject.should_receive(:read_deploy_time)
|
72
|
+
subject.should_receive(:read_current_timestamp)
|
73
|
+
subject.determine_latest_deploy_time
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'uses the time stored in the file when no time is stored in redis' do
|
77
|
+
now = Time.now
|
78
|
+
create_deploy_file(now)
|
79
|
+
subject.stub(:read_current_timestamp).and_return(0)
|
80
|
+
subject.determine_latest_deploy_time.should == now.to_i
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'always stores the latest deploy time to redis' do
|
84
|
+
time = Time.now - 500
|
85
|
+
newer_time = Time.now
|
86
|
+
create_deploy_file(time)
|
87
|
+
subject.should_receive(:read_deploy_time).and_return(newer_time.to_i)
|
88
|
+
subject.should_receive(:store_timestamp).with(newer_time.to_i)
|
89
|
+
subject.boot
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'stores a timestamp when a deployment file exists' do
|
93
|
+
create_deploy_file
|
94
|
+
subject.should_receive(:store_timestamp)
|
95
|
+
subject.boot
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'uses the configuration to lookup the exception prefix' do
|
99
|
+
config_double = double()
|
100
|
+
config_double.should_receive( :exception_prefix ).and_return('aesop:exceptions')
|
101
|
+
subject.stub(:configuration).and_return(config_double)
|
102
|
+
subject.reset_exceptions
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'resets all exceptions when #reset_exceptions is called' do
|
106
|
+
5.times do |i|
|
107
|
+
subject.redis.set("#{config.exception_prefix}:SomeException#{i}:count", i)
|
108
|
+
end
|
109
|
+
|
110
|
+
subject.reset_exceptions
|
111
|
+
subject.redis.keys("#{config.exception_prefix}:*").size.should == 0
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'resets all exceptions when a new deployment has occured' do
|
115
|
+
older_time = Time.now - 500
|
116
|
+
newer_time = Time.now
|
117
|
+
subject.stub(:read_deploy_time).and_return(newer_time.to_i)
|
118
|
+
subject.stub(:read_current_timestamp).and_return(older_time.to_i)
|
119
|
+
subject.should_receive(:reset_exceptions)
|
120
|
+
subject.boot
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'does not rest exceptions when the time in redis is newer' do
|
124
|
+
older_time = Time.now - 500
|
125
|
+
newer_time = Time.now
|
126
|
+
subject.stub(:read_deploy_time).and_return(older_time.to_i)
|
127
|
+
subject.stub(:read_current_timestamp).and_return(newer_time.to_i)
|
128
|
+
subject.should_not_receive(:reset_exceptions)
|
129
|
+
subject.boot
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'stores the timestamp in redis in the aesop:deployment:timestamp key' do
|
133
|
+
time = 12345
|
134
|
+
subject.redis.should_receive(:set).with(config.deployment_key, time)
|
135
|
+
subject.store_timestamp( time )
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|