Class: GitlabQuality::TestTooling::CodeCoverage::ClickHouse::TestHealthRiskAggregator

Inherits:
Object
  • Object
show all
Includes:
Client
Defined in:
lib/gitlab_quality/test_tooling/code_coverage/click_house/test_health_risk_aggregator.rb

Overview

Runs the daily aggregation that turns ‘code_coverage.test_coverage_per_file` rows into a small `code_coverage.test_health_risk_per_group` summary the dashboard reads.

Hybrid model: this Ruby class is the orchestrator (schedule, error handling, parameter substitution); ClickHouse runs the bitmap math via ‘INSERT … SELECT` from the SQL file shipped alongside.

Constant Summary collapse

SQL_FILE =
File.expand_path('test_health_risk_aggregation.sql', __dir__)
DEFAULT_COVERAGE_WINDOW =

2 DAY rather than 1 DAY makes the aggregation self-healing across a single missed nightly run: if last night’s export failed, this night’s run still sees yesterday’s per-test rows and produces a current snapshot. ReplacingMergeTree FINAL on the source table ensures we read only the latest version per (test_file, source_file). ClickHouse accepts both ‘2 DAY’ and ‘2 DAYS’; we use the singular form for consistency with ‘30 DAY` below.

'2 DAY'
DEFAULT_RISK_WINDOW =
'30 DAY'
DATE_PATTERN =

‘snapshot_date` is YYYY-MM-DD; intervals are `<integer> <unit>` (singular or plural).

/\A\d{4}-\d{2}-\d{2}\z/
INTERVAL_PATTERN =
/\A\d+\s+(SECOND|MINUTE|HOUR|DAY|WEEK|MONTH|QUARTER|YEAR)S?\z/i

Instance Method Summary collapse

Constructor Details

#initialize(url:, database:, username: nil, password: nil, logger: nil, coverage_window: DEFAULT_COVERAGE_WINDOW, risk_window: DEFAULT_RISK_WINDOW) ⇒ TestHealthRiskAggregator

Returns a new instance of TestHealthRiskAggregator.



37
38
39
40
41
42
43
44
45
46
47
# File 'lib/gitlab_quality/test_tooling/code_coverage/click_house/test_health_risk_aggregator.rb', line 37

def initialize(
  url:, database:, username: nil, password: nil, logger: nil,
  coverage_window: DEFAULT_COVERAGE_WINDOW, risk_window: DEFAULT_RISK_WINDOW)
  @url = url
  @database = database
  @username = username
  @password = password
  @logger = logger || ::Logger.new($stdout, level: 1)
  @coverage_window = coverage_window
  @risk_window = risk_window
end

Instance Method Details

#run(snapshot_date: Date.today) ⇒ void

This method returns an undefined value.

Parameters:

  • snapshot_date (Date, String) (defaults to: Date.today)

    date stamp for this run; defaults to today.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/gitlab_quality/test_tooling/code_coverage/click_house/test_health_risk_aggregator.rb', line 51

def run(snapshot_date: Date.today) # rubocop:disable Metrics/AbcSize
  sql = build_sql(snapshot_date: snapshot_date)
  logger.info(
    "#{LOG_PREFIX} Running test_health_risk aggregation snapshot_date=#{snapshot_date} " \
      "coverage_window=#{coverage_window} risk_window=#{risk_window}"
  )
  client.query(sql, format: "TabSeparated")
  inserted = fetch_row_count(snapshot_date)
  if inserted.is_a?(Integer) && inserted.zero?
    logger.warn(
      "#{LOG_PREFIX} Aggregation wrote 0 rows for snapshot_date=#{snapshot_date}. " \
        "This is valid if no per-test data is in the coverage_window, but worth checking " \
        "test_coverage_per_file directly if a recent export ran."
    )
  else
    logger.info("#{LOG_PREFIX} Aggregation wrote #{inserted} rows for snapshot_date=#{snapshot_date}")
  end
rescue StandardError => e
  logger.error("#{LOG_PREFIX} Aggregation failed for #{snapshot_date}: #{e.message}")
  raise
end