summaryrefslogtreecommitdiff
path: root/spec/support/shared_examples/models
diff options
context:
space:
mode:
Diffstat (limited to 'spec/support/shared_examples/models')
-rw-r--r--spec/support/shared_examples/models/application_setting_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/concerns/bulk_users_by_email_load_shared_examples.rb39
-rw-r--r--spec/support/shared_examples/models/concerns/from_set_operator_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/models/group_shared_examples.rb43
-rw-r--r--spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb61
-rw-r--r--spec/support/shared_examples/models/issuable_link_shared_examples.rb13
-rw-r--r--spec/support/shared_examples/models/member_shared_examples.rb60
-rw-r--r--spec/support/shared_examples/models/project_shared_examples.rb27
-rw-r--r--spec/support/shared_examples/models/wiki_shared_examples.rb140
10 files changed, 301 insertions, 94 deletions
diff --git a/spec/support/shared_examples/models/application_setting_shared_examples.rb b/spec/support/shared_examples/models/application_setting_shared_examples.rb
index 38f5c7be393..74ec6474e80 100644
--- a/spec/support/shared_examples/models/application_setting_shared_examples.rb
+++ b/spec/support/shared_examples/models/application_setting_shared_examples.rb
@@ -239,7 +239,7 @@ RSpec.shared_examples 'application settings examples' do
describe '#allowed_key_types' do
it 'includes all key types by default' do
- expect(setting.allowed_key_types).to contain_exactly(*described_class::SUPPORTED_KEY_TYPES)
+ expect(setting.allowed_key_types).to contain_exactly(*Gitlab::SSHPublicKey.supported_types)
end
it 'excludes disabled key types' do
diff --git a/spec/support/shared_examples/models/concerns/bulk_users_by_email_load_shared_examples.rb b/spec/support/shared_examples/models/concerns/bulk_users_by_email_load_shared_examples.rb
new file mode 100644
index 00000000000..c3e9ff5c91a
--- /dev/null
+++ b/spec/support/shared_examples/models/concerns/bulk_users_by_email_load_shared_examples.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'a BulkUsersByEmailLoad model' do
+ describe '#users_by_emails' do
+ let_it_be(:user1) { create(:user, emails: [create(:email, email: 'user1@example.com')]) }
+ let_it_be(:user2) { create(:user, emails: [create(:email, email: 'user2@example.com')]) }
+
+ subject(:model) { described_class.new(id: non_existing_record_id) }
+
+ context 'when nothing is loaded' do
+ let(:passed_emails) { [user1.emails.first.email, user2.email] }
+
+ it 'preforms the yielded query and supplies the data with only emails desired' do
+ expect(model.users_by_emails(passed_emails).keys).to contain_exactly(*passed_emails)
+ end
+ end
+
+ context 'when store is preloaded', :request_store do
+ let(:passed_emails) { [user1.emails.first.email, user2.email, user1.email] }
+ let(:resource_data) do
+ {
+ user1.emails.first.email => instance_double('User'),
+ user2.email => instance_double('User')
+ }
+ end
+
+ before do
+ Gitlab::SafeRequestStore["user_by_email_for_users:#{model.class.name}:#{model.id}"] = resource_data
+ end
+
+ it 'passes back loaded data and does not update the items that already exist' do
+ users_by_emails = model.users_by_emails(passed_emails)
+
+ expect(users_by_emails.keys).to contain_exactly(*passed_emails)
+ expect(users_by_emails).to include(resource_data.merge(user1.email => user1))
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/concerns/from_set_operator_shared_examples.rb b/spec/support/shared_examples/models/concerns/from_set_operator_shared_examples.rb
index 6b208c0024d..e625ba785d2 100644
--- a/spec/support/shared_examples/models/concerns/from_set_operator_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/from_set_operator_shared_examples.rb
@@ -20,6 +20,12 @@ RSpec.shared_examples 'from set operator' do |sql_klass|
expect(query.to_sql).to match(/FROM \(\(SELECT.+\)\n#{operator_keyword}\n\(SELECT.+\)\) users/m)
end
+ it "returns empty set when passing empty array" do
+ query = model.public_send(operator_method, [])
+
+ expect(query.to_sql).to match(/WHERE \(1=0\)/m)
+ end
+
it 'supports the use of a custom alias for the sub query' do
query = model.public_send(operator_method,
[model.where(id: 1), model.where(id: 2)],
diff --git a/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb b/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb
index d6415e98289..da5c35c970a 100644
--- a/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb
@@ -227,9 +227,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
end
context 'for confidential notes' do
- before_all do
- issue_note.update!(confidential: true)
- end
+ let_it_be(:issue_note) { create(:note_on_issue, project: project, note: "issue note", confidential: true) }
it 'falls back to note channel' do
expect(::Slack::Messenger).to execute_with_options(channel: ['random'])
diff --git a/spec/support/shared_examples/models/group_shared_examples.rb b/spec/support/shared_examples/models/group_shared_examples.rb
new file mode 100644
index 00000000000..9f3359ba4ab
--- /dev/null
+++ b/spec/support/shared_examples/models/group_shared_examples.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'checks self and root ancestor feature flag' do
+ let_it_be(:root_group) { create(:group) }
+ let_it_be(:group) { create(:group, parent: root_group) }
+ let_it_be(:project) { create(:project, group: group) }
+
+ subject { group.public_send(feature_flag_method) }
+
+ context 'when FF is enabled for the root group' do
+ before do
+ stub_feature_flags(feature_flag => root_group)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when FF is enabled for the group' do
+ before do
+ stub_feature_flags(feature_flag => group)
+ end
+
+ it { is_expected.to be_truthy }
+
+ context 'when root_group is the actor' do
+ it 'is not enabled if the FF is enabled for a child' do
+ expect(root_group.public_send(feature_flag_method)).to be_falsey
+ end
+ end
+ end
+
+ context 'when FF is disabled globally' do
+ before do
+ stub_feature_flags(feature_flag => false)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when FF is enabled globally' do
+ it { is_expected.to be_truthy }
+ end
+end
diff --git a/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb b/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb
deleted file mode 100644
index 13ffc1b7f87..00000000000
--- a/spec/support/shared_examples/models/issuable_hook_data_shared_examples.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-
-# This shared example requires a `builder` and `user` variable
-RSpec.shared_examples 'issuable hook data' do |kind|
- let(:data) { builder.build(user: user) }
-
- include_examples 'project hook data' do
- let(:project) { builder.issuable.project }
- end
-
- include_examples 'deprecated repository hook data'
-
- context "with a #{kind}" do
- it 'contains issuable data' do
- expect(data[:object_kind]).to eq(kind)
- expect(data[:user]).to eq(user.hook_attrs)
- expect(data[:project]).to eq(builder.issuable.project.hook_attrs)
- expect(data[:object_attributes]).to eq(builder.issuable.hook_attrs)
- expect(data[:changes]).to eq({})
- expect(data[:repository]).to eq(builder.issuable.project.hook_attrs.slice(:name, :url, :description, :homepage))
- end
-
- it 'does not contain certain keys' do
- expect(data).not_to have_key(:assignees)
- expect(data).not_to have_key(:assignee)
- end
-
- describe 'changes are given' do
- let(:changes) do
- {
- cached_markdown_version: %w[foo bar],
- description: ['A description', 'A cool description'],
- description_html: %w[foo bar],
- in_progress_merge_commit_sha: %w[foo bar],
- lock_version: %w[foo bar],
- merge_jid: %w[foo bar],
- title: ['A title', 'Hello World'],
- title_html: %w[foo bar]
- }
- end
-
- let(:data) { builder.build(user: user, changes: changes) }
-
- it 'populates the :changes hash' do
- expect(data[:changes]).to match(hash_including({
- title: { previous: 'A title', current: 'Hello World' },
- description: { previous: 'A description', current: 'A cool description' }
- }))
- end
-
- it 'does not contain certain keys' do
- expect(data[:changes]).not_to have_key('cached_markdown_version')
- expect(data[:changes]).not_to have_key('description_html')
- expect(data[:changes]).not_to have_key('lock_version')
- expect(data[:changes]).not_to have_key('title_html')
- expect(data[:changes]).not_to have_key('in_progress_merge_commit_sha')
- expect(data[:changes]).not_to have_key('merge_jid')
- end
- end
- end
-end
diff --git a/spec/support/shared_examples/models/issuable_link_shared_examples.rb b/spec/support/shared_examples/models/issuable_link_shared_examples.rb
index ca98c2597a2..9892e66b582 100644
--- a/spec/support/shared_examples/models/issuable_link_shared_examples.rb
+++ b/spec/support/shared_examples/models/issuable_link_shared_examples.rb
@@ -55,6 +55,19 @@ RSpec.shared_examples 'issuable link' do
end
end
+ describe 'scopes' do
+ describe '.for_source_or_target' do
+ it 'returns only links where id is either source or target id' do
+ link1 = create(issuable_link_factory, source: issuable_link.source)
+ link2 = create(issuable_link_factory, target: issuable_link.source)
+ # unrelated link, should not be included in result list
+ create(issuable_link_factory) # rubocop: disable Rails/SaveBang
+
+ expect(described_class.for_source_or_target(issuable_link.source_id)).to match_array([issuable_link, link1, link2])
+ end
+ end
+ end
+
describe '.link_type' do
it { is_expected.to define_enum_for(:link_type).with_values(relates_to: 0, blocks: 1) }
diff --git a/spec/support/shared_examples/models/member_shared_examples.rb b/spec/support/shared_examples/models/member_shared_examples.rb
index 17026f085bb..a329a6dca91 100644
--- a/spec/support/shared_examples/models/member_shared_examples.rb
+++ b/spec/support/shared_examples/models/member_shared_examples.rb
@@ -88,19 +88,55 @@ RSpec.shared_examples_for "member creation" do
expect(member).to be_persisted
end
- context 'when admin mode is enabled', :enable_admin_mode do
+ context 'when adding a project_bot' do
+ let_it_be(:project_bot) { create(:user, :project_bot) }
+
+ before_all do
+ source.add_owner(user)
+ end
+
+ context 'when project_bot is already a member' do
+ before do
+ source.add_developer(project_bot)
+ end
+
+ it 'does not update the member' do
+ member = described_class.new(source, project_bot, :maintainer, current_user: user).execute
+
+ expect(source.users.reload).to include(project_bot)
+ expect(member).to be_persisted
+ expect(member.access_level).to eq(Gitlab::Access::DEVELOPER)
+ expect(member.errors.full_messages).to include(/not authorized to update member/)
+ end
+ end
+
+ context 'when project_bot is not already a member' do
+ it 'adds the member' do
+ member = described_class.new(source, project_bot, :maintainer, current_user: user).execute
+
+ expect(source.users.reload).to include(project_bot)
+ expect(member).to be_persisted
+ end
+ end
+ end
+
+ context 'when admin mode is enabled', :enable_admin_mode, :aggregate_failures do
it 'sets members.created_by to the given admin current_user' do
member = described_class.new(source, user, :maintainer, current_user: admin).execute
+ expect(member).to be_persisted
+ expect(source.users.reload).to include(user)
expect(member.created_by).to eq(admin)
end
end
context 'when admin mode is disabled' do
- it 'rejects setting members.created_by to the given admin current_user' do
+ it 'rejects setting members.created_by to the given admin current_user', :aggregate_failures do
member = described_class.new(source, user, :maintainer, current_user: admin).execute
- expect(member.created_by).to be_nil
+ expect(member).not_to be_persisted
+ expect(source.users.reload).not_to include(user)
+ expect(member.errors.full_messages).to include(/not authorized to create member/)
end
end
@@ -142,7 +178,7 @@ RSpec.shared_examples_for "member creation" do
end
context 'when called with an unknown user id' do
- it 'adds the user as a member' do
+ it 'does not add the user as a member' do
expect(source.users).not_to include(user)
described_class.new(source, non_existing_record_id, :maintainer).execute
@@ -410,6 +446,22 @@ RSpec.shared_examples_for "bulk member creation" do
end
end
+ it 'with the same user sent more than once by user and by email' do
+ members = described_class.add_users(source, [user1, user1.email], :maintainer)
+
+ expect(members.map(&:user)).to contain_exactly(user1)
+ expect(members).to all(be_a(member_type))
+ expect(members).to all(be_persisted)
+ end
+
+ it 'with the same user sent more than once by user id and by email' do
+ members = described_class.add_users(source, [user1.id, user1.email], :maintainer)
+
+ expect(members.map(&:user)).to contain_exactly(user1)
+ expect(members).to all(be_a(member_type))
+ expect(members).to all(be_persisted)
+ end
+
context 'when a member already exists' do
before do
source.add_user(user1, :developer)
diff --git a/spec/support/shared_examples/models/project_shared_examples.rb b/spec/support/shared_examples/models/project_shared_examples.rb
new file mode 100644
index 00000000000..475ac1da04b
--- /dev/null
+++ b/spec/support/shared_examples/models/project_shared_examples.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'returns true if project is inactive' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:storage_size, :last_activity_at, :expected_result) do
+ 1.megabyte | 1.month.ago | false
+ 1.megabyte | 3.years.ago | false
+ 8.megabytes | 1.month.ago | false
+ 8.megabytes | 3.years.ago | true
+ end
+
+ with_them do
+ before do
+ stub_application_setting(inactive_projects_min_size_mb: 5)
+ stub_application_setting(inactive_projects_send_warning_email_after_months: 24)
+
+ project.statistics.storage_size = storage_size
+ project.last_activity_at = last_activity_at
+ project.save!
+ end
+
+ it 'returns expected result' do
+ expect(project.inactive?).to eq(expected_result)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/wiki_shared_examples.rb b/spec/support/shared_examples/models/wiki_shared_examples.rb
index b3f79d9fe6e..03e9dd65e33 100644
--- a/spec/support/shared_examples/models/wiki_shared_examples.rb
+++ b/spec/support/shared_examples/models/wiki_shared_examples.rb
@@ -11,6 +11,10 @@ RSpec.shared_examples 'wiki model' do
subject { wiki }
+ it 'VALID_USER_MARKUPS contains all valid markups' do
+ expect(described_class::VALID_USER_MARKUPS.keys).to match_array(%i(markdown rdoc asciidoc org))
+ end
+
it 'container class includes HasWiki' do
# NOTE: This is not enforced at runtime, since we also need to support Geo::DeletedProject
expect(wiki_container).to be_kind_of(HasWiki)
@@ -427,45 +431,131 @@ RSpec.shared_examples 'wiki model' do
end
describe '#update_page' do
- let(:page) { create(:wiki_page, wiki: subject, title: 'update-page') }
+ shared_examples 'update_page tests' do
+ with_them do
+ let!(:page) { create(:wiki_page, wiki: subject, title: original_title, format: original_format, content: 'original content') }
+
+ let(:message) { 'updated page' }
+ let(:updated_content) { 'updated content' }
+
+ def update_page
+ subject.update_page(
+ page.page,
+ content: updated_content,
+ title: updated_title,
+ format: updated_format,
+ message: message
+ )
+ end
+
+ specify :aggregate_failures do
+ expect(subject).to receive(:after_wiki_activity)
+ expect(update_page).to eq true
+
+ page = subject.find_page(updated_title.presence || original_title)
- def update_page
- subject.update_page(
- page.page,
- content: 'some other content',
- format: :markdown,
- message: 'updated page'
- )
+ expect(page.raw_content).to eq(updated_content)
+ expect(page.path).to eq(expected_path)
+ expect(page.version.message).to eq(message)
+ expect(user.commit_email).not_to eq(user.email)
+ expect(commit.author_email).to eq(user.commit_email)
+ expect(commit.committer_email).to eq(user.commit_email)
+ end
+ end
end
- it 'updates the content of the page' do
- update_page
- page = subject.find_page('update-page')
+ shared_context 'common examples' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:original_title, :original_format, :updated_title, :updated_format, :expected_path) do
+ 'test page' | :markdown | 'new test page' | :markdown | 'new-test-page.md'
+ 'test page' | :markdown | 'test page' | :markdown | 'test-page.md'
+ 'test page' | :markdown | 'test page' | :asciidoc | 'test-page.asciidoc'
+
+ 'test page' | :markdown | 'new dir/new test page' | :markdown | 'new-dir/new-test-page.md'
+ 'test page' | :markdown | 'new dir/test page' | :markdown | 'new-dir/test-page.md'
- expect(page.raw_content).to eq('some other content')
+ 'test dir/test page' | :markdown | 'new dir/new test page' | :markdown | 'new-dir/new-test-page.md'
+ 'test dir/test page' | :markdown | 'test dir/test page' | :markdown | 'test-dir/test-page.md'
+ 'test dir/test page' | :markdown | 'test dir/test page' | :asciidoc | 'test-dir/test-page.asciidoc'
+
+ 'test dir/test page' | :markdown | 'new test page' | :markdown | 'new-test-page.md'
+ 'test dir/test page' | :markdown | 'test page' | :markdown | 'test-page.md'
+
+ 'test page' | :markdown | nil | :markdown | 'test-page.md'
+ 'test.page' | :markdown | nil | :markdown | 'test.page.md'
+ end
end
- it 'sets the correct commit message' do
- update_page
- page = subject.find_page('update-page')
+ # There are two bugs in Gollum. THe first one is when the title and the format are updated
+ # at the same time https://gitlab.com/gitlab-org/gitlab/-/issues/243519.
+ # The second one is when the wiki page is within a dir and the `title` argument
+ # we pass to the update method is `nil`. Gollum will remove the dir and move the page.
+ #
+ # We can include this context into the former once it is fixed
+ # or when Gollum is removed since the Gitaly approach already fixes it.
+ shared_context 'extended examples' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:original_title, :original_format, :updated_title, :updated_format, :expected_path) do
+ 'test page' | :markdown | 'new test page' | :asciidoc | 'new-test-page.asciidoc'
+ 'test page' | :markdown | 'new dir/new test page' | :asciidoc | 'new-dir/new-test-page.asciidoc'
+ 'test dir/test page' | :markdown | 'new dir/new test page' | :asciidoc | 'new-dir/new-test-page.asciidoc'
+ 'test dir/test page' | :markdown | 'new test page' | :asciidoc | 'new-test-page.asciidoc'
+ 'test page' | :markdown | nil | :asciidoc | 'test-page.asciidoc'
+ 'test dir/test page' | :markdown | nil | :asciidoc | 'test-dir/test-page.asciidoc'
+ 'test dir/test page' | :markdown | nil | :markdown | 'test-dir/test-page.md'
+ 'test page' | :markdown | '' | :markdown | 'test-page.md'
+ 'test.page' | :markdown | '' | :markdown | 'test.page.md'
+ end
+ end
- expect(page.version.message).to eq('updated page')
+ it_behaves_like 'update_page tests' do
+ include_context 'common examples'
+ include_context 'extended examples'
end
- it 'sets the correct commit email' do
- update_page
+ context 'when format is invalid' do
+ let!(:page) { create(:wiki_page, wiki: subject, title: 'test page') }
- expect(user.commit_email).not_to eq(user.email)
- expect(commit.author_email).to eq(user.commit_email)
- expect(commit.committer_email).to eq(user.commit_email)
+ it 'returns false and sets error message' do
+ expect(subject.update_page(page.page, content: 'new content', format: :foobar)).to eq false
+ expect(subject.error_message).to match(/Invalid format selected/)
+ end
end
- it 'runs after_wiki_activity callbacks' do
- page
+ context 'when format is not allowed' do
+ let!(:page) { create(:wiki_page, wiki: subject, title: 'test page') }
- expect(subject).to receive(:after_wiki_activity)
+ it 'returns false and sets error message' do
+ expect(subject.update_page(page.page, content: 'new content', format: :creole)).to eq false
+ expect(subject.error_message).to match(/Invalid format selected/)
+ end
+ end
+
+ context 'when page path does not have a default extension' do
+ let!(:page) { create(:wiki_page, wiki: subject, title: 'test page') }
+
+ context 'when format is not different' do
+ it 'does not change the default extension' do
+ path = 'test-page.markdown'
+ page.page.instance_variable_set(:@path, path)
- update_page
+ expect(subject.repository).to receive(:update_file).with(user, path, anything, anything)
+
+ subject.update_page(page.page, content: 'new content', format: :markdown)
+ end
+ end
+ end
+
+ context 'when feature flag :gitaly_replace_wiki_update_page is disabled' do
+ before do
+ stub_feature_flags(gitaly_replace_wiki_update_page: false)
+ end
+
+ it_behaves_like 'update_page tests' do
+ include_context 'common examples'
+ end
end
end