build_status_server 0.8 → 0.9
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.
- data/Gemfile +2 -1
- data/Gemfile.lock +5 -1
- data/build_status_server.gemspec +1 -1
- data/config/config-example.yml +1 -0
- data/lib/build_status_server.html +118 -0
- data/lib/build_status_server/config.html +157 -0
- data/lib/build_status_server/config.rb +4 -0
- data/lib/build_status_server/server.html +202 -0
- data/lib/build_status_server/server.rb +52 -53
- data/lib/build_status_server/version.html +32 -0
- data/lib/build_status_server/version.rb +1 -1
- data/spec/lib/build_status_server/config_spec.rb +7 -7
- data/spec/lib/build_status_server/server_spec.rb +288 -11
- metadata +8 -7
- data/lib/build_status_server.rb~ +0 -10
- data/lib/build_status_server/server.rb~ +0 -162
- data/lib/build_status_server/version.rb~ +0 -3
@@ -1,9 +1,6 @@
|
|
1
|
-
# TODO
|
2
|
-
# move all configuration stuff to Config
|
3
|
-
# and just call config[:blaj] instead of if blah
|
4
1
|
module BuildStatusServer
|
5
2
|
class Server
|
6
|
-
attr_reader :config, :store
|
3
|
+
attr_reader :config, :store, :udp_server
|
7
4
|
|
8
5
|
def initialize(options = {})
|
9
6
|
@config = Config.new
|
@@ -11,30 +8,11 @@ module BuildStatusServer
|
|
11
8
|
end
|
12
9
|
|
13
10
|
def listen
|
14
|
-
|
15
|
-
udp_server = config.udp_server
|
16
|
-
|
17
|
-
begin
|
18
|
-
sock.bind(udp_server["address"], udp_server["port"])
|
19
|
-
rescue Errno::EADDRINUSE
|
20
|
-
STDERR.puts <<-EOT
|
21
|
-
There appears that another instance is running, or another process
|
22
|
-
is listening at the same port (#{udp_server["address"]}:#{udp_server["port"]}
|
23
|
-
|
24
|
-
EOT
|
25
|
-
exit
|
26
|
-
end
|
27
|
-
|
28
|
-
puts "Listening on UDP #{udp_server["address"]}:#{udp_server["port"]}" if config.verbose
|
11
|
+
setup_udp_server
|
29
12
|
|
30
13
|
begin
|
31
14
|
while true
|
32
|
-
|
33
|
-
|
34
|
-
if process_job(data)
|
35
|
-
status = process_all_statuses
|
36
|
-
notify(status)
|
37
|
-
end
|
15
|
+
process_loop
|
38
16
|
end
|
39
17
|
rescue Interrupt
|
40
18
|
puts "Good bye."
|
@@ -45,6 +23,39 @@ is listening at the same port (#{udp_server["address"]}:#{udp_server["port"]}
|
|
45
23
|
|
46
24
|
private
|
47
25
|
|
26
|
+
def process_loop
|
27
|
+
data, addr = udp_server.recvfrom(2048)
|
28
|
+
|
29
|
+
if process_job(data)
|
30
|
+
status = process_all_statuses
|
31
|
+
notify(status)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def setup_udp_server
|
36
|
+
address, port = config.udp_server["address"], config.udp_server["port"]
|
37
|
+
@udp_server = UDPSocket.new
|
38
|
+
|
39
|
+
begin
|
40
|
+
udp_server.bind(address, port)
|
41
|
+
rescue Errno::EADDRINUSE
|
42
|
+
STDERR.puts <<-EOT
|
43
|
+
There appears that another instance is running, or another process
|
44
|
+
is listening on the same port (#{address}:#{port})
|
45
|
+
|
46
|
+
EOT
|
47
|
+
exit
|
48
|
+
rescue Errno::EADDRNOTAVAIL
|
49
|
+
STDERR.puts <<-EOT
|
50
|
+
The address configured is not available (#{address})
|
51
|
+
|
52
|
+
EOT
|
53
|
+
exit
|
54
|
+
end
|
55
|
+
|
56
|
+
STDOUT.puts "Listening on UDP #{address}:#{port}" if config.verbose
|
57
|
+
end
|
58
|
+
|
48
59
|
def load_store
|
49
60
|
@store = begin
|
50
61
|
YAML.load_file(config.store_file)
|
@@ -75,7 +86,8 @@ is listening at the same port (#{udp_server["address"]}:#{udp_server["port"]}
|
|
75
86
|
status = job["build"]["status"]
|
76
87
|
|
77
88
|
if phase == "FINISHED"
|
78
|
-
|
89
|
+
# Got SUCCESS for topic_action_master on Tue May 01 12:02:31 -0400 2012 []
|
90
|
+
STDOUT.puts "Got #{status} for #{build_name} on #{Time.now} [#{job_internals(job)}]" if config.verbose
|
79
91
|
case status
|
80
92
|
when "SUCCESS", "FAILURE"
|
81
93
|
load_store
|
@@ -84,12 +96,18 @@ is listening at the same port (#{udp_server["address"]}:#{udp_server["port"]}
|
|
84
96
|
return true
|
85
97
|
end
|
86
98
|
else
|
87
|
-
|
99
|
+
# Started for topic_action_master on Tue May 01 12:00:30 -0400 2012 [{"name"=>"topic_action_master", "url"=>"job/topic_action_master/", "build"=>{"number"=>98, "url"=>"job/topic_action_master/98/", "phase"= >"STARTED", "full_url"=>"http://ci.berman.challengepost.com/job/topic_action_master/98/"}}]
|
100
|
+
# Started for topic_action_master on Tue May 01 12:02:31 -0400 2012 [{"name"=>"topic_action_master", "url"=>"job/topic_action_master/", "build"=>{"number"=>98, "url"=>"job/topic_action_master/98/", "status" =>"SUCCESS", "phase"=>"COMPLETED", "full_url"=>"http://ci.berman.challengepost.com/job/topic_action_master/98/"}}]
|
101
|
+
STDOUT.puts "Started for #{build_name} on #{Time.now} [#{job_internals(job)}]" if config.verbose
|
88
102
|
end
|
89
103
|
|
90
104
|
return false
|
91
105
|
end
|
92
106
|
|
107
|
+
def job_internals(job)
|
108
|
+
"build=>#{job["build"]["number"]}, status=>#{job["build"]["status"]}"
|
109
|
+
end
|
110
|
+
|
93
111
|
def should_process_build(build_name)
|
94
112
|
# If mask exists, then ...
|
95
113
|
! (
|
@@ -103,7 +121,7 @@ is listening at the same port (#{udp_server["address"]}:#{udp_server["port"]}
|
|
103
121
|
def process_all_statuses
|
104
122
|
pass = true
|
105
123
|
|
106
|
-
|
124
|
+
store.values.each do |val|
|
107
125
|
pass &&= (val == "pass" || val == "SUCCESS")
|
108
126
|
end
|
109
127
|
|
@@ -112,10 +130,12 @@ is listening at the same port (#{udp_server["address"]}:#{udp_server["port"]}
|
|
112
130
|
|
113
131
|
def notify(status)
|
114
132
|
tcp_client = config.tcp_client
|
133
|
+
tcp_client["attempts"] ||= 2
|
115
134
|
|
116
135
|
attempts = 0
|
117
136
|
light = status ? tcp_client["pass"] : tcp_client["fail"]
|
118
137
|
|
138
|
+
client = nil
|
119
139
|
begin
|
120
140
|
timeout(5) do
|
121
141
|
attempts += 1
|
@@ -123,39 +143,18 @@ is listening at the same port (#{udp_server["address"]}:#{udp_server["port"]}
|
|
123
143
|
client.print "GET #{light} HTTP/1.0\n\n"
|
124
144
|
answer = client.gets(nil)
|
125
145
|
STDOUT.puts answer if config.verbose
|
126
|
-
client.close
|
127
146
|
end
|
128
147
|
rescue Timeout::Error => ex
|
129
148
|
STDERR.puts "Error: #{ex} while trying to send #{light}"
|
130
|
-
retry unless attempts >
|
149
|
+
retry unless attempts > tcp_client["attempts"]
|
131
150
|
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH => ex
|
132
151
|
STDERR.puts "Error: #{ex} while trying to send #{light}"
|
133
152
|
STDERR.puts "Will wait for 2 seconds and try again..."
|
134
153
|
sleep 2
|
135
|
-
retry unless attempts >
|
154
|
+
retry unless attempts > tcp_client["attempts"]
|
155
|
+
ensure
|
156
|
+
client.close if client
|
136
157
|
end
|
137
158
|
end
|
138
159
|
end
|
139
160
|
end
|
140
|
-
|
141
|
-
__END__
|
142
|
-
|
143
|
-
Example payload:
|
144
|
-
{
|
145
|
-
"name":"test",
|
146
|
-
"url":"job/test/",
|
147
|
-
"build":{
|
148
|
-
"full_url":"http://cronus.local:3001/job/test/20/",
|
149
|
-
"number":20,
|
150
|
-
"phase":"FINISHED",
|
151
|
-
"status":"SUCCESS",
|
152
|
-
"url":"job/test/20/"
|
153
|
-
}
|
154
|
-
}
|
155
|
-
|
156
|
-
We're getting this error once in a while:
|
157
|
-
/usr/local/lib/ruby/1.8/timeout.rb:64:in `notify': execution expired (Timeout::Error)
|
158
|
-
from /home/jcmuller/build_notifier/lib/server.rb:102:in `notify'
|
159
|
-
from /home/jcmuller/build_notifier/lib/server.rb:33:in `listen'
|
160
|
-
from bin/server:5
|
161
|
-
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="content-type" content="text/html;charset=utf-8">
|
5
|
+
<title>version.rb</title>
|
6
|
+
<link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<div id='container'>
|
10
|
+
<div id="background"></div>
|
11
|
+
<div id="jump_to">
|
12
|
+
Jump To …
|
13
|
+
<div id="jump_wrapper">
|
14
|
+
<div id="jump_page">
|
15
|
+
<a class="source" href="../build_status_server.html">build_status_server.rb</a>
|
16
|
+
<a class="source" href="config.html">config.rb</a>
|
17
|
+
<a class="source" href="server.html">server.rb</a>
|
18
|
+
<a class="source" href="version.html">version.rb</a>
|
19
|
+
</div>
|
20
|
+
</div>
|
21
|
+
</div>
|
22
|
+
<table cellspacing=0 cellpadding=0>
|
23
|
+
<thead>
|
24
|
+
<tr>
|
25
|
+
<th class=docs><h1>version.rb</h1></th>
|
26
|
+
<th class=code></th>
|
27
|
+
</tr>
|
28
|
+
</thead>
|
29
|
+
<tbody>
|
30
|
+
</table>
|
31
|
+
</div>
|
32
|
+
</body>
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "spec_helper"
|
2
|
+
require "build_status_server"
|
3
|
+
require "tempfile"
|
4
4
|
|
5
5
|
describe BuildStatusServer::Config do
|
6
6
|
let(:config) { BuildStatusServer::Config.new }
|
@@ -15,7 +15,7 @@ describe BuildStatusServer::Config do
|
|
15
15
|
it "should set the config values from yaml file" do
|
16
16
|
config.should_receive(:load_config_file).and_return(YAML.load(config.send(:get_example_config)))
|
17
17
|
config.load
|
18
|
-
config.udp_server.should == {
|
18
|
+
config.udp_server.should == {"address" => "127.0.0.1", "port" => 1234}
|
19
19
|
config.verbose.should == false
|
20
20
|
end
|
21
21
|
end
|
@@ -24,7 +24,7 @@ describe BuildStatusServer::Config do
|
|
24
24
|
it "should load the yaml file passed in as a file argument" do
|
25
25
|
file_name = nil
|
26
26
|
|
27
|
-
Tempfile.open(
|
27
|
+
Tempfile.open(["config", ".yml"]) do |f|
|
28
28
|
f.puts "---"
|
29
29
|
f.puts "key: value"
|
30
30
|
f.puts "key2: value2"
|
@@ -39,7 +39,7 @@ describe BuildStatusServer::Config do
|
|
39
39
|
|
40
40
|
it "should try to load paths from the locations to try" do
|
41
41
|
file_name = nil
|
42
|
-
Tempfile.open("config") do |f|
|
42
|
+
Tempfile.open(["config", ".yml"]) do |f|
|
43
43
|
f.puts "---"
|
44
44
|
f.puts "key: value"
|
45
45
|
f.puts "key2: value2"
|
@@ -60,7 +60,7 @@ describe BuildStatusServer::Config do
|
|
60
60
|
|
61
61
|
it "should throw an exception if the config file isn't a hash" do
|
62
62
|
file_name = nil
|
63
|
-
Tempfile.open(
|
63
|
+
Tempfile.open(["base", ".yml"]) do |f|
|
64
64
|
f.puts "YADDA YADDA"
|
65
65
|
file_name = f.path
|
66
66
|
end
|
@@ -5,12 +5,101 @@ describe BuildStatusServer::Server do
|
|
5
5
|
let(:server) { BuildStatusServer::Server.new }
|
6
6
|
|
7
7
|
before do
|
8
|
-
STDERR.should_receive
|
8
|
+
STDERR.should_receive(:puts)
|
9
9
|
end
|
10
10
|
|
11
11
|
describe "#listen"
|
12
12
|
|
13
13
|
context "private methods" do
|
14
|
+
|
15
|
+
describe "#setup_udp_server" do
|
16
|
+
it "reads the udp_server options from configuration file" do
|
17
|
+
server.config.stub!(:udp_server).and_return({"address" => "address", "port" => "port"})
|
18
|
+
socket = mock(:udp_socket)
|
19
|
+
socket.should_receive(:bind).with("address", "port")
|
20
|
+
UDPSocket.should_receive(:new).and_return(socket)
|
21
|
+
|
22
|
+
server.send(:setup_udp_server)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "instantiates a UDPSocket object and binds it to address and port" do
|
26
|
+
server.config.stub!(:udp_server).and_return({"address" => "127.0.0.1", "port" => "9999"})
|
27
|
+
|
28
|
+
server.send(:setup_udp_server)
|
29
|
+
|
30
|
+
client = UDPSocket.new
|
31
|
+
client.connect("127.0.0.1", 9999)
|
32
|
+
client.send "hello, world!", 0
|
33
|
+
msg = server.udp_server.recvfrom(13)
|
34
|
+
|
35
|
+
msg[0].should == "hello, world!"
|
36
|
+
["AF_INET", "127.0.0.1"].each do |e|
|
37
|
+
msg[1].should include e
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should show message and exit when connecting to address not available" do
|
42
|
+
server.config.stub!(:udp_server).and_return({"address" => "192.192.192.192", "port" => "9999"})
|
43
|
+
|
44
|
+
STDERR.should_receive(:puts).with("The address configured is not available (192.192.192.192)\n\n")
|
45
|
+
server.should_receive(:exit)
|
46
|
+
|
47
|
+
server.send(:setup_udp_server)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "it recovers from an address in use exception" do
|
51
|
+
server.config.stub!(:udp_server).and_return({"address" => "127.0.0.1", "port" => "9999"})
|
52
|
+
|
53
|
+
socket = mock(:udp_socket)
|
54
|
+
socket.should_receive(:bind).and_raise(Errno::EADDRINUSE)
|
55
|
+
UDPSocket.should_receive(:new).and_return(socket)
|
56
|
+
|
57
|
+
STDERR.should_receive(:puts).with("There appears that another instance is running, or another process\nis listening on the same port (127.0.0.1:9999)\n\n")
|
58
|
+
server.should_receive(:exit)
|
59
|
+
server.send(:setup_udp_server)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "if verbose is enabled, show message" do
|
63
|
+
server.config.stub!(:udp_server).and_return({"address" => "address", "port" => "port"})
|
64
|
+
socket = mock(:udp_socket)
|
65
|
+
socket.should_receive(:bind).with("address", "port")
|
66
|
+
UDPSocket.should_receive(:new).and_return(socket)
|
67
|
+
|
68
|
+
server.config.stub!(:verbose).and_return(true)
|
69
|
+
STDOUT.should_receive(:puts).with("Listening on UDP address:port")
|
70
|
+
|
71
|
+
server.send(:setup_udp_server)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#process_loop" do
|
76
|
+
it "should process all statuses and notify when process job returns true" do
|
77
|
+
socket = mock(:udp_socket)
|
78
|
+
socket.stub!(:recvfrom).and_return("data", "addr")
|
79
|
+
|
80
|
+
server.should_receive(:udp_server).and_return(socket)
|
81
|
+
server.should_receive(:process_job).with("data").and_return(true)
|
82
|
+
|
83
|
+
server.should_receive(:process_all_statuses).and_return("status")
|
84
|
+
server.should_receive(:notify).with("status")
|
85
|
+
|
86
|
+
server.send(:process_loop)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should not process all statuses or notify when process job returns false" do
|
90
|
+
socket = mock(:udp_socket)
|
91
|
+
socket.stub!(:recvfrom).and_return("data", "addr")
|
92
|
+
|
93
|
+
server.should_receive(:udp_server).and_return(socket)
|
94
|
+
server.should_receive(:process_job).with("data").and_return(false)
|
95
|
+
|
96
|
+
server.should_not_receive(:process_all_statuses)
|
97
|
+
server.should_not_receive(:notify)
|
98
|
+
|
99
|
+
server.send(:process_loop)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
14
103
|
describe "#load_store" do
|
15
104
|
before do
|
16
105
|
server.config.stub!(:store_file).and_return("/tmp/build")
|
@@ -38,19 +127,12 @@ describe BuildStatusServer::Server do
|
|
38
127
|
end
|
39
128
|
end
|
40
129
|
|
41
|
-
describe "#notify"
|
42
|
-
describe "#process_all_statuses"
|
43
|
-
describe "#process_job"
|
44
|
-
|
45
130
|
describe "#should_process_build" do
|
46
131
|
context "when mask exists" do
|
47
|
-
before do
|
48
|
-
server.stub!(:mask).and_return(%r{.*(?:master).*})
|
49
|
-
end
|
50
132
|
|
51
133
|
context "when policy is include" do
|
52
134
|
before do
|
53
|
-
server.stub!(:
|
135
|
+
server.config.stub!(:mask).and_return({"policy" => "include", "regex" => %r{.*(?:master).*}})
|
54
136
|
end
|
55
137
|
|
56
138
|
it "ignores builds if mask doesn't match build name" do
|
@@ -64,7 +146,7 @@ describe BuildStatusServer::Server do
|
|
64
146
|
|
65
147
|
context "when policy is exclude" do
|
66
148
|
before do
|
67
|
-
server.config.stub!(:mask).and_return({"policy" => "exclude", "regex" =>
|
149
|
+
server.config.stub!(:mask).and_return({"policy" => "exclude", "regex" => %r{.*(?:master).*}})
|
68
150
|
end
|
69
151
|
|
70
152
|
it "ignores builds if mask matches build name" do
|
@@ -105,7 +187,7 @@ describe BuildStatusServer::Server do
|
|
105
187
|
end
|
106
188
|
end
|
107
189
|
|
108
|
-
context "when mask doesn't" do
|
190
|
+
context "when mask regex doesn't" do
|
109
191
|
before do
|
110
192
|
server.config.stub!(:mask).and_return({"policy" => "include", "regex" => nil})
|
111
193
|
end
|
@@ -115,6 +197,201 @@ describe BuildStatusServer::Server do
|
|
115
197
|
end
|
116
198
|
end
|
117
199
|
end
|
200
|
+
|
201
|
+
describe "#process_job" do
|
202
|
+
it "returns false if should_process_build returns false" do
|
203
|
+
server.should_receive(:should_process_build).and_return(false)
|
204
|
+
server.send(:process_job).should be_false
|
205
|
+
end
|
206
|
+
|
207
|
+
it "returns false and says so on stderr if payload doesn't have a hash for build" do
|
208
|
+
server.should_receive(:should_process_build).and_return(true)
|
209
|
+
JSON.should_receive(:parse).and_return({"build" => "Not a hash!"})
|
210
|
+
STDERR.should_receive(:puts).with("Pinged with an invalid payload")
|
211
|
+
server.send(:process_job).should be_false
|
212
|
+
end
|
213
|
+
|
214
|
+
it "returns false and says that the we got the job started when phase is FINISHED but status isn't success nor failure" do
|
215
|
+
server.config.should_receive(:verbose).and_return(true)
|
216
|
+
server.should_receive(:should_process_build).and_return(true)
|
217
|
+
JSON.should_receive(:parse).with("{}").and_return({
|
218
|
+
"name" => "name",
|
219
|
+
"build" => { "phase" => "FINISHED", "status" => "some status", "number" => "number" }
|
220
|
+
})
|
221
|
+
Time.should_receive(:now).and_return("this is the time")
|
222
|
+
STDOUT.should_receive(:puts).with('Got some status for name on this is the time [build=>number, status=>some status]')
|
223
|
+
server.send(:process_job).should be_false
|
224
|
+
end
|
225
|
+
|
226
|
+
it "returns false and says that the job started when the phase isn't finished" do
|
227
|
+
server.config.should_receive(:verbose).and_return(true)
|
228
|
+
server.should_receive(:should_process_build).and_return(true)
|
229
|
+
JSON.should_receive(:parse).with("{}").and_return({
|
230
|
+
"name" => "name",
|
231
|
+
"build" => { "phase" => "STARTED", "status" => "some status", "number" => "number" }
|
232
|
+
})
|
233
|
+
Time.should_receive(:now).and_return("this is the time")
|
234
|
+
STDOUT.should_receive(:puts).with("Started for name on this is the time [build=>number, status=>some status]")
|
235
|
+
server.send(:process_job).should be_false
|
236
|
+
end
|
237
|
+
|
238
|
+
context "phase is FINISHED and status is either SUCCESS or FAILURE" do
|
239
|
+
before do
|
240
|
+
server.config.should_receive(:verbose).and_return(true)
|
241
|
+
server.should_receive(:should_process_build).and_return(true)
|
242
|
+
Time.should_receive(:now).and_return("this is the time")
|
243
|
+
YAML.should_receive(:load_file).and_return({})
|
244
|
+
File.should_receive(:open)
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should return true and write yaml file when phase is FINISHED and status is SUCCESS" do
|
248
|
+
JSON.should_receive(:parse).with("{}").and_return({
|
249
|
+
"name" => "name",
|
250
|
+
"build" => { "phase" => "FINISHED", "status" => "SUCCESS", "number" => "number" }
|
251
|
+
})
|
252
|
+
STDOUT.should_receive(:puts).with("Got SUCCESS for name on this is the time [build=>number, status=>SUCCESS]")
|
253
|
+
|
254
|
+
server.send(:process_job).should be_true
|
255
|
+
end
|
256
|
+
|
257
|
+
it "should return true and write yaml file when phase is FINISHED and status is FAILURE" do
|
258
|
+
JSON.should_receive(:parse).with("{}").and_return({
|
259
|
+
"name" => "name",
|
260
|
+
"build" => { "phase" => "FINISHED", "status" => "FAILURE", "number" => "number" }
|
261
|
+
})
|
262
|
+
STDOUT.should_receive(:puts).with("Got FAILURE for name on this is the time [build=>number, status=>FAILURE]")
|
263
|
+
|
264
|
+
server.send(:process_job).should be_true
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
describe "#notify" do
|
270
|
+
let(:client) { mock(:client) }
|
271
|
+
|
272
|
+
context "no exceptions" do
|
273
|
+
before do
|
274
|
+
options = {
|
275
|
+
"pass" => "pass",
|
276
|
+
"fail" => "fail",
|
277
|
+
"host" => "host",
|
278
|
+
"port" => "port"
|
279
|
+
}
|
280
|
+
config = mock(:config)
|
281
|
+
config.should_receive(:tcp_client).and_return(options)
|
282
|
+
config.should_receive(:verbose).and_return(true)
|
283
|
+
|
284
|
+
server.should_receive(:config).twice.and_return(config)
|
285
|
+
|
286
|
+
STDOUT.should_receive(:puts).with("answer")
|
287
|
+
|
288
|
+
client.should_receive(:gets).and_return("answer")
|
289
|
+
client.should_receive(:close)
|
290
|
+
|
291
|
+
TCPSocket.should_receive(:new).with("host", "port").and_return(client)
|
292
|
+
end
|
293
|
+
|
294
|
+
it "should send passing packet to tcp socket when status is true" do
|
295
|
+
client.should_receive(:print).with("GET pass HTTP/1.0\n\n")
|
296
|
+
server.send(:notify, true)
|
297
|
+
end
|
298
|
+
|
299
|
+
it "should send failing packet to tcp socket when status is false" do
|
300
|
+
client.should_receive(:print).with("GET fail HTTP/1.0\n\n")
|
301
|
+
server.send(:notify, false)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
context "exceptions" do
|
306
|
+
before do
|
307
|
+
options = {
|
308
|
+
"fail" => "fail",
|
309
|
+
"host" => "host",
|
310
|
+
"port" => "port",
|
311
|
+
"attempts" => 2
|
312
|
+
}
|
313
|
+
config = mock(:config)
|
314
|
+
config.should_receive(:tcp_client).and_return(options)
|
315
|
+
config.should_receive(:verbose).and_return(false)
|
316
|
+
|
317
|
+
server.should_receive(:config).twice.and_return(config)
|
318
|
+
client.should_receive(:close)
|
319
|
+
|
320
|
+
client.should_receive(:gets).and_return("answer")
|
321
|
+
end
|
322
|
+
|
323
|
+
it "should time out and retry 2 times" do
|
324
|
+
TCPSocket.should_receive(:new).exactly(3).with("host", "port").and_return(client)
|
325
|
+
STDERR.should_receive(:puts).exactly(2).with("Error: Timeout::Error while trying to send fail")
|
326
|
+
client.should_receive(:print).exactly(2).with("GET fail HTTP/1.0\n\n").and_raise(Timeout::Error)
|
327
|
+
client.should_receive(:print).with("GET fail HTTP/1.0\n\n")
|
328
|
+
|
329
|
+
server.send(:notify, false)
|
330
|
+
end
|
331
|
+
|
332
|
+
it "should not connect and retry 2 times" do
|
333
|
+
STDERR.should_receive(:puts).with("Error: Connection refused while trying to send fail")
|
334
|
+
STDERR.should_receive(:puts).with("Error: No route to host while trying to send fail")
|
335
|
+
STDERR.should_receive(:puts).exactly(2).with("Will wait for 2 seconds and try again...")
|
336
|
+
|
337
|
+
TCPSocket.should_receive(:new).with("host", "port").and_raise(Errno::ECONNREFUSED)
|
338
|
+
TCPSocket.should_receive(:new).with("host", "port").and_raise(Errno::EHOSTUNREACH)
|
339
|
+
TCPSocket.should_receive(:new).with("host", "port").and_return(client)
|
340
|
+
|
341
|
+
server.should_receive(:sleep).twice.with(2)
|
342
|
+
|
343
|
+
client.should_receive(:print).with("GET fail HTTP/1.0\n\n")
|
344
|
+
|
345
|
+
server.send(:notify, false)
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
it "should gracefully recover if config doesn't have attempts configured" do
|
350
|
+
options = {
|
351
|
+
"fail" => "fail",
|
352
|
+
"host" => "host",
|
353
|
+
"port" => "port"
|
354
|
+
}
|
355
|
+
|
356
|
+
config = mock(:config)
|
357
|
+
config.should_receive(:tcp_client).and_return(options)
|
358
|
+
config.should_receive(:verbose).and_return(false)
|
359
|
+
|
360
|
+
server.should_receive(:config).twice.and_return(config)
|
361
|
+
client.should_receive(:close)
|
362
|
+
|
363
|
+
client.should_receive(:gets).and_return("answer")
|
364
|
+
TCPSocket.should_receive(:new).exactly(3).with("host", "port").and_return(client)
|
365
|
+
STDERR.should_receive(:puts).exactly(2).with("Error: Timeout::Error while trying to send fail")
|
366
|
+
client.should_receive(:print).exactly(2).with("GET fail HTTP/1.0\n\n").and_raise(Timeout::Error)
|
367
|
+
client.should_receive(:print).with("GET fail HTTP/1.0\n\n")
|
368
|
+
|
369
|
+
server.send(:notify, false)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
describe "#process_all_statuses" do
|
374
|
+
it "should return true if all values are SUCCESS" do
|
375
|
+
server.should_receive(:store).and_return(mock(:blah, :values => %w(SUCCESS SUCCESS SUCCESS)))
|
376
|
+
server.send(:process_all_statuses).should be_true
|
377
|
+
end
|
378
|
+
|
379
|
+
it "should return true if all values are pass" do
|
380
|
+
server.should_receive(:store).and_return(mock(:blah, :values => %w(pass pass pass)))
|
381
|
+
server.send(:process_all_statuses).should be_true
|
382
|
+
end
|
383
|
+
|
384
|
+
it "should return true if some values are pass and some are SUCCESS" do
|
385
|
+
server.should_receive(:store).and_return(mock(:blah, :values => %w(SUCCESS pass SUCCESS)))
|
386
|
+
server.send(:process_all_statuses).should be_true
|
387
|
+
end
|
388
|
+
|
389
|
+
it "should return false if at least one value isn't pass or SUCCESS" do
|
390
|
+
server.should_receive(:store).and_return(mock(:blah, :values => %w(SUCCESS blah SUCCESS)))
|
391
|
+
server.send(:process_all_statuses).should be_false
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
118
395
|
end
|
119
396
|
end
|
120
397
|
|