# frozen_string_literal: true require_relative 'gitlab_client/job_client' module GitlabQuality module TestTooling class JobTraceAnalyzer attr_reader :project, :token, :job_id TRANSIENT_ROOT_CAUSE_TO_TRACE_MAP = { failed_to_pull_image: ['job failed: failed to pull image'], gitlab_com_overloaded: ['gitlab is currently unable to handle this request due to load'], runner_disk_full: [ 'no space left on device', 'Check free disk space' ], job_timeout: [ 'ERROR: Job failed: execution took longer than', 'Rspec suite is exceeding the 80 minute limit and is forced to exit with error' ], gitaly: ['gitaly spawn failed'], infrastructure: [ 'the requested url returned error: 5', # any 5XX error code should be transient 'error: downloading artifacts from coordinator', 'error: uploading artifacts as "archive" to coordinator', '500 Internal Server Error', "Internal Server Error 500", '502 Bad Gateway', '503 Service Unavailable', 'Error: EEXIST: file already exists', 'Failed to connect to 127.0.0.1', "Failed to open TCP connection to", 'connection reset by peer', 'segmentation fault', 'no space left on device', 'Check free disk space', 'CLUSTERDOWN' ], flaky_test: [ "We have detected a PG::QueryCanceled error in the specs, so we're failing early" ] }.freeze def initialize(project:, token:, job_id:) @project = project @token = token @job_id = job_id end def found_infrastructure_error? TRANSIENT_ROOT_CAUSE_TO_TRACE_MAP[:infrastructure].any? do |search_string| found = job_trace.downcase.include?(search_string.downcase) puts "Found infrastructure error stacktrace: #{search_string}" if found found end end private def job_trace @job_trace ||= GitlabClient::JobClient.new(project: project, token: token, job_id: job_id).job_trace end end end end