flapjack 0.6.38 → 0.6.39

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.
@@ -4,12 +4,44 @@ require 'flapjack/data/contact'
4
4
 
5
5
  describe Flapjack::Data::Contact, :redis => true do
6
6
 
7
+ it "returns a list of all contacts" do
8
+ Flapjack::Data::Contact.add({'id' => '362',
9
+ 'first_name' => 'John',
10
+ 'last_name' => 'Johnson',
11
+ 'email' => 'johnj@example.com' },
12
+ :redis => @redis)
13
+ Flapjack::Data::Contact.add({'id' => '363',
14
+ 'first_name' => 'Jane',
15
+ 'last_name' => 'Janeley',
16
+ 'email' => 'janej@example.com'},
17
+ :redis => @redis)
18
+
19
+ contacts = Flapjack::Data::Contact.all(:redis => @redis)
20
+ contacts.should_not be_nil
21
+ contacts.should be_an(Array)
22
+ contacts.should have(2).contacts
23
+ contacts[0].id.should == '362'
24
+ contacts[1].id.should == '363'
25
+ end
26
+
27
+ it "finds a contact by id" do
28
+ Flapjack::Data::Contact.add({'id' => '362',
29
+ 'first_name' => 'John',
30
+ 'last_name' => 'Johnson',
31
+ 'email' => 'johnj@example.com' },
32
+ :redis => @redis)
33
+
34
+ contact = Flapjack::Data::Contact.find_by_id('362', :redis => @redis)
35
+ contact.should_not be_nil
36
+ contact.name.should == "John Johnson"
37
+ end
38
+
7
39
  it "finds all contacts for a check on an entity"
8
40
 
9
41
  it "deletes all contacts"
10
42
 
11
- it "adds a contact"
12
-
13
43
  it "returns pagerduty credentials for a contact"
14
44
 
45
+ it "returns a list of entities for a contact"
46
+
15
47
  end
@@ -6,10 +6,6 @@ describe Flapjack::Data::Entity, :redis => true do
6
6
  let(:name) { 'abc-123' }
7
7
  let(:check) { 'ping' }
8
8
 
9
- it "adds an entity, including contacts"
10
-
11
- it "finds an entity by name"
12
-
13
9
  it "creates an entity if allowed when it can't find it" do
14
10
  entity = Flapjack::Data::Entity.find_by_name(name, :redis => @redis, :create => true)
15
11
 
@@ -18,22 +14,40 @@ describe Flapjack::Data::Entity, :redis => true do
18
14
  @redis.get("entity_id:#{name}").should == ''
19
15
  end
20
16
 
21
- it "finds an entity by id"
17
+ it "finds an entity by id" do
18
+ Flapjack::Data::Entity.add({'id' => '5000',
19
+ 'name' => name},
20
+ :redis => @redis)
21
+
22
+ entity = Flapjack::Data::Entity.find_by_id('5000', :redis => @redis)
23
+ entity.should_not be_nil
24
+ entity.name.should == name
25
+ end
26
+
27
+ it "finds an entity by name" do
28
+ Flapjack::Data::Entity.add({'id' => '5000',
29
+ 'name' => name},
30
+ :redis => @redis)
31
+
32
+ entity = Flapjack::Data::Entity.find_by_name(name, :redis => @redis)
33
+ entity.should_not be_nil
34
+ entity.id.should == '5000'
35
+ end
22
36
 
23
37
  it "returns a list of all entities" do
