diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-04 18:08:40 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-02-04 18:08:40 +0300 |
commit | 6b833f1e0340e00fdee074da9c42c0d4e07a46d2 (patch) | |
tree | 6fc3a7a2f8a02fec8d1e7561b453d33eb4048dad /spec | |
parent | 88a0824944720b6edaaef56376713541b9a02118 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
12 files changed, 427 insertions, 145 deletions
diff --git a/spec/frontend/diffs/components/diff_stats_spec.js b/spec/frontend/diffs/components/diff_stats_spec.js index 9073462a51f..0dffc74f608 100644 --- a/spec/frontend/diffs/components/diff_stats_spec.js +++ b/spec/frontend/diffs/components/diff_stats_spec.js @@ -3,6 +3,18 @@ import Icon from '~/vue_shared/components/icon.vue'; import DiffStats from '~/diffs/components/diff_stats.vue'; describe('diff_stats', () => { + it('does not render a group if diffFileLengths is empty', () => { + const wrapper = shallowMount(DiffStats, { + propsData: { + addedLines: 1, + removedLines: 2, + }, + }); + const groups = wrapper.findAll('.diff-stats-group'); + + expect(groups.length).toBe(2); + }); + it('does not render a group if diffFileLengths is not a number', () => { const wrapper = shallowMount(DiffStats, { propsData: { diff --git a/spec/frontend/error_tracking/components/error_details_spec.js b/spec/frontend/error_tracking/components/error_details_spec.js index 1e1d20800da..cfb9ce51979 100644 --- a/spec/frontend/error_tracking/components/error_details_spec.js +++ b/spec/frontend/error_tracking/components/error_details_spec.js @@ -1,7 +1,7 @@ import { createLocalVue, shallowMount } from '@vue/test-utils'; import Vuex from 'vuex'; import { __ } from '~/locale'; -import { GlLoadingIcon, GlLink, GlBadge, GlFormInput } from '@gitlab/ui'; +import { GlLoadingIcon, GlLink, GlBadge, GlFormInput, GlAlert, GlSprintf } from '@gitlab/ui'; import LoadingButton from '~/vue_shared/components/loading_button.vue'; import Stacktrace from '~/error_tracking/components/stacktrace.vue'; import ErrorDetails from '~/error_tracking/components/error_details.vue'; @@ -28,7 +28,7 @@ describe('ErrorDetails', () => { function mountComponent() { wrapper = shallowMount(ErrorDetails, { - stubs: { LoadingButton }, + stubs: { LoadingButton, GlSprintf }, localVue, store, mocks, @@ -62,7 +62,7 @@ describe('ErrorDetails', () => { startPollingDetails: () => {}, startPollingStacktrace: () => {}, updateIgnoreStatus: jest.fn(), - updateResolveStatus: jest.fn(), + updateResolveStatus: jest.fn().mockResolvedValue({ closed_issue_iid: 1 }), }; getters = { @@ -313,6 +313,20 @@ describe('ErrorDetails', () => { expect.objectContaining({ status: errorStatus.UNRESOLVED }), ); }); + + it('should show alert with closed issueId', () => { + const findAlert = () => wrapper.find(GlAlert); + const closedIssueId = 123; + wrapper.setData({ + isAlertVisible: true, + closedIssueId, + }); + + return wrapper.vm.$nextTick().then(() => { + expect(findAlert().exists()).toBe(true); + expect(findAlert().text()).toContain(`#${closedIssueId}`); + }); + }); }); }); diff --git a/spec/frontend/pages/admin/users/components/__snapshots__/user_operation_confirmation_modal_spec.js.snap b/spec/frontend/pages/admin/users/components/__snapshots__/user_operation_confirmation_modal_spec.js.snap index 4b4e9997953..dbf8caae357 100644 --- a/spec/frontend/pages/admin/users/components/__snapshots__/user_operation_confirmation_modal_spec.js.snap +++ b/spec/frontend/pages/admin/users/components/__snapshots__/user_operation_confirmation_modal_spec.js.snap @@ -6,6 +6,7 @@ exports[`User Operation confirmation modal renders modal with form included 1`] modalid="user-operation-modal" ok-title="action" ok-variant="warning" + size="md" title="title" titletag="h4" > diff --git a/spec/frontend/self_monitor/components/__snapshots__/self_monitor_spec.js.snap b/spec/frontend/self_monitor/components/__snapshots__/self_monitor_spec.js.snap index b1644ac2b1f..d5546021430 100644 --- a/spec/frontend/self_monitor/components/__snapshots__/self_monitor_spec.js.snap +++ b/spec/frontend/self_monitor/components/__snapshots__/self_monitor_spec.js.snap @@ -61,6 +61,7 @@ exports[`self monitor component When the self monitor project has not been creat modalid="delete-self-monitor-modal" ok-title="Delete project" ok-variant="danger" + size="md" title="Disable self monitoring?" titletag="h4" > diff --git a/spec/lib/gitlab/diff/formatters/image_formatter_spec.rb b/spec/lib/gitlab/diff/formatters/image_formatter_spec.rb index 2e6eb71d37d..edf30ffc56f 100644 --- a/spec/lib/gitlab/diff/formatters/image_formatter_spec.rb +++ b/spec/lib/gitlab/diff/formatters/image_formatter_spec.rb @@ -3,20 +3,34 @@ require 'spec_helper' describe Gitlab::Diff::Formatters::ImageFormatter do - it_behaves_like "position formatter" do - let(:base_attrs) do - { - base_sha: 123, - start_sha: 456, - head_sha: 789, - old_path: 'old_image.png', - new_path: 'new_image.png', - position_type: 'image' - } - end + let(:base_attrs) do + { + base_sha: 123, + start_sha: 456, + head_sha: 789, + old_path: 'old_image.png', + new_path: 'new_image.png', + position_type: 'image' + } + end + + let(:attrs) do + base_attrs.merge(width: 100, height: 100, x: 1, y: 2) + end + + it_behaves_like 'position formatter' + + describe '#==' do + subject { described_class.new(attrs) } + + it { is_expected.to eq(subject) } + + [:width, :height, :x, :y].each do |attr| + let(:other_formatter) do + described_class.new(attrs.merge(attr => 9)) + end - let(:attrs) do - base_attrs.merge(width: 100, height: 100, x: 1, y: 2) + it { is_expected.not_to eq(other_formatter) } end end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index df32545b90b..7decc1bc911 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -106,6 +106,14 @@ describe Project do it { is_expected.to have_many(:sourced_pipelines) } it { is_expected.to have_many(:source_pipelines) } + it_behaves_like 'model with repository' do + let_it_be(:container) { create(:project, :repository, path: 'somewhere') } + let(:stubbed_container) { build_stubbed(:project) } + let(:expected_full_path) { "#{container.namespace.full_path}/somewhere" } + let(:expected_repository_klass) { Repository } + let(:expected_storage_klass) { Storage::Hashed } + end + it 'has an inverse relationship with merge requests' do expect(described_class.reflect_on_association(:merge_requests).has_inverse?).to eq(:target_project) end @@ -510,7 +518,6 @@ describe Project do describe 'Respond to' do it { is_expected.to respond_to(:url_to_repo) } - it { is_expected.to respond_to(:repo_exists?) } it { is_expected.to respond_to(:execute_hooks) } it { is_expected.to respond_to(:owner) } it { is_expected.to respond_to(:path_with_namespace) } @@ -664,44 +671,6 @@ describe Project do expect(project.url_to_repo).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + 'somewhere.git') end - describe "#web_url" do - let(:project) { create(:project, path: "somewhere") } - - context 'when given the only_path option' do - subject { project.web_url(only_path: only_path) } - - context 'when only_path is false' do - let(:only_path) { false } - - it 'returns the full web URL for this repo' do - expect(subject).to eq("#{Gitlab.config.gitlab.url}/#{project.namespace.full_path}/somewhere") - end - end - - context 'when only_path is true' do - let(:only_path) { true } - - it 'returns the relative web URL for this repo' do - expect(subject).to eq("/#{project.namespace.full_path}/somewhere") - end - end - - context 'when only_path is nil' do - let(:only_path) { nil } - - it 'returns the full web URL for this repo' do - expect(subject).to eq("#{Gitlab.config.gitlab.url}/#{project.namespace.full_path}/somewhere") - end - end - end - - context 'when not given the only_path option' do - it 'returns the full web URL for this repo' do - expect(project.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.namespace.full_path}/somewhere") - end - end - end - describe "#readme_url" do context 'with a non-existing repository' do let(:project) { create(:project) } @@ -931,14 +900,6 @@ describe Project do end end - describe '#repository' do - let(:project) { create(:project, :repository) } - - it 'returns valid repo' do - expect(project.repository).to be_kind_of(Repository) - end - end - describe '#default_issues_tracker?' do it "is true if used internal tracker" do project = build(:project) @@ -954,24 +915,6 @@ describe Project do end end - describe '#empty_repo?' do - context 'when the repo does not exist' do - let(:project) { build_stubbed(:project) } - - it 'returns true' do - expect(project.empty_repo?).to be(true) - end - end - - context 'when the repo exists' do - let(:project) { create(:project, :repository) } - let(:empty_project) { create(:project, :empty_repo) } - - it { expect(empty_project.empty_repo?).to be(true) } - it { expect(project.empty_repo?).to be(false) } - end - end - describe '#external_issue_tracker' do let(:project) { create(:project) } let(:ext_project) { create(:redmine_project) } @@ -3406,59 +3349,6 @@ describe Project do end end - describe '#http_url_to_repo' do - let(:project) { create(:project) } - - context 'when a custom HTTP clone URL root is not set' do - it 'returns the url to the repo without a username' do - expect(project.http_url_to_repo).to eq("#{project.web_url}.git") - expect(project.http_url_to_repo).not_to include('@') - end - end - - context 'when a custom HTTP clone URL root is set' do - before do - stub_application_setting(custom_http_clone_url_root: custom_http_clone_url_root) - end - - context 'when custom HTTP clone URL root has a relative URL root' do - context 'when custom HTTP clone URL root ends with a slash' do - let(:custom_http_clone_url_root) { 'https://git.example.com:51234/mygitlab/' } - - it 'returns the url to the repo, with the root replaced with the custom one' do - expect(project.http_url_to_repo).to eq("https://git.example.com:51234/mygitlab/#{project.full_path}.git") - end - end - - context 'when custom HTTP clone URL root does not end with a slash' do - let(:custom_http_clone_url_root) { 'https://git.example.com:51234/mygitlab' } - - it 'returns the url to the repo, with the root replaced with the custom one' do - expect(project.http_url_to_repo).to eq("https://git.example.com:51234/mygitlab/#{project.full_path}.git") - end - end - end - - context 'when custom HTTP clone URL root does not have a relative URL root' do - context 'when custom HTTP clone URL root ends with a slash' do - let(:custom_http_clone_url_root) { 'https://git.example.com:51234/' } - - it 'returns the url to the repo, with the root replaced with the custom one' do - expect(project.http_url_to_repo).to eq("https://git.example.com:51234/#{project.full_path}.git") - end - end - - context 'when custom HTTP clone URL root does not end with a slash' do - let(:custom_http_clone_url_root) { 'https://git.example.com:51234' } - - it 'returns the url to the repo, with the root replaced with the custom one' do - expect(project.http_url_to_repo).to eq("https://git.example.com:51234/#{project.full_path}.git") - end - end - end - end - end - describe '#lfs_http_url_to_repo' do let(:project) { create(:project) } @@ -5054,16 +4944,6 @@ describe Project do end end - context '#commits_by' do - let(:project) { create(:project, :repository) } - let(:commits) { project.repository.commits('HEAD', limit: 3).commits } - let(:commit_shas) { commits.map(&:id) } - - it 'retrieves several commits from the repository by oid' do - expect(project.commits_by(oids: commit_shas)).to eq commits - end - end - context '#members_among' do let(:users) { create_list(:user, 3) } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 42151d86ac0..610b3e47c11 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -4084,4 +4084,46 @@ describe User, :do_not_mock_admin_mode do end end end + + describe '#read_only_attribute?' do + context 'when LDAP server is enabled' do + before do + allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(true) + end + + %i[name email location].each do |attribute| + it "is true for #{attribute}" do + expect(subject.read_only_attribute?(attribute)).to be_truthy + end + end + + context 'and ldap_readonly_attributes feature is disabled' do + before do + stub_feature_flags(ldap_readonly_attributes: false) + end + + %i[name email location].each do |attribute| + it "is false" do + expect(subject.read_only_attribute?(attribute)).to be_falsey + end + end + end + end + + context 'when synced attributes metadata is present' do + it 'delegates to synced_attributes_metadata' do + subject.build_user_synced_attributes_metadata + + expect(subject.build_user_synced_attributes_metadata) + .to receive(:read_only?).with(:email).and_return('return-value') + expect(subject.read_only_attribute?(:email)).to eq('return-value') + end + end + + context 'when synced attributes metadata is present' do + it 'is false for any attribute' do + expect(subject.read_only_attribute?(:email)).to be_falsey + end + end + end end diff --git a/spec/rubocop/cop/scalability/bulk_perform_with_context_spec.rb b/spec/rubocop/cop/scalability/bulk_perform_with_context_spec.rb new file mode 100644 index 00000000000..8107cfa8957 --- /dev/null +++ b/spec/rubocop/cop/scalability/bulk_perform_with_context_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require 'rubocop' +require_relative '../../../support/helpers/expect_offense' +require_relative '../../../../rubocop/cop/scalability/bulk_perform_with_context' + +describe RuboCop::Cop::Scalability::BulkPerformWithContext do + include CopHelper + include ExpectOffense + + subject(:cop) { described_class.new } + + it "adds an offense when calling bulk_perform_async" do + inspect_source(<<~CODE.strip_indent) + Worker.bulk_perform_async(args) + CODE + + expect(cop.offenses.size).to eq(1) + end + + it "adds an offense when calling bulk_perform_in" do + inspect_source(<<~CODE.strip_indent) + diffs.each_batch(of: BATCH_SIZE) do |relation, index| + ids = relation.pluck_primary_key.map { |id| [id] } + DeleteDiffFilesWorker.bulk_perform_in(index * 5.minutes, ids) + end + CODE + + expect(cop.offenses.size).to eq(1) + end + + it "does not add an offense for migrations" do + allow(cop).to receive(:in_migration?).and_return(true) + + inspect_source(<<~CODE.strip_indent) + Worker.bulk_perform_in(args) + CODE + + expect(cop.offenses.size).to eq(0) + end + + it "does not add an offence for specs" do + allow(cop).to receive(:in_spec?).and_return(true) + + inspect_source(<<~CODE.strip_indent) + Worker.bulk_perform_in(args) + CODE + + expect(cop.offenses.size).to eq(0) + end + + it "does not add an offense for scheduling BackgroundMigrations" do + inspect_source(<<~CODE.strip_indent) + BackgroundMigrationWorker.bulk_perform_in(args) + CODE + + expect(cop.offenses.size).to eq(0) + end +end diff --git a/spec/rubocop/cop/scalability/cron_worker_context_spec.rb b/spec/rubocop/cop/scalability/cron_worker_context_spec.rb new file mode 100644 index 00000000000..bf10b8dc02c --- /dev/null +++ b/spec/rubocop/cop/scalability/cron_worker_context_spec.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require 'rubocop' +require_relative '../../../support/helpers/expect_offense' +require_relative '../../../../rubocop/cop/scalability/cron_worker_context' + +describe RuboCop::Cop::Scalability::CronWorkerContext do + include CopHelper + include ExpectOffense + + subject(:cop) { described_class.new } + + it 'adds an offense when including CronjobQueue' do + inspect_source(<<~CODE.strip_indent) + class SomeWorker + include CronjobQueue + end + CODE + + expect(cop.offenses.size).to eq(1) + end + + it 'does not add offenses for other workers' do + expect_no_offenses(<<~CODE.strip_indent) + class SomeWorker + end + CODE + end + + it 'does not add an offense when the class defines a context' do + expect_no_offenses(<<~CODE.strip_indent) + class SomeWorker + include CronjobQueue + + with_context user: 'bla' + end + CODE + end + + it 'does not add an offense when the worker calls `with_context`' do + expect_no_offenses(<<~CODE.strip_indent) + class SomeWorker + include CronjobQueue + + def perform + with_context(user: 'bla') do + # more work + end + end + end + CODE + end + + it 'does not add an offense when the worker calls `bulk_perform_async_with_contexts`' do + expect_no_offenses(<<~CODE.strip_indent) + class SomeWorker + include CronjobQueue + + def perform + SomeOtherWorker.bulk_perform_async_with_contexts(contexts_for_arguments) + end + end + CODE + end + + it 'does not add an offense when the worker calls `bulk_perform_in_with_contexts`' do + expect_no_offenses(<<~CODE.strip_indent) + class SomeWorker + include CronjobQueue + + def perform + SomeOtherWorker.bulk_perform_in_with_contexts(contexts_for_arguments) + end + end + CODE + end +end diff --git a/spec/services/users/update_service_spec.rb b/spec/services/users/update_service_spec.rb index 50bbb16e368..5cd6283ca96 100644 --- a/spec/services/users/update_service_spec.rb +++ b/spec/services/users/update_service_spec.rb @@ -55,6 +55,15 @@ describe Users::UpdateService do expect(result[:message]).to eq("Emoji is not included in the list") end + it 'ignores read-only attributes' do + allow(user).to receive(:read_only_attribute?).with(:name).and_return(true) + + expect do + update_user(user, name: 'changed' + user.name) + user.reload + end.not_to change { user.name } + end + def update_user(user, opts) described_class.new(user, opts.merge(user: user)).execute end diff --git a/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb b/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb new file mode 100644 index 00000000000..fdea312dfa9 --- /dev/null +++ b/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb @@ -0,0 +1,171 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'model with repository' do + describe '#commits_by' do + let(:commits) { container.repository.commits('HEAD', limit: 3).commits } + let(:commit_shas) { commits.map(&:id) } + + it 'retrieves several commits from the repository by oid' do + expect(container.commits_by(oids: commit_shas)).to eq commits + end + end + + describe "#web_url" do + context 'when given the only_path option' do + subject { container.web_url(only_path: only_path) } + + context 'when only_path is false' do + let(:only_path) { false } + + it 'returns the full web URL for this repo' do + expect(subject).to eq("#{Gitlab.config.gitlab.url}/#{expected_full_path}") + end + end + + context 'when only_path is true' do + let(:only_path) { true } + + it 'returns the relative web URL for this repo' do + expect(subject).to eq("/#{expected_full_path}") + end + end + + context 'when only_path is nil' do + let(:only_path) { nil } + + it 'returns the full web URL for this repo' do + expect(subject).to eq("#{Gitlab.config.gitlab.url}/#{expected_full_path}") + end + end + end + + context 'when not given the only_path option' do + it 'returns the full web URL for this repo' do + expect(container.web_url).to eq("#{Gitlab.config.gitlab.url}/#{expected_full_path}") + end + end + end + + describe '#ssh_url_to_repo' do + it 'returns container ssh address' do + expect(container.ssh_url_to_repo).to eq container.url_to_repo + end + end + + describe '#http_url_to_repo' do + subject { container.http_url_to_repo } + + context 'when a custom HTTP clone URL root is not set' do + it 'returns the url to the repo without a username' do + expect(subject).to eq("#{container.web_url}.git") + expect(subject).not_to include('@') + end + end + + context 'when a custom HTTP clone URL root is set' do + before do + stub_application_setting(custom_http_clone_url_root: custom_http_clone_url_root) + end + + context 'when custom HTTP clone URL root has a relative URL root' do + context 'when custom HTTP clone URL root ends with a slash' do + let(:custom_http_clone_url_root) { 'https://git.example.com:51234/mygitlab/' } + + it 'returns the url to the repo, with the root replaced with the custom one' do + expect(subject).to eq("#{custom_http_clone_url_root}#{expected_full_path}.git") + end + end + + context 'when custom HTTP clone URL root does not end with a slash' do + let(:custom_http_clone_url_root) { 'https://git.example.com:51234/mygitlab' } + + it 'returns the url to the repo, with the root replaced with the custom one' do + expect(subject).to eq("#{custom_http_clone_url_root}/#{expected_full_path}.git") + end + end + end + + context 'when custom HTTP clone URL root does not have a relative URL root' do + context 'when custom HTTP clone URL root ends with a slash' do + let(:custom_http_clone_url_root) { 'https://git.example.com:51234/' } + + it 'returns the url to the repo, with the root replaced with the custom one' do + expect(subject).to eq("#{custom_http_clone_url_root}#{expected_full_path}.git") + end + end + + context 'when custom HTTP clone URL root does not end with a slash' do + let(:custom_http_clone_url_root) { 'https://git.example.com:51234' } + + it 'returns the url to the repo, with the root replaced with the custom one' do + expect(subject).to eq("#{custom_http_clone_url_root}/#{expected_full_path}.git") + end + end + end + end + end + + describe '#repository' do + it 'returns valid repo' do + expect(container.repository).to be_kind_of(expected_repository_klass) + end + end + + describe '#storage' do + it 'returns valid storage' do + expect(container.storage).to be_kind_of(expected_storage_klass) + end + end + + describe '#full_path' do + it 'returns valid full_path' do + expect(container.full_path).to eq(expected_full_path) + end + end + + describe '#empty_repo?' do + context 'when the repo does not exist' do + it 'returns true' do + expect(stubbed_container.empty_repo?).to be(true) + end + end + + context 'when the repo exists' do + it { expect(container.empty_repo?).to be(false) } + + it 'returns true when repository is empty' do + allow(container.repository).to receive(:empty?).and_return(true) + + expect(container.empty_repo?).to be(true) + end + end + end + + describe '#valid_repo?' do + it { expect(stubbed_container.valid_repo?).to be(false)} + it { expect(container.valid_repo?).to be(true) } + end + + describe '#repository_exists?' do + it { expect(stubbed_container.repository_exists?).to be(false)} + it { expect(container.repository_exists?).to be(true) } + end + + describe '#repo_exists?' do + it { expect(stubbed_container.repo_exists?).to be(false)} + it { expect(container.repo_exists?).to be(true) } + end + + describe '#root_ref' do + let(:root_ref) { container.repository.root_ref } + + it { expect(container.root_ref?(root_ref)).to be(true) } + it { expect(container.root_ref?('HEAD')).to be(false) } + it { expect(container.root_ref?('foo')).to be(false) } + end + + describe 'Respond to' do + it { is_expected.to respond_to(:base_dir) } + it { is_expected.to respond_to(:disk_path) } + end +end diff --git a/spec/workers/concerns/cronjob_queue_spec.rb b/spec/workers/concerns/cronjob_queue_spec.rb index 21483d0e4e3..ea3b7bad2e1 100644 --- a/spec/workers/concerns/cronjob_queue_spec.rb +++ b/spec/workers/concerns/cronjob_queue_spec.rb @@ -10,7 +10,7 @@ describe CronjobQueue do end include ApplicationWorker - include CronjobQueue + include CronjobQueue # rubocop:disable Scalability/CronWorkerContext end end |