Bootstrap Rubocop configuration and fix offenses
This commit is contained in:
parent
22e3f7c267
commit
6f0077a60e
|
@ -0,0 +1,49 @@
|
|||
AllCops:
|
||||
NewCops: enable
|
||||
|
||||
Metrics:
|
||||
Enabled: false
|
||||
|
||||
Style/WordArray:
|
||||
EnforcedStyle: brackets
|
||||
|
||||
Style/StringLiterals:
|
||||
EnforcedStyle: double_quotes
|
||||
|
||||
Style/GlobalVars:
|
||||
Exclude:
|
||||
- test/sample_suites/flakey_suite/**/*.rb
|
||||
- test/sample_suites/flaky_job_detection/**/*.rb
|
||||
|
||||
Style/SpecialGlobalVars:
|
||||
Enabled: false
|
||||
|
||||
Style/IfUnlessModifier:
|
||||
Enabled: false
|
||||
|
||||
Style/GuardClause:
|
||||
Enabled: false
|
||||
|
||||
Style/TrailingCommaInArrayLiteral:
|
||||
Enabled: false
|
||||
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: false
|
||||
|
||||
Style/NegatedIf:
|
||||
Enabled: false
|
||||
|
||||
Style/NumericPredicate:
|
||||
Enabled: false
|
||||
|
||||
Layout/FirstArrayElementIndentation:
|
||||
Enabled: false
|
||||
|
||||
Layout/ArgumentAlignment:
|
||||
Enabled: false
|
||||
|
||||
Gemspec/RequiredRubyVersion:
|
||||
Enabled: false
|
||||
|
||||
Naming/MethodParameterName:
|
||||
Enabled: false
|
2
Rakefile
2
Rakefile
|
@ -2,7 +2,7 @@ require "rake/testtask"
|
|||
|
||||
Rake::TestTask.new do |t|
|
||||
t.libs << "test"
|
||||
t.test_files = FileList['test/test_*.rb']
|
||||
t.test_files = FileList["test/test_*.rb"]
|
||||
t.verbose = true
|
||||
end
|
||||
|
||||
|
|
12
bin/rspecq
12
bin/rspecq
|
@ -2,7 +2,7 @@
|
|||
require "optparse"
|
||||
require "rspecq"
|
||||
|
||||
DEFAULT_REDIS_HOST = "127.0.0.1"
|
||||
DEFAULT_REDIS_HOST = "127.0.0.1".freeze
|
||||
DEFAULT_REPORT_TIMEOUT = 3600 # 1 hour
|
||||
DEFAULT_MAX_REQUEUES = 3
|
||||
DEFAULT_FAIL_FAST = 0
|
||||
|
@ -66,7 +66,7 @@ OptionParser.new do |o|
|
|||
|
||||
o.on("--report", "Enable reporter mode: do not pull tests off the queue; " \
|
||||
"instead print build progress and exit when it's " \
|
||||
"finished.\n#{o.summary_indent*9} " \
|
||||
"finished.\n#{o.summary_indent * 9} " \
|
||||
"Exits with a non-zero status code if there were any " \
|
||||
"failures.") do |v|
|
||||
opts[:report] = v
|
||||
|
@ -85,7 +85,7 @@ OptionParser.new do |o|
|
|||
end
|
||||
|
||||
o.on("--fail-fast N", Integer, "Abort build with a non-zero status code " \
|
||||
"after N failed examples." ) do |v|
|
||||
"after N failed examples.") do |v|
|
||||
opts[:fail_fast] = v
|
||||
end
|
||||
|
||||
|
@ -104,15 +104,17 @@ opts[:build] ||= ENV["RSPECQ_BUILD"]
|
|||
opts[:worker] ||= ENV["RSPECQ_WORKER"]
|
||||
opts[:redis_host] ||= ENV["RSPECQ_REDIS"] || DEFAULT_REDIS_HOST
|
||||
opts[:timings] ||= env_set?("RSPECQ_UPDATE_TIMINGS")
|
||||
opts[:file_split_threshold] ||= Integer(ENV["RSPECQ_FILE_SPLIT_THRESHOLD"] || 9999999)
|
||||
opts[:file_split_threshold] ||= Integer(ENV["RSPECQ_FILE_SPLIT_THRESHOLD"] || 9_999_999)
|
||||
opts[:report] ||= env_set?("RSPECQ_REPORT")
|
||||
opts[:report_timeout] ||= Integer(ENV["RSPECQ_REPORT_TIMEOUT"] || DEFAULT_REPORT_TIMEOUT)
|
||||
opts[:max_requeues] ||= Integer(ENV["RSPECQ_MAX_REQUEUES"] || DEFAULT_MAX_REQUEUES)
|
||||
opts[:redis_url] ||= ENV["RSPECQ_REDIS_URL"]
|
||||
opts[:fail_fast] ||= Integer(ENV["RSPECQ_FAIL_FAST"] || DEFAULT_FAIL_FAST)
|
||||
|
||||
# rubocop:disable Style/RaiseArgs, Layout/EmptyLineAfterGuardClause
|
||||
raise OptionParser::MissingArgument.new(:build) if opts[:build].nil?
|
||||
raise OptionParser::MissingArgument.new(:worker) if !opts[:report] && opts[:worker].nil?
|
||||
# rubocop:enable Style/RaiseArgs, Layout/EmptyLineAfterGuardClause
|
||||
|
||||
redis_opts = {}
|
||||
|
||||
|
@ -126,7 +128,7 @@ if opts[:report]
|
|||
reporter = RSpecQ::Reporter.new(
|
||||
build_id: opts[:build],
|
||||
timeout: opts[:report_timeout],
|
||||
redis_opts: redis_opts,
|
||||
redis_opts: redis_opts
|
||||
)
|
||||
|
||||
reporter.report
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
module RSpecQ
|
||||
module Formatters
|
||||
# Persists failed examples information (i.e. message and backtrace), so
|
||||
# that they can be reported to the end user by the Reporter.
|
||||
#
|
||||
# Also persists non-example error information (e.g. a syntax error that
|
||||
# in a spec file).
|
||||
class FailureRecorder
|
||||
def initialize(queue, job, max_requeues)
|
||||
@queue = queue
|
||||
|
@ -33,16 +38,19 @@ module RSpecQ
|
|||
end
|
||||
|
||||
presenter = RSpec::Core::Formatters::ExceptionPresenter.new(
|
||||
example.exception, example)
|
||||
example.exception, example
|
||||
)
|
||||
|
||||
msg = presenter.fully_formatted(nil, @colorizer)
|
||||
msg << "\n"
|
||||
msg << @colorizer.wrap(
|
||||
"bin/rspec #{example.location_rerun_argument}",
|
||||
RSpec.configuration.failure_color)
|
||||
RSpec.configuration.failure_color
|
||||
)
|
||||
|
||||
msg << @colorizer.wrap(
|
||||
" # #{example.full_description}", RSpec.configuration.detail_color)
|
||||
" # #{example.full_description}", RSpec.configuration.detail_color
|
||||
)
|
||||
|
||||
@queue.record_example_failure(notification.example.id, msg)
|
||||
end
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
module RSpecQ
|
||||
module Formatters
|
||||
# Persists each job's timing (in seconds). Those timings are used when
|
||||
# determining the ordering in which jobs are scheduled (slower jobs will
|
||||
# be enqueued first).
|
||||
class JobTimingRecorder
|
||||
def initialize(queue, job)
|
||||
@queue = queue
|
||||
|
|
|
@ -14,4 +14,3 @@ module RSpecQ
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ module RSpecQ
|
|||
# NOTE: jobs will be processed from head to tail (lpop)
|
||||
def publish(jobs, fail_fast = 0)
|
||||
@redis.multi do
|
||||
@redis.hset(key_queue_config, 'fail_fast', fail_fast)
|
||||
@redis.hset(key_queue_config, "fail_fast", fail_fast)
|
||||
@redis.rpush(key_queue_unprocessed, jobs)
|
||||
@redis.set(key_queue_status, STATUS_READY)
|
||||
end.first
|
||||
|
@ -131,7 +131,7 @@ module RSpecQ
|
|||
@redis.eval(
|
||||
REQUEUE_JOB,
|
||||
keys: [key_queue_unprocessed, key_requeues],
|
||||
argv: [job, max_requeues],
|
||||
argv: [job, max_requeues]
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -210,9 +210,10 @@ module RSpecQ
|
|||
@redis.get(key_queue_status) == STATUS_READY
|
||||
end
|
||||
|
||||
def wait_until_published(timeout=30)
|
||||
def wait_until_published(timeout = 30)
|
||||
(timeout * 10).times do
|
||||
return if published?
|
||||
|
||||
sleep 0.1
|
||||
end
|
||||
|
||||
|
@ -250,7 +251,7 @@ module RSpecQ
|
|||
def fail_fast
|
||||
return nil unless published?
|
||||
|
||||
@fail_fast ||= Integer(@redis.hget(key_queue_config, 'fail_fast'))
|
||||
@fail_fast ||= Integer(@redis.hget(key_queue_config, "fail_fast"))
|
||||
end
|
||||
|
||||
# Returns true if the number of failed tests, has surpassed the threshold
|
||||
|
|
|
@ -16,7 +16,7 @@ module RSpecQ
|
|||
|
||||
# We want feedback to be immediattely printed to CI users, so
|
||||
# we disable buffering.
|
||||
STDOUT.sync = true
|
||||
$stdout.sync = true
|
||||
end
|
||||
|
||||
def report
|
||||
|
@ -28,7 +28,7 @@ module RSpecQ
|
|||
failure_heading_printed = false
|
||||
|
||||
tests_duration = measure_duration do
|
||||
@timeout.times do |i|
|
||||
@timeout.times do
|
||||
@queue.example_failures.each do |job, rspec_output|
|
||||
next if reported_failures[job]
|
||||
|
||||
|
@ -124,13 +124,13 @@ module RSpecQ
|
|||
return if jobs.empty?
|
||||
|
||||
jobs.each do |job|
|
||||
filename = job.sub(/\[.+\]/, '')
|
||||
filename = job.sub(/\[.+\]/, "")
|
||||
|
||||
extra = {
|
||||
build: @build_id,
|
||||
build_timeout: @timeout,
|
||||
queue: @queue.inspect,
|
||||
object: self.inspect,
|
||||
object: inspect,
|
||||
pid: Process.pid,
|
||||
job_path: job,
|
||||
build_duration: build_duration
|
||||
|
@ -143,7 +143,7 @@ module RSpecQ
|
|||
|
||||
Raven.capture_message(
|
||||
"Flaky test in #{filename}",
|
||||
level: 'warning',
|
||||
level: "warning",
|
||||
extra: extra,
|
||||
tags: tags
|
||||
)
|
||||
|
|
|
@ -55,7 +55,7 @@ module RSpecQ
|
|||
@fail_fast = 0
|
||||
@files_or_dirs_to_run = "spec"
|
||||
@populate_timings = false
|
||||
@file_split_threshold = 999999
|
||||
@file_split_threshold = 999_999
|
||||
@heartbeat_updated_at = nil
|
||||
@max_requeues = 3
|
||||
|
||||
|
@ -98,7 +98,7 @@ module RSpecQ
|
|||
# reconfigure rspec
|
||||
RSpec.configuration.detail_color = :magenta
|
||||
RSpec.configuration.seed = srand && srand % 0xFFFF
|
||||
RSpec.configuration.backtrace_formatter.filter_gem('rspecq')
|
||||
RSpec.configuration.backtrace_formatter.filter_gem("rspecq")
|
||||
RSpec.configuration.add_formatter(Formatters::FailureRecorder.new(queue, job, max_requeues))
|
||||
RSpec.configuration.add_formatter(Formatters::ExampleCountRecorder.new(queue))
|
||||
RSpec.configuration.add_formatter(Formatters::WorkerHeartbeatRecorder.new(self))
|
||||
|
@ -155,7 +155,7 @@ module RSpecQ
|
|||
jobs.concat(files_to_run)
|
||||
end
|
||||
|
||||
default_timing = timings.values[timings.values.size/2]
|
||||
default_timing = timings.values[timings.values.size / 2]
|
||||
|
||||
# assign timings (based on previous runs) to all jobs
|
||||
jobs = jobs.each_with_object({}) do |j, h|
|
||||
|
@ -180,7 +180,8 @@ module RSpecQ
|
|||
# see https://github.com/rspec/rspec-core/pull/2723
|
||||
if Gem::Version.new(RSpec::Core::Version::STRING) <= Gem::Version.new("3.9.1")
|
||||
RSpec.world.instance_variable_set(
|
||||
:@example_group_counts_by_spec_file, Hash.new(0))
|
||||
:@example_group_counts_by_spec_file, Hash.new(0)
|
||||
)
|
||||
end
|
||||
|
||||
# RSpec.clear_examples does not reset those, which causes issues when
|
||||
|
@ -204,17 +205,17 @@ module RSpecQ
|
|||
|
||||
if !cmd_result.success?
|
||||
rspec_output = begin
|
||||
JSON.parse(out)
|
||||
rescue JSON::ParserError
|
||||
out
|
||||
end
|
||||
JSON.parse(out)
|
||||
rescue JSON::ParserError
|
||||
out
|
||||
end
|
||||
|
||||
log_event(
|
||||
"Failed to split slow files, falling back to regular scheduling.\n #{err}",
|
||||
"error",
|
||||
rspec_stdout: rspec_output,
|
||||
rspec_stderr: err,
|
||||
cmd_result: cmd_result.inspect,
|
||||
cmd_result: cmd_result.inspect
|
||||
)
|
||||
|
||||
pp rspec_output
|
||||
|
@ -236,7 +237,7 @@ module RSpecQ
|
|||
|
||||
# Prints msg to standard output and emits an event to Sentry, if the
|
||||
# SENTRY_DSN environment variable is set.
|
||||
def log_event(msg, level, additional={})
|
||||
def log_event(msg, level, additional = {})
|
||||
puts msg
|
||||
|
||||
Raven.capture_message(msg, level: level, extra: {
|
||||
|
@ -247,8 +248,8 @@ module RSpecQ
|
|||
populate_timings: populate_timings,
|
||||
file_split_threshold: file_split_threshold,
|
||||
heartbeat_updated_at: @heartbeat_updated_at,
|
||||
object: self.inspect,
|
||||
pid: Process.pid,
|
||||
object: inspect,
|
||||
pid: Process.pid
|
||||
}.merge(additional))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,7 +13,7 @@ Gem::Specification.new do |s|
|
|||
s.license = "MIT"
|
||||
|
||||
if ENV["CI"] && ENV["RSPEC_CORE"]
|
||||
s.add_dependency "rspec-core", "#{ENV['RSPEC_CORE']}"
|
||||
s.add_dependency "rspec-core", ENV["RSPEC_CORE"]
|
||||
else
|
||||
s.add_dependency "rspec-core"
|
||||
end
|
||||
|
@ -21,9 +21,9 @@ Gem::Specification.new do |s|
|
|||
s.add_dependency "redis"
|
||||
s.add_dependency "sentry-raven"
|
||||
|
||||
s.add_development_dependency "rake"
|
||||
s.add_development_dependency "pry-byebug"
|
||||
s.add_development_dependency "minitest"
|
||||
s.add_development_dependency "pry-byebug"
|
||||
s.add_development_dependency "rake"
|
||||
s.add_development_dependency "rspec"
|
||||
s.add_development_dependency "rubocop", "~> 0.93.0"
|
||||
end
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
# rubocop:disable Style/StderrPuts
|
||||
$stderr.puts "I'm a warning!"
|
||||
# rubocop:enable Style/StderrPuts
|
||||
|
||||
describe "A slow spec file to be splitted" do
|
||||
it do
|
||||
|
|
|
@ -17,12 +17,13 @@ class TestEndToEnd < RSpecQTest
|
|||
"./spec/success_spec.rb",
|
||||
], queue
|
||||
|
||||
assert_equal 3 + 3 + 5, queue.example_count
|
||||
assert_equal 3 + 3 + 5, queue.example_count
|
||||
|
||||
assert_equal({
|
||||
"./spec/fail_1_spec.rb[1:2]" => "3",
|
||||
"./spec/fail_2_spec.rb[1:2]" => "3",
|
||||
}, queue.requeued_jobs)
|
||||
assert_equal(
|
||||
{ "./spec/fail_1_spec.rb[1:2]" => "3",
|
||||
"./spec/fail_2_spec.rb[1:2]" => "3" },
|
||||
queue.requeued_jobs
|
||||
)
|
||||
end
|
||||
|
||||
def test_passing_suite
|
||||
|
@ -87,7 +88,7 @@ class TestEndToEnd < RSpecQTest
|
|||
"./spec/medium_spec.rb",
|
||||
"./spec/slow_spec.rb",
|
||||
"./spec/very_slow_spec.rb",
|
||||
], queue.timings.sort_by { |k,v| v }.map(&:first)
|
||||
], queue.timings.sort_by { |_, v| v }.map(&:first)
|
||||
end
|
||||
|
||||
def test_timings_no_update
|
||||
|
@ -98,11 +99,11 @@ class TestEndToEnd < RSpecQTest
|
|||
end
|
||||
|
||||
def test_spec_file_splitting
|
||||
queue = exec_build( "spec_file_splitting", "--update-timings")
|
||||
queue = exec_build("spec_file_splitting", "--update-timings")
|
||||
assert queue.build_successful?
|
||||
refute_empty queue.timings
|
||||
|
||||
queue = exec_build( "spec_file_splitting", "--file-split-threshold 1")
|
||||
queue = exec_build("spec_file_splitting", "--file-split-threshold 1")
|
||||
|
||||
assert queue.build_successful?
|
||||
refute_empty queue.timings
|
||||
|
|
|
@ -3,7 +3,7 @@ require "securerandom"
|
|||
require "rspecq"
|
||||
|
||||
module TestHelpers
|
||||
REDIS_OPTS = {host: "127.0.0.1"}.freeze
|
||||
REDIS_OPTS = { host: "127.0.0.1" }.freeze
|
||||
EXEC_CMD = "bundle exec rspecq".freeze
|
||||
|
||||
def rand_id
|
||||
|
@ -20,7 +20,7 @@ module TestHelpers
|
|||
w
|
||||
end
|
||||
|
||||
def exec_build(path, args="")
|
||||
def exec_build(path, args = "")
|
||||
worker_id = rand_id
|
||||
build_id = rand_id
|
||||
|
||||
|
@ -34,7 +34,7 @@ module TestHelpers
|
|||
queue = RSpecQ::Queue.new(build_id, worker_id, REDIS_OPTS)
|
||||
assert_queue_well_formed(queue)
|
||||
|
||||
return queue
|
||||
queue
|
||||
end
|
||||
|
||||
def suite_path(path)
|
||||
|
@ -42,11 +42,11 @@ module TestHelpers
|
|||
end
|
||||
|
||||
# Returns the worker pid
|
||||
def start_worker(build_id:, worker_id: rand_id, suite:)
|
||||
def start_worker(build_id:, suite:, worker_id: rand_id)
|
||||
Process.spawn(
|
||||
"#{EXEC_CMD} -w #{worker_id} -b #{build_id}",
|
||||
chdir: suite_path(suite),
|
||||
out: (ENV["RSPECQ_DEBUG"] ? :out : File::NULL),
|
||||
out: (ENV["RSPECQ_DEBUG"] ? :out : File::NULL)
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -59,7 +59,7 @@ module TestHelpers
|
|||
|
||||
begin
|
||||
orig = $stdout.clone
|
||||
$stdout.reopen(File::NULL, 'w')
|
||||
$stdout.reopen(File::NULL, "w")
|
||||
yield
|
||||
ensure
|
||||
$stdout.reopen(orig)
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
module TestHelpers
|
||||
module Assertions
|
||||
def assert_queue_well_formed(queue, msg=nil)
|
||||
def assert_queue_well_formed(queue, _msg = nil)
|
||||
redis = queue.redis
|
||||
heartbeats = redis.zrange(
|
||||
queue.send(:key_worker_heartbeats), 0, -1, withscores: true)
|
||||
queue.send(:key_worker_heartbeats), 0, -1, withscores: true
|
||||
)
|
||||
|
||||
assert queue.published?
|
||||
assert (queue.build_failed_fast? || queue.exhausted?)
|
||||
assert(queue.build_failed_fast? || queue.exhausted?)
|
||||
assert_operator heartbeats.size, :>=, 0
|
||||
assert heartbeats.all? { |hb| Time.at(hb.last) <= Time.now }
|
||||
assert(heartbeats.all? { |hb| Time.at(hb.last) <= Time.now })
|
||||
end
|
||||
|
||||
def assert_build_not_flakey(queue)
|
||||
|
|
|
@ -20,7 +20,8 @@ class TestQueue < RSpecQTest
|
|||
"./spec/flaky_spec.rb[1:1]",
|
||||
"./spec/flaky_spec.rb[1:3]",
|
||||
"./spec/legit_failure_spec.rb",
|
||||
"./spec/legit_failure_spec.rb[1:3]"], queue)
|
||||
"./spec/legit_failure_spec.rb[1:3]"], queue
|
||||
)
|
||||
|
||||
assert_failures(["./spec/legit_failure_spec.rb[1:3]"], queue)
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue