testbot 0.5.2 → 0.5.3

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