diff options
Diffstat (limited to 'spec/lib')
47 files changed, 897 insertions, 245 deletions
diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb index 68643effb66..5a7858e77f3 100644 --- a/spec/lib/banzai/filter/redactor_filter_spec.rb +++ b/spec/lib/banzai/filter/redactor_filter_spec.rb @@ -46,7 +46,7 @@ describe Banzai::Filter::RedactorFilter do it 'allows permitted Project references' do user = create(:user) project = create(:project) - project.team << [user, :master] + project.add_master(user) link = reference_link(project: project.id, reference_type: 'test') doc = filter(link, current_user: user) @@ -94,7 +94,7 @@ describe Banzai::Filter::RedactorFilter do it 'removes references for project members with guest role' do member = create(:user) project = create(:project, :public) - project.team << [member, :guest] + project.add_guest(member) issue = create(:issue, :confidential, project: project) link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') @@ -128,7 +128,7 @@ describe Banzai::Filter::RedactorFilter do it 'allows references for project members' do member = create(:user) project = create(:project, :public) - project.team << [member, :developer] + project.add_developer(member) issue = create(:issue, :confidential, project: project) link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb index ef306f1cd4a..f38f0776303 100644 --- a/spec/lib/banzai/filter/relative_link_filter_spec.rb +++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb @@ -76,6 +76,11 @@ describe Banzai::Filter::RelativeLinkFilter do expect { filter(act) }.not_to raise_error end + it 'does not raise an exception with a garbled path' do + act = link("open(/var/tmp/):%20/location%0Afrom:%20/test") + expect { filter(act) }.not_to raise_error + end + it 'ignores ref if commit is passed' do doc = filter(link('non/existent.file'), commit: project.commit('empty-branch') ) expect(doc.at_css('a')['href']) diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb index fc03741976e..c76adc262fc 100644 --- a/spec/lib/banzai/filter/user_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb @@ -34,11 +34,11 @@ describe Banzai::Filter::UserReferenceFilter do let(:reference) { User.reference_prefix + 'all' } before do - project.team << [project.creator, :developer] + project.add_developer(project.creator) end it 'supports a special @all mention' do - project.team << [user, :developer] + project.add_developer(user) doc = reference_filter("Hey #{reference}", author: user) expect(doc.css('a').length).to eq 1 @@ -47,7 +47,7 @@ describe Banzai::Filter::UserReferenceFilter do end it 'includes a data-author attribute when there is an author' do - project.team << [user, :developer] + project.add_developer(user) doc = reference_filter(reference, author: user) expect(doc.css('a').first.attr('data-author')).to eq(user.id.to_s) diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb index e49726aca6c..b079a3be029 100644 --- a/spec/lib/banzai/reference_parser/user_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb @@ -63,8 +63,8 @@ describe Banzai::ReferenceParser::UserParser do let(:contributor) { create(:user) } before do - project.team << [user, :developer] - project.team << [contributor, :developer] + project.add_developer(user) + project.add_developer(contributor) end it 'returns the members of a project' do @@ -162,7 +162,7 @@ describe Banzai::ReferenceParser::UserParser do context 'when the link has a data-author attribute' do it 'returns the nodes when the user is a member of the project' do other_project = create(:project) - other_project.team << [user, :developer] + other_project.add_developer(user) link['data-project'] = other_project.id.to_s link['data-author'] = user.id.to_s diff --git a/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb b/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb index 5c471cbdeda..9bae7e53b71 100644 --- a/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb +++ b/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb @@ -24,17 +24,12 @@ describe Gitlab::BackgroundMigration::DeleteConflictingRedirectRoutesRange, :mig redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'foo5') end - it 'deletes the conflicting redirect_routes in the range' do + # No-op. See https://gitlab.com/gitlab-com/infrastructure/issues/3460#note_53223252 + it 'NO-OP: does not delete any redirect_routes' do expect(redirect_routes.count).to eq(8) - expect do - described_class.new.perform(1, 3) - end.to change { redirect_routes.where("path like 'foo%'").count }.from(5).to(2) + described_class.new.perform(1, 5) - expect do - described_class.new.perform(4, 5) - end.to change { redirect_routes.where("path like 'foo%'").count }.from(2).to(0) - - expect(redirect_routes.count).to eq(3) + expect(redirect_routes.count).to eq(8) end end diff --git a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb index 7351d45336a..5432d270555 100644 --- a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb +++ b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb @@ -281,6 +281,17 @@ describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads, :migrati migration.process_event(event) end + + it 'handles an error gracefully' do + event1 = create_push_event(project, author, { commits: [] }) + + expect(migration).to receive(:replicate_event).and_call_original + expect(migration).to receive(:create_push_event_payload).and_raise(ActiveRecord::InvalidForeignKey, 'invalid foreign key') + + migration.process_event(event1) + + expect(described_class::EventForMigration.all.count).to eq(0) + end end describe '#replicate_event' do @@ -335,9 +346,8 @@ describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads, :migrati it 'does not create push event payloads for removed events' do allow(event).to receive(:id).and_return(-1) - payload = migration.create_push_event_payload(event) + expect { migration.create_push_event_payload(event) }.to raise_error(ActiveRecord::InvalidForeignKey) - expect(payload).to be_nil expect(PushEventPayload.count).to eq(0) end diff --git a/spec/lib/gitlab/background_migration/populate_merge_request_metrics_with_events_data_spec.rb b/spec/lib/gitlab/background_migration/populate_merge_request_metrics_with_events_data_spec.rb new file mode 100644 index 00000000000..dfe3b31f1c0 --- /dev/null +++ b/spec/lib/gitlab/background_migration/populate_merge_request_metrics_with_events_data_spec.rb @@ -0,0 +1,124 @@ +require 'rails_helper' + +describe Gitlab::BackgroundMigration::PopulateMergeRequestMetricsWithEventsData, :migration, schema: 20171128214150 do + describe '#perform' do + let(:mr_with_event) { create(:merge_request) } + let!(:merged_event) { create(:event, :merged, target: mr_with_event) } + let!(:closed_event) { create(:event, :closed, target: mr_with_event) } + + before do + # Make sure no metrics are created and kept through after_* callbacks. + mr_with_event.metrics.destroy! + end + + it 'inserts metrics and updates closed and merged events' do + subject.perform(mr_with_event.id, mr_with_event.id) + + mr_with_event.reload + + expect(mr_with_event.metrics).to have_attributes(latest_closed_by_id: closed_event.author_id, + merged_by_id: merged_event.author_id) + expect(mr_with_event.metrics.latest_closed_at.to_s).to eq(closed_event.updated_at.to_s) + end + end + + describe '#insert_metrics_for_range' do + let!(:mrs_without_metrics) { create_list(:merge_request, 3) } + let!(:mrs_with_metrics) { create_list(:merge_request, 2) } + + before do + # Make sure no metrics are created and kept through after_* callbacks. + mrs_without_metrics.each { |m| m.metrics.destroy! } + end + + it 'inserts merge_request_metrics for merge_requests without one' do + expect { subject.insert_metrics_for_range(MergeRequest.first.id, MergeRequest.last.id) } + .to change(MergeRequest::Metrics, :count).from(2).to(5) + + mrs_without_metrics.each do |mr_without_metrics| + expect(mr_without_metrics.reload.metrics).to be_present + end + end + + it 'does not inserts merge_request_metrics for MRs out of given range' do + expect { subject.insert_metrics_for_range(mrs_with_metrics.first.id, mrs_with_metrics.last.id) } + .not_to change(MergeRequest::Metrics, :count).from(2) + end + end + + describe '#update_metrics_with_events_data' do + context 'closed events data update' do + let(:users) { create_list(:user, 3) } + let(:mrs_with_event) { create_list(:merge_request, 3) } + + before do + create_list(:event, 2, :closed, author: users.first, target: mrs_with_event.first) + create_list(:event, 3, :closed, author: users.second, target: mrs_with_event.second) + create(:event, :closed, author: users.third, target: mrs_with_event.third) + end + + it 'migrates multiple MR metrics with closed event data' do + mr_without_event = create(:merge_request) + create(:event, :merged) + + subject.update_metrics_with_events_data(mrs_with_event.first.id, mrs_with_event.last.id) + + mrs_with_event.each do |mr_with_event| + latest_event = Event.where(action: 3, target: mr_with_event).last + + mr_with_event.metrics.reload + + expect(mr_with_event.metrics.latest_closed_by).to eq(latest_event.author) + expect(mr_with_event.metrics.latest_closed_at.to_s).to eq(latest_event.updated_at.to_s) + end + + expect(mr_without_event.metrics.reload).to have_attributes(latest_closed_by_id: nil, + latest_closed_at: nil) + end + + it 'does not updates metrics out of given range' do + out_of_range_mr = create(:merge_request) + create(:event, :closed, author: users.last, target: out_of_range_mr) + + expect { subject.perform(mrs_with_event.first.id, mrs_with_event.second.id) } + .not_to change { out_of_range_mr.metrics.reload.merged_by } + .from(nil) + end + end + + context 'merged events data update' do + let(:users) { create_list(:user, 3) } + let(:mrs_with_event) { create_list(:merge_request, 3) } + + before do + create_list(:event, 2, :merged, author: users.first, target: mrs_with_event.first) + create_list(:event, 3, :merged, author: users.second, target: mrs_with_event.second) + create(:event, :merged, author: users.third, target: mrs_with_event.third) + end + + it 'migrates multiple MR metrics with merged event data' do + mr_without_event = create(:merge_request) + create(:event, :merged) + + subject.update_metrics_with_events_data(mrs_with_event.first.id, mrs_with_event.last.id) + + mrs_with_event.each do |mr_with_event| + latest_event = Event.where(action: Event::MERGED, target: mr_with_event).last + + expect(mr_with_event.metrics.reload.merged_by).to eq(latest_event.author) + end + + expect(mr_without_event.metrics.reload).to have_attributes(merged_by_id: nil) + end + + it 'does not updates metrics out of given range' do + out_of_range_mr = create(:merge_request) + create(:event, :merged, author: users.last, target: out_of_range_mr) + + expect { subject.perform(mrs_with_event.first.id, mrs_with_event.second.id) } + .not_to change { out_of_range_mr.metrics.reload.merged_by } + .from(nil) + end + end + end +end diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb index 8a83e446935..b5d86df09d2 100644 --- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb +++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb @@ -68,8 +68,14 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do expect(Project.find_by_full_path(project_path)).not_to be_nil end + it 'does not schedule an import' do + expect_any_instance_of(Project).not_to receive(:import_schedule) + + importer.create_project_if_needed + end + it 'creates the Git repo in disk' do - FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git")) + create_bare_repository("#{project_path}.git") importer.create_project_if_needed @@ -124,13 +130,14 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do end it 'creates the Git repo in disk' do - FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git")) + create_bare_repository("#{project_path}.git") importer.create_project_if_needed project = Project.find_by_full_path("#{admin.full_path}/#{project_path}") expect(File).to exist(File.join(project.repository_storage_path, project.disk_path + '.git')) + expect(File).to exist(File.join(project.repository_storage_path, project.disk_path + '.wiki.git')) end it 'moves an existing project to the correct path' do @@ -158,8 +165,11 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do it_behaves_like 'importing a repository' it 'creates the Wiki git repo in disk' do - FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git")) - FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.wiki.git")) + create_bare_repository("#{project_path}.git") + create_bare_repository("#{project_path}.wiki.git") + + expect(Projects::CreateService).to receive(:new).with(admin, hash_including(skip_wiki: true, + import_type: 'bare_repository')).and_call_original importer.create_project_if_needed @@ -182,4 +192,9 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do end end end + + def create_bare_repository(project_path) + repo_path = File.join(base_dir, project_path) + Gitlab::Git::Repository.create(repo_path, bare: true) + end end diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb index 61b73abcba4..9f42cf1dfca 100644 --- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb +++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb @@ -1,58 +1,122 @@ require 'spec_helper' describe ::Gitlab::BareRepositoryImport::Repository do - let(:project_repo_path) { described_class.new('/full/path/', '/full/path/to/repo.git') } + context 'legacy storage' do + subject { described_class.new('/full/path/', '/full/path/to/repo.git') } - it 'stores the repo path' do - expect(project_repo_path.repo_path).to eq('/full/path/to/repo.git') - end + it 'stores the repo path' do + expect(subject.repo_path).to eq('/full/path/to/repo.git') + end - it 'stores the group path' do - expect(project_repo_path.group_path).to eq('to') - end + it 'stores the group path' do + expect(subject.group_path).to eq('to') + end - it 'stores the project name' do - expect(project_repo_path.project_name).to eq('repo') - end + it 'stores the project name' do + expect(subject.project_name).to eq('repo') + end - it 'stores the wiki path' do - expect(project_repo_path.wiki_path).to eq('/full/path/to/repo.wiki.git') - end + it 'stores the wiki path' do + expect(subject.wiki_path).to eq('/full/path/to/repo.wiki.git') + end + + describe '#processable?' do + it 'returns false if it is a wiki' do + subject = described_class.new('/full/path/', '/full/path/to/a/b/my.wiki.git') + + expect(subject).not_to be_processable + end + + it 'returns true if group path is missing' do + subject = described_class.new('/full/path/', '/full/path/repo.git') - describe '#wiki?' do - it 'returns true if it is a wiki' do - wiki_path = described_class.new('/full/path/', '/full/path/to/a/b/my.wiki.git') + expect(subject).to be_processable + end - expect(wiki_path.wiki?).to eq(true) + it 'returns true when group path and project name are present' do + expect(subject).to be_processable + end end - it 'returns false if it is not a wiki' do - expect(project_repo_path.wiki?).to eq(false) + describe '#project_full_path' do + it 'returns the project full path with trailing slash in the root path' do + expect(subject.project_full_path).to eq('to/repo') + end + + it 'returns the project full path with no trailing slash in the root path' do + subject = described_class.new('/full/path', '/full/path/to/repo.git') + + expect(subject.project_full_path).to eq('to/repo') + end end end - describe '#hashed?' do - it 'returns true if it is a hashed folder' do - path = described_class.new('/full/path/', '/full/path/@hashed/my.repo.git') + context 'hashed storage' do + let(:gitlab_shell) { Gitlab::Shell.new } + let(:repository_storage) { 'default' } + let(:root_path) { Gitlab.config.repositories.storages[repository_storage]['path'] } + let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' } + let(:hashed_path) { "@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b" } + let(:repo_path) { File.join(root_path, "#{hashed_path}.git") } + let(:wiki_path) { File.join(root_path, "#{hashed_path}.wiki.git") } - expect(path.hashed?).to eq(true) + before do + gitlab_shell.add_repository(repository_storage, hashed_path) + repository = Rugged::Repository.new(repo_path) + repository.config['gitlab.fullpath'] = 'to/repo' end - it 'returns false if it is not a hashed folder' do - expect(project_repo_path.hashed?).to eq(false) + after do + gitlab_shell.remove_repository(root_path, hashed_path) end - end - describe '#project_full_path' do - it 'returns the project full path' do - expect(project_repo_path.repo_path).to eq('/full/path/to/repo.git') - expect(project_repo_path.project_full_path).to eq('to/repo') + subject { described_class.new(root_path, repo_path) } + + it 'stores the repo path' do + expect(subject.repo_path).to eq(repo_path) + end + + it 'stores the wiki path' do + expect(subject.wiki_path).to eq(wiki_path) + end + + it 'reads the group path from .git/config' do + expect(subject.group_path).to eq('to') + end + + it 'reads the project name from .git/config' do + expect(subject.project_name).to eq('repo') end - it 'with no trailing slash in the root path' do - repo_path = described_class.new('/full/path', '/full/path/to/repo.git') + describe '#processable?' do + it 'returns false if it is a wiki' do + subject = described_class.new(root_path, wiki_path) + + expect(subject).not_to be_processable + end + + it 'returns false when group and project name are missing' do + repository = Rugged::Repository.new(repo_path) + repository.config.delete('gitlab.fullpath') + + expect(subject).not_to be_processable + end + + it 'returns true when group path and project name are present' do + expect(subject).to be_processable + end + end + + describe '#project_full_path' do + it 'returns the project full path with trailing slash in the root path' do + expect(subject.project_full_path).to eq('to/repo') + end + + it 'returns the project full path with no trailing slash in the root path' do + subject = described_class.new(root_path[0...-1], repo_path) - expect(repo_path.project_full_path).to eq('to/repo') + expect(subject.project_full_path).to eq('to/repo') + end end end end diff --git a/spec/lib/gitlab/checks/project_moved_spec.rb b/spec/lib/gitlab/checks/project_moved_spec.rb index fa1575e2177..f90c2d6aded 100644 --- a/spec/lib/gitlab/checks/project_moved_spec.rb +++ b/spec/lib/gitlab/checks/project_moved_spec.rb @@ -35,6 +35,12 @@ describe Gitlab::Checks::ProjectMoved, :clean_gitlab_redis_shared_state do project_moved = described_class.new(project, user, 'foo/bar', 'http') expect(project_moved.add_redirect_message).to eq("OK") end + + it 'should handle anonymous clones' do + project_moved = described_class.new(project, nil, 'foo/bar', 'http') + + expect(project_moved.add_redirect_message).to eq(nil) + end end describe '#redirect_message' do diff --git a/spec/lib/gitlab/ci/ansi2html_spec.rb b/spec/lib/gitlab/ci/ansi2html_spec.rb index 33540eab5d6..05e2d94cbd6 100644 --- a/spec/lib/gitlab/ci/ansi2html_spec.rb +++ b/spec/lib/gitlab/ci/ansi2html_spec.rb @@ -120,6 +120,10 @@ describe Gitlab::Ci::Ansi2html do expect(convert_html("\e[48;5;240mHello")).to eq('<span class="xterm-bg-240">Hello</span>') end + it "can print 256 xterm fg bold colors" do + expect(convert_html("\e[38;5;16;1mHello")).to eq('<span class="xterm-fg-16 term-bold">Hello</span>') + end + it "can print 256 xterm bg colors on normal magenta foreground" do expect(convert_html("\e[48;5;16;35mHello")).to eq('<span class="term-fg-magenta xterm-bg-16">Hello</span>') end diff --git a/spec/lib/gitlab/ci/status/build/common_spec.rb b/spec/lib/gitlab/ci/status/build/common_spec.rb index 03d1f46b517..2cce7a23ea7 100644 --- a/spec/lib/gitlab/ci/status/build/common_spec.rb +++ b/spec/lib/gitlab/ci/status/build/common_spec.rb @@ -18,7 +18,7 @@ describe Gitlab::Ci::Status::Build::Common do describe '#has_details?' do context 'when user has access to read build' do before do - project.team << [user, :developer] + project.add_developer(user) end it { is_expected.to have_details } diff --git a/spec/lib/gitlab/ci/status/external/common_spec.rb b/spec/lib/gitlab/ci/status/external/common_spec.rb index b38fbee2486..40871f86568 100644 --- a/spec/lib/gitlab/ci/status/external/common_spec.rb +++ b/spec/lib/gitlab/ci/status/external/common_spec.rb @@ -29,7 +29,7 @@ describe Gitlab::Ci::Status::External::Common do describe '#has_details?' do context 'when user has access to read commit status' do before do - project.team << [user, :developer] + project.add_developer(user) end it { is_expected.to have_details } diff --git a/spec/lib/gitlab/ci/status/external/factory_spec.rb b/spec/lib/gitlab/ci/status/external/factory_spec.rb index c96fd53e730..529d02a3e39 100644 --- a/spec/lib/gitlab/ci/status/external/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/external/factory_spec.rb @@ -8,7 +8,7 @@ describe Gitlab::Ci::Status::External::Factory do let(:external_url) { 'http://gitlab.com/status' } before do - project.team << [user, :developer] + project.add_developer(user) end context 'when external status has a simple core status' do diff --git a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb index 4a5b45e7cae..57df8325635 100644 --- a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb @@ -18,7 +18,7 @@ describe Gitlab::Ci::Status::Pipeline::Common do describe '#has_details?' do context 'when user has access to read pipeline' do before do - project.team << [user, :developer] + project.add_developer(user) end it { is_expected.to have_details } diff --git a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb index dd754b849b2..defb3fdc0df 100644 --- a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb @@ -7,7 +7,7 @@ describe Gitlab::Ci::Status::Pipeline::Factory do let(:factory) { described_class.new(pipeline, user) } before do - project.team << [user, :developer] + project.add_developer(user) end context 'when pipeline has a core status' do diff --git a/spec/lib/gitlab/ci/status/stage/common_spec.rb b/spec/lib/gitlab/ci/status/stage/common_spec.rb index f5f03ac0395..6ec35f8da7e 100644 --- a/spec/lib/gitlab/ci/status/stage/common_spec.rb +++ b/spec/lib/gitlab/ci/status/stage/common_spec.rb @@ -27,7 +27,7 @@ describe Gitlab::Ci::Status::Stage::Common do context 'when user has permission to read pipeline' do before do - project.team << [user, :master] + project.add_master(user) end it 'has details' do diff --git a/spec/lib/gitlab/ci/status/stage/factory_spec.rb b/spec/lib/gitlab/ci/status/stage/factory_spec.rb index 432b07e4902..dee4f4efd1b 100644 --- a/spec/lib/gitlab/ci/status/stage/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/stage/factory_spec.rb @@ -18,7 +18,7 @@ describe Gitlab::Ci::Status::Stage::Factory do end before do - project.team << [user, :developer] + project.add_developer(user) end context 'when stage has a core status' do diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb index ef7d766a13d..8c79ef54c6c 100644 --- a/spec/lib/gitlab/closing_issue_extractor_spec.rb +++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb @@ -13,8 +13,8 @@ describe Gitlab::ClosingIssueExtractor do subject { described_class.new(project, project.creator) } before do - project.team << [project.creator, :developer] - project2.team << [project.creator, :master] + project.add_developer(project.creator) + project2.add_master(project.creator) end describe "#closed_by_message" do @@ -297,7 +297,7 @@ describe Gitlab::ClosingIssueExtractor do context 'with an external issue tracker reference' do it 'extracts the referenced issue' do jira_project = create(:jira_project, name: 'JIRA_EXT1') - jira_project.team << [jira_project.creator, :master] + jira_project.add_master(jira_project.creator) jira_issue = ExternalIssue.new("#{jira_project.name}-1", project: jira_project) closing_issue_extractor = described_class.new(jira_project, jira_project.creator) message = "Resolve #{jira_issue.to_reference}" diff --git a/spec/lib/gitlab/cycle_analytics/permissions_spec.rb b/spec/lib/gitlab/cycle_analytics/permissions_spec.rb index 2a0dd7be439..6de4bd3dc7c 100644 --- a/spec/lib/gitlab/cycle_analytics/permissions_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/permissions_spec.rb @@ -38,7 +38,7 @@ describe Gitlab::CycleAnalytics::Permissions do context 'user is master' do before do - project.team << [user, :master] + project.add_master(user) end it 'has permissions to issue stage' do @@ -72,7 +72,7 @@ describe Gitlab::CycleAnalytics::Permissions do context 'user has no build permissions' do before do - project.team << [user, :guest] + project.add_guest(user) end it 'has permissions to issue stage' do @@ -90,7 +90,7 @@ describe Gitlab::CycleAnalytics::Permissions do context 'user has no merge request permissions' do before do - project.team << [user, :guest] + project.add_guest(user) end it 'has permissions to issue stage' do @@ -108,7 +108,7 @@ describe Gitlab::CycleAnalytics::Permissions do context 'user has no issue permissions' do before do - project.team << [user, :developer] + project.add_developer(user) project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED) end diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index 664ba0f7234..7727a1d81b1 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -902,7 +902,7 @@ describe Gitlab::Database::MigrationHelpers do describe '#check_trigger_permissions!' do it 'does nothing when the user has the correct permissions' do expect { model.check_trigger_permissions!('users') } - .not_to raise_error(RuntimeError) + .not_to raise_error end it 'raises RuntimeError when the user does not have the correct permissions' do @@ -1036,4 +1036,93 @@ describe Gitlab::Database::MigrationHelpers do end end end + + describe '#change_column_type_using_background_migration' do + let!(:issue) { create(:issue) } + + let(:issue_model) do + Class.new(ActiveRecord::Base) do + self.table_name = 'issues' + include EachBatch + end + end + + it 'changes the type of a column using a background migration' do + expect(model) + .to receive(:add_column) + .with('issues', 'closed_at_for_type_change', :datetime_with_timezone) + + expect(model) + .to receive(:install_rename_triggers) + .with('issues', :closed_at, 'closed_at_for_type_change') + + expect(BackgroundMigrationWorker) + .to receive(:perform_in) + .ordered + .with( + 10.minutes, + 'CopyColumn', + ['issues', :closed_at, 'closed_at_for_type_change', issue.id, issue.id] + ) + + expect(BackgroundMigrationWorker) + .to receive(:perform_in) + .ordered + .with( + 1.hour + 10.minutes, + 'CleanupConcurrentTypeChange', + ['issues', :closed_at, 'closed_at_for_type_change'] + ) + + expect(Gitlab::BackgroundMigration) + .to receive(:steal) + .ordered + .with('CopyColumn') + + expect(Gitlab::BackgroundMigration) + .to receive(:steal) + .ordered + .with('CleanupConcurrentTypeChange') + + model.change_column_type_using_background_migration( + issue_model.all, + :closed_at, + :datetime_with_timezone + ) + end + end + + describe '#perform_background_migration_inline?' do + it 'returns true in a test environment' do + allow(Rails.env) + .to receive(:test?) + .and_return(true) + + expect(model.perform_background_migration_inline?).to eq(true) + end + + it 'returns true in a development environment' do + allow(Rails.env) + .to receive(:test?) + .and_return(false) + + allow(Rails.env) + .to receive(:development?) + .and_return(true) + + expect(model.perform_background_migration_inline?).to eq(true) + end + + it 'returns false in a production environment' do + allow(Rails.env) + .to receive(:test?) + .and_return(false) + + allow(Rails.env) + .to receive(:development?) + .and_return(false) + + expect(model.perform_background_migration_inline?).to eq(false) + end + end end diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index ff9acfd08b9..9204ea37963 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -431,4 +431,29 @@ describe Gitlab::Diff::File do end end end + + context 'when neither blob exists' do + let(:blank_diff_refs) { Gitlab::Diff::DiffRefs.new(base_sha: Gitlab::Git::BLANK_SHA, head_sha: Gitlab::Git::BLANK_SHA) } + let(:diff_file) { described_class.new(diff, diff_refs: blank_diff_refs, repository: project.repository) } + + describe '#blob' do + it 'returns a concrete nil so it can be used in boolean expressions' do + actual = diff_file.blob && true + + expect(actual).to be_nil + end + end + + describe '#binary?' do + it 'returns false' do + expect(diff_file).not_to be_binary + end + end + + describe '#size' do + it 'returns zero' do + expect(diff_file.size).to be_zero + end + end + end end diff --git a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb index d0fa16ce4d1..031efcf1291 100644 --- a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb +++ b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb @@ -66,7 +66,7 @@ describe Gitlab::Email::Handler::CreateNoteHandler do context 'and current user can update noteable' do before do - project.team << [user, :developer] + project.add_developer(user) end it 'does not raise an error' do @@ -99,7 +99,7 @@ describe Gitlab::Email::Handler::CreateNoteHandler do context 'and current user can update noteable' do before do - project.team << [user, :developer] + project.add_developer(user) end it 'post a note and updates the noteable' do diff --git a/spec/lib/gitlab/encoding_helper_spec.rb b/spec/lib/gitlab/encoding_helper_spec.rb index f6e5c55240f..87ec2698fc1 100644 --- a/spec/lib/gitlab/encoding_helper_spec.rb +++ b/spec/lib/gitlab/encoding_helper_spec.rb @@ -145,4 +145,18 @@ describe Gitlab::EncodingHelper do end end end + + describe 'encode_binary' do + [ + [nil, ""], + ["", ""], + [" ", " "], + %w(a1 a1), + ["编码", "\xE7\xBC\x96\xE7\xA0\x81".b] + ].each do |input, result| + it "encodes #{input.inspect} to #{result.inspect}" do + expect(ext_class.encode_binary(input)).to eq(result) + end + end + end end diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb index 7dc06c90078..4d2f08f95fc 100644 --- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb @@ -10,7 +10,7 @@ describe Gitlab::Gfm::ReferenceRewriter do let(:text) { 'some text' } before do - old_project.team << [user, :reporter] + old_project.add_reporter(user) end describe '#rewrite' do diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb index 5ed639543e0..6d35734d306 100644 --- a/spec/lib/gitlab/git/commit_spec.rb +++ b/spec/lib/gitlab/git/commit_spec.rb @@ -428,6 +428,11 @@ describe Gitlab::Git::Commit, seed_helper: true do subject { super().deletions } it { is_expected.to eq(6) } end + + describe '#total' do + subject { super().total } + it { is_expected.to eq(17) } + end end describe '#stats with gitaly on' do diff --git a/spec/lib/gitlab/git/gitlab_projects_spec.rb b/spec/lib/gitlab/git/gitlab_projects_spec.rb index 24da9589458..a798b188a0d 100644 --- a/spec/lib/gitlab/git/gitlab_projects_spec.rb +++ b/spec/lib/gitlab/git/gitlab_projects_spec.rb @@ -243,7 +243,6 @@ describe Gitlab::Git::GitlabProjects do let(:dest_repos_path) { tmp_repos_path } let(:dest_repo_name) { File.join('@hashed', 'aa', 'bb', 'xyz.git') } let(:dest_repo) { File.join(dest_repos_path, dest_repo_name) } - let(:dest_namespace) { File.dirname(dest_repo) } subject { gl_projects.fork_repository(dest_repos_path, dest_repo_name) } @@ -255,37 +254,64 @@ describe Gitlab::Git::GitlabProjects do FileUtils.rm_rf(dest_repos_path) end - it 'forks the repository' do - message = "Forking repository from <#{tmp_repo_path}> to <#{dest_repo}>." - expect(logger).to receive(:info).with(message) + shared_examples 'forking a repository' do + it 'forks the repository' do + is_expected.to be_truthy - is_expected.to be_truthy + expect(File.exist?(dest_repo)).to be_truthy + expect(File.exist?(File.join(dest_repo, 'hooks', 'pre-receive'))).to be_truthy + expect(File.exist?(File.join(dest_repo, 'hooks', 'post-receive'))).to be_truthy + end + + it 'does not fork if a project of the same name already exists' do + # create a fake project at the intended destination + FileUtils.mkdir_p(dest_repo) - expect(File.exist?(dest_repo)).to be_truthy - expect(File.exist?(File.join(dest_repo, 'hooks', 'pre-receive'))).to be_truthy - expect(File.exist?(File.join(dest_repo, 'hooks', 'post-receive'))).to be_truthy + is_expected.to be_falsy + end end - it 'does not fork if a project of the same name already exists' do - # create a fake project at the intended destination - FileUtils.mkdir_p(dest_repo) + context 'when Gitaly fork_repository feature is enabled' do + it_behaves_like 'forking a repository' + end - # trying to fork again should fail as the repo already exists - message = "fork-repository failed: destination repository <#{dest_repo}> already exists." - expect(logger).to receive(:error).with(message) + context 'when Gitaly fork_repository feature is disabled', :disable_gitaly do + it_behaves_like 'forking a repository' - is_expected.to be_falsy - end + # We seem to be stuck to having only one working Gitaly storage in tests, changing + # that is not very straight-forward so I'm leaving this test here for now till + # https://gitlab.com/gitlab-org/gitlab-ce/issues/41393 is fixed. + context 'different storages' do + let(:dest_repos_path) { File.join(File.dirname(tmp_repos_path), 'alternative') } - context 'different storages' do - let(:dest_repos_path) { File.join(File.dirname(tmp_repos_path), 'alternative') } + it 'forks the repo' do + is_expected.to be_truthy - it 'forks the repo' do - is_expected.to be_truthy + expect(File.exist?(dest_repo)).to be_truthy + expect(File.exist?(File.join(dest_repo, 'hooks', 'pre-receive'))).to be_truthy + expect(File.exist?(File.join(dest_repo, 'hooks', 'post-receive'))).to be_truthy + end + end - expect(File.exist?(dest_repo)).to be_truthy - expect(File.exist?(File.join(dest_repo, 'hooks', 'pre-receive'))).to be_truthy - expect(File.exist?(File.join(dest_repo, 'hooks', 'post-receive'))).to be_truthy + describe 'log messages' do + describe 'successful fork' do + it do + message = "Forking repository from <#{tmp_repo_path}> to <#{dest_repo}>." + expect(logger).to receive(:info).with(message) + + subject + end + end + + describe 'failed fork due existing destination' do + it do + FileUtils.mkdir_p(dest_repo) + message = "fork-repository failed: destination repository <#{dest_repo}> already exists." + expect(logger).to receive(:error).with(message) + + subject + end + end end end end diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 03a9cc488ca..faccc2c8e00 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -18,9 +18,10 @@ describe Gitlab::Git::Repository, seed_helper: true do end let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') } + let(:storage_path) { TestEnv.repos_path } describe '.create_hooks' do - let(:repo_path) { File.join(TestEnv.repos_path, 'hook-test.git') } + let(:repo_path) { File.join(storage_path, 'hook-test.git') } let(:hooks_dir) { File.join(repo_path, 'hooks') } let(:target_hooks_dir) { Gitlab.config.gitlab_shell.hooks_path } let(:existing_target) { File.join(repo_path, 'foobar') } @@ -645,7 +646,7 @@ describe Gitlab::Git::Repository, seed_helper: true do end after do - Gitlab::Shell.new.remove_repository(TestEnv.repos_path, 'my_project') + Gitlab::Shell.new.remove_repository(storage_path, 'my_project') end it 'fetches a repository as a mirror remote' do @@ -701,21 +702,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - describe '#remote_exists?' do - before(:all) do - @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') - @repo.add_remote("new_remote", SeedHelper::GITLAB_GIT_TEST_REPO_URL) - end - - it 'returns true for an existing remote' do - expect(@repo.remote_exists?('new_remote')).to eq(true) - end - - it 'returns false for a non-existing remote' do - expect(@repo.remote_exists?('foo')).to eq(false) - end - end - describe "#log" do let(:commit_with_old_name) do Gitlab::Git::Commit.decorate(repository, @commit_with_old_name_id) @@ -1030,7 +1016,7 @@ describe Gitlab::Git::Repository, seed_helper: true do shared_examples 'extended commit counting' do context 'with after timestamp' do it 'returns the number of commits after timestamp' do - options = { ref: 'master', limit: nil, after: Time.iso8601('2013-03-03T20:15:01+00:00') } + options = { ref: 'master', after: Time.iso8601('2013-03-03T20:15:01+00:00') } expect(repository.count_commits(options)).to eq(25) end @@ -1038,7 +1024,7 @@ describe Gitlab::Git::Repository, seed_helper: true do context 'with before timestamp' do it 'returns the number of commits before timestamp' do - options = { ref: 'feature', limit: nil, before: Time.iso8601('2015-03-03T20:15:01+00:00') } + options = { ref: 'feature', before: Time.iso8601('2015-03-03T20:15:01+00:00') } expect(repository.count_commits(options)).to eq(9) end @@ -1046,11 +1032,19 @@ describe Gitlab::Git::Repository, seed_helper: true do context 'with path' do it 'returns the number of commits with path ' do - options = { ref: 'master', limit: nil, path: "encoding" } + options = { ref: 'master', path: "encoding" } expect(repository.count_commits(options)).to eq(2) end end + + context 'with max_count' do + it 'returns the number of commits up to the passed limit' do + options = { ref: 'master', max_count: 10, after: Time.iso8601('2013-03-03T20:15:01+00:00') } + + expect(repository.count_commits(options)).to eq(10) + end + end end context 'when Gitaly count_commits feature is enabled' do @@ -1670,7 +1664,7 @@ describe Gitlab::Git::Repository, seed_helper: true do let(:branch_name) { "to-be-deleted-soon" } before do - project.team << [user, :developer] + project.add_developer(user) repository.create_branch(branch_name) end @@ -1734,6 +1728,20 @@ describe Gitlab::Git::Repository, seed_helper: true do expect(result.repo_created).to eq(false) expect(result.branch_created).to eq(false) end + + it 'returns nil if there was a concurrent branch update' do + concurrent_update_id = '33f3729a45c02fc67d00adb1b8bca394b0e761d9' + result = repository.merge(user, source_sha, target_branch, 'Test merge') do + # This ref update should make the merge fail + repository.write_ref(Gitlab::Git::BRANCH_REF_PREFIX + target_branch, concurrent_update_id) + end + + # This 'nil' signals that the merge was not applied + expect(result).to be_nil + + # Our concurrent ref update should not have been undone + expect(repository.find_branch(target_branch).target).to eq(concurrent_update_id) + end end context 'with gitaly' do @@ -1843,6 +1851,166 @@ describe Gitlab::Git::Repository, seed_helper: true do end end + describe 'remotes' do + let(:repository) do + Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') + end + let(:remote_name) { 'my-remote' } + + after do + ensure_seeds + end + + describe '#add_remote' do + let(:url) { 'http://my-repo.git' } + let(:mirror_refmap) { '+refs/*:refs/*' } + + it 'creates a new remote via Gitaly' do + expect_any_instance_of(Gitlab::GitalyClient::RemoteService) + .to receive(:add_remote).with(remote_name, url, mirror_refmap) + + repository.add_remote(remote_name, url, mirror_refmap: mirror_refmap) + end + + context 'with Gitaly disabled', :skip_gitaly_mock do + it 'creates a new remote via Rugged' do + expect_any_instance_of(Rugged::RemoteCollection).to receive(:create) + .with(remote_name, url) + expect_any_instance_of(Rugged::Config).to receive(:[]=) + .with("remote.#{remote_name}.mirror", true) + expect_any_instance_of(Rugged::Config).to receive(:[]=) + .with("remote.#{remote_name}.prune", true) + expect_any_instance_of(Rugged::Config).to receive(:[]=) + .with("remote.#{remote_name}.fetch", mirror_refmap) + + repository.add_remote(remote_name, url, mirror_refmap: mirror_refmap) + end + end + end + + describe '#remove_remote' do + it 'removes the remote via Gitaly' do + expect_any_instance_of(Gitlab::GitalyClient::RemoteService) + .to receive(:remove_remote).with(remote_name) + + repository.remove_remote(remote_name) + end + + context 'with Gitaly disabled', :skip_gitaly_mock do + it 'removes the remote via Rugged' do + expect_any_instance_of(Rugged::RemoteCollection).to receive(:delete) + .with(remote_name) + + repository.remove_remote(remote_name) + end + end + end + end + + describe '#gitlab_projects' do + subject { repository.gitlab_projects } + + it { expect(subject.shard_path).to eq(storage_path) } + it { expect(subject.repository_relative_path).to eq(repository.relative_path) } + end + + context 'gitlab_projects commands' do + let(:gitlab_projects) { repository.gitlab_projects } + let(:timeout) { Gitlab.config.gitlab_shell.git_timeout } + + describe '#push_remote_branches' do + subject do + repository.push_remote_branches('downstream-remote', ['master']) + end + + it 'executes the command' do + expect(gitlab_projects).to receive(:push_branches) + .with('downstream-remote', timeout, true, ['master']) + .and_return(true) + + is_expected.to be_truthy + end + + it 'raises an error if the command fails' do + allow(gitlab_projects).to receive(:output) { 'error' } + expect(gitlab_projects).to receive(:push_branches) + .with('downstream-remote', timeout, true, ['master']) + .and_return(false) + + expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error') + end + end + + describe '#delete_remote_branches' do + subject do + repository.delete_remote_branches('downstream-remote', ['master']) + end + + it 'executes the command' do + expect(gitlab_projects).to receive(:delete_remote_branches) + .with('downstream-remote', ['master']) + .and_return(true) + + is_expected.to be_truthy + end + + it 'raises an error if the command fails' do + allow(gitlab_projects).to receive(:output) { 'error' } + expect(gitlab_projects).to receive(:delete_remote_branches) + .with('downstream-remote', ['master']) + .and_return(false) + + expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error') + end + end + + describe '#delete_remote_branches' do + subject do + repository.delete_remote_branches('downstream-remote', ['master']) + end + + it 'executes the command' do + expect(gitlab_projects).to receive(:delete_remote_branches) + .with('downstream-remote', ['master']) + .and_return(true) + + is_expected.to be_truthy + end + + it 'raises an error if the command fails' do + allow(gitlab_projects).to receive(:output) { 'error' } + expect(gitlab_projects).to receive(:delete_remote_branches) + .with('downstream-remote', ['master']) + .and_return(false) + + expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error') + end + end + + describe '#delete_remote_branches' do + subject do + repository.delete_remote_branches('downstream-remote', ['master']) + end + + it 'executes the command' do + expect(gitlab_projects).to receive(:delete_remote_branches) + .with('downstream-remote', ['master']) + .and_return(true) + + is_expected.to be_truthy + end + + it 'raises an error if the command fails' do + allow(gitlab_projects).to receive(:output) { 'error' } + expect(gitlab_projects).to receive(:delete_remote_branches) + .with('downstream-remote', ['master']) + .and_return(false) + + expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error') + end + end + end + def create_remote_branch(repository, remote_name, branch_name, source_branch_name) source_branch = repository.branches.find { |branch| branch.name == source_branch_name } rugged = repository.rugged diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index 2db560c2cec..4290fbb0087 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -275,7 +275,7 @@ describe Gitlab::GitAccess do describe '#check_command_disabled!' do before do - project.team << [user, :master] + project.add_master(user) end context 'over http' do @@ -404,7 +404,7 @@ describe Gitlab::GitAccess do describe 'reporter user' do before do - project.team << [user, :reporter] + project.add_reporter(user) end context 'pull code' do @@ -417,7 +417,7 @@ describe Gitlab::GitAccess do context 'when member of the project' do before do - project.team << [user, :reporter] + project.add_reporter(user) end context 'pull code' do @@ -497,7 +497,7 @@ describe Gitlab::GitAccess do if role == :admin user.update_attribute(:admin, true) else - project.team << [user, role] + project.add_role(user, role) end aggregate_failures do @@ -658,7 +658,7 @@ describe Gitlab::GitAccess do context 'when project is authorized' do before do - project.team << [user, :reporter] + project.add_reporter(user) end it { expect { push_access_check }.to raise_unauthorized(described_class::ERROR_MESSAGES[:upload]) } diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb index 1056074264a..186b2d9279d 100644 --- a/spec/lib/gitlab/git_access_wiki_spec.rb +++ b/spec/lib/gitlab/git_access_wiki_spec.rb @@ -18,7 +18,7 @@ describe Gitlab::GitAccessWiki do context 'when user can :create_wiki' do before do create(:protected_branch, name: 'master', project: project) - project.team << [user, :developer] + project.add_developer(user) end subject { access.check('git-receive-pack', changes) } @@ -41,7 +41,7 @@ describe Gitlab::GitAccessWiki do subject { access.check('git-upload-pack', '_any') } before do - project.team << [user, :developer] + project.add_developer(user) end context 'when wiki feature is enabled' do diff --git a/spec/lib/gitlab/gitaly_client/conflicts_service_spec.rb b/spec/lib/gitlab/gitaly_client/conflicts_service_spec.rb new file mode 100644 index 00000000000..b9641de7eda --- /dev/null +++ b/spec/lib/gitlab/gitaly_client/conflicts_service_spec.rb @@ -0,0 +1,90 @@ +require 'spec_helper' + +describe Gitlab::GitalyClient::ConflictsService do + let(:project) { create(:project, :repository) } + let(:target_project) { create(:project, :repository) } + let(:source_repository) { project.repository.raw } + let(:target_repository) { target_project.repository.raw } + let(:target_gitaly_repository) { target_repository.gitaly_repository } + let(:our_commit_oid) { 'f00' } + let(:their_commit_oid) { 'f44' } + let(:client) do + described_class.new(target_repository, our_commit_oid, their_commit_oid) + end + + describe '#list_conflict_files' do + let(:request) do + Gitaly::ListConflictFilesRequest.new( + repository: target_gitaly_repository, our_commit_oid: our_commit_oid, + their_commit_oid: their_commit_oid + ) + end + let(:our_path) { 'our/path' } + let(:their_path) { 'their/path' } + let(:our_mode) { 0744 } + let(:header) do + double(repository: target_gitaly_repository, commit_oid: our_commit_oid, + our_path: our_path, our_mode: 0744, their_path: their_path) + end + let(:response) do + [ + double(files: [double(header: header), double(content: 'foo', header: nil)]), + double(files: [double(content: 'bar', header: nil)]) + ] + end + let(:file) { subject[0] } + + subject { client.list_conflict_files } + + it 'sends an RPC request' do + expect_any_instance_of(Gitaly::ConflictsService::Stub).to receive(:list_conflict_files) + .with(request, kind_of(Hash)).and_return([]) + + subject + end + + it 'forms a Gitlab::Git::ConflictFile collection from the response' do + allow_any_instance_of(Gitaly::ConflictsService::Stub).to receive(:list_conflict_files) + .with(request, kind_of(Hash)).and_return(response) + + expect(subject.size).to be(1) + expect(file.content).to eq('foobar') + expect(file.their_path).to eq(their_path) + expect(file.our_path).to eq(our_path) + expect(file.our_mode).to be(our_mode) + expect(file.repository).to eq(target_repository) + expect(file.commit_oid).to eq(our_commit_oid) + end + end + + describe '#resolve_conflicts' do + let(:user) { create(:user) } + let(:files) do + [{ old_path: 'some/path', new_path: 'some/path', content: '' }] + end + let(:source_branch) { 'master' } + let(:target_branch) { 'feature' } + let(:commit_message) { 'Solving conflicts' } + let(:resolution) do + Gitlab::Git::Conflict::Resolution.new(user, files, commit_message) + end + + subject do + client.resolve_conflicts(source_repository, resolution, source_branch, target_branch) + end + + it 'sends an RPC request' do + expect_any_instance_of(Gitaly::ConflictsService::Stub).to receive(:resolve_conflicts) + .with(kind_of(Enumerator), kind_of(Hash)).and_return(double(resolution_error: "")) + + subject + end + + it 'raises a relevant exception if resolution_error is present' do + expect_any_instance_of(Gitaly::ConflictsService::Stub).to receive(:resolve_conflicts) + .with(kind_of(Enumerator), kind_of(Hash)).and_return(double(resolution_error: "something happened")) + + expect { subject }.to raise_error(Gitlab::Git::Conflict::Resolver::ResolutionError) + end + end +end diff --git a/spec/lib/gitlab/gitaly_client/remote_service_spec.rb b/spec/lib/gitlab/gitaly_client/remote_service_spec.rb new file mode 100644 index 00000000000..69c6f054016 --- /dev/null +++ b/spec/lib/gitlab/gitaly_client/remote_service_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe Gitlab::GitalyClient::RemoteService do + let(:project) { create(:project) } + let(:storage_name) { project.repository_storage } + let(:relative_path) { project.disk_path + '.git' } + let(:remote_name) { 'my-remote' } + let(:client) { described_class.new(project.repository) } + + describe '#add_remote' do + let(:url) { 'http://my-repo.git' } + let(:mirror_refmap) { :all_refs } + + it 'sends an add_remote message' do + expect_any_instance_of(Gitaly::RemoteService::Stub) + .to receive(:add_remote) + .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash)) + .and_return(double(:add_remote_response)) + + client.add_remote(remote_name, url, mirror_refmap) + end + end + + describe '#remove_remote' do + it 'sends an remove_remote message and returns the result value' do + expect_any_instance_of(Gitaly::RemoteService::Stub) + .to receive(:remove_remote) + .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash)) + .and_return(double(result: true)) + + expect(client.remove_remote(remote_name)).to be(true) + end + end +end diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb index a871ed0df0e..309b7338ef0 100644 --- a/spec/lib/gitlab/gitaly_client_spec.rb +++ b/spec/lib/gitlab/gitaly_client_spec.rb @@ -38,20 +38,6 @@ describe Gitlab::GitalyClient, skip_gitaly_mock: true do end end - describe 'encode' do - [ - [nil, ""], - ["", ""], - [" ", " "], - %w(a1 a1), - ["编码", "\xE7\xBC\x96\xE7\xA0\x81".b] - ].each do |input, result| - it "encodes #{input.inspect} to #{result.inspect}" do - expect(described_class.encode(input)).to eq result - end - end - end - describe 'allow_n_plus_1_calls' do context 'when RequestStore is enabled', :request_store do it 'returns the result of the allow_n_plus_1_calls block' do diff --git a/spec/lib/gitlab/google_code_import/importer_spec.rb b/spec/lib/gitlab/google_code_import/importer_spec.rb index 798ea0bac58..017facd0f5e 100644 --- a/spec/lib/gitlab/google_code_import/importer_spec.rb +++ b/spec/lib/gitlab/google_code_import/importer_spec.rb @@ -15,7 +15,7 @@ describe Gitlab::GoogleCodeImport::Importer do subject { described_class.new(project) } before do - project.team << [project.creator, :master] + project.add_master(project.creator) project.create_import_data(data: import_data) end diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb index 6243b6ac9f0..6faf3d82981 100644 --- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb @@ -9,7 +9,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver do let!(:project) { setup_project } before do - project.team << [user, :master] + project.add_master(user) allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) allow_any_instance_of(MergeRequest).to receive(:source_branch_sha).and_return('ABCD') allow_any_instance_of(MergeRequest).to receive(:target_branch_sha).and_return('DCBA') diff --git a/spec/lib/gitlab/import_export/repo_saver_spec.rb b/spec/lib/gitlab/import_export/repo_saver_spec.rb index e6ad516deef..44f972fe530 100644 --- a/spec/lib/gitlab/import_export/repo_saver_spec.rb +++ b/spec/lib/gitlab/import_export/repo_saver_spec.rb @@ -9,7 +9,7 @@ describe Gitlab::ImportExport::RepoSaver do let(:bundler) { described_class.new(project: project, shared: shared) } before do - project.team << [user, :master] + project.add_master(user) allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) end diff --git a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb index 0e55993c8ef..1d1e7e7f89a 100644 --- a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb +++ b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb @@ -10,7 +10,7 @@ describe Gitlab::ImportExport::WikiRepoSaver do let!(:project_wiki) { ProjectWiki.new(project, user) } before do - project.team << [user, :master] + project.add_master(user) allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) project_wiki.wiki project_wiki.create_page("index", "test content") diff --git a/spec/lib/gitlab/project_authorizations_spec.rb b/spec/lib/gitlab/project_authorizations_spec.rb index 953cfbb8b88..f3cd6961e94 100644 --- a/spec/lib/gitlab/project_authorizations_spec.rb +++ b/spec/lib/gitlab/project_authorizations_spec.rb @@ -15,7 +15,7 @@ describe Gitlab::ProjectAuthorizations do end before do - other_project.team << [user, :reporter] + other_project.add_reporter(user) group.add_developer(user) end diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb index a424f0f5cfe..17937726f2c 100644 --- a/spec/lib/gitlab/project_search_results_spec.rb +++ b/spec/lib/gitlab/project_search_results_spec.rb @@ -179,7 +179,7 @@ describe Gitlab::ProjectSearchResults do end it 'does not list project confidential issues for project members with guest role' do - project.team << [member, :guest] + project.add_guest(member) results = described_class.new(member, project, query) issues = results.objects('issues') @@ -211,7 +211,7 @@ describe Gitlab::ProjectSearchResults do end it 'lists project confidential issues for project members' do - project.team << [member, :developer] + project.add_developer(member) results = described_class.new(member, project, query) issues = results.objects('issues') @@ -290,12 +290,12 @@ describe Gitlab::ProjectSearchResults do let!(:private_project) { create(:project, :private, :repository, creator: creator, namespace: creator.namespace) } let(:team_master) do user = create(:user, username: 'private-project-master') - private_project.team << [user, :master] + private_project.add_master(user) user end let(:team_reporter) do user = create(:user, username: 'private-project-reporter') - private_project.team << [user, :reporter] + private_project.add_reporter(user) user end diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb index 8ec3f55e6de..4139d1c650c 100644 --- a/spec/lib/gitlab/reference_extractor_spec.rb +++ b/spec/lib/gitlab/reference_extractor_spec.rb @@ -4,7 +4,7 @@ describe Gitlab::ReferenceExtractor do let(:project) { create(:project) } before do - project.team << [project.creator, :developer] + project.add_developer(project.creator) end subject { described_class.new(project, project.creator) } @@ -14,8 +14,8 @@ describe Gitlab::ReferenceExtractor do @u_bar = create(:user, username: 'bar') @u_offteam = create(:user, username: 'offteam') - project.team << [@u_foo, :reporter] - project.team << [@u_bar, :guest] + project.add_guest(@u_foo) + project.add_guest(@u_bar) subject.analyze('@foo, @baduser, @bar, and @offteam') expect(subject.users).to match_array([@u_foo, @u_bar, @u_offteam]) @@ -26,8 +26,8 @@ describe Gitlab::ReferenceExtractor do @u_bar = create(:user, username: 'bar') @u_offteam = create(:user, username: 'offteam') - project.team << [@u_foo, :reporter] - project.team << [@u_bar, :guest] + project.add_reporter(@u_foo) + project.add_reporter(@u_bar) subject.analyze(%Q{ Inline code: `@foo` @@ -228,7 +228,7 @@ describe Gitlab::ReferenceExtractor do let(:issue) { create(:issue, project: other_project) } before do - other_project.team << [project.creator, :developer] + other_project.add_developer(project.creator) end it 'handles project issue references' do @@ -246,7 +246,7 @@ describe Gitlab::ReferenceExtractor do let(:text) { "Ref. #{issue.to_reference} and #{label.to_reference}" } before do - project.team << [project.creator, :developer] + project.add_developer(project.creator) subject.analyze(text) end diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb index a958baab44f..b5a9ac570e6 100644 --- a/spec/lib/gitlab/search_results_spec.rb +++ b/spec/lib/gitlab/search_results_spec.rb @@ -16,7 +16,7 @@ describe Gitlab::SearchResults do context 'as a user with access' do before do - project.team << [user, :developer] + project.add_developer(user) end describe '#projects_count' do @@ -52,15 +52,36 @@ describe Gitlab::SearchResults do expect(results.objects('merge_requests')).to include merge_request_2 end - it 'includes project filter by default' do - expect(results).to receive(:project_ids_relation).and_call_original - results.objects('merge_requests') + describe '#merge_requests' do + it 'includes project filter by default' do + expect(results).to receive(:project_ids_relation).and_call_original + + results.objects('merge_requests') + end + + it 'it skips project filter if default project context is used' do + allow(results).to receive(:default_project_filter).and_return(true) + + expect(results).not_to receive(:project_ids_relation) + + results.objects('merge_requests') + end end - it 'it skips project filter if default is used' do - allow(results).to receive(:default_project_filter).and_return(true) - expect(results).not_to receive(:project_ids_relation) - results.objects('merge_requests') + describe '#issues' do + it 'includes project filter by default' do + expect(results).to receive(:project_ids_relation).and_call_original + + results.objects('issues') + end + + it 'it skips project filter if default project context is used' do + allow(results).to receive(:default_project_filter).and_return(true) + + expect(results).not_to receive(:project_ids_relation) + + results.objects('issues') + end end end @@ -104,8 +125,8 @@ describe Gitlab::SearchResults do end it 'does not list confidential issues for project members with guest role' do - project_1.team << [member, :guest] - project_2.team << [member, :guest] + project_1.add_guest(member) + project_2.add_guest(member) results = described_class.new(member, limit_projects, query) issues = results.objects('issues') @@ -146,8 +167,8 @@ describe Gitlab::SearchResults do end it 'lists confidential issues for project members' do - project_1.team << [member, :developer] - project_2.team << [member, :developer] + project_1.add_developer(member) + project_2.add_developer(member) results = described_class.new(member, limit_projects, query) issues = results.objects('issues') diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb index dd779b04741..81d9e6a8f82 100644 --- a/spec/lib/gitlab/shell_spec.rb +++ b/spec/lib/gitlab/shell_spec.rb @@ -347,62 +347,6 @@ describe Gitlab::Shell do end.to raise_error(Gitlab::Shell::Error, "error") end end - - describe '#push_remote_branches' do - subject(:result) do - gitlab_shell.push_remote_branches( - project.repository_storage_path, - project.disk_path, - 'downstream-remote', - ['master'] - ) - end - - it 'executes the command' do - expect(gitlab_projects).to receive(:push_branches) - .with('downstream-remote', timeout, true, ['master']) - .and_return(true) - - is_expected.to be_truthy - end - - it 'fails to execute the command' do - allow(gitlab_projects).to receive(:output) { 'error' } - expect(gitlab_projects).to receive(:push_branches) - .with('downstream-remote', timeout, true, ['master']) - .and_return(false) - - expect { result }.to raise_error(Gitlab::Shell::Error, 'error') - end - end - - describe '#delete_remote_branches' do - subject(:result) do - gitlab_shell.delete_remote_branches( - project.repository_storage_path, - project.disk_path, - 'downstream-remote', - ['master'] - ) - end - - it 'executes the command' do - expect(gitlab_projects).to receive(:delete_remote_branches) - .with('downstream-remote', ['master']) - .and_return(true) - - is_expected.to be_truthy - end - - it 'fails to execute the command' do - allow(gitlab_projects).to receive(:output) { 'error' } - expect(gitlab_projects).to receive(:delete_remote_branches) - .with('downstream-remote', ['master']) - .and_return(false) - - expect { result }.to raise_error(Gitlab::Shell::Error, 'error') - end - end end describe 'namespace actions' do diff --git a/spec/lib/gitlab/slash_commands/issue_new_spec.rb b/spec/lib/gitlab/slash_commands/issue_new_spec.rb index 75ae58d0582..3b077c58c50 100644 --- a/spec/lib/gitlab/slash_commands/issue_new_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_new_spec.rb @@ -7,7 +7,7 @@ describe Gitlab::SlashCommands::IssueNew do let(:regex_match) { described_class.match("issue create bird is the word") } before do - project.team << [user, :master] + project.add_master(user) end subject do diff --git a/spec/lib/gitlab/slash_commands/issue_search_spec.rb b/spec/lib/gitlab/slash_commands/issue_search_spec.rb index 51f59216413..e41e5254dde 100644 --- a/spec/lib/gitlab/slash_commands/issue_search_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_search_spec.rb @@ -21,7 +21,7 @@ describe Gitlab::SlashCommands::IssueSearch do context 'the user has access' do before do - project.team << [user, :master] + project.add_master(user) end it 'returns all results' do diff --git a/spec/lib/gitlab/slash_commands/issue_show_spec.rb b/spec/lib/gitlab/slash_commands/issue_show_spec.rb index 08c380ca8f1..e5834d5a2ee 100644 --- a/spec/lib/gitlab/slash_commands/issue_show_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_show_spec.rb @@ -8,7 +8,7 @@ describe Gitlab::SlashCommands::IssueShow do let(:regex_match) { described_class.match("issue show #{issue.iid}") } before do - project.team << [user, :master] + project.add_master(user) end subject do diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb index cd97416bcc9..7280acb6c82 100644 --- a/spec/lib/gitlab/user_access_spec.rb +++ b/spec/lib/gitlab/user_access_spec.rb @@ -8,19 +8,19 @@ describe Gitlab::UserAccess do describe '#can_push_to_branch?' do describe 'push to none protected branch' do it 'returns true if user is a master' do - project.team << [user, :master] + project.add_master(user) expect(access.can_push_to_branch?('random_branch')).to be_truthy end it 'returns true if user is a developer' do - project.team << [user, :developer] + project.add_developer(user) expect(access.can_push_to_branch?('random_branch')).to be_truthy end it 'returns false if user is a reporter' do - project.team << [user, :reporter] + project.add_reporter(user) expect(access.can_push_to_branch?('random_branch')).to be_falsey end @@ -31,34 +31,34 @@ describe Gitlab::UserAccess do let(:project_access) { described_class.new(user, project: empty_project) } it 'returns true if user is master' do - empty_project.team << [user, :master] + empty_project.add_master(user) expect(project_access.can_push_to_branch?('master')).to be_truthy end it 'returns false if user is developer and project is fully protected' do - empty_project.team << [user, :developer] + empty_project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_FULL) expect(project_access.can_push_to_branch?('master')).to be_falsey end it 'returns false if user is developer and it is not allowed to push new commits but can merge into branch' do - empty_project.team << [user, :developer] + empty_project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE) expect(project_access.can_push_to_branch?('master')).to be_falsey end it 'returns true if user is developer and project is unprotected' do - empty_project.team << [user, :developer] + empty_project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE) expect(project_access.can_push_to_branch?('master')).to be_truthy end it 'returns true if user is developer and project grants developers permission' do - empty_project.team << [user, :developer] + empty_project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH) expect(project_access.can_push_to_branch?('master')).to be_truthy @@ -70,25 +70,25 @@ describe Gitlab::UserAccess do let(:not_existing_branch) { create :protected_branch, :developers_can_merge, project: project } it 'returns true if user is a master' do - project.team << [user, :master] + project.add_master(user) expect(access.can_push_to_branch?(branch.name)).to be_truthy end it 'returns false if user is a developer' do - project.team << [user, :developer] + project.add_developer(user) expect(access.can_push_to_branch?(branch.name)).to be_falsey end it 'returns false if user is a reporter' do - project.team << [user, :reporter] + project.add_reporter(user) expect(access.can_push_to_branch?(branch.name)).to be_falsey end it 'returns false if branch does not exist' do - project.team << [user, :developer] + project.add_developer(user) expect(access.can_push_to_branch?(not_existing_branch.name)).to be_falsey end @@ -100,19 +100,19 @@ describe Gitlab::UserAccess do end it 'returns true if user is a master' do - project.team << [user, :master] + project.add_master(user) expect(access.can_push_to_branch?(@branch.name)).to be_truthy end it 'returns true if user is a developer' do - project.team << [user, :developer] + project.add_developer(user) expect(access.can_push_to_branch?(@branch.name)).to be_truthy end it 'returns false if user is a reporter' do - project.team << [user, :reporter] + project.add_reporter(user) expect(access.can_push_to_branch?(@branch.name)).to be_falsey end @@ -124,19 +124,19 @@ describe Gitlab::UserAccess do end it 'returns true if user is a master' do - project.team << [user, :master] + project.add_master(user) expect(access.can_merge_to_branch?(@branch.name)).to be_truthy end it 'returns true if user is a developer' do - project.team << [user, :developer] + project.add_developer(user) expect(access.can_merge_to_branch?(@branch.name)).to be_truthy end it 'returns false if user is a reporter' do - project.team << [user, :reporter] + project.add_reporter(user) expect(access.can_merge_to_branch?(@branch.name)).to be_falsey end diff --git a/spec/lib/gitlab/visibility_level_spec.rb b/spec/lib/gitlab/visibility_level_spec.rb index 48a67773de9..d85dac630b4 100644 --- a/spec/lib/gitlab/visibility_level_spec.rb +++ b/spec/lib/gitlab/visibility_level_spec.rb @@ -49,4 +49,31 @@ describe Gitlab::VisibilityLevel do .to eq([Gitlab::VisibilityLevel::PUBLIC]) end end + + describe '.allowed_levels' do + it 'only includes the levels that arent restricted' do + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::INTERNAL]) + + expect(described_class.allowed_levels) + .to contain_exactly(described_class::PRIVATE, described_class::PUBLIC) + end + end + + describe '.closest_allowed_level' do + it 'picks INTERNAL instead of PUBLIC if public is restricted' do + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + + expect(described_class.closest_allowed_level(described_class::PUBLIC)) + .to eq(described_class::INTERNAL) + end + + it 'picks PRIVATE if nothing is available' do + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC, + Gitlab::VisibilityLevel::INTERNAL, + Gitlab::VisibilityLevel::PRIVATE]) + + expect(described_class.closest_allowed_level(described_class::PUBLIC)) + .to eq(described_class::PRIVATE) + end + end end |