diff options
Diffstat (limited to 'qa/qa/tools/long_running_spec_reporter.rb')
-rw-r--r-- | qa/qa/tools/long_running_spec_reporter.rb | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/qa/qa/tools/long_running_spec_reporter.rb b/qa/qa/tools/long_running_spec_reporter.rb new file mode 100644 index 00000000000..ce035248baa --- /dev/null +++ b/qa/qa/tools/long_running_spec_reporter.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +require "fog/google" +require "slack-notifier" + +module QA + module Tools + class LongRunningSpecReporter + extend SingleForwardable + + SLACK_CHANNEL = "#quality-reports" + PROJECT = "gitlab-qa-resources" + BUCKET = "knapsack-reports" + REPORT_NAME = "ee-instance-parallel.json" + RUNTIME_THRESHOLD = 300 + + def_delegator :new, :execute + + # Find and report specs exceeding runtime threshold + # + # @return [void] + def execute + return puts("No long running specs detected, all good!") if long_running_specs.empty? + + specs = long_running_specs.map { |k, v| "#{k}: #{(v / 60).round(2)} minutes" }.join("\n") + average = mean_runtime < 60 ? "#{mean_runtime.round(0)} seconds" : "#{(mean_runtime / 60).round(2)} minutes" + msg = <<~MSG + Following spec files are exceeding #{RUNTIME_THRESHOLD / 60} minute runtime threshold! + Current average spec runtime: #{average}. + MSG + + puts("#{msg}\n#{specs}") + notifier.post(icon_emoji: ":time-out:", text: "#{msg}\n```#{specs}```") + end + + private + + # Average runtime of spec files + # + # @return [Number] + def mean_runtime + @mean_runtime ||= latest_report.values + .select { |v| v < RUNTIME_THRESHOLD } + .yield_self { |runtimes| runtimes.sum(0.0) / runtimes.length } + end + + # Spec files exceeding runtime threshold + # + # @return [Hash] + def long_running_specs + @long_running_specs ||= latest_report.select { |k, v| v > RUNTIME_THRESHOLD } + end + + # Latest knapsack report + # + # @return [Hash] + def latest_report + @latest_report ||= JSON.parse(client.get_object(BUCKET, REPORT_NAME)[:body]) + end + + # Slack notifier + # + # @return [Slack::Notifier] + def notifier + @notifier ||= Slack::Notifier.new( + slack_webhook_url, + channel: SLACK_CHANNEL, + username: "Spec Runtime Report" + ) + end + + # GCS client + # + # @return [Fog::Storage::GoogleJSON] + def client + @client ||= Fog::Storage::Google.new( + google_project: PROJECT, + **(File.exist?(gcs_json) ? { google_json_key_location: gcs_json } : { google_json_key_string: gcs_json }) + ) + end + + # Slack webhook url + # + # @return [String] + def slack_webhook_url + @slack_webhook_url ||= ENV["SLACK_WEBHOOK"] || raise("Missing SLACK_WEBHOOK env variable") + end + + # GCS credentials json + # + # @return [Hash] + def gcs_json + ENV["QA_KNAPSACK_REPORT_GCS_CREDENTIALS"] || raise("Missing QA_KNAPSACK_REPORT_GCS_CREDENTIALS env variable!") + end + end + end +end |