diff options
author | Rémy Coutable <remy@rymai.me> | 2018-04-10 13:22:19 +0200 |
---|---|---|
committer | Rémy Coutable <remy@rymai.me> | 2018-04-10 15:38:40 +0200 |
commit | b11e887582882bcf9c1787e18ccf34747ae50f91 (patch) | |
tree | 3eebc627a3cceceb4454664be059e2b75c7dd071 /spec/lib/rspec_flaky | |
parent | 9bb97abf041d7aa17fc72b850ecc1695c1bad0f5 (diff) | |
download | gitlab-ce-b11e887582882bcf9c1787e18ccf34747ae50f91.tar.gz |
Improve the architecture of RspecFlaky classes by introducing a new RspecFlaky::Report class
Signed-off-by: Rémy Coutable <remy@rymai.me>
Diffstat (limited to 'spec/lib/rspec_flaky')
-rw-r--r-- | spec/lib/rspec_flaky/config_spec.rb | 30 | ||||
-rw-r--r-- | spec/lib/rspec_flaky/examples_pruner_spec.rb | 33 | ||||
-rw-r--r-- | spec/lib/rspec_flaky/flaky_examples_collection_spec.rb | 14 | ||||
-rw-r--r-- | spec/lib/rspec_flaky/listener_spec.rb | 114 | ||||
-rw-r--r-- | spec/lib/rspec_flaky/report_spec.rb | 125 |
5 files changed, 179 insertions, 137 deletions
diff --git a/spec/lib/rspec_flaky/config_spec.rb b/spec/lib/rspec_flaky/config_spec.rb index 83556787e85..4a71b1feebd 100644 --- a/spec/lib/rspec_flaky/config_spec.rb +++ b/spec/lib/rspec_flaky/config_spec.rb @@ -16,23 +16,25 @@ describe RspecFlaky::Config, :aggregate_failures do end end - context "when ENV['FLAKY_RSPEC_GENERATE_REPORT'] is set to 'false'" do - before do - stub_env('FLAKY_RSPEC_GENERATE_REPORT', 'false') - end - - it 'returns false' do - expect(described_class).not_to be_generate_report + 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 - end - context "when ENV['FLAKY_RSPEC_GENERATE_REPORT'] is set to 'true'" do - before do - stub_env('FLAKY_RSPEC_GENERATE_REPORT', 'true') - end + with_them do + before do + stub_env('FLAKY_RSPEC_GENERATE_REPORT', env_value) + end - it 'returns true' do - expect(described_class).to be_generate_report + it 'returns false' do + expect(described_class.generate_report?).to be(result) + end end end end diff --git a/spec/lib/rspec_flaky/examples_pruner_spec.rb b/spec/lib/rspec_flaky/examples_pruner_spec.rb deleted file mode 100644 index 40a086e92cb..00000000000 --- a/spec/lib/rspec_flaky/examples_pruner_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -require 'spec_helper' - -describe RspecFlaky::ExamplesPruner, :aggregate_failures do - 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.utc(2000, 1, 1).to_s, last_flaky_at: Time.utc(2000, 2, 1).to_s } - } - end - - describe '#initialize' do - it 'accepts a collection' do - expect { described_class.new(RspecFlaky::FlakyExamplesCollection.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 RspecFlaky::FlakyExamplesCollection, Array given!") - end - end - - describe '#prune_examples_older_than' do - it 'returns a new collection without the examples older than 3 months' do - collection = RspecFlaky::FlakyExamplesCollection.new(collection_hash) - - new_report = collection.to_report.dup.tap { |r| r.delete(:b) } - new_collection = described_class.new(collection).prune_examples_older_than(3.months.ago) - - expect(new_collection).to be_a(RspecFlaky::FlakyExamplesCollection) - expect(new_collection.to_report).to eq(new_report) - expect(collection).to have_key(:b) - end - end -end diff --git a/spec/lib/rspec_flaky/flaky_examples_collection_spec.rb b/spec/lib/rspec_flaky/flaky_examples_collection_spec.rb index 06a8ba0d02e..6731a27ed17 100644 --- a/spec/lib/rspec_flaky/flaky_examples_collection_spec.rb +++ b/spec/lib/rspec_flaky/flaky_examples_collection_spec.rb @@ -24,14 +24,6 @@ describe RspecFlaky::FlakyExamplesCollection, :aggregate_failures do } end - describe '.from_json' do - it 'accepts a JSON' do - collection = described_class.from_json(JSON.pretty_generate(collection_hash)) - - expect(collection.to_report).to eq(described_class.new(collection_hash).to_report) - end - end - describe '#initialize' do it 'accepts no argument' do expect { described_class.new }.not_to raise_error @@ -46,11 +38,11 @@ describe RspecFlaky::FlakyExamplesCollection, :aggregate_failures do end end - describe '#to_report' do + describe '#to_h' do it 'calls #to_h on the values' do collection = described_class.new(collection_hash) - expect(collection.to_report).to eq(collection_report) + expect(collection.to_h).to eq(collection_report) end end @@ -61,7 +53,7 @@ describe RspecFlaky::FlakyExamplesCollection, :aggregate_failures do a: { example_id: 'spec/foo/bar_spec.rb:2' }, c: { example_id: 'spec/bar/baz_spec.rb:4' }) - expect((collection2 - collection1).to_report).to eq( + expect((collection2 - collection1).to_h).to eq( c: { example_id: 'spec/bar/baz_spec.rb:4', first_flaky_at: nil, diff --git a/spec/lib/rspec_flaky/listener_spec.rb b/spec/lib/rspec_flaky/listener_spec.rb index bfb7648b486..ef085445081 100644 --- a/spec/lib/rspec_flaky/listener_spec.rb +++ b/spec/lib/rspec_flaky/listener_spec.rb @@ -4,7 +4,7 @@ describe RspecFlaky::Listener, :aggregate_failures do let(:already_flaky_example_uid) { '6e869794f4cfd2badd93eb68719371d1' } let(:suite_flaky_example_report) do { - already_flaky_example_uid => { + "#{already_flaky_example_uid}": { example_id: 'spec/foo/bar_spec.rb:2', file: 'spec/foo/bar_spec.rb', line: 2, @@ -55,8 +55,7 @@ describe RspecFlaky::Listener, :aggregate_failures do it 'returns a valid Listener instance' do listener = described_class.new - expect(listener.to_report(listener.suite_flaky_examples)) - .to eq(expected_suite_flaky_examples) + expect(listener.suite_flaky_examples.to_h).to eq(expected_suite_flaky_examples) expect(listener.flaky_examples).to eq({}) end end @@ -65,25 +64,35 @@ describe RspecFlaky::Listener, :aggregate_failures do it_behaves_like 'a valid Listener instance' end - context 'when a report file exists and set by SUITE_FLAKY_RSPEC_REPORT_PATH' do - let(:report_file) do - Tempfile.new(%w[rspec_flaky_report .json]).tap do |f| - f.write(JSON.pretty_generate(suite_flaky_example_report)) - f.rewind - end - end + context 'when SUITE_FLAKY_RSPEC_REPORT_PATH is set' do + let(:report_file_path) { 'foo/report.json' } before do - stub_env('SUITE_FLAKY_RSPEC_REPORT_PATH', report_file.path) + stub_env('SUITE_FLAKY_RSPEC_REPORT_PATH', report_file_path) end - after do - report_file.close - report_file.unlink + 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 - it_behaves_like 'a valid Listener instance' do - let(:expected_suite_flaky_examples) { suite_flaky_example_report } + 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 @@ -186,74 +195,21 @@ describe RspecFlaky::Listener, :aggregate_failures do let(:notification_already_flaky_rspec_example) { double(example: already_flaky_rspec_example) } context 'when a report file path is set by FLAKY_RSPEC_REPORT_PATH' do - let(:report_file_path) { Rails.root.join('tmp', 'rspec_flaky_report.json') } - let(:new_report_file_path) { Rails.root.join('tmp', 'rspec_flaky_new_report.json') } + it 'delegates the writes to RspecFlaky::Report' do + listener.example_passed(notification_new_flaky_rspec_example) + listener.example_passed(notification_already_flaky_rspec_example) - before do - stub_env('FLAKY_RSPEC_REPORT_PATH', report_file_path) - stub_env('NEW_FLAKY_RSPEC_REPORT_PATH', new_report_file_path) - FileUtils.rm(report_file_path) if File.exist?(report_file_path) - FileUtils.rm(new_report_file_path) if File.exist?(new_report_file_path) - end + report1 = double + report2 = double - after do - FileUtils.rm(report_file_path) if File.exist?(report_file_path) - FileUtils.rm(new_report_file_path) if File.exist?(new_report_file_path) - end + 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) - context 'when FLAKY_RSPEC_GENERATE_REPORT == "false"' do - before do - stub_env('FLAKY_RSPEC_GENERATE_REPORT', 'false') - end - - it 'does not write any report file' do - listener.example_passed(notification_new_flaky_rspec_example) + expect(RspecFlaky::Report).to receive(:new).with(listener.flaky_examples - listener.suite_flaky_examples).and_return(report2) + expect(report2).to receive(:write).with(RspecFlaky::Config.new_flaky_examples_report_path) - listener.dump_summary(nil) - - expect(File.exist?(report_file_path)).to be(false) - expect(File.exist?(new_report_file_path)).to be(false) - end + listener.dump_summary(nil) end - - context 'when FLAKY_RSPEC_GENERATE_REPORT == "true"' do - before do - stub_env('FLAKY_RSPEC_GENERATE_REPORT', 'true') - end - - around do |example| - Timecop.freeze { example.run } - end - - it 'writes the report files' do - listener.example_passed(notification_new_flaky_rspec_example) - listener.example_passed(notification_already_flaky_rspec_example) - - listener.dump_summary(nil) - - expect(File.exist?(report_file_path)).to be(true) - expect(File.exist?(new_report_file_path)).to be(true) - - expect(File.read(report_file_path)) - .to eq(JSON.pretty_generate(listener.to_report(listener.flaky_examples))) - - new_example = RspecFlaky::Example.new(notification_new_flaky_rspec_example) - new_flaky_example = RspecFlaky::FlakyExample.new(new_example) - new_flaky_example.update_flakiness! - - expect(File.read(new_report_file_path)) - .to eq(JSON.pretty_generate(listener.to_report(new_example.uid => new_flaky_example))) - end - end - end - end - - describe '#to_report' do - let(:listener) { described_class.new(suite_flaky_example_report.to_json) } - - it 'transforms the internal hash to a JSON-ready hash' do - expect(listener.to_report(already_flaky_example_uid => already_flaky_example)) - .to match(hash_including(suite_flaky_example_report)) end end end diff --git a/spec/lib/rspec_flaky/report_spec.rb b/spec/lib/rspec_flaky/report_spec.rb new file mode 100644 index 00000000000..7d57d99f7e5 --- /dev/null +++ b/spec/lib/rspec_flaky/report_spec.rb @@ -0,0 +1,125 @@ +require 'spec_helper' + +describe RspecFlaky::Report, :aggregate_failures do + let(:a_hundred_days) { 3600 * 24 * 100 } + 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 - a_hundred_days).to_s, last_flaky_at: (Time.now - a_hundred_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, + last_flaky_job: nil + } + } + end + let(:flaky_examples) { RspecFlaky::FlakyExamplesCollection.new(collection_hash) } + let(:report) { described_class.new(flaky_examples) } + + 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)) + 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) + 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) { Rails.root.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)) + end + end + end + + describe '#prune_outdated' do + it 'returns a new collection without the examples older than 90 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: 200) + + expect(new_flaky_examples.to_h).to eq(report.to_h) + end + end +end |