# frozen_string_literal: true module GitlabQuality module TestTooling module KnapsackReports class SpecRunTime attr_reader :file, :expected, :actual, :expected_suite_duration, :actual_suite_duration ACTUAL_TO_EXPECTED_SPEC_RUN_TIME_RATIO_THRESHOLD = 1.5 # actual run time is longer than expected by 50% + SPEC_WEIGHT_PERCENTAGE_TRESHOLD = 15 # a spec file takes 15%+ of the total test suite run time SUITE_DURATION_THRESHOLD = 70 * 60 # if test suite takes more than 70 minutes, job risks timing out def initialize(file:, expected:, actual:, expected_suite_duration:, actual_suite_duration:) @file = file @expected = expected.to_f @actual = actual.to_f @expected_suite_duration = expected_suite_duration.to_f @actual_suite_duration = actual_suite_duration.to_f end def should_report? # guideline proposed in https://gitlab.com/gitlab-org/quality/engineering-productivity/team/-/issues/354 exceed_actual_to_expected_ratio_threshold? && test_suite_bottleneck? end def ci_pipeline_url_markdown "[#{ci_pipeline_id}](#{ci_pipeline_url})" end def ci_pipeline_created_at ENV.fetch('CI_PIPELINE_CREATED_AT', nil) end def ci_job_link_markdown "[#{ci_job_name}](#{ci_job_url})" end def file_link_markdown "[#{file}](#{file_link})" end def actual_percentage (actual / actual_suite_duration * 100).round(2) end def name nil end private def exceed_actual_to_expected_ratio_threshold? actual / expected >= ACTUAL_TO_EXPECTED_SPEC_RUN_TIME_RATIO_THRESHOLD end def test_suite_bottleneck? # now we only report bottlenecks when they risk causing job timeouts return unless actual_suite_duration > SUITE_DURATION_THRESHOLD actual_percentage > SPEC_WEIGHT_PERCENTAGE_TRESHOLD end def ci_job_url ENV.fetch('CI_JOB_URL', nil) end def ci_job_name ENV.fetch('CI_JOB_NAME_SLUG', nil) end def ci_pipeline_id ENV.fetch('CI_PIPELINE_IID', nil) end def ci_pipeline_url ENV.fetch('CI_PIPELINE_URL', nil) end def file_link "#{Runtime::Env.file_base_url}#{file}" end end end end end