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
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-04-20 21:08:30 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-04-20 21:08:30 +0300
commit4faa270685797bd689d2035efe7c7e724950eb82 (patch)
tree880f35cfcb4ef5dad3c82f701937d27d5cc85389 /spec
parentda23c5d563d68bfa5271b216209a7715c7ce3073 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/frontend/super_sidebar/components/nav_item_spec.js7
-rw-r--r--spec/helpers/projects_helper_spec.rb74
-rw-r--r--spec/helpers/sidebars_helper_spec.rb44
-rw-r--r--spec/lib/gitlab/metrics/sidekiq_slis_spec.rb65
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb79
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb32
-rw-r--r--spec/lib/sidebars/menu_item_spec.rb10
-rw-r--r--spec/lib/sidebars/menu_spec.rb6
-rw-r--r--spec/lib/sidebars/static_menu_spec.rb6
-rw-r--r--spec/mailers/emails/merge_requests_spec.rb15
-rw-r--r--spec/mailers/emails/pipelines_spec.rb18
-rw-r--r--spec/mailers/notify_spec.rb60
-rw-r--r--spec/models/ci/commit_with_pipeline_spec.rb45
-rw-r--r--spec/models/concerns/require_email_verification_spec.rb16
-rw-r--r--spec/requests/api/terraform/state_spec.rb82
-rw-r--r--spec/services/projects/android_target_platform_detector_service_spec.rb30
-rw-r--r--spec/services/projects/record_target_platforms_service_spec.rb68
-rw-r--r--spec/support/rspec_order_todo.yml1
-rw-r--r--spec/workers/projects/record_target_platforms_worker_spec.rb67
19 files changed, 512 insertions, 213 deletions
diff --git a/spec/frontend/super_sidebar/components/nav_item_spec.js b/spec/frontend/super_sidebar/components/nav_item_spec.js
index d96d2b77d21..ffbdaa326f9 100644
--- a/spec/frontend/super_sidebar/components/nav_item_spec.js
+++ b/spec/frontend/super_sidebar/components/nav_item_spec.js
@@ -53,6 +53,13 @@ describe('NavItem component', () => {
expect(findLink().attributes('class')).toContain(customClass);
});
+ it('applies custom classes set in the backend', () => {
+ const customClass = 'customBackendClass';
+ createWrapper({ title: 'Foo', link_classes: customClass });
+
+ expect(findLink().attributes('class')).toContain(customClass);
+ });
+
describe('Data Tracking Attributes', () => {
it('adds no labels on sections', () => {
const id = 'my-id';
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index c4ab9fb115f..2d3bb06df41 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -212,6 +212,80 @@ RSpec.describe ProjectsHelper, feature_category: :source_code_management do
end
end
+ describe '#last_pipeline_from_status_cache' do
+ before do
+ # clear cross-example caches
+ project_with_repo.pipeline_status.delete_from_cache
+ project_with_repo.instance_variable_set(:@pipeline_status, nil)
+ end
+
+ context 'without a pipeline' do
+ it 'returns nil', :aggregate_failures do
+ expect(::Gitlab::GitalyClient).to receive(:call).at_least(:once).and_call_original
+ actual_pipeline = last_pipeline_from_status_cache(project_with_repo)
+ expect(actual_pipeline).to be_nil
+ end
+
+ context 'when pipeline_status is loaded' do
+ before do
+ project_with_repo.pipeline_status # this loads the status
+ end
+
+ it 'returns nil without calling gitaly when there is no pipeline', :aggregate_failures do
+ expect(::Gitlab::GitalyClient).not_to receive(:call)
+ actual_pipeline = last_pipeline_from_status_cache(project_with_repo)
+ expect(actual_pipeline).to be_nil
+ end
+ end
+
+ context 'when FF load_last_pipeline_from_pipeline_status is disabled' do
+ before do
+ stub_feature_flags(last_pipeline_from_pipeline_status: false)
+ end
+
+ it 'returns nil', :aggregate_failures do
+ expect(project_with_repo).not_to receive(:pipeline_status)
+ actual_pipeline = last_pipeline_from_status_cache(project_with_repo)
+ expect(actual_pipeline).to be_nil
+ end
+ end
+ end
+
+ context 'with a pipeline' do
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project_with_repo) }
+
+ it 'returns the latest pipeline', :aggregate_failures do
+ expect(::Gitlab::GitalyClient).to receive(:call).at_least(:once).and_call_original
+ actual_pipeline = last_pipeline_from_status_cache(project_with_repo)
+ expect(actual_pipeline).to eq pipeline
+ end
+
+ context 'when pipeline_status is loaded' do
+ before do
+ project_with_repo.pipeline_status # this loads the status
+ end
+
+ it 'returns the latest pipeline without calling gitaly' do
+ expect(::Gitlab::GitalyClient).not_to receive(:call)
+ actual_pipeline = last_pipeline_from_status_cache(project_with_repo)
+ expect(actual_pipeline).to eq pipeline
+ end
+
+ context 'when FF load_last_pipeline_from_pipeline_status is disabled' do
+ before do
+ stub_feature_flags(last_pipeline_from_pipeline_status: false)
+ end
+
+ it 'returns the latest pipeline', :aggregate_failures do
+ expect(project_with_repo).not_to receive(:pipeline_status)
+ actual_pipeline = last_pipeline_from_status_cache(project_with_repo)
+ expect(actual_pipeline).to eq pipeline
+ end
+ end
+ end
+ end
+ end
+
describe '#show_no_ssh_key_message?' do
before do
allow(helper).to receive(:current_user).and_return(user)
diff --git a/spec/helpers/sidebars_helper_spec.rb b/spec/helpers/sidebars_helper_spec.rb
index 5323b041a9e..6c0ac024944 100644
--- a/spec/helpers/sidebars_helper_spec.rb
+++ b/spec/helpers/sidebars_helper_spec.rb
@@ -66,9 +66,10 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
let_it_be(:group) { build(:group) }
let_it_be(:panel) { {} }
let_it_be(:panel_type) { 'project' }
+ let(:project) { nil }
subject do
- helper.super_sidebar_context(user, group: group, project: nil, panel: panel, panel_type: panel_type)
+ helper.super_sidebar_context(user, group: group, project: project, panel: panel, panel_type: panel_type)
end
before do
@@ -160,6 +161,47 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
})
end
+ describe "shortcut links" do
+ let(:global_shortcut_links) do
+ [
+ {
+ title: _('Milestones'),
+ href: dashboard_milestones_path,
+ css_class: 'dashboard-shortcuts-milestones'
+ },
+ {
+ title: _('Snippets'),
+ href: dashboard_snippets_path,
+ css_class: 'dashboard-shortcuts-snippets'
+ },
+ {
+ title: _('Activity'),
+ href: activity_dashboard_path,
+ css_class: 'dashboard-shortcuts-activity'
+ }
+ ]
+ end
+
+ it 'returns global shortcut links' do
+ expect(subject[:shortcut_links]).to eq(global_shortcut_links)
+ end
+
+ context 'in a project' do
+ let(:project) { build(:project) }
+
+ it 'returns project-specific shortcut links' do
+ expect(subject[:shortcut_links]).to eq([
+ *global_shortcut_links,
+ {
+ title: _('Create a new issue'),
+ href: new_project_issue_path(project),
+ css_class: 'shortcuts-new-issue'
+ }
+ ])
+ end
+ end
+ end
+
it 'returns "Merge requests" menu', :use_clean_rails_memory_store_caching do
expect(subject[:merge_request_menu]).to eq([
{
diff --git a/spec/lib/gitlab/metrics/sidekiq_slis_spec.rb b/spec/lib/gitlab/metrics/sidekiq_slis_spec.rb
new file mode 100644
index 00000000000..eef9a9c79e6
--- /dev/null
+++ b/spec/lib/gitlab/metrics/sidekiq_slis_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Metrics::SidekiqSlis, feature_category: :error_budgets do
+ using RSpec::Parameterized::TableSyntax
+
+ describe ".initialize_slis!" do
+ let(:possible_labels) do
+ [
+ {
+ worker: "Projects::RecordTargetPlatformsWorker",
+ feature_category: "projects",
+ urgency: "low"
+ }
+ ]
+ end
+
+ it "initializes the apdex and error rate SLIs" do
+ expect(Gitlab::Metrics::Sli::Apdex).to receive(:initialize_sli).with(:sidekiq_execution, possible_labels)
+ expect(Gitlab::Metrics::Sli::ErrorRate).to receive(:initialize_sli).with(:sidekiq_execution, possible_labels)
+
+ described_class.initialize_slis!(possible_labels)
+ end
+ end
+
+ describe ".record_execution_apdex" do
+ where(:urgency, :duration, :success) do
+ "high" | 5 | true
+ "high" | 11 | false
+ "low" | 295 | true
+ "low" | 400 | false
+ "throttled" | 295 | true
+ "throttled" | 400 | false
+ "not_found" | 295 | true
+ "not_found" | 400 | false
+ end
+
+ with_them do
+ it "increments the apdex SLI with success based on urgency requirement" do
+ labels = { urgency: urgency }
+ expect(Gitlab::Metrics::Sli::Apdex[:sidekiq_execution]).to receive(:increment).with(
+ labels: labels,
+ success: success
+ )
+
+ described_class.record_execution_apdex(labels, duration)
+ end
+ end
+ end
+
+ describe ".record_execution_error" do
+ it "increments the error rate SLI with the given labels and error" do
+ labels = { urgency: :throttled }
+ error = StandardError.new("something went wrong")
+
+ expect(Gitlab::Metrics::Sli::ErrorRate[:sidekiq_execution]).to receive(:increment).with(
+ labels: labels,
+ error: error
+ )
+
+ described_class.record_execution_error(labels, error)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb b/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
index 80c1af1b913..965ca612b3f 100644
--- a/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
@@ -59,6 +59,45 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
described_class.initialize_process_metrics
end
+ context 'when sidekiq_execution_application_slis FF is turned on' do
+ it 'initializes sidekiq SLIs for the workers in the current Sidekiq process' do
+ allow(Gitlab::SidekiqConfig)
+ .to receive(:current_worker_queue_mappings)
+ .and_return('MergeWorker' => 'merge', 'Ci::BuildFinishedWorker' => 'default')
+
+ allow(completion_seconds_metric).to receive(:get)
+
+ expect(Gitlab::Metrics::SidekiqSlis)
+ .to receive(:initialize_slis!).with([
+ {
+ worker: 'MergeWorker',
+ urgency: 'high',
+ feature_category: 'source_code_management'
+ },
+ {
+ worker: 'Ci::BuildFinishedWorker',
+ urgency: 'high',
+ feature_category: 'continuous_integration'
+ }
+ ])
+
+ described_class.initialize_process_metrics
+ end
+ end
+
+ context 'when sidekiq_execution_application_slis FF is turned off' do
+ before do
+ stub_feature_flags(sidekiq_execution_application_slis: false)
+ end
+
+ it 'does not initialize sidekiq SLIs' do
+ expect(Gitlab::Metrics::SidekiqSlis)
+ .not_to receive(:initialize_slis!)
+
+ described_class.initialize_process_metrics
+ end
+ end
+
context 'when the sidekiq_job_completion_metric_initialize feature flag is disabled' do
before do
stub_feature_flags(sidekiq_job_completion_metric_initialize: false)
@@ -79,6 +118,17 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
described_class.initialize_process_metrics
end
+
+ it 'does not initializes sidekiq SLIs' do
+ allow(Gitlab::SidekiqConfig)
+ .to receive(:current_worker_queue_mappings)
+ .and_return('MergeWorker' => 'merge', 'Ci::BuildFinishedWorker' => 'default')
+
+ expect(Gitlab::Metrics::SidekiqSlis)
+ .not_to receive(:initialize_slis!)
+
+ described_class.initialize_process_metrics
+ end
end
end
@@ -110,6 +160,12 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
expect(redis_requests_total).to receive(:increment).with(labels_with_job_status, redis_calls)
expect(elasticsearch_requests_total).to receive(:increment).with(labels_with_job_status, elasticsearch_calls)
expect(sidekiq_mem_total_bytes).to receive(:set).with(labels_with_job_status, mem_total_bytes)
+ expect(Gitlab::Metrics::SidekiqSlis).to receive(:record_execution_apdex).with(labels.slice(:worker,
+ :feature_category,
+ :urgency), monotonic_time_duration)
+ expect(Gitlab::Metrics::SidekiqSlis).to receive(:record_execution_error).with(labels.slice(:worker,
+ :feature_category,
+ :urgency), false)
subject.call(worker, job, :test) { nil }
end
@@ -159,6 +215,16 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
expect { subject.call(worker, job, :test) { raise StandardError, "Failed" } }.to raise_error(StandardError, "Failed")
end
+
+ it 'records sidekiq SLI error but does not record sidekiq SLI apdex' do
+ expect(failed_total_metric).to receive(:increment)
+ expect(Gitlab::Metrics::SidekiqSlis).not_to receive(:record_execution_apdex)
+ expect(Gitlab::Metrics::SidekiqSlis).to receive(:record_execution_error).with(labels.slice(:worker,
+ :feature_category,
+ :urgency), true)
+
+ expect { subject.call(worker, job, :test) { raise StandardError, "Failed" } }.to raise_error(StandardError, "Failed")
+ end
end
context 'when job is retried' do
@@ -180,6 +246,19 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
subject.call(worker, job, :test) { nil }
end
end
+
+ context 'when sidekiq_execution_application_slis FF is turned off' do
+ before do
+ stub_feature_flags(sidekiq_execution_application_slis: false)
+ end
+
+ it 'does not call record_execution_apdex nor record_execution_error' do
+ expect(Gitlab::Metrics::SidekiqSlis).not_to receive(:record_execution_apdex)
+ expect(Gitlab::Metrics::SidekiqSlis).not_to receive(:record_execution_error)
+
+ subject.call(worker, job, :test) { nil }
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index 3c7542ea5f9..a1c2f7d667f 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -458,18 +458,42 @@ RSpec.describe Gitlab::Workhorse do
describe '.send_url' do
let(:url) { 'http://example.com' }
- subject { described_class.send_url(url) }
-
it 'sets the header correctly' do
- key, command, params = decode_workhorse_header(subject)
+ key, command, params = decode_workhorse_header(
+ described_class.send_url(url)
+ )
expect(key).to eq("Gitlab-Workhorse-Send-Data")
expect(command).to eq("send-url")
expect(params).to eq({
'URL' => url,
- 'AllowRedirects' => false
+ 'AllowRedirects' => false,
+ 'Body' => '',
+ 'Method' => 'GET'
}.deep_stringify_keys)
end
+
+ context 'when body, headers and method are specified' do
+ let(:body) { 'body' }
+ let(:headers) { { Authorization: ['Bearer token'] } }
+ let(:method) { 'POST' }
+
+ it 'sets the header correctly' do
+ key, command, params = decode_workhorse_header(
+ described_class.send_url(url, body: body, headers: headers, method: method)
+ )
+
+ expect(key).to eq("Gitlab-Workhorse-Send-Data")
+ expect(command).to eq("send-url")
+ expect(params).to eq({
+ 'URL' => url,
+ 'AllowRedirects' => false,
+ 'Body' => body,
+ 'Header' => headers,
+ 'Method' => method
+ }.deep_stringify_keys)
+ end
+ end
end
describe '.send_scaled_image' do
diff --git a/spec/lib/sidebars/menu_item_spec.rb b/spec/lib/sidebars/menu_item_spec.rb
index 15804f51934..84bc3430260 100644
--- a/spec/lib/sidebars/menu_item_spec.rb
+++ b/spec/lib/sidebars/menu_item_spec.rb
@@ -18,4 +18,14 @@ RSpec.describe Sidebars::MenuItem do
expect(menu_item.container_html_options).to eq html_options
end
end
+
+ describe "#serialize_for_super_sidebar" do
+ let(:html_options) { { class: 'custom-class' } }
+
+ subject { menu_item.serialize_for_super_sidebar }
+
+ it 'includes custom CSS classes' do
+ expect(subject[:link_classes]).to be('custom-class')
+ end
+ end
end
diff --git a/spec/lib/sidebars/menu_spec.rb b/spec/lib/sidebars/menu_spec.rb
index 74ed344dd24..21aec10ec27 100644
--- a/spec/lib/sidebars/menu_spec.rb
+++ b/spec/lib/sidebars/menu_spec.rb
@@ -61,7 +61,8 @@ RSpec.describe Sidebars::Menu, feature_category: :navigation do
icon: nil,
link: "foo2",
is_active: true,
- pill_count: nil
+ pill_count: nil,
+ link_classes: nil
},
{
id: 'id2',
@@ -69,7 +70,8 @@ RSpec.describe Sidebars::Menu, feature_category: :navigation do
icon: nil,
link: "foo3",
is_active: false,
- pill_count: 10
+ pill_count: 10,
+ link_classes: nil
}
]
})
diff --git a/spec/lib/sidebars/static_menu_spec.rb b/spec/lib/sidebars/static_menu_spec.rb
index b336b457302..3d9feee0494 100644
--- a/spec/lib/sidebars/static_menu_spec.rb
+++ b/spec/lib/sidebars/static_menu_spec.rb
@@ -25,7 +25,8 @@ RSpec.describe Sidebars::StaticMenu, feature_category: :navigation do
icon: nil,
link: "foo2",
is_active: true,
- pill_count: nil
+ pill_count: nil,
+ link_classes: nil
},
{
id: 'id2',
@@ -33,7 +34,8 @@ RSpec.describe Sidebars::StaticMenu, feature_category: :navigation do
icon: nil,
link: "foo3",
is_active: false,
- pill_count: nil
+ pill_count: nil,
+ link_classes: nil
}
]
)
diff --git a/spec/mailers/emails/merge_requests_spec.rb b/spec/mailers/emails/merge_requests_spec.rb
index 7682cf39450..9aece9538dc 100644
--- a/spec/mailers/emails/merge_requests_spec.rb
+++ b/spec/mailers/emails/merge_requests_spec.rb
@@ -13,12 +13,15 @@ RSpec.describe Emails::MergeRequests do
let_it_be(:reviewer, reload: true) { create(:user, email: 'reviewer@example.com', name: 'Jane Doe') }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:merge_request) do
- create(:merge_request, source_project: project,
- target_project: project,
- author: current_user,
- assignees: [assignee],
- reviewers: [reviewer],
- description: 'Awesome description')
+ create(
+ :merge_request,
+ source_project: project,
+ target_project: project,
+ author: current_user,
+ assignees: [assignee],
+ reviewers: [reviewer],
+ description: 'Awesome description'
+ )
end
let(:recipient) { assignee }
diff --git a/spec/mailers/emails/pipelines_spec.rb b/spec/mailers/emails/pipelines_spec.rb
index 1ac989cc46b..ae0876338f5 100644
--- a/spec/mailers/emails/pipelines_spec.rb
+++ b/spec/mailers/emails/pipelines_spec.rb
@@ -25,8 +25,13 @@ RSpec.describe Emails::Pipelines do
let(:pipeline) { create(:ci_pipeline, ref: 'master', sha: sha, project: project) }
let!(:merge_request) do
- create(:merge_request, source_branch: 'master', target_branch: 'feature',
- source_project: project, target_project: project)
+ create(
+ :merge_request,
+ source_branch: 'master',
+ target_branch: 'feature',
+ source_project: project,
+ target_project: project
+ )
end
it 'has correct information that there is no merge request link' do
@@ -55,8 +60,13 @@ RSpec.describe Emails::Pipelines do
context 'when branch pipeline is set to a merge request as a head pipeline' do
let(:pipeline) do
- create(:ci_pipeline, project: project, ref: ref, sha: sha,
- merge_requests_as_head_pipeline: [merge_request])
+ create(
+ :ci_pipeline,
+ project: project,
+ ref: ref,
+ sha: sha,
+ merge_requests_as_head_pipeline: [merge_request]
+ )
end
let(:merge_request) do
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index eb681846e82..c2c32abbdc4 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -21,19 +21,25 @@ RSpec.describe Notify do
let_it_be(:reviewer, reload: true) { create(:user, email: 'reviewer@example.com', name: 'Jane Doe') }
let_it_be(:merge_request) do
- create(:merge_request, source_project: project,
- target_project: project,
- author: current_user,
- assignees: [assignee],
- reviewers: [reviewer],
- description: 'Awesome description')
+ create(
+ :merge_request,
+ source_project: project,
+ target_project: project,
+ author: current_user,
+ assignees: [assignee],
+ reviewers: [reviewer],
+ description: 'Awesome description'
+ )
end
let_it_be(:issue, reload: true) do
- create(:issue, author: current_user,
- assignees: [assignee],
- project: project,
- description: 'My awesome description!')
+ create(
+ :issue,
+ author: current_user,
+ assignees: [assignee],
+ project: project,
+ description: 'My awesome description!'
+ )
end
describe 'with HTML-encoded entities' do
@@ -824,9 +830,11 @@ RSpec.describe Notify do
end
it 'has References header including the notes and issue of the discussion' do
- expect(subject.header['References'].message_ids).to include("issue_#{first_note.noteable.id}@#{host}",
- "note_#{first_note.id}@#{host}",
- "note_#{second_note.id}@#{host}")
+ expect(subject.header['References'].message_ids).to include(
+ "issue_#{first_note.noteable.id}@#{host}",
+ "note_#{first_note.id}@#{host}",
+ "note_#{second_note.id}@#{host}"
+ )
end
it 'has X-GitLab-Discussion-ID header' do
@@ -899,9 +907,11 @@ RSpec.describe Notify do
end
it 'links to the project snippet' do
- target_url = project_snippet_url(project,
- project_snippet_note.noteable,
- { anchor: "note_#{project_snippet_note.id}" })
+ target_url = project_snippet_url(
+ project,
+ project_snippet_note.noteable,
+ { anchor: "note_#{project_snippet_note.id}" }
+ )
is_expected.to have_body_text target_url
end
end
@@ -910,9 +920,7 @@ RSpec.describe Notify do
let_it_be(:design) { create(:design, :with_file) }
let_it_be(:recipient) { create(:user) }
let_it_be(:note) do
- create(:diff_note_on_design,
- noteable: design,
- note: "Hello #{recipient.to_reference}")
+ create(:diff_note_on_design, noteable: design, note: "Hello #{recipient.to_reference}")
end
let(:header_name) { 'X-Gitlab-DesignManagement-Design-ID' }
@@ -1078,9 +1086,10 @@ RSpec.describe Notify do
is_expected.to have_body_text project.full_name
is_expected.to have_body_text project_member.human_access.downcase
is_expected.to have_body_text project_member.invite_token
- is_expected.to have_link('Join now',
- href: invite_url(project_member.invite_token,
- invite_type: Emails::Members::INITIAL_INVITE))
+ is_expected.to have_link(
+ 'Join now',
+ href: invite_url(project_member.invite_token, invite_type: Emails::Members::INITIAL_INVITE)
+ )
is_expected.to have_content("#{inviter.name} invited you to join the")
is_expected.to have_content('Project details')
is_expected.to have_content("What's it about?")
@@ -1096,9 +1105,10 @@ RSpec.describe Notify do
is_expected.to have_body_text project.full_name
is_expected.to have_body_text project_member.human_access.downcase
is_expected.to have_body_text project_member.invite_token
- is_expected.to have_link('Join now',
- href: invite_url(project_member.invite_token,
- invite_type: Emails::Members::INITIAL_INVITE))
+ is_expected.to have_link(
+ 'Join now',
+ href: invite_url(project_member.invite_token, invite_type: Emails::Members::INITIAL_INVITE)
+ )
is_expected.to have_content('Project details')
is_expected.to have_content("What's it about?")
end
diff --git a/spec/models/ci/commit_with_pipeline_spec.rb b/spec/models/ci/commit_with_pipeline_spec.rb
index 320143535e2..766e99288c0 100644
--- a/spec/models/ci/commit_with_pipeline_spec.rb
+++ b/spec/models/ci/commit_with_pipeline_spec.rb
@@ -2,9 +2,9 @@
require 'spec_helper'
-RSpec.describe Ci::CommitWithPipeline do
- let(:project) { create(:project, :public, :repository) }
- let(:commit) { described_class.new(project.commit) }
+RSpec.describe Ci::CommitWithPipeline, feature_category: :continuous_integration do
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let(:commit) { described_class.new(project.commit) }
describe '#last_pipeline' do
let!(:first_pipeline) do
@@ -27,28 +27,43 @@ RSpec.describe Ci::CommitWithPipeline do
end
describe '#lazy_latest_pipeline' do
- let(:commit_1) do
- described_class.new(Commit.new(RepoHelpers.sample_commit, project))
+ let_it_be(:other_project) { create(:project, :repository) }
+
+ let_it_be(:commits_with_pipelines) do
+ [
+ described_class.new(Commit.new(RepoHelpers.sample_commit, project)),
+ described_class.new(Commit.new(RepoHelpers.another_sample_commit, project)),
+ described_class.new(Commit.new(RepoHelpers.sample_big_commit, project)),
+ described_class.new(Commit.new(RepoHelpers.sample_commit, other_project))
+ ]
end
- let(:commit_2) do
- described_class.new(Commit.new(RepoHelpers.another_sample_commit, project))
+ let_it_be(:commits) do
+ commits_with_pipelines + [
+ described_class.new(Commit.new(RepoHelpers.another_sample_commit, other_project))
+ ]
end
- let!(:commits) { [commit_1, commit_2] }
+ before(:all) do
+ commits_with_pipelines.each do |commit|
+ create(:ci_empty_pipeline, project: commit.project, sha: commit.sha)
+ end
+ end
- it 'executes only 1 SQL query' do
+ it 'returns the correct pipelines with only 1 SQL query per project', :aggregate_failures do
recorder = ActiveRecord::QueryRecorder.new do
- # Running this first ensures we don't run one query for every
- # commit.
+ # batch commits
commits.each(&:lazy_latest_pipeline)
- # This forces the execution of the SQL queries necessary to load the
- # data.
- commits.each { |c| c.latest_pipeline.try(:id) }
+ # assert result correctness
+ commits_with_pipelines.each do |commit|
+ expect(commit.lazy_latest_pipeline.project).to eq(commit.project)
+ end
+
+ expect(commits.last.lazy_latest_pipeline&.itself).to be_nil
end
- expect(recorder.count).to eq(1)
+ expect(recorder.count).to eq(2)
end
end
diff --git a/spec/models/concerns/require_email_verification_spec.rb b/spec/models/concerns/require_email_verification_spec.rb
index 0a6293f852e..1fb54e4276f 100644
--- a/spec/models/concerns/require_email_verification_spec.rb
+++ b/spec/models/concerns/require_email_verification_spec.rb
@@ -15,24 +15,20 @@ RSpec.describe RequireEmailVerification, feature_category: :insider_threat do
using RSpec::Parameterized::TableSyntax
- where(:feature_flag_enabled, :two_factor_enabled, :skipped, :overridden) do
- false | false | false | false
- false | false | true | false
- false | true | false | false
- false | true | true | false
- true | false | false | true
- true | false | true | false
- true | true | false | false
- true | true | true | false
- end
+ where(feature_flag_enabled: [true, false],
+ two_factor_enabled: [true, false],
+ oauth_user: [true, false],
+ skipped: [true, false])
with_them do
let(:instance) { model.new(id: 1) }
let(:another_instance) { model.new(id: 2) }
+ let(:overridden) { feature_flag_enabled && !two_factor_enabled && !oauth_user && !skipped }
before do
stub_feature_flags(require_email_verification: feature_flag_enabled ? instance : another_instance)
allow(instance).to receive(:two_factor_enabled?).and_return(two_factor_enabled)
+ allow(instance).to receive(:identities).and_return(oauth_user ? [:google] : [])
stub_feature_flags(skip_require_email_verification: skipped ? instance : another_instance)
end
diff --git a/spec/requests/api/terraform/state_spec.rb b/spec/requests/api/terraform/state_spec.rb
index 4c9f930df2f..bce004dcd48 100644
--- a/spec/requests/api/terraform/state_spec.rb
+++ b/spec/requests/api/terraform/state_spec.rb
@@ -114,6 +114,17 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
end
end
+ context 'allow_dots_on_tf_state_names is disabled, and the state name contains a dot' do
+ let(:state_name) { 'state-name-with-dot' }
+ let(:state_path) { "/projects/#{project_id}/terraform/state/#{state_name}.tfstate" }
+
+ before do
+ stub_feature_flags(allow_dots_on_tf_state_names: false)
+ end
+
+ it_behaves_like 'can access terraform state'
+ end
+
context 'for a project that does not exist' do
let(:project_id) { '0000' }
@@ -266,6 +277,21 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
expect(Gitlab::Json.parse(response.body)).to be_empty
end
end
+
+ context 'allow_dots_on_tf_state_names is disabled, and the state name contains a dot' do
+ let(:non_existing_state_name) { 'state-name-with-dot.tfstate' }
+
+ before do
+ stub_feature_flags(allow_dots_on_tf_state_names: false)
+ end
+
+ it 'strips characters after the dot' do
+ expect { request }.to change { Terraform::State.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(Terraform::State.last.name).to eq('state-name-with-dot')
+ end
+ end
end
context 'without body' do
@@ -373,6 +399,18 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
it_behaves_like 'schedules the state for deletion'
end
+ context 'allow_dots_on_tf_state_names is disabled, and the state name contains a dot' do
+ let(:state_name) { 'state-name-with-dot' }
+ let(:state_name_with_dot) { "#{state_name}.tfstate" }
+ let(:state_path) { "/projects/#{project_id}/terraform/state/#{state_name_with_dot}" }
+
+ before do
+ stub_feature_flags(allow_dots_on_tf_state_names: false)
+ end
+
+ it_behaves_like 'schedules the state for deletion'
+ end
+
context 'with invalid state name' do
let(:state_name) { 'foo/bar' }
@@ -462,10 +500,30 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
context 'with a dot in the state name' do
let(:state_name) { 'test.state' }
- it 'locks the terraform state' do
- request
+ context 'with allow_dots_on_tf_state_names ff enabled' do
+ before do
+ stub_feature_flags(allow_dots_on_tf_state_names: true)
+ end
- expect(response).to have_gitlab_http_status(:ok)
+ let(:state_name) { 'test.state' }
+
+ it 'locks the terraform state' do
+ request
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'with allow_dots_on_tf_state_names ff disabled' do
+ before do
+ stub_feature_flags(allow_dots_on_tf_state_names: false)
+ end
+
+ it 'returns 404' do
+ request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
end
end
end
@@ -486,6 +544,7 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
before do
state.lock_xid = '123.456'
state.save!
+ stub_feature_flags(allow_dots_on_tf_state_names: true)
end
subject(:request) { delete api("#{state_path}/lock"), headers: auth_header, params: params }
@@ -516,6 +575,23 @@ RSpec.describe API::Terraform::State, :snowplow, feature_category: :infrastructu
end
end
+ context 'with allow_dots_on_tf_state_names ff disabled' do
+ before do
+ stub_feature_flags(allow_dots_on_tf_state_names: false)
+ end
+
+ context 'with dots in the state name' do
+ let(:lock_id) { '123.456' }
+ let(:state_name) { 'test.state' }
+
+ it 'returns 404' do
+ request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
context 'with no lock id (force-unlock)' do
let(:params) { {} }
diff --git a/spec/services/projects/android_target_platform_detector_service_spec.rb b/spec/services/projects/android_target_platform_detector_service_spec.rb
deleted file mode 100644
index d5feef4ec3d..00000000000
--- a/spec/services/projects/android_target_platform_detector_service_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Projects::AndroidTargetPlatformDetectorService, feature_category: :projects do
- let_it_be(:project) { build(:project) }
-
- subject { described_class.new(project).execute }
-
- before do
- allow(Gitlab::FileFinder).to receive(:new) { finder }
- end
-
- context 'when project is not an Android project' do
- let(:finder) { instance_double(Gitlab::FileFinder, find: []) }
-
- it { is_expected.to be_nil }
- end
-
- context 'when project is an Android project' do
- let(:finder) { instance_double(Gitlab::FileFinder) }
-
- before do
- query = described_class::MANIFEST_FILE_SEARCH_QUERY
- allow(finder).to receive(:find).with(query) { [instance_double(Gitlab::Search::FoundBlob)] }
- end
-
- it { is_expected.to eq :android }
- end
-end
diff --git a/spec/services/projects/record_target_platforms_service_spec.rb b/spec/services/projects/record_target_platforms_service_spec.rb
index dd4e9fe19e0..17aa7fd7009 100644
--- a/spec/services/projects/record_target_platforms_service_spec.rb
+++ b/spec/services/projects/record_target_platforms_service_spec.rb
@@ -9,34 +9,23 @@ RSpec.describe Projects::RecordTargetPlatformsService, '#execute', feature_categ
subject(:execute) { described_class.new(project, detector_service).execute }
- context 'when detector returns target platform values' do
- let(:detector_result) { [:ios, :osx] }
- let(:service_result) { detector_result.map(&:to_s) }
+ context 'when project is an XCode project' do
+ def project_setting
+ ProjectSetting.find_by_project_id(project.id)
+ end
before do
- double = instance_double(detector_service, execute: detector_result)
- allow(detector_service).to receive(:new) { double }
+ double = instance_double(detector_service, execute: [:ios, :osx])
+ allow(Projects::AppleTargetPlatformDetectorService).to receive(:new) { double }
end
- shared_examples 'saves and returns detected target platforms' do
- it 'creates a new setting record for the project', :aggregate_failures do
- expect { execute }.to change { ProjectSetting.count }.from(0).to(1)
- expect(ProjectSetting.last.target_platforms).to match_array(service_result)
- end
-
- it 'returns the array of stored target platforms' do
- expect(execute).to match_array service_result
- end
+ it 'creates a new setting record for the project', :aggregate_failures do
+ expect { execute }.to change { ProjectSetting.count }.from(0).to(1)
+ expect(ProjectSetting.last.target_platforms).to match_array(%w(ios osx))
end
- it_behaves_like 'saves and returns detected target platforms'
-
- context 'when detector returns a non-array value' do
- let(:detector_service) { Projects::AndroidTargetPlatformDetectorService }
- let(:detector_result) { :android }
- let(:service_result) { [detector_result.to_s] }
-
- it_behaves_like 'saves and returns detected target platforms'
+ it 'returns array of detected target platforms' do
+ expect(execute).to match_array %w(ios osx)
end
context 'when a project has an existing setting record' do
@@ -44,10 +33,6 @@ RSpec.describe Projects::RecordTargetPlatformsService, '#execute', feature_categ
create(:project_setting, project: project, target_platforms: saved_target_platforms)
end
- def project_setting
- ProjectSetting.find_by_project_id(project.id)
- end
-
context 'when target platforms changed' do
let(:saved_target_platforms) { %w(tvos) }
@@ -98,44 +83,23 @@ RSpec.describe Projects::RecordTargetPlatformsService, '#execute', feature_categ
it_behaves_like 'tracks experiment assignment event'
end
- shared_examples 'does not send email' do
- it 'does not execute a Projects::InProductMarketingCampaignEmailsService' do
- expect(Projects::InProductMarketingCampaignEmailsService).not_to receive(:new)
-
- execute
- end
- end
-
context 'experiment control' do
before do
stub_experiments(build_ios_app_guide_email: :control)
end
- it_behaves_like 'does not send email'
- it_behaves_like 'tracks experiment assignment event'
- end
-
- context 'when project is not an iOS project' do
- let(:detector_service) { Projects::AppleTargetPlatformDetectorService }
- let(:detector_result) { :android }
-
- before do
- stub_experiments(build_ios_app_guide_email: :candidate)
- end
-
- it_behaves_like 'does not send email'
-
- it 'does not track experiment assignment event', :experiment do
- expect(experiment(:build_ios_app_guide_email))
- .not_to track(:assignment)
+ it 'does not execute a Projects::InProductMarketingCampaignEmailsService' do
+ expect(Projects::InProductMarketingCampaignEmailsService).not_to receive(:new)
execute
end
+
+ it_behaves_like 'tracks experiment assignment event'
end
end
end
- context 'when detector does not return any target platform values' do
+ context 'when project is not an XCode project' do
before do
double = instance_double(Projects::AppleTargetPlatformDetectorService, execute: [])
allow(Projects::AppleTargetPlatformDetectorService).to receive(:new).with(project) { double }
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index e488ca19903..a6b069bc93b 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -9495,7 +9495,6 @@
- './spec/services/projects/alerting/notify_service_spec.rb'
- './spec/services/projects/all_issues_count_service_spec.rb'
- './spec/services/projects/all_merge_requests_count_service_spec.rb'
-- './spec/services/projects/android_target_platform_detector_service_spec.rb'
- './spec/services/projects/apple_target_platform_detector_service_spec.rb'
- './spec/services/projects/autocomplete_service_spec.rb'
- './spec/services/projects/auto_devops/disable_service_spec.rb'
diff --git a/spec/workers/projects/record_target_platforms_worker_spec.rb b/spec/workers/projects/record_target_platforms_worker_spec.rb
index c1e99d52473..0e106fe32f9 100644
--- a/spec/workers/projects/record_target_platforms_worker_spec.rb
+++ b/spec/workers/projects/record_target_platforms_worker_spec.rb
@@ -7,11 +7,11 @@ RSpec.describe Projects::RecordTargetPlatformsWorker, feature_category: :project
let_it_be(:swift) { create(:programming_language, name: 'Swift') }
let_it_be(:objective_c) { create(:programming_language, name: 'Objective-C') }
- let_it_be(:java) { create(:programming_language, name: 'Java') }
- let_it_be(:kotlin) { create(:programming_language, name: 'Kotlin') }
let_it_be(:project) { create(:project, :repository, detected_repository_languages: true) }
let(:worker) { described_class.new }
+ let(:service_result) { %w(ios osx watchos) }
+ let(:service_double) { instance_double(Projects::RecordTargetPlatformsService, execute: service_result) }
let(:lease_key) { "#{described_class.name.underscore}:#{project.id}" }
let(:lease_timeout) { described_class::LEASE_TIMEOUT }
@@ -49,68 +49,19 @@ RSpec.describe Projects::RecordTargetPlatformsWorker, feature_category: :project
end
end
- def create_language(language)
- create(:repository_language, project: project, programming_language: language)
- end
-
- context 'when project uses programming language for Apple platform' do
- let(:service_result) { %w(ios osx watchos) }
-
- context 'when project uses Swift programming language' do
- before do
- create_language(swift)
- end
-
- it_behaves_like 'performs detection', Projects::AppleTargetPlatformDetectorService
- end
+ context 'when project uses Swift programming language' do
+ let!(:repository_language) { create(:repository_language, project: project, programming_language: swift) }
- context 'when project uses Objective-C programming language' do
- before do
- create_language(objective_c)
- end
-
- it_behaves_like 'performs detection', Projects::AppleTargetPlatformDetectorService
- end
+ include_examples 'performs detection', Projects::AppleTargetPlatformDetectorService
end
- context 'when project uses programming language for Android platform' do
- let(:feature_enabled) { true }
- let(:service_result) { %w(android) }
-
- before do
- stub_feature_flags(detect_android_projects: feature_enabled)
- end
+ context 'when project uses Objective-C programming language' do
+ let!(:repository_language) { create(:repository_language, project: project, programming_language: objective_c) }
- context 'when project uses Java' do
- before do
- create_language(java)
- end
-
- it_behaves_like 'performs detection', Projects::AndroidTargetPlatformDetectorService
-
- context 'when feature flag is disabled' do
- let(:feature_enabled) { false }
-
- it_behaves_like 'does nothing'
- end
- end
-
- context 'when project uses Kotlin' do
- before do
- create_language(kotlin)
- end
-
- it_behaves_like 'performs detection', Projects::AndroidTargetPlatformDetectorService
-
- context 'when feature flag is disabled' do
- let(:feature_enabled) { false }
-
- it_behaves_like 'does nothing'
- end
- end
+ include_examples 'performs detection', Projects::AppleTargetPlatformDetectorService
end
- context 'when the project does not use programming languages for Apple or Android platforms' do
+ context 'when the project does not contain programming languages for Apple platforms' do
it_behaves_like 'does nothing'
end