testbot 0.6.5 → 0.6.6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,15 @@
1
+ 0.6.6
2
+
3
+ The runner will now run config/testbot/before_run.rb if it exists.
4
+
5
+ Replaced the old process code with the posix-spawn gem's methods. This fixed
6
+ process shutdown in my current setup. Hopefully more stable overall.
7
+
8
+ The requester will now request that the build is stopped when exiting early (like when killed),
9
+ and not only on ctrl+c (SIGINT).
10
+
11
+ Most of this was based on a fork by https://github.com/Skalar.
12
+
1
13
  0.6.5
2
14
 
3
15
  Fixed test unit require path so that it works with ruby 1.9.
data/README.markdown CHANGED
@@ -67,7 +67,7 @@ Using testbot with Rails 2:
67
67
 
68
68
  # Add testbot to your Gemfile if you use bundler. You also need the plugin because
69
69
  # Rails 2 does not load raketasks from gems.
70
- ruby script/plugin install git://github.com/joakimk/testbot.git -r 'refs/tags/v0.6.5'
70
+ ruby script/plugin install git://github.com/joakimk/testbot.git -r 'refs/tags/v0.6.6'
71
71
  script/generate testbot --connect 192.168.0.100
72
72
 
73
73
  rake testbot:spec (or :rspec, :test, :features)
@@ -140,4 +140,3 @@ More
140
140
  ----
141
141
 
142
142
  * Check the [wiki](http://github.com/joakimk/testbot/wiki) for more info.
143
- * Chat: [https://convore.com/github/testbot](https://convore.com/github/testbot)
@@ -43,7 +43,8 @@ module Testbot::Requester
43
43
 
44
44
  log "Syncing files" do
45
45
  rsync_ignores = config.rsync_ignores.to_s.split.map { |pattern| "--exclude='#{pattern}'" }.join(' ')
46
- system "rsync -az --delete -e ssh #{rsync_ignores} . #{rsync_uri}"
46
+ # todo: exit when this fails
47
+ system "rsync -az --delete --delete-excluded -e ssh #{rsync_ignores} . #{rsync_uri}"
47
48
  end
48
49
 
49
50
  files = adapter.test_files(dir)
@@ -70,7 +71,13 @@ module Testbot::Requester
70
71
  end
71
72
  end
72
73
 
73
- trap("SIGINT") { HTTParty.delete("#{server_uri}/builds/#{build_id}"); return false }
74
+ at_exit do
75
+ unless ENV['IN_TEST'] || @done
76
+ log "Notifying server we want to stop the run" do
77
+ HTTParty.delete("#{server_uri}/builds/#{build_id}")
78
+ end
79
+ end
80
+ end
74
81
 
75
82
  puts if config.logging
76
83
 
@@ -114,6 +121,7 @@ module Testbot::Requester
114
121
  puts "\n" + adapter.sum_results(@build['results'])
115
122
  end
116
123
 
124
+ @done = true
117
125
  @build["success"]
118
126
  end
119
127
 
data/lib/runner/job.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), 'runner.rb'))
2
2
  require File.expand_path(File.join(File.dirname(__FILE__), 'safe_result_text.rb'))
3
+ require 'posix/spawn'
3
4
 
4
5
  module Testbot::Runner
5
6
  class Job
@@ -8,6 +9,7 @@ module Testbot::Runner
8
9
  def initialize(runner, id, build_id, project, root, type, ruby_interpreter, files)
9
10
  @runner, @id, @build_id, @project, @root, @type, @ruby_interpreter, @files =
10
11
  runner, id, build_id, project, root, type, ruby_interpreter, files
12
+ @success = true
11
13
  end
12
14
 
13
15
  def jruby?
@@ -31,15 +33,19 @@ module Testbot::Runner
31
33
  end
32
34
 
33
35
  def kill!(build_id)
34
- if @build_id == build_id && @test_process
35
- # The child process that runs the tests is a shell, we need to kill it's child process
36
- system("pkill -KILL -P #{@test_process.pid}")
36
+ if @build_id == build_id && @pid
37
+ kill_processes
37
38
  @killed = true
38
39
  end
39
40
  end
40
41
 
41
42
  private
42
43
 
44
+ def kill_processes
45
+ # Kill process and its children (processes in the same group)
46
+ Process.kill('KILL', -@pid) rescue :failed_to_kill_process
47
+ end
48
+
43
49
  def status
