diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-19 14:01:45 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-12-19 14:01:45 +0300 |
commit | 9297025d0b7ddf095eb618dfaaab2ff8f2018d8b (patch) | |
tree | 865198c01d1824a9b098127baa3ab980c9cd2c06 /qa/spec | |
parent | 6372471f43ee03c05a7c1f8b0c6ac6b8a7431dbe (diff) |
Add latest changes from gitlab-org/gitlab@16-7-stable-eev16.7.0-rc42
Diffstat (limited to 'qa/spec')
-rw-r--r-- | qa/spec/fixtures/knapsack_report/instance-selective-parallel.json | 3 | ||||
-rw-r--r-- | qa/spec/fixtures/knapsack_report/instance.json | 1 | ||||
-rw-r--r-- | qa/spec/git/repository_spec.rb | 2 | ||||
-rw-r--r-- | qa/spec/runtime/path_spec.rb | 27 | ||||
-rw-r--r-- | qa/spec/scenario/template_spec.rb | 57 | ||||
-rw-r--r-- | qa/spec/scenario_shared_examples.rb | 6 | ||||
-rw-r--r-- | qa/spec/spec_helper.rb | 6 | ||||
-rw-r--r-- | qa/spec/specs/allure_report_spec.rb | 2 | ||||
-rw-r--r-- | qa/spec/specs/helpers/feature_setup_spec.rb | 96 | ||||
-rw-r--r-- | qa/spec/support/knapsack_report_spec.rb | 9 | ||||
-rw-r--r-- | qa/spec/support/ssh_spec.rb | 4 | ||||
-rw-r--r-- | qa/spec/tools/reliable_report_spec.rb | 160 |
12 files changed, 266 insertions, 107 deletions
diff --git a/qa/spec/fixtures/knapsack_report/instance-selective-parallel.json b/qa/spec/fixtures/knapsack_report/instance-selective-parallel.json index adf506c9d30..0b0d0f7cee0 100644 --- a/qa/spec/fixtures/knapsack_report/instance-selective-parallel.json +++ b/qa/spec/fixtures/knapsack_report/instance-selective-parallel.json @@ -1,5 +1,4 @@ { "qa/specs/features/ee/browser_ui/3_create/repository/code_owners_with_protected_branch_and_squashed_commits_spec.rb": 18.85673829499956, - "qa/specs/features/api/3_create/repository/files_spec.rb": 3.180753622999873, - "qa/specs/features/browser_ui/3_create/web_ide_old/server_hooks_custom_error_message_spec.rb": 0.010764157999801682 + "qa/specs/features/api/3_create/repository/files_spec.rb": 3.180753622999873 } diff --git a/qa/spec/fixtures/knapsack_report/instance.json b/qa/spec/fixtures/knapsack_report/instance.json index 3d659bc53fb..f28bf78e890 100644 --- a/qa/spec/fixtures/knapsack_report/instance.json +++ b/qa/spec/fixtures/knapsack_report/instance.json @@ -1,7 +1,6 @@ { "qa/specs/features/ee/browser_ui/3_create/repository/code_owners_with_protected_branch_and_squashed_commits_spec.rb": 18.85673829499956, "qa/specs/features/api/3_create/repository/files_spec.rb": 3.180753622999873, - "qa/specs/features/browser_ui/3_create/web_ide_old/server_hooks_custom_error_message_spec.rb": 0.010764157999801682, "qa/specs/features/api/9_data_stores/users_spec.rb": 0.2808277129997805, "qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb": 4.882168451000325 } diff --git a/qa/spec/git/repository_spec.rb b/qa/spec/git/repository_spec.rb index 513e807dd99..c2442db9ec9 100644 --- a/qa/spec/git/repository_spec.rb +++ b/qa/spec/git/repository_spec.rb @@ -9,7 +9,7 @@ RSpec.describe QA::Git::Repository do let(:repo_uri_with_credentials) { 'http://root@foo/bar.git' } let(:env_vars) { [%q(HOME="temp")] } let(:extra_env_vars) { [] } - let(:run_params) { { env: env_vars + extra_env_vars, log_prefix: "Git: " } } + let(:run_params) { { env: env_vars + extra_env_vars, sleep_internal: 10, log_prefix: "Git: " } } let(:repository) do described_class.new.tap do |r| r.uri = repo_uri diff --git a/qa/spec/runtime/path_spec.rb b/qa/spec/runtime/path_spec.rb new file mode 100644 index 00000000000..276522b3276 --- /dev/null +++ b/qa/spec/runtime/path_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +RSpec.describe QA::Runtime::Path do + describe '.qa_root' do + it 'returns the fully-qualified path to the QA directory' do + expect(described_class.qa_root).to eq(File.expand_path('../../', __dir__)) + end + end + + describe '.fixtures_path' do + it 'returns the fully-qualified path to the fixtures directory' do + expect(described_class.fixtures_path).to eq(File.expand_path('../../qa/fixtures', __dir__)) + end + end + + describe '.fixture' do + it 'returns the fully-qualified path to a fixture file' do + expect(described_class.fixture('foo', 'bar')).to eq(File.expand_path('../../qa/fixtures/foo/bar', __dir__)) + end + end + + describe '.qa_tmp' do + it 'returns the fully-qualified path to the qa tmp directory' do + expect(described_class.qa_tmp('foo', 'bar')).to eq(File.expand_path('../../tmp/foo/bar', __dir__)) + end + end +end diff --git a/qa/spec/scenario/template_spec.rb b/qa/spec/scenario/template_spec.rb index 56521cc13bc..37875ad57c9 100644 --- a/qa/spec/scenario/template_spec.rb +++ b/qa/spec/scenario/template_spec.rb @@ -11,7 +11,6 @@ RSpec.describe QA::Scenario::Template do before do stub_const('QA::Runtime::Release', release) - stub_const('QA::Runtime::Feature', feature) stub_const('QA::Runtime::Scenario', scenario) stub_const('QA::Specs::Runner', runner) @@ -26,62 +25,6 @@ RSpec.describe QA::Scenario::Template do QA::Support::GitlabAddress.instance_variable_set(:@initialized, false) end - it 'allows a feature to be enabled' do - subject.perform({ gitlab_address: gitlab_address, enable_feature: 'a-feature' }) - - expect(feature).to have_received(:enable).with('a-feature') - expect(feature).to have_received(:disable).with('a-feature') - end - - it 'allows a feature to be disabled' do - allow(QA::Runtime::Feature).to receive(:enabled?).with('another-feature').and_return(true) - - subject.perform({ gitlab_address: gitlab_address, disable_feature: 'another-feature' }) - - expect(feature).to have_received(:disable).with('another-feature') - expect(feature).to have_received(:enable).with('another-feature') - end - - it 'does not disable a feature if already disabled' do - allow(QA::Runtime::Feature).to receive(:enabled?).with('another-feature').and_return(false) - - subject.perform({ gitlab_address: gitlab_address, disable_feature: 'another-feature' }) - - expect(feature).not_to have_received(:disable).with('another-feature') - end - - it 'ensures an enabled feature is disabled afterwards' do - allow(QA::Specs::Runner).to receive(:perform).and_raise('failed test') - - expect { subject.perform({ gitlab_address: gitlab_address, enable_feature: 'a-feature' }) } - .to raise_error('failed test') - - expect(feature).to have_received(:enable).with('a-feature') - expect(feature).to have_received(:disable).with('a-feature') - end - - it 'ensures a disabled feature is enabled afterwards' do - allow(QA::Specs::Runner).to receive(:perform).and_raise('failed test') - allow(QA::Runtime::Feature).to receive(:enabled?).with('another-feature').and_return(true) - - expect { subject.perform({ gitlab_address: gitlab_address, disable_feature: 'another-feature' }) } - .to raise_error('failed test') - - expect(feature).to have_received(:disable).with('another-feature') - expect(feature).to have_received(:enable).with('another-feature') - end - - it 'ensures a disabled feature is not enabled afterwards if it was disabled earlier' do - allow(QA::Specs::Runner).to receive(:perform).and_raise('failed test') - allow(QA::Runtime::Feature).to receive(:enabled?).with('another-feature').and_return(false) - - expect { subject.perform({ gitlab_address: gitlab_address, disable_feature: 'another-feature' }) } - .to raise_error('failed test') - - expect(feature).not_to have_received(:disable).with('another-feature') - expect(feature).not_to have_received(:enable).with('another-feature') - end - it 'defines gitlab address from positional argument' do allow(scenario).to receive(:attributes).and_return({}) diff --git a/qa/spec/scenario_shared_examples.rb b/qa/spec/scenario_shared_examples.rb index 944e309c4cb..968bbfdd7dd 100644 --- a/qa/spec/scenario_shared_examples.rb +++ b/qa/spec/scenario_shared_examples.rb @@ -28,12 +28,6 @@ module QA expect(subject).to respond_to(:perform) end - it 'performs before hooks only once' do - subject.perform(args) - - expect(release).to have_received(:perform_before_hooks).once - end - it 'sets tags on runner' do subject.perform(args) diff --git a/qa/spec/spec_helper.rb b/qa/spec/spec_helper.rb index 84d3199a274..2fe6fd8f325 100644 --- a/qa/spec/spec_helper.rb +++ b/qa/spec/spec_helper.rb @@ -4,3 +4,9 @@ require_relative '../qa' require_relative 'scenario_shared_examples' require_relative('../../jh/qa/spec/spec_helper') if GitlabEdition.jh? + +RSpec.configure do |config| + config.expect_with :rspec do |expectations| + expectations.max_formatted_output_length = nil + end +end diff --git a/qa/spec/specs/allure_report_spec.rb b/qa/spec/specs/allure_report_spec.rb index 85befb2f602..8b01d50b4f3 100644 --- a/qa/spec/specs/allure_report_spec.rb +++ b/qa/spec/specs/allure_report_spec.rb @@ -3,7 +3,7 @@ describe QA::Runtime::AllureReport do include QA::Support::Helpers::StubEnv - let(:rspec_config) { instance_double('RSpec::Core::Configuration', 'add_formatter': nil, append_after: nil) } + let(:rspec_config) { instance_double('RSpec::Core::Configuration', add_formatter: nil, append_after: nil) } let(:png_path) { 'png_path' } let(:html_path) { 'html_path' } diff --git a/qa/spec/specs/helpers/feature_setup_spec.rb b/qa/spec/specs/helpers/feature_setup_spec.rb new file mode 100644 index 00000000000..07203e31aca --- /dev/null +++ b/qa/spec/specs/helpers/feature_setup_spec.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true + +describe QA::Specs::Helpers::FeatureSetup do + include QA::Support::Helpers::StubEnv + + let(:rspec_config) { instance_double(RSpec::Core::Configuration) } + let(:options) { {} } + let(:feature_enabled) { true } + + let(:feature_flags_env) { "" } + let(:feature_flags) { feature_flags_env.split(",").to_h { |ff| ff.split("=") } } + + before do + stub_env('QA_FEATURE_FLAGS', feature_flags_env) + + allow(RSpec).to receive(:configure).and_yield(rspec_config) + allow(rspec_config).to receive(:before).with(:suite).and_yield + allow(rspec_config).to receive(:after).with(:suite).and_yield + + allow(QA::Support::GlobalOptions).to receive(:get).and_return(options) + allow(QA::Runtime::Feature).to receive(:disable) + allow(QA::Runtime::Feature).to receive(:enable) + allow(QA::Runtime::Feature).to receive(:set).with(feature_flags) + allow(QA::Runtime::Feature).to receive(:enabled?).and_return(feature_enabled) + allow(QA::Runtime::Logger).to receive(:logger).and_return(instance_double(ActiveSupport::Logger, error: nil)) + + described_class.configure! + end + + context "without any features configured" do + it "doesn't perform any operations" do + expect(QA::Runtime::Feature).not_to have_received(:set) + expect(QA::Runtime::Feature).not_to have_received(:enable) + expect(QA::Runtime::Feature).not_to have_received(:disable) + end + end + + context "with enabling a feature" do + let(:options) { { enable_feature: 'a-feature' } } + + context "when feature is not enabled" do + let(:feature_enabled) { false } + + it "enables and restores feature" do + expect(QA::Runtime::Feature).to have_received(:enable).with(options[:enable_feature]) + expect(QA::Runtime::Feature).to have_received(:disable).with(options[:enable_feature]) + end + end + + context "when feature is already enabled" do + it "skips feature" do + expect(QA::Runtime::Feature).not_to have_received(:disable) + expect(QA::Runtime::Feature).not_to have_received(:enable) + end + end + end + + context "with disabling a feature" do + let(:options) { { disable_feature: 'a-feature' } } + + context "when feature is enabled" do + it "disables and restore feature" do + expect(QA::Runtime::Feature).to have_received(:disable).with(options[:disable_feature]) + expect(QA::Runtime::Feature).to have_received(:enable).with(options[:disable_feature]) + end + end + + context "when feature is already disabled" do + let(:feature_enabled) { false } + + it "skips feature" do + expect(QA::Runtime::Feature).not_to have_received(:disable) + expect(QA::Runtime::Feature).not_to have_received(:enable) + end + end + end + + context "with feature flags" do + context "with valid ff string" do + let(:feature_flags_env) { "some_flag=enabled,some_other_flag=disabled" } + + it "sets feature flags" do + expect(QA::Runtime::Feature).to have_received(:set).with(feature_flags) + end + end + + context "with not valid ff string" do + let(:feature_flags_env) { "some_flag=enabled,some_other_flag=invalid_state" } + let(:feature_flags) { { "some_flag" => "enabled" } } + + it "skips invalid pair" do + expect(QA::Runtime::Feature).to have_received(:set).with(feature_flags) + end + end + end +end diff --git a/qa/spec/support/knapsack_report_spec.rb b/qa/spec/support/knapsack_report_spec.rb index 914a30513e5..bbe560fad66 100644 --- a/qa/spec/support/knapsack_report_spec.rb +++ b/qa/spec/support/knapsack_report_spec.rb @@ -24,16 +24,9 @@ RSpec.describe QA::Support::KnapsackReport do end it 'creates a filtered file based on qa_tests' do - expect(File).to receive(:write) - .with('knapsack/instance-selective-parallel.json', expected_output.to_json) + expect(File).to receive(:write).with('knapsack/instance-selective-parallel.json', expected_output.to_json) knapsack_report.create_for_selective(qa_tests) end end - - describe '#selective_path' do - it 'returns the path with file name suffixed with -selective-parallel' do - expect(knapsack_report.selective_path).to eq('knapsack/instance-selective-parallel.json') - end - end end diff --git a/qa/spec/support/ssh_spec.rb b/qa/spec/support/ssh_spec.rb index 2edff824fd6..fe38ba7a64e 100644 --- a/qa/spec/support/ssh_spec.rb +++ b/qa/spec/support/ssh_spec.rb @@ -59,8 +59,8 @@ RSpec.describe QA::Support::SSH do end describe '#setup' do - let(:expected_ssh_command_no_port) { "ssh-keyscan -H foo.com >> #{known_hosts_file.path}" } - let(:expected_ssh_command_port) { "ssh-keyscan -H -p #{port} foo.com >> #{known_hosts_file.path}" } + let(:expected_ssh_command_no_port) { "ssh-keyscan -T 60 -H foo.com >> #{known_hosts_file.path}" } + let(:expected_ssh_command_port) { "ssh-keyscan -T 60 -H -p #{port} foo.com >> #{known_hosts_file.path}" } let(:call_method) { ssh.setup } before do diff --git a/qa/spec/tools/reliable_report_spec.rb b/qa/spec/tools/reliable_report_spec.rb index cf5c9dea794..c8488424259 100644 --- a/qa/spec/tools/reliable_report_spec.rb +++ b/qa/spec/tools/reliable_report_spec.rb @@ -18,10 +18,19 @@ describe QA::Tools::ReliableReport do let(:runs) do values = { - "name" => "stable spec", + "name" => "stable spec1", + "status" => "passed", + "file_path" => "some/spec.rb", + "stage" => "create", + "product_group" => "code_review", + "_time" => time + } + more_values = { + "name" => "stable spec2", "status" => "passed", "file_path" => "some/spec.rb", "stage" => "manage", + "product_group" => "import_and_integrate", "_time" => time } [ @@ -32,6 +41,14 @@ describe QA::Tools::ReliableReport do instance_double("InfluxDB2::FluxRecord", values: values), instance_double("InfluxDB2::FluxRecord", values: values.merge({ "_time" => Time.now.to_s })) ] + ), + instance_double( + "InfluxDB2::FluxTable", + records: [ + instance_double("InfluxDB2::FluxRecord", values: more_values), + instance_double("InfluxDB2::FluxRecord", values: more_values), + instance_double("InfluxDB2::FluxRecord", values: more_values.merge({ "_time" => Time.now.to_s })) + ] ) ] end @@ -42,6 +59,17 @@ describe QA::Tools::ReliableReport do "status" => "failed", "file_path" => "some/spec.rb", "stage" => "create", + "product_group" => "code_review", + "failure_exception" => failure_message, + "job_url" => "https://job/url", + "_time" => time + } + more_values = { + "name" => "unstable spec", + "status" => "failed", + "file_path" => "some/spec.rb", + "stage" => "manage", + "product_group" => "import_and_integrate", "failure_exception" => failure_message, "job_url" => "https://job/url", "_time" => time @@ -54,6 +82,14 @@ describe QA::Tools::ReliableReport do instance_double("InfluxDB2::FluxRecord", values: values), instance_double("InfluxDB2::FluxRecord", values: values.merge({ "_time" => Time.now.to_s })) ] + ), + instance_double( + "InfluxDB2::FluxTable", + records: [ + instance_double("InfluxDB2::FluxRecord", values: { **more_values, "status" => "passed" }), + instance_double("InfluxDB2::FluxRecord", values: more_values), + instance_double("InfluxDB2::FluxRecord", values: more_values.merge({ "_time" => Time.now.to_s })) + ] ) ] end @@ -82,21 +118,20 @@ describe QA::Tools::ReliableReport do ) |> filter(fn: (r) => r["_field"] == "job_url" or r["_field"] == "failure_exception" or - r["_field"] == "id" + r["_field"] == "id" or + r["_field"] == "failure_issue" ) |> pivot(rowKey: ["_time"], columnKey: ["_field"], valueColumn: "_value") |> group(columns: ["name"]) QUERY end - def markdown_section(summary, result, stage, type) + def expected_stage_markdown(result, stage, product_group, type) <<~SECTION.strip - #{summary_table(summary, type, true)} - - ## #{stage} (1) + ## #{stage.capitalize} (1) <details> - <summary>Executions table</summary> + <summary>Executions table ~\"group::#{product_group}\" (1)</summary> #{table(result, ['NAME', 'RUNS', 'FAILURES', 'FAILURE RATE'], "Top #{type} specs in '#{stage}' stage for past #{range} days", true)} @@ -104,7 +139,7 @@ describe QA::Tools::ReliableReport do SECTION end - def summary_table(summary, type, markdown = false) + def expected_summary_table(summary, type, markdown = false) table(summary, %w[STAGE COUNT], "#{type.capitalize} spec summary for past #{range} days".ljust(50), markdown) end @@ -117,12 +152,12 @@ describe QA::Tools::ReliableReport do ) end - def name_column(spec_name, exceptions_and_job_urls = {}) - "**Name**: #{spec_name}<br>**File**: [spec.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/specs/features/some/spec.rb)#{exceptions_markdown(exceptions_and_job_urls)}" + def name_column(spec_name, exceptions_and_related_urls = {}) + "**Name**: #{spec_name}<br>**File**: [spec.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/qa/qa/specs/features/some/spec.rb)#{exceptions_markdown(exceptions_and_related_urls)}" end - def exceptions_markdown(exceptions_and_job_urls) - exceptions_and_job_urls.empty? ? '' : "<br>**Exceptions**:<br>- [`#{failure_message}`](https://job/url)" + def exceptions_markdown(exceptions_and_related_urls) + exceptions_and_related_urls.empty? ? '' : "<br>**Exceptions**:<br>- [`#{failure_message}`](https://job/url)" end before do @@ -241,28 +276,36 @@ describe QA::Tools::ReliableReport do let(:expected_issue_body) do <<~TXT.strip - [[_TOC_]] + [[_TOC_]] + + # Candidates for promotion to reliable (#{Date.today - range} - #{Date.today}) - # Candidates for promotion to reliable (#{Date.today - range} - #{Date.today}) + Total amount: **2** - Total amount: **1** + #{expected_summary_table([['create', 1], ['manage', 1]], :stable, true)} - #{markdown_section([['manage', 1]], [[name_column('stable spec'), 3, 0, '0%']], 'manage', 'stable')} + #{expected_stage_markdown([[name_column('stable spec1'), 3, 0, '0%']], 'create', 'code review', :stable)} - # Reliable specs with failures (#{Date.today - range} - #{Date.today}) + #{expected_stage_markdown([[name_column('stable spec2'), 3, 0, '0%']], 'manage', 'import and integrate', :stable)} - Total amount: **1** + # Reliable specs with failures (#{Date.today - range} - #{Date.today}) - #{markdown_section([['create', 1]], [[name_column('unstable spec', { failure_message => 'https://job/url' }), 3, 2, '66.67%']], 'create', 'unstable')} + Total amount: **2** + + #{expected_summary_table([['create', 1], ['manage', 1]], :unstable, true)} + + #{expected_stage_markdown([[name_column('unstable spec', { failure_message => 'https://job/url' }), 3, 2, '66.67%']], 'create', 'code review', :unstable)} + + #{expected_stage_markdown([[name_column('unstable spec', { failure_message => 'https://job/url' }), 3, 2, '66.67%']], 'manage', 'import and integrate', :unstable)} TXT end let(:expected_slack_text) do <<~TEXT - ```#{summary_table([['manage', 1]], 'stable')}``` - ```#{summary_table([['create', 1]], 'unstable')}``` + ```#{expected_summary_table([['create', 1], ['manage', 1]], :stable)}``` + ```#{expected_summary_table([['create', 1], ['manage', 1]], :unstable)}``` - #{issue_url} + #{issue_url} TEXT end @@ -274,22 +317,26 @@ describe QA::Tools::ReliableReport do let(:expected_issue_body) do <<~TXT.strip - [[_TOC_]] + [[_TOC_]] - # Candidates for promotion to reliable (#{Date.today - range} - #{Date.today}) + # Candidates for promotion to reliable (#{Date.today - range} - #{Date.today}) - Total amount: **1** + Total amount: **2** - #{markdown_section([['manage', 1]], [[name_column('stable spec'), 3, 0, '0%']], 'manage', 'stable')} + #{expected_summary_table([['create', 1], ['manage', 1]], :stable, true)} + + #{expected_stage_markdown([[name_column('stable spec1'), 3, 0, '0%']], 'create', 'code review', :stable)} + + #{expected_stage_markdown([[name_column('stable spec2'), 3, 0, '0%']], 'manage', 'import and integrate', :stable)} TXT end let(:expected_slack_text) do <<~TEXT - ```#{summary_table([['manage', 1]], 'stable')}``` - ```#{summary_table([], 'unstable')}``` + ```#{expected_summary_table([['create', 1], ['manage', 1]], :stable)}``` + ```#{expected_summary_table([], :unstable)}``` - #{issue_url} + #{issue_url} TEXT end @@ -327,4 +374,59 @@ describe QA::Tools::ReliableReport do %q([Unable to find css "[data-testid=\"user_action_dropdown\"]"]))).to be false end end + + describe "#exceptions_and_related_urls" do + subject(:reliable_report) { described_class.new(14) } + + let(:failure_message) { "This is a failure exception" } + let(:job_url) { "https://example.com/job/url" } + let(:failure_issue_url) { "https://example.com/failure/issue" } + + let(:records) do + [instance_double("InfluxDB2::FluxRecord", values: values)] + end + + context "without failure_exception" do + let(:values) do + { + "failure_exception" => nil, + "job_url" => job_url, + "failure_issue" => failure_issue_url + } + end + + it "returns an empty hash" do + expect(reliable_report.send(:exceptions_and_related_urls, records)).to be_empty + end + + context "with failure_exception" do + context "without failure_issue" do + let(:values) do + { + "failure_exception" => failure_message, + "job_url" => job_url + } + end + + it "returns job_url as value" do + expect(reliable_report.send(:exceptions_and_related_urls, records).values).to eq([job_url]) + end + end + + context "with failure_issue and job_url" do + let(:values) do + { + "failure_exception" => failure_message, + "failure_issue" => failure_issue_url, + "job_url" => job_url + } + end + + it "returns failure_issue as value" do + expect(reliable_report.send(:exceptions_and_related_urls, records).values).to eq([failure_issue_url]) + end + end + end + end + end end |