Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-12-13 09:09:48 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-13 09:09:48 +0300
commite7b6c527c40962adc6623521ff190771e4ac50e4 (patch)
tree8e8191419a1e82c99545a0aa755055703167c16f /spec/tooling/lib
parent49d65a7ae290040834a890fffd2481a606ba97f2 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/tooling/lib')
-rw-r--r--spec/tooling/lib/tooling/api/job_spec.rb95
-rw-r--r--spec/tooling/lib/tooling/api/pipeline_spec.rb63
-rw-r--r--spec/tooling/lib/tooling/api/request_spec.rb53
-rw-r--r--spec/tooling/lib/tooling/debug_spec.rb76
4 files changed, 287 insertions, 0 deletions
diff --git a/spec/tooling/lib/tooling/api/job_spec.rb b/spec/tooling/lib/tooling/api/job_spec.rb
new file mode 100644
index 00000000000..dfb047f0e6d
--- /dev/null
+++ b/spec/tooling/lib/tooling/api/job_spec.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+
+require_relative '../../../../../tooling/lib/tooling/api/job'
+require_relative '../../../../../tooling/lib/tooling/api/request'
+
+RSpec.describe Tooling::API::Job, feature_category: :tooling do
+ describe '#rspec_failed_files' do
+ let(:job) { described_class.new('api_token', 'project_id', 'job_id') }
+ let(:failures) { '' }
+ let(:log) do
+ <<~LOG
+ lots of content at the top of the file
+ #{failures}
+ some content at the bottom of the file
+ LOG
+ end
+
+ subject(:rspec_failed_files) { job.rspec_failed_files }
+
+ shared_context 'with stubbed API request' do
+ before do
+ # Stub the API request.
+ allow(job).to receive(:get_job_log).and_return(log)
+ end
+ end
+
+ it 'will fetch job logs' do
+ uri = URI("https://gitlab.com/api/v4/projects/project_id/jobs/job_id/trace")
+
+ response_double = instance_double(Net::HTTPOK, body: log)
+ expect(Tooling::API::Request).to receive(:get).with('api_token', uri).and_return(response_double)
+
+ rspec_failed_files
+ end
+
+ context 'when there are no failures' do
+ include_context 'with stubbed API request'
+
+ let(:failures) { '' }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'when a spec fails on a specified line' do
+ include_context 'with stubbed API request'
+
+ let(:failures) { 'rspec ./spec/foo_spec.rb:123' }
+
+ it { is_expected.to eq(%w[spec/foo_spec.rb]) }
+ end
+
+ context 'when a nested spec fails' do
+ include_context 'with stubbed API request'
+
+ let(:failures) { %(rspec './spec/foo_spec.rb[123:456]') }
+
+ it { is_expected.to eq(%w[spec/foo_spec.rb]) }
+ end
+
+ context 'when there are multiple spec failures' do
+ include_context 'with stubbed API request'
+
+ let(:failures) do
+ <<~LOG
+ rspec spec/foo_spec.rb:123
+ rspec spec/bar_spec.rb:456
+ rspec 'spec/ro_spec.rb[1:2]'
+ rspec 'spec/sham_spec.rb[3:4]'
+ rspec 'spec/bo_spec.rb[5:6]'
+ LOG
+ end
+
+ it do
+ is_expected.to match_array(
+ %w[spec/bar_spec.rb spec/bo_spec.rb spec/foo_spec.rb spec/ro_spec.rb spec/sham_spec.rb]
+ )
+ end
+ end
+
+ context 'when there are multiple spec failures in the same file' do
+ include_context 'with stubbed API request'
+
+ let(:failures) do
+ <<~LOG
+ rspec ./spec/foo_spec.rb:123
+ rspec ./spec/foo_spec.rb:456
+ rspec './spec/bar_spec.rb[1:2]'
+ rspec './spec/bar_spec.rb[3:4]'
+ LOG
+ end
+
+ it { is_expected.to eq(%w[spec/foo_spec.rb spec/bar_spec.rb]) }
+ end
+ end
+end
diff --git a/spec/tooling/lib/tooling/api/pipeline_spec.rb b/spec/tooling/lib/tooling/api/pipeline_spec.rb
new file mode 100644
index 00000000000..1c641328796
--- /dev/null
+++ b/spec/tooling/lib/tooling/api/pipeline_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require_relative '../../../../../tooling/lib/tooling/api/pipeline'
+require_relative '../../../../../tooling/lib/tooling/api/job'
+
+RSpec.describe Tooling::API::Pipeline, feature_category: :tooling do
+ let(:pipeline) { described_class.new('api_token', 'project_id', 'pipeline_id') }
+
+ describe '#failed_jobs' do
+ subject { pipeline.failed_jobs }
+
+ context 'when there are failed jobs' do
+ let(:jobs) { [{ 'id' => '123' }, { 'id' => '456' }] }
+ let(:response) { instance_double(Net::HTTPOK, body: jobs.to_json, '[]' => nil) }
+
+ it 'returns the jobs' do
+ allow(Tooling::API::Request).to receive(:get).and_yield(response)
+
+ expect(pipeline.failed_jobs).to eq(jobs)
+ end
+ end
+ end
+
+ describe '#failed_spec_files' do
+ let(:job1) { { 'id' => 1 } }
+ let(:job2) { { 'id' => 2 } }
+ let(:failed_jobs) { [job1, job2] }
+ let(:job1_failed_files) { %w[spec/foo_spec.rb spec/bar_spec.rb] }
+ let(:job2_failed_files) { %w[spec/baz_spec.rb spec/qux_spec.rb] }
+ let(:failed_files) { job1_failed_files + job2_failed_files }
+
+ subject { pipeline.failed_spec_files }
+
+ before do
+ allow(pipeline).to receive(:failed_jobs).and_return(failed_jobs)
+
+ allow(Tooling::API::Job).to receive(:new).with(anything, anything, job1['id']).and_return(job1)
+ allow(job1).to receive(:rspec_failed_files).and_return(job1_failed_files)
+
+ allow(Tooling::API::Job).to receive(:new).with(anything, anything, job2['id']).and_return(job2)
+ allow(job2).to receive(:rspec_failed_files).and_return(job2_failed_files)
+ end
+
+ it 'returns the failed spec files' do
+ expect(pipeline.failed_spec_files).to match_array(failed_files)
+ end
+
+ context 'when Tooling::Debug is enabled' do
+ around do |example|
+ Tooling::Debug.debug = true
+ example.run
+ ensure
+ Tooling::Debug.debug = false
+ end
+
+ it 'outputs the job logs' do
+ expect { pipeline.failed_spec_files }.to output(/Fetching failed jobs... found 2/).to_stdout
+ expect { pipeline.failed_spec_files }.to output(/Fetching job logs for #1/).to_stdout
+ expect { pipeline.failed_spec_files }.to output(/Fetching job logs for #2/).to_stdout
+ end
+ end
+ end
+end
diff --git a/spec/tooling/lib/tooling/api/request_spec.rb b/spec/tooling/lib/tooling/api/request_spec.rb
new file mode 100644
index 00000000000..091bd860cbd
--- /dev/null
+++ b/spec/tooling/lib/tooling/api/request_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require_relative '../../../../../tooling/lib/tooling/api/request'
+
+require 'webmock/rspec'
+
+RSpec.describe Tooling::API::Request, feature_category: :tooling do
+ let(:base_url) { 'https://gitlab.com/api/v4/projects/project_id/pipelines/pipeline_id/jobs' }
+
+ describe '.get' do
+ let(:body) { 'body' }
+
+ subject(:response) { described_class.get('api_token', URI(base_url)) }
+
+ context 'when the response is successful' do
+ before do
+ stub_request(:get, base_url).to_return(status: 200, body: body)
+ end
+
+ it { expect(response.body).to eq(body) }
+ end
+
+ context 'when the response is not successful' do
+ before do
+ stub_request(:get, base_url).to_return(status: 500)
+ end
+
+ it { expect(response.body).to be_empty }
+ end
+
+ context 'when there are multiple pages' do
+ let(:body1) { 'body1' }
+ let(:body2) { 'body2' }
+
+ before do
+ stub_request(:get, base_url).to_return(
+ status: 200, body: body1, headers: { 'Link' => %(<#{base_url}&page=2>; rel="next") }
+ )
+ stub_request(:get, "#{base_url}&page=2").to_return(status: 200, body: body2, headers: { 'Link' => '' })
+ end
+
+ it 'yields each page' do
+ expected = [body1, body2]
+
+ expected_yield = proc do |response|
+ expect(response.body).to eq(expected.shift)
+ end
+
+ described_class.get('api_token', URI(base_url), &expected_yield)
+ end
+ end
+ end
+end
diff --git a/spec/tooling/lib/tooling/debug_spec.rb b/spec/tooling/lib/tooling/debug_spec.rb
new file mode 100644
index 00000000000..c506a93a24a
--- /dev/null
+++ b/spec/tooling/lib/tooling/debug_spec.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+require_relative '../../../../tooling/lib/tooling/debug'
+
+RSpec.describe Tooling::Debug, feature_category: :tooling do
+ let(:some_class) do
+ Class.new do
+ include Tooling::Debug
+
+ def print_hello_world
+ print 'hello world'
+ end
+
+ def puts_hello_world
+ puts 'hello world'
+ end
+ end
+ end
+
+ after do
+ # Ensure that debug mode is default disabled at start of specs.
+ described_class.debug = false
+ end
+
+ shared_context 'when debug is enabled' do
+ before do
+ described_class.debug = true
+ end
+ end
+
+ shared_context 'when debug is disabled' do
+ before do
+ described_class.debug = false
+ end
+ end
+
+ shared_examples 'writes to stdout' do |str|
+ it 'writes to stdout' do
+ expect { subject }.to output(str).to_stdout
+ end
+ end
+
+ shared_examples 'does not write to stdout' do
+ it 'does not write to stdout' do
+ expect { subject }.not_to output.to_stdout
+ end
+ end
+
+ describe '#print' do
+ subject { some_class.new.print_hello_world }
+
+ context 'when debug is enabled' do
+ include_context 'when debug is enabled'
+ include_examples 'writes to stdout', 'hello world'
+ end
+
+ context 'when debug is disabled' do
+ include_context 'when debug is disabled'
+ include_examples 'does not write to stdout'
+ end
+ end
+
+ describe '#puts' do
+ subject { some_class.new.puts_hello_world }
+
+ context 'when debug is enabled' do
+ include_context 'when debug is enabled'
+ include_examples 'writes to stdout', "hello world\n"
+ end
+
+ context 'when debug is disabled' do
+ include_context 'when debug is disabled'
+ include_examples 'does not write to stdout'
+ end
+ end
+end