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