44
50
  success? ? "successful" : "failed"
45
51
  end
@@ -55,23 +61,40 @@ module Testbot::Runner
55
61
  end
56
62
 
57
63
  def run_and_return_result(command)
58
- @test_process = open("|#{command} 2>&1", 'r')
64
+ read_pipe = spawn_process(command)
65
+
59
66
  output = ""
60
- t = Time.now
61
- while char = @test_process.getc
67
+ last_post_time = Time.now
68
+ while char = read_pipe.getc
62
69
  char = (char.is_a?(Fixnum) ? char.chr : char) # 1.8 <-> 1.9
63
70
  output << char
64
- if Time.now - t > 0.5
71
+ if Time.now - last_post_time > 0.5
65
72
  post_results(output)
66
- t = Time.now
73
+ last_post_time = Time.now
67
74
  end
68
75
  end
69
- @test_process.close
76
+
77
+ # Kill child processes, if any
78
+ kill_processes
79
+
70
80
  output
71
81
  end
72
82
 
83
+ def spawn_process(command)
84
+ read_pipe, write_pipe = IO.pipe
85
+ @pid = POSIX::Spawn::spawn(command, :err => write_pipe, :out => write_pipe, :pgroup => true)
86
+
87
+ Thread.new do
88
+ Process.waitpid(@pid)
89
+ @success = ($?.exitstatus == 0)
90
+ write_pipe.close
91
+ end
92
+
93
+ read_pipe
94
+ end
95
+
73
96
  def success?
74
- $?.exitstatus == 0
97
+ @success
75
98
  end
76
99
 
77
100
  def ruby_cmd
data/lib/runner/runner.rb CHANGED
@@ -104,7 +104,7 @@ module Testbot::Runner
104
104
  job = Job.new(*([ self, next_job.split(',') ].flatten))
105
105
  if first_job_from_build?
106
106
  fetch_code(job)
107
- before_run(job) if File.exists?("#{job.project}/lib/tasks/testbot.rake")
107
+ before_run(job)
108
108
  end
109
109
 
110
110
  @last_build_id = job.build_id
@@ -123,12 +123,18 @@ module Testbot::Runner
123
123
  end
124
124
 
125
125
  def fetch_code(job)
126
- system "rsync -az --delete -e ssh #{job.root}/ #{job.project}"
126
+ system "rsync -az --delete --delete-excluded -e ssh #{job.root}/ #{job.project}"
127
127
  end
128
128
 
129
129
  def before_run(job)
130
- bundler_cmd = RubyEnv.bundler?(job.project) ? "bundle; bundle exec" : ""
131
- system "export RAILS_ENV=test; export TEST_INSTANCES=#{@config.max_instances}; cd #{job.project}; #{bundler_cmd} rake testbot:before_run"
130
+ using_bundler = RubyEnv.bundler?(job.project)
131
+ bundler_cmd = using_bundler ? "bundle exec" : ""
132
+ command_prefix = "cd #{job.project}; RAILS_ENV=test TEST_INSTANCES=#{@config.max_instances} #{bundler_cmd}"
133
+
134
+ # todo: exit if this fails, report back, etc.
135
+ system("cd #{job.project}; bundle") if using_bundler
136
+ system "#{command_prefix} rake testbot:before_run" if File.exists?("#{job.project}/lib/tasks/testbot.rake")
137
+ system "#{command_prefix} ruby config/testbot/before_run.rb" if File.exists?("#{job.project}/config/testbot/before_run.rb")
132
138
  end
133
139
 
134
140
  def first_job_from_build?
@@ -1,7 +1,7 @@
1
1
  class RubyEnv
2
2
 
3
3
  def self.bundler?(project_path)
4
- Gem.available?("bundler") && File.exists?("#{project_path}/Gemfile")
4
+ Gem::Specification.find_by_name("bundler") && File.exists?("#{project_path}/Gemfile") rescue false
5
5
  end
6
6
 
7
7
  def self.ruby_command(project_path, opts = {})
@@ -1,7 +1,7 @@
1
1
  module Testbot
2
2
  # Don't forget to update readme and changelog
3
3
  def self.version
4
- version = "0.6.5"
4
+ version = "0.6.6"
5
5
  dev_version_file = File.join(File.dirname(__FILE__), '..', '..', 'DEV_VERSION')
