testbot 0.6.5 → 0.6.6

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,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