Commit 24baf450 authored by Dylan Griffith's avatar Dylan Griffith

Merge branch 'eb-suitename-in-testcase-key' into 'master'

Include testsuite name in test case key

See merge request gitlab-org/gitlab!44473
parents df8d9a44 4b60d9d4
...@@ -47,7 +47,7 @@ module Ci ...@@ -47,7 +47,7 @@ module Ci
def test_case_hashes(build, test_suite) def test_case_hashes(build, test_suite)
[].tap do |hashes| [].tap do |hashes|
test_suite.each_test_case do |test_case| test_suite.each_test_case do |test_case|
key = "#{build.project_id}-#{test_suite.name}-#{test_case.key}" key = "#{build.project_id}-#{test_case.key}"
hashes << Digest::SHA256.hexdigest(key) hashes << Digest::SHA256.hexdigest(key)
end end
end end
......
...@@ -12,7 +12,7 @@ module Gitlab ...@@ -12,7 +12,7 @@ module Gitlab
root = Hash.from_xml(xml_data) root = Hash.from_xml(xml_data)
all_cases(root) do |test_case| all_cases(root) do |test_case|
test_case = create_test_case(test_case, args) test_case = create_test_case(test_case, test_suite, args)
test_suite.add_test_case(test_case) test_suite.add_test_case(test_case)
end end
rescue Nokogiri::XML::SyntaxError => e rescue Nokogiri::XML::SyntaxError => e
...@@ -33,20 +33,24 @@ module Gitlab ...@@ -33,20 +33,24 @@ module Gitlab
all_cases(node['testsuites'], root, &blk) unless parent all_cases(node['testsuites'], root, &blk) unless parent
# we require at least one level of testsuites or testsuite # we require at least one level of testsuites or testsuite
each_case(node['testcase'], &blk) if parent each_case(node['testcase'], node['name'], &blk) if parent
# we allow multiple nested 'testsuite' (eg. PHPUnit) # we allow multiple nested 'testsuite' (eg. PHPUnit)
all_cases(node['testsuite'], root, &blk) all_cases(node['testsuite'], root, &blk)
end end
end end
def each_case(testcase, &blk) def each_case(testcase, testsuite_name, &blk)
return unless testcase.present? return unless testcase.present?
[testcase].flatten.compact.map(&blk) [testcase].flatten.compact.each do |tc|
tc['suite_name'] = testsuite_name
yield(tc)
end
end end
def create_test_case(data, args) def create_test_case(data, test_suite, args)
if data.key?('failure') if data.key?('failure')
status = ::Gitlab::Ci::Reports::TestCase::STATUS_FAILED status = ::Gitlab::Ci::Reports::TestCase::STATUS_FAILED
system_output = data['failure'] system_output = data['failure']
...@@ -63,6 +67,7 @@ module Gitlab ...@@ -63,6 +67,7 @@ module Gitlab
end end
::Gitlab::Ci::Reports::TestCase.new( ::Gitlab::Ci::Reports::TestCase.new(
suite_name: data['suite_name'] || test_suite.name,
classname: data['classname'], classname: data['classname'],
name: data['name'], name: data['name'],
file: data['file'], file: data['file'],
...@@ -74,6 +79,10 @@ module Gitlab ...@@ -74,6 +79,10 @@ module Gitlab
) )
end end
def suite_name(parent, test_suite)
parent.dig('testsuite', 'name') || test_suite.name
end
def attachment_path(data) def attachment_path(data)
return unless data return unless data
......
...@@ -10,9 +10,10 @@ module Gitlab ...@@ -10,9 +10,10 @@ module Gitlab
STATUS_ERROR = 'error' STATUS_ERROR = 'error'
STATUS_TYPES = [STATUS_ERROR, STATUS_FAILED, STATUS_SUCCESS, STATUS_SKIPPED].freeze STATUS_TYPES = [STATUS_ERROR, STATUS_FAILED, STATUS_SUCCESS, STATUS_SKIPPED].freeze
attr_reader :name, :classname, :execution_time, :status, :file, :system_output, :stack_trace, :key, :attachment, :job attr_reader :suite_name, :name, :classname, :execution_time, :status, :file, :system_output, :stack_trace, :key, :attachment, :job
def initialize(params) def initialize(params)
@suite_name = params.fetch(:suite_name)
@name = params.fetch(:name) @name = params.fetch(:name)
@classname = params.fetch(:classname) @classname = params.fetch(:classname)
@file = params.fetch(:file, nil) @file = params.fetch(:file, nil)
...@@ -23,7 +24,7 @@ module Gitlab ...@@ -23,7 +24,7 @@ module Gitlab
@attachment = params.fetch(:attachment, nil) @attachment = params.fetch(:attachment, nil)
@job = params.fetch(:job, nil) @job = params.fetch(:job, nil)
@key = hash_key("#{classname}_#{name}") @key = hash_key("#{suite_name}_#{classname}_#{name}")
end end
def has_attachment? def has_attachment?
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
FactoryBot.define do FactoryBot.define do
factory :test_case, class: 'Gitlab::Ci::Reports::TestCase' do factory :test_case, class: 'Gitlab::Ci::Reports::TestCase' do
suite_name { "rspec" }
name { "test-1" } name { "test-1" }
classname { "trace" } classname { "trace" }
file { "spec/trace_spec.rb" } file { "spec/trace_spec.rb" }
...@@ -25,6 +26,7 @@ FactoryBot.define do ...@@ -25,6 +26,7 @@ FactoryBot.define do
initialize_with do initialize_with do
new( new(
suite_name: suite_name,
name: name, name: name,
classname: classname, classname: classname,
file: file, file: file,
......
...@@ -43,7 +43,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do ...@@ -43,7 +43,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
let(:junit) do let(:junit) do
<<-EOF.strip_heredoc <<-EOF.strip_heredoc
<testsuites> <testsuites>
<testsuite> <testsuite name='Math'>
<testcase classname='Calculator' name='sumTest1' time='0.01'></testcase> <testcase classname='Calculator' name='sumTest1' time='0.01'></testcase>
</testsuite> </testsuite>
</testsuites> </testsuites>
...@@ -53,6 +53,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do ...@@ -53,6 +53,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
it 'parses XML and adds a test case to a suite' do it 'parses XML and adds a test case to a suite' do
expect { subject }.not_to raise_error expect { subject }.not_to raise_error
expect(test_cases[0].suite_name).to eq('Math')
expect(test_cases[0].classname).to eq('Calculator') expect(test_cases[0].classname).to eq('Calculator')
expect(test_cases[0].name).to eq('sumTest1') expect(test_cases[0].name).to eq('sumTest1')
expect(test_cases[0].execution_time).to eq(0.01) expect(test_cases[0].execution_time).to eq(0.01)
...@@ -62,7 +63,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do ...@@ -62,7 +63,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
context 'when there is <testcase>' do context 'when there is <testcase>' do
let(:junit) do let(:junit) do
<<-EOF.strip_heredoc <<-EOF.strip_heredoc
<testsuite> <testsuite name='Math'>
<testcase classname='Calculator' name='sumTest1' time='0.01'> <testcase classname='Calculator' name='sumTest1' time='0.01'>
#{testcase_content} #{testcase_content}
</testcase> </testcase>
...@@ -79,6 +80,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do ...@@ -79,6 +80,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
shared_examples_for '<testcase> XML parser' do |status, output| shared_examples_for '<testcase> XML parser' do |status, output|
it 'parses XML and adds a test case to the suite' do it 'parses XML and adds a test case to the suite' do
aggregate_failures do aggregate_failures do
expect(test_case.suite_name).to eq('Math')
expect(test_case.classname).to eq('Calculator') expect(test_case.classname).to eq('Calculator')
expect(test_case.name).to eq('sumTest1') expect(test_case.name).to eq('sumTest1')
expect(test_case.execution_time).to eq(0.01) expect(test_case.execution_time).to eq(0.01)
...@@ -152,13 +154,15 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do ...@@ -152,13 +154,15 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
expect { subject }.not_to raise_error expect { subject }.not_to raise_error
expect(test_cases.count).to eq(1) expect(test_cases.count).to eq(1)
expect(test_cases.first.suite_name).to eq("XXX\\FrontEnd\\WebBundle\\Tests\\Controller\\LogControllerTest")
expect(test_cases.first.name).to eq("testIndexAction")
end end
end end
context 'when there are two test cases' do context 'when there are two test cases' do
let(:junit) do let(:junit) do
<<-EOF.strip_heredoc <<-EOF.strip_heredoc
<testsuite> <testsuite name='Math'>
<testcase classname='Calculator' name='sumTest1' time='0.01'></testcase> <testcase classname='Calculator' name='sumTest1' time='0.01'></testcase>
<testcase classname='Calculator' name='sumTest2' time='0.02'></testcase> <testcase classname='Calculator' name='sumTest2' time='0.02'></testcase>
</testsuite> </testsuite>
...@@ -168,9 +172,11 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do ...@@ -168,9 +172,11 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
it 'parses XML and adds test cases to a suite' do it 'parses XML and adds test cases to a suite' do
expect { subject }.not_to raise_error expect { subject }.not_to raise_error
expect(test_cases[0].suite_name).to eq('Math')
expect(test_cases[0].classname).to eq('Calculator') expect(test_cases[0].classname).to eq('Calculator')
expect(test_cases[0].name).to eq('sumTest1') expect(test_cases[0].name).to eq('sumTest1')
expect(test_cases[0].execution_time).to eq(0.01) expect(test_cases[0].execution_time).to eq(0.01)
expect(test_cases[1].suite_name).to eq('Math')
expect(test_cases[1].classname).to eq('Calculator') expect(test_cases[1].classname).to eq('Calculator')
expect(test_cases[1].name).to eq('sumTest2') expect(test_cases[1].name).to eq('sumTest2')
expect(test_cases[1].execution_time).to eq(0.02) expect(test_cases[1].execution_time).to eq(0.02)
...@@ -181,7 +187,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do ...@@ -181,7 +187,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
let(:junit) do let(:junit) do
<<-EOF.strip_heredoc <<-EOF.strip_heredoc
<testsuites> <testsuites>
<testsuite> <testsuite name='Math'>
<testcase classname='Calculator' name='sumTest1' time='0.01'></testcase> <testcase classname='Calculator' name='sumTest1' time='0.01'></testcase>
<testcase classname='Calculator' name='sumTest2' time='0.02'></testcase> <testcase classname='Calculator' name='sumTest2' time='0.02'></testcase>
</testsuite> </testsuite>
...@@ -196,18 +202,32 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do ...@@ -196,18 +202,32 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
it 'parses XML and adds test cases to a suite' do it 'parses XML and adds test cases to a suite' do
expect { subject }.not_to raise_error expect { subject }.not_to raise_error
expect(test_cases[0].classname).to eq('Calculator') expect(test_cases).to contain_exactly(
expect(test_cases[0].name).to eq('sumTest1') have_attributes(
expect(test_cases[0].execution_time).to eq(0.01) suite_name: 'Math',
expect(test_cases[1].classname).to eq('Calculator') classname: 'Calculator',
expect(test_cases[1].name).to eq('sumTest2') name: 'sumTest1',
expect(test_cases[1].execution_time).to eq(0.02) execution_time: 0.01
expect(test_cases[2].classname).to eq('Statemachine') ),
expect(test_cases[2].name).to eq('happy path') have_attributes(
expect(test_cases[2].execution_time).to eq(100) suite_name: 'Math',
expect(test_cases[3].classname).to eq('Statemachine') classname: 'Calculator',
expect(test_cases[3].name).to eq('unhappy path') name: 'sumTest2',
expect(test_cases[3].execution_time).to eq(200) execution_time: 0.02
),
have_attributes(
suite_name: test_suite.name, # Defaults to test suite instance's name
classname: 'Statemachine',
name: 'happy path',
execution_time: 100
),
have_attributes(
suite_name: test_suite.name, # Defaults to test suite instance's name
classname: 'Statemachine',
name: 'unhappy path',
execution_time: 200
)
)
end end
end end
end end
......
...@@ -6,39 +6,26 @@ RSpec.describe Gitlab::Ci::Reports::TestCase do ...@@ -6,39 +6,26 @@ RSpec.describe Gitlab::Ci::Reports::TestCase do
describe '#initialize' do describe '#initialize' do
let(:test_case) { described_class.new(params) } let(:test_case) { described_class.new(params) }
context 'when both classname and name are given' do context 'when required params are given' do
context 'when test case is passed' do let(:job) { build(:ci_build) }
let(:job) { build(:ci_build) } let(:params) { attributes_for(:test_case).merge!(job: job) }
let(:params) { attributes_for(:test_case).merge!(job: job) }
it 'initializes an instance' do
expect { test_case }.not_to raise_error
expect(test_case.name).to eq('test-1')
expect(test_case.classname).to eq('trace')
expect(test_case.file).to eq('spec/trace_spec.rb')
expect(test_case.execution_time).to eq(1.23)
expect(test_case.status).to eq(described_class::STATUS_SUCCESS)
expect(test_case.system_output).to be_nil
expect(test_case.job).to be_present
end
end
context 'when test case is failed' do it 'initializes an instance', :aggregate_failures do
let(:job) { build(:ci_build) } expect { test_case }.not_to raise_error
let(:params) { attributes_for(:test_case, :failed).merge!(job: job) }
expect(test_case).to have_attributes(
it 'initializes an instance' do suite_name: params[:suite_name],
expect { test_case }.not_to raise_error name: params[:name],
classname: params[:classname],
expect(test_case.name).to eq('test-1') file: params[:file],
expect(test_case.classname).to eq('trace') execution_time: params[:execution_time],
expect(test_case.file).to eq('spec/trace_spec.rb') status: params[:status],
expect(test_case.execution_time).to eq(1.23) system_output: params[:system_output],
expect(test_case.status).to eq(described_class::STATUS_FAILED) job: params[:job]
expect(test_case.system_output) )
.to eq('Failure/Error: is_expected.to eq(300) expected: 300 got: -100')
end key = "#{test_case.suite_name}_#{test_case.classname}_#{test_case.name}"
expect(test_case.key).to eq(Digest::SHA256.hexdigest(key))
end end
end end
...@@ -53,6 +40,10 @@ RSpec.describe Gitlab::Ci::Reports::TestCase do ...@@ -53,6 +40,10 @@ RSpec.describe Gitlab::Ci::Reports::TestCase do
end end
end end
context 'when suite_name is missing' do
it_behaves_like 'param is missing', :suite_name
end
context 'when classname is missing' do context 'when classname is missing' do
it_behaves_like 'param is missing', :classname it_behaves_like 'param is missing', :classname
end end
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
module TestReportsHelper module TestReportsHelper
def create_test_case_rspec_success(name = 'test_spec') def create_test_case_rspec_success(name = 'test_spec')
Gitlab::Ci::Reports::TestCase.new( Gitlab::Ci::Reports::TestCase.new(
suite_name: 'rspec',
name: 'Test#sum when a is 1 and b is 3 returns summary', name: 'Test#sum when a is 1 and b is 3 returns summary',
classname: "spec.#{name}", classname: "spec.#{name}",
file: './spec/test_spec.rb', file: './spec/test_spec.rb',
...@@ -12,6 +13,7 @@ module TestReportsHelper ...@@ -12,6 +13,7 @@ module TestReportsHelper
def create_test_case_rspec_failed(name = 'test_spec', execution_time = 2.22) def create_test_case_rspec_failed(name = 'test_spec', execution_time = 2.22)
Gitlab::Ci::Reports::TestCase.new( Gitlab::Ci::Reports::TestCase.new(
suite_name: 'rspec',
name: 'Test#sum when a is 1 and b is 3 returns summary', name: 'Test#sum when a is 1 and b is 3 returns summary',
classname: "spec.#{name}", classname: "spec.#{name}",
file: './spec/test_spec.rb', file: './spec/test_spec.rb',
...@@ -22,6 +24,7 @@ module TestReportsHelper ...@@ -22,6 +24,7 @@ module TestReportsHelper
def create_test_case_rspec_skipped(name = 'test_spec') def create_test_case_rspec_skipped(name = 'test_spec')
Gitlab::Ci::Reports::TestCase.new( Gitlab::Ci::Reports::TestCase.new(
suite_name: 'rspec',
name: 'Test#sum when a is 3 and b is 3 returns summary', name: 'Test#sum when a is 3 and b is 3 returns summary',
classname: "spec.#{name}", classname: "spec.#{name}",
file: './spec/test_spec.rb', file: './spec/test_spec.rb',
...@@ -31,6 +34,7 @@ module TestReportsHelper ...@@ -31,6 +34,7 @@ module TestReportsHelper
def create_test_case_rspec_error(name = 'test_spec') def create_test_case_rspec_error(name = 'test_spec')
Gitlab::Ci::Reports::TestCase.new( Gitlab::Ci::Reports::TestCase.new(
suite_name: 'rspec',
name: 'Test#sum when a is 4 and b is 4 returns summary', name: 'Test#sum when a is 4 and b is 4 returns summary',
classname: "spec.#{name}", classname: "spec.#{name}",
file: './spec/test_spec.rb', file: './spec/test_spec.rb',
...@@ -52,6 +56,7 @@ module TestReportsHelper ...@@ -52,6 +56,7 @@ module TestReportsHelper
def create_test_case_java_success(name = 'addTest') def create_test_case_java_success(name = 'addTest')
Gitlab::Ci::Reports::TestCase.new( Gitlab::Ci::Reports::TestCase.new(
suite_name: 'java',
name: name, name: name,
classname: 'CalculatorTest', classname: 'CalculatorTest',
execution_time: 5.55, execution_time: 5.55,
...@@ -60,6 +65,7 @@ module TestReportsHelper ...@@ -60,6 +65,7 @@ module TestReportsHelper
def create_test_case_java_failed(name = 'addTest') def create_test_case_java_failed(name = 'addTest')
Gitlab::Ci::Reports::TestCase.new( Gitlab::Ci::Reports::TestCase.new(
suite_name: 'java',
name: name, name: name,
classname: 'CalculatorTest', classname: 'CalculatorTest',
execution_time: 6.66, execution_time: 6.66,
...@@ -69,6 +75,7 @@ module TestReportsHelper ...@@ -69,6 +75,7 @@ module TestReportsHelper
def create_test_case_java_skipped(name = 'addTest') def create_test_case_java_skipped(name = 'addTest')
Gitlab::Ci::Reports::TestCase.new( Gitlab::Ci::Reports::TestCase.new(
suite_name: 'java',
name: name, name: name,
classname: 'CalculatorTest', classname: 'CalculatorTest',
execution_time: 7.77, execution_time: 7.77,
...@@ -77,6 +84,7 @@ module TestReportsHelper ...@@ -77,6 +84,7 @@ module TestReportsHelper
def create_test_case_java_error(name = 'addTest') def create_test_case_java_error(name = 'addTest')
Gitlab::Ci::Reports::TestCase.new( Gitlab::Ci::Reports::TestCase.new(
suite_name: 'java',
name: name, name: name,
classname: 'CalculatorTest', classname: 'CalculatorTest',
execution_time: 8.88, execution_time: 8.88,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment