Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/support/rspec_run_time.rb')
-rw-r--r--spec/support/rspec_run_time.rb107
1 files changed, 107 insertions, 0 deletions
diff --git a/spec/support/rspec_run_time.rb b/spec/support/rspec_run_time.rb
new file mode 100644
index 00000000000..977d4885624
--- /dev/null
+++ b/spec/support/rspec_run_time.rb
@@ -0,0 +1,107 @@
+# frozen_string_literal: true
+
+require 'os'
+require 'yaml'
+require 'rspec/core/formatters/base_formatter'
+require_relative '../../tooling/lib/tooling/helpers/duration_formatter'
+
+module Support
+ module RSpecRunTime
+ class RSpecFormatter < RSpec::Core::Formatters::BaseFormatter
+ include Tooling::Helpers::DurationFormatter
+
+ TIME_LIMIT_IN_MINUTES = 80
+
+ RSpec::Core::Formatters.register self, :example_group_started, :example_group_finished
+
+ def start(_notification)
+ @group_level = 0
+ @rspec_test_suite_start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ output.puts "\n# [RSpecRunTime] Starting RSpec timer..."
+
+ init_expected_duration_report
+ end
+
+ def example_group_started(notification)
+ if @last_elapsed_seconds && @last_elapsed_seconds > TIME_LIMIT_IN_MINUTES * 60
+ RSpec::Expectations.fail_with(
+ "Rspec suite is exceeding the #{TIME_LIMIT_IN_MINUTES} minute limit and is forced to exit with error.")
+ end
+
+ if @group_level == 0
+ @current_group_start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ file_path = spec_file_path(notification)
+ output.puts "# [RSpecRunTime] Starting example group #{file_path}. #{expected_run_time(file_path)}"
+ end
+
+ @group_level += 1
+ end
+
+ def example_group_finished(notification)
+ @group_level -= 1 if @group_level > 0
+
+ if @group_level == 0
+ file_path = spec_file_path(notification)
+ time_now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ actual_duration = time_now - @current_group_start_time
+
+ output.puts "\n# [RSpecRunTime] Finishing example group #{file_path}. " \
+ "It took #{readable_duration(actual_duration)}. " \
+ "#{expected_run_time(file_path)}"
+ end
+
+ output_elapsed_time
+ end
+
+ private
+
+ def expected_duration_report
+ report_path = ENV['KNAPSACK_RSPEC_SUITE_REPORT_PATH']
+
+ return unless report_path && File.exist?(report_path)
+
+ # rubocop:disable Gitlab/Json -- regular JSON is sufficient
+ @expected_duration_report ||= JSON.parse(File.read(report_path))
+ # rubocop:enable Gitlab/Json
+ end
+ alias_method :init_expected_duration_report, :expected_duration_report
+
+ def spec_file_path(notification)
+ notification.group.metadata[:file_path].sub('./', '')
+ end
+
+ def expected_run_time(spec_file_path)
+ return '' unless expected_duration_report
+
+ expected_duration = expected_duration_report[spec_file_path]
+ return "Missing expected duration from Knapsack report for #{spec_file_path}." unless expected_duration
+
+ "Expected to take #{readable_duration(expected_duration)}."
+ end
+
+ def output_elapsed_time
+ time_now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ elapsed_seconds = time_now - @rspec_test_suite_start_time
+
+ # skip the output unless the duration increased by at least 1 second
+ unless @last_elapsed_seconds.nil? || elapsed_seconds - @last_elapsed_seconds < 1
+ output.puts \
+ "# [RSpecRunTime] RSpec elapsed time: #{readable_duration(elapsed_seconds)}. " \
+ "#{current_rss_in_megabytes}\n\n"
+ end
+
+ @last_elapsed_seconds = elapsed_seconds
+ end
+
+ def current_rss_in_megabytes
+ rss_in_megabytes = OS.rss_bytes / 1024 / 1024
+
+ "Current RSS: ~#{rss_in_megabytes.round}M"
+ end
+ end
+ end
+end
+
+RSpec.configure do |config|
+ config.add_formatter Support::RSpecRunTime::RSpecFormatter if ENV['GITLAB_CI']
+end