flapjack 0.6.61 → 0.7.0

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.
Files changed (38) hide show
  1. data/Gemfile +2 -1
  2. data/README.md +8 -4
  3. data/features/events.feature +269 -146
  4. data/features/notification_rules.feature +93 -0
  5. data/features/steps/events_steps.rb +162 -21
  6. data/features/steps/notifications_steps.rb +1 -1
  7. data/features/steps/time_travel_steps.rb +30 -19
  8. data/features/support/env.rb +71 -1
  9. data/flapjack.gemspec +3 -0
  10. data/lib/flapjack/data/contact.rb +256 -57
  11. data/lib/flapjack/data/entity.rb +2 -1
  12. data/lib/flapjack/data/entity_check.rb +22 -7
  13. data/lib/flapjack/data/global.rb +1 -0
  14. data/lib/flapjack/data/message.rb +2 -0
  15. data/lib/flapjack/data/notification_rule.rb +172 -0
  16. data/lib/flapjack/data/tag.rb +7 -2
  17. data/lib/flapjack/data/tag_set.rb +16 -0
  18. data/lib/flapjack/executive.rb +147 -13
  19. data/lib/flapjack/filters/delays.rb +21 -9
  20. data/lib/flapjack/gateways/api.rb +407 -27
  21. data/lib/flapjack/gateways/pagerduty.rb +1 -1
  22. data/lib/flapjack/gateways/web.rb +50 -22
  23. data/lib/flapjack/gateways/web/views/self_stats.haml +2 -0
  24. data/lib/flapjack/utility.rb +10 -0
  25. data/lib/flapjack/version.rb +1 -1
  26. data/spec/lib/flapjack/data/contact_spec.rb +103 -6
  27. data/spec/lib/flapjack/data/global_spec.rb +2 -0
  28. data/spec/lib/flapjack/data/message_spec.rb +6 -0
  29. data/spec/lib/flapjack/data/notification_rule_spec.rb +22 -0
  30. data/spec/lib/flapjack/data/notification_spec.rb +6 -0
  31. data/spec/lib/flapjack/gateways/api_spec.rb +727 -4
  32. data/spec/lib/flapjack/gateways/jabber_spec.rb +1 -0
  33. data/spec/lib/flapjack/gateways/web_spec.rb +11 -1
  34. data/spec/spec_helper.rb +10 -0
  35. data/tmp/notification_rules.rb +73 -0
  36. data/tmp/test_json_post.rb +16 -0
  37. data/tmp/test_notification_rules_api.rb +170 -0
  38. metadata +59 -2