24
- Flapjack::Data::Entity.add({'id' => '5000',
25
- 'name' => name},
38
+ Flapjack::Data::Entity.add({'id' => '5000',
39
+ 'name' => name},
26
40
  :redis => @redis)
27
- Flapjack::Data::Entity.add({'id' => '5001',
28
- 'name' => "z_" + name},
41
+ Flapjack::Data::Entity.add({'id' => '5001',
42
+ 'name' => "z_" + name},
29
43
  :redis => @redis)
30
44
 
31
45
  entities = Flapjack::Data::Entity.all(:redis => @redis)
32
46
  entities.should_not be_nil
33
47
  entities.should be_an(Array)
34
48
  entities.should have(2).entities
35
- entities[0].id.should == 5000
36
- entities[1].id.should == 5001
49
+ entities[0].id.should == '5000'
50
+ entities[1].id.should == '5001'
37
51
  end
38
52
 
39
53
  it "returns a list of checks for an entity" do
@@ -27,8 +27,7 @@ describe Flapjack::Jabber do
27
27
  fj.bootstrap(:config => config)
28
28
  fj.should_receive(:build_redis_connection_pool)
29
29
 
30
- EM.should_receive(:next_tick).exactly(4).times.and_yield
31
- EM.should_receive(:synchrony).exactly(4).times.and_yield
30
+ EventMachine::Synchrony.should_receive(:next_tick).exactly(4).times.and_yield
32
31
 
33
32
  fj.should_receive(:register_handler).with(:ready).and_yield(stanza)
34
33
  fj.should_receive(:on_ready).with(stanza)
@@ -149,7 +148,7 @@ describe Flapjack::Jabber do
149
148
  ["jabber_notifications", %q{{"notification_type":"shutdown"}}]
150
149
  )
151
150
 
152
- EM.should_receive(:next_tick).twice.and_yield
151
+ EventMachine::Synchrony.should_receive(:next_tick).twice.and_yield
153
152
  fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message))
154
153
  fj.should_receive(:close)
155
154
 
