summaryrefslogtreecommitdiff
path: root/spec/services
diff options
context:
space:
mode:
Diffstat (limited to 'spec/services')
-rw-r--r--spec/services/application_settings/update_service_spec.rb3
-rw-r--r--spec/services/applications/create_service_spec.rb13
-rw-r--r--spec/services/audit_event_service_spec.rb26
-rw-r--r--spec/services/boards/visits/create_service_spec.rb53
-rw-r--r--spec/services/boards/visits/latest_service_spec.rb47
-rw-r--r--spec/services/ci/process_build_service_spec.rb232
-rw-r--r--spec/services/ci/retry_build_service_spec.rb1
-rw-r--r--spec/services/clusters/applications/create_service_spec.rb71
-rw-r--r--spec/services/clusters/applications/schedule_installation_service_spec.rb7
-rw-r--r--spec/services/clusters/create_service_spec.rb2
-rw-r--r--spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb1
-rw-r--r--spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb1
-rw-r--r--spec/services/clusters/update_service_spec.rb2
-rw-r--r--spec/services/groups/update_service_spec.rb6
-rw-r--r--spec/services/projects/after_rename_service_spec.rb198
-rw-r--r--spec/services/projects/create_service_spec.rb11
-rw-r--r--spec/services/projects/destroy_service_spec.rb24
-rw-r--r--spec/services/projects/fork_service_spec.rb25
-rw-r--r--spec/services/projects/import_service_spec.rb2
-rw-r--r--spec/services/projects/unlink_fork_service_spec.rb9
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb79
-rw-r--r--spec/services/resource_events/merge_into_notes_service_spec.rb9
-rw-r--r--spec/services/web_hook_service_spec.rb2
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')