@@ -0,0 +1,93 @@
1
+ @notification_rules @resque
2
+ Feature: Notification rules on a per contact basis
3
+
4
+ Background:
5
+ Given the following users exist:
6
+ | id | first_name | last_name | email | sms |
7
+ | 1 | Malak | Al-Musawi | malak@example.com | +61400000001 |
8
+ | 2 | Imani | Farooq | imani@example.com | +61400000002 |
9
+
10
+ And the following entities exist:
11
+ | id | name | contacts |
12
+ | 1 | foo | 1 |
13
+ | 2 | bar | 1,2 |
14
+
15
+ And user 1 has the following notification intervals:
16
+ | email | sms |
17
+ | 15 | 60 |
18
+
19
+ And user 1 has the following notification rules:
20
+ | id | entities | entity_tags | warning_media | critical_media | warning_blackhole | critical_blackhole | time_restrictions |
21
+ | 1 | foo | | email | sms,email | | | 8-18 weekdays |
22
+ | 2 | bar | | | sms,email | true | | |
23
+
24
+ @time_restrictions @time
25
+ Scenario: Alerts only during specified time restrictions
26
+ Given the timezone is America/New_York
27
+ And the time is February 1 2013 6:59
28
+ And the check is check 'ping' on entity 'foo'
29
+ And the check is in an ok state
30
+ And a critical event is received
31
+ Then no email alerts should be queued for malak@example.com
32
+ And the time is February 1 2013 7:01
33
+ And a critical event is received
34
+ Then no email alerts should be queued for malak@example.com
35
+ And the time is February 1 2013 8:01
36
+ And a critical event is received
37
+ Then 1 email alert should be queued for malak@example.com
38
+ When the time is February 1 2013 12:00
39
+ Then all alert dropping keys for user 1 should have expired
40
+ When a critical event is received
41
+ Then 2 email alerts should be queued for malak@example.com
42
+ When the time is February 1 2013 17:59
43
+ Then all alert dropping keys for user 1 should have expired
44
+ When a critical event is received
45
+ Then 3 email alerts should be queued for malak@example.com
46
+ When the time is February 1 2013 18:01
47
+ Then all alert dropping keys for user 1 should have expired
48
+ When a critical event is received
49
+ Then 3 email alerts should be queued for malak@example.com
50
+
51
+ Scenario: time restrictions continue to work as expected when a contact changes timezone
52
+
53
+ @severity @time
54
+ Scenario: Don't alert when media,severity does not match any matching rule's severity's media
55
+ Given the check is check 'ping' on entity 'bar'
56
+ And the check is in an ok state
57
+ When a warning event is received
58
+ And 60 minutes passes
59
+ And a warning event is received
60
+ Then no email alerts should be queued for malak@example.com
61
+
62
+ @severity @time
63
+ Scenario: Alerts only when media,severity matches any matching rule's severity's media with ok->warning->critical
64
+ Given the check is check 'ping' on entity 'bar'
65
+ And the check is in an ok state
66
+ When a warning event is received
67
+ And 1 minute passes
68
+ And a warning event is received
69
+ Then no email alerts should be queued for malak@example.com
70
+ When a critical event is received
71
+ And 5 minute passes
72
+ And a critical event is received
73
+ Then 1 email alert should be queued for malak@example.com
74
+
75
+ @blackhole
76
+ Scenario: Drop alerts matching a blackhole rule
77
+
78
+ @intervals @time
79
+ Scenario: Alerts according to custom interval
80
+ Given the check is check 'ping' on entity 'bar'
81
+ And the check is in an ok state
82
+ When a critical event is received
83
+ Then no email alerts should be queued for malak@example.com
84
+ When 1 minute passes
85
+ And a critical event is received
86
+ Then 1 email alert should be queued for malak@example.com
87
+ When 10 minutes passes
88
+ And a critical event is received
89
+ Then 1 email alert should be queued for malak@example.com
90
+ When 5 minutes passes
91
+ And a critical event is received
92
+ Then 2 email alerts should be queued for malak@example.com
93
+
@@ -1,8 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'flapjack/data/entity_check'
4
- require 'flapjack/data/event'
5
-
6
3
  def drain_events
7
4
  loop do
8
5
  event = Flapjack::Data::Event.next(:block => false, :redis => @redis)
@@ -53,12 +50,18 @@ def set_ok_state(entity, check)
53
50
  :timestamp => (Time.now.to_i - (60*60*24)))
54
51
  end
55
52
 
56
- def set_failure_state(entity, check)
53
+ def set_critical_state(entity, check)
57
54
  entity_check = Flapjack::Data::EntityCheck.for_entity_name(entity, check, :redis => @redis)
58
55
  entity_check.update_state(Flapjack::Data::EntityCheck::STATE_CRITICAL,
59
56
  :timestamp => (Time.now.to_i - (60*60*24)))
60
57
  end
61
58
 
59
+ def set_warning_state(entity, check)
60
+ entity_check = Flapjack::Data::EntityCheck.for_entity_name(entity, check, :redis => @redis)
61
+ entity_check.update_state(Flapjack::Data::EntityCheck::STATE_WARNING,
62
+ :timestamp => (Time.now.to_i - (60*60*24)))
63
+ end
64
+
62
65
  def submit_ok(entity, check)
