Skip to content

Commit 02ddd8e

Browse files
Merge pull request #92 from FRRouting/master
Release 2.3.7
2 parents 1e77306 + d8bba16 commit 02ddd8e

5 files changed

Lines changed: 130 additions & 50 deletions

File tree

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# SPDX-License-Identifier: BSD-2-Clause
2+
#
3+
# retrieve_error.rb
4+
# Part of NetDEF CI System
5+
#
6+
# Copyright (c) 2024 by
7+
# Network Device Education Foundation, Inc. ("NetDEF")
8+
#
9+
# frozen_string_literal: true
10+
11+
module Github
12+
module TopotestFailures
13+
class RetrieveError
14+
attr_reader :failures
15+
16+
def initialize(job)
17+
@job = job
18+
@failures = []
19+
end
20+
21+
def retrieve
22+
fetch_failures(BambooCi::Result.fetch(@job.job_ref))
23+
24+
@failures
25+
end
26+
27+
def fetch_failures(output)
28+
output.dig('testResults', 'failedTests', 'testResult')&.each do |test_result|
29+
@failures << {
30+
'suite' => test_result['className'],
31+
'case' => test_result['methodName'],
32+
'message' => test_result.dig('errors', 'error').map { |error| error['message'] }.join("\n"),
33+
'execution_time' => test_result['durationInSeconds']
34+
}
35+
end
36+
end
37+
end
38+
end
39+
end

lib/github/update_status.rb

Lines changed: 15 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,12 @@ class UpdateStatus
2020
def initialize(payload)
2121
@status = payload['status']
2222

23-
@output =
24-
if payload.dig('output', 'title').nil? and payload.dig('output', 'summary').nil?
25-
{}
26-
else
27-
{ title: payload.dig('output', 'title'), summary: payload.dig('output', 'summary') }
28-
end
29-
3023
@reference = payload['bamboo_ref'] || 'invalid_reference'
3124
@job = CiJob.find_by(job_ref: payload['bamboo_ref'])
3225
@check_suite = @job&.check_suite
3326
@failures = payload['failures']
3427

3528
logger_initializer
36-
logger(Logger::WARN, "UpdateStatus: #{@reference} #{@status} (Output in info log)")
37-
logger(Logger::INFO, "UpdateStatus: #{@reference} #{@status} #{@output}")
3829
end
3930

4031
def update
@@ -68,9 +59,9 @@ def failures_stats
6859
def update_status
6960
case @status
7061
when 'in_progress'
71-
@job.in_progress(@github_check, output: @output)
62+
@job.in_progress(@github_check)
7263
when 'success'
73-
@job.success(@github_check, output: @output)
64+
@job.success(@github_check)
7465
slack_notify_success
7566
else
7667
failure
@@ -128,46 +119,26 @@ def current_execution?
128119
# The unable2find string must match the phrase defined in the ci-files repository file
129120
# github_checks/hook_api.py method __topotest_title_summary
130121
def failure
131-
unable2find = "There was some test that failed, but I couldn't find the log."
132-
fetch_and_update_failures(unable2find) if !@output.empty? and @output[:summary].match?(unable2find)
122+
@job.failure(@github_check)
133123

134-
@job.failure(@github_check, output: @output)
135-
failures_stats if @job.name.downcase.match? 'topotest' and @failures.is_a? Array
124+
retrieve_stats
136125
end
137126

138-
def fetch_and_update_failures(to_be_replaced)
139-
count = 0
140-
begin
141-
output = BambooCi::Result.fetch(@job.job_ref)
142-
return if output.nil? or output.empty?
127+
def retrieve_stats
128+
return failures_stats if @failures.is_a? Array and !@failures.empty?
143129

144-
@output[:summary] = @output[:summary].sub(to_be_replaced, fetch_failures(output))[0..65_535]
145-
rescue NoMethodError => e
146-
logger Logger::ERROR, "#{e.class} #{e.message}"
147-
count += 1
148-
sleep 5
149-
retry if count <= 10
150-
end
130+
retrieve_errors
151131
end
152132

153-
def fetch_failures(output)
154-
buffer = ''
155-
output.dig('testResults', 'failedTests', 'testResult')&.each do |test_result|
156-
message = ''
157-
test_result.dig('errors', 'error').each do |error|
158-
message += error['message']
159-
buffer += message
160-
end
161-
162-
@failures << {
163-
'suite' => test_result['className'],
164-
'case' => test_result['methodName'],
165-
'message' => message,
166-
'execution_time' => test_result['durationInSeconds']
167-
}
168-
end
133+
def retrieve_errors
134+
@retrieve_error = Github::TopotestFailures::RetrieveError.new(@job)
135+
@retrieve_error.retrieve
136+
137+
return if @retrieve_error.failures.empty?
138+
139+
@failures = @retrieve_error.failures
169140

