flapjack 0.6.38 → 0.6.39

Sign up to get free protection for your applications and to get access to all the features.
@@ -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