Bootstrap Rubocop configuration and fix offenses

This commit is contained in:
Agis Anastasopoulos 2020-10-11 13:35:36 +03:00
parent 22e3f7c267
commit 6f0077a60e
15 changed files with 121 additions and 53 deletions

49
.rubocop.yml Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -14,4 +14,3 @@ module RSpecQ
end
end
end

View File

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

View File

@ -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
)

View File

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

View File

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

View File

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

View File

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

View File

@ -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)

View File

@ -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)

View File

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