testbot_instructure 0.7.8
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.
- checksums.yaml +7 -0
- data/.gemtest +0 -0
- data/CHANGELOG +264 -0
- data/Gemfile +3 -0
- data/README.markdown +141 -0
- data/Rakefile +35 -0
- data/bin/testbot +59 -0
- data/lib/generators/testbot/templates/testbot.rake.erb +35 -0
- data/lib/generators/testbot/templates/testbot.yml.erb +45 -0
- data/lib/generators/testbot/testbot_generator.rb +19 -0
- data/lib/railtie.rb +16 -0
- data/lib/requester/requester.rb +171 -0
- data/lib/runner/job.rb +112 -0
- data/lib/runner/runner.rb +222 -0
- data/lib/runner/safe_result_text.rb +29 -0
- data/lib/server/build.rb +36 -0
- data/lib/server/group.rb +48 -0
- data/lib/server/job.rb +64 -0
- data/lib/server/memory_model.rb +91 -0
- data/lib/server/runner.rb +47 -0
- data/lib/server/server.rb +103 -0
- data/lib/server/status/javascripts/jquery-1.4.4.min.js +167 -0
- data/lib/server/status/status.html +48 -0
- data/lib/server/status/stylesheets/status.css +14 -0
- data/lib/shared/adapters/adapter.rb +27 -0
- data/lib/shared/adapters/cucumber_adapter.rb +91 -0
- data/lib/shared/adapters/helpers/ruby_env.rb +47 -0
- data/lib/shared/adapters/rspec2_adapter.rb +61 -0
- data/lib/shared/adapters/rspec_adapter.rb +79 -0
- data/lib/shared/adapters/test_unit_adapter.rb +44 -0
- data/lib/shared/color.rb +16 -0
- data/lib/shared/simple_daemonize.rb +25 -0
- data/lib/shared/ssh_tunnel.rb +36 -0
- data/lib/shared/testbot.rb +132 -0
- data/lib/shared/version.rb +12 -0
- data/lib/tasks/testbot.rake +30 -0
- data/lib/testbot.rb +2 -0
- data/test/fixtures/local/Rakefile +7 -0
- data/test/fixtures/local/config/testbot.yml +5 -0
- data/test/fixtures/local/log/test.log +0 -0
- data/test/fixtures/local/script/spec +2 -0
- data/test/fixtures/local/spec/models/car_spec.rb +0 -0
- data/test/fixtures/local/spec/models/house_spec.rb +0 -0
- data/test/fixtures/local/spec/spec.opts +0 -0
- data/test/fixtures/local/tmp/restart.txt +0 -0
- data/test/integration_test.rb +55 -0
- data/test/requester/requester_test.rb +407 -0
- data/test/requester/testbot.yml +7 -0
- data/test/requester/testbot_with_erb.yml +2 -0
- data/test/runner/job_test.rb +94 -0
- data/test/runner/safe_result_text_test.rb +20 -0
- data/test/server/group_test.rb +43 -0
- data/test/server/server_test.rb +511 -0
- data/test/shared/adapters/adapter_test.rb +22 -0
- data/test/shared/adapters/cucumber_adapter_test.rb +72 -0
- data/test/shared/adapters/helpers/ruby_env_test.rb +108 -0
- data/test/shared/adapters/rspec_adapter_test.rb +109 -0
- data/test/shared/testbot_test.rb +185 -0
- data/testbot.gemspec +34 -0
- metadata +313 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
class Adapter
|
2
|
+
|
3
|
+
FILES = Dir[File.dirname(__FILE__) + "/*_adapter.rb"]
|
4
|
+
FILES.each { |file| require(file) }
|
5
|
+
|
6
|
+
def self.all
|
7
|
+
FILES.map { |file| load_adapter(file) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.find(type)
|
11
|
+
if adapter = all.find { |adapter| adapter.type == type.to_s }
|
12
|
+
adapter
|
13
|
+
else
|
14
|
+
raise "Unknown adapter: #{type}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def self.load_adapter(file)
|
21
|
+
eval("::" + File.basename(file).
|
22
|
+
gsub(/\.rb/, '').
|
23
|
+
gsub(/(?:^|_)(.)/) { $1.upcase })
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "/helpers/ruby_env"))
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "../color"))
|
3
|
+
|
4
|
+
class CucumberAdapter
|
5
|
+
|
6
|
+
def self.command(project_path, ruby_interpreter, files)
|
7
|
+
cucumber_command = RubyEnv.ruby_command(project_path, :script => "script/cucumber", :bin => "cucumber",
|
8
|
+
:ruby_interpreter => ruby_interpreter)
|
9
|
+
"export AUTOTEST=1; #{cucumber_command} -f progress --backtrace -r features/support -r features/step_definitions #{files} -t ~@disabled"
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.test_files(dir)
|
13
|
+
Dir["#{dir}/#{file_pattern}"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.get_sizes(files)
|
17
|
+
files.map { |file| File.stat(file).size }
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.requester_port
|
21
|
+
2230
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.pluralized
|
25
|
+
'features'
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.base_path
|
29
|
+
pluralized
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.name
|
33
|
+
'Cucumber'
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.type
|
37
|
+
pluralized
|
38
|
+
end
|
39
|
+
|
40
|
+
# This is an optional method. It gets passed the entire test result and summarizes it. See the tests.
|
41
|
+
def self.sum_results(text)
|
42
|
+
scenarios, steps = parse_scenarios_and_steps(text)
|
43
|
+
|
44
|
+
scenarios_line = "#{scenarios[:total]} scenarios (" + [
|
45
|
+
(Color.colorize("#{scenarios[:failed]} failed", :red) if scenarios[:failed] > 0),
|
46
|
+
(Color.colorize("#{scenarios[:undefined]} undefined", :orange) if scenarios[:undefined] > 0),
|
47
|
+
(Color.colorize("#{scenarios[:passed]} passed", :green) if scenarios[:passed] > 0)
|
48
|
+
].compact.join(', ') + ")"
|
49
|
+
|
50
|
+
steps_line = "#{steps[:total]} steps (" + [
|
51
|
+
(Color.colorize("#{steps[:failed]} failed", :red) if steps[:failed] > 0),
|
52
|
+
(Color.colorize("#{steps[:skipped]} skipped", :cyan) if steps[:skipped] > 0),
|
53
|
+
(Color.colorize("#{steps[:undefined]} undefined", :orange) if steps[:undefined] > 0),
|
54
|
+
(Color.colorize("#{steps[:passed]} passed", :green) if steps[:passed] > 0)
|
55
|
+
].compact.join(', ') + ")"
|
56
|
+
|
57
|
+
scenarios_line + "\n" + steps_line
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def self.parse_scenarios_and_steps(text)
|
63
|
+
results = {
|
64
|
+
:scenarios => { :total => 0, :passed => 0, :failed => 0, :undefined => 0 },
|
65
|
+
:steps => { :total => 0, :passed => 0, :failed => 0, :skipped => 0, :undefined => 0 }
|
66
|
+
}
|
67
|
+
|
68
|
+
Color.strip(text).split("\n").each do |line|
|
69
|
+
type = line.include?("scenarios") ? :scenarios : :steps
|
70
|
+
|
71
|
+
if match = line.match(/\((.+)\)/)
|
72
|
+
results[type][:total] += line.split.first.to_i
|
73
|
+
parse_status_counts(results[type], match[1])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
[ results[:scenarios], results[:steps] ]
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.parse_status_counts(results, status_counts)
|
81
|
+
status_counts.split(', ').each do |part|
|
82
|
+
results.keys.each do |key|
|
83
|
+
results[key] += part.split.first.to_i if part.include?(key.to_s)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.file_pattern
|
89
|
+
'**/**/*.feature'
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class RubyEnv
|
2
|
+
def self.bundler?(project_path)
|
3
|
+
gem_exists?("bundler") && File.exists?("#{project_path}/Gemfile")
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.gem_exists?(gem)
|
7
|
+
if Gem::Specification.respond_to?(:find_by_name)
|
8
|
+
Gem::Specification.find_by_name(gem)
|
9
|
+
else
|
10
|
+
# older depricated method
|
11
|
+
Gem.available?(gem)
|
12
|
+
end
|
13
|
+
rescue Gem::LoadError
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.ruby_command(project_path, opts = {})
|
18
|
+
ruby_interpreter = opts[:ruby_interpreter] || "ruby"
|
19
|
+
|
20
|
+
if opts[:script] && File.exists?("#{project_path}/#{opts[:script]}")
|
21
|
+
command = opts[:script]
|
22
|
+
elsif opts[:bin]
|
23
|
+
command = opts[:bin]
|
24
|
+
else
|
25
|
+
command = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
if bundler?(project_path)
|
29
|
+
"#{rvm_prefix(project_path)} #{ruby_interpreter} -S bundle exec #{command}".strip
|
30
|
+
else
|
31
|
+
"#{rvm_prefix(project_path)} #{ruby_interpreter} -S #{command}".strip
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.rvm_prefix(project_path)
|
36
|
+
if rvm?
|
37
|
+
rvmrc_path = File.join project_path, ".rvmrc"
|
38
|
+
if File.exists?(rvmrc_path)
|
39
|
+
File.read(rvmrc_path).to_s.strip + " exec"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.rvm?
|
45
|
+
system("rvm info") != nil
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "/helpers/ruby_env"))
|
2
|
+
|
3
|
+
class Rspec2Adapter
|
4
|
+
|
5
|
+
def self.command(project_path, ruby_interpreter, files)
|
6
|
+
spec_command = RubyEnv.ruby_command(project_path,
|
7
|
+
:bin => "rspec",
|
8
|
+
:ruby_interpreter => ruby_interpreter)
|
9
|
+
|
10
|
+
if File.exists?("#{project_path}/spec/spec.opts")
|
11
|
+
spec_command += " -O spec/spec.opts"
|
12
|
+
end
|
13
|
+
|
14
|
+
"export RSPEC_COLOR=true; #{spec_command} #{files}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.test_files(dir)
|
18
|
+
if ENV['SELENIUM_SPECS']
|
19
|
+
puts 'running selenium specs'
|
20
|
+
test_files = FileList['spec/selenium/**/*_spec.rb'] + FileList['vendor/plugins/*/spec_canvas/selenium/*_spec.rb']
|
21
|
+
elsif ENV['PLUGIN_SPECS']
|
22
|
+
puts 'running plugin specs'
|
23
|
+
test_files = FileList['vendor/plugins/*/spec_canvas/**/*_spec.rb'].exclude('vendor/plugins/*/spec_canvas/selenium/*_spec.rb') + FileList['spec/**/*_spec.rb'].exclude('spec/selenium/**/*_spec.rb')
|
24
|
+
:ew3else
|
25
|
+
puts 'normal pattern'
|
26
|
+
test_files = Dir["#{dir}/#{file_pattern}"]
|
27
|
+
end
|
28
|
+
test_files
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.get_sizes(files)
|
32
|
+
files.map { |file| File.stat(file).size }
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.requester_port
|
36
|
+
2299
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.pluralized
|
40
|
+
'specs'
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.base_path
|
44
|
+
"spec"
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.name
|
48
|
+
'RSpec2'
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.type
|
52
|
+
'rspec'
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def self.file_pattern
|
58
|
+
'**/**/*_spec.rb'
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "/helpers/ruby_env"))
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "../color"))
|
3
|
+
|
4
|
+
class RspecAdapter
|
5
|
+
|
6
|
+
def self.command(project_path, ruby_interpreter, files)
|
7
|
+
spec_command = RubyEnv.ruby_command(project_path, :script => "script/spec", :bin => "rspec",
|
8
|
+
:ruby_interpreter => ruby_interpreter)
|
9
|
+
if File.exists?("#{project_path}/spec/spec.opts")
|
10
|
+
spec_command += " -O spec/spec.opts"
|
11
|
+
end
|
12
|
+
|
13
|
+
"export RSPEC_COLOR=true; #{spec_command} #{files}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.test_files(dir)
|
17
|
+
Dir["#{dir}/#{file_pattern}"]
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.get_sizes(files)
|
21
|
+
files.map { |file| File.stat(file).size }
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.requester_port
|
25
|
+
2299
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.pluralized
|
29
|
+
'specs'
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.base_path
|
33
|
+
type
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.name
|
37
|
+
'RSpec'
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.type
|
41
|
+
'spec'
|
42
|
+
end
|
43
|
+
|
44
|
+
# This is an optional method. It gets passed the entire test result and summarizes it. See the tests.
|
45
|
+
def self.sum_results(results)
|
46
|
+
examples, failures, pending = 0, 0, 0
|
47
|
+
results.split("\n").each do |line|
|
48
|
+
line =~ /(\d+) examples?, (\d+) failures?(, (\d+) pending)?/
|
49
|
+
next unless $1
|
50
|
+
examples += $1.to_i
|
51
|
+
failures += $2.to_i
|
52
|
+
pending += $4.to_i
|
53
|
+
end
|
54
|
+
|
55
|
+
result = [ pluralize(examples, 'example'), pluralize(failures, 'failure'), (pending > 0 ? "#{pending} pending" : nil) ].compact.join(', ')
|
56
|
+
if failures == 0 && pending == 0
|
57
|
+
Color.colorize(result, :green)
|
58
|
+
elsif failures == 0 && pending > 0
|
59
|
+
Color.colorize(result, :orange)
|
60
|
+
else
|
61
|
+
Color.colorize(result, :red)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def self.pluralize(count, singular)
|
68
|
+
if count == 1
|
69
|
+
"#{count} #{singular}"
|
70
|
+
else
|
71
|
+
"#{count} #{singular}s"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.file_pattern
|
76
|
+
'**/**/*_spec.rb'
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "/helpers/ruby_env"))
|
2
|
+
|
3
|
+
class TestUnitAdapter
|
4
|
+
|
5
|
+
def self.command(project_path, ruby_interpreter, files)
|
6
|
+
ruby_command = RubyEnv.ruby_command(project_path, :ruby_interpreter => ruby_interpreter)
|
7
|
+
%{#{ruby_command} -Itest -e '%w(#{files}).each { |file| require(Dir.pwd + "/" + file) }'}
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.test_files(dir)
|
11
|
+
Dir["#{dir}/#{file_pattern}"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.get_sizes(files)
|
15
|
+
files.map { |file| File.stat(file).size }
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.requester_port
|
19
|
+
2231
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.pluralized
|
23
|
+
'tests'
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.base_path
|
27
|
+
type
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.name
|
31
|
+
'Test::Unit'
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.type
|
35
|
+
'test'
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def self.file_pattern
|
41
|
+
'**/**/*_test.rb'
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
data/lib/shared/color.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
class Color
|
2
|
+
def self.colorize(text, color)
|
3
|
+
colors = { :green => 32, :orange => 33, :red => 31, :cyan => 36 }
|
4
|
+
|
5
|
+
if colors[color]
|
6
|
+
"\033[#{colors[color]}m#{text}\033[0m"
|
7
|
+
else
|
8
|
+
raise "Color not implemented: #{color}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.strip(text)
|
13
|
+
text.gsub(/\e.+?m/, '')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'daemons'
|
3
|
+
|
4
|
+
class SimpleDaemonize
|
5
|
+
|
6
|
+
def self.start(proc, pid_path, app_name)
|
7
|
+
working_dir = Dir.pwd
|
8
|
+
|
9
|
+
group = Daemons::ApplicationGroup.new(app_name)
|
10
|
+
group.new_application(:mode => :none).start
|
11
|
+
|
12
|
+
File.open(pid_path, 'w') { |file| file.write(Process.pid) }
|
13
|
+
Dir.chdir(working_dir)
|
14
|
+
proc.call
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.stop(pid_path)
|
18
|
+
return unless File.exists?(pid_path)
|
19
|
+
pid = File.read(pid_path)
|
20
|
+
|
21
|
+
system "kill -9 #{pid} &> /dev/null"
|
22
|
+
system "rm #{pid_path} &> /dev/null"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'net/ssh'
|
3
|
+
|
4
|
+
class SSHTunnel
|
5
|
+
|
6
|
+
def initialize(host, user, local_port = 2288)
|
7
|
+
@host, @user, @local_port = host, user, local_port
|
8
|
+
end
|
9
|
+
|
10
|
+
def open
|
11
|
+
connect
|
12
|
+
|
13
|
+
start_time = Time.now
|
14
|
+
while true
|
15
|
+
break if @up
|
16
|
+
sleep 0.5
|
17
|
+
|
18
|
+
if Time.now - start_time > 5
|
19
|
+
puts "SSH connection failed, trying again..."
|
20
|
+
start_time = Time.now
|
21
|
+
connect
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def connect
|
27
|
+
@thread.kill! if @thread
|
28
|
+
@thread = Thread.new do
|
29
|
+
Net::SSH.start(@host, @user, { :timeout => 1 }) do |ssh|
|
30
|
+
ssh.forward.local(@local_port, 'localhost', Testbot::SERVER_PORT)
|
31
|
+
ssh.loop { @up = true }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '/version'))
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '/simple_daemonize'))
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '/adapters/adapter'))
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
module Testbot
|
7
|
+
require 'railtie' if defined?(Rails)
|
8
|
+
|
9
|
+
if ENV['INTEGRATION_TEST']
|
10
|
+
SERVER_PID = "/tmp/integration_test_testbot_server.pid"
|
11
|
+
RUNNER_PID = "/tmp/integration_test_testbot_runner.pid"
|
12
|
+
else
|
13
|
+
SERVER_PID = "/tmp/testbot_server.pid"
|
14
|
+
RUNNER_PID = "/tmp/testbot_runner.pid"
|
15
|
+
end
|
16
|
+
|
17
|
+
DEFAULT_WORKING_DIR = "/tmp/testbot"
|
18
|
+
DEFAULT_SERVER_PATH = "/tmp/testbot/#{ENV['USER']}"
|
19
|
+
DEFAULT_USER = "testbot"
|
20
|
+
DEFAULT_PROJECT = "project"
|
21
|
+
DEFAULT_RUNNER_USAGE = "100%"
|
22
|
+
SERVER_PORT = ENV['INTEGRATION_TEST'] ? 22880 : 2288
|
23
|
+
|
24
|
+
class CLI
|
25
|
+
|
26
|
+
def self.run(argv)
|
27
|
+
return false if argv == []
|
28
|
+
opts = parse_args(argv)
|
29
|
+
|
30
|
+
if opts[:help]
|
31
|
+
return false
|
32
|
+
elsif opts[:version]
|
33
|
+
puts "Testbot #{Testbot.version}"
|
34
|
+
elsif [ true, 'run', 'start' ].include?(opts[:server])
|
35
|
+
start_server(opts[:server])
|
36
|
+
elsif opts[:server] == 'stop'
|
37
|
+
stop('server', Testbot::SERVER_PID)
|
38
|
+
elsif [ true, 'run', 'start' ].include?(opts[:runner])
|
39
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '/../runner/runner'))
|
40
|
+
return false unless valid_runner_opts?(opts)
|
41
|
+
start_runner(opts)
|
42
|
+
elsif opts[:runner] == 'stop'
|
43
|
+
stop('runner', Testbot::RUNNER_PID)
|
44
|
+
elsif adapter = Adapter.all.find { |adapter| opts[adapter.type.to_sym] }
|
45
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '/../requester/requester'))
|
46
|
+
start_requester(opts, adapter)
|
47
|
+
end
|
48
|
+
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.parse_args(argv)
|
53
|
+
last_setter = nil
|
54
|
+
hash = {}
|
55
|
+
str = ''
|
56
|
+
argv.each_with_index do |arg, i|
|
57
|
+
if arg.include?('--')
|
58
|
+
str = ''
|
59
|
+
last_setter = arg.split('--').last.to_sym
|
60
|
+
hash[last_setter] = true if (i == argv.size - 1) || argv[i+1].include?('--')
|
61
|
+
else
|
62
|
+
str += ' ' + arg
|
63
|
+
hash[last_setter] = str.strip
|
64
|
+
end
|
65
|
+
end
|
66
|
+
hash
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.start_runner(opts)
|
70
|
+
stop('runner', Testbot::RUNNER_PID)
|
71
|
+
|
72
|
+
proc = lambda {
|
73
|
+
working_dir = opts[:working_dir] || Testbot::DEFAULT_WORKING_DIR
|
74
|
+
FileUtils.mkdir_p(working_dir)
|
75
|
+
Dir.chdir(working_dir)
|
76
|
+
runner = Runner::Runner.new(:server_host => opts[:connect],
|
77
|
+
:auto_update => opts[:auto_update], :max_instances => opts[:cpus],
|
78
|
+
:ssh_tunnel => opts[:ssh_tunnel], :server_user => opts[:user],
|
79
|
+
:max_jruby_instances => opts[:max_jruby_instances],
|
80
|
+
:dev_gem_root => opts[:dev_gem_root],
|
81
|
+
:wait_for_updated_gem => opts[:wait_for_updated_gem],
|
82
|
+
:jruby_opts => opts[:jruby_opts])
|
83
|
+
runner.run!
|
84
|
+
}
|
85
|
+
|
86
|
+
if opts[:runner] == 'run'
|
87
|
+
proc.call
|
88
|
+
else
|
89
|
+
puts "Testbot runner started (pid: #{Process.pid})"
|
90
|
+
SimpleDaemonize.start(proc, Testbot::RUNNER_PID, "testbot (runner)")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.start_server(type)
|
95
|
+
stop('server', Testbot::SERVER_PID)
|
96
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '/../server/server'))
|
97
|
+
|
98
|
+
if type == 'run'
|
99
|
+
Sinatra::Application.run! :environment => "production"
|
100
|
+
else
|
101
|
+
puts "Testbot server started (pid: #{Process.pid})"
|
102
|
+
SimpleDaemonize.start(lambda {
|
103
|
+
Sinatra::Application.run! :environment => "production"
|
104
|
+
}, Testbot::SERVER_PID, "testbot (server)")
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.stop(name, pid)
|
109
|
+
puts "Testbot #{name} stopped" if SimpleDaemonize.stop(pid)
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.start_requester(opts, adapter)
|
113
|
+
requester = Requester::Requester.new(:server_host => opts[:connect],
|
114
|
+
:rsync_path => opts[:rsync_path],
|
115
|
+
:rsync_ignores => opts[:rsync_ignores].to_s,
|
116
|
+
:available_runner_usage => nil,
|
117
|
+
:project => opts[:project],
|
118
|
+
:ssh_tunnel => opts[:ssh_tunnel], :server_user => opts[:user])
|
119
|
+
requester.run_tests(adapter, adapter.base_path)
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.valid_runner_opts?(opts)
|
123
|
+
opts[:connect].is_a?(String)
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.lib_path
|
127
|
+
File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Testbot
|
2
|
+
# Don't forget to update readme and changelog
|
3
|
+
def self.version
|
4
|
+
version = "0.7.8"
|
5
|
+
dev_version_file = File.join(File.dirname(__FILE__), '..', '..', 'DEV_VERSION')
|
6
|
+
if File.exists?(dev_version_file)
|
7
|
+
version += File.read(dev_version_file)
|
8
|
+
end
|
9
|
+
version
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../shared/adapters/adapter'
|
2
|
+
|
3
|
+
namespace :testbot do
|
4
|
+
|
5
|
+
def run_and_show_results(adapter, custom_path)
|
6
|
+
'testbot:before_request'.tap { |t| Rake::Task.task_defined?(t) && Rake::Task[t].invoke }
|
7
|
+
|
8
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'requester', 'requester.rb'))
|
9
|
+
requester = Testbot::Requester::Requester.create_by_config("#{Rails.root}/config/testbot.yml")
|
10
|
+
|
11
|
+
puts "Running #{adapter.pluralized}..."
|
12
|
+
start_time = Time.now
|
13
|
+
|
14
|
+
path = custom_path ? "#{adapter.base_path}/#{custom_path}" : adapter.base_path
|
15
|
+
success = requester.run_tests(adapter, path)
|
16
|
+
|
17
|
+
puts
|
18
|
+
puts "Finished in #{Time.now - start_time} seconds."
|
19
|
+
success
|
20
|
+
end
|
21
|
+
|
22
|
+
Adapter.all.each do |adapter|
|
23
|
+
|
24
|
+
desc "Run the #{adapter.name} tests using testbot"
|
25
|
+
task adapter.type, :custom_path do |_, args|
|
26
|
+
exit 1 unless run_and_show_results(adapter, args[:custom_path])
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/lib/testbot.rb
ADDED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|