testbot 0.5.2 → 0.5.3

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/CHANGELOG CHANGED
@@ -1,4 +1,4 @@
1
- 0.5.2
1
+ 0.5.3
2
2
 
3
3
  Added support for rubygems-test and http://gem-testers.org.
4
4
 
@@ -61,7 +61,7 @@ Running tests:
61
61
 
62
62
  Using testbot with Rails 2:
63
63
 
64
- ruby script/plugin install git://github.com/joakimk/testbot.git -r 'refs/tags/v0.5.2'
64
+ ruby script/plugin install git://github.com/joakimk/testbot.git -r 'refs/tags/v0.5.3'
65
65
  script/generate testbot --connect 192.168.0.100
66
66
 
67
67
  rake testbot:spec (or :test, :features)
@@ -0,0 +1,53 @@
1
+ require 'bundler'
2
+ # TODO: Add when possible. Currently "rake features" fails.
3
+ # require 'bundler/setup'
4
+ require 'cucumber'
5
+ require 'cucumber/rake/task'
6
+
7
+ Bundler::GemHelper.install_tasks
8
+
9
+ task :default => [ :test, :features ] do
10
+ end
11
+
12
+ desc "Run Test::Unit tests"
13
+ task :test do
14
+ Dir["test/**/test_*.rb"].each { |test| require(File.expand_path(test)) }
15
+ end
16
+
17
+
18
+ desc "Used for quickly deploying and testing updates without pusing to rubygems.org"
19
+ task :deploy do
20
+ File.open("DEV_VERSION", "w") { |f| f.write(".DEV.#{Time.now.to_i}") }
21
+
22
+ gem_file = "testbot-#{Testbot.version}.gem"
23
+ config = YAML.load_file(".deploy_config.yml")
24
+ Rake::Task["build"].invoke
25
+
26
+ begin
27
+ system(config["upload_gem"].gsub(/GEM_FILE/, gem_file)) || fail
28
+ system(config["update_server"].gsub(/GEM_FILE/, gem_file)) || fail
29
+ system(config["restart_server"]) || fail
30
+ ensure
31
+ system("rm DEV_VERSION")
32
+ end
33
+ end
34
+
35
+ desc "Used to restart the server when developing testbot"
36
+ task :restart do
37
+ config = YAML.load_file(".deploy_config.yml")
38
+ system(config["restart_server"]) || fail
39
+ end
40
+
41
+ Cucumber::Rake::Task.new(:features) do |t|
42
+ t.cucumber_opts = "features --format progress"
43
+ end
44
+
45
+ # HACK: As we use RVM to install gems while running cucumber we don't want bundler
46
+ # to raise an error like "rails is not part of the bundle. Add it to Gemfile.".
47
+ module Cucumber::Rake
48
+ class Task::ForkedCucumberRunner
49
+ def runner
50
+ [ RUBY ]
51
+ end
52
+ end
53
+ end
@@ -7,7 +7,7 @@ module Testbot
7
7
 
8
8
  # Don't forget to update readme and changelog
9
9
  def self.version
10
- version = "0.5.2"
10
+ version = "0.5.3"
11
11
  dev_version_file = File.join(File.dirname(__FILE__), '..', '..', 'DEV_VERSION')
12
12
  if File.exists?(dev_version_file)
13
13
  version += File.read(dev_version_file)