6
6
  if File.exists?(dev_version_file)
7
7
  version += File.read(dev_version_file)
@@ -3,7 +3,7 @@ require File.dirname(__FILE__) + '/../shared/adapters/adapter'
3
3
  namespace :testbot do
4
4
 
5
5
  def run_and_show_results(adapter, custom_path)
6
- Rake::Task["testbot:before_request"].invoke
6
+ 'testbot:before_request'.tap { |t| Rake::Task.task_defined?(t) && Rake::Task[t].invoke }
7
7
 
8
8
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'requester', 'requester.rb'))
9
9
  requester = Testbot::Requester::Requester.create_by_config("#{Rails.root}/config/testbot.yml")
@@ -41,6 +41,7 @@ module Testbot::Requester
41
41
 
42
42
  def setup
43
43
  ENV['USE_JRUBY'] = nil
44
+ ENV['IN_TEST'] = 'true'
44
45
  end
45
46
 
46
47
  def mock_file_sizes
@@ -233,7 +234,7 @@ module Testbot::Requester
233
234
  flexmock(HTTParty).should_receive(:get).once.with("http://192.168.1.100:#{Testbot::SERVER_PORT}/builds/5",
234
235
  :format => :json).and_return({ "done" => true, "results" => "" })
235
236
 
236
- flexmock(requester).should_receive('system').with("rsync -az --delete -e ssh --exclude='.git' --exclude='tmp' . testbot@192.168.1.100:/path")
237
+ flexmock(requester).should_receive('system').with("rsync -az --delete --delete-excluded -e ssh --exclude='.git' --exclude='tmp' . testbot@192.168.1.100:/path")
237
238
  mock_file_sizes
238
239
 
239
240
  requester.run_tests(RspecAdapter, 'spec')
@@ -336,7 +337,7 @@ module Testbot::Requester
336
337
  flexmock(requester).should_receive(:print)
337
338
  flexmock(requester).should_receive(:puts)
338
339
 
339
- flexmock(requester).should_receive('system').with("rsync -az --delete -e ssh . cruise@somewhere:/tmp/testbot/foo")
340
+ flexmock(requester).should_receive('system').with("rsync -az --delete --delete-excluded -e ssh . cruise@somewhere:/tmp/testbot/foo")
340
341
  mock_file_sizes
341
342
 
342
343
  requester.run_tests(RspecAdapter, 'spec')
@@ -12,10 +12,38 @@ module Testbot::Runner
12
12
  flexmock(RubyEnv).should_receive(:bundler?).with("/path").returns(true)
13
13
 
14
14
  runner = Runner.new({:max_instances => 1})
15
+ flexmock(File).should_receive(:exists?).with("/path/lib/tasks/testbot.rake").and_return(true)
16
+ flexmock(File).should_receive(:exists?).with("/path/config/testbot/before_run.rb").and_return(false)
15
17
  flexmock(runner)
16
- flexmock(runner).should_receive(:system).with("export RAILS_ENV=test; export TEST_INSTANCES=1; cd /path; bundle; bundle exec rake testbot:before_run").once
18
+ flexmock(runner).should_receive(:system).with("cd /path; bundle").once
19
+ flexmock(runner).should_receive(:system).with("cd /path; RAILS_ENV=test TEST_INSTANCES=1 bundle exec rake testbot:before_run").once
17
20
  runner.send(:before_run, job)
18
21
  end
22
+
23
+ should "be able to use a plain ruby before_run file" do
24
+ job = flexmock(:job, :project => "/path")
25
+ flexmock(RubyEnv).should_receive(:bundler?).with("/path").returns(true)
26
+
27
+ runner = Runner.new({:max_instances => 1})
28
+ flexmock(File).should_receive(:exists?).with("/path/lib/tasks/testbot.rake").and_return(false)
29
+ flexmock(File).should_receive(:exists?).with("/path/config/testbot/before_run.rb").and_return(true)
30
+ flexmock(runner)
31
+ flexmock(runner).should_receive(:system).with("cd /path; bundle").once
32
+ flexmock(runner).should_receive(:system).with("cd /path; RAILS_ENV=test TEST_INSTANCES=1 bundle exec ruby config/testbot/before_run.rb").once
33
+ runner.send(:before_run, job)
34
+ end
35
+
36
+ should "be able to run without bundler" do
37
+ job = flexmock(:job, :project => "/path")
38
+ flexmock(RubyEnv).should_receive(:bundler?).with("/path").returns(false)
39
+
40
+ runner = Runner.new({:max_instances => 1})
41
+ flexmock(File).should_receive(:exists?).with("/path/lib/tasks/testbot.rake").and_return(false)
42
+ flexmock(File).should_receive(:exists?).with("/path/config/testbot/before_run.rb").and_return(true)
43
+ flexmock(runner)
44
+ flexmock(runner).should_receive(:system).with("cd /path; RAILS_ENV=test TEST_INSTANCES=1 ruby config/testbot/before_run.rb").once
45
+ runner.send(:before_run, job)
46
+ end
19
47
  end
