diff options
Diffstat (limited to 'spec/services')
23 files changed, 597 insertions, 227 deletions
diff --git a/spec/services/application_settings/update_service_spec.rb b/spec/services/application_settings/update_service_spec.rb index 6337ee7d724..daf5dfba6b1 100644 --- a/spec/services/application_settings/update_service_spec.rb +++ b/spec/services/application_settings/update_service_spec.rb @@ -10,6 +10,9 @@ describe ApplicationSettings::UpdateService do before do # So the caching behaves like it would in production stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') + + # Creating these settings first ensures they're used by other factories + application_settings end describe 'updating terms' do diff --git a/spec/services/applications/create_service_spec.rb b/spec/services/applications/create_service_spec.rb index 9c43b56744b..c8134087fa1 100644 --- a/spec/services/applications/create_service_spec.rb +++ b/spec/services/applications/create_service_spec.rb @@ -1,17 +1,14 @@ +# frozen_string_literal: true + require "spec_helper" describe ::Applications::CreateService do + include TestRequestHelpers + let(:user) { create(:user) } let(:params) { attributes_for(:application) } - let(:request) do - if Gitlab.rails5? - ActionController::TestRequest.new({ remote_ip: "127.0.0.1" }, ActionController::TestSession.new) - else - ActionController::TestRequest.new(remote_ip: "127.0.0.1") - end - end subject { described_class.new(user, params) } - it { expect { subject.execute(request) }.to change { Doorkeeper::Application.count }.by(1) } + it { expect { subject.execute(test_request) }.to change { Doorkeeper::Application.count }.by(1) } end diff --git a/spec/services/audit_event_service_spec.rb b/spec/services/audit_event_service_spec.rb new file mode 100644 index 00000000000..32fd98e6ef9 --- /dev/null +++ b/spec/services/audit_event_service_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe AuditEventService do + let(:project) { create(:project) } + let(:user) { create(:user) } + let(:project_member) { create(:project_member, user: user) } + let(:service) { described_class.new(user, project, { action: :destroy }) } + let(:logger) { instance_double(Gitlab::AuditJsonLogger) } + + describe '#security_event' do + before do + expect(service).to receive(:file_logger).and_return(logger) + end + + it 'creates an event and logs to a file' do + expect(logger).to receive(:info).with(author_id: user.id, + entity_id: project.id, + entity_type: "Project", + action: :destroy) + + expect { service.security_event }.to change(SecurityEvent, :count).by(1) + end + end +end diff --git a/spec/services/boards/visits/create_service_spec.rb b/spec/services/boards/visits/create_service_spec.rb new file mode 100644 index 00000000000..6baf7ac9deb --- /dev/null +++ b/spec/services/boards/visits/create_service_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Boards::Visits::CreateService do + describe '#execute' do + let(:user) { create(:user) } + + context 'when a project board' do + let(:project) { create(:project) } + let(:project_board) { create(:board, project: project) } + + subject(:service) { described_class.new(project_board.parent, user) } + + it 'returns nil when there is no user' do + service.current_user = nil + + expect(service.execute(project_board)).to eq nil + end + + it 'returns nil when database is read only' do + allow(Gitlab::Database).to receive(:read_only?) { true } + + expect(service.execute(project_board)).to eq nil + end + + it 'records the visit' do + expect(BoardProjectRecentVisit).to receive(:visited!).once + + service.execute(project_board) + end + end + + context 'when a group board' do + let(:group) { create(:group) } + let(:group_board) { create(:board, group: group) } + + subject(:service) { described_class.new(group_board.parent, user) } + + it 'returns nil when there is no user' do + service.current_user = nil + + expect(service.execute(group_board)).to eq nil + end + + it 'records the visit' do + expect(BoardGroupRecentVisit).to receive(:visited!).once + + service.execute(group_board) + end + end + end +end diff --git a/spec/services/boards/visits/latest_service_spec.rb b/spec/services/boards/visits/latest_service_spec.rb new file mode 100644 index 00000000000..e55d599e2cc --- /dev/null +++ b/spec/services/boards/visits/latest_service_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Boards::Visits::LatestService do + describe '#execute' do + let(:user) { create(:user) } + + context 'when a project board' do + let(:project) { create(:project) } + let(:project_board) { create(:board, project: project) } + + subject(:service) { described_class.new(project_board.parent, user) } + + it 'returns nil when there is no user' do + service.current_user = nil + + expect(service.execute).to eq nil + end + + it 'queries for most recent visit' do + expect(BoardProjectRecentVisit).to receive(:latest).once + + service.execute + end + end + + context 'when a group board' do + let(:group) { create(:group) } + let(:group_board) { create(:board, group: group) } + + subject(:service) { described_class.new(group_board.parent, user) } + + it 'returns nil when there is no user' do + service.current_user = nil + + expect(service.execute).to eq nil + end + + it 'queries for most recent visit' do + expect(BoardGroupRecentVisit).to receive(:latest).once + + service.execute + end + end + end +end diff --git a/spec/services/ci/process_build_service_spec.rb b/spec/services/ci/process_build_service_spec.rb index 9f47439dc4a..9a53b32394d 100644 --- a/spec/services/ci/process_build_service_spec.rb +++ b/spec/services/ci/process_build_service_spec.rb @@ -11,213 +11,135 @@ describe Ci::ProcessBuildService, '#execute' do project.add_maintainer(user) end - shared_examples_for 'Enqueuing properly' do |valid_statuses_for_when| - valid_statuses_for_when.each do |status_for_prior_stages| - context "when status for prior stages is #{status_for_prior_stages}" do - let(:current_status) { status_for_prior_stages } - - %w[created skipped manual scheduled].each do |status| - context "when build status is #{status}" do - let(:build) { create(:ci_build, status.to_sym, when: when_option, user: user, project: project) } - - it 'enqueues the build' do - expect { subject }.to change { build.status }.to('pending') - end - end - end + context 'when build has on_success option' do + let(:build) { create(:ci_build, :created, when: :on_success, user: user, project: project) } - %w[pending running success failed canceled].each do |status| - context "when build status is #{status}" do - let(:build) { create(:ci_build, status.to_sym, when: when_option, user: user, project: project) } + context 'when current status is success' do + let(:current_status) { 'success' } - it 'does not change the build status' do - expect { subject }.not_to change { build.status } - end - end - end + it 'changes the build status' do + expect { subject }.to change { build.status }.to('pending') end end - (HasStatus::AVAILABLE_STATUSES - valid_statuses_for_when).each do |status_for_prior_stages| - let(:current_status) { status_for_prior_stages } - - context "when status for prior stages is #{status_for_prior_stages}" do - %w[created pending].each do |status| - context "when build status is #{status}" do - let(:build) { create(:ci_build, status.to_sym, when: when_option, user: user, project: project) } + context 'when current status is failed' do + let(:current_status) { 'failed' } - it 'skips the build' do - expect { subject }.to change { build.status }.to('skipped') - end - end - end - - (HasStatus::AVAILABLE_STATUSES - %w[created pending]).each do |status| - context "when build status is #{status}" do - let(:build) { create(:ci_build, status.to_sym, when: when_option, user: user, project: project) } - - it 'does not change build status' do - expect { subject }.not_to change { build.status } - end - end - end + it 'does not change the build status' do + expect { subject }.to change { build.status }.to('skipped') end end end - shared_examples_for 'Actionizing properly' do |valid_statuses_for_when| - valid_statuses_for_when.each do |status_for_prior_stages| - context "when status for prior stages is #{status_for_prior_stages}" do - let(:current_status) { status_for_prior_stages } - - %w[created].each do |status| - context "when build status is #{status}" do - let(:build) { create(:ci_build, status.to_sym, :actionable, user: user, project: project) } - - it 'enqueues the build' do - expect { subject }.to change { build.status }.to('manual') - end - end - end + context 'when build has on_failure option' do + let(:build) { create(:ci_build, :created, when: :on_failure, user: user, project: project) } - %w[manual skipped pending running success failed canceled scheduled].each do |status| - context "when build status is #{status}" do - let(:build) { create(:ci_build, status.to_sym, :actionable, user: user, project: project) } + context 'when current status is success' do + let(:current_status) { 'success' } - it 'does not change the build status' do - expect { subject }.not_to change { build.status } - end - end - end + it 'changes the build status' do + expect { subject }.to change { build.status }.to('skipped') end end - (HasStatus::AVAILABLE_STATUSES - valid_statuses_for_when).each do |status_for_prior_stages| - let(:current_status) { status_for_prior_stages } - - context "when status for prior stages is #{status_for_prior_stages}" do - %w[created pending].each do |status| - context "when build status is #{status}" do - let(:build) { create(:ci_build, status.to_sym, :actionable, user: user, project: project) } - - it 'skips the build' do - expect { subject }.to change { build.status }.to('skipped') - end - end - end - - (HasStatus::AVAILABLE_STATUSES - %w[created pending]).each do |status| - context "when build status is #{status}" do - let(:build) { create(:ci_build, status.to_sym, :actionable, user: user, project: project) } + context 'when current status is failed' do + let(:current_status) { 'failed' } - it 'does not change build status' do - expect { subject }.not_to change { build.status } - end - end - end + it 'does not change the build status' do + expect { subject }.to change { build.status }.to('pending') end end end - shared_examples_for 'Scheduling properly' do |valid_statuses_for_when| - valid_statuses_for_when.each do |status_for_prior_stages| - context "when status for prior stages is #{status_for_prior_stages}" do - let(:current_status) { status_for_prior_stages } - - %w[created].each do |status| - context "when build status is #{status}" do - let(:build) { create(:ci_build, status.to_sym, :schedulable, user: user, project: project) } - - it 'enqueues the build' do - expect { subject }.to change { build.status }.to('scheduled') - end - end - end + context 'when build has always option' do + let(:build) { create(:ci_build, :created, when: :always, user: user, project: project) } - %w[manual skipped pending running success failed canceled scheduled].each do |status| - context "when build status is #{status}" do - let(:build) { create(:ci_build, status.to_sym, :schedulable, user: user, project: project) } + context 'when current status is success' do + let(:current_status) { 'success' } - it 'does not change the build status' do - expect { subject }.not_to change { build.status } - end - end - end + it 'changes the build status' do + expect { subject }.to change { build.status }.to('pending') end end - (HasStatus::AVAILABLE_STATUSES - valid_statuses_for_when).each do |status_for_prior_stages| - let(:current_status) { status_for_prior_stages } + context 'when current status is failed' do + let(:current_status) { 'failed' } - context "when status for prior stages is #{status_for_prior_stages}" do - %w[created pending].each do |status| - context "when build status is #{status}" do - let(:build) { create(:ci_build, status.to_sym, :schedulable, user: user, project: project) } - - it 'skips the build' do - expect { subject }.to change { build.status }.to('skipped') - end - end - end - - (HasStatus::AVAILABLE_STATUSES - %w[created pending]).each do |status| - context "when build status is #{status}" do - let(:build) { create(:ci_build, status.to_sym, :schedulable, user: user, project: project) } - - it 'does not change build status' do - expect { subject }.not_to change { build.status } - end - end - end + it 'does not change the build status' do + expect { subject }.to change { build.status }.to('pending') end end end - context 'when build has on_success option' do - let(:when_option) { :on_success } - - it_behaves_like 'Enqueuing properly', %w[success skipped] - end - - context 'when build has on_failure option' do - let(:when_option) { :on_failure } - - it_behaves_like 'Enqueuing properly', %w[failed] - end + context 'when build has manual option' do + let(:build) { create(:ci_build, :created, :actionable, user: user, project: project) } - context 'when build has always option' do - let(:when_option) { :always } + context 'when current status is success' do + let(:current_status) { 'success' } - it_behaves_like 'Enqueuing properly', %w[success failed skipped] - end + it 'changes the build status' do + expect { subject }.to change { build.status }.to('manual') + end + end - context 'when build has manual option' do - let(:when_option) { :manual } + context 'when current status is failed' do + let(:current_status) { 'failed' } - it_behaves_like 'Actionizing properly', %w[success skipped] + it 'does not change the build status' do + expect { subject }.to change { build.status }.to('skipped') + end + end end context 'when build has delayed option' do - let(:when_option) { :delayed } - before do allow(Ci::BuildScheduleWorker).to receive(:perform_at) { } end + let(:build) { create(:ci_build, :created, :schedulable, user: user, project: project) } + context 'when ci_enable_scheduled_build is enabled' do before do stub_feature_flags(ci_enable_scheduled_build: true) end - it_behaves_like 'Scheduling properly', %w[success skipped] + context 'when current status is success' do + let(:current_status) { 'success' } + + it 'changes the build status' do + expect { subject }.to change { build.status }.to('scheduled') + end + end + + context 'when current status is failed' do + let(:current_status) { 'failed' } + + it 'does not change the build status' do + expect { subject }.to change { build.status }.to('skipped') + end + end end - context 'when ci_enable_scheduled_build is enabled' do + context 'when ci_enable_scheduled_build is disabled' do before do stub_feature_flags(ci_enable_scheduled_build: false) end - it_behaves_like 'Actionizing properly', %w[success skipped] + context 'when current status is success' do + let(:current_status) { 'success' } + + it 'changes the build status' do + expect { subject }.to change { build.status }.to('manual') + end + end + + context 'when current status is failed' do + let(:current_status) { 'failed' } + + it 'does not change the build status' do + expect { subject }.to change { build.status }.to('skipped') + end + end end end end diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 642de81ed52..368abded448 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -27,6 +27,7 @@ describe Ci::RetryBuildService do job_artifacts_metadata job_artifacts_trace job_artifacts_junit job_artifacts_sast job_artifacts_dependency_scanning job_artifacts_container_scanning job_artifacts_dast + job_artifacts_license_management job_artifacts_performance job_artifacts_codequality scheduled_at].freeze IGNORE_ACCESSORS = diff --git a/spec/services/clusters/applications/create_service_spec.rb b/spec/services/clusters/applications/create_service_spec.rb new file mode 100644 index 00000000000..056db0c5486 --- /dev/null +++ b/spec/services/clusters/applications/create_service_spec.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Clusters::Applications::CreateService do + include TestRequestHelpers + + let(:cluster) { create(:cluster, :project, :provided_by_gcp) } + let(:user) { create(:user) } + let(:params) { { application: 'helm' } } + let(:service) { described_class.new(cluster, user, params) } + + describe '#execute' do + before do + allow(ClusterInstallAppWorker).to receive(:perform_async) + end + + subject { service.execute(test_request) } + + it 'creates an application' do + expect do + subject + + cluster.reload + end.to change(cluster, :application_helm) + end + + it 'schedules an install via worker' do + expect(ClusterInstallAppWorker).to receive(:perform_async).with('helm', anything).once + + subject + end + + context 'jupyter application' do + let(:params) do + { + application: 'jupyter', + hostname: 'example.com' + } + end + + before do + allow_any_instance_of(Clusters::Applications::ScheduleInstallationService).to receive(:execute) + end + + it 'creates the application' do + expect do + subject + + cluster.reload + end.to change(cluster, :application_jupyter) + end + + it 'sets the hostname' do + expect(subject.hostname).to eq('example.com') + end + + it 'sets the oauth_application' do + expect(subject.oauth_application).to be_present + end + end + + context 'invalid application' do + let(:params) { { application: 'non-existent' } } + + it 'raises an error' do + expect { subject }.to raise_error(Clusters::Applications::CreateService::InvalidApplicationError) + end + end + end +end diff --git a/spec/services/clusters/applications/schedule_installation_service_spec.rb b/spec/services/clusters/applications/schedule_installation_service_spec.rb index bca1e71bef2..21797edd533 100644 --- a/spec/services/clusters/applications/schedule_installation_service_spec.rb +++ b/spec/services/clusters/applications/schedule_installation_service_spec.rb @@ -10,14 +10,13 @@ describe Clusters::Applications::ScheduleInstallationService do expect(ClusterInstallAppWorker).not_to receive(:perform_async) count_before = count_scheduled - expect { service.execute(application) }.to raise_error(StandardError) + expect { service.execute }.to raise_error(StandardError) expect(count_scheduled).to eq(count_before) end end describe '#execute' do - let(:project) { double(:project) } - let(:service) { described_class.new(project, nil) } + let(:service) { described_class.new(application) } context 'when application is installable' do let(:application) { create(:clusters_applications_helm, :installable) } @@ -25,7 +24,7 @@ describe Clusters::Applications::ScheduleInstallationService do it 'make the application scheduled' do expect(ClusterInstallAppWorker).to receive(:perform_async).with(application.name, kind_of(Numeric)).once - expect { service.execute(application) }.to change { application.class.with_status(:scheduled).count }.by(1) + expect { service.execute }.to change { application.class.with_status(:scheduled).count }.by(1) end end diff --git a/spec/services/clusters/create_service_spec.rb b/spec/services/clusters/create_service_spec.rb index 1685dc748bd..3959295c13e 100644 --- a/spec/services/clusters/create_service_spec.rb +++ b/spec/services/clusters/create_service_spec.rb @@ -5,7 +5,7 @@ describe Clusters::CreateService do let(:project) { create(:project) } let(:user) { create(:user) } - subject { described_class.new(project, user, params).execute(access_token) } + subject { described_class.new(user, params).execute(project: project, access_token: access_token) } context 'when provider is gcp' do context 'when project has no clusters' do diff --git a/spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb b/spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb index 065d021db5e..b096f1fa4fb 100644 --- a/spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb +++ b/spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb @@ -16,7 +16,6 @@ describe Clusters::Gcp::Kubernetes::CreateServiceAccountService do let(:kubeclient) do Gitlab::Kubernetes::KubeClient.new( api_url, - ['api', 'apis/rbac.authorization.k8s.io'], auth_options: { username: username, password: password } ) end diff --git a/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb b/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb index c543de21d5b..2355827fa5a 100644 --- a/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb +++ b/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb @@ -11,7 +11,6 @@ describe Clusters::Gcp::Kubernetes::FetchKubernetesTokenService do let(:kubeclient) do Gitlab::Kubernetes::KubeClient.new( api_url, - ['api', 'apis/rbac.authorization.k8s.io'], auth_options: { username: username, password: password } ) end diff --git a/spec/services/clusters/update_service_spec.rb b/spec/services/clusters/update_service_spec.rb index 2d91a21035d..dcd75b6912d 100644 --- a/spec/services/clusters/update_service_spec.rb +++ b/spec/services/clusters/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Clusters::UpdateService do describe '#execute' do - subject { described_class.new(cluster.project, cluster.user, params).execute(cluster) } + subject { described_class.new(cluster.user, params).execute(cluster) } let(:cluster) { create(:cluster, :project, :provided_by_user) } diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb index 7c5c7409cc1..84cfa53ea05 100644 --- a/spec/services/groups/update_service_spec.rb +++ b/spec/services/groups/update_service_spec.rb @@ -24,6 +24,12 @@ describe Groups::UpdateService do expect(TodosDestroyer::GroupPrivateWorker).not_to receive(:perform_in) end + + it "returns false if save failed" do + allow(public_group).to receive(:save).and_return(false) + + expect(service.execute).to be_falsey + end end context "internal group with internal project" do diff --git a/spec/services/projects/after_rename_service_spec.rb b/spec/services/projects/after_rename_service_spec.rb new file mode 100644 index 00000000000..b4718a07204 --- /dev/null +++ b/spec/services/projects/after_rename_service_spec.rb @@ -0,0 +1,198 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Projects::AfterRenameService do + let(:rugged_config) { rugged_repo(project.repository).config } + + describe '#execute' do + context 'using legacy storage' do + let(:project) { create(:project, :repository, :legacy_storage) } + let(:gitlab_shell) { Gitlab::Shell.new } + let(:project_storage) { project.send(:storage) } + + before do + # Project#gitlab_shell returns a new instance of Gitlab::Shell on every + # call. This makes testing a bit easier. + allow(project).to receive(:gitlab_shell).and_return(gitlab_shell) + + allow(project) + .to receive(:previous_changes) + .and_return('path' => ['foo']) + + allow(project) + .to receive(:path_was) + .and_return('foo') + + stub_feature_flags(skip_hashed_storage_upgrade: false) + end + + it 'renames a repository' do + stub_container_registry_config(enabled: false) + + expect(gitlab_shell).to receive(:mv_repository) + .ordered + .with(project.repository_storage, "#{project.namespace.full_path}/foo", "#{project.full_path}") + .and_return(true) + + expect(gitlab_shell).to receive(:mv_repository) + .ordered + .with(project.repository_storage, "#{project.namespace.full_path}/foo.wiki", "#{project.full_path}.wiki") + .and_return(true) + + expect_any_instance_of(SystemHooksService) + .to receive(:execute_hooks_for) + .with(project, :rename) + + expect_any_instance_of(Gitlab::UploadsTransfer) + .to receive(:rename_project) + .with('foo', project.path, project.namespace.full_path) + + expect(project).to receive(:expire_caches_before_rename) + + described_class.new(project).execute + end + + context 'container registry with images' do + let(:container_repository) { create(:container_repository) } + + before do + stub_container_registry_config(enabled: true) + stub_container_registry_tags(repository: :any, tags: ['tag']) + project.container_repositories << container_repository + end + + it 'raises a RenameFailedError' do + expect { described_class.new(project).execute } + .to raise_error(described_class::RenameFailedError) + end + end + + context 'gitlab pages' do + before do + expect(project_storage).to receive(:rename_repo) { true } + end + + it 'moves pages folder to new location' do + expect_any_instance_of(Gitlab::PagesTransfer).to receive(:rename_project) + + described_class.new(project).execute + end + end + + context 'attachments' do + before do + expect(project_storage).to receive(:rename_repo) { true } + end + + it 'moves uploads folder to new location' do + expect_any_instance_of(Gitlab::UploadsTransfer).to receive(:rename_project) + + described_class.new(project).execute + end + end + + it 'updates project full path in .git/config' do + allow(project_storage).to receive(:rename_repo).and_return(true) + + described_class.new(project).execute + + expect(rugged_config['gitlab.fullpath']).to eq(project.full_path) + end + end + + context 'using hashed storage' do + let(:project) { create(:project, :repository, skip_disk_validation: true) } + let(:gitlab_shell) { Gitlab::Shell.new } + let(:hash) { Digest::SHA2.hexdigest(project.id.to_s) } + let(:hashed_prefix) { File.join('@hashed', hash[0..1], hash[2..3]) } + let(:hashed_path) { File.join(hashed_prefix, hash) } + + before do + # Project#gitlab_shell returns a new instance of Gitlab::Shell on every + # call. This makes testing a bit easier. + allow(project).to receive(:gitlab_shell).and_return(gitlab_shell) + allow(project).to receive(:previous_changes).and_return('path' => ['foo']) + + stub_feature_flags(skip_hashed_storage_upgrade: false) + stub_application_setting(hashed_storage_enabled: true) + end + + context 'migration to hashed storage' do + it 'calls HashedStorageMigrationService with correct options' do + project = create(:project, :repository, :legacy_storage) + allow(project).to receive(:previous_changes).and_return('path' => ['foo']) + + expect_next_instance_of(::Projects::HashedStorageMigrationService) do |service| + expect(service).to receive(:execute).and_return(true) + end + + described_class.new(project).execute + end + end + + it 'renames a repository' do + stub_container_registry_config(enabled: false) + + expect(gitlab_shell).not_to receive(:mv_repository) + + expect_any_instance_of(SystemHooksService) + .to receive(:execute_hooks_for) + .with(project, :rename) + + expect(project).to receive(:expire_caches_before_rename) + + described_class.new(project).execute + end + + context 'container registry with images' do + let(:container_repository) { create(:container_repository) } + + before do + stub_container_registry_config(enabled: true) + stub_container_registry_tags(repository: :any, tags: ['tag']) + project.container_repositories << container_repository + end + + it 'raises a RenameFailedError' do + expect { described_class.new(project).execute } + .to raise_error(described_class::RenameFailedError) + end + end + + context 'gitlab pages' do + it 'moves pages folder to new location' do + expect_any_instance_of(Gitlab::PagesTransfer).to receive(:rename_project) + + described_class.new(project).execute + end + end + + context 'attachments' do + it 'keeps uploads folder location unchanged' do + expect_any_instance_of(Gitlab::UploadsTransfer).not_to receive(:rename_project) + + described_class.new(project).execute + end + + context 'when not rolled out' do + let(:project) { create(:project, :repository, storage_version: 1, skip_disk_validation: true) } + + it 'moves pages folder to hashed storage' do + expect_next_instance_of(Projects::HashedStorage::MigrateAttachmentsService) do |service| + expect(service).to receive(:execute) + end + + described_class.new(project).execute + end + end + end + + it 'updates project full path in .git/config' do + described_class.new(project).execute + + expect(rugged_config['gitlab.fullpath']).to eq(project.full_path) + end + end + end +end diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb index a80c8a7fe51..08de27ca44a 100644 --- a/spec/services/projects/create_service_spec.rb +++ b/spec/services/projects/create_service_spec.rb @@ -295,6 +295,17 @@ describe Projects::CreateService, '#execute' do end end + it 'calls the passed block' do + fake_block = double('block') + opts[:relations_block] = fake_block + + expect_next_instance_of(Project) do |project| + expect(fake_block).to receive(:call).with(project) + end + + create_project(user, opts) + end + it 'writes project full path to .git/config' do project = create_project(user, opts) rugged = rugged_repo(project.repository) diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index beff499f2be..12ddf8447bd 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -65,10 +65,12 @@ describe Projects::DestroyService do context 'Sidekiq inline' do before do - # Run sidekiq immediatly to check that renamed repository will be removed + # Run sidekiq immediately to check that renamed repository will be removed perform_enqueued_jobs { destroy_project(project, user, {}) } end + it_behaves_like 'deleting the project' + context 'when has remote mirrors' do let!(:project) do create(:project, :repository, namespace: user.namespace).tap do |project| @@ -82,13 +84,28 @@ describe Projects::DestroyService do end end - it_behaves_like 'deleting the project' - it 'invalidates personal_project_count cache' do expect(user).to receive(:invalidate_personal_projects_count) destroy_project(project, user) end + + context 'when project has exports' do + let!(:project_with_export) do + create(:project, :repository, namespace: user.namespace).tap do |project| + create(:import_export_upload, + project: project, + export_file: fixture_file_upload('spec/fixtures/project_export.tar.gz')) + end + end + let!(:async) { true } + + it 'destroys project and export' do + expect { destroy_project(project_with_export, user) }.to change(ImportExportUpload, :count).by(-1) + + expect(Project.all).not_to include(project_with_export) + end + end end context 'Sidekiq fake' do @@ -242,7 +259,6 @@ describe Projects::DestroyService do before do project.lfs_objects << create(:lfs_object) - forked_project.forked_project_link.destroy forked_project.reload end diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb index 947cb61038d..a3d24ae312a 100644 --- a/spec/services/projects/fork_service_spec.rb +++ b/spec/services/projects/fork_service_spec.rb @@ -31,6 +31,10 @@ describe Projects::ForkService do it { is_expected.not_to be_persisted } it { expect(subject.errors[:forked_from_project_id]).to eq(['is forbidden']) } + + it 'does not create a fork network' do + expect { subject }.not_to change { @from_project.reload.fork_network } + end end describe "successfully creates project in the user namespace" do @@ -70,6 +74,12 @@ describe Projects::ForkService do expect(fork_network.root_project).to eq(@from_project) expect(fork_network.projects).to contain_exactly(@from_project, to_project) end + + it 'imports the repository of the forked project' do + to_project = fork_project(@from_project, @to_user, repository: true) + + expect(to_project.empty_repo?).to be_falsy + end end context 'creating a fork of a fork' do @@ -247,11 +257,13 @@ describe Projects::ForkService do context 'if project is not forked' do it 'creates fork relation' do - expect(fork_to_project.forked?).to be false + expect(fork_to_project.forked?).to be_falsy expect(forked_from_project(fork_to_project)).to be_nil subject.execute(fork_to_project) + fork_to_project.reload + expect(fork_to_project.forked?).to be true expect(forked_from_project(fork_to_project)).to eq fork_from_project expect(fork_to_project.forked_from_project).to eq fork_from_project @@ -272,6 +284,17 @@ describe Projects::ForkService do .to change { fork_to_project.lfs_objects_projects.count } .to(0) end + + context 'if the fork is not allowed' do + let(:fork_from_project) { create(:project, :private) } + + it 'does not delete the LFS objects' do + create(:lfs_objects_project, project: fork_to_project) + + expect { subject.execute(fork_to_project) } + .not_to change { fork_to_project.lfs_objects_projects.size } + end + end end end end diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb index e2a600d12d1..e6ffa2b957b 100644 --- a/spec/services/projects/import_service_spec.rb +++ b/spec/services/projects/import_service_spec.rb @@ -235,7 +235,7 @@ describe Projects::ImportService do result = described_class.new(project, user).execute expect(result[:status]).to eq :error - expect(result[:message]).to include('Only allowed ports are 22, 80, 443') + expect(result[:message]).to include('Only allowed ports are 80, 443') end end diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb index 3ec6139bfa6..014aab44281 100644 --- a/spec/services/projects/unlink_fork_service_spec.rb +++ b/spec/services/projects/unlink_fork_service_spec.rb @@ -5,13 +5,12 @@ describe Projects::UnlinkForkService do subject { described_class.new(forked_project, user) } - let(:fork_link) { forked_project.forked_project_link } let(:project) { create(:project, :public) } let(:forked_project) { fork_project(project, user) } let(:user) { create(:user) } context 'with opened merge request on the source project' do - let(:merge_request) { create(:merge_request, source_project: forked_project, target_project: fork_link.forked_from_project) } + let(:merge_request) { create(:merge_request, source_project: forked_project, target_project: forked_project.forked_from_project) } let(:merge_request2) { create(:merge_request, source_project: forked_project, target_project: fork_project(project)) } let(:merge_request_in_fork) { create(:merge_request, source_project: forked_project, target_project: forked_project) } @@ -35,12 +34,6 @@ describe Projects::UnlinkForkService do end end - it 'remove fork relation' do - expect(forked_project.forked_project_link).to receive(:destroy) - - subject.execute - end - it 'removes the link to the fork network' do expect(forked_project.fork_network_member).to be_present expect(forked_project.fork_network).to be_present diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index ac0ca1f33a5..41a170e4f25 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -380,6 +380,14 @@ describe QuickActions::InterpretService do end end + shared_examples 'assign command' do + it 'assigns to a single user' do + _, updates = service.execute(content, issuable) + + expect(updates).to eq(assignee_ids: [developer.id]) + end + end + it_behaves_like 'reopen command' do let(:content) { '/reopen' } let(:issuable) { issue } @@ -474,67 +482,56 @@ describe QuickActions::InterpretService do let(:issuable) { issue } end - context 'assign command' do - let(:content) { "/assign @#{developer.username}" } - - context 'Issue' do - it 'fetches assignee and populates assignee_ids if content contains /assign' do - _, updates = service.execute(content, issue) - - expect(updates[:assignee_ids]).to match_array([developer.id]) - end + context 'assign command with one user' do + it_behaves_like 'assign command' do + let(:content) { "/assign @#{developer.username}" } + let(:issuable) { issue } end - context 'Merge Request' do - it 'fetches assignee and populates assignee_ids if content contains /assign' do - _, updates = service.execute(content, merge_request) - - expect(updates).to eq(assignee_ids: [developer.id]) - end + it_behaves_like 'assign command' do + let(:content) { "/assign @#{developer.username}" } + let(:issuable) { merge_request } end end + # CE does not have multiple assignees context 'assign command with multiple assignees' do - let(:content) { "/assign @#{developer.username} @#{developer2.username}" } - before do project.add_developer(developer2) end - context 'Issue' do - it 'fetches assignee and populates assignee_ids if content contains /assign' do - _, updates = service.execute(content, issue) - - expect(updates[:assignee_ids]).to match_array([developer.id]) - end + it_behaves_like 'assign command' do + let(:content) { "/assign @#{developer.username} @#{developer2.username}" } + let(:issuable) { issue } end - context 'Merge Request' do - it 'fetches assignee and populates assignee_ids if content contains /assign' do - _, updates = service.execute(content, merge_request) - - expect(updates).to eq(assignee_ids: [developer.id]) - end + it_behaves_like 'assign command' do + let(:content) { "/assign @#{developer.username} @#{developer2.username}" } + let(:issuable) { merge_request } end end context 'assign command with me alias' do - let(:content) { "/assign me" } - - context 'Issue' do - it 'fetches assignee and populates assignee_ids if content contains /assign' do - _, updates = service.execute(content, issue) + it_behaves_like 'assign command' do + let(:content) { '/assign me' } + let(:issuable) { issue } + end - expect(updates).to eq(assignee_ids: [developer.id]) - end + it_behaves_like 'assign command' do + let(:content) { '/assign me' } + let(:issuable) { merge_request } end + end - context 'Merge Request' do - it 'fetches assignee and populates assignee_ids if content contains /assign' do - _, updates = service.execute(content, merge_request) + context 'assign command with me alias and whitespace' do + it_behaves_like 'assign command' do + let(:content) { '/assign me ' } + let(:issuable) { issue } + end - expect(updates).to eq(assignee_ids: [developer.id]) - end + it_behaves_like 'assign command' do + let(:content) { '/assign me ' } + let(:issuable) { merge_request } end end diff --git a/spec/services/resource_events/merge_into_notes_service_spec.rb b/spec/services/resource_events/merge_into_notes_service_spec.rb index 0d333d541c9..c76f6e6f77e 100644 --- a/spec/services/resource_events/merge_into_notes_service_spec.rb +++ b/spec/services/resource_events/merge_into_notes_service_spec.rb @@ -66,5 +66,14 @@ describe ResourceEvents::MergeIntoNotesService do expect(notes.count).to eq 1 expect(notes.first.discussion_id).to eq event.discussion_id end + + it "preloads the note author's status" do + event = create_event(created_at: time) + create(:user_status, user: event.user) + + notes = described_class.new(resource, user).execute + + expect(notes.first.author.association(:status)).to be_loaded + end end end diff --git a/spec/services/web_hook_service_spec.rb b/spec/services/web_hook_service_spec.rb index 622e56e1da5..b1cc6d2eb83 100644 --- a/spec/services/web_hook_service_spec.rb +++ b/spec/services/web_hook_service_spec.rb @@ -97,7 +97,7 @@ describe WebHookService do end it 'handles exceptions' do - exceptions = [SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Net::OpenTimeout, Net::ReadTimeout, Gitlab::HTTP::BlockedUrlError] + exceptions = [SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Net::OpenTimeout, Net::ReadTimeout, Gitlab::HTTP::BlockedUrlError, Gitlab::HTTP::RedirectionTooDeep] exceptions.each do |exception_class| exception = exception_class.new('Exception message') |