@@ -0,0 +1,7 @@
1
+ namespace :testbot do
2
+
3
+ task :before_run do
4
+ puts "prepare got called"
5
+ end
6
+
7
+ end
@@ -0,0 +1,5 @@
1
+ server_host: localhost
2
+ rsync_path: ../server
3
+ available_runner_usage: 100%
4
+ rsync_ignores: log/* tmp/*
5
+
File without changes
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ puts "script/spec got called with #{ARGV.inspect}"
File without changes
File without changes
@@ -0,0 +1,346 @@
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('5')
21
+ flexmock(requester).should_receive(:sleep).once
22
+ flexmock(requester).should_receive(:puts).once
23
+ flexmock(requester).should_receive(:system)
24
+ flexmock(HTTParty).should_receive(:get).once.with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
25
+ :format => :json).and_return({ "done" => true, "results" => results })
26
+ requester
27
+ end
28
+
29
+ def build_with_result(results)
30
+ requester_with_result(results).run_tests(RSpecAdapter, 'spec')
31
+ end
32
+
33
+ def setup
34
+ ENV['USE_JRUBY'] = nil
35
+ end
36
+
37
+ def mock_file_sizes
38
+ flexmock(File).should_receive(:stat).and_return(mock = Object.new)
39
+ flexmock(mock).should_receive(:size).and_return(0)
40
+ end
41
+
42
+ context "self.create_by_config" do
43
+
44
+ should 'create a requester from config' do
45
+ flexmock(YAML).should_receive(:load_file).once.with("testbot.yml").
46
+ and_return({ :server_host => 'hostname', :rsync_path => '/path',
47
+ :rsync_ignores => ".git tmp", :available_runner_usage => '50%',
48
+ :ssh_tunnel => false, :project => "appname", :server_user => "user" })
49
+ flexmock(Requester).should_receive(:new).once.with({ :server_host => 'hostname',
50
+ :rsync_path => '/path', :rsync_ignores => '.git tmp',
51
+ :available_runner_usage => '50%', :ssh_tunnel => false, :project => "appname",
52
+ :server_user => "user" })
53
+ Requester.create_by_config("testbot.yml")
54
+ end
55
+
56
+
57
+ end
58
+
59
+ context "initialize" do
60
+
61
+ should "use defaults when values are missing" do
62
+ expected = { :server_host => 'hostname',
63
+ :rsync_path => Testbot::DEFAULT_SERVER_PATH,
64
+ :project => Testbot::DEFAULT_PROJECT,
65
+ :server_user => Testbot::DEFAULT_USER,
66
+ :available_runner_usage => Testbot::DEFAULT_RUNNER_USAGE }
67
+
68
+ actual = Requester.new({ "server_host" => 'hostname' }).config
69
+
70
+ assert_equal OpenStruct.new(expected), actual
71
+ end
72
+
73
+ end
74
+
75
+ context "run_tests" do
76
+
77
+ should "should be able to create a build" do
78
+ flexmock(Mac).should_receive(:addr).and_return('aa:aa:aa:aa:aa:aa')
79
+ requester = Requester.new(:server_host => "192.168.1.100", :rsync_path => '/path', :available_runner_usage => '60%', :project => 'things', :server_user => "cruise")
80
+ flexmock(RSpecAdapter).should_receive(:test_files).with('spec').once.and_return([ 'spec/models/house_spec.rb', 'spec/models/car_spec.rb' ])
81
+
82
+ 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)
83
+ 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)
84
+
85
+ flexmock(HTTParty).should_receive(:post).once.with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds",
86
+ :body => { :type => "spec",
87
+ :root => "cruise@192.168.1.100:/path",
88
+ :project => "things",
89
+ :available_runner_usage => "60%",
90
+ :requester_mac => 'aa:aa:aa:aa:aa:aa',
91
+ :files => "spec/models/house_spec.rb" +
92
+ " spec/models/car_spec.rb",
93
+ :sizes => "10 20",
94
+ :jruby => false })
95
+
96
+ flexmock(HTTParty).should_receive(:get).and_return({ "done" => true, 'results' => '', "success" => true })
97
+ flexmock(requester).should_receive(:sleep)
98
+ flexmock(requester).should_receive(:puts)
99
+ flexmock(requester).should_receive(:system)
100
+
101
+ assert_equal true, requester.run_tests(RSpecAdapter, 'spec')
102
+ end
103
+
104
+ should "keep calling the server for results until done" do
105
+ requester = Requester.new(:server_host => "192.168.1.100")
106
+
107
+ flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
108
+ flexmock(requester).should_receive(:system)
109
+
110
+ flexmock(HTTParty).should_receive(:post).and_return('5')
111
+
112
+ flexmock(HTTParty).should_receive(:get).times(2).with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
113
+ :format => :json).and_return({ "done" => false, "results" => "job 2 done: ...." },
114
+ { "done" => true, "results" => "job 2 done: ....job 1 done: ...." })
115
+ mock_file_sizes
116
+
117
+ flexmock(requester).should_receive(:sleep).times(2).with(1)
118
+ flexmock(requester).should_receive(:puts).once.with("job 2 done: ....")
119
+ flexmock(requester).should_receive(:puts).once.with("job 1 done: ....")
120
+
121
+ requester.run_tests(RSpecAdapter, 'spec')
122
+ end
123
+
124
+ should "return false if not successful" do
125
+ requester = Requester.new(:server_host => "192.168.1.100")
126
+
127
+ flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
128
+ flexmock(requester).should_receive(:system)
129
+
130
+ flexmock(HTTParty).should_receive(:post).and_return('5')
131
+
132
+ flexmock(HTTParty).should_receive(:get).once.with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
133
+ :format => :json).and_return({ "success" => false, "done" => true, "results" => "job 2 done: ....job 1 done: ...." })
134
+
135
+ flexmock(requester).should_receive(:sleep).once.with(1)
136
+ flexmock(requester).should_receive(:puts).once.with("job 2 done: ....job 1 done: ....")
137
+ mock_file_sizes
138
+
139
+ assert_equal false, requester.run_tests(RSpecAdapter, 'spec')
140
+ end
141
+
142
+ should "not print empty lines when there is no result" 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('5')
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" => "" },
152
+ { "done" => true, "results" => "job 2 done: ....job 1 done: ...." })
153
+
154
+ flexmock(requester).should_receive(:sleep).times(2).with(1)
155
+ flexmock(requester).should_receive(:puts).once.with("job 2 done: ....job 1 done: ....")
156
+ mock_file_sizes
157
+
158
+ requester.run_tests(RSpecAdapter, 'spec')
159
+ end
160
+
161
+ should "sync the files to the server" do
162
+ requester = Requester.new(:server_host => "192.168.1.100", :rsync_path => '/path', :rsync_ignores => '.git tmp')
163
+
164
+ flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
165
+ flexmock(requester).should_receive(:system)
166
+
167
+ flexmock(HTTParty).should_receive(:post).and_return('5')
168
+ flexmock(requester).should_receive(:sleep).once
169
+ flexmock(HTTParty).should_receive(:get).once.with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
170
+ :format => :json).and_return({ "done" => true, "results" => "" })
171
+
172
+ flexmock(requester).should_receive('system').with("rsync -az --delete -e ssh --exclude='.git' --exclude='tmp' . testbot@192.168.1.100:/path")
173
+ mock_file_sizes
174
+
175
+ requester.run_tests(RSpecAdapter, 'spec')
176
+ end
177
+
178
+ should "just try again if the request encounters an error while running and print on the fith time" do
179
+ requester = Requester.new(:server_host => "192.168.1.100")
180
+
181
+ flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
182
+ flexmock(requester).should_receive(:system)
183
+
184
+ flexmock(HTTParty).should_receive(:post).and_return('5')
185
+
186
+ flexmock(HTTParty).should_receive(:get).times(5).with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
187
+ :format => :json).and_raise('some connection error')
188
+ flexmock(HTTParty).should_receive(:get).times(1).with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
189
+ :format => :json).and_return({ "done" => true, "results" => "job 2 done: ....job 1 done: ...." })
190
+
191
+ flexmock(requester).should_receive(:sleep).times(6).with(1)
192
+ flexmock(requester).should_receive(:puts).once.with("Failed to get status: some connection error")
193
+ flexmock(requester).should_receive(:puts).once.with("job 2 done: ....job 1 done: ....")
194
+ mock_file_sizes
195
+
196
+ requester.run_tests(RSpecAdapter, 'spec')
197
+ end
198
+
199
+ should "just try again if the status returns as nil" do
200
+ requester = Requester.new(:server_host => "192.168.1.100")
201
+
202
+ flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
203
+ flexmock(requester).should_receive(:system)
204
+
205
+ flexmock(HTTParty).should_receive(:post).and_return('5')
206
+
207
+ flexmock(HTTParty).should_receive(:get).times(2).with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
208
+ :format => :json).and_return(nil,
209
+ { "done" => true, "results" => "job 2 done: ....job 1 done: ...." })
210
+
211
+ flexmock(requester).should_receive(:sleep).times(2).with(1)
212
+ flexmock(requester).should_receive(:puts).once.with("job 2 done: ....job 1 done: ....")
213
+ mock_file_sizes
214
+
215
+ requester.run_tests(RSpecAdapter, 'spec')
216
+ end
217
+
218
+ should "remove unnessesary output from rspec when told to do so" do
219
+ requester = Requester.new(:server_host => "192.168.1.100", :simple_output => true)
220
+
221
+ flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb', 'spec_models/car_spec.rb' ])
222
+ flexmock(requester).should_receive(:system)
223
+
224
+ flexmock(HTTParty).should_receive(:post).and_return('5')
225
+
226
+ flexmock(HTTParty).should_receive(:get).times(2).with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
227
+ :format => :json).and_return(nil,
228
+ { "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" })
229
+
230
+ flexmock(requester).should_receive(:sleep).times(2).with(1)
231
+
232
+ # Imperfect match, includes "." in 84.333, but good enough.
233
+ flexmock(requester).should_receive(:print).once.with("......F...")
234
+ flexmock(requester).should_receive(:puts)
235
+ mock_file_sizes
236
+
237
+ requester.run_tests(RSpecAdapter, 'spec')
238
+ end
239
+
240
+ should "use SSHTunnel when specified (with a port that does not collide with the runner)" do
241
+ requester = Requester.new(:ssh_tunnel => true, :server_host => "somewhere")
242
+ flexmock(requester).should_receive(:system)
243
+
244
+ flexmock(SSHTunnel).should_receive(:new).once.with("somewhere", "testbot", 2299).and_return(ssh_tunnel = Object.new)
245
+ flexmock(ssh_tunnel).should_receive(:open).once
246
+
247
+ flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb' ])
248
+ flexmock(HTTParty).should_receive(:post).with("http://127.0.0.1:2299/builds", any).and_return('5')
249
+ flexmock(HTTParty).should_receive(:get).and_return({ "done" => true, "results" => "job 1 done: ...." })
250
+ flexmock(requester).should_receive(:sleep)
251
+ flexmock(requester).should_receive(:puts)
252
+ mock_file_sizes
253
+
254
+ requester.run_tests(RSpecAdapter, 'spec')
255
+ end
256
+
257
+ should "use another user for rsync and ssh_tunnel when specified" do
258
+ requester = Requester.new(:ssh_tunnel => true, :server_host => "somewhere",
259
+ :server_user => "cruise", :rsync_path => "/tmp/testbot/foo")
260
+
261
+ flexmock(SSHTunnel).should_receive(:new).once.with("somewhere", "cruise", 2299).and_return(ssh_tunnel = Object.new)
262
+ flexmock(ssh_tunnel).should_receive(:open).once
263
+
264
+ flexmock(requester).should_receive(:find_tests).and_return([ 'spec/models/house_spec.rb' ])
265
+ flexmock(HTTParty).should_receive(:post).with("http://127.0.0.1:2299/builds", any).and_return('5')
266
+ flexmock(HTTParty).should_receive(:get).and_return({ "done" => true, "results" => "job 1 done: ...." })
267
+ flexmock(requester).should_receive(:sleep)
268
+ flexmock(requester).should_receive(:puts)
269
+
270
+ flexmock(requester).should_receive('system').with("rsync -az --delete -e ssh . cruise@somewhere:/tmp/testbot/foo")
271
+ mock_file_sizes
272
+
273
+ requester.run_tests(RSpecAdapter, 'spec')
274
+ end
275
+
276
+ should "use another port for cucumber to be able to run at the same time as rspec" do
277
+ requester = Requester.new(:ssh_tunnel => true, :server_host => "somewhere")
278
+ flexmock(requester).should_receive(:system)
279
+
280
+ flexmock(SSHTunnel).should_receive(:new).once.with("somewhere", "testbot", 2230).and_return(ssh_tunnel = Object.new)
281
+ flexmock(ssh_tunnel).should_receive(:open).once
282
+
283
+ flexmock(requester).should_receive(:find_tests).and_return([ 'features/some.feature' ])
284
+ flexmock(HTTParty).should_receive(:post).with("http://127.0.0.1:2230/builds", any).and_return('5')
285
+ flexmock(HTTParty).should_receive(:get).and_return({ "done" => true, "results" => "job 1 done: ...." })
286
+ flexmock(requester).should_receive(:sleep)
287
+ flexmock(requester).should_receive(:puts)
288
+ mock_file_sizes
289
+
290
+ requester.run_tests(CucumberAdapter, 'features')
291
+ end
292
+
293
+ should "use another port for Test::Unit" do
294
+ requester = Requester.new(:ssh_tunnel => true, :server_host => "somewhere")
295
+ flexmock(requester).should_receive(:system)
296
+
297
+ flexmock(SSHTunnel).should_receive(:new).once.with("somewhere", "testbot", 2231).and_return(ssh_tunnel = Object.new)
298
+ flexmock(ssh_tunnel).should_receive(:open).once
299
+
300
+ flexmock(requester).should_receive(:find_tests).and_return([ 'test/some_test.rb' ])
301
+ flexmock(HTTParty).should_receive(:post).with("http://127.0.0.1:2231/builds", any).and_return('5')
302
+ flexmock(HTTParty).should_receive(:get).and_return({ "done" => true, "results" => "job 1 done: ...." })
303
+ flexmock(requester).should_receive(:sleep)
304
+ flexmock(requester).should_receive(:puts)
305
+ mock_file_sizes
306
+
307
+ requester.run_tests(TestUnitAdapter, 'test')
308
+ end
309
+
310
+ should "request a run with jruby if USE_JRUBY is set" do
311
+ ENV['USE_JRUBY'] = "true"
312
+ requester = Requester.new
313
+ flexmock(requester).should_receive(:system)
314
+ flexmock(Mac).should_receive(:addr).and_return("00:01:..")
315
+
316
+ # This is quite ugly. I want something like hash_including instead...
317
+ other_args = { :type=>"test", :available_runner_usage=>"100%",
318
+ :root=>"testbot@:/tmp/testbot/#{ENV['USER']}", :files=>"test/some_test.rb",
319
+ :requester_mac=>"00:01:..", :sizes=>"0", :project=>"project" }
320
+
321
+ flexmock(TestUnitAdapter).should_receive(:test_files).and_return([ 'test/some_test.rb' ])
322
+ flexmock(HTTParty).should_receive(:post).with(any, :body => other_args.merge({ :jruby => true })).and_return('5')
323
+ flexmock(HTTParty).should_receive(:get).and_return({ "done" => true, "results" => "job 1 done: ...." })
324
+ flexmock(requester).should_receive(:sleep)
325
+ flexmock(requester).should_receive(:puts)
326
+ mock_file_sizes
327
+
328
+ requester.run_tests(TestUnitAdapter, 'test')
329
+ end
330
+
331
+ end
332
+
333
+ context "result_lines" do
334
+
335
+ should "return all lines with results in them" do
336
+ results = "one\ntwo..\n... 0 failures\nthree"
337
+ requester = requester_with_result(results)
338
+ requester.run_tests(RSpecAdapter, 'spec')
339
+ assert_equal [ '... 0 failures' ], requester.result_lines
340
+ end
341
+
342
+ end
343
+
344
+ end
345
+
346
+ end