rrrspec-client 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/Rakefile +1 -0
- data/bin/rrrspec +13 -0
- data/bin/rrrspec-client +4 -0
- data/lib/rrrspec/client/cli.rb +131 -0
- data/lib/rrrspec/client/configuration.rb +82 -0
- data/lib/rrrspec/client/rspec_runner.rb +83 -0
- data/lib/rrrspec/client/slave_runner.rb +128 -0
- data/lib/rrrspec/client/support.rb +147 -0
- data/lib/rrrspec/client/version.rb +5 -0
- data/lib/rrrspec/client.rb +5 -0
- data/lib/rrrspec/configuration.rb +42 -0
- data/lib/rrrspec/redis_models.rb +1091 -0
- data/lib/rrrspec.rb +103 -0
- data/rrrspec-client.gemspec +37 -0
- data/spec/fixture.rb +32 -0
- data/spec/rrrspec/client/cli_spec.rb +45 -0
- data/spec/rrrspec/redis_models_spec.rb +34 -0
- data/spec/spec_helper.rb +54 -0
- metadata +225 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 187ea5b96b3437a7c839c23b3e5f1aa3df3b5716
|
4
|
+
data.tar.gz: d83a9df93ffa5ae672b5909e887a52173f6941ff
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c6583325da9e6865baca29415e524f662ecfcdf1a7d2be524b3769748855a20f6629cfe9dae6102bf035534fd4a314a4271e5ace84e421780e56ed5121d435af
|
7
|
+
data.tar.gz: b1f67aba5e30a24d1ee5dad72ae4dc15587d5b25470546c29ebc290be512c3b63743ae43a1b3e630619abb1b9d1308563ad2d0347d8ed7c9cc004431e611a93e
|
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0-p247
|
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/rrrspec
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
case ARGV[0]
|
4
|
+
when "server", "worker"
|
5
|
+
require 'rrrspec/server/cli'
|
6
|
+
RRRSpec::Server::CLI.start
|
7
|
+
when "scaler", "scalerspy"
|
8
|
+
require 'rrrspec/scaler/cli'
|
9
|
+
RRRSpec::Scaler::CLI.start
|
10
|
+
else
|
11
|
+
require 'rrrspec/client/cli'
|
12
|
+
RRRSpec::Client::CLI.start
|
13
|
+
end
|
data/bin/rrrspec-client
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'rrrspec/client'
|
2
|
+
require 'launchy'
|
3
|
+
require 'thor'
|
4
|
+
|
5
|
+
module RRRSpec
|
6
|
+
module Client
|
7
|
+
class CLI < Thor
|
8
|
+
WAIT_POLLING_SEC = 10
|
9
|
+
|
10
|
+
package_name 'RRRSpec'
|
11
|
+
default_command 'help'
|
12
|
+
class_option :config, aliases: '-c', type: :string, default: ''
|
13
|
+
|
14
|
+
no_commands do
|
15
|
+
def setup(conf)
|
16
|
+
RRRSpec.setup(conf, options[:config].split(':'))
|
17
|
+
end
|
18
|
+
|
19
|
+
def log_exception
|
20
|
+
yield
|
21
|
+
rescue
|
22
|
+
RRRSpec.logger.error($!)
|
23
|
+
raise
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
option :'key-only', type: :boolean
|
28
|
+
option :'rsync-name', type: :string, default: ENV['USER']
|
29
|
+
option :'worker-type', type: :string
|
30
|
+
desc 'start', 'start RRRSpec'
|
31
|
+
def start
|
32
|
+
setup(ClientConfiguration.new)
|
33
|
+
if options[:'worker-type']
|
34
|
+
RRRSpec.configuration.worker_type = options[:'worker-type']
|
35
|
+
end
|
36
|
+
taskset = Support.start_taskset(RRRSpec.configuration, options[:'rsync-name'])
|
37
|
+
puts taskset.key
|
38
|
+
|
39
|
+
if RRRSpec.configuration.rrrspec_web_base && !options[:'key-only']
|
40
|
+
url = "#{RRRSpec.configuration.rrrspec_web_base}/tasksets/#{taskset.key}"
|
41
|
+
Launchy.open(url)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'cancel', 'cancel the taskset'
|
46
|
+
def cancel(taskset_id)
|
47
|
+
setup(Configuration.new)
|
48
|
+
taskset = Taskset.new(taskset_id)
|
49
|
+
exit(1) unless taskset.exist?
|
50
|
+
taskset.cancel
|
51
|
+
end
|
52
|
+
|
53
|
+
desc 'cancelall', 'cancel all tasksets whose rsync name is specified name'
|
54
|
+
def cancelall(rsync_name)
|
55
|
+
setup(Configuration.new)
|
56
|
+
ActiveTaskset.all_tasksets_of(rsync_name).each do |taskset|
|
57
|
+
taskset.cancel
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
desc 'actives', 'list up the active tasksets'
|
62
|
+
def actives
|
63
|
+
setup(Configuration.new)
|
64
|
+
ActiveTaskset.list.each { |taskset| puts taskset.key }
|
65
|
+
end
|
66
|
+
|
67
|
+
desc 'nodes', 'list up the active nodes'
|
68
|
+
def nodes
|
69
|
+
setup(Configuration.new)
|
70
|
+
puts "Server:"
|
71
|
+
puts "\t#{RSyncInfo.exist? ? "Yes" : "No"}"
|
72
|
+
puts "Workers:"
|
73
|
+
Worker.list.each { |worker| puts "\t#{worker.key}" }
|
74
|
+
end
|
75
|
+
|
76
|
+
option :pollsec, type: :numeric, default: WAIT_POLLING_SEC
|
77
|
+
desc 'waitfor', 'wait for the taskset'
|
78
|
+
def waitfor(taskset_id)
|
79
|
+
setup(Configuration.new)
|
80
|
+
taskset = Taskset.new(taskset_id)
|
81
|
+
exit(1) unless taskset.exist?
|
82
|
+
|
83
|
+
rd, wt = IO.pipe
|
84
|
+
Signal.trap(:TERM) { wt.write("1") }
|
85
|
+
Signal.trap(:INT) { wt.write("1") }
|
86
|
+
|
87
|
+
loop do
|
88
|
+
rs, ws, = IO.select([rd], [], [], options[:pollsec])
|
89
|
+
if rs == nil
|
90
|
+
break if taskset.persisted?
|
91
|
+
elsif rs.size != 0
|
92
|
+
rs[0].getc
|
93
|
+
taskset.cancel
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
option :'failure-exit-code', type: :numeric, default: 1
|
99
|
+
option :verbose, type: :boolean, default: false
|
100
|
+
desc 'show', 'show the result of the taskset'
|
101
|
+
def show(taskset_id)
|
102
|
+
setup(Configuration.new)
|
103
|
+
taskset = Taskset.new(taskset_id)
|
104
|
+
exit 1 unless taskset.exist?
|
105
|
+
Support.show_result(taskset, options[:verbose])
|
106
|
+
|
107
|
+
if taskset.status != 'succeeded'
|
108
|
+
exit options[:'failure-exit-code']
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
desc 'slave', 'run RRRSpec as a slave'
|
113
|
+
def slave(working_dir=nil, taskset_key=nil)
|
114
|
+
$0 = 'rrrspec slave'
|
115
|
+
working_dir ||= ENV['RRRSPEC_WORKING_DIR']
|
116
|
+
taskset_key ||= ENV['RRRSPEC_TASKSET_KEY']
|
117
|
+
exit 1 unless taskset_key && working_dir
|
118
|
+
|
119
|
+
setup(Configuration.new)
|
120
|
+
log_exception do
|
121
|
+
slave = Slave.create
|
122
|
+
slave_runner = SlaveRunner.new(slave, working_dir, taskset_key)
|
123
|
+
Thread.abort_on_exception = true
|
124
|
+
Thread.fork { RRRSpec.pacemaker(slave, 60, 5) }
|
125
|
+
Thread.fork { slave_runner.work_loop }
|
126
|
+
Kernel.sleep
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module RRRSpec
|
2
|
+
module Client
|
3
|
+
class ClientConfiguration < Configuration
|
4
|
+
attr_accessor :packaging_dir
|
5
|
+
attr_accessor :packaging_rsync_options
|
6
|
+
attr_writer :spec_files
|
7
|
+
attr_accessor :setup_command, :slave_command
|
8
|
+
attr_accessor :taskset_class, :worker_type
|
9
|
+
attr_accessor :max_workers, :max_trials
|
10
|
+
attr_accessor :rrrspec_web_base
|
11
|
+
attr_accessor :unknown_spec_timeout_sec, :least_timeout_sec
|
12
|
+
|
13
|
+
def spec_files
|
14
|
+
case @spec_files
|
15
|
+
when Proc then @spec_files.call
|
16
|
+
when String then [@spec_files]
|
17
|
+
else @spec_files
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
super()
|
23
|
+
@type = :client
|
24
|
+
@unknown_spec_timeout_sec = 5 * 60
|
25
|
+
@least_timeout_sec = 30
|
26
|
+
end
|
27
|
+
|
28
|
+
def check_validity
|
29
|
+
validity = super
|
30
|
+
|
31
|
+
unless Dir.exists?(packaging_dir)
|
32
|
+
$stderr.puts("The packaging_dir does not exists: '#{packaging_dir}'")
|
33
|
+
validity = false
|
34
|
+
end
|
35
|
+
|
36
|
+
unless spec_files.is_a?(Array)
|
37
|
+
$stderr.puts("The spec_files should be an Array: '#{spec_files}'")
|
38
|
+
validity = false
|
39
|
+
else
|
40
|
+
spec_files.each do |filepath|
|
41
|
+
unless File.exists?(File.join(packaging_dir, filepath))
|
42
|
+
$stderr.puts("One of the spec_files does not exists '#{filepath}'")
|
43
|
+
validity = false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
unless max_workers.is_a?(Integer)
|
49
|
+
$stderr.puts("The max_workers should be an Integer: '#{max_workers}'")
|
50
|
+
validity = false
|
51
|
+
else
|
52
|
+
unless max_workers >= 1
|
53
|
+
$stderr.puts("The max_workers should not be less than 1: #{max_workers}")
|
54
|
+
validity = false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
unless max_trials.is_a?(Integer)
|
59
|
+
$stderr.puts("The max_trials should be an Integer: '#{max_trials}'")
|
60
|
+
validity = false
|
61
|
+
end
|
62
|
+
|
63
|
+
unless taskset_class.is_a?(String)
|
64
|
+
$stderr.puts("The taskset_class should be a String: '#{taskset_class}'")
|
65
|
+
validity = false
|
66
|
+
end
|
67
|
+
|
68
|
+
unless unknown_spec_timeout_sec.is_a?(Integer)
|
69
|
+
$stderr.puts("The unknown_spec_timeout_sec should be an Integer: '#{unknown_spec_timeout_sec}'")
|
70
|
+
validity = false
|
71
|
+
end
|
72
|
+
|
73
|
+
unless least_timeout_sec.is_a?(Integer)
|
74
|
+
$stderr.puts("The least_timeout_sec should be an Integer: '#{least_timeout_sec}'")
|
75
|
+
validity = false
|
76
|
+
end
|
77
|
+
|
78
|
+
validity
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'rspec/core/formatters/base_text_formatter'
|
3
|
+
|
4
|
+
module RRRSpec
|
5
|
+
module Client
|
6
|
+
class RSpecRunner
|
7
|
+
def initialize
|
8
|
+
@options = RSpec::Core::ConfigurationOptions.new([])
|
9
|
+
@options.parse_options
|
10
|
+
@configuration = RSpec.configuration
|
11
|
+
@configuration.setup_load_path_and_require([])
|
12
|
+
@world = RSpec.world
|
13
|
+
@before_suite_run = false
|
14
|
+
end
|
15
|
+
|
16
|
+
def exc_safe_replace_stdouts
|
17
|
+
outbuf = ''
|
18
|
+
errbuf = ''
|
19
|
+
$stdout = StringIO.new(outbuf)
|
20
|
+
$stderr = StringIO.new(errbuf)
|
21
|
+
begin
|
22
|
+
yield
|
23
|
+
rescue Exception
|
24
|
+
$stdout.puts $!
|
25
|
+
$stdout.puts $!.backtrace.join("\n")
|
26
|
+
end
|
27
|
+
[outbuf, errbuf]
|
28
|
+
ensure
|
29
|
+
$stdout = STDOUT
|
30
|
+
$stderr = STDERR
|
31
|
+
end
|
32
|
+
|
33
|
+
def setup(filepath)
|
34
|
+
status = false
|
35
|
+
outbuf, errbuf = exc_safe_replace_stdouts do
|
36
|
+
begin
|
37
|
+
@options.configure(@configuration)
|
38
|
+
@configuration.files_to_run = [filepath]
|
39
|
+
@configuration.load_spec_files
|
40
|
+
@world.announce_filters
|
41
|
+
unless @before_suite_run
|
42
|
+
@configuration.run_hook(:before, :suite)
|
43
|
+
@before_suite_run = true
|
44
|
+
end
|
45
|
+
status = true
|
46
|
+
rescue Exception
|
47
|
+
$stdout.puts $!
|
48
|
+
$stdout.puts $!.backtrace.join("\n")
|
49
|
+
status = false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
[status, outbuf, errbuf]
|
54
|
+
end
|
55
|
+
|
56
|
+
def run(*formatters)
|
57
|
+
status = false
|
58
|
+
outbuf, errbuf = exc_safe_replace_stdouts do
|
59
|
+
@configuration.formatters << RSpec::Core::Formatters::BaseTextFormatter.new($stdout)
|
60
|
+
formatters.each do |formatter|
|
61
|
+
@configuration.formatters << formatter
|
62
|
+
end
|
63
|
+
@configuration.reporter.report(
|
64
|
+
@world.example_count,
|
65
|
+
@configuration.randomize? ? @configuration.seed : nil
|
66
|
+
) do |reporter|
|
67
|
+
@world.example_groups.ordered.each do |example_group|
|
68
|
+
example_group.run(reporter)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
status = true
|
72
|
+
end
|
73
|
+
|
74
|
+
[status, outbuf, errbuf]
|
75
|
+
end
|
76
|
+
|
77
|
+
def reset
|
78
|
+
@world.example_groups.clear
|
79
|
+
@configuration.reset
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'extreme_timeout'
|
3
|
+
require 'timeout'
|
4
|
+
|
5
|
+
module RRRSpec
|
6
|
+
module Client
|
7
|
+
class SlaveRunner
|
8
|
+
attr_reader :key
|
9
|
+
|
10
|
+
TASKQUEUE_TASK_TIMEOUT = -1
|
11
|
+
TASKQUEUE_ARBITER_TIMEOUT = 20
|
12
|
+
TIMEOUT_EXITCODE = 42
|
13
|
+
class SoftTimeoutException < Exception; end
|
14
|
+
|
15
|
+
def initialize(slave, working_dir, taskset_key)
|
16
|
+
@slave = slave
|
17
|
+
@taskset = Taskset.new(taskset_key)
|
18
|
+
@timeout = TASKQUEUE_TASK_TIMEOUT
|
19
|
+
@rspec_runner = RSpecRunner.new
|
20
|
+
@working_path = File.join(working_dir, @taskset.rsync_name)
|
21
|
+
@unknown_spec_timeout_sec = @taskset.unknown_spec_timeout_sec
|
22
|
+
@least_timeout_sec = @taskset.least_timeout_sec
|
23
|
+
@worked_task_keys = Set.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def work_loop
|
27
|
+
loop { work }
|
28
|
+
end
|
29
|
+
|
30
|
+
def spec_timeout_sec(task)
|
31
|
+
if task.estimate_sec == nil
|
32
|
+
soft_timeout_sec = @unknown_spec_timeout_sec
|
33
|
+
hard_timeout_sec = @unknown_spec_timeout_sec + 30
|
34
|
+
else
|
35
|
+
estimate_sec = task.estimate_sec
|
36
|
+
soft_timeout_sec = estimate_sec * 2
|
37
|
+
hard_timeout_sec = estimate_sec * 3
|
38
|
+
end
|
39
|
+
return [soft_timeout_sec, @least_timeout_sec].max, [hard_timeout_sec, @least_timeout_sec].max
|
40
|
+
end
|
41
|
+
|
42
|
+
def work
|
43
|
+
task = @taskset.dequeue_task(@timeout)
|
44
|
+
unless task
|
45
|
+
@timeout = TASKQUEUE_ARBITER_TIMEOUT
|
46
|
+
ArbiterQueue.check(@taskset)
|
47
|
+
else
|
48
|
+
@timeout = TASKQUEUE_TASK_TIMEOUT
|
49
|
+
if @worked_task_keys.include?(task.key)
|
50
|
+
@taskset.reversed_enqueue_task(task)
|
51
|
+
return
|
52
|
+
else
|
53
|
+
@worked_task_keys << task.key
|
54
|
+
end
|
55
|
+
|
56
|
+
return if task.status.present?
|
57
|
+
trial = Trial.create(task, @slave)
|
58
|
+
|
59
|
+
@rspec_runner.reset
|
60
|
+
status, outbuf, errbuf = @rspec_runner.setup(File.join(@working_path, task.spec_file))
|
61
|
+
unless status
|
62
|
+
trial.finish('error', outbuf, errbuf, nil, nil, nil)
|
63
|
+
ArbiterQueue.trial(trial)
|
64
|
+
return
|
65
|
+
end
|
66
|
+
|
67
|
+
soft_timeout_sec, hard_timeout_sec = spec_timeout_sec(task)
|
68
|
+
|
69
|
+
formatter = RedisReportingFormatter.new
|
70
|
+
trial.start
|
71
|
+
status, outbuf, errbuf = ExtremeTimeout::timeout(
|
72
|
+
hard_timeout_sec, TIMEOUT_EXITCODE
|
73
|
+
) do
|
74
|
+
Timeout::timeout(soft_timeout_sec, SoftTimeoutException) do
|
75
|
+
@rspec_runner.run(formatter)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
if status
|
79
|
+
trial.finish(formatter.status, outbuf, errbuf,
|
80
|
+
formatter.passed, formatter.pending, formatter.failed)
|
81
|
+
else
|
82
|
+
trial.finish('error', outbuf, errbuf, nil, nil, nil)
|
83
|
+
end
|
84
|
+
|
85
|
+
ArbiterQueue.trial(trial)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class RedisReportingFormatter
|
90
|
+
attr_reader :passed, :pending, :failed
|
91
|
+
|
92
|
+
def initialize
|
93
|
+
@passed = 0
|
94
|
+
@pending = 0
|
95
|
+
@failed = 0
|
96
|
+
@timeout = false
|
97
|
+
end
|
98
|
+
|
99
|
+
def example_passed(example)
|
100
|
+
@passed += 1
|
101
|
+
end
|
102
|
+
|
103
|
+
def example_pending(example)
|
104
|
+
@pending += 1
|
105
|
+
end
|
106
|
+
|
107
|
+
def example_failed(example)
|
108
|
+
@failed += 1
|
109
|
+
if example.exception.is_a?(SoftTimeoutException)
|
110
|
+
@timeout = true
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def status
|
115
|
+
if @timeout
|
116
|
+
'timeout'
|
117
|
+
elsif @failed != 0
|
118
|
+
'failed'
|
119
|
+
elsif @pending != 0
|
120
|
+
'pending'
|
121
|
+
else
|
122
|
+
'passed'
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module RRRSpec
|
2
|
+
module Client
|
3
|
+
module Support
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def start_taskset(conf, rsync_name)
|
7
|
+
$stderr.puts '1/3) Making a package...'
|
8
|
+
if is_using_rsync?(rsync_name)
|
9
|
+
$stderr.puts 'It seems you are running rrrspec already'
|
10
|
+
$stderr.puts 'Please wait until the previous run finishes'
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
unless run_rsync_package(rsync_name)
|
14
|
+
$stderr.puts 'rsync failed.'
|
15
|
+
exit 1
|
16
|
+
end
|
17
|
+
|
18
|
+
$stderr.puts '2/3) Uploading the package...'
|
19
|
+
taskset = Taskset.create(
|
20
|
+
rsync_name,
|
21
|
+
conf.setup_command,
|
22
|
+
conf.slave_command,
|
23
|
+
conf.worker_type,
|
24
|
+
conf.taskset_class,
|
25
|
+
conf.max_workers,
|
26
|
+
conf.max_trials,
|
27
|
+
conf.unknown_spec_timeout_sec,
|
28
|
+
conf.least_timeout_sec
|
29
|
+
)
|
30
|
+
estimate_sec_sorted(conf.taskset_class, conf.spec_files.uniq).reverse_each do |spec_file, estimate_sec|
|
31
|
+
task = Task.create(taskset, estimate_sec, spec_file)
|
32
|
+
taskset.add_task(task)
|
33
|
+
taskset.enqueue_task(task)
|
34
|
+
end
|
35
|
+
|
36
|
+
$stderr.puts '3/3) Enqueue the taskset...'
|
37
|
+
ActiveTaskset.add(taskset)
|
38
|
+
DispatcherQueue.notify
|
39
|
+
$stderr.puts 'Your request is successfully enqueued!'
|
40
|
+
return taskset
|
41
|
+
end
|
42
|
+
|
43
|
+
def show_result(taskset, verbose=false)
|
44
|
+
puts "Status: #{taskset.status}"
|
45
|
+
puts "Created: #{taskset.created_at}"
|
46
|
+
puts "Finished: #{taskset.finished_at}"
|
47
|
+
puts "Tasks: #{taskset.task_size}"
|
48
|
+
puts "Succeeded: #{taskset.succeeded_count}"
|
49
|
+
puts "Failed: #{taskset.failed_count}"
|
50
|
+
|
51
|
+
if verbose
|
52
|
+
puts
|
53
|
+
|
54
|
+
puts "Log:"
|
55
|
+
taskset.log.split("\n").each { |line| puts "\t#{line}" }
|
56
|
+
puts
|
57
|
+
|
58
|
+
puts "Workers:"
|
59
|
+
taskset.worker_logs.each do |worker_log|
|
60
|
+
puts "\tKey: #{worker_log.key}"
|
61
|
+
puts "\tStarted: #{worker_log.started_at}"
|
62
|
+
puts "\tRSync Finished: #{worker_log.rsync_finished_at}"
|
63
|
+
puts "\tSetup Finished: #{worker_log.setup_finished_at}"
|
64
|
+
puts "\tFinished: #{worker_log.finished_at}"
|
65
|
+
puts "\tLog:"
|
66
|
+
worker_log.log.split("\n").each { |line| puts "\t\t#{line}" }
|
67
|
+
end
|
68
|
+
puts
|
69
|
+
|
70
|
+
puts "Slaves:"
|
71
|
+
taskset.slaves.each do |slave|
|
72
|
+
puts "\tKey: #{slave.key}"
|
73
|
+
puts "\tStatus: #{slave.status}"
|
74
|
+
puts "\tTrials:"
|
75
|
+
slave.trials.each do |trial|
|
76
|
+
puts "\t\t#{trial.key}"
|
77
|
+
end
|
78
|
+
puts "\tLog:"
|
79
|
+
slave.log.split("\n").each { |line| puts "\t\t#{line}" }
|
80
|
+
end
|
81
|
+
puts
|
82
|
+
|
83
|
+
puts "Tasks:"
|
84
|
+
taskset.tasks.each do |task|
|
85
|
+
puts "\tKey: #{task.key}"
|
86
|
+
puts "\tSpec: #{task.spec_file}"
|
87
|
+
puts "\tStatus: #{task.status}"
|
88
|
+
puts "\tTrials:"
|
89
|
+
task.trials.each do |trial|
|
90
|
+
puts "\t\tKey: #{trial.key}"
|
91
|
+
puts "\t\tSlave: #{trial.slave.key}"
|
92
|
+
puts "\t\tStatus: #{trial.status}"
|
93
|
+
puts "\t\tStarted: #{trial.started_at}"
|
94
|
+
puts "\t\tFinished: #{trial.finished_at}"
|
95
|
+
puts "\t\tPassed: #{trial.passed}"
|
96
|
+
puts "\t\tPending: #{trial.pending}"
|
97
|
+
puts "\t\tFailed: #{trial.failed}"
|
98
|
+
stdout = trial.stdout
|
99
|
+
if stdout
|
100
|
+
puts "\t\tSTDOUT:"
|
101
|
+
stdout.split("\n").each { |line| puts "\t\t\t#{line}" }
|
102
|
+
end
|
103
|
+
stderr = trial.stderr
|
104
|
+
if stderr
|
105
|
+
puts "\t\tSTDERR:"
|
106
|
+
stderr.split("\n").each { |line| puts "\t\t\t#{line}" }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def run_rsync_package(rsync_name)
|
114
|
+
conf = RRRSpec.configuration
|
115
|
+
remote_dir = File.join(RSyncInfo.rsync_dir, rsync_name)
|
116
|
+
remote_path = "#{RSyncInfo.rsync_server}:#{remote_dir}"
|
117
|
+
command = "rsync #{conf.packaging_rsync_options} #{conf.packaging_dir}/ #{remote_path}"
|
118
|
+
$stderr.puts command
|
119
|
+
system(command)
|
120
|
+
$?.success?
|
121
|
+
end
|
122
|
+
|
123
|
+
def is_using_rsync?(rsync_name)
|
124
|
+
ActiveTaskset.list.any? do |taskset|
|
125
|
+
taskset.rsync_name == rsync_name
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Public: Sort the spec filepaths by their estiamted spec execution times.
|
130
|
+
#
|
131
|
+
# Returns an array of [spec_file, estiamte_sec]
|
132
|
+
def estimate_sec_sorted(taskset_class, spec_files)
|
133
|
+
estimate_secs = TasksetEstimation.estimate_secs(taskset_class)
|
134
|
+
spec_files.map do |spec_file|
|
135
|
+
[spec_file, estimate_secs[spec_file]]
|
136
|
+
end.sort do |a, b|
|
137
|
+
case
|
138
|
+
when a[1] == nil && b[1] == nil then 0
|
139
|
+
when a[1] == nil && b[1] != nil then 1
|
140
|
+
when a[1] != nil && b[1] == nil then -1
|
141
|
+
else a[1] - b[1]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module RRRSpec
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :loaded
|
4
|
+
attr_reader :type
|
5
|
+
|
6
|
+
def redis=(arg)
|
7
|
+
@redis_value = arg
|
8
|
+
end
|
9
|
+
|
10
|
+
def redis
|
11
|
+
case @redis_value
|
12
|
+
when Hash then Redis.new(@redis_value)
|
13
|
+
when Proc then @redis_value.call
|
14
|
+
else @redis_value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def check_validity
|
19
|
+
validity = true
|
20
|
+
|
21
|
+
unless @redis_value
|
22
|
+
$stderr.puts("Redis configuration is empty")
|
23
|
+
validity = false
|
24
|
+
end
|
25
|
+
|
26
|
+
validity
|
27
|
+
end
|
28
|
+
|
29
|
+
def load_files(files)
|
30
|
+
loaded = []
|
31
|
+
files.each do |filepath|
|
32
|
+
filepath = File.absolute_path(filepath)
|
33
|
+
next unless File.exists?(filepath)
|
34
|
+
$stderr.puts("Loading: #{filepath}")
|
35
|
+
load filepath
|
36
|
+
loaded << filepath
|
37
|
+
end
|
38
|
+
|
39
|
+
RRRSpec.configuration.loaded = loaded
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|