63
66
  event = {
64
67
  'type' => 'service',
@@ -71,6 +74,18 @@ def submit_ok(entity, check)
71
74
  submit_event(event)
72
75
  end
73
76
 
77
+ def submit_warning(entity, check)
78
+ event = {
79
+ 'type' => 'service',
80
+ 'state' => 'warning',
81
+ 'summary' => '25% packet loss',
82
+ 'entity' => entity,
83
+ 'check' => check,
84
+ 'client' => 'clientx'
85
+ }
86
+ submit_event(event)
87
+ end
88
+
74
89
  def submit_critical(entity, check)
75
90
  event = {
76
91
  'type' => 'service',
@@ -102,62 +117,188 @@ Given /^an entity '([\w\.\-]+)' exists$/ do |entity|
102
117
  :redis => @redis )
103
118
  end
104
119
 
105
- Given /^^check '([\w\.\-]+)' for entity '([\w\.\-]+)' is in an ok state$/ do |check, entity|
120
+ Given /^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') is in an ok state$/ do |check, entity|
121
+ check = check ? check : @check
122
+ entity = entity ? entity : @entity
106
123
  remove_unscheduled_maintenance(entity, check)
107
124
  remove_scheduled_maintenance(entity, check)
108
125
  remove_notifications(entity, check)
109
126
  set_ok_state(entity, check)
110
127
  end
111
128
 
112
- Given /^check '([\w\.\-]+)' for entity '([\w\.\-]+)' is in a failure state$/ do |check, entity|
129
+ Given /^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') is in a critical state$/ do |check, entity|
130
+ check = check ? check : @check
131
+ entity = entity ? entity : @entity
113
132
  remove_unscheduled_maintenance(entity, check)
114
133
  remove_scheduled_maintenance(entity, check)
115
134
  remove_notifications(entity, check)
116
- set_failure_state(entity, check)
135
+ set_critical_state(entity, check)
117
136
  end
118
137
 
119
- Given /^check '([\w\.\-]+)' for entity '([\w\.\-]+)' is in scheduled maintenance$/ do |check, entity|
138
+ Given /^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') is in scheduled maintenance$/ do |check, entity|
139
+ check = check ? check : @check
140
+ entity = entity ? entity : @entity
120
141
  remove_unscheduled_maintenance(entity, check)
121
142
  set_scheduled_maintenance(entity, check)
122
143
  end
123
144
 
124
145
  # TODO set the state directly rather than submit & drain
125
- Given /^check '([\w\.\-]+)' for entity '([\w\.\-]+)' is in unscheduled maintenance$/ do |check, entity|
146
+ Given /^(?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') is in unscheduled maintenance$/ do |check, entity|
147
+ check = check ? check : @check
148
+ entity = entity ? entity : @entity
126
149
  remove_scheduled_maintenance(entity, check)
127
- set_failure_state(entity, check)
150
+ set_critical_state(entity, check)
128
151
  submit_acknowledgement(entity, check)
129
152
  drain_events # TODO these should only be in When clauses
130
153
  end
131
154
 
132
- When /^an ok event is received for check '([\w\.\-]+)' on entity '([\w\.\-]+)'$/ do |check, entity|
155
+ Given /^the check is check '(.*)' on entity '([\w\.\-]+)'$/ do |check, entity|
156
+ @check = check
157
+ @entity = entity
158
+ end
159
+
160
+ When /^an ok event is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
161
+ check ||= @check
162
+ entity ||= @entity
133
163
  submit_ok(entity, check)
134
164
  drain_events
135
165
  end
136
166
 
137
- When /^a failure event is received for check '([\w\.\-]+)' on entity '([\w\.\-]+)'$/ do |check, entity|
167
+ When /^a failure event is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
168
+ check ||= @check
169
+ entity ||= @entity
138
170
  submit_critical(entity, check)
139
171
  drain_events
140
172
  end
141
173
 
142
- When /^an acknowledgement .*is received for check '([\w\.\-]+)' on entity '([\w\.\-]+)'$/ do |check, entity|
143
- submit_acknowledgement(entity, check)
174
+ When /^a critical event is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
175
+ check ||= @check
176
+ entity ||= @entity
177
+ submit_critical(entity, check)
144
178
  drain_events
145
179
  end
146
180
 
181
+ When /^a warning event is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
182
+ check ||= @check
183
+ entity ||= @entity
184
+ submit_warning(entity, check)
185
+ drain_events
186
+ end
187
+
188
+ When /^an acknowledgement .*is received(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
189
+ check ||= @check
190
+ entity ||= @entity
191
+ submit_acknowledgement(entity, check)
192
+ drain_events
193
+ end
147
194
 
148
195
  # TODO logging is a side-effect, should test for notification generation itself
149
- Then /^a notification should not be generated for check '([\w\.\-]+)' on entity '([\w\.\-]+)'$/ do |check, entity|
196
+ Then /^a notification should not be generated(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
197
+ check ||= @check
198
+ entity ||= @entity
150
199
  message = @logger.messages.find_all {|m| m =~ /enerating notifications for event #{entity}:#{check}/ }.last
151
- message ? happy = message.match(/Not generating notifications/) : happy = false
152
- happy.should be_true
200
+ found = message ? message.match(/Not generating notifications/) : false
201
+ found.should be_true
153
202
  end
154
203
 
155
- Then /^a notification should be generated for check '([\w\.\-]+)' on entity '([\w\.\-]+)'$/ do |check, entity|
204
+ Then /^a notification should be generated(?: for check '([\w\.\-]+)' on entity '([\w\.\-]+)')?$/ do |check, entity|
205
+ check ||= @check
206
+ entity ||= @entity
156
207
  message = @logger.messages.find_all {|m| m =~ /enerating notifications for event #{entity}:#{check}/ }.last
157
- message ? happy = message.match(/Generating notifications/) : happy = false
158
- happy.should be_true
208
+ found = message ? message.match(/Generating notifications/) : false
209
+ found.should be_true
159
210
  end
160
211
 
161
- Then /^show me the notifications?$/ do
212
+ Then /^show me the log$/ do
162
213
  puts @logger.messages.join("\n")
163
214
  end
215
+
216
+ # added for notification rules:
217
+
218
+ Given /^the following entities exist:$/ do |entities|
219
+ entities.hashes.each do |entity|
220
+ contacts = entity['contacts'].split(',')
221
+ contacts.map! do |contact|
222
+ contact.strip
223
+ end
224
+ #puts "adding entity #{entity['name']} (#{entity['id']}) with contacts: [#{contacts.join(', ')}]"
225
+ Flapjack::Data::Entity.add({'id' => entity['id'],
226
+ 'name' => entity['name'],
227
+ 'contacts' => contacts},
228
+ :redis => @redis )
229
+ end
230
+ end
231
+
232
+ Given /^the following users exist:$/ do |contacts|
233
+ contacts.hashes.each do |contact|
234
+ media = {}
235
+ media['email'] = contact['email']
236
+ media['sms'] = contact['sms']
237
+ Flapjack::Data::Contact.add({'id' => contact['id'],
238
+ 'first_name' => contact['first_name'],
239
+ 'last_name' => contact['last_name'],
240
+ 'email' => contact['email'],
241
+ 'media' => media},
242
+ :redis => @redis )
243
+ end
244
+ end
245
+
246
+ Given /^user (\d+) has the following notification intervals:$/ do |contact_id, intervals|
247
+ contact = Flapjack::Data::Contact.find_by_id(contact_id, :redis => @redis)
248
+ intervals.hashes.each do |interval|
249
+ contact.set_interval_for_media('email', interval['email'].to_i * 60)
250
+ contact.set_interval_for_media('sms', interval['sms'].to_i * 60)
251
+ end
252
+ end
253
+
254
+ Given /^user (\d+) has the following notification rules:$/ do |contact_id, rules|
255
+ rules.hashes.each do |rule|
256
+ entities = rule['entities'].split(',').map { |x| x.strip }
257
+ entity_tags = rule['entity_tags'].split(',').map { |x| x.strip }
258
+ warning_media = rule['warning_media'].split(',').map { |x| x.strip }
259
+ critical_media = rule['critical_media'].split(',').map { |x| x.strip }
260
+ warning_blackhole = rule['warning_blackhole'].downcase == 'true' ? 'true' : 'false'
261
+ critical_blackhole = rule['critical_blackhole'].downcase == 'true' ? 'true' : 'false'
262
+ time_restrictions = []
263
+ rule['time_restrictions'].split(',').map { |x| x.strip }.each do |time_restriction|
264
+ case time_restriction
265
+ when '8-18 weekdays'
266
+ # FIXME: get timezone from the user definition (or config[:default_contact_timezone])
267
+ time_zone = ActiveSupport::TimeZone.new("America/New_York")
268
+ weekdays_8_18 = IceCube::Schedule.new(time_zone.local(2013,2,1,8,0,0), :duration => 60 * 60 * 10)
269
+ weekdays_8_18.add_recurrence_rule(IceCube::Rule.weekly.day(:monday, :tuesday, :wednesday, :thursday, :friday))
270
+ time_restrictions << Flapjack::Data::NotificationRule.time_restriction_from_ice_cube_hash(weekdays_8_18.to_hash, time_zone)
271
+ end
272
+ end
273
+ Flapjack::Data::NotificationRule.add({:contact_id => contact_id,
274
+ :entities => entities,
275
+ :entity_tags => entity_tags,
276
+ :warning_media => warning_media,
277
+ :critical_media => critical_media,
278
+ :warning_blackhole => warning_blackhole,
279
+ :critical_blackhole => critical_blackhole,
280
+ :time_restrictions => time_restrictions}, :redis => @redis)
281
+ end
282
+ end
283
+
284
+ Then /^all alert dropping keys for user (\d+) should have expired$/ do |contact_id|
285
+ @redis.keys("drop_alerts_for_contact:#{contact_id}*").should be_empty
286
+ end
287
+
288
+ # When /^the (\w*) alert block for user (\d*) for (?:the check|check '([\w\.\-]+)' for entity '([\w\.\-]+)') for state (.*) expires$/ do |media, contact, check, entity, state|
289
+ # check = check ? check : @check
290
+ # entity = entity ? entity : @entity
291
+ # num_deleted = @redis.del("drop_alerts_for_contact:#{contact}:#{media}:#{entity}:#{check}:#{state}")
292
+ # puts "Warning: no keys expired" unless num_deleted > 0
293
+ # end
294
+
295
+ Then /^(.*) email alert(?:s)? should be queued for (.*)$/ do |num_queued, address|
296
+ check = check ? check : @check
297
+ entity = entity ? entity : @entity
298
+ case num_queued
299
+ when 'no'
300
+ num_queued = 0
301
+ end
302
+ queue = Resque.peek('email_notifications', 0, 30)
303
+ queue.find_all {|n| n['args'].first['address'] == address }.length.should == num_queued.to_i
304
+ end
@@ -66,7 +66,7 @@ When /^an event notification is generated for entity '([\w\.\-]+)'$/ do |entity|
66
66
  'entity' => entity,
67
67
  'check' => 'ping')
68
68
  entity_check = Flapjack::Data::EntityCheck.for_entity_name(entity, 'ping', :redis => @redis)
69
- @app.send(:send_notification_messages, event, entity_check)
69
+ @app.send(:generate_notification_messages, event, entity_check)
70
70
  end
71
71
 
72
72
  Then /^an SMS notification for entity '([\w\.\-]+)' should be queued for the user$/ do |entity|
@@ -2,33 +2,44 @@
2
2
 
3
3
  require 'delorean'
4
4
  require 'chronic'
5
+ require 'active_support/time'
5
6
 
6
7
  When /^(.+) passes$/ do |time|
7
8
  period = Chronic.parse("#{time} from now")
8
- Delorean.time_travel_to(period)
9
- # puts "Time Travelled to #{Time.now.to_s}"
9
+ RedisDelorean.time_travel_to(period)
10
+ #puts "Time Travelled to #{Time.now.to_s}"
10
11
  end
11
12
 
12
- Given /^I time travel to (.+)$/ do |period|
13
- Delorean.time_travel_to(period)
14
- # puts "Time Travelled to #{Time.now.to_s}"
15
- end
13
+ # Given /^I time travel to (.+)$/ do |period|
14
+ # RedisDelorean.time_travel_to(period)
15
+ # # puts "Time Travelled to #{Time.now.to_s}"
16
+ # end
16
17
 
17
- Given /^I come back to the present$/ do
18
- Delorean.back_to_the_present
19
- # puts "Time Travelled to the present, #{Time.now.to_s}"
18
+ Given /^the timezone is (.*)$/ do |tz|
19
+ Time.zone = tz
20
+ Chronic.time_class = Time.zone
20
21
  end
21
22
 
22
- Given /^I time travel in (.+) to (.+)$/ do |zone_name, timestamp|
23
- zone = ::Time.find_zone!(zone_name)
24
- time = zone.parse timestamp
25
- Delorean.time_travel_to time
26
- # puts "Time Travelled to #{Time.now.to_s}"
23
+ Given /^the time is (.*)$/ do |time|
24
+ RedisDelorean.time_travel_to(Chronic.parse("#{time}"))
25
+ #puts "Time Travelled to #{Time.now.to_s}"
27
26
  end
28
27
 
29
- Then /^the time in UTC should be about (.+)$/ do |timestamp|
30
- actual = Time.now.in_time_zone('UTC')
31
- expected = Time.parse("#{timestamp} UTC")
32
- (expected..expected+5).cover?(actual).should be_true
33
- end
28
+ # Given /^I come back to the present$/ do
29
+ # RedisDelorean.back_to_the_present
30
+ # # puts "Time Travelled to the present, #{Time.now.to_s}"
31
+ # end
32
+
33
+ # Given /^I time travel in (.+) to (.+)$/ do |zone_name, timestamp|
34
+ # zone = ::Time.find_zone!(zone_name)
35
+ # time = zone.parse timestamp
36
+ # RedisDelorean.time_travel_to time
37
+ # # puts "Time Travelled to #{Time.now.to_s}"
38
+ # end
39
+
40
+ # Then /^the time in UTC should be about (.+)$/ do |timestamp|
41
+ # actual = Time.now.in_time_zone('UTC')
42
+ # expected = Time.parse("#{timestamp} UTC")
43
+ # (expected..expected+5).cover?(actual).should be_true
44
+ # end
34
45
 
@@ -1,4 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ require 'delorean'
4
+ require 'chronic'
5
+ require 'active_support/time'
6
+ require 'ice_cube'
7
+ require 'flapjack/data/entity_check'
8
+ require 'flapjack/data/event'
2
9
 
3
10
  if ENV['COVERAGE']
4
11
  require 'simplecov'
@@ -43,9 +50,66 @@ class MockEmailer
43
50
  include EM::Deferrable
44
51
  end
45
52
 
53
+ class RedisDelorean
54
+
55
+ ExpireAsIfAtScript = <<EXPIRE_AS_IF_AT
56
+ local keys = redis.call('keys', KEYS[1])
57
+ local current_time = tonumber(ARGV[1])
58
+ local expire_as_if_at = tonumber(ARGV[2])
59
+ local counter = 0
60
+
61
+ for i,k in ipairs(keys) do
62
+ local key_ttl = redis.call('ttl', k)
63
+
64
+ -- key does not have timeout if < 0
65
+ if ( (key_ttl >= 0) and ((current_time + key_ttl) <= expire_as_if_at) ) then
66
+ redis.call('del', k)
67
+ counter = counter + 1
68
+ end
69
+ end
70
+ return counter
71
+ EXPIRE_AS_IF_AT
72
+
73
+ def self.before_all(options = {})
74
+ redis = options[:redis]
75
+ @expire_as_if_at_sha = redis.script(:load, ExpireAsIfAtScript)
76
+ end
77
+
78
+ def self.before_each(options = {})
79
+ @redis = options[:redis]
80
+ end
81
+
82
+ def self.time_travel_to(dest_time)
83
+ # puts "travelling to #{Time.now.in_time_zone}, real time is #{Time.now_without_delorean.in_time_zone}"
84
+ old_maybe_fake_time = Time.now.in_time_zone
85
+
86
+ Delorean.time_travel_to(dest_time)
87
+ # puts "travelled to #{Time.now.in_time_zone}, real time is #{Time.now_without_delorean.in_time_zone}"
88
+ return if dest_time < old_maybe_fake_time
89
+
90
+ # dumps the first offset -- we're not interested in time difference from
91
+ # real, only with context to the fake frame of reference...
92
+ # This may mean all scenarios using this code should have an initial
93
+ # Given it is *datetime*
94
+ # step
95
+ offsets = Delorean.send(:time_travel_offsets).dup
96
+ offsets.shift
97
+ delta = -offsets.inject(0){ |sum, val| sum + val }.floor
98
+
99
+ real_time = Time.now_without_delorean.to_i
100
+ # puts "delta #{delta}, expire before real time #{Time.at(real_time + delta)}"
101
+
102
+ result = @redis.evalsha(@expire_as_if_at_sha, ['*'],
103
+ [real_time, real_time + delta])
104
+ # puts "Expired #{result} key#{(result == 1) ? '' : 's'}"
105
+ end
106
+
107
+ end
108
+
46
109
  redis_opts = { :db => 14, :driver => :ruby }
47
110
  redis = ::Redis.new(redis_opts)
48
111
  redis.flushdb
112
+ RedisDelorean.before_all(:redis => redis)
49
113
  redis.quit
50
114
 
51
115
  # NB: this seems to execute outside the Before/After hooks
@@ -63,7 +127,8 @@ Before do
63
127
  # Use a separate database whilst testing
64
128
  @app = Flapjack::Executive.new(:logger => @logger,
65
129
  :config => {'email_queue' => 'email_notifications',
66
- 'sms_queue' => 'sms_notifications'},
130
+ 'sms_queue' => 'sms_notifications',
131
+ 'default_contact_timezone' => 'America/New_York'},
67
132
  :redis_config => redis_opts)
68
133
  @redis = @app.instance_variable_get('@redis')
69
134
  end
@@ -77,6 +142,11 @@ end
77
142
 
78
143
  Before('@resque') do
79
144
  ResqueSpec.reset!
145
+ @queues = {:email => 'email_queue'}
146
+ end
147
+
148
+ Before('@time') do
149
+ RedisDelorean.before_each(:redis => @redis)
80
150
  end
81
151
 
82
152
  After('@time') do