rrrspec-client 0.2.0
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/.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
|