summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-02-28 12:14:07 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2023-02-28 12:14:07 +0000
commit22ecb1e3fc02bb923c3e9941b1baa849348a036f (patch)
treec01d9e91564f50e790a63c71675dd0f6e7735153 /spec
parent5eab6dcdd923ca375b86d6993f20a3e37dbd7a51 (diff)
downloadgitlab-ce-22ecb1e3fc02bb923c3e9941b1baa849348a036f.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb14
-rw-r--r--spec/features/groups/new_group_page_spec.rb42
-rw-r--r--spec/features/projects/new_project_spec.rb40
-rw-r--r--spec/frontend/issues/create_merge_request_dropdown_spec.js8
-rw-r--r--spec/helpers/sidebars_helper_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb21
-rw-r--r--spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb21
-rw-r--r--spec/lib/sidebars/concerns/super_sidebar_panel_spec.rb141
-rw-r--r--spec/lib/sidebars/menu_spec.rb16
-rw-r--r--spec/lib/sidebars/projects/panel_spec.rb6
-rw-r--r--spec/lib/sidebars/projects/super_sidebar_menus/plan_menu_spec.rb12
-rw-r--r--spec/lib/sidebars/projects/super_sidebar_panel_spec.rb47
-rw-r--r--spec/lib/sidebars/static_menu_spec.rb36
-rw-r--r--spec/lib/sidebars/uncategorized_menu_spec.rb12
-rw-r--r--spec/models/namespace_spec.rb31
-rw-r--r--spec/models/uploads/fog_spec.rb87
-rw-r--r--spec/requests/api/ci/runner/jobs_request_post_spec.rb13
-rw-r--r--spec/scripts/generate_rspec_pipeline_spec.rb198
-rw-r--r--spec/services/ci/create_pipeline_service/scripts_spec.rb25
-rw-r--r--spec/support/helpers/stub_object_storage.rb4
-rw-r--r--spec/support/rspec_order_todo.yml1
21 files changed, 691 insertions, 88 deletions
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index 96006974c13..5e4e47be2c5 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -436,6 +436,13 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
expect(json_response['commands_changes']).to include('emoji_award', 'time_estimate', 'spend_time')
expect(json_response['commands_changes']).not_to include('target_project', 'title')
end
+
+ it 'includes command_names' do
+ create!
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['command_names']).to include('award', 'estimate', 'spend')
+ end
end
context 'with commands that do not return changes' do
@@ -454,6 +461,13 @@ RSpec.describe Projects::NotesController, type: :controller, feature_category: :
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['commands_changes']).not_to include('target_project', 'title')
end
+
+ it 'includes command_names' do
+ create!
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['command_names']).to include('move', 'title')
+ end
end
end
end
diff --git a/spec/features/groups/new_group_page_spec.rb b/spec/features/groups/new_group_page_spec.rb
index 4670df3fb5e..6d9513ce84f 100644
--- a/spec/features/groups/new_group_page_spec.rb
+++ b/spec/features/groups/new_group_page_spec.rb
@@ -30,16 +30,42 @@ RSpec.describe 'New group page', :js, feature_category: :subgroups do
end
describe 'sidebar' do
- context 'for a new top-level group' do
- it_behaves_like 'a dashboard page with sidebar', :new_group_path, :groups
+ context 'in the current navigation' do
+ before do
+ user.update!(use_new_navigation: false)
+ end
+
+ context 'for a new top-level group' do
+ it_behaves_like 'a dashboard page with sidebar', :new_group_path, :groups
+ end
+
+ context 'for a new subgroup' do
+ it 'shows the group sidebar of the parent group' do
+ visit new_group_path(parent_id: parent_group.id, anchor: 'create-group-pane')
+ expect(page).to have_selector(
+ ".nav-sidebar[aria-label=\"Group navigation\"] .context-header[title=\"#{parent_group.name}\"]"
+ )
+ end
+ end
end
- context 'for a new subgroup' do
- it 'shows the group sidebar of the parent group' do
- visit new_group_path(parent_id: parent_group.id, anchor: 'create-group-pane')
- expect(page).to have_selector(
- ".nav-sidebar[aria-label=\"Group navigation\"] .context-header[title=\"#{parent_group.name}\"]"
- )
+ context 'in the new navigation' do
+ before do
+ user.update!(use_new_navigation: true)
+ end
+
+ context 'for a new top-level group' do
+ it 'shows the "Your work" navigation' do
+ visit new_group_path
+ expect(page).to have_selector(".super-sidebar .context-switcher-toggle", text: "Your work")
+ end
+ end
+
+ context 'for a new subgroup' do
+ it 'shows the group navigation of the parent group' do
+ visit new_group_path(parent_id: parent_group.id, anchor: 'create-group-pane')
+ expect(page).to have_selector(".super-sidebar .context-switcher-toggle", text: parent_group.name)
+ end
end
end
end
diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb
index 3cbfa14208f..439ae4275ae 100644
--- a/spec/features/projects/new_project_spec.rb
+++ b/spec/features/projects/new_project_spec.rb
@@ -588,14 +588,42 @@ RSpec.describe 'New project', :js, feature_category: :projects do
sign_in(user)
end
- context 'for a new top-level project' do
- it_behaves_like 'a dashboard page with sidebar', :new_project_path, :projects
+ context 'in the current navigation' do
+ before do
+ user.update!(use_new_navigation: false)
+ end
+
+ context 'for a new top-level project' do
+ it_behaves_like 'a dashboard page with sidebar', :new_project_path, :projects
+ end
+
+ context 'for a new group project' do
+ it 'shows the group sidebar of the parent group' do
+ visit new_project_path(namespace_id: parent_group.id)
+ expect(page).to have_selector(".nav-sidebar[aria-label=\"Group navigation\"] .context-header[title=\"#{parent_group.name}\"]")
+ end
+ end
end
- context 'for a new group project' do
- it 'shows the group sidebar of the parent group' do
- visit new_project_path(namespace_id: parent_group.id)
- expect(page).to have_selector(".nav-sidebar[aria-label=\"Group navigation\"] .context-header[title=\"#{parent_group.name}\"]")
+ context 'in the new navigation' do
+ before do
+ parent_group.add_owner(user)
+ user.update!(use_new_navigation: true)
+ sign_in(user)
+ end
+
+ context 'for a new top-level project' do
+ it 'shows the "Your work" navigation' do
+ visit new_project_path
+ expect(page).to have_selector(".super-sidebar .context-switcher-toggle", text: "Your work")
+ end
+ end
+
+ context 'for a new group project' do
+ it 'shows the group sidebar of the parent group' do
+ visit new_project_path(namespace_id: parent_group.id)
+ expect(page).to have_selector(".super-sidebar .context-switcher-toggle", text: parent_group.name)
+ end
end
end
end
diff --git a/spec/frontend/issues/create_merge_request_dropdown_spec.js b/spec/frontend/issues/create_merge_request_dropdown_spec.js
index cc2ee84348a..21ae844e2dd 100644
--- a/spec/frontend/issues/create_merge_request_dropdown_spec.js
+++ b/spec/frontend/issues/create_merge_request_dropdown_spec.js
@@ -65,6 +65,14 @@ describe('CreateMergeRequestDropdown', () => {
expect(dropdown.createMrPath).toBe(
`${TEST_HOST}/create_merge_request?merge_request%5Bsource_branch%5D=contains%23hash&merge_request%5Btarget_branch%5D=master&merge_request%5Bissue_iid%5D=42`,
);
+
+ expect(dropdown.wrapperEl.dataset.createBranchPath).toBe(
+ `${TEST_HOST}/branches?branch_name=contains%23hash&issue=42`,
+ );
+
+ expect(dropdown.wrapperEl.dataset.createMrPath).toBe(
+ `${TEST_HOST}/create_merge_request?merge_request%5Bsource_branch%5D=contains%23hash&merge_request%5Btarget_branch%5D=master&merge_request%5Bissue_iid%5D=42`,
+ );
});
});
diff --git a/spec/helpers/sidebars_helper_spec.rb b/spec/helpers/sidebars_helper_spec.rb
index aa6b1dba6e8..1afe4efaf22 100644
--- a/spec/helpers/sidebars_helper_spec.rb
+++ b/spec/helpers/sidebars_helper_spec.rb
@@ -192,7 +192,7 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
before do
allow(helper).to receive(:project_sidebar_context_data).and_return(
- { current_user: nil, container: project, can_view_pipeline_editor: false })
+ { current_user: nil, container: project, can_view_pipeline_editor: false, learn_gitlab_enabled: false })
allow(helper).to receive(:group_sidebar_context_data).and_return({ current_user: nil, container: group })
allow(group).to receive(:to_global_id).and_return(5)
@@ -204,7 +204,7 @@ RSpec.describe SidebarsHelper, feature_category: :navigation do
end
it 'returns Project Panel for project nav' do
- expect(helper.super_sidebar_nav_panel(nav: 'project')).to be_a(Sidebars::Projects::Panel)
+ expect(helper.super_sidebar_nav_panel(nav: 'project')).to be_a(Sidebars::Projects::SuperSidebarPanel)
end
it 'returns Group Panel for group nav' do
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index 4773c0b5e1e..c8b4a8b8a0e 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -728,27 +728,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job, feature_category: :pipeline_compo
scheduling_type: :stage,
id_tokens: { TEST_ID_TOKEN: { aud: 'https://gitlab.com' } })
end
-
- context 'when the FF ci_hooks_pre_get_sources_script is disabled' do
- before do
- stub_feature_flags(ci_hooks_pre_get_sources_script: false)
- end
-
- it 'returns correct value' do
- expect(entry.value)
- .to eq(name: :rspec,
- before_script: %w[ls pwd],
- script: %w[rspec],
- stage: 'test',
- ignore: false,
- after_script: %w[cleanup],
- only: { refs: %w[branches tags] },
- job_variables: {},
- root_variables_inheritance: true,
- scheduling_type: :stage,
- id_tokens: { TEST_ID_TOKEN: { aud: 'https://gitlab.com' } })
- end
- end
end
end
diff --git a/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb b/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb
index 57c5011590c..6bcefa455cf 100644
--- a/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb
+++ b/spec/lib/gitlab/database/migrations/test_batched_background_runner_spec.rb
@@ -48,6 +48,7 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
let(:result_dir) { Pathname.new(Dir.mktmpdir) }
let(:connection) { base_model.connection }
let(:table_name) { "_test_column_copying" }
+ let(:num_rows_in_table) { 1000 }
let(:from_id) { 0 }
after do
@@ -61,7 +62,7 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
data bigint default 0
);
- insert into #{table_name} (id) select i from generate_series(1, 1000) g(i);
+ insert into #{table_name} (id) select i from generate_series(1, #{num_rows_in_table}) g(i);
SQL
end
@@ -134,6 +135,24 @@ RSpec.describe Gitlab::Database::Migrations::TestBatchedBackgroundRunner, :freez
expect(calls).not_to be_empty
end
+ it 'samples 1 job with a batch size higher than the table size' do
+ calls = []
+ define_background_migration(migration_name) do |*args|
+ travel 1.minute
+ calls << args
+ end
+
+ queue_migration(migration_name, table_name, :id,
+ job_interval: 5.minutes,
+ batch_size: num_rows_in_table * 2,
+ sub_batch_size: num_rows_in_table * 2)
+
+ described_class.new(result_dir: result_dir, connection: connection,
+ from_id: from_id).run_jobs(for_duration: 3.minutes)
+
+ expect(calls.size).to eq(1)
+ end
+
context 'with multiple jobs to run' do
let(:last_id) do
Gitlab::Database::SharedModel.using_connection(connection) do
diff --git a/spec/lib/sidebars/concerns/super_sidebar_panel_spec.rb b/spec/lib/sidebars/concerns/super_sidebar_panel_spec.rb
new file mode 100644
index 00000000000..55598948271
--- /dev/null
+++ b/spec/lib/sidebars/concerns/super_sidebar_panel_spec.rb
@@ -0,0 +1,141 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Sidebars::Concerns::SuperSidebarPanel, feature_category: :navigation do
+ let(:menu_class_foo) { Class.new(Sidebars::Menu) }
+ let(:menu_foo) { menu_class_foo.new({}) }
+
+ let(:menu_class_bar) do
+ Class.new(Sidebars::Menu) do
+ def title
+ "Bar"
+ end
+ end
+ end
+
+ let(:menu_bar) { menu_class_bar.new({}) }
+
+ subject do
+ Class.new(Sidebars::Panel) do
+ include Sidebars::Concerns::SuperSidebarPanel
+ end.new({})
+ end
+
+ before do
+ allow(menu_foo).to receive(:render?).and_return(true)
+ allow(menu_bar).to receive(:render?).and_return(true)
+ end
+
+ describe '#pick_from_old_menus' do
+ it 'removes element of a given class from a list and adds it to menus' do
+ old_menus = [menu_foo, menu_bar]
+
+ subject.pick_from_old_menus(old_menus, menu_class_foo)
+
+ expect(old_menus).not_to include(menu_foo)
+ expect(subject.renderable_menus).to include(menu_foo)
+ end
+
+ it 'is a noop, if the list does not contain an element of the wanted class' do
+ old_menus = [menu_foo]
+
+ subject.pick_from_old_menus(old_menus, menu_class_bar)
+
+ expect(old_menus).to eq([menu_foo])
+ expect(subject.renderable_menus).to eq([])
+ end
+ end
+
+ describe '#transform_old_menus' do
+ let(:uncategorized_menu) { ::Sidebars::UncategorizedMenu.new({}) }
+
+ let(:menu_item) do
+ Sidebars::MenuItem.new(title: 'foo3', link: 'foo3', active_routes: { controller: 'barc' },
+ super_sidebar_parent: menu_class_foo)
+ end
+
+ let(:nil_menu_item) { Sidebars::NilMenuItem.new(item_id: :nil_item) }
+ let(:existing_item) do
+ Sidebars::MenuItem.new(
+ item_id: :exists,
+ title: 'Existing item',
+ link: 'foo2',
+ active_routes: { controller: 'foo2' }
+ )
+ end
+
+ let(:current_menus) { [menu_foo, uncategorized_menu] }
+
+ before do
+ allow(menu_bar).to receive(:serialize_as_menu_item_args).and_return(nil)
+ menu_foo.add_item(existing_item)
+ end
+
+ context 'for Menus with Menu Items' do
+ before do
+ menu_bar.add_item(menu_item)
+ menu_bar.add_item(nil_menu_item)
+ end
+
+ it 'adds Menu Items to defined super_sidebar_parent' do
+ subject.transform_old_menus(current_menus, menu_bar)
+
+ expect(menu_foo.renderable_items).to eq([existing_item, menu_item])
+ expect(uncategorized_menu.renderable_items).to eq([])
+ end
+
+ it 'adds Menu Items to defined super_sidebar_parent, before super_sidebar_before' do
+ allow(menu_item).to receive(:super_sidebar_before).and_return(:exists)
+ subject.transform_old_menus(current_menus, menu_bar)
+
+ expect(menu_foo.renderable_items).to eq([menu_item, existing_item])
+ expect(uncategorized_menu.renderable_items).to eq([])
+ end
+
+ it 'considers Menu Items uncategorized if super_sidebar_parent is nil' do
+ allow(menu_item).to receive(:super_sidebar_parent).and_return(nil)
+ subject.transform_old_menus(current_menus, menu_bar)
+
+ expect(menu_foo.renderable_items).to eq([existing_item])
+ expect(uncategorized_menu.renderable_items).to eq([menu_item])
+ end
+
+ it 'considers Menu Items uncategorized if super_sidebar_parent cannot be found' do
+ allow(menu_item).to receive(:super_sidebar_parent).and_return(menu_class_bar)
+ subject.transform_old_menus(current_menus, menu_bar)
+
+ expect(menu_foo.renderable_items).to eq([existing_item])
+ expect(uncategorized_menu.renderable_items).to eq([menu_item])
+ end
+
+ it 'considers Menu Items deleted if super_sidebar_parent is Sidebars::NilMenuItem' do
+ allow(menu_item).to receive(:super_sidebar_parent).and_return(::Sidebars::NilMenuItem)
+ subject.transform_old_menus(current_menus, menu_bar)
+
+ expect(menu_foo.renderable_items).to eq([existing_item])
+ expect(uncategorized_menu.renderable_items).to eq([])
+ end
+ end
+
+ it 'converts "solo" top-level Menu entry to Menu Item' do
+ allow(Sidebars::MenuItem).to receive(:new).and_return(menu_item)
+ allow(menu_bar).to receive(:serialize_as_menu_item_args).and_return({})
+
+ subject.transform_old_menus(current_menus, menu_bar)
+
+ expect(menu_foo.renderable_items).to eq([existing_item, menu_item])
+ expect(uncategorized_menu.renderable_items).to eq([])
+ end
+
+ it 'drops "solo" top-level Menu entries, if they serialize to nil' do
+ allow(Sidebars::MenuItem).to receive(:new).and_return(menu_item)
+ allow(menu_bar).to receive(:serialize_as_menu_item_args).and_return(nil)
+
+ subject.transform_old_menus(current_menus, menu_bar)
+
+ expect(menu_foo.renderable_items).to eq([existing_item])
+ expect(uncategorized_menu.renderable_items).to eq([])
+ end
+ end
+end
diff --git a/spec/lib/sidebars/menu_spec.rb b/spec/lib/sidebars/menu_spec.rb
index c84e04a738f..7c4d74aecc8 100644
--- a/spec/lib/sidebars/menu_spec.rb
+++ b/spec/lib/sidebars/menu_spec.rb
@@ -56,6 +56,22 @@ RSpec.describe Sidebars::Menu, feature_category: :navigation do
end
end
+ describe '#serialize_as_menu_item_args' do
+ it 'returns hash of title, link, active_routes, container_html_options' do
+ allow(menu).to receive(:title).and_return('Title')
+ allow(menu).to receive(:active_routes).and_return({ path: 'foo' })
+ allow(menu).to receive(:container_html_options).and_return({ class: 'foo' })
+ allow(menu).to receive(:link).and_return('/link')
+
+ expect(menu.serialize_as_menu_item_args).to eq({
+ title: 'Title',
+ link: '/link',
+ active_routes: { path: 'foo' },
+ container_html_options: { class: 'foo' }
+ })
+ end
+ end
+
describe '#render?' do
context 'when the menus has no items' do
it 'returns false' do
diff --git a/spec/lib/sidebars/projects/panel_spec.rb b/spec/lib/sidebars/projects/panel_spec.rb
index a581b982f9f..ec1df438cf1 100644
--- a/spec/lib/sidebars/projects/panel_spec.rb
+++ b/spec/lib/sidebars/projects/panel_spec.rb
@@ -13,12 +13,6 @@ RSpec.describe Sidebars::Projects::Panel, feature_category: :navigation do
expect(subject.scope_menu).to be_a(Sidebars::Projects::Menus::ScopeMenu)
end
- it 'implements #super_sidebar_context_header' do
- expect(subject.super_sidebar_context_header).to eq({
- title: project.name, avatar: project.avatar_url, id: project.id
- })
- end
-
context 'Confluence menu item' do
subject { described_class.new(context).instance_variable_get(:@menus) }
diff --git a/spec/lib/sidebars/projects/super_sidebar_menus/plan_menu_spec.rb b/spec/lib/sidebars/projects/super_sidebar_menus/plan_menu_spec.rb
new file mode 100644
index 00000000000..3917d26f6f2
--- /dev/null
+++ b/spec/lib/sidebars/projects/super_sidebar_menus/plan_menu_spec.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::Projects::SuperSidebarMenus::PlanMenu, feature_category: :navigation do
+ subject { described_class.new({}) }
+
+ it 'has title and sprite_icon' do
+ expect(subject.title).to eq(_("Plan"))
+ expect(subject.sprite_icon).to eq("planning")
+ end
+end
diff --git a/spec/lib/sidebars/projects/super_sidebar_panel_spec.rb b/spec/lib/sidebars/projects/super_sidebar_panel_spec.rb
new file mode 100644
index 00000000000..a4df46ca493
--- /dev/null
+++ b/spec/lib/sidebars/projects/super_sidebar_panel_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::Projects::SuperSidebarPanel, feature_category: :navigation do
+ let_it_be(:project) { create(:project, :repository) }
+
+ let(:user) { project.first_owner }
+
+ let(:context) do
+ double("Stubbed context", current_user: user, container: project, project: project, current_ref: 'master').as_null_object # rubocop:disable RSpec/VerifiedDoubles
+ end
+
+ subject { described_class.new(context) }
+
+ it 'implements #super_sidebar_context_header' do
+ expect(subject.super_sidebar_context_header).to eq(
+ {
+ title: project.name,
+ avatar: project.avatar_url,
+ id: project.id
+ })
+ end
+
+ describe '#renderable_menus' do
+ let(:category_menu) do
+ [
+ Sidebars::StaticMenu,
+ Sidebars::Projects::SuperSidebarMenus::PlanMenu,
+ Sidebars::Projects::Menus::RepositoryMenu,
+ Sidebars::Projects::Menus::CiCdMenu,
+ Sidebars::Projects::Menus::SecurityComplianceMenu,
+ Sidebars::Projects::Menus::DeploymentsMenu,
+ Sidebars::Projects::Menus::PackagesRegistriesMenu,
+ Sidebars::Projects::Menus::InfrastructureMenu,
+ Sidebars::Projects::Menus::MonitorMenu,
+ Sidebars::Projects::Menus::AnalyticsMenu,
+ Sidebars::UncategorizedMenu,
+ Sidebars::Projects::Menus::SettingsMenu
+ ]
+ end
+
+ it "is exposed as a renderable menu" do
+ expect(subject.renderable_menus.map(&:class)).to eq(category_menu)
+ end
+ end
+end
diff --git a/spec/lib/sidebars/static_menu_spec.rb b/spec/lib/sidebars/static_menu_spec.rb
new file mode 100644
index 00000000000..a42fed4b170
--- /dev/null
+++ b/spec/lib/sidebars/static_menu_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::StaticMenu, feature_category: :navigation do
+ let(:context) { {} }
+
+ subject { described_class.new(context) }
+
+ describe '#serialize_for_super_sidebar' do
+ it 'returns flat list of all menu items' do
+ subject.add_item(Sidebars::MenuItem.new(title: 'Is active', link: 'foo2', active_routes: { controller: 'fooc' }))
+ subject.add_item(Sidebars::MenuItem.new(title: 'Not active', link: 'foo3', active_routes: { controller: 'barc' }))
+ subject.add_item(Sidebars::NilMenuItem.new(item_id: 'nil_item'))
+
+ allow(context).to receive(:route_is_active).and_return(->(x) { x[:controller] == 'fooc' })
+
+ expect(subject.serialize_for_super_sidebar).to eq(
+ [
+ {
+ title: "Is active",
+ icon: nil,
+ link: "foo2",
+ is_active: true
+ },
+ {
+ title: "Not active",
+ icon: nil,
+ link: "foo3",
+ is_active: false
+ }
+ ]
+ )
+ end
+ end
+end
diff --git a/spec/lib/sidebars/uncategorized_menu_spec.rb b/spec/lib/sidebars/uncategorized_menu_spec.rb
new file mode 100644
index 00000000000..45e7c0c87e2
--- /dev/null
+++ b/spec/lib/sidebars/uncategorized_menu_spec.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::UncategorizedMenu, feature_category: :navigation do
+ subject { described_class.new({}) }
+
+ it 'has title and sprite_icon' do
+ expect(subject.title).to eq(_("Uncategorized"))
+ expect(subject.sprite_icon).to eq("question")
+ end
+end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 4e3d8f633b7..2d6ddd74dfd 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -465,6 +465,14 @@ RSpec.describe Namespace, feature_category: :subgroups do
end
end
+ context 'when parent is nil' do
+ let(:namespace) { build(:group, parent: nil) }
+
+ it 'returns []' do
+ expect(namespace.traversal_ids).to eq []
+ end
+ end
+
context 'when made a child group' do
let!(:namespace) { create(:group) }
let!(:parent_namespace) { create(:group, children: [namespace]) }
@@ -1961,6 +1969,29 @@ RSpec.describe Namespace, feature_category: :subgroups do
expect(very_deep_nested_group.root_ancestor).to eq(root_group)
end
end
+
+ context 'when parent is changed' do
+ let(:group) { create(:group) }
+ let(:new_parent) { create(:group) }
+
+ shared_examples 'updates root_ancestor' do
+ it do
+ expect { subject }.to change { group.root_ancestor }.from(group).to(new_parent)
+ end
+ end
+
+ context 'by object' do
+ subject { group.parent = new_parent }
+
+ include_examples 'updates root_ancestor'
+ end
+
+ context 'by id' do
+ subject { group.parent_id = new_parent.id }
+
+ include_examples 'updates root_ancestor'
+ end
+ end
end
describe '#full_path_before_last_save' do
diff --git a/spec/models/uploads/fog_spec.rb b/spec/models/uploads/fog_spec.rb
index 1ffe7c6c43b..a1b0bcf95e0 100644
--- a/spec/models/uploads/fog_spec.rb
+++ b/spec/models/uploads/fog_spec.rb
@@ -3,10 +3,21 @@
require 'spec_helper'
RSpec.describe Uploads::Fog do
+ let(:credentials) do
+ {
+ provider: "AWS",
+ aws_access_key_id: "AWS_ACCESS_KEY_ID",
+ aws_secret_access_key: "AWS_SECRET_ACCESS_KEY",
+ region: "eu-central-1"
+ }
+ end
+
+ let(:bucket_prefix) { nil }
let(:data_store) { described_class.new }
+ let(:config) { { connection: credentials, bucket_prefix: bucket_prefix, remote_directory: 'uploads' } }
before do
- stub_uploads_object_storage(FileUploader)
+ stub_uploads_object_storage(FileUploader, config: config)
end
describe '#available?' do
@@ -18,7 +29,7 @@ RSpec.describe Uploads::Fog do
context 'when object storage is disabled' do
before do
- stub_uploads_object_storage(FileUploader, enabled: false)
+ stub_uploads_object_storage(FileUploader, config: config, enabled: false)
end
it { is_expected.to be_falsy }
@@ -28,6 +39,60 @@ RSpec.describe Uploads::Fog do
context 'model with uploads' do
let(:project) { create(:project) }
let(:relation) { project.uploads }
+ let(:connection) { ::Fog::Storage.new(credentials) }
+ let(:paths) { relation.pluck(:path) }
+
+ # Only fog-aws simulates mocking of deleting an object properly.
+ # We'll just test that the various providers implement the require methods.
+ describe 'Fog provider acceptance tests' do
+ let!(:uploads) { create_list(:upload, 2, :with_file, :issuable_upload, model: project) }
+
+ shared_examples 'Fog provider' do
+ describe '#get_object' do
+ it 'returns a Hash with a body' do
+ expect(connection.get_object('uploads', paths.first)[:body]).not_to be_nil
+ end
+ end
+
+ describe '#delete_object' do
+ it 'returns true' do
+ expect(connection.delete_object('uploads', paths.first)).to be_truthy
+ end
+ end
+ end
+
+ before do
+ uploads.each { |upload| upload.retrieve_uploader.migrate!(2) }
+ end
+
+ context 'with AWS provider' do
+ it_behaves_like 'Fog provider'
+ end
+
+ context 'with Google provider' do
+ let(:credentials) do
+ {
+ provider: "Google",
+ google_storage_access_key_id: 'ACCESS_KEY_ID',
+ google_storage_secret_access_key: 'SECRET_ACCESS_KEY'
+ }
+ end
+
+ it_behaves_like 'Fog provider'
+ end
+
+ context 'with AzureRM provider' do
+ let(:credentials) do
+ {
+ provider: 'AzureRM',
+ azure_storage_account_name: 'test-access-id',
+ azure_storage_access_key: 'secret'
+ }
+ end
+
+ it_behaves_like 'Fog provider'
+ end
+ end
describe '#keys' do
let!(:uploads) { create_list(:upload, 2, :object_storage, uploader: FileUploader, model: project) }
@@ -40,7 +105,7 @@ RSpec.describe Uploads::Fog do
end
describe '#delete_keys' do
- let(:connection) { ::Fog::Storage.new(FileUploader.object_store_credentials) }
+ let(:connection) { ::Fog::Storage.new(credentials) }
let(:keys) { data_store.keys(relation) }
let(:paths) { relation.pluck(:path) }
let!(:uploads) { create_list(:upload, 2, :with_file, :issuable_upload, model: project) }
@@ -63,6 +128,22 @@ RSpec.describe Uploads::Fog do
end
end
+ context 'with bucket prefix' do
+ let(:bucket_prefix) { 'test-prefix' }
+
+ it 'deletes multiple data' do
+ paths.each do |path|
+ expect(connection.get_object('uploads', File.join(bucket_prefix, path))[:body]).not_to be_nil
+ end
+
+ subject
+
+ paths.each do |path|
+ expect { connection.get_object('uploads', File.join(bucket_prefix, path))[:body] }.to raise_error(Excon::Error::NotFound)
+ end
+ end
+ end
+
context 'when one of keys is missing' do
let(:keys) { ['unknown'] + super() }
diff --git a/spec/requests/api/ci/runner/jobs_request_post_spec.rb b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
index 6e721d40560..28dbc4fd168 100644
--- a/spec/requests/api/ci/runner/jobs_request_post_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
@@ -831,19 +831,6 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego
end
end
end
-
- context 'when the FF ci_hooks_pre_get_sources_script is disabled' do
- before do
- stub_feature_flags(ci_hooks_pre_get_sources_script: false)
- end
-
- it 'does not return the pre_get_sources_script' do
- request_job
-
- expect(response).to have_gitlab_http_status(:created)
- expect(json_response).not_to have_key('hooks')
- end
- end
end
describe 'port support' do
diff --git a/spec/scripts/generate_rspec_pipeline_spec.rb b/spec/scripts/generate_rspec_pipeline_spec.rb
new file mode 100644
index 00000000000..b3eaf9e9127
--- /dev/null
+++ b/spec/scripts/generate_rspec_pipeline_spec.rb
@@ -0,0 +1,198 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'tempfile'
+
+require_relative '../../scripts/generate_rspec_pipeline'
+
+RSpec.describe GenerateRspecPipeline, :silence_stdout, feature_category: :tooling do
+ describe '#generate!' do
+ let!(:rspec_files) { Tempfile.new(['rspec_files_path', '.txt']) }
+ let(:rspec_files_content) do
+ "spec/migrations/a_spec.rb spec/migrations/b_spec.rb " \
+ "spec/lib/gitlab/background_migration/a_spec.rb spec/lib/gitlab/background_migration/b_spec.rb " \
+ "spec/models/a_spec.rb spec/models/b_spec.rb " \
+ "spec/controllers/a_spec.rb spec/controllers/b_spec.rb " \
+ "spec/features/a_spec.rb spec/features/b_spec.rb"
+ end
+
+ let(:pipeline_template) { Tempfile.new(['pipeline_template', '.yml.erb']) }
+ let(:pipeline_template_content) do
+ <<~YAML
+ <% if rspec_files_per_test_level[:migration][:files].size > 0 %>
+ rspec migration:
+ <% if rspec_files_per_test_level[:migration][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:migration][:parallelization] %>
+ <% end %>
+ <% end %>
+ <% if rspec_files_per_test_level[:background_migration][:files].size > 0 %>
+ rspec background_migration:
+ <% if rspec_files_per_test_level[:background_migration][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:background_migration][:parallelization] %>
+ <% end %>
+ <% end %>
+ <% if rspec_files_per_test_level[:unit][:files].size > 0 %>
+ rspec unit:
+ <% if rspec_files_per_test_level[:unit][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:unit][:parallelization] %>
+ <% end %>
+ <% end %>
+ <% if rspec_files_per_test_level[:integration][:files].size > 0 %>
+ rspec integration:
+ <% if rspec_files_per_test_level[:integration][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:integration][:parallelization] %>
+ <% end %>
+ <% end %>
+ <% if rspec_files_per_test_level[:system][:files].size > 0 %>
+ rspec system:
+ <% if rspec_files_per_test_level[:system][:parallelization] > 1 %>
+ parallel: <%= rspec_files_per_test_level[:system][:parallelization] %>
+ <% end %>
+ <% end %>
+ YAML
+ end
+
+ let(:knapsack_report) { Tempfile.new(['knapsack_report', '.json']) }
+ let(:knapsack_report_content) do
+ <<~JSON
+ {
+ "spec/migrations/a_spec.rb": 360.3,
+ "spec/migrations/b_spec.rb": 180.1,
+ "spec/lib/gitlab/background_migration/a_spec.rb": 60.5,
+ "spec/lib/gitlab/background_migration/b_spec.rb": 180.3,
+ "spec/models/a_spec.rb": 360.2,
+ "spec/models/b_spec.rb": 180.6,
+ "spec/controllers/a_spec.rb": 60.2,
+ "spec/controllers/ab_spec.rb": 180.4,
+ "spec/features/a_spec.rb": 360.1,
+ "spec/features/b_spec.rb": 180.5
+ }
+ JSON
+ end
+
+ around do |example|
+ rspec_files.write(rspec_files_content)
+ rspec_files.rewind
+ pipeline_template.write(pipeline_template_content)
+ pipeline_template.rewind
+ knapsack_report.write(knapsack_report_content)
+ knapsack_report.rewind
+ example.run
+ ensure
+ rspec_files.close
+ rspec_files.unlink
+ pipeline_template.close
+ pipeline_template.unlink
+ knapsack_report.close
+ knapsack_report.unlink
+ end
+
+ context 'when rspec_files and pipeline_template_path exists' do
+ subject do
+ described_class.new(
+ rspec_files_path: rspec_files.path,
+ pipeline_template_path: pipeline_template.path
+ )
+ end
+
+ it 'generates the pipeline config with default parallelization' do
+ subject.generate!
+
+ expect(File.read("#{pipeline_template.path}.yml"))
+ .to eq(
+ "rspec migration:\nrspec background_migration:\nrspec unit:\n" \
+ "rspec integration:\nrspec system:"
+ )
+ end
+
+ context 'when parallelization > 0' do
+ before do
+ stub_const("#{described_class}::DEFAULT_AVERAGE_TEST_FILE_DURATION_IN_SECONDS", 360)
+ end
+
+ it 'generates the pipeline config' do
+ subject.generate!
+
+ expect(File.read("#{pipeline_template.path}.yml"))
+ .to eq(
+ "rspec migration:\n parallel: 2\nrspec background_migration:\n parallel: 2\n" \
+ "rspec unit:\n parallel: 2\nrspec integration:\n parallel: 2\n" \
+ "rspec system:\n parallel: 2"
+ )
+ end
+ end
+
+ context 'when parallelization > MAX_NODES_COUNT' do
+ let(:rspec_files_content) do
+ Array.new(51) { |i| "spec/migrations/#{i}_spec.rb" }.join(' ')
+ end
+
+ before do
+ stub_const(
+ "#{described_class}::DEFAULT_AVERAGE_TEST_FILE_DURATION_IN_SECONDS",
+ described_class::OPTIMAL_TEST_JOB_DURATION_IN_SECONDS
+ )
+ end
+
+ it 'generates the pipeline config with max parallelization of 50' do
+ subject.generate!
+
+ expect(File.read("#{pipeline_template.path}.yml")).to eq("rspec migration:\n parallel: 50")
+ end
+ end
+ end
+
+ context 'when knapsack_report_path is given' do
+ subject do
+ described_class.new(
+ rspec_files_path: rspec_files.path,
+ pipeline_template_path: pipeline_template.path,
+ knapsack_report_path: knapsack_report.path
+ )
+ end
+
+ it 'generates the pipeline config with parallelization based on Knapsack' do
+ subject.generate!
+
+ expect(File.read("#{pipeline_template.path}.yml"))
+ .to eq(
+ "rspec migration:\n parallel: 2\nrspec background_migration:\n" \
+ "rspec unit:\n parallel: 2\nrspec integration:\n" \
+ "rspec system:\n parallel: 2"
+ )
+ end
+
+ context 'and Knapsack report does not contain valid JSON' do
+ let(:knapsack_report_content) { "#{super()}," }
+
+ it 'generates the pipeline config with default parallelization' do
+ subject.generate!
+
+ expect(File.read("#{pipeline_template.path}.yml"))
+ .to eq(
+ "rspec migration:\nrspec background_migration:\nrspec unit:\n" \
+ "rspec integration:\nrspec system:"
+ )
+ end
+ end
+ end
+
+ context 'when rspec_files does not exist' do
+ subject { described_class.new(rspec_files_path: nil, pipeline_template_path: pipeline_template.path) }
+
+ it 'generates the pipeline config using the no-op template' do
+ subject.generate!
+
+ expect(File.read("#{pipeline_template.path}.yml")).to include("no-op:")
+ end
+ end
+
+ context 'when pipeline_template_path does not exist' do
+ subject { described_class.new(rspec_files_path: rspec_files.path, pipeline_template_path: nil) }
+
+ it 'generates the pipeline config using the no-op template' do
+ expect { subject }.to raise_error(ArgumentError)
+ end
+ end
+ end
+end
diff --git a/spec/services/ci/create_pipeline_service/scripts_spec.rb b/spec/services/ci/create_pipeline_service/scripts_spec.rb
index 50b558e505a..770db9331cd 100644
--- a/spec/services/ci/create_pipeline_service/scripts_spec.rb
+++ b/spec/services/ci/create_pipeline_service/scripts_spec.rb
@@ -83,30 +83,5 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
options: { script: ["echo 'hello job3 script'"] }
)
end
-
- context 'when the FF ci_hooks_pre_get_sources_script is disabled' do
- before do
- stub_feature_flags(ci_hooks_pre_get_sources_script: false)
- end
-
- it 'creates jobs without hook data' do
- expect(pipeline).to be_created_successfully
- expect(pipeline.builds.find_by(name: 'job1')).to have_attributes(
- name: 'job1',
- stage: 'test',
- options: { script: ["echo 'hello job1 script'"] }
- )
- expect(pipeline.builds.find_by(name: 'job2')).to have_attributes(
- name: 'job2',
- stage: 'test',
- options: { script: ["echo 'hello job2 script'"] }
- )
- expect(pipeline.builds.find_by(name: 'job3')).to have_attributes(
- name: 'job3',
- stage: 'test',
- options: { script: ["echo 'hello job3 script'"] }
- )
- end
- end
end
end
diff --git a/spec/support/helpers/stub_object_storage.rb b/spec/support/helpers/stub_object_storage.rb
index c163ce1d880..6b633856228 100644
--- a/spec/support/helpers/stub_object_storage.rb
+++ b/spec/support/helpers/stub_object_storage.rb
@@ -15,7 +15,7 @@ module StubObjectStorage
direct_upload: false,
cdn: {}
)
-
+ old_config = Settingslogic.new(config.deep_stringify_keys)
new_config = config.to_h.deep_symbolize_keys.merge({
enabled: enabled,
proxy_download: proxy_download,
@@ -37,7 +37,7 @@ module StubObjectStorage
return unless enabled
stub_object_storage(connection_params: uploader.object_store_credentials,
- remote_directory: config.remote_directory)
+ remote_directory: old_config.remote_directory)
end
def stub_object_storage(connection_params:, remote_directory:)
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index 8d1e5e907c5..7b7b7da13e5 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -226,7 +226,6 @@
- './ee/spec/features/analytics/code_analytics_spec.rb'
- './ee/spec/features/analytics/group_analytics_spec.rb'
- './ee/spec/features/billings/billing_plans_spec.rb'
-- './ee/spec/features/billings/extend_reactivate_trial_spec.rb'
- './ee/spec/features/billings/qrtly_reconciliation_alert_spec.rb'
- './ee/spec/features/boards/board_filters_spec.rb'
- './ee/spec/features/boards/boards_licensed_features_spec.rb'