From e4384360a16dd9a19d4d2d25d0ef1f2b862ed2a6 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 19 Jul 2023 14:16:28 +0000 Subject: Add latest changes from gitlab-org/gitlab@16-2-stable-ee --- spec/tooling/danger/experiments_spec.rb | 59 ++++++ spec/tooling/danger/project_helper_spec.rb | 12 +- spec/tooling/lib/tooling/find_changes_spec.rb | 2 +- spec/tooling/lib/tooling/find_tests_spec.rb | 2 +- spec/tooling/lib/tooling/gettext_extractor_spec.rb | 2 +- spec/tooling/lib/tooling/predictive_tests_spec.rb | 2 +- spec/tooling/quality/test_level_spec.rb | 2 +- spec/tooling/rspec_flaky/config_spec.rb | 106 ---------- spec/tooling/rspec_flaky/example_spec.rb | 99 --------- spec/tooling/rspec_flaky/flaky_example_spec.rb | 148 ------------- .../rspec_flaky/flaky_examples_collection_spec.rb | 85 -------- spec/tooling/rspec_flaky/listener_spec.rb | 228 --------------------- spec/tooling/rspec_flaky/report_spec.rb | 138 ------------- 13 files changed, 74 insertions(+), 811 deletions(-) create mode 100644 spec/tooling/danger/experiments_spec.rb delete mode 100644 spec/tooling/rspec_flaky/config_spec.rb delete mode 100644 spec/tooling/rspec_flaky/example_spec.rb delete mode 100644 spec/tooling/rspec_flaky/flaky_example_spec.rb delete mode 100644 spec/tooling/rspec_flaky/flaky_examples_collection_spec.rb delete mode 100644 spec/tooling/rspec_flaky/listener_spec.rb delete mode 100644 spec/tooling/rspec_flaky/report_spec.rb (limited to 'spec/tooling') diff --git a/spec/tooling/danger/experiments_spec.rb b/spec/tooling/danger/experiments_spec.rb new file mode 100644 index 00000000000..85f8060a3ec --- /dev/null +++ b/spec/tooling/danger/experiments_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'gitlab-dangerfiles' +require 'gitlab/dangerfiles/spec_helper' + +require_relative '../../../tooling/danger/experiments' + +RSpec.describe Tooling::Danger::Experiments, feature_category: :tooling do + include_context "with dangerfile" + + let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) } + + subject(:experiments) { fake_danger.new(helper: fake_helper) } + + describe '#removed_experiments' do + let(:removed_experiments_yml_files) do + [ + 'config/feature_flags/experiment/tier_badge.yml', + 'ee/config/feature_flags/experiment/direct_to_trial.yml' + ] + end + + let(:deleted_files) do + [ + 'app/models/model.rb', + 'app/assets/javascripts/file.js' + ] + removed_experiments_yml_files + end + + it 'returns names of removed experiments' do + expect(experiments.removed_experiments).to eq(%w[tier_badge direct_to_trial]) + end + end + + describe '#class_files_removed?' do + let(:removed_experiments_name) { current_experiment_with_class_files_example } + + context 'when yml file is deleted but not class file' do + let(:deleted_files) { ["config/feature_flags/experiment/#{removed_experiments_name}.yml"] } + + it 'returns false' do + expect(experiments.class_files_removed?).to eq(false) + end + end + + context 'when yml file is deleted but no corresponding class file exists' do + let(:deleted_files) { ["config/feature_flags/experiment/fake_experiment.yml"] } + + it 'returns true' do + expect(experiments.class_files_removed?).to eq(true) + end + end + end + + def current_experiment_with_class_files_example + path = Dir.glob("app/experiments/*.rb").last + File.basename(path).chomp('_experiment.rb') + end +end diff --git a/spec/tooling/danger/project_helper_spec.rb b/spec/tooling/danger/project_helper_spec.rb index 3910f569400..5ae0a8695eb 100644 --- a/spec/tooling/danger/project_helper_spec.rb +++ b/spec/tooling/danger/project_helper_spec.rb @@ -5,9 +5,9 @@ require 'gitlab-dangerfiles' require 'danger' require 'danger/plugins/internal/helper' require 'gitlab/dangerfiles/spec_helper' +require 'gitlab/rspec/all' require_relative '../../../danger/plugins/project_helper' -require_relative '../../../spec/support/helpers/stub_env' RSpec.describe Tooling::Danger::ProjectHelper do include StubENV @@ -65,6 +65,11 @@ RSpec.describe Tooling::Danger::ProjectHelper do 'config/foo.js' | [:frontend] 'config/deep/foo.js' | [:frontend] + 'app/components/pajamas/empty_state_component.html.haml' | [:frontend, :backend] + 'ee/app/components/pajamas/empty_state_component.html.haml' | [:frontend, :backend] + 'app/components/diffs/overflow_warning_component.html.haml' | [:frontend, :backend] + 'app/components/layouts/horizontal_section_component.rb' | [:frontend, :backend] + 'ee/app/assets/foo' | [:frontend] 'ee/app/views/foo' | [:frontend, :backend] 'ee/spec/frontend/bar' | [:frontend] @@ -80,6 +85,7 @@ RSpec.describe Tooling::Danger::ProjectHelper do '.rubocop.yml' | [:backend] '.rubocop_todo.yml' | [:backend] '.rubocop_todo/cop/name.yml' | [:backend] + 'gems/foo/.rubocop.yml' | [:backend] 'spec/foo' | [:backend] 'spec/foo/bar' | [:backend] @@ -112,7 +118,7 @@ RSpec.describe Tooling::Danger::ProjectHelper do 'scripts/glfm/bar.rb' | [:backend] 'scripts/glfm/bar.js' | [:frontend] - 'scripts/remote_development/run-smoke-test-suite.sh' | [:remote_development] + 'scripts/remote_development/run-smoke-test-suite.sh' | [:remote_development_be] 'scripts/lib/glfm/bar.rb' | [:backend] 'scripts/lib/glfm/bar.js' | [:frontend] 'scripts/bar.rb' | [:backend, :tooling] @@ -136,6 +142,8 @@ RSpec.describe Tooling::Danger::ProjectHelper do 'tooling/bin/find_foss_tests' | [:tooling] '.codeclimate.yml' | [:tooling] '.gitlab/CODEOWNERS' | [:tooling] + 'gems/gem.gitlab-ci.yml' | [:tooling] + 'gems/config/rubocop.yml' | [:tooling] 'lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml' | [:ci_template] 'lib/gitlab/ci/templates/dotNET-Core.yml' | [:ci_template] diff --git a/spec/tooling/lib/tooling/find_changes_spec.rb b/spec/tooling/lib/tooling/find_changes_spec.rb index 43c3da5699d..fef29ad3f2c 100644 --- a/spec/tooling/lib/tooling/find_changes_spec.rb +++ b/spec/tooling/lib/tooling/find_changes_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require_relative '../../../../tooling/lib/tooling/find_changes' -require_relative '../../../support/helpers/stub_env' +require 'gitlab/rspec/all' require 'json' require 'tempfile' diff --git a/spec/tooling/lib/tooling/find_tests_spec.rb b/spec/tooling/lib/tooling/find_tests_spec.rb index 905f81c4bbd..67b6650b335 100644 --- a/spec/tooling/lib/tooling/find_tests_spec.rb +++ b/spec/tooling/lib/tooling/find_tests_spec.rb @@ -2,7 +2,7 @@ require 'tempfile' require_relative '../../../../tooling/lib/tooling/find_tests' -require_relative '../../../support/helpers/stub_env' +require 'gitlab/rspec/all' RSpec.describe Tooling::FindTests, feature_category: :tooling do include StubENV diff --git a/spec/tooling/lib/tooling/gettext_extractor_spec.rb b/spec/tooling/lib/tooling/gettext_extractor_spec.rb index 3c0f91342c2..14310c804f1 100644 --- a/spec/tooling/lib/tooling/gettext_extractor_spec.rb +++ b/spec/tooling/lib/tooling/gettext_extractor_spec.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true require 'rspec/parameterized' +require 'gitlab/rspec/all' require_relative '../../../../tooling/lib/tooling/gettext_extractor' -require_relative '../../../support/helpers/stub_env' require_relative '../../../support/tmpdir' RSpec.describe Tooling::GettextExtractor, feature_category: :tooling do diff --git a/spec/tooling/lib/tooling/predictive_tests_spec.rb b/spec/tooling/lib/tooling/predictive_tests_spec.rb index b82364fe6f6..fdb7d09a3e2 100644 --- a/spec/tooling/lib/tooling/predictive_tests_spec.rb +++ b/spec/tooling/lib/tooling/predictive_tests_spec.rb @@ -2,8 +2,8 @@ require 'tempfile' require 'fileutils' +require 'gitlab/rspec/all' require_relative '../../../../tooling/lib/tooling/predictive_tests' -require_relative '../../../support/helpers/stub_env' RSpec.describe Tooling::PredictiveTests, feature_category: :tooling do include StubENV diff --git a/spec/tooling/quality/test_level_spec.rb b/spec/tooling/quality/test_level_spec.rb index a7e4e42206a..6ccd2e46f7b 100644 --- a/spec/tooling/quality/test_level_spec.rb +++ b/spec/tooling/quality/test_level_spec.rb @@ -238,7 +238,7 @@ RSpec.describe Quality::TestLevel, feature_category: :tooling do it 'ensures all spec/ folders are covered by a test level' do Dir['{,ee/}spec/**/*/'].each do |path| - next if path =~ %r{\A(ee/)?spec/(benchmarks|docs_screenshots|fixtures|frontend_integration|support)/} + next if %r{\A(ee/)?spec/(benchmarks|docs_screenshots|fixtures|frontend_integration|support)/}.match?(path) expect { subject.level_for(path) }.not_to raise_error end diff --git a/spec/tooling/rspec_flaky/config_spec.rb b/spec/tooling/rspec_flaky/config_spec.rb deleted file mode 100644 index 63f42d7c6cc..00000000000 --- a/spec/tooling/rspec_flaky/config_spec.rb +++ /dev/null @@ -1,106 +0,0 @@ -# frozen_string_literal: true - -require 'rspec-parameterized' -require_relative '../../support/helpers/stub_env' - -require_relative '../../../tooling/rspec_flaky/config' - -RSpec.describe RspecFlaky::Config, :aggregate_failures do - include StubENV - - before do - # Stub these env variables otherwise specs don't behave the same on the CI - stub_env('FLAKY_RSPEC_GENERATE_REPORT', nil) - stub_env('FLAKY_RSPEC_SUITE_REPORT_PATH', nil) - stub_env('FLAKY_RSPEC_REPORT_PATH', nil) - stub_env('NEW_FLAKY_RSPEC_REPORT_PATH', nil) - # Ensure the behavior is the same locally and on CI (where Rails is defined since we run this test as part of the whole suite), i.e. Rails isn't defined - allow(described_class).to receive(:rails_path).and_wrap_original do |method, path| - path - end - end - - describe '.generate_report?' do - context "when ENV['FLAKY_RSPEC_GENERATE_REPORT'] is not set" do - it 'returns false' do - expect(described_class).not_to be_generate_report - end - end - - context "when ENV['FLAKY_RSPEC_GENERATE_REPORT'] is set" do - using RSpec::Parameterized::TableSyntax - - where(:env_value, :result) do - '1' | true - 'true' | true - 'foo' | false - '0' | false - 'false' | false - end - - with_them do - before do - stub_env('FLAKY_RSPEC_GENERATE_REPORT', env_value) - end - - it 'returns false' do - expect(described_class.generate_report?).to be(result) - end - end - end - end - - describe '.suite_flaky_examples_report_path' do - context "when ENV['FLAKY_RSPEC_SUITE_REPORT_PATH'] is not set" do - it 'returns the default path' do - expect(described_class.suite_flaky_examples_report_path).to eq('rspec/flaky/suite-report.json') - end - end - - context "when ENV['FLAKY_RSPEC_SUITE_REPORT_PATH'] is set" do - before do - stub_env('FLAKY_RSPEC_SUITE_REPORT_PATH', 'foo/suite-report.json') - end - - it 'returns the value of the env variable' do - expect(described_class.suite_flaky_examples_report_path).to eq('foo/suite-report.json') - end - end - end - - describe '.flaky_examples_report_path' do - context "when ENV['FLAKY_RSPEC_REPORT_PATH'] is not set" do - it 'returns the default path' do - expect(described_class.flaky_examples_report_path).to eq('rspec/flaky/report.json') - end - end - - context "when ENV['FLAKY_RSPEC_REPORT_PATH'] is set" do - before do - stub_env('FLAKY_RSPEC_REPORT_PATH', 'foo/report.json') - end - - it 'returns the value of the env variable' do - expect(described_class.flaky_examples_report_path).to eq('foo/report.json') - end - end - end - - describe '.new_flaky_examples_report_path' do - context "when ENV['NEW_FLAKY_RSPEC_REPORT_PATH'] is not set" do - it 'returns the default path' do - expect(described_class.new_flaky_examples_report_path).to eq('rspec/flaky/new-report.json') - end - end - - context "when ENV['NEW_FLAKY_RSPEC_REPORT_PATH'] is set" do - before do - stub_env('NEW_FLAKY_RSPEC_REPORT_PATH', 'foo/new-report.json') - end - - it 'returns the value of the env variable' do - expect(described_class.new_flaky_examples_report_path).to eq('foo/new-report.json') - end - end - end -end diff --git a/spec/tooling/rspec_flaky/example_spec.rb b/spec/tooling/rspec_flaky/example_spec.rb deleted file mode 100644 index d001ed32444..00000000000 --- a/spec/tooling/rspec_flaky/example_spec.rb +++ /dev/null @@ -1,99 +0,0 @@ -# frozen_string_literal: true - -require_relative '../../../tooling/rspec_flaky/example' - -RSpec.describe RspecFlaky::Example do - let(:example_attrs) do - { - id: 'spec/foo/bar_spec.rb:2', - metadata: { - file_path: 'spec/foo/bar_spec.rb', - line_number: 2, - full_description: 'hello world', - feature_category: :feature_category - }, - execution_result: double(status: 'passed', exception: 'BOOM!'), - attempts: 1 - } - end - - let(:rspec_example) { double(example_attrs) } - - describe '#initialize' do - shared_examples 'a valid Example instance' do - it 'returns valid attributes' do - example = described_class.new(args) - - expect(example.example_id).to eq(example_attrs[:id]) - end - end - - context 'when given an Rspec::Core::Example that responds to #example' do - let(:args) { double(example: rspec_example) } - - it_behaves_like 'a valid Example instance' - end - - context 'when given an Rspec::Core::Example that does not respond to #example' do - let(:args) { rspec_example } - - it_behaves_like 'a valid Example instance' - end - end - - subject { described_class.new(rspec_example) } - - describe '#uid' do - it 'returns a hash of the full description' do - expect(subject.uid).to eq(Digest::MD5.hexdigest("#{subject.description}-#{subject.file}")) - end - end - - describe '#example_id' do - it 'returns the ID of the RSpec::Core::Example' do - expect(subject.example_id).to eq(rspec_example.id) - end - end - - describe '#attempts' do - it 'returns the attempts of the RSpec::Core::Example' do - expect(subject.attempts).to eq(rspec_example.attempts) - end - end - - describe '#file' do - it 'returns the metadata[:file_path] of the RSpec::Core::Example' do - expect(subject.file).to eq(rspec_example.metadata[:file_path]) - end - end - - describe '#line' do - it 'returns the metadata[:line_number] of the RSpec::Core::Example' do - expect(subject.line).to eq(rspec_example.metadata[:line_number]) - end - end - - describe '#description' do - it 'returns the metadata[:full_description] of the RSpec::Core::Example' do - expect(subject.description).to eq(rspec_example.metadata[:full_description]) - end - end - - describe '#status' do - it 'returns the execution_result.status of the RSpec::Core::Example' do - expect(subject.status).to eq(rspec_example.execution_result.status) - end - end - - describe '#exception' do - it 'returns the execution_result.exception of the RSpec::Core::Example' do - expect(subject.exception).to eq(rspec_example.execution_result.exception) - end - end - - describe '#feature_category' do - it 'returns the metadata[:feature_category] of the RSpec::Core::Example' do - expect(subject.feature_category).to eq(rspec_example.metadata[:feature_category]) - end - end -end diff --git a/spec/tooling/rspec_flaky/flaky_example_spec.rb b/spec/tooling/rspec_flaky/flaky_example_spec.rb deleted file mode 100644 index 511f3286f56..00000000000 --- a/spec/tooling/rspec_flaky/flaky_example_spec.rb +++ /dev/null @@ -1,148 +0,0 @@ -# frozen_string_literal: true - -require_relative '../../support/helpers/stub_env' -require_relative '../../support/time_travel' - -require_relative '../../../tooling/rspec_flaky/flaky_example' - -RSpec.describe RspecFlaky::FlakyExample, :aggregate_failures do - include ActiveSupport::Testing::TimeHelpers - include StubENV - - let(:example_attrs) do - { - example_id: 'spec/foo/bar_spec.rb:2', - file: 'spec/foo/bar_spec.rb', - line: 2, - description: 'hello world', - last_attempts_count: 2, - feature_category: :feature_category - } - end - - before do - # Stub these env variables otherwise specs don't behave the same on the CI - stub_env('CI_JOB_URL', nil) - end - - describe '#initialize', :freeze_time do - shared_examples 'a valid FlakyExample instance' do - let(:flaky_example) { described_class.new(args) } - - it 'returns valid attributes' do - attrs = flaky_example.to_h - - expect(attrs[:uid]).to eq(example_attrs[:uid]) - expect(attrs[:file]).to eq(example_attrs[:file]) - expect(attrs[:line]).to eq(example_attrs[:line]) - expect(attrs[:description]).to eq(example_attrs[:description]) - expect(attrs[:feature_category]).to eq(example_attrs[:feature_category]) - expect(attrs[:first_flaky_at]).to eq(expected_first_flaky_at) - expect(attrs[:last_flaky_at]).to eq(expected_last_flaky_at) - expect(attrs[:last_attempts_count]).to eq(example_attrs[:last_attempts_count]) - expect(attrs[:flaky_reports]).to eq(expected_flaky_reports) - end - end - - context 'when given an Example.to_h' do - it_behaves_like 'a valid FlakyExample instance' do - let(:args) { example_attrs } - let(:expected_first_flaky_at) { Time.now } - let(:expected_last_flaky_at) { Time.now } - let(:expected_flaky_reports) { 0 } - end - end - end - - describe '#update!' do - shared_examples 'an up-to-date FlakyExample instance' do - let(:flaky_example) { described_class.new(args) } - - it 'sets the first_flaky_at if none exists' do - args[:first_flaky_at] = nil - - freeze_time do - flaky_example.update!(example_attrs) - - expect(flaky_example.to_h[:first_flaky_at]).to eq(Time.now) - end - end - - it 'maintains the first_flaky_at if exists' do - flaky_example.update!(example_attrs) - expected_first_flaky_at = flaky_example.to_h[:first_flaky_at] - - travel_to(Time.now + 42) do - flaky_example.update!(example_attrs) - expect(flaky_example.to_h[:first_flaky_at]).to eq(expected_first_flaky_at) - end - end - - it 'updates the last_flaky_at' do - travel_to(Time.now + 42) do - the_future = Time.now - flaky_example.update!(example_attrs) - - expect(flaky_example.to_h[:last_flaky_at]).to eq(the_future) - end - end - - it 'updates the flaky_reports' do - expected_flaky_reports = flaky_example.to_h[:first_flaky_at] ? flaky_example.to_h[:flaky_reports] + 1 : 1 - - expect { flaky_example.update!(example_attrs) }.to change { flaky_example.to_h[:flaky_reports] }.by(1) - expect(flaky_example.to_h[:flaky_reports]).to eq(expected_flaky_reports) - end - - it 'updates the last_attempts_count' do - example_attrs[:last_attempts_count] = 42 - flaky_example.update!(example_attrs) - - expect(flaky_example.to_h[:last_attempts_count]).to eq(42) - end - - context 'when run on the CI' do - let(:job_url) { 'https://gitlab.com/gitlab-org/gitlab-foss/-/jobs/42' } - - before do - stub_env('CI_JOB_URL', job_url) - end - - it 'updates the last_flaky_job' do - flaky_example.update!(example_attrs) - - expect(flaky_example.to_h[:last_flaky_job]).to eq(job_url) - end - end - end - - context 'when given an Example hash' do - it_behaves_like 'an up-to-date FlakyExample instance' do - let(:args) { example_attrs } - end - end - end - - describe '#to_h', :freeze_time do - shared_examples 'a valid FlakyExample hash' do - let(:additional_attrs) { {} } - - it 'returns a valid hash' do - flaky_example = described_class.new(args) - final_hash = example_attrs.merge(additional_attrs) - - expect(flaky_example.to_h).to eq(final_hash) - end - end - - context 'when given an Example hash' do - let(:args) { example_attrs } - - it_behaves_like 'a valid FlakyExample hash' do - let(:additional_attrs) do - { first_flaky_at: Time.now, last_flaky_at: Time.now, last_flaky_job: nil, flaky_reports: 0 } - end - end - end - end -end diff --git a/spec/tooling/rspec_flaky/flaky_examples_collection_spec.rb b/spec/tooling/rspec_flaky/flaky_examples_collection_spec.rb deleted file mode 100644 index 9d75c97febe..00000000000 --- a/spec/tooling/rspec_flaky/flaky_examples_collection_spec.rb +++ /dev/null @@ -1,85 +0,0 @@ -# frozen_string_literal: true - -require_relative '../../support/time_travel' - -require_relative '../../../tooling/rspec_flaky/flaky_examples_collection' - -RSpec.describe RspecFlaky::FlakyExamplesCollection, :aggregate_failures, :freeze_time do - let(:collection_hash) do - { - a: { example_id: 'spec/foo/bar_spec.rb:2' }, - b: { example_id: 'spec/foo/baz_spec.rb:3' } - } - end - - let(:collection_report) do - { - a: { - example_id: 'spec/foo/bar_spec.rb:2', - first_flaky_at: Time.now, - last_flaky_at: Time.now, - last_flaky_job: nil, - flaky_reports: 0, - feature_category: nil, - last_attempts_count: nil - }, - b: { - example_id: 'spec/foo/baz_spec.rb:3', - first_flaky_at: Time.now, - last_flaky_at: Time.now, - last_flaky_job: nil, - flaky_reports: 0, - feature_category: nil, - last_attempts_count: nil - } - } - end - - describe '#initialize' do - it 'accepts no argument' do - expect { described_class.new }.not_to raise_error - end - - it 'accepts a hash' do - expect { described_class.new(collection_hash) }.not_to raise_error - end - - it 'does not accept anything else' do - expect { described_class.new([1, 2, 3]) }.to raise_error(ArgumentError, "`collection` must be a Hash, Array given!") - end - end - - describe '#to_h' do - it 'calls #to_h on the values' do - collection = described_class.new(collection_hash) - - expect(collection.to_h).to eq(collection_report) - end - end - - describe '#-' do - it 'returns only examples that are not present in the given collection' do - collection1 = described_class.new(collection_hash) - collection2 = described_class.new( - a: { example_id: 'spec/foo/bar_spec.rb:2' }, - c: { example_id: 'spec/bar/baz_spec.rb:4' }) - - expect((collection2 - collection1).to_h).to eq( - c: { - example_id: 'spec/bar/baz_spec.rb:4', - first_flaky_at: Time.now, - last_flaky_at: Time.now, - last_flaky_job: nil, - flaky_reports: 0, - feature_category: nil, - last_attempts_count: nil - }) - end - - it 'fails if the given collection does not respond to `#key?`' do - collection = described_class.new(collection_hash) - - expect { collection - [1, 2, 3] }.to raise_error(ArgumentError, "`other` must respond to `#key?`, Array does not!") - end - end -end diff --git a/spec/tooling/rspec_flaky/listener_spec.rb b/spec/tooling/rspec_flaky/listener_spec.rb deleted file mode 100644 index 0bbd6454969..00000000000 --- a/spec/tooling/rspec_flaky/listener_spec.rb +++ /dev/null @@ -1,228 +0,0 @@ -# frozen_string_literal: true - -require_relative '../../support/helpers/stub_env' -require_relative '../../support/time_travel' - -require_relative '../../../tooling/rspec_flaky/listener' - -RSpec.describe RspecFlaky::Listener, :aggregate_failures do - include ActiveSupport::Testing::TimeHelpers - include StubENV - - let(:already_flaky_example_uid) { '6e869794f4cfd2badd93eb68719371d1' } - let(:suite_flaky_example_report) do - { - "#{already_flaky_example_uid}": { - example_id: 'spec/foo/bar_spec.rb:2', - file: 'spec/foo/bar_spec.rb', - line: 2, - description: 'hello world', - first_flaky_at: 1234, - last_flaky_at: 4321, - last_attempts_count: 3, - flaky_reports: 1, - last_flaky_job: nil - } - } - end - - let(:already_flaky_example_attrs) do - { - id: 'spec/foo/bar_spec.rb:2', - metadata: { - file_path: 'spec/foo/bar_spec.rb', - line_number: 2, - full_description: 'hello world' - }, - execution_result: double(status: 'passed', exception: nil) - } - end - - let(:already_flaky_example) { RspecFlaky::FlakyExample.new(suite_flaky_example_report[already_flaky_example_uid]) } - let(:new_example_attrs) do - { - id: 'spec/foo/baz_spec.rb:3', - metadata: { - file_path: 'spec/foo/baz_spec.rb', - line_number: 3, - full_description: 'hello GitLab' - }, - execution_result: double(status: 'passed', exception: nil) - } - end - - before do - # Stub these env variables otherwise specs don't behave the same on the CI - stub_env('CI_JOB_URL', nil) - stub_env('FLAKY_RSPEC_SUITE_REPORT_PATH', nil) - end - - describe '#initialize' do - shared_examples 'a valid Listener instance' do - let(:expected_suite_flaky_examples) { {} } - - it 'returns a valid Listener instance' do - listener = described_class.new - - expect(listener.suite_flaky_examples.to_h).to eq(expected_suite_flaky_examples) - expect(listener.flaky_examples).to eq({}) - end - end - - context 'when no report file exists' do - it_behaves_like 'a valid Listener instance' - end - - context 'when FLAKY_RSPEC_SUITE_REPORT_PATH is set' do - let(:report_file_path) { 'foo/report.json' } - - before do - stub_env('FLAKY_RSPEC_SUITE_REPORT_PATH', report_file_path) - end - - context 'and report file exists' do - before do - expect(File).to receive(:exist?).with(report_file_path).and_return(true) - end - - it 'delegates the load to RspecFlaky::Report' do - report = RspecFlaky::Report.new(RspecFlaky::FlakyExamplesCollection.new(suite_flaky_example_report)) - - expect(RspecFlaky::Report).to receive(:load).with(report_file_path).and_return(report) - expect(described_class.new.suite_flaky_examples.to_h).to eq(report.flaky_examples.to_h) - end - end - - context 'and report file does not exist' do - before do - expect(File).to receive(:exist?).with(report_file_path).and_return(false) - end - - it 'return an empty hash' do - expect(RspecFlaky::Report).not_to receive(:load) - expect(described_class.new.suite_flaky_examples.to_h).to eq({}) - end - end - end - end - - describe '#example_passed' do - let(:rspec_example) { double(new_example_attrs) } - let(:notification) { double(example: rspec_example) } - let(:listener) { described_class.new(suite_flaky_example_report.to_json) } - - shared_examples 'a non-flaky example' do - it 'does not change the flaky examples hash' do - expect { listener.example_passed(notification) } - .not_to change { listener.flaky_examples } - end - end - - shared_examples 'an existing flaky example' do - let(:expected_flaky_example) do - { - example_id: 'spec/foo/bar_spec.rb:2', - file: 'spec/foo/bar_spec.rb', - line: 2, - description: 'hello world', - first_flaky_at: 1234, - last_attempts_count: 2, - flaky_reports: 2, - feature_category: nil, - last_flaky_job: nil - } - end - - it 'changes the flaky examples hash' do - new_example = RspecFlaky::Example.new(rspec_example) - - travel_to(Time.now + 42) do - the_future = Time.now - expect { listener.example_passed(notification) } - .to change { listener.flaky_examples[new_example.uid].to_h } - expect(listener.flaky_examples[new_example.uid].to_h) - .to eq(expected_flaky_example.merge(last_flaky_at: the_future)) - end - end - end - - shared_examples 'a new flaky example' do - let(:expected_flaky_example) do - { - example_id: 'spec/foo/baz_spec.rb:3', - file: 'spec/foo/baz_spec.rb', - line: 3, - description: 'hello GitLab', - last_attempts_count: 2, - flaky_reports: 1, - feature_category: nil, - last_flaky_job: nil - } - end - - it 'changes the all flaky examples hash' do - new_example = RspecFlaky::Example.new(rspec_example) - - travel_to(Time.now + 42) do - the_future = Time.now - expect { listener.example_passed(notification) } - .to change { listener.flaky_examples[new_example.uid].to_h } - expect(listener.flaky_examples[new_example.uid].to_h) - .to eq(expected_flaky_example.merge(first_flaky_at: the_future, last_flaky_at: the_future)) - end - end - end - - describe 'when the RSpec example does not respond to attempts' do - it_behaves_like 'a non-flaky example' - end - - describe 'when the RSpec example has 1 attempt' do - let(:rspec_example) { double(new_example_attrs.merge(attempts: 1)) } - - it_behaves_like 'a non-flaky example' - end - - describe 'when the RSpec example has 2 attempts' do - let(:rspec_example) { double(new_example_attrs.merge(attempts: 2)) } - - it_behaves_like 'a new flaky example' - - context 'with an existing flaky example' do - let(:rspec_example) { double(already_flaky_example_attrs.merge(attempts: 2)) } - - it_behaves_like 'an existing flaky example' - end - end - end - - describe '#dump_summary' do - let(:listener) { described_class.new(suite_flaky_example_report.to_json) } - let(:new_flaky_rspec_example) { double(new_example_attrs.merge(attempts: 2)) } - let(:already_flaky_rspec_example) { double(already_flaky_example_attrs.merge(attempts: 2)) } - let(:notification_new_flaky_rspec_example) { double(example: new_flaky_rspec_example) } - let(:notification_already_flaky_rspec_example) { double(example: already_flaky_rspec_example) } - - before do - allow(Kernel).to receive(:warn) - end - - context 'when a report file path is set by FLAKY_RSPEC_REPORT_PATH' do - it 'delegates the writes to RspecFlaky::Report' do - listener.example_passed(notification_new_flaky_rspec_example) - listener.example_passed(notification_already_flaky_rspec_example) - - report1 = double - report2 = double - - expect(RspecFlaky::Report).to receive(:new).with(listener.flaky_examples).and_return(report1) - expect(report1).to receive(:write).with(RspecFlaky::Config.flaky_examples_report_path) - - expect(RspecFlaky::Report).to receive(:new).with(listener.__send__(:new_flaky_examples)).and_return(report2) - expect(report2).to receive(:write).with(RspecFlaky::Config.new_flaky_examples_report_path) - - listener.dump_summary(nil) - end - end - end -end diff --git a/spec/tooling/rspec_flaky/report_spec.rb b/spec/tooling/rspec_flaky/report_spec.rb deleted file mode 100644 index e7365c1e150..00000000000 --- a/spec/tooling/rspec_flaky/report_spec.rb +++ /dev/null @@ -1,138 +0,0 @@ -# frozen_string_literal: true - -require 'tempfile' - -require_relative '../../support/time_travel' - -require_relative '../../../tooling/rspec_flaky/report' - -RSpec.describe RspecFlaky::Report, :aggregate_failures, :freeze_time do - let(:thirty_one_days) { 3600 * 24 * 31 } - let(:collection_hash) do - { - a: { example_id: 'spec/foo/bar_spec.rb:2' }, - b: { example_id: 'spec/foo/baz_spec.rb:3', first_flaky_at: (Time.now - thirty_one_days).to_s, last_flaky_at: (Time.now - thirty_one_days).to_s } - } - end - - let(:suite_flaky_example_report) do - { - '6e869794f4cfd2badd93eb68719371d1': { - example_id: 'spec/foo/bar_spec.rb:2', - file: 'spec/foo/bar_spec.rb', - line: 2, - description: 'hello world', - first_flaky_at: 1234, - last_flaky_at: 4321, - last_attempts_count: 3, - flaky_reports: 1, - feature_category: 'feature_category', - last_flaky_job: nil - } - } - end - - let(:flaky_examples) { RspecFlaky::FlakyExamplesCollection.new(collection_hash) } - let(:report) { described_class.new(flaky_examples) } - - before do - allow(Kernel).to receive(:warn) - end - - describe '.load' do - let!(:report_file) do - Tempfile.new(%w[rspec_flaky_report .json]).tap do |f| - f.write(JSON.pretty_generate(suite_flaky_example_report)) # rubocop:disable Gitlab/Json - f.rewind - end - end - - after do - report_file.close - report_file.unlink - end - - it 'loads the report file' do - expect(described_class.load(report_file.path).flaky_examples.to_h).to eq(suite_flaky_example_report) - end - end - - describe '.load_json' do - let(:report_json) do - JSON.pretty_generate(suite_flaky_example_report) # rubocop:disable Gitlab/Json - end - - it 'loads the report file' do - expect(described_class.load_json(report_json).flaky_examples.to_h).to eq(suite_flaky_example_report) - end - end - - describe '#initialize' do - it 'accepts a RspecFlaky::FlakyExamplesCollection' do - expect { report }.not_to raise_error - end - - it 'does not accept anything else' do - expect { described_class.new([1, 2, 3]) }.to raise_error(ArgumentError, "`flaky_examples` must be a RspecFlaky::FlakyExamplesCollection, Array given!") - end - end - - it 'delegates to #flaky_examples using SimpleDelegator' do - expect(report.__getobj__).to eq(flaky_examples) - end - - describe '#write' do - let(:report_file_path) { File.join('tmp', 'rspec_flaky_report.json') } - - before do - FileUtils.rm(report_file_path) if File.exist?(report_file_path) - end - - after do - FileUtils.rm(report_file_path) if File.exist?(report_file_path) - end - - context 'when RspecFlaky::Config.generate_report? is false' do - before do - allow(RspecFlaky::Config).to receive(:generate_report?).and_return(false) - end - - it 'does not write any report file' do - report.write(report_file_path) - - expect(File.exist?(report_file_path)).to be(false) - end - end - - context 'when RspecFlaky::Config.generate_report? is true' do - before do - allow(RspecFlaky::Config).to receive(:generate_report?).and_return(true) - end - - it 'delegates the writes to RspecFlaky::Report' do - report.write(report_file_path) - - expect(File.exist?(report_file_path)).to be(true) - expect(File.read(report_file_path)) - .to eq(JSON.pretty_generate(report.flaky_examples.to_h)) # rubocop:disable Gitlab/Json - end - end - end - - describe '#prune_outdated' do - it 'returns a new collection without the examples older than 30 days by default' do - new_report = flaky_examples.to_h.dup.tap { |r| r.delete(:b) } - new_flaky_examples = report.prune_outdated - - expect(new_flaky_examples).to be_a(described_class) - expect(new_flaky_examples.to_h).to eq(new_report) - expect(flaky_examples).to have_key(:b) - end - - it 'accepts a given number of days' do - new_flaky_examples = report.prune_outdated(days: 32) - - expect(new_flaky_examples.to_h).to eq(report.to_h) - end - end -end -- cgit v1.2.3