@@ -0,0 +1,140 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/oobetet'
3
+
4
+ describe Flapjack::Oobetet do
5
+
6
+ let(:config) { {'server' => 'example.com',
7
+ 'port' => '5222',
8
+ 'jabberid' => 'flapjack@example.com',
9
+ 'password' => 'password',
10
+ 'alias' => 'flapjack',
11
+ 'watched_check' => 'PING',
12
+ 'watched_entity' => 'foo.bar.net',
13
+ 'rooms' => ['flapjacktest@conference.example.com']
14
+ }
15
+ }
16
+
17
+ let(:stanza) { mock('stanza') }
18
+
19
+ it "raises an error if a required config setting is not set" do
20
+ Socket.should_receive(:gethostname).and_return('thismachine')
21
+
22
+ fo = Flapjack::Oobetet.new
23
+ fo.bootstrap(:config => config.delete('watched_check'))
24
+
25
+ lambda {
26
+ fo.setup
27
+ }.should raise_error
28
+ end
29
+
30
+ it "hooks up event handlers to the appropriate methods" do
31
+ fo = Flapjack::Oobetet.new
32
+ fo.bootstrap(:config => config)
33
+
34
+ EventMachine::Synchrony.should_receive(:next_tick).exactly(3).times.and_yield
35
+
36
+ fo.should_receive(:register_handler).with(:ready).and_yield(stanza)
37
+ fo.should_receive(:on_ready).with(stanza)
38
+
39
+ fo.should_receive(:register_handler).with(:message, :groupchat?).and_yield(stanza)
40
+ fo.should_receive(:on_groupchat).with(stanza)
41
+
42
+ fo.should_receive(:register_handler).with(:disconnected).and_yield(stanza)
43
+ fo.should_receive(:on_disconnect).with(stanza).and_return(true)
44
+
45
+ fo.register_handlers
46
+ end
47
+
48
+ it "joins a chat room after connecting" do
49
+ fo = Flapjack::Oobetet.new
50
+ fo.bootstrap(:config => config)
51
+
52
+ fo.should_receive(:write).with(an_instance_of(Blather::Stanza::Presence))
53
+ fo.should_receive(:write).with(an_instance_of(Blather::Stanza::Message))
54
+
55
+ fo.on_ready(stanza)
56
+ end
57
+
58
+ it "reconnects when disconnected (if not quitting)" do
59
+ fo = Flapjack::Oobetet.new
60
+ fo.bootstrap(:config => config)
61
+
62
+ EventMachine::Timer.should_receive(:new).with(1).and_yield
63
+ fo.should_receive(:connect)
64
+
65
+ ret = fo.on_disconnect(stanza)
66
+ ret.should be_true
67
+ end
68
+
69
+ it "records times of a problem status messages" do
70
+ fo = Flapjack::Oobetet.new
71
+ fo.bootstrap(:config => config)
72
+
73
+ fo.setup
74
+
75
+ t = Time.now
76
+
77
+ stanza.should_receive(:body).and_return( %q{PROBLEM: "PING" on foo.bar.net} )
78
+ Time.should_receive(:now).and_return(t)
79
+
80
+ fo.on_groupchat(stanza)
81
+ fo_times = fo.instance_variable_get('@times')
82
+ fo_times.should_not be_nil
83
+ fo_times.should have_key(:last_problem)
84
+ fo_times[:last_problem].should == t.to_i
85
+ end
86
+
87
+ it "records times of a recovery status messages" do
88
+ fo = Flapjack::Oobetet.new
89
+ fo.bootstrap(:config => config)
90
+
91
+ fo.setup
92
+
93
+ t = Time.now
94
+
95
+ stanza.should_receive(:body).and_return( %q{RECOVERY: "PING" on foo.bar.net} )
96
+ Time.should_receive(:now).and_return(t)
97
+
98
+ fo.on_groupchat(stanza)
99
+ fo_times = fo.instance_variable_get('@times')
100
+ fo_times.should_not be_nil
101
+ fo_times.should have_key(:last_recovery)
102
+ fo_times[:last_recovery].should == t.to_i
103
+ end
104
+
105
+ it "records times of an acknowledgement status messages" do
106
+ fo = Flapjack::Oobetet.new
107
+ fo.bootstrap(:config => config)
108
+
109
+ fo.setup
110
+
111
+ t = Time.now
112
+
113
+ stanza.should_receive(:body).and_return( %q{ACKNOWLEDGEMENT: "PING" on foo.bar.net} )
114
+ Time.should_receive(:now).and_return(t)
115
+
116
+ fo.on_groupchat(stanza)
117
+ fo_times = fo.instance_variable_get('@times')
118
+ fo_times.should_not be_nil
119
+ fo_times.should have_key(:last_ack)
120
+ fo_times[:last_ack].should == t.to_i
121
+ end
122
+
123
+ it "runs a loop checking for recorded problems" do
124
+ timer = mock('timer')
125
+ timer.should_receive(:cancel)
126
+ EM::Synchrony.should_receive(:add_periodic_timer).with(60).and_return(timer)
127
+
128
+ fo = Flapjack::Oobetet.new
129
+ fo.bootstrap(:config => config)
130
+ fo.should_receive(:register_handler).exactly(3).times
131
+
132
+ fo.should_receive(:connect)
133
+ fo.should_receive(:should_quit?).twice.and_return(false, true)
134
+
135
+ EM::Synchrony.should_receive(:sleep).with(10)
136
+
137
+ fo.main
138
+ end
139
+
140
+ end
@@ -0,0 +1,177 @@
1
+ require 'spec_helper'
2
+
3
+ require 'yajl/json_gem'
4
+
5
+ require 'flapjack/pagerduty'
6
+
7
+ describe Flapjack::Pagerduty, :redis => true do
8
+
9
+ let(:config) { {'queue' => 'pagerduty_notifications'} }
10
+
11
+ let(:time) { Time.new }
12
+
13
+ it "prompts the blocking redis connection to quit" do
14
+ redis = mock('redis')
15
+ redis.should_receive(:rpush).with(nil, %q{{"notification_type":"shutdown"}})
16
+
17
+ pagerduty = Flapjack::Pagerduty.new
18
+ pagerduty.bootstrap
19
+ pagerduty.add_shutdown_event(:redis => redis)
20
+ end
21
+
22
+ it "doesn't look for acknowledgements if this search is already running" do
23
+ @redis.set(Flapjack::Pagerduty::SEM_PAGERDUTY_ACKS_RUNNING, 'true')
24
+
25
+ fp = Flapjack::Pagerduty.new
26
+ fp.bootstrap(:config => config)
27
+ fp.instance_variable_set("@redis_timer", @redis)
28
+
29
+ fp.should_not_receive(:find_pagerduty_acknowledgements)
30
+ fp.find_pagerduty_acknowledgements_if_safe
31
+ end
32
+
33
+ it "looks for acknowledgements if the search is not already running" do
34
+ fp = Flapjack::Pagerduty.new
35
+ fp.bootstrap(:config => config)
36
+ fp.instance_variable_set("@redis_timer", @redis)
37
+
38
+ fp.should_receive(:find_pagerduty_acknowledgements)
39
+ fp.find_pagerduty_acknowledgements_if_safe
40
+ end
41
+
42
+ # Testing the private PagerDuty methods separately, it's simpler. May be
43
+ # an argument for splitting some of them to another module, accessed by this
44
+ # class, in which case it makes more sense for the methods to be public.
45
+
46
+ # NB: needs to run in synchrony block to catch the evented HTTP requests
47
+ it "looks for acknowledgements via the PagerDuty API" do
48
+ EM.synchrony do
49
+ fp = Flapjack::Pagerduty.new
50
+ fp.bootstrap(:config => config)
51
+
52
+ check = 'PING'
53
+ Time.should_receive(:now).and_return(time)
54
+ since = (time.utc - (60*60*24*7)).iso8601 # the last week
55
+ unt = (time.utc + (60*60*24)).iso8601 # 1 day in the future
56
+
57
+ response = {"incidents" =>
58
+ [{"incident_number" => 12,
59
+ "status" => "acknowledged",
60
+ "last_status_change_by" => {"id"=>"ABCDEFG", "name"=>"John Smith",
61
+ "email"=>"johns@example.com",
62
+ "html_url"=>"http://flpjck.pagerduty.com/users/ABCDEFG"}
63
+ }
64
+ ],
65
+ "limit"=>100,
66
+ "offset"=>0,
67
+ "total"=>1}
68
+
69
+ stub_request(:get, "https://flpjck.pagerduty.com/api/v1/incidents?" +
70
+ "fields=incident_number,status,last_status_change_by&incident_key=#{check}&" +
71
+ "since=#{since}&status=acknowledged&until=#{unt}").
72
+ with(:headers => {'Authorization'=>['flapjack', 'password123']}).
73
+ to_return(:status => 200, :body => response.to_json, :headers => {})
74
+
75
+ result = fp.send(:pagerduty_acknowledged?, 'subdomain' => 'flpjck', 'username' => 'flapjack',
76
+ 'password' => 'password123', 'check' => check)
77
+
78
+ result.should be_a(Hash)
79
+ result.should have_key(:pg_acknowledged_by)
80
+ result[:pg_acknowledged_by].should be_a(Hash)
81
+ result[:pg_acknowledged_by].should have_key('id')
82
+ result[:pg_acknowledged_by]['id'].should == 'ABCDEFG'
83
+ EM.stop
84
+ end
85
+ end
86
+
87
+ it "creates acknowledgements when pagerduty acknowledgements are found" do
88
+ fp = Flapjack::Pagerduty.new
89
+ fp.bootstrap(:config => config)
90
+
91
+ entity_check = mock('entity_check')
92
+ entity_check.should_receive(:check).and_return('PING')
93
+ entity_check.should_receive(:pagerduty_credentials).and_return([{
94
+ 'service_key' => '12345678',
95
+ 'subdomain"' => 'flpjck',
96
+ 'username' => 'flapjack',
97
+ 'password' => 'password123'
98
+ }])
99
+ entity_check.should_receive(:create_acknowledgement).with('summary' => 'Acknowledged on PagerDuty')
100
+
101
+ Flapjack::Data::Global.should_receive(:unacknowledged_failing_checks).and_return([entity_check])
102
+
103
+ fp.should_receive(:pagerduty_acknowledged?).and_return({})
104
+
105
+ fp.send(:find_pagerduty_acknowledgements)
106
+ end
107
+
108
+ it "runs a blocking loop listening for notifications" do
109
+ timer = mock('timer')
110
+ timer.should_receive(:cancel)
111
+ EM::Synchrony.should_receive(:add_periodic_timer).with(10).and_return(timer)
112
+
113
+ redis = mock('redis')
114
+ redis.should_receive(:del).with('sem_pagerduty_acks_running')
115
+ redis.should_receive(:empty!)
116
+
117
+ fp = Flapjack::Pagerduty.new
118
+ fp.bootstrap(:config => config)
119
+ fp.should_receive(:build_redis_connection_pool).and_return(redis)
120
+
121
+ fp.should_receive(:should_quit?).exactly(3).times.and_return(false, false, true)
122
+ redis.should_receive(:blpop).twice.and_return(
123
+ ["pagerduty_notifications", %q{{"notification_type":"problem","event_id":"main-example.com:ping","state":"critical","summary":"!!!"}}],
124
+ ["pagerduty_notifications", %q{{"notification_type":"shutdown"}}]
125
+ )
126
+
127
+ fp.should_receive(:test_pagerduty_connection).and_return(true)
128
+ fp.should_receive(:send_pagerduty_event)
129
+
130
+ fp.main
131
+ end
132
+
133
+ it "tests the pagerduty connection" do
134
+ EM.synchrony do
135
+
136
+ evt = { "service_key" => "11111111111111111111111111111111",
137
+ "incident_key" => "Flapjack is running a NOOP",
138
+ "event_type" => "nop",
139
+ "description" => "I love APIs with noops." }
140
+
141
+ body = evt.to_json
142
+ stub_request(:post, "https://events.pagerduty.com/generic/2010-04-15/create_event.json").
143
+ with(:body => body).to_return(:status => 200, :body => '{"status":"success"}', :headers => {})
144
+
145
+ fp = Flapjack::Pagerduty.new
146
+ fp.bootstrap(:config => config)
147
+
148
+ ret = fp.send(:test_pagerduty_connection)
149
+ ret.should be_true
150
+
151
+ EM.stop
152
+ end
153
+ end
154
+
155
+ it "sends an event to pagerduty" do
156
+ EM.synchrony do
157
+
158
+ evt = {"service_key" => "abcdefg",
159
+ "incident_key" => "Flapjack test",
160
+ "event_type" => "nop",
161
+ "description" => "Not really sent anyway"}
162
+ body = evt.to_json
163
+ stub_request(:post, "https://events.pagerduty.com/generic/2010-04-15/create_event.json").
164
+ with(:body => body).to_return(:status => 200, :body => "", :headers => {})
165
+
166
+ fp = Flapjack::Pagerduty.new
167
+ fp.bootstrap(:config => config)
168
+
169
+ ret = fp.send(:send_pagerduty_event, evt)
170
+ ret.should_not be_nil
171
+ ret.should == [200, nil]
172
+
173
+ EM.stop
174
+ end
175
+ end
176
+
177
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require 'flapjack/redis_pool'
3
+
4
+ describe Flapjack::RedisPool do
5
+
6
+ it "is initialized, and emptied" do
7
+ EM.synchrony do
8
+ redis_count = 3
9
+
10
+ redis_conns = redis_count.times.collect {
11
+ redis = mock('redis')
12
+ redis.should_receive(:quit)
13
+ redis
14
+ }
15
+ ::Redis.should_receive(:new).exactly(redis_count).times.and_return(*redis_conns)
16
+
17
+ frp = Flapjack::RedisPool.new(:size => redis_count)
18
+ frp.empty!
19
+
20
+ EM.stop
21
+ end
22
+ end
23
+
24
+ end