20
48
  end
21
49
 
@@ -8,19 +8,19 @@ class RubyEnvTest < Test::Unit::TestCase
8
8
  context "self.bundler?" do
9
9
 
10
10
  should "return true if bundler is installed and there is a Gemfile" do
11
- flexmock(Gem).should_receive(:available?).with("bundler").once.and_return(true)
11
+ flexmock(Gem::Specification).should_receive(:find_by_name).with("bundler").once.and_return(true)
12
12
  flexmock(File).should_receive(:exists?).with("path/to/project/Gemfile").once.and_return(true)
13
13
  assert_equal true, RubyEnv.bundler?("path/to/project")
14
14
  end
15
15
 
16
16
  should "return false if bundler is installed but there is no Gemfile" do
17
- flexmock(Gem).should_receive(:available?).with("bundler").once.and_return(true)
17
+ flexmock(Gem::Specification).should_receive(:find_by_name).with("bundler").once.and_return(true)
18
18
  flexmock(File).should_receive(:exists?).and_return(false)
19
19
  assert_equal false, RubyEnv.bundler?("path/to/project")
20
20
  end
21
21
 
22
22
  should "return false if bundler is not installed" do
23
- flexmock(Gem).should_receive(:available?).with("bundler").once.and_return(false)
23
+ flexmock(Gem::Specification).should_receive(:find_by_name).with("bundler").once.and_return(false)
24
24
  assert_equal false, RubyEnv.bundler?("path/to/project")
25
25
  end
26
26
 
@@ -53,7 +53,6 @@ class RubyEnvTest < Test::Unit::TestCase
53
53
  end
54
54
 
55
55
  should "not look for a script when none is provided" do
56
- flexmock(File).should_receive(:exists?).once # Once for bundler check
57
56
  assert_equal 'ruby -S rspec', RubyEnv.ruby_command("path/to/project", :bin => "rspec")
58
57
  end
59
58
 
data/testbot.gemspec CHANGED
@@ -13,6 +13,7 @@ Gem::Specification.new do |s|
13
13
  s.executables = [ "testbot" ]
14
14
  s.files = Dir.glob("lib/**/*") + Dir.glob("test/**/*") + %w(Gemfile .gemtest Rakefile testbot.gemspec CHANGELOG README.markdown bin/testbot) +
15
15
  (File.exists?("DEV_VERSION") ? [ "DEV_VERSION" ] : [])
16
+
16
17
  s.add_dependency('sinatra', '>=1.0.0')
17
18
  s.add_dependency('httparty', '>= 0.6.1')
18
19
  s.add_dependency('macaddr', '>= 1.0.0')
@@ -20,6 +21,7 @@ Gem::Specification.new do |s|
20
21
  s.add_dependency('json_pure', '>= 1.4.6')
21
22
  s.add_dependency('daemons', '>= 1.0.10')
22
23
  s.add_dependency('acts_as_rails3_generator')
24
+ s.add_dependency('posix-spawn', '>= 0.3.6')
23
25
 
24
26
  s.add_development_dependency("shoulda")
25
27
  s.add_development_dependency("rack-test")
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: testbot
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
4
+ hash: 11
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 6
9
- - 5
10
- version: 0.6.5
9
+ - 6
10
+ version: 0.6.6
11
11
  platform: ruby
12
12
  authors:
13
13
  - "Joakim Kolsj\xC3\xB6"
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-04-28 00:00:00 +02:00
18
+ date: 2012-04-27 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -129,21 +129,23 @@ dependencies:
129
129
  type: :runtime
130
130
  version_requirements: *id007
131
131
  - !ruby/object:Gem::Dependency
