testbot_instructure 0.7.8
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.
- checksums.yaml +7 -0
- data/.gemtest +0 -0
- data/CHANGELOG +264 -0
- data/Gemfile +3 -0
- data/README.markdown +141 -0
- data/Rakefile +35 -0
- data/bin/testbot +59 -0
- data/lib/generators/testbot/templates/testbot.rake.erb +35 -0
- data/lib/generators/testbot/templates/testbot.yml.erb +45 -0
- data/lib/generators/testbot/testbot_generator.rb +19 -0
- data/lib/railtie.rb +16 -0
- data/lib/requester/requester.rb +171 -0
- data/lib/runner/job.rb +112 -0
- data/lib/runner/runner.rb +222 -0
- data/lib/runner/safe_result_text.rb +29 -0
- data/lib/server/build.rb +36 -0
- data/lib/server/group.rb +48 -0
- data/lib/server/job.rb +64 -0
- data/lib/server/memory_model.rb +91 -0
- data/lib/server/runner.rb +47 -0
- data/lib/server/server.rb +103 -0
- data/lib/server/status/javascripts/jquery-1.4.4.min.js +167 -0
- data/lib/server/status/status.html +48 -0
- data/lib/server/status/stylesheets/status.css +14 -0
- data/lib/shared/adapters/adapter.rb +27 -0
- data/lib/shared/adapters/cucumber_adapter.rb +91 -0
- data/lib/shared/adapters/helpers/ruby_env.rb +47 -0
- data/lib/shared/adapters/rspec2_adapter.rb +61 -0
- data/lib/shared/adapters/rspec_adapter.rb +79 -0
- data/lib/shared/adapters/test_unit_adapter.rb +44 -0
- data/lib/shared/color.rb +16 -0
- data/lib/shared/simple_daemonize.rb +25 -0
- data/lib/shared/ssh_tunnel.rb +36 -0
- data/lib/shared/testbot.rb +132 -0
- data/lib/shared/version.rb +12 -0
- data/lib/tasks/testbot.rake +30 -0
- data/lib/testbot.rb +2 -0
- data/test/fixtures/local/Rakefile +7 -0
- data/test/fixtures/local/config/testbot.yml +5 -0
- data/test/fixtures/local/log/test.log +0 -0
- data/test/fixtures/local/script/spec +2 -0
- data/test/fixtures/local/spec/models/car_spec.rb +0 -0
- data/test/fixtures/local/spec/models/house_spec.rb +0 -0
- data/test/fixtures/local/spec/spec.opts +0 -0
- data/test/fixtures/local/tmp/restart.txt +0 -0
- data/test/integration_test.rb +55 -0
- data/test/requester/requester_test.rb +407 -0
- data/test/requester/testbot.yml +7 -0
- data/test/requester/testbot_with_erb.yml +2 -0
- data/test/runner/job_test.rb +94 -0
- data/test/runner/safe_result_text_test.rb +20 -0
- data/test/server/group_test.rb +43 -0
- data/test/server/server_test.rb +511 -0
- data/test/shared/adapters/adapter_test.rb +22 -0
- data/test/shared/adapters/cucumber_adapter_test.rb +72 -0
- data/test/shared/adapters/helpers/ruby_env_test.rb +108 -0
- data/test/shared/adapters/rspec_adapter_test.rb +109 -0
- data/test/shared/testbot_test.rb +185 -0
- data/testbot.gemspec +34 -0
- metadata +313 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'shoulda'
|
5
|
+
|
6
|
+
class IntegrationTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def stop!
|
9
|
+
system "export INTEGRATION_TEST=true; bin/testbot --server stop > /dev/null"
|
10
|
+
system "export INTEGRATION_TEST=true; bin/testbot --runner stop > /dev/null"
|
11
|
+
end
|
12
|
+
|
13
|
+
# This is slow, and Test:Unit does not have "before/after :all" method, so I'm using a single testcase for multiple tests
|
14
|
+
should "be able to send a build request, have it run and show the results" do
|
15
|
+
Thread.new {
|
16
|
+
|
17
|
+
sleep 30
|
18
|
+
puts "Still running after 30 secs, stopping..."
|
19
|
+
stop!
|
20
|
+
}
|
21
|
+
|
22
|
+
system "rm -rf tmp; mkdir -p tmp; cp -rf test/fixtures/local tmp/local"
|
23
|
+
system "export INTEGRATION_TEST=true; bin/testbot --runner --connect 127.0.0.1 --working_dir tmp/runner > /dev/null"
|
24
|
+
system "export INTEGRATION_TEST=true; bin/testbot --server > /dev/null"
|
25
|
+
|
26
|
+
# For debug
|
27
|
+
# Thread.new do
|
28
|
+
# system "export INTEGRATION_TEST=true; bin/testbot --runner run --connect 127.0.0.1 --working_dir tmp/runner"
|
29
|
+
# end
|
30
|
+
# Thread.new do
|
31
|
+
# system "export INTEGRATION_TEST=true; bin/testbot --server run"
|
32
|
+
# end
|
33
|
+
|
34
|
+
sleep 2.0
|
35
|
+
result = `cd tmp/local; INTEGRATION_TEST=true ../../bin/testbot --spec --connect 127.0.0.1 --rsync_path ../server --rsync_ignores "log/* tmp/*"`
|
36
|
+
|
37
|
+
# Should include the result from script/spec
|
38
|
+
#puts result.inspect
|
39
|
+
assert result.include?('script/spec got called with ["-O", "spec/spec.opts", "spec/models/house_spec.rb", "spec/models/car_spec.rb"]') ||
|
40
|
+
result.include?('script/spec got called with ["-O", "spec/spec.opts", "spec/models/car_spec.rb", "spec/models/house_spec.rb"]')
|
41
|
+
|
42
|
+
|
43
|
+
# Should not include ignored files
|
44
|
+
assert !File.exists?("tmp/server/log/test.log")
|
45
|
+
assert !File.exists?("tmp/server/tmp/restart.txt")
|
46
|
+
assert !File.exists?("tmp/runner/local/log/test.log")
|
47
|
+
assert !File.exists?("tmp/runner/local/tmp/restart.txt")
|
48
|
+
end
|
49
|
+
|
50
|
+
def teardown
|
51
|
+
stop!
|
52
|
+
FileUtils.rm_rf "tmp"
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,407 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../lib/requester/requester.rb'))
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
require 'flexmock/test_unit'
|
5
|
+
|
6
|
+
# Probably a bug in flexmock, for 1.9.2
|
7
|
+
unless defined?(Test::Unit::AssertionFailedError)
|
8
|
+
class Test::Unit::AssertionFailedError
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Testbot::Requester
|
13
|
+
|
14
|
+
class RequesterTest < Test::Unit::TestCase
|
15
|
+
|
16
|
+
def requester_with_result(results)
|
17
|
+
requester = Requester.new(:server_host => "192.168.1.100", :rsync_path => 'user@server:/tmp/somewhere')
|
18
|
+
|
19
|
+
flexmock(requester).should_receive(:find_tests).and_return([])
|
20
|
+
flexmock(HTTParty).should_receive(:post).and_return(response_with_build_id)
|
21
|
+
flexmock(requester).should_receive(:sleep).once
|
22
|
+
flexmock(requester).should_receive(:print).once
|
23
|
+
flexmock(requester).should_receive(:puts).once
|
24
|
+
flexmock(requester).should_receive(:system)
|
25
|
+
flexmock(HTTParty).should_receive(:get).once.with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
|
26
|
+
:format => :json).and_return({ "done" => true, "results" => results })
|
27
|
+
requester
|
28
|
+
end
|
29
|
+
|
30
|
+
def response_with_build_id
|
31
|
+
OpenStruct.new(:response => OpenStruct.new(:code => "200", :body => "5"))
|
32
|
+
end
|
33
|
+
|
34
|
+
def error_response(opts = {})
|
35
|
+
OpenStruct.new(:response => OpenStruct.new(opts))
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_with_result(results)
|
39
|
+
requester_with_result(results).run_tests(RspecAdapter, 'spec')
|
40
|
+
end
|
41
|
+
|
42
|
+
def setup
|
43
|
+
ENV['USE_JRUBY'] = nil
|
44
|
+
ENV['IN_TEST'] = 'true'
|
45
|
+
end
|
46
|
+
|
47
|
+
def mock_file_sizes
|
48
|
+
flexmock(File).should_receive(:stat).and_return(mock = Object.new)
|
49
|
+
flexmock(mock).should_receive(:size).and_return(0)
|
50
|
+
end
|
51
|
+
|
52
|
+
def fixture_path(local_path)
|
53
|
+
File.join(File.dirname(__FILE__), local_path)
|
54
|
+
end
|
55
|
+
|
56
|
+
context "self.create_by_config" do
|
57
|
+
|
58
|
+
should 'create a requester from config' do
|
59
|
+
requester = Requester.create_by_config(fixture_path("testbot.yml"))
|
60
|
+
assert_equal 'hostname', requester.config.server_host
|
61
|
+
assert_equal '/path', requester.config.rsync_path
|
62
|
+
assert_equal '.git tmp', requester.config.rsync_ignores
|
63
|
+
assert_equal 'appname', requester.config.project
|
64
|
+
assert_equal false, requester.config.ssh_tunnel
|
65
|
+
assert_equal 'user', requester.config.server_user
|
66
|
+
assert_equal '50%', requester.config.available_runner_usage
|
67
|
+
end
|
68
|
+
|
69
|
+
should 'accept ERB-snippets in testbot.yml' do
|
70
|
+
requester = Requester.create_by_config(fixture_path("testbot_with_erb.yml"))
|
71
|
+
assert_equal 'dynamic_host', requester.config.server_host
|
72
|
+
assert_equal '50%', requester.config.available_runner_usage
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "initialize" do
|
77
|
+
|
78
|
+
should "use defaults when values are missing" do
|
79
|
+
expected = { :server_host => 'hostname',
|
80
|
+
:rsync_path => Testbot::DEFAULT_SERVER_PATH,
|
81
|
+
:project => Testbot::DEFAULT_PROJECT,
|
82
|
+
:server_user => Testbot::DEFAULT_USER,
|
83
|
+
:available_runner_usage => Testbot::DEFAULT_RUNNER_USAGE }
|
84
|
+
|
85
|
+
actual = Requester.new({ "server_host" => 'hostname' }).config
|
86
|
+
|
87
|
+
assert_equal OpenStruct.new(expected), actual
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
context "run_tests" do
|
93
|
+
|
94
|
+
should "should be able to create a build" do
|
95
|
+
requester = Requester.new(:server_host => "192.168.1.100", :rsync_path => '/path', :available_runner_usage => '60%', :project => 'things', :server_user => "cruise")
|
96
|
+
flexmock(RspecAdapter).should_receive(:test_files).with('spec').once.and_return([ 'spec/models/house_spec.rb', 'spec/models/car_spec.rb' ])
|
97
|
+
|
98
|
+
flexmock(File).should_receive(:stat).once.with("spec/models/house_spec.rb").and_return(mock = Object.new); flexmock(mock).should_receive(:size).and_return(10)
|
99
|
+
flexmock(File).should_receive(:stat).once.with("spec/models/car_spec.rb").and_return(mock = Object.new); flexmock(mock).should_receive(:size).and_return(20)
|
100
|
+
|
101
|
+
flexmock(HTTParty).should_receive(:post).once.with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds",
|
102
|
+
:body => { :type => "spec",
|
103
|
+
:root => "cruise@192.168.1.100:/path",
|
104
|
+
:project => "things",
|
105
|
+
:available_runner_usage => "60%",
|
106
|
+
:files => "spec/models/house_spec.rb" +
|
107
|
+
" spec/models/car_spec.rb",
|
108
|
+
:sizes => "10 20",
|
109
|
+
:jruby => false }).and_return(response_with_build_id)
|
110
|
+
|
111
|
+
flexmock(HTTParty).should_receive(:get).and_return({ "done" => true, 'results' => '', "success" => true })
|
112
|
+
flexmock(requester).should_receive(:sleep)
|
113
|
+
flexmock(requester).should_receive(:print)
|
114
|
+
flexmock(requester).should_receive(:puts)
|
115
|
+
flexmock(requester).should_receive(:system)
|
116
|
+
|
117
|
+
assert_equal true, requester.run_tests(RspecAdapter, 'spec')
|
118
|
+
end
|
119
|
+
|
120
|
+
should "print a message and exit if the status is 503" do
|
121
|
+
requester = Requester.new(:server_host => "192.168.1.100")
|
122
|
+
|
123
|
+
flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
|
124
|
+
flexmock(requester).should_receive(:system)
|
125
|
+
|
126
|
+
flexmock(HTTParty).should_receive(:post).and_return(error_response(:code => "503"))
|
127
|
+
flexmock(requester).should_receive(:puts)
|
128
|
+
assert_equal false, requester.run_tests(RspecAdapter, 'spec')
|
129
|
+
end
|
130
|
+
|
131
|
+
should "print what the server returns in case there is anything but a 200 response" do
|
132
|
+
requester = Requester.new(:server_host => "192.168.1.100")
|
133
|
+
|
134
|
+
flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
|
135
|
+
flexmock(requester).should_receive(:system)
|
136
|
+
|
137
|
+
flexmock(HTTParty).should_receive(:post).and_return(error_response(:code => "123", :body => "Some error"))
|
138
|
+
flexmock(requester).should_receive(:puts).with("Could not create build, 123: Some error")
|
139
|
+
assert_equal false, requester.run_tests(RspecAdapter, 'spec')
|
140
|
+
end
|
141
|
+
|
142
|
+
should "print the sum of results formatted by the adapter" do
|
143
|
+
requester = Requester.new(:server_host => "192.168.1.100")
|
144
|
+
|
145
|
+
flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
|
146
|
+
flexmock(requester).should_receive(:system)
|
147
|
+
|
148
|
+
flexmock(HTTParty).should_receive(:post).and_return(response_with_build_id)
|
149
|
+
|
150
|
+
flexmock(HTTParty).should_receive(:get).times(2).with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
|
151
|
+
:format => :json).and_return({ "done" => false, "results" => "job 2 done: ...." },
|
152
|
+
{ "done" => true, "results" => "job 2 done: ....job 1 done: ...." })
|
153
|
+
mock_file_sizes
|
154
|
+
|
155
|
+
flexmock(requester).should_receive(:sleep).times(2).with(0.5)
|
156
|
+
flexmock(requester).should_receive(:print).once.with("job 2 done: ....")
|
157
|
+
flexmock(requester).should_receive(:print).once.with("job 1 done: ....")
|
158
|
+
flexmock(requester).should_receive(:puts).once.with("\nformatted result")
|
159
|
+
|
160
|
+
flexmock(RspecAdapter).should_receive(:sum_results).with("job 2 done: ....job 1 done: ....").and_return("formatted result")
|
161
|
+
requester.run_tests(RspecAdapter, 'spec')
|
162
|
+
end
|
163
|
+
|
164
|
+
should "keep calling the server for results until done" do
|
165
|
+
requester = Requester.new(:server_host => "192.168.1.100")
|
166
|
+
|
167
|
+
flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
|
168
|
+
flexmock(requester).should_receive(:system)
|
169
|
+
|
170
|
+
flexmock(HTTParty).should_receive(:post).and_return(response_with_build_id)
|
171
|
+
|
172
|
+
flexmock(HTTParty).should_receive(:get).times(2).with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
|
173
|
+
:format => :json).and_return({ "done" => false, "results" => "job 2 done: ...." },
|
174
|
+
{ "done" => true, "results" => "job 2 done: ....job 1 done: ...." })
|
175
|
+
mock_file_sizes
|
176
|
+
|
177
|
+
flexmock(requester).should_receive(:sleep).times(2).with(0.5)
|
178
|
+
flexmock(requester).should_receive(:print).once.with("job 2 done: ....")
|
179
|
+
flexmock(requester).should_receive(:print).once.with("job 1 done: ....")
|
180
|
+
flexmock(requester).should_receive(:puts).once.with("\n\033[32m0 examples, 0 failures\033[0m")
|
181
|
+
|
182
|
+
requester.run_tests(RspecAdapter, 'spec')
|
183
|
+
end
|
184
|
+
|
185
|
+
should "return false if not successful" do
|
186
|
+
requester = Requester.new(:server_host => "192.168.1.100")
|
187
|
+
|
188
|
+
flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
|
189
|
+
flexmock(requester).should_receive(:system)
|
190
|
+
|
191
|
+
flexmock(HTTParty).should_receive(:post).and_return(response_with_build_id)
|
192
|
+
|
193
|
+
flexmock(HTTParty).should_receive(:get).once.with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
|
194
|
+
:format => :json).and_return({ "success" => false, "done" => true, "results" => "job 2 done: ....job 1 done: ...." })
|
195
|
+
|
196
|
+
flexmock(requester).should_receive(:sleep).once.with(0.5)
|
197
|
+
flexmock(requester).should_receive(:print).once.with("job 2 done: ....job 1 done: ....")
|
198
|
+
flexmock(requester).should_receive(:puts).once.with("\n\033[32m0 examples, 0 failures\033[0m")
|
199
|
+
mock_file_sizes
|
200
|
+
|
201
|
+
assert_equal false, requester.run_tests(RspecAdapter, 'spec')
|
202
|
+
end
|
203
|
+
|
204
|
+
should "not print empty lines when there is no result" do
|
205
|
+
requester = Requester.new(:server_host => "192.168.1.100")
|
206
|
+
|
207
|
+
flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
|
208
|
+
flexmock(requester).should_receive(:system)
|
209
|
+
|
210
|
+
flexmock(HTTParty).should_receive(:post).and_return(response_with_build_id)
|
211
|
+
|
212
|
+
flexmock(HTTParty).should_receive(:get).times(2).with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
|
213
|
+
:format => :json).and_return({ "done" => false, "results" => "" },
|
214
|
+
{ "done" => true, "results" => "job 2 done: ....job 1 done: ...." })
|
215
|
+
|
216
|
+
flexmock(requester).should_receive(:sleep).times(2).with(0.5)
|
217
|
+
flexmock(requester).should_receive(:print).once.with("job 2 done: ....job 1 done: ....")
|
218
|
+
flexmock(requester).should_receive(:puts).once.with("\n\033[32m0 examples, 0 failures\033[0m")
|
219
|
+
mock_file_sizes
|
220
|
+
|
221
|
+
requester.run_tests(RspecAdapter, 'spec')
|
222
|
+
end
|
223
|
+
|
224
|
+
should "sync the files to the server" do
|
225
|
+
requester = Requester.new(:server_host => "192.168.1.100", :rsync_path => '/path', :rsync_ignores => '.git tmp')
|
226
|
+
|
227
|
+
flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
|
228
|
+
flexmock(requester).should_receive(:system)
|
229
|
+
|
230
|
+
flexmock(HTTParty).should_receive(:post).and_return(response_with_build_id)
|
231
|
+
flexmock(requester).should_receive(:sleep).once
|
232
|
+
flexmock(requester).should_receive(:print)
|
233
|
+
flexmock(requester).should_receive(:puts)
|
234
|
+
flexmock(HTTParty).should_receive(:get).once.with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
|
235
|
+
:format => :json).and_return({ "done" => true, "results" => "" })
|
236
|
+
|
237
|
+
flexmock(requester).should_receive('system').with("rsync -az --delete --delete-excluded -e ssh --exclude='.git' --exclude='tmp' . testbot@192.168.1.100:/path")
|
238
|
+
mock_file_sizes
|
239
|
+
|
240
|
+
requester.run_tests(RspecAdapter, 'spec')
|
241
|
+
end
|
242
|
+
|
243
|
+
should "just try again if the request encounters an error while running and print on the fith time" do
|
244
|
+
requester = Requester.new(:server_host => "192.168.1.100")
|
245
|
+
|
246
|
+
flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
|
247
|
+
flexmock(requester).should_receive(:system)
|
248
|
+
|
249
|
+
flexmock(HTTParty).should_receive(:post).and_return(response_with_build_id)
|
250
|
+
|
251
|
+
flexmock(HTTParty).should_receive(:get).times(5).with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
|
252
|
+
:format => :json).and_raise('some connection error')
|
253
|
+
flexmock(HTTParty).should_receive(:get).times(1).with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
|
254
|
+
:format => :json).and_return({ "done" => true, "results" => "job 2 done: ....job 1 done: ...." })
|
255
|
+
|
256
|
+
flexmock(requester).should_receive(:sleep).times(6).with(0.5)
|
257
|
+
flexmock(requester).should_receive(:puts).once.with("Failed to get status: some connection error")
|
258
|
+
flexmock(requester).should_receive(:print).once.with("job 2 done: ....job 1 done: ....")
|
259
|
+
flexmock(requester).should_receive(:puts).once.with("\n\033[32m0 examples, 0 failures\033[0m")
|
260
|
+
mock_file_sizes
|
261
|
+
|
262
|
+
requester.run_tests(RspecAdapter, 'spec')
|
263
|
+
end
|
264
|
+
|
265
|
+
should "just try again if the status returns as nil" do
|
266
|
+
requester = Requester.new(:server_host => "192.168.1.100")
|
267
|
+
|
268
|
+
flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
|
269
|
+
flexmock(requester).should_receive(:system)
|
270
|
+
|
271
|
+
flexmock(HTTParty).should_receive(:post).and_return(response_with_build_id)
|
272
|
+
|
273
|
+
flexmock(HTTParty).should_receive(:get).times(2).with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
|
274
|
+
:format => :json).and_return(nil,
|
275
|
+
{ "done" => true, "results" => "job 2 done: ....job 1 done: ...." })
|
276
|
+
|
277
|
+
flexmock(requester).should_receive(:sleep).times(2).with(0.5)
|
278
|
+
flexmock(requester).should_receive(:print).once.with("job 2 done: ....job 1 done: ....")
|
279
|
+
flexmock(requester).should_receive(:puts).once.with("\n\033[32m0 examples, 0 failures\033[0m")
|
280
|
+
mock_file_sizes
|
281
|
+
|
282
|
+
requester.run_tests(RspecAdapter, 'spec')
|
283
|
+
end
|
284
|
+
|
285
|
+
should "remove unnessesary output from rspec when told to do so" do
|
286
|
+
requester = Requester.new(:server_host => "192.168.1.100", :simple_output => true)
|
287
|
+
|
288
|
+
flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
|
289
|
+
flexmock(requester).should_receive(:system)
|
290
|
+
|
291
|
+
flexmock(HTTParty).should_receive(:post).and_return(response_with_build_id)
|
292
|
+
|
293
|
+
flexmock(HTTParty).should_receive(:get).times(2).with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
|
294
|
+
:format => :json).and_return(nil,
|
295
|
+
{ "done" => true, "results" => "testbot4:\n....\n\nFinished in 84.333 seconds\n\n206 examples, 0 failures, 2 pending; testbot4:\n.F..\n\nFinished in 84.333 seconds\n\n206 examples, 0 failures, 2 pending" })
|
296
|
+
|
297
|
+
flexmock(requester).should_receive(:sleep).times(2).with(0.5)
|
298
|
+
|
299
|
+
# Imperfect match, includes "." in 84.333, but good enough.
|
300
|
+
flexmock(requester).should_receive(:print).once.with("......F...")
|
301
|
+
flexmock(requester).should_receive(:print)
|
302
|
+
flexmock(requester).should_receive(:puts)
|
303
|
+
mock_file_sizes
|
304
|
+
|
305
|
+
requester.run_tests(RspecAdapter, 'spec')
|
306
|
+
end
|
307
|
+
|
308
|
+
should "use SSHTunnel when specified (with a port that does not collide with the runner)" do
|
309
|
+
requester = Requester.new(:ssh_tunnel => true, :server_host => "somewhere")
|
310
|
+
flexmock(requester).should_receive(:system)
|
311
|
+
|
312
|
+
flexmock(SSHTunnel).should_receive(:new).once.with("somewhere", "testbot", 2299).and_return(ssh_tunnel = Object.new)
|
313
|
+
flexmock(ssh_tunnel).should_receive(:open).once
|
314
|
+
|
315
|
+
flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb' ])
|
316
|
+
flexmock(HTTParty).should_receive(:post).with("http://127.0.0.1:2299/builds", any).and_return(response_with_build_id)
|
317
|
+
flexmock(HTTParty).should_receive(:get).and_return({ "done" => true, "results" => "job 1 done: ...." })
|
318
|
+
flexmock(requester).should_receive(:sleep)
|
319
|
+
flexmock(requester).should_receive(:print)
|
320
|
+
flexmock(requester).should_receive(:puts)
|
321
|
+
mock_file_sizes
|
322
|
+
|
323
|
+
requester.run_tests(RspecAdapter, 'spec')
|
324
|
+
end
|
325
|
+
|
326
|
+
should "use another user for rsync and ssh_tunnel when specified" do
|
327
|
+
requester = Requester.new(:ssh_tunnel => true, :server_host => "somewhere",
|
328
|
+
:server_user => "cruise", :rsync_path => "/tmp/testbot/foo")
|
329
|
+
|
330
|
+
flexmock(SSHTunnel).should_receive(:new).once.with("somewhere", "cruise", 2299).and_return(ssh_tunnel = Object.new)
|
331
|
+
flexmock(ssh_tunnel).should_receive(:open).once
|
332
|
+
|
333
|
+
flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb' ])
|
334
|
+
flexmock(HTTParty).should_receive(:post).with("http://127.0.0.1:2299/builds", any).and_return(response_with_build_id)
|
335
|
+
flexmock(HTTParty).should_receive(:get).and_return({ "done" => true, "results" => "job 1 done: ...." })
|
336
|
+
flexmock(requester).should_receive(:sleep)
|
337
|
+
flexmock(requester).should_receive(:print)
|
338
|
+
flexmock(requester).should_receive(:puts)
|
339
|
+
|
340
|
+
flexmock(requester).should_receive('system').with("rsync -az --delete --delete-excluded -e ssh . cruise@somewhere:/tmp/testbot/foo")
|
341
|
+
mock_file_sizes
|
342
|
+
|
343
|
+
requester.run_tests(RspecAdapter, 'spec')
|
344
|
+
end
|
345
|
+
|
346
|
+
should "use another port for cucumber to be able to run at the same time as rspec" do
|
347
|
+
requester = Requester.new(:ssh_tunnel => true, :server_host => "somewhere")
|
348
|
+
flexmock(requester).should_receive(:system)
|
349
|
+
|
350
|
+
flexmock(SSHTunnel).should_receive(:new).once.with("somewhere", "testbot", 2230).and_return(ssh_tunnel = Object.new)
|
351
|
+
flexmock(ssh_tunnel).should_receive(:open).once
|
352
|
+
|
353
|
+
flexmock(requester).should_receive(:find_tests).and_return([ 'features/some.feature' ])
|
354
|
+
flexmock(HTTParty).should_receive(:post).with("http://127.0.0.1:2230/builds", any).and_return(response_with_build_id)
|
355
|
+
flexmock(HTTParty).should_receive(:get).and_return({ "done" => true, "results" => "job 1 done: ...." })
|
356
|
+
flexmock(requester).should_receive(:sleep)
|
357
|
+
flexmock(requester).should_receive(:print)
|
358
|
+
flexmock(requester).should_receive(:puts)
|
359
|
+
mock_file_sizes
|
360
|
+
|
361
|
+
requester.run_tests(CucumberAdapter, 'features')
|
362
|
+
end
|
363
|
+
|
364
|
+
should "use another port for Test::Unit" do
|
365
|
+
requester = Requester.new(:ssh_tunnel => true, :server_host => "somewhere")
|
366
|
+
flexmock(requester).should_receive(:system)
|
367
|
+
|
368
|
+
flexmock(SSHTunnel).should_receive(:new).once.with("somewhere", "testbot", 2231).and_return(ssh_tunnel = Object.new)
|
369
|
+
flexmock(ssh_tunnel).should_receive(:open).once
|
370
|
+
|
371
|
+
flexmock(requester).should_receive(:find_tests).and_return([ 'test/some_test.rb' ])
|
372
|
+
flexmock(HTTParty).should_receive(:post).with("http://127.0.0.1:2231/builds", any).and_return(response_with_build_id)
|
373
|
+
flexmock(HTTParty).should_receive(:get).and_return({ "done" => true, "results" => "job 1 done: ...." })
|
374
|
+
flexmock(requester).should_receive(:sleep)
|
375
|
+
flexmock(requester).should_receive(:print)
|
376
|
+
flexmock(requester).should_receive(:puts)
|
377
|
+
mock_file_sizes
|
378
|
+
|
379
|
+
requester.run_tests(TestUnitAdapter, 'test')
|
380
|
+
end
|
381
|
+
|
382
|
+
should "request a run with jruby if USE_JRUBY is set" do
|
383
|
+
ENV['USE_JRUBY'] = "true"
|
384
|
+
requester = Requester.new
|
385
|
+
flexmock(requester).should_receive(:system)
|
386
|
+
|
387
|
+
# This is quite ugly. I want something like hash_including instead...
|
388
|
+
other_args = { :type=>"test", :available_runner_usage=>"100%",
|
389
|
+
:root=>"testbot@:/tmp/testbot/#{ENV['USER']}", :files=>"test/some_test.rb",
|
390
|
+
:sizes=>"0", :project=>"project" }
|
391
|
+
|
392
|
+
flexmock(TestUnitAdapter).should_receive(:test_files).and_return([ 'test/some_test.rb' ])
|
393
|
+
flexmock(HTTParty).should_receive(:post).with(any, :body => other_args.merge({ :jruby => true })).and_return(response_with_build_id)
|
394
|
+
flexmock(HTTParty).should_receive(:get).and_return({ "done" => true, "results" => "job 1 done: ...." })
|
395
|
+
flexmock(requester).should_receive(:sleep)
|
396
|
+
flexmock(requester).should_receive(:print)
|
397
|
+
flexmock(requester).should_receive(:puts)
|
398
|
+
mock_file_sizes
|
399
|
+
|
400
|
+
requester.run_tests(TestUnitAdapter, 'test')
|
401
|
+
end
|
402
|
+
|
403
|
+
end
|
404
|
+
|
405
|
+
end
|
406
|
+
|
407
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../lib/shared/testbot.rb'))
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../lib/runner/job.rb'))
|
3
|
+
require 'test/unit'
|
4
|
+
require 'shoulda'
|
5
|
+
require 'flexmock/test_unit'
|
6
|
+
|
7
|
+
module Testbot::Runner
|
8
|
+
|
9
|
+
class JobTest < Test::Unit::TestCase
|
10
|
+
|
11
|
+
def expect_put_with(id, result_text, status, time = 0)
|
12
|
+
expected_result = "\n#{`hostname`.chomp}:#{Dir.pwd}\n"
|
13
|
+
expected_result += result_text
|
14
|
+
flexmock(Server).should_receive(:put).once.with("/jobs/#{id}", :body =>
|
15
|
+
{ :result => expected_result, :status => status, :time => time })
|
16
|
+
end
|
17
|
+
|
18
|
+
def expect_put
|
19
|
+
flexmock(Server).should_receive(:put).once
|
20
|
+
end
|
21
|
+
|
22
|
+
def expect_put_to_timeout
|
23
|
+
flexmock(Server).should_receive(:put).and_raise(Timeout::Error)
|
24
|
+
end
|
25
|
+
|
26
|
+
def stub_duration(seconds)
|
27
|
+
time ||= Time.now
|
28
|
+
flexmock(Time).should_receive(:now).and_return(time, time + seconds)
|
29
|
+
end
|
30
|
+
|
31
|
+
should "be able to run a successful job" do
|
32
|
+
job = Job.new(Runner.new({}), 10, "00:00", "project", "/tmp/testbot/user", "spec", "ruby", "spec/foo_spec.rb spec/bar_spec.rb")
|
33
|
+
flexmock(job).should_receive(:puts)
|
34
|
+
stub_duration(0)
|
35
|
+
|
36
|
+
expect_put_with(10, "result text", "successful")
|
37
|
+
flexmock(job).should_receive(:run_and_return_result).once.
|
38
|
+
with("export RAILS_ENV=test; export TEST_ENV_NUMBER=; cd project; export RSPEC_COLOR=true; ruby -S bundle exec rspec spec/foo_spec.rb spec/bar_spec.rb").
|
39
|
+
and_return('result text')
|
40
|
+
flexmock(RubyEnv).should_receive(:bundler?).returns(true)
|
41
|
+
flexmock(RubyEnv).should_receive(:rvm?).returns(false)
|
42
|
+
job.run(0)
|
43
|
+
end
|
44
|
+
|
45
|
+
should "not raise an error when posting results time out" do
|
46
|
+
job = Job.new(Runner.new({}), 10, "00:00", "project", "/tmp/testbot/user", "spec", "ruby", "spec/foo_spec.rb spec/bar_spec.rb")
|
47
|
+
flexmock(job).should_receive(:puts)
|
48
|
+
|
49
|
+
# We're using send here because triggering post_results though the rest of the
|
50
|
+
# code requires very complex setup. The code need to be refactored to be more testable.
|
51
|
+
expect_put
|
52
|
+
job.send(:post_results, "result text")
|
53
|
+
expect_put_to_timeout
|
54
|
+
job.send(:post_results, "result text")
|
55
|
+
end
|
56
|
+
|
57
|
+
should "not be successful when the job fails" do
|
58
|
+
job = Job.new(Runner.new({}), 10, "00:00", "project", "/tmp/testbot/user", "spec", "ruby", "spec/foo_spec.rb spec/bar_spec.rb")
|
59
|
+
flexmock(job).should_receive(:puts)
|
60
|
+
stub_duration(0)
|
61
|
+
|
62
|
+
expect_put_with(10, "result text", "failed")
|
63
|
+
flexmock(job).should_receive(:run_and_return_result).and_return('result text')
|
64
|
+
flexmock(job).should_receive(:success?).and_return(false)
|
65
|
+
job.run(0)
|
66
|
+
end
|
67
|
+
|
68
|
+
should "set an instance number when the instance is not 0" do
|
69
|
+
job = Job.new(Runner.new({}), 10, "00:00", "project", "/tmp/testbot/user", "spec", "ruby", "spec/foo_spec.rb spec/bar_spec.rb")
|
70
|
+
flexmock(job).should_receive(:puts)
|
71
|
+
stub_duration(0)
|
72
|
+
|
73
|
+
expect_put_with(10, "result text", "successful")
|
74
|
+
flexmock(job).should_receive(:run_and_return_result).
|
75
|
+
with(/TEST_ENV_NUMBER=2/).
|
76
|
+
and_return('result text')
|
77
|
+
flexmock(RubyEnv).should_receive(:rvm?).returns(false)
|
78
|
+
job.run(1)
|
79
|
+
end
|
80
|
+
|
81
|
+
should "return test runtime in milliseconds" do
|
82
|
+
job = Job.new(Runner.new({}), 10, "00:00", "project", "/tmp/testbot/user", "spec", "ruby", "spec/foo_spec.rb spec/bar_spec.rb")
|
83
|
+
flexmock(job).should_receive(:puts)
|
84
|
+
|
85
|
+
stub_duration(10.55)
|
86
|
+
expect_put_with(10, "result text", "successful", 1055)
|
87
|
+
flexmock(job).should_receive(:run_and_return_result).and_return('result text')
|
88
|
+
flexmock(RubyEnv).should_receive(:rvm?).returns(false)
|
89
|
+
job.run(0)
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../lib/shared/testbot.rb'))
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../lib/runner/safe_result_text.rb'))
|
3
|
+
require 'test/unit'
|
4
|
+
require 'shoulda'
|
5
|
+
|
6
|
+
module Testbot::Runner
|
7
|
+
|
8
|
+
class SafeResultTextTest < Test::Unit::TestCase
|
9
|
+
|
10
|
+
should "not break escape sequences" do
|
11
|
+
assert_equal "^[[32m.^[[0m^[[32m.^[[0m", SafeResultText.clean("^[[32m.^[[0m^[[32m.^[[0m^[[32m.")
|
12
|
+
assert_equal "^[[32m.^[[0m^[[32m.^[[0m", SafeResultText.clean("^[[32m.^[[0m^[[32m.^[[0m^[[3")
|
13
|
+
assert_equal "^[[32m.^[[0m", SafeResultText.clean("^[[32m.^[[0m^[")
|
14
|
+
assert_equal "[32m.[0m[32m.[0m[3", SafeResultText.clean("[32m.[0m[32m.[0m[3")
|
15
|
+
assert_equal "...", SafeResultText.clean("...")
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../lib/server/group'))
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
require 'flexmock/test_unit'
|
5
|
+
|
6
|
+
module Testbot::Server
|
7
|
+
|
8
|
+
class GroupTest < Test::Unit::TestCase
|
9
|
+
|
10
|
+
context "self.build" do
|
11
|
+
|
12
|
+
should "create file groups based on the number of instances" do
|
13
|
+
groups = Group.build([ 'spec/models/car_spec.rb', 'spec/models/car2_spec.rb',
|
14
|
+
'spec/models/house_spec.rb', 'spec/models/house2_spec.rb' ], [ 1, 1, 1, 1 ], 2, 'spec')
|
15
|
+
|
16
|
+
assert_equal 2, groups.size
|
17
|
+
assert_equal [ 'spec/models/house2_spec.rb', 'spec/models/house_spec.rb' ], groups[0]
|
18
|
+
assert_equal [ 'spec/models/car2_spec.rb', 'spec/models/car_spec.rb' ], groups[1]
|
19
|
+
end
|
20
|
+
|
21
|
+
should "create a small grop when there isn't enough specs to fill a normal one" do
|
22
|
+
groups = Group.build(["spec/models/car_spec.rb", "spec/models/car2_spec.rb",
|
23
|
+
"spec/models/house_spec.rb", "spec/models/house2_spec.rb",
|
24
|
+
"spec/models/house3_spec.rb"], [ 1, 1, 1, 1, 1 ], 3, 'spec')
|
25
|
+
|
26
|
+
assert_equal 3, groups.size
|
27
|
+
assert_equal [ "spec/models/car_spec.rb" ], groups[2]
|
28
|
+
end
|
29
|
+
|
30
|
+
should "use sizes when building groups" do
|
31
|
+
groups = Group.build([ 'spec/models/car_spec.rb', 'spec/models/car2_spec.rb',
|
32
|
+
'spec/models/house_spec.rb', 'spec/models/house2_spec.rb' ], [ 40, 10, 10, 20 ], 2, 'spec')
|
33
|
+
|
34
|
+
assert_equal [ 'spec/models/car_spec.rb' ], groups[0]
|
35
|
+
assert ![ 'spec/models/house2_spec.rb', 'spec/models/car2_spec.rb', 'spec/models/house_spec.rb' ].
|
36
|
+
find { |file| !groups[1].include?(file) }
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|