170-
buffer
141+
failures_stats
171142
end
172143

173144
def slack_notify_success

lib/github_ci_app.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
require_relative 'github/plan_execution/finished'
3030
require_relative 'github/user_info'
3131
require_relative 'github/build/skip_old_tests'
32+
require_relative 'github/topotest_failures/retrieve_error'
3233

3334
# Helpers libs
3435
require_relative 'helpers/configuration'

spec/lib/github/update_status_spec.rb

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
allow(fake_github_check).to receive(:queued).and_return(ci_job.check_suite)
5050

5151
allow(Github::Build::UnavailableJobs).to receive(:new).and_return(fake_unavailable)
52+
53+
allow(BambooCi::Result).to receive(:fetch).and_return({})
5254
end
5355

5456
context 'when Ci Job Checkout Code update from queued -> failure' do
@@ -276,8 +278,33 @@
276278
update_status.update
277279
end
278280

279-
it 'must update the output' do
280-
expect(ci_job).to have_received(:failure).with(fake_github_check, output: expected_output)
281+
it 'must create TopoTestFailure' do
282+
expect(TopotestFailure.all.size).to eq(1)
283+
expect(TopotestFailure.last.to_h).to eq(expected_topotest_failure)
284+
end
285+
end
286+
287+
context 'when updated a test that failed and it has no error output - AddressSanitizer' do
288+
let(:payload) do
289+
{
290+
'status' => status,
291+
'bamboo_ref' => ci_job.job_ref,
292+
'output' => {
293+
'title' => 'Failed test',
294+
'summary' => 'Details at https://netdef.org/browse/FRR-PULLREQ3-ASAN9D12AMD64-123'
295+
},
296+
'failures' => []
297+
}
298+
end
299+
300+
before do
301+
allow(CiJob).to receive(:find_by).and_return(ci_job)
302+
allow(ci_job).to receive(:failure)
303+
allow(BambooCi::Result).to receive(:fetch).and_return(fake_output)
304+
305+
ci_job.update(name: 'AddressSanitizer Debian 12 amd64')
306+
307+
update_status.update
281308
end
282309

283310
it 'must create TopoTestFailure' do
@@ -323,10 +350,6 @@
323350
update_status.update
324351
end
325352

326-
it 'must maintain the same output' do
327-
expect(ci_job).to have_received(:failure).with(fake_github_check, output: expected_output)
328-
end
329-
330353
it 'must not create a TopoTestFailure' do
331354
expect(TopotestFailure.all.size).to eq(0)
332355
end
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# SPDX-License-Identifier: BSD-2-Clause
2+
#
3+
# retrieve_address_sanitizer_error.rb
4+
#
5+
# > Overview
6+
# The retrieve_address_sanitizer_error.rb script is part of the NetDEF CI System.
7+
# It is designed to retrieve and log AddressSanitizer errors from CI jobs that have failed.
8+
# The script processes CI jobs, retrieves errors using the Github::TopotestFailures::RetrieveError class,
9+
# and logs these errors into the TopotestFailure model.
10+
#
11+
# Part of NetDEF CI System
12+
#
13+
# Copyright (c) 2024 by
14+
# Network Device Education Foundation, Inc. ("NetDEF")
15+
#
16+
# frozen_string_literal: true
17+
18+
require_relative '../config/setup'
19+
20+
CiJob
21+
.left_outer_joins(:topotest_failures)
22+
.joins(:stage)
23+
.where(topotest_failures: { id: nil })
24+
.where("ci_jobs.name LIKE '%AddressSanitizer%'")
25+
.where(status: :failure)
26+
.where(stage: { status: :failure })
27+
.where('ci_jobs.created_at > ?', 6.month.ago)
28+
.each do |job|
29+
next if job.topotest_failures.any?
30+
31+
CiJob.transaction do
32+
failures = Github::TopotestFailures::RetrieveError.new(job).retrieve
33+
34+
puts "Found #{failures.size} failures for job #{job.job_ref}"
35+
36+
next if failures.empty?
37+
38+
failures.each do |failure|
39+
TopotestFailure.create(ci_job: job,
40+
test_suite: failure['suite'],
41+
test_case: failure['case'],
42+
message: failure['message'],
43+
execution_time: failure['execution_time'])
44+
end
45+
end
46+
end

0 commit comments

Comments
 (0)