Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RetrieveError and UpdateStatus #89

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions lib/github/topotest_failures/retrieve_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# SPDX-License-Identifier: BSD-2-Clause
#
# retrieve_error.rb
# Part of NetDEF CI System
#
# Copyright (c) 2024 by
# Network Device Education Foundation, Inc. ("NetDEF")
#
# frozen_string_literal: true

module Github
module TopotestFailures
class RetrieveError
attr_reader :failures

def initialize(job)
@job = job
@failures = []
end

def retrieve
fetch_failures(BambooCi::Result.fetch(@job.job_ref))

@failures
end

def fetch_failures(output)
output.dig('testResults', 'failedTests', 'testResult')&.each do |test_result|
@failures << {
'suite' => test_result['className'],
'case' => test_result['methodName'],
'message' => test_result.dig('errors', 'error').map { |error| error['message'] }.join("\n"),
'execution_time' => test_result['durationInSeconds']
}
end
end
end
end
end
59 changes: 15 additions & 44 deletions lib/github/update_status.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,12 @@ class UpdateStatus
def initialize(payload)
@status = payload['status']

@output =
if payload.dig('output', 'title').nil? and payload.dig('output', 'summary').nil?
{}
else
{ title: payload.dig('output', 'title'), summary: payload.dig('output', 'summary') }
end

@reference = payload['bamboo_ref'] || 'invalid_reference'
@job = CiJob.find_by(job_ref: payload['bamboo_ref'])
@check_suite = @job&.check_suite
@failures = payload['failures']

logger_initializer
logger(Logger::WARN, "UpdateStatus: #{@reference} #{@status} (Output in info log)")
logger(Logger::INFO, "UpdateStatus: #{@reference} #{@status} #{@output}")
end

def update
Expand Down Expand Up @@ -68,9 +59,9 @@ def failures_stats
def update_status
case @status
when 'in_progress'
@job.in_progress(@github_check, output: @output)
@job.in_progress(@github_check)
when 'success'
@job.success(@github_check, output: @output)
@job.success(@github_check)
slack_notify_success
else
failure
Expand Down Expand Up @@ -128,46 +119,26 @@ def current_execution?
# The unable2find string must match the phrase defined in the ci-files repository file
# github_checks/hook_api.py method __topotest_title_summary
def failure
unable2find = "There was some test that failed, but I couldn't find the log."
fetch_and_update_failures(unable2find) if [email protected]? and @output[:summary].match?(unable2find)
@job.failure(@github_check)

@job.failure(@github_check, output: @output)
failures_stats if @job.name.downcase.match? 'topotest' and @failures.is_a? Array
retrieve_stats
end

def fetch_and_update_failures(to_be_replaced)
count = 0
begin
output = BambooCi::Result.fetch(@job.job_ref)
return if output.nil? or output.empty?
def retrieve_stats
return failures_stats if @failures.is_a? Array and [email protected]?

@output[:summary] = @output[:summary].sub(to_be_replaced, fetch_failures(output))[0..65_535]
rescue NoMethodError => e
logger Logger::ERROR, "#{e.class} #{e.message}"
count += 1
sleep 5
retry if count <= 10
end
retrieve_errors
end

def fetch_failures(output)
buffer = ''
output.dig('testResults', 'failedTests', 'testResult')&.each do |test_result|
message = ''
test_result.dig('errors', 'error').each do |error|
message += error['message']
buffer += message
end

@failures << {
'suite' => test_result['className'],
'case' => test_result['methodName'],
'message' => message,
'execution_time' => test_result['durationInSeconds']
}
end
def retrieve_errors
@retrieve_error = Github::TopotestFailures::RetrieveError.new(@job)
@retrieve_error.retrieve

return if @retrieve_error.failures.empty?

@failures = @retrieve_error.failures

buffer
failures_stats
end

def slack_notify_success
Expand Down
1 change: 1 addition & 0 deletions lib/github_ci_app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
require_relative 'github/plan_execution/finished'
require_relative 'github/user_info'
require_relative 'github/build/skip_old_tests'
require_relative 'github/topotest_failures/retrieve_error'

# Helpers libs
require_relative 'helpers/configuration'
Expand Down
35 changes: 29 additions & 6 deletions spec/lib/github/update_status_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
allow(fake_github_check).to receive(:queued).and_return(ci_job.check_suite)

allow(Github::Build::UnavailableJobs).to receive(:new).and_return(fake_unavailable)

allow(BambooCi::Result).to receive(:fetch).and_return({})
end

context 'when Ci Job Checkout Code update from queued -> failure' do
Expand Down Expand Up @@ -276,8 +278,33 @@
update_status.update
end

it 'must update the output' do
expect(ci_job).to have_received(:failure).with(fake_github_check, output: expected_output)
it 'must create TopoTestFailure' do
expect(TopotestFailure.all.size).to eq(1)
expect(TopotestFailure.last.to_h).to eq(expected_topotest_failure)
end
end

context 'when updated a test that failed and it has no error output - AddressSanitizer' do
let(:payload) do
{
'status' => status,
'bamboo_ref' => ci_job.job_ref,
'output' => {
'title' => 'Failed test',
'summary' => 'Details at https://netdef.org/browse/FRR-PULLREQ3-ASAN9D12AMD64-123'
},
'failures' => []
}
end

before do
allow(CiJob).to receive(:find_by).and_return(ci_job)
allow(ci_job).to receive(:failure)
allow(BambooCi::Result).to receive(:fetch).and_return(fake_output)

ci_job.update(name: 'AddressSanitizer Debian 12 amd64')

update_status.update
end

it 'must create TopoTestFailure' do
Expand Down Expand Up @@ -323,10 +350,6 @@
update_status.update
end

it 'must maintain the same output' do
expect(ci_job).to have_received(:failure).with(fake_github_check, output: expected_output)
end

it 'must not create a TopoTestFailure' do
expect(TopotestFailure.all.size).to eq(0)
end
Expand Down
39 changes: 39 additions & 0 deletions tasks/retrieve_address_sanitizer_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# SPDX-License-Identifier: BSD-2-Clause
#
# retrieve_address_sanitizer_error.rb
#
# > Overview
# The retrieve_address_sanitizer_error.rb script is part of the NetDEF CI System.
# It is designed to retrieve and log AddressSanitizer errors from CI jobs that have failed.
# The script processes CI jobs, retrieves errors using the Github::TopotestFailures::RetrieveError class,
# and logs these errors into the TopotestFailure model.
#
# Part of NetDEF CI System
#
# Copyright (c) 2024 by
# Network Device Education Foundation, Inc. ("NetDEF")
#
# frozen_string_literal: true

require_relative '../config/setup'

CiJob
.where("ci_jobs.name LIKE '%AddressSanitizer%'")
.where(status: :failure)
.each do |job|
next if job.topotest_failures.any?

CiJob.transaction do
failures = Github::TopotestFailures::RetrieveError.new(job).retrieve

next if failures.empty?

failures.each do |failure|
TopotestFailure.create(ci_job: job,
test_suite: failure['suite'],
test_case: failure['case'],
message: failure['message'],
execution_time: failure['execution_time'])
end
end
end
Loading