132
- name: shoulda
132
+ name: posix-spawn
133
133
  prerelease: false
134
134
  requirement: &id008 !ruby/object:Gem::Requirement
135
135
  none: false
136
136
  requirements:
137
137
  - - ">="
138
138
  - !ruby/object:Gem::Version
139
- hash: 3
139
+ hash: 31
140
140
  segments:
141
141
  - 0
142
- version: "0"
143
- type: :development
142
+ - 3
143
+ - 6
144
+ version: 0.3.6
145
+ type: :runtime
144
146
  version_requirements: *id008
145
147
  - !ruby/object:Gem::Dependency
146
- name: rack-test
148
+ name: shoulda
147
149
  prerelease: false
148
150
  requirement: &id009 !ruby/object:Gem::Requirement
149
151
  none: false
@@ -157,7 +159,7 @@ dependencies:
157
159
  type: :development
158
160
  version_requirements: *id009
159
161
  - !ruby/object:Gem::Dependency
160
- name: flexmock
162
+ name: rack-test
161
163
  prerelease: false
162
164
  requirement: &id010 !ruby/object:Gem::Requirement
163
165
  none: false
@@ -171,7 +173,7 @@ dependencies:
171
173
  type: :development
172
174
  version_requirements: *id010
173
175
  - !ruby/object:Gem::Dependency
174
- name: rvm
176
+ name: flexmock
175
177
  prerelease: false
176
178
  requirement: &id011 !ruby/object:Gem::Requirement
177
179
  none: false
@@ -185,9 +187,23 @@ dependencies:
185
187
  type: :development
186
188
  version_requirements: *id011
187
189
  - !ruby/object:Gem::Dependency
188
- name: rake
190
+ name: rvm
189
191
  prerelease: false
190
192
  requirement: &id012 !ruby/object:Gem::Requirement
193
+ none: false
194
+ requirements:
195
+ - - ">="
196
+ - !ruby/object:Gem::Version
197
+ hash: 3
198
+ segments:
199
+ - 0
200
+ version: "0"
201
+ type: :development
202
+ version_requirements: *id012
203
+ - !ruby/object:Gem::Dependency
204
+ name: rake
205
+ prerelease: false
206
+ requirement: &id013 !ruby/object:Gem::Requirement
191
207
  none: false
192
208
  requirements:
193
209
  - - "="
@@ -199,11 +215,11 @@ dependencies:
199
215
  - 7
200
216
  version: 0.8.7
201
217
  type: :development
202
- version_requirements: *id012
218
+ version_requirements: *id013
203
219
  - !ruby/object:Gem::Dependency
204
220
  name: bundler
205
221
  prerelease: false
206
- requirement: &id013 !ruby/object:Gem::Requirement
222
+ requirement: &id014 !ruby/object:Gem::Requirement
207
223
  none: false
208
224
  requirements:
209
225
  - - ">="
@@ -213,11 +229,11 @@ dependencies:
213
229
  - 0
214
230
  version: "0"
215
231
  type: :development
216
- version_requirements: *id013
232
+ version_requirements: *id014
217
233
  - !ruby/object:Gem::Dependency
218
234
  name: guard
219
235
  prerelease: false
220
- requirement: &id014 !ruby/object:Gem::Requirement
236
+ requirement: &id015 !ruby/object:Gem::Requirement
221
237
  none: false
222
238
  requirements:
223
239
  - - ">="
@@ -227,11 +243,11 @@ dependencies:
227
243
  - 0
228
244
  version: "0"
229
245
  type: :development
230
- version_requirements: *id014
246
+ version_requirements: *id015
231
247
  - !ruby/object:Gem::Dependency
232
248
  name: guard-test
233
249
  prerelease: false
234
- requirement: &id015 !ruby/object:Gem::Requirement
250
+ requirement: &id016 !ruby/object:Gem::Requirement
235
251
  none: false
236
252
  requirements:
237
253
  - - ">="
@@ -241,7 +257,7 @@ dependencies:
241
257
  - 0
242
258
  version: "0"
243
259
  type: :development
244
- version_requirements: *id015
260
+ version_requirements: *id016
245
261
  description: Testbot is a test distribution tool that works with Rails, RSpec, RSpec2, Test::Unit and Cucumber.
246
262
  email:
247
263
  - joakim.kolsjo@gmail.com