testbot_instructure 0.7.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/CHANGELOG +264 -0
  4. data/Gemfile +3 -0
  5. data/README.markdown +141 -0
  6. data/Rakefile +35 -0
  7. data/bin/testbot +59 -0
  8. data/lib/generators/testbot/templates/testbot.rake.erb +35 -0
  9. data/lib/generators/testbot/templates/testbot.yml.erb +45 -0
  10. data/lib/generators/testbot/testbot_generator.rb +19 -0
  11. data/lib/railtie.rb +16 -0
  12. data/lib/requester/requester.rb +171 -0
  13. data/lib/runner/job.rb +112 -0
  14. data/lib/runner/runner.rb +222 -0
  15. data/lib/runner/safe_result_text.rb +29 -0
  16. data/lib/server/build.rb +36 -0
  17. data/lib/server/group.rb +48 -0
  18. data/lib/server/job.rb +64 -0
  19. data/lib/server/memory_model.rb +91 -0
  20. data/lib/server/runner.rb +47 -0
  21. data/lib/server/server.rb +103 -0
  22. data/lib/server/status/javascripts/jquery-1.4.4.min.js +167 -0
  23. data/lib/server/status/status.html +48 -0
  24. data/lib/server/status/stylesheets/status.css +14 -0
  25. data/lib/shared/adapters/adapter.rb +27 -0
  26. data/lib/shared/adapters/cucumber_adapter.rb +91 -0
  27. data/lib/shared/adapters/helpers/ruby_env.rb +47 -0
  28. data/lib/shared/adapters/rspec2_adapter.rb +61 -0
  29. data/lib/shared/adapters/rspec_adapter.rb +79 -0
  30. data/lib/shared/adapters/test_unit_adapter.rb +44 -0
  31. data/lib/shared/color.rb +16 -0
  32. data/lib/shared/simple_daemonize.rb +25 -0
  33. data/lib/shared/ssh_tunnel.rb +36 -0
  34. data/lib/shared/testbot.rb +132 -0
  35. data/lib/shared/version.rb +12 -0
  36. data/lib/tasks/testbot.rake +30 -0
  37. data/lib/testbot.rb +2 -0
  38. data/test/fixtures/local/Rakefile +7 -0
  39. data/test/fixtures/local/config/testbot.yml +5 -0
  40. data/test/fixtures/local/log/test.log +0 -0
  41. data/test/fixtures/local/script/spec +2 -0
  42. data/test/fixtures/local/spec/models/car_spec.rb +0 -0
  43. data/test/fixtures/local/spec/models/house_spec.rb +0 -0
  44. data/test/fixtures/local/spec/spec.opts +0 -0
  45. data/test/fixtures/local/tmp/restart.txt +0 -0
  46. data/test/integration_test.rb +55 -0
  47. data/test/requester/requester_test.rb +407 -0
  48. data/test/requester/testbot.yml +7 -0
  49. data/test/requester/testbot_with_erb.yml +2 -0
  50. data/test/runner/job_test.rb +94 -0
  51. data/test/runner/safe_result_text_test.rb +20 -0
  52. data/test/server/group_test.rb +43 -0
  53. data/test/server/server_test.rb +511 -0
  54. data/test/shared/adapters/adapter_test.rb +22 -0
  55. data/test/shared/adapters/cucumber_adapter_test.rb +72 -0
  56. data/test/shared/adapters/helpers/ruby_env_test.rb +108 -0
  57. data/test/shared/adapters/rspec_adapter_test.rb +109 -0
  58. data/test/shared/testbot_test.rb +185 -0
  59. data/testbot.gemspec +34 -0
  60. 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,7 @@
1
+ server_host: hostname
2
+ rsync_path: /path
3
+ rsync_ignores: .git tmp
4
+ project: appname
5
+ ssh_tunnel: false
6
+ server_user: user
7
+ available_runner_usage: 50%
@@ -0,0 +1,2 @@
1
+ server_host: <%= "dynamic_host" %>
2
+ available_runner_usage: "<%= 50 %>%"
@@ -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