diff options
Diffstat (limited to 'spec/services')
542 files changed, 6201 insertions, 1940 deletions
diff --git a/spec/services/access_token_validation_service_spec.rb b/spec/services/access_token_validation_service_spec.rb index b2a8da6c4c6..2bf74d64dc9 100644 --- a/spec/services/access_token_validation_service_spec.rb +++ b/spec/services/access_token_validation_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe AccessTokenValidationService do +RSpec.describe AccessTokenValidationService do describe ".include_any_scope?" do let(:request) { double("request") } diff --git a/spec/services/alert_management/alerts/todo/create_service_spec.rb b/spec/services/alert_management/alerts/todo/create_service_spec.rb new file mode 100644 index 00000000000..e3d9de8b4df --- /dev/null +++ b/spec/services/alert_management/alerts/todo/create_service_spec.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe AlertManagement::Alerts::Todo::CreateService do + let_it_be(:user) { create(:user) } + let_it_be(:alert) { create(:alert_management_alert) } + + let(:current_user) { user } + + describe '#execute' do + subject(:result) { AlertManagement::Alerts::Todo::CreateService.new(alert, current_user).execute } + + shared_examples 'permissions error' do + it 'returns an error', :aggregate_failures do + expect(result.error?).to be(true) + expect(result.message).to eq('You have insufficient permissions to create a Todo for this alert') + expect(result.payload[:todo]).to be(nil) + expect(result.payload[:alert]).to be(alert) + end + end + + context 'when the user is anonymous' do + let(:current_user) { nil } + + it_behaves_like 'permissions error' + end + + context 'when the user does not have permission' do + it_behaves_like 'permissions error' + end + + context 'when user has permission' do + before do + alert.project.add_developer(user) + end + + it 'creates a todo' do + expect { result }.to change { Todo.count }.by(1) + end + + it 'returns the alert and todo in the payload', :aggregate_failures do + expect(result.success?).to be(true) + expect(result.payload[:alert][:id]).to be(alert.id) + expect(result.payload[:todo][:id]).to be(Todo.last.id) + end + + context 'when the user has a marked todo for the alert' do + let_it_be(:todo_params) do + { project: alert.project, + target: alert, + user: user, + action: Todo::MARKED } + end + + context 'when todo is pending' do + before_all do + create(:todo, :pending, **todo_params) + end + + it 'does not create a todo' do + expect { result }.not_to change { Todo.count } + end + + it 'returns an error', :aggregate_failures do + expect(result.error?).to be(true) + expect(result.message).to be('You already have pending todo for this alert') + expect(result.payload[:todo]).to be(nil) + expect(result.payload[:alert]).to be(alert) + end + end + + context 'when todo is done' do + before do + create(:todo, :done, **todo_params) + end + + it { expect(result.success?).to be(true) } + it { expect { result }.to change { Todo.count }.by(1) } + end + end + end + end +end diff --git a/spec/services/alert_management/alerts/update_service_spec.rb b/spec/services/alert_management/alerts/update_service_spec.rb index e185e67c5cf..91b02325bad 100644 --- a/spec/services/alert_management/alerts/update_service_spec.rb +++ b/spec/services/alert_management/alerts/update_service_spec.rb @@ -2,11 +2,12 @@ require 'spec_helper' -describe AlertManagement::Alerts::UpdateService do +RSpec.describe AlertManagement::Alerts::UpdateService do let_it_be(:user_with_permissions) { create(:user) } + let_it_be(:other_user_with_permissions) { create(:user) } let_it_be(:user_without_permissions) { create(:user) } - let_it_be(:alert, reload: true) { create(:alert_management_alert) } - let_it_be(:project) { alert.project } + let_it_be(:project) { create(:project) } + let_it_be(:alert, reload: true) { create(:alert_management_alert, :triggered, project: project) } let(:current_user) { user_with_permissions } let(:params) { {} } @@ -15,119 +16,225 @@ describe AlertManagement::Alerts::UpdateService do before_all do project.add_developer(user_with_permissions) + project.add_developer(other_user_with_permissions) end describe '#execute' do + shared_examples 'does not add a todo' do + specify { expect { response }.not_to change(Todo, :count) } + end + + shared_examples 'does not add a system note' do + specify { expect { response }.not_to change(Note, :count) } + end + + shared_examples 'adds a system note' do + specify { expect { response }.to change { alert.reload.notes.count }.by(1) } + end + + shared_examples 'error response' do |message| + it_behaves_like 'does not add a todo' + it_behaves_like 'does not add a system note' + + it 'has an informative message' do + expect(response).to be_error + expect(response.message).to eq(message) + end + end + subject(:response) { service.execute } context 'when the current_user is nil' do let(:current_user) { nil } - it 'results in an error' do - expect(response).to be_error - expect(response.message).to eq('You have no permissions') - end + it_behaves_like 'error response', 'You have no permissions' end - context 'when user does not have permission to update alerts' do + context 'when current_user does not have permission to update alerts' do let(:current_user) { user_without_permissions } - it 'results in an error' do - expect(response).to be_error - expect(response.message).to eq('You have no permissions') - end + it_behaves_like 'error response', 'You have no permissions' end context 'when no parameters are included' do - it 'results in an error' do - expect(response).to be_error - expect(response.message).to eq('Please provide attributes to update') - end + it_behaves_like 'error response', 'Please provide attributes to update' end - context 'when an error occures during update' do + context 'when an error occurs during update' do let(:params) { { title: nil } } - it 'results in an error' do - expect { response }.not_to change { alert.reload.notes.count } - expect(response).to be_error - expect(response.message).to eq("Title can't be blank") - end + it_behaves_like 'error response', "Title can't be blank" end - context 'when a model attribute is included without assignees' do - let(:params) { { title: 'This is an updated alert.' } } + shared_examples 'title update' do + it_behaves_like 'does not add a todo' + it_behaves_like 'does not add a system note' it 'updates the attribute' do original_title = alert.title - expect { response }.to change { alert.title }.from(original_title).to(params[:title]) + expect { response }.to change { alert.title }.from(original_title).to(expected_title) expect(response).to be_success end + end - it 'skips adding a todo' do - expect { response }.not_to change(Todo, :count) - end + context 'when a model attribute is included without assignees' do + let(:params) { { title: 'This is an updated alert.' } } + let(:expected_title) { params[:title] } + + it_behaves_like 'title update' + end + + context 'when alert is resolved and another existing open alert' do + let!(:alert) { create(:alert_management_alert, :resolved, project: project) } + let!(:existing_alert) { create(:alert_management_alert, :triggered, project: project) } + + let(:params) { { title: 'This is an updated alert.' } } + let(:expected_title) { params[:title] } + + it_behaves_like 'title update' end context 'when assignees are included' do - let(:params) { { assignees: [user_with_permissions] } } + shared_examples 'adds a todo' do + let(:assignee) { expected_assignees.first } - after do - alert.assignees = [] + specify do + expect { response }.to change { assignee.reload.todos.count }.by(1) + expect(assignee.todos.last.author).to eq(current_user) + end end - it 'assigns the user' do - expect { response }.to change { alert.reload.assignees }.from([]).to(params[:assignees]) - expect(response).to be_success + shared_examples 'successful assignment' do + it_behaves_like 'adds a system note' + it_behaves_like 'adds a todo' + + after do + alert.assignees = [] + end + + specify do + expect { response }.to change { alert.reload.assignees }.from([]).to(expected_assignees) + expect(response).to be_success + end + end + + let(:expected_assignees) { params[:assignees] } + + context 'when the assignee is the current user' do + let(:params) { { assignees: [current_user] } } + + it_behaves_like 'successful assignment' end - it 'creates a system note for the assignment' do - expect { response }.to change { alert.reload.notes.count }.by(1) + context 'when the assignee has read permissions' do + let(:params) { { assignees: [other_user_with_permissions] } } + + it_behaves_like 'successful assignment' end - it 'adds a todo' do - expect { response }.to change { Todo.where(user: user_with_permissions).count }.by(1) + context 'when the assignee does not have read permissions' do + let(:params) { { assignees: [user_without_permissions] } } + + it_behaves_like 'error response', 'Assignee has no permissions' end - context 'when current user is not the assignee' do - let(:assignee_user) { create(:user) } - let(:params) { { assignees: [assignee_user] } } + context 'when user is already assigned' do + let(:params) { { assignees: [user_with_permissions] } } - it 'skips adding todo for assignee without permission to read alert' do - expect { response }.not_to change(Todo, :count) + before do + alert.assignees << user_with_permissions end - context 'when assignee has read permission' do - before do - project.add_developer(assignee_user) - end + it_behaves_like 'does not add a system note' + # TODO: We should not add another todo in this scenario + it_behaves_like 'adds a todo' + end - it 'adds a todo' do - response + context 'with multiple users included' do + let(:params) { { assignees: [user_with_permissions, user_without_permissions] } } + let(:expected_assignees) { [user_with_permissions] } - expect(Todo.first.author).to eq(current_user) - end + it_behaves_like 'successful assignment' + end + end + + context 'when a status is included' do + let(:params) { { status: new_status } } + let(:new_status) { AlertManagement::Alert::STATUSES[:acknowledged] } + + it 'successfully changes the status' do + expect { response }.to change { alert.acknowledged? }.to(true) + expect(response).to be_success + expect(response.payload[:alert]).to eq(alert) + end + + it_behaves_like 'adds a system note' + + context 'with unknown status' do + let(:new_status) { -1 } + + it_behaves_like 'error response', 'Invalid status' + end + + context 'with resolving status' do + let(:new_status) { AlertManagement::Alert::STATUSES[:resolved] } + + it 'changes the status' do + expect { response }.to change { alert.resolved? }.to(true) + end + + it "resolves the current user's related todos" do + todo = create(:todo, :pending, target: alert, user: current_user, project: alert.project) + + expect { response }.to change { todo.reload.state }.from('pending').to('done') + end + end + + context 'with an opening status and existing open alert' do + let_it_be(:alert) { create(:alert_management_alert, :resolved, :with_fingerprint, project: project) } + let_it_be(:existing_alert) { create(:alert_management_alert, :triggered, fingerprint: alert.fingerprint, project: project) } + let_it_be(:url) { Gitlab::Routing.url_helpers.details_project_alert_management_path(project, existing_alert) } + let_it_be(:link) { ActionController::Base.helpers.link_to(_('alert'), url) } + + let(:message) do + "An #{link} with the same fingerprint is already open. " \ + 'To change the status of this alert, resolve the linked alert.' end - context 'when current_user is nil' do - let(:current_user) { nil } + it_behaves_like 'does not add a todo' + it_behaves_like 'does not add a system note' + + it 'has an informative message' do + expect(response).to be_error + expect(response.message).to eq(message) + end - it 'skips adding todo if current_user is nil' do - project.add_developer(assignee_user) + context 'fingerprints are blank' do + let_it_be(:alert) { create(:alert_management_alert, :resolved, project: project, fingerprint: nil) } + let_it_be(:existing_alert) { create(:alert_management_alert, :triggered, fingerprint: alert.fingerprint, project: project) } - expect { response }.not_to change(Todo, :count) + it 'successfully changes the status' do + expect { response }.to change { alert.acknowledged? }.to(true) + expect(response).to be_success + expect(response.payload[:alert]).to eq(alert) end + + it_behaves_like 'adds a system note' end end - context 'with multiple users included' do - let(:params) { { assignees: [user_with_permissions, user_without_permissions] } } + context 'two existing closed alerts' do + let_it_be(:alert) { create(:alert_management_alert, :resolved, :with_fingerprint, project: project) } + let_it_be(:existing_alert) { create(:alert_management_alert, :resolved, fingerprint: alert.fingerprint, project: project) } - it 'assigns the first permissioned user' do - expect { response }.to change { alert.reload.assignees }.from([]).to([user_with_permissions]) + it 'successfully changes the status' do + expect { response }.to change { alert.acknowledged? }.to(true) expect(response).to be_success + expect(response.payload[:alert]).to eq(alert) end + + it_behaves_like 'adds a system note' end end end diff --git a/spec/services/alert_management/create_alert_issue_service_spec.rb b/spec/services/alert_management/create_alert_issue_service_spec.rb index 9bc8b731dc1..a8f2b4ee09c 100644 --- a/spec/services/alert_management/create_alert_issue_service_spec.rb +++ b/spec/services/alert_management/create_alert_issue_service_spec.rb @@ -4,19 +4,18 @@ require 'spec_helper' RSpec.describe AlertManagement::CreateAlertIssueService do let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project) } + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } let_it_be(:payload) do { - 'annotations' => { - 'title' => 'Alert title' - }, 'startsAt' => '2020-04-27T10:10:22.265949279Z', 'generatorURL' => 'http://8d467bd4607a:9090/graph?g0.expr=vector%281%29&g0.tab=1' } end let_it_be(:generic_alert, reload: true) { create(:alert_management_alert, :triggered, project: project, payload: payload) } - let_it_be(:prometheus_alert) { create(:alert_management_alert, :triggered, :prometheus, project: project, payload: payload) } + let_it_be(:prometheus_alert, reload: true) { create(:alert_management_alert, :triggered, :prometheus, project: project, payload: payload) } let(:alert) { generic_alert } + let(:alert_presenter) { alert.present } let(:created_issue) { Issue.last! } describe '#execute' do @@ -29,7 +28,7 @@ RSpec.describe AlertManagement::CreateAlertIssueService do .and_return(can_create) end - shared_examples 'creating an alert' do + shared_examples 'creating an alert issue' do it 'creates an issue' do expect { execute }.to change { project.issues.count }.by(1) end @@ -48,11 +47,27 @@ RSpec.describe AlertManagement::CreateAlertIssueService do expect(alert.reload.issue_id).to eq(created_issue.id) end - it 'sets issue author to the current user' do + it 'creates a system note' do + expect { execute }.to change { alert.reload.notes.count }.by(1) + end + end + + shared_examples 'setting an issue attributes' do + before do execute + end + it 'sets issue author to the current user' do expect(created_issue.author).to eq(user) end + + it 'sets the issue title' do + expect(created_issue.title).to eq(alert.title) + end + + it 'sets the issue description' do + expect(created_issue.description).to include(alert_presenter.issue_summary_markdown.strip) + end end context 'when a user is allowed to create an issue' do @@ -69,27 +84,33 @@ RSpec.describe AlertManagement::CreateAlertIssueService do context 'when the alert is prometheus alert' do let(:alert) { prometheus_alert } + let(:issue) { subject.payload[:issue] } - it_behaves_like 'creating an alert' + it_behaves_like 'creating an alert issue' + it_behaves_like 'setting an issue attributes' + it_behaves_like 'create alert issue sets issue labels' end context 'when the alert is generic' do let(:alert) { generic_alert } + let(:issue) { subject.payload[:issue] } - it_behaves_like 'creating an alert' + it_behaves_like 'creating an alert issue' + it_behaves_like 'setting an issue attributes' + it_behaves_like 'create alert issue sets issue labels' end context 'when issue cannot be created' do - let(:alert) { prometheus_alert } + let(:alert) { generic_alert } before do - # set invalid payload for Prometheus alert - alert.update!(payload: {}) + # Invalid alert + alert.update_columns(title: '') end it 'has an unsuccessful status' do expect(execute).to be_error - expect(execute.message).to eq('invalid alert') + expect(execute.message).to eq("Title can't be blank") end end diff --git a/spec/services/alert_management/process_prometheus_alert_service_spec.rb b/spec/services/alert_management/process_prometheus_alert_service_spec.rb index 5b4da5e9077..0ce88f6b5b7 100644 --- a/spec/services/alert_management/process_prometheus_alert_service_spec.rb +++ b/spec/services/alert_management/process_prometheus_alert_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe AlertManagement::ProcessPrometheusAlertService do - let_it_be(:project) { create(:project) } + let_it_be(:project) { create(:project, :repository) } before do allow(ProjectServiceWorker).to receive(:perform_async) @@ -35,26 +35,31 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do } end - context 'when Prometheus alert status is firing' do - let(:status) { 'firing' } + let(:status) { 'firing' } + context 'when Prometheus alert status is firing' do context 'when alert with the same fingerprint already exists' do - let!(:alert) { create(:alert_management_alert, :resolved, project: project, fingerprint: parsed_alert.gitlab_fingerprint) } + let!(:alert) { create(:alert_management_alert, project: project, fingerprint: parsed_alert.gitlab_fingerprint) } + + it_behaves_like 'adds an alert management alert event' + + context 'existing alert is resolved' do + let!(:alert) { create(:alert_management_alert, :resolved, project: project, fingerprint: parsed_alert.gitlab_fingerprint) } - it 'increases alert events count' do - expect { execute }.to change { alert.reload.events }.by(1) + it_behaves_like 'creates an alert management alert' end - context 'when status can be changed' do - it 'changes status to triggered' do - expect { execute }.to change { alert.reload.triggered? }.to(true) - end + context 'existing alert is ignored' do + let!(:alert) { create(:alert_management_alert, :ignored, project: project, fingerprint: parsed_alert.gitlab_fingerprint) } + + it_behaves_like 'adds an alert management alert event' end - it 'does not executes the alert service hooks' do - expect(alert).not_to receive(:execute_services) + context 'two existing alerts, one resolved one open' do + let!(:resolved_alert) { create(:alert_management_alert, :resolved, project: project, fingerprint: parsed_alert.gitlab_fingerprint) } + let!(:alert) { create(:alert_management_alert, project: project, fingerprint: parsed_alert.gitlab_fingerprint) } - subject + it_behaves_like 'adds an alert management alert event' end context 'when status change did not succeed' do @@ -73,23 +78,11 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do execute end end - - it { is_expected.to be_success } end context 'when alert does not exist' do context 'when alert can be created' do - it 'creates a new alert' do - expect { execute }.to change { AlertManagement::Alert.where(project: project).count }.by(1) - end - - it 'executes the alert service hooks' do - slack_service = create(:service, type: 'SlackService', project: project, alert_events: true, active: true) - - subject - - expect(ProjectServiceWorker).to have_received(:perform_async).with(slack_service.id, an_instance_of(Hash)) - end + it_behaves_like 'creates an alert management alert' end context 'when alert cannot be created' do @@ -123,6 +116,31 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do it 'resolves an existing alert' do expect { execute }.to change { alert.reload.resolved? }.to(true) end + + [true, false].each do |state_tracking_enabled| + context 'existing issue' do + before do + stub_feature_flags(track_resource_state_change_events: state_tracking_enabled) + end + + let!(:alert) { create(:alert_management_alert, :with_issue, project: project, fingerprint: parsed_alert.gitlab_fingerprint) } + + it 'closes the issue' do + issue = alert.issue + + expect { execute } + .to change { issue.reload.state } + .from('opened') + .to('closed') + end + + if state_tracking_enabled + specify { expect { execute }.to change(ResourceStateEvent, :count).by(1) } + else + specify { expect { execute }.to change(Note, :count).by(1) } + end + end + end end context 'when status change did not succeed' do @@ -144,6 +162,33 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do it { is_expected.to be_success } end + + context 'environment given' do + let(:environment) { create(:environment, project: project) } + + it 'sets the environment' do + payload['labels']['gitlab_environment_name'] = environment.name + execute + + alert = project.alert_management_alerts.last + + expect(alert.environment).to eq(environment) + end + end + + context 'prometheus alert given' do + let(:prometheus_alert) { create(:prometheus_alert, project: project) } + + it 'sets the prometheus alert and environment' do + payload['labels']['gitlab_alert_id'] = prometheus_alert.prometheus_metric_id + execute + + alert = project.alert_management_alerts.last + + expect(alert.prometheus_alert).to eq(prometheus_alert) + expect(alert.environment).to eq(prometheus_alert.environment) + end + end end context 'when alert payload is invalid' do diff --git a/spec/services/alert_management/update_alert_status_service_spec.rb b/spec/services/alert_management/update_alert_status_service_spec.rb deleted file mode 100644 index b287d0d1614..00000000000 --- a/spec/services/alert_management/update_alert_status_service_spec.rb +++ /dev/null @@ -1,66 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe AlertManagement::UpdateAlertStatusService do - let(:project) { alert.project } - let_it_be(:user) { build(:user) } - - let_it_be(:alert, reload: true) do - create(:alert_management_alert, :triggered) - end - - let(:service) { described_class.new(alert, user, new_status) } - - describe '#execute' do - shared_examples 'update failure' do |error_message| - it 'returns an error' do - expect(response).to be_error - expect(response.message).to eq(error_message) - expect(response.payload[:alert]).to eq(alert) - end - - it 'does not update the status' do - expect { response }.not_to change { alert.status } - end - end - - let(:new_status) { Types::AlertManagement::StatusEnum.values['ACKNOWLEDGED'].value } - let(:can_update) { true } - - subject(:response) { service.execute } - - before do - allow(user).to receive(:can?) - .with(:update_alert_management_alert, project) - .and_return(can_update) - end - - it 'returns success' do - expect(response).to be_success - expect(response.payload[:alert]).to eq(alert) - end - - it 'updates the status' do - expect { response }.to change { alert.acknowledged? }.to(true) - end - - context 'when user has no permissions' do - let(:can_update) { false } - - include_examples 'update failure', _('You have no permissions') - end - - context 'with no status' do - let(:new_status) { nil } - - include_examples 'update failure', _('Invalid status') - end - - context 'with unknown status' do - let(:new_status) { -1 } - - include_examples 'update failure', _('Invalid status') - end - end -end diff --git a/spec/services/application_settings/update_service_spec.rb b/spec/services/application_settings/update_service_spec.rb index 3a37cbc3522..e5060fa2eeb 100644 --- a/spec/services/application_settings/update_service_spec.rb +++ b/spec/services/application_settings/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ApplicationSettings::UpdateService do +RSpec.describe ApplicationSettings::UpdateService do include ExternalAuthorizationServiceHelpers let(:application_settings) { create(:application_setting) } diff --git a/spec/services/applications/create_service_spec.rb b/spec/services/applications/create_service_spec.rb index c8134087fa1..58ac723ee55 100644 --- a/spec/services/applications/create_service_spec.rb +++ b/spec/services/applications/create_service_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -describe ::Applications::CreateService do +RSpec.describe ::Applications::CreateService do include TestRequestHelpers let(:user) { create(:user) } diff --git a/spec/services/audit_event_service_spec.rb b/spec/services/audit_event_service_spec.rb index dc86735805c..530d3469481 100644 --- a/spec/services/audit_event_service_spec.rb +++ b/spec/services/audit_event_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe AuditEventService do +RSpec.describe AuditEventService do let(:project) { create(:project) } let(:user) { create(:user, :with_sign_ins) } let(:project_member) { create(:project_member, user: user) } @@ -17,6 +17,7 @@ describe AuditEventService do it 'creates an event and logs to a file' do expect(service).to receive(:file_logger).and_return(logger) expect(logger).to receive(:info).with(author_id: user.id, + author_name: user.name, entity_id: project.id, entity_type: "Project", action: :destroy) @@ -35,6 +36,7 @@ describe AuditEventService do }) expect(service).to receive(:file_logger).and_return(logger) expect(logger).to receive(:info).with(author_id: user.id, + author_name: user.name, entity_type: 'Project', entity_id: project.id, from: 'true', @@ -56,6 +58,7 @@ describe AuditEventService do it 'logs security event to file' do expect(service).to receive(:file_logger).and_return(logger) expect(logger).to receive(:info).with(author_id: user.id, + author_name: user.name, entity_type: 'Project', entity_id: project.id, action: :destroy) diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb index 70eb35f0826..8d58c4b27e1 100644 --- a/spec/services/auth/container_registry_authentication_service_spec.rb +++ b/spec/services/auth/container_registry_authentication_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Auth::ContainerRegistryAuthenticationService do +RSpec.describe Auth::ContainerRegistryAuthenticationService do let(:current_project) { nil } let(:current_user) { nil } let(:current_params) { {} } diff --git a/spec/services/authorized_project_update/periodic_recalculate_service_spec.rb b/spec/services/authorized_project_update/periodic_recalculate_service_spec.rb index 020056da36e..c776e013fdf 100644 --- a/spec/services/authorized_project_update/periodic_recalculate_service_spec.rb +++ b/spec/services/authorized_project_update/periodic_recalculate_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe AuthorizedProjectUpdate::PeriodicRecalculateService do +RSpec.describe AuthorizedProjectUpdate::PeriodicRecalculateService do subject(:service) { described_class.new } describe '#execute' do diff --git a/spec/services/authorized_project_update/project_create_service_spec.rb b/spec/services/authorized_project_update/project_create_service_spec.rb index 5b3e36af766..891800bfb87 100644 --- a/spec/services/authorized_project_update/project_create_service_spec.rb +++ b/spec/services/authorized_project_update/project_create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe AuthorizedProjectUpdate::ProjectCreateService do +RSpec.describe AuthorizedProjectUpdate::ProjectCreateService do let_it_be(:group_parent) { create(:group, :private) } let_it_be(:group) { create(:group, :private, parent: group_parent) } let_it_be(:group_child) { create(:group, :private, parent: group) } diff --git a/spec/services/authorized_project_update/project_group_link_create_service_spec.rb b/spec/services/authorized_project_update/project_group_link_create_service_spec.rb new file mode 100644 index 00000000000..d30d9f1e766 --- /dev/null +++ b/spec/services/authorized_project_update/project_group_link_create_service_spec.rb @@ -0,0 +1,190 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe AuthorizedProjectUpdate::ProjectGroupLinkCreateService do + let_it_be(:group_parent) { create(:group, :private) } + let_it_be(:group) { create(:group, :private, parent: group_parent) } + let_it_be(:group_child) { create(:group, :private, parent: group) } + + let_it_be(:parent_group_user) { create(:user) } + let_it_be(:group_user) { create(:user) } + + let_it_be(:project) { create(:project, :private, group: create(:group, :private)) } + + let(:access_level) { Gitlab::Access::MAINTAINER } + + subject(:service) { described_class.new(project, group) } + + describe '#perform' do + context 'direct group members' do + before do + create(:group_member, access_level: access_level, group: group, user: group_user) + ProjectAuthorization.delete_all + end + + it 'creates project authorization' do + expect { service.execute }.to( + change { ProjectAuthorization.count }.from(0).to(1)) + + project_authorization = ProjectAuthorization.where( + project_id: project.id, + user_id: group_user.id, + access_level: access_level) + + expect(project_authorization).to exist + end + end + + context 'inherited group members' do + before do + create(:group_member, access_level: access_level, group: group_parent, user: parent_group_user) + ProjectAuthorization.delete_all + end + + it 'creates project authorization' do + expect { service.execute }.to( + change { ProjectAuthorization.count }.from(0).to(1)) + + project_authorization = ProjectAuthorization.where( + project_id: project.id, + user_id: parent_group_user.id, + access_level: access_level) + expect(project_authorization).to exist + end + end + + context 'membership overrides' do + before do + create(:group_member, access_level: Gitlab::Access::REPORTER, group: group_parent, user: group_user) + create(:group_member, access_level: Gitlab::Access::DEVELOPER, group: group, user: group_user) + ProjectAuthorization.delete_all + end + + it 'creates project authorization' do + expect { service.execute }.to( + change { ProjectAuthorization.count }.from(0).to(1)) + + project_authorization = ProjectAuthorization.where( + project_id: project.id, + user_id: group_user.id, + access_level: Gitlab::Access::DEVELOPER) + expect(project_authorization).to exist + end + end + + context 'no group member' do + it 'does not create project authorization' do + expect { service.execute }.not_to( + change { ProjectAuthorization.count }.from(0)) + end + end + + context 'unapproved access requests' do + before do + create(:group_member, :guest, :access_request, user: group_user, group: group) + end + + it 'does not create project authorization' do + expect { service.execute }.not_to( + change { ProjectAuthorization.count }.from(0)) + end + end + + context 'project has more users than BATCH_SIZE' do + let(:batch_size) { 2 } + let(:users) { create_list(:user, batch_size + 1 ) } + + before do + stub_const("#{described_class.name}::BATCH_SIZE", batch_size) + + users.each do |user| + create(:group_member, access_level: access_level, group: group_parent, user: user) + end + + ProjectAuthorization.delete_all + end + + it 'bulk creates project authorizations in batches' do + users.each_slice(batch_size) do |batch| + attributes = batch.map do |user| + { user_id: user.id, project_id: project.id, access_level: access_level } + end + + expect(ProjectAuthorization).to( + receive(:insert_all).with(array_including(attributes)).and_call_original) + end + + expect { service.execute }.to( + change { ProjectAuthorization.count }.from(0).to(batch_size + 1)) + end + end + + context 'users have existing project authorizations' do + before do + create(:group_member, access_level: access_level, group: group, user: group_user) + ProjectAuthorization.delete_all + + create(:project_authorization, user_id: group_user.id, + project_id: project.id, + access_level: existing_access_level) + end + + context 'when access level is the same' do + let(:existing_access_level) { access_level } + + it 'does not create project authorization' do + project_authorization = ProjectAuthorization.where( + project_id: project.id, + user_id: group_user.id, + access_level: existing_access_level) + + expect(ProjectAuthorization).not_to receive(:insert_all) + + expect { service.execute }.not_to( + change { project_authorization.reload.exists? }.from(true)) + end + end + + context 'when existing access level is lower' do + let(:existing_access_level) { Gitlab::Access::DEVELOPER } + + it 'creates new project authorization' do + project_authorization = ProjectAuthorization.where( + project_id: project.id, + user_id: group_user.id, + access_level: access_level) + + expect { service.execute }.to( + change { project_authorization.reload.exists? }.from(false).to(true)) + end + + it 'deletes previous project authorization' do + project_authorization = ProjectAuthorization.where( + project_id: project.id, + user_id: group_user.id, + access_level: existing_access_level) + + expect { service.execute }.to( + change { project_authorization.reload.exists? }.from(true).to(false)) + end + end + + context 'when existing access level is higher' do + let(:existing_access_level) { Gitlab::Access::OWNER } + + it 'does not create project authorization' do + project_authorization = ProjectAuthorization.where( + project_id: project.id, + user_id: group_user.id, + access_level: existing_access_level) + + expect(ProjectAuthorization).not_to receive(:insert_all) + + expect { service.execute }.not_to( + change { project_authorization.reload.exists? }.from(true)) + end + end + end + end +end diff --git a/spec/services/authorized_project_update/recalculate_for_user_range_service_spec.rb b/spec/services/authorized_project_update/recalculate_for_user_range_service_spec.rb index 28cbda6f4fd..a4637b6ba1c 100644 --- a/spec/services/authorized_project_update/recalculate_for_user_range_service_spec.rb +++ b/spec/services/authorized_project_update/recalculate_for_user_range_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe AuthorizedProjectUpdate::RecalculateForUserRangeService do +RSpec.describe AuthorizedProjectUpdate::RecalculateForUserRangeService do describe '#execute' do let_it_be(:users) { create_list(:user, 2) } diff --git a/spec/services/auto_merge/base_service_spec.rb b/spec/services/auto_merge/base_service_spec.rb index e08e1d670bf..98fa6012089 100644 --- a/spec/services/auto_merge/base_service_spec.rb +++ b/spec/services/auto_merge/base_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe AutoMerge::BaseService do +RSpec.describe AutoMerge::BaseService do let(:project) { create(:project) } let(:user) { create(:user) } let(:service) { described_class.new(project, user, params) } @@ -51,7 +51,7 @@ describe AutoMerge::BaseService do expect(merge_request.merge_params['commit_message']).to eq("Merge branch 'patch-12' into 'master'") expect(merge_request.merge_params['sha']).to eq('200fcc9c260f7219eaf0daba87d818f0922c5b18') expect(merge_request.merge_params['should_remove_source_branch']).to eq(false) - expect(merge_request.squash).to eq(false) + expect(merge_request.squash_on_merge?).to eq(false) expect(merge_request.merge_params['squash_commit_message']).to eq('Update README.md') end end diff --git a/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb b/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb index b6e8d3c636a..3bf59f6a2d1 100644 --- a/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb +++ b/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe AutoMerge::MergeWhenPipelineSucceedsService do +RSpec.describe AutoMerge::MergeWhenPipelineSucceedsService do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :repository) } @@ -69,6 +69,7 @@ describe AutoMerge::MergeWhenPipelineSucceedsService do before do allow(merge_request) .to receive_messages(head_pipeline: pipeline, actual_head_pipeline: pipeline) + expect(MailScheduler::NotificationServiceWorker).to receive(:perform_async).with('merge_when_pipeline_succeeds', merge_request, user).once service.execute(merge_request) end @@ -90,6 +91,18 @@ describe AutoMerge::MergeWhenPipelineSucceedsService do end end + context 'without feature enabled' do + it 'does not send notification' do + stub_feature_flags(mwps_notification: false) + + allow(merge_request) + .to receive_messages(head_pipeline: pipeline, actual_head_pipeline: pipeline) + expect(MailScheduler::NotificationServiceWorker).not_to receive(:perform_async) + + service.execute(merge_request) + end + end + context 'already approved' do let(:service) { described_class.new(project, user, should_remove_source_branch: true) } let(:build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch) } @@ -106,6 +119,7 @@ describe AutoMerge::MergeWhenPipelineSucceedsService do it 'updates the merge params' do expect(SystemNoteService).not_to receive(:merge_when_pipeline_succeeds) + expect(MailScheduler::NotificationServiceWorker).not_to receive(:perform_async).with('merge_when_pipeline_succeeds', any_args) service.execute(mr_merge_if_green_enabled) expect(mr_merge_if_green_enabled.merge_params).to have_key('should_remove_source_branch') diff --git a/spec/services/auto_merge_service_spec.rb b/spec/services/auto_merge_service_spec.rb index bab69fb4aa3..eab95973e1b 100644 --- a/spec/services/auto_merge_service_spec.rb +++ b/spec/services/auto_merge_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe AutoMergeService do +RSpec.describe AutoMergeService do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } let(:service) { described_class.new(project, user) } diff --git a/spec/services/award_emojis/add_service_spec.rb b/spec/services/award_emojis/add_service_spec.rb index 4bcb5fa039f..85c39015614 100644 --- a/spec/services/award_emojis/add_service_spec.rb +++ b/spec/services/award_emojis/add_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe AwardEmojis::AddService do +RSpec.describe AwardEmojis::AddService do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:awardable) { create(:note, project: project) } diff --git a/spec/services/award_emojis/collect_user_emoji_service_spec.rb b/spec/services/award_emojis/collect_user_emoji_service_spec.rb index a0dea31b403..bf5aa0eb9ef 100644 --- a/spec/services/award_emojis/collect_user_emoji_service_spec.rb +++ b/spec/services/award_emojis/collect_user_emoji_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe AwardEmojis::CollectUserEmojiService do +RSpec.describe AwardEmojis::CollectUserEmojiService do describe '#execute' do it 'returns an Array containing the awarded emoji names' do user = create(:user) diff --git a/spec/services/award_emojis/destroy_service_spec.rb b/spec/services/award_emojis/destroy_service_spec.rb index f411345560e..2aba078b638 100644 --- a/spec/services/award_emojis/destroy_service_spec.rb +++ b/spec/services/award_emojis/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe AwardEmojis::DestroyService do +RSpec.describe AwardEmojis::DestroyService do let_it_be(:user) { create(:user) } let_it_be(:awardable) { create(:note) } let_it_be(:project) { awardable.project } diff --git a/spec/services/award_emojis/toggle_service_spec.rb b/spec/services/award_emojis/toggle_service_spec.rb index 069bdfcb99f..a7feeed50c6 100644 --- a/spec/services/award_emojis/toggle_service_spec.rb +++ b/spec/services/award_emojis/toggle_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe AwardEmojis::ToggleService do +RSpec.describe AwardEmojis::ToggleService do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :public) } let_it_be(:awardable) { create(:note, project: project) } diff --git a/spec/services/base_container_service_spec.rb b/spec/services/base_container_service_spec.rb index 47cfb387e25..1de79eec702 100644 --- a/spec/services/base_container_service_spec.rb +++ b/spec/services/base_container_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe BaseContainerService do +RSpec.describe BaseContainerService do let(:project) { Project.new } let(:user) { User.new } diff --git a/spec/services/base_count_service_spec.rb b/spec/services/base_count_service_spec.rb index 275bec9982d..18cab2e8e9a 100644 --- a/spec/services/base_count_service_spec.rb +++ b/spec/services/base_count_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe BaseCountService, :use_clean_rails_memory_store_caching do +RSpec.describe BaseCountService, :use_clean_rails_memory_store_caching do let(:service) { described_class.new } describe '#relation_for_count' do diff --git a/spec/services/boards/create_service_spec.rb b/spec/services/boards/create_service_spec.rb index 7d4fb04c6c0..f6a9f0903ce 100644 --- a/spec/services/boards/create_service_spec.rb +++ b/spec/services/boards/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Boards::CreateService do +RSpec.describe Boards::CreateService do describe '#execute' do context 'when board parent is a project' do let(:parent) { create(:project) } diff --git a/spec/services/boards/issues/create_service_spec.rb b/spec/services/boards/issues/create_service_spec.rb index 3520630dd83..9a6b48c13bf 100644 --- a/spec/services/boards/issues/create_service_spec.rb +++ b/spec/services/boards/issues/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Boards::Issues::CreateService do +RSpec.describe Boards::Issues::CreateService do describe '#execute' do let(:project) { create(:project) } let(:board) { create(:board, project: project) } diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb index c46ab004af6..29b49db42f9 100644 --- a/spec/services/boards/issues/list_service_spec.rb +++ b/spec/services/boards/issues/list_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Boards::Issues::ListService do +RSpec.describe Boards::Issues::ListService do describe '#execute' do context 'when parent is a project' do let(:user) { create(:user) } diff --git a/spec/services/boards/issues/move_service_spec.rb b/spec/services/boards/issues/move_service_spec.rb index b9ebbc30c1a..01a3ec72987 100644 --- a/spec/services/boards/issues/move_service_spec.rb +++ b/spec/services/boards/issues/move_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Boards::Issues::MoveService do +RSpec.describe Boards::Issues::MoveService do describe '#execute' do context 'when parent is a project' do let(:user) { create(:user) } diff --git a/spec/services/boards/list_service_spec.rb b/spec/services/boards/list_service_spec.rb index 4eb023907fa..7c94332a78d 100644 --- a/spec/services/boards/list_service_spec.rb +++ b/spec/services/boards/list_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Boards::ListService do +RSpec.describe Boards::ListService do describe '#execute' do context 'when board parent is a project' do let(:parent) { create(:project) } diff --git a/spec/services/boards/lists/create_service_spec.rb b/spec/services/boards/lists/create_service_spec.rb index 295ec2c8156..f3d4e62eeca 100644 --- a/spec/services/boards/lists/create_service_spec.rb +++ b/spec/services/boards/lists/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Boards::Lists::CreateService do +RSpec.describe Boards::Lists::CreateService do describe '#execute' do shared_examples 'creating board lists' do let(:user) { create(:user) } diff --git a/spec/services/boards/lists/destroy_service_spec.rb b/spec/services/boards/lists/destroy_service_spec.rb index b936ef3837f..4c512b96065 100644 --- a/spec/services/boards/lists/destroy_service_spec.rb +++ b/spec/services/boards/lists/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Boards::Lists::DestroyService do +RSpec.describe Boards::Lists::DestroyService do describe '#execute' do context 'when board parent is a project' do let(:project) { create(:project) } diff --git a/spec/services/boards/lists/generate_service_spec.rb b/spec/services/boards/lists/generate_service_spec.rb index 77b42392470..9597c8e0f54 100644 --- a/spec/services/boards/lists/generate_service_spec.rb +++ b/spec/services/boards/lists/generate_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Boards::Lists::GenerateService do +RSpec.describe Boards::Lists::GenerateService do describe '#execute' do let(:project) { create(:project) } let(:board) { create(:board, project: project) } diff --git a/spec/services/boards/lists/list_service_spec.rb b/spec/services/boards/lists/list_service_spec.rb index 2535f339495..3d71c467e96 100644 --- a/spec/services/boards/lists/list_service_spec.rb +++ b/spec/services/boards/lists/list_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Boards::Lists::ListService do +RSpec.describe Boards::Lists::ListService do let(:user) { create(:user) } describe '#execute' do diff --git a/spec/services/boards/lists/move_service_spec.rb b/spec/services/boards/lists/move_service_spec.rb index f8fc70ef2d6..2861fc48b4d 100644 --- a/spec/services/boards/lists/move_service_spec.rb +++ b/spec/services/boards/lists/move_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Boards::Lists::MoveService do +RSpec.describe Boards::Lists::MoveService do describe '#execute' do context 'when board parent is a project' do let(:project) { create(:project) } diff --git a/spec/services/boards/lists/update_service_spec.rb b/spec/services/boards/lists/update_service_spec.rb index 243e0fc50ad..cdc7784469a 100644 --- a/spec/services/boards/lists/update_service_spec.rb +++ b/spec/services/boards/lists/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Boards::Lists::UpdateService do +RSpec.describe Boards::Lists::UpdateService do let(:user) { create(:user) } let!(:list) { create(:list, board: board, position: 0) } diff --git a/spec/services/boards/visits/create_service_spec.rb b/spec/services/boards/visits/create_service_spec.rb index 203c287f396..a9a8754825b 100644 --- a/spec/services/boards/visits/create_service_spec.rb +++ b/spec/services/boards/visits/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Boards::Visits::CreateService do +RSpec.describe Boards::Visits::CreateService do describe '#execute' do let(:user) { create(:user) } diff --git a/spec/services/branches/create_service_spec.rb b/spec/services/branches/create_service_spec.rb index 072a86d17fc..b682a3f26ec 100644 --- a/spec/services/branches/create_service_spec.rb +++ b/spec/services/branches/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Branches::CreateService do +RSpec.describe Branches::CreateService do subject(:service) { described_class.new(project, user) } let_it_be(:project) { create(:project_empty_repo) } diff --git a/spec/services/branches/delete_merged_service_spec.rb b/spec/services/branches/delete_merged_service_spec.rb index 5c87f156ec7..2cf0f53c8c3 100644 --- a/spec/services/branches/delete_merged_service_spec.rb +++ b/spec/services/branches/delete_merged_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Branches::DeleteMergedService do +RSpec.describe Branches::DeleteMergedService do include ProjectForksHelper subject(:service) { described_class.new(project, project.owner) } diff --git a/spec/services/branches/delete_service_spec.rb b/spec/services/branches/delete_service_spec.rb index 2219416d94d..f1e7c9340b1 100644 --- a/spec/services/branches/delete_service_spec.rb +++ b/spec/services/branches/delete_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Branches::DeleteService do +RSpec.describe Branches::DeleteService do let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:user) { create(:user) } @@ -10,6 +10,10 @@ describe Branches::DeleteService do subject(:service) { described_class.new(project, user) } shared_examples 'a deleted branch' do |branch_name| + before do + allow(Ci::RefDeleteUnlockArtifactsWorker).to receive(:perform_async) + end + it 'removes the branch' do expect(branch_exists?(branch_name)).to be true @@ -18,6 +22,12 @@ describe Branches::DeleteService do expect(result.status).to eq :success expect(branch_exists?(branch_name)).to be false end + + it 'calls the RefDeleteUnlockArtifactsWorker' do + expect(Ci::RefDeleteUnlockArtifactsWorker).to receive(:perform_async).with(project.id, user.id, "refs/heads/#{branch_name}") + + service.execute(branch_name) + end end describe '#execute' do diff --git a/spec/services/branches/diverging_commit_counts_service_spec.rb b/spec/services/branches/diverging_commit_counts_service_spec.rb index 370da773ab2..34a2b81c831 100644 --- a/spec/services/branches/diverging_commit_counts_service_spec.rb +++ b/spec/services/branches/diverging_commit_counts_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Branches::DivergingCommitCountsService do +RSpec.describe Branches::DivergingCommitCountsService do let(:project) { create(:project, :repository) } let(:repository) { project.repository } diff --git a/spec/services/branches/validate_new_service_spec.rb b/spec/services/branches/validate_new_service_spec.rb index 6d5078d3ccb..02127c8c10d 100644 --- a/spec/services/branches/validate_new_service_spec.rb +++ b/spec/services/branches/validate_new_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Branches::ValidateNewService do +RSpec.describe Branches::ValidateNewService do let(:project) { create(:project, :repository) } subject(:service) { described_class.new(project) } diff --git a/spec/services/bulk_push_event_payload_service_spec.rb b/spec/services/bulk_push_event_payload_service_spec.rb index 661c3540aa0..381c735c003 100644 --- a/spec/services/bulk_push_event_payload_service_spec.rb +++ b/spec/services/bulk_push_event_payload_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe BulkPushEventPayloadService do +RSpec.describe BulkPushEventPayloadService do let(:event) { create(:push_event) } let(:push_data) do diff --git a/spec/services/chat_names/authorize_user_service_spec.rb b/spec/services/chat_names/authorize_user_service_spec.rb index 7f32948daad..b0bb741564d 100644 --- a/spec/services/chat_names/authorize_user_service_spec.rb +++ b/spec/services/chat_names/authorize_user_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ChatNames::AuthorizeUserService do +RSpec.describe ChatNames::AuthorizeUserService do describe '#execute' do subject { described_class.new(service, params) } diff --git a/spec/services/chat_names/find_user_service_spec.rb b/spec/services/chat_names/find_user_service_spec.rb index 9d26f98cd56..a29b243ad2c 100644 --- a/spec/services/chat_names/find_user_service_spec.rb +++ b/spec/services/chat_names/find_user_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ChatNames::FindUserService, :clean_gitlab_redis_shared_state do +RSpec.describe ChatNames::FindUserService, :clean_gitlab_redis_shared_state do describe '#execute' do let(:service) { create(:service) } diff --git a/spec/services/ci/archive_trace_service_spec.rb b/spec/services/ci/archive_trace_service_spec.rb index ba94013b574..07ea314debc 100644 --- a/spec/services/ci/archive_trace_service_spec.rb +++ b/spec/services/ci/archive_trace_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::ArchiveTraceService, '#execute' do +RSpec.describe Ci::ArchiveTraceService, '#execute' do subject { described_class.new.execute(job, worker_name: ArchiveTraceWorker.name) } context 'when job is finished' do diff --git a/spec/services/ci/build_report_result_service_spec.rb b/spec/services/ci/build_report_result_service_spec.rb index dbdfc774314..3c1ef5301fc 100644 --- a/spec/services/ci/build_report_result_service_spec.rb +++ b/spec/services/ci/build_report_result_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::BuildReportResultService do +RSpec.describe Ci::BuildReportResultService do describe "#execute" do subject(:build_report_result) { described_class.new.execute(build) } diff --git a/spec/services/ci/cancel_user_pipelines_service_spec.rb b/spec/services/ci/cancel_user_pipelines_service_spec.rb index b18bf48a50a..12117051b64 100644 --- a/spec/services/ci/cancel_user_pipelines_service_spec.rb +++ b/spec/services/ci/cancel_user_pipelines_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::CancelUserPipelinesService do +RSpec.describe Ci::CancelUserPipelinesService do describe '#execute' do let(:user) { create(:user) } diff --git a/spec/services/ci/compare_accessibility_reports_service_spec.rb b/spec/services/ci/compare_accessibility_reports_service_spec.rb index aee1fd14bc5..6903a633eeb 100644 --- a/spec/services/ci/compare_accessibility_reports_service_spec.rb +++ b/spec/services/ci/compare_accessibility_reports_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::CompareAccessibilityReportsService do +RSpec.describe Ci::CompareAccessibilityReportsService do let(:service) { described_class.new(project) } let(:project) { create(:project, :repository) } diff --git a/spec/services/ci/compare_test_reports_service_spec.rb b/spec/services/ci/compare_test_reports_service_spec.rb index 46f4d2d42ff..7d31db73b6a 100644 --- a/spec/services/ci/compare_test_reports_service_spec.rb +++ b/spec/services/ci/compare_test_reports_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::CompareTestReportsService do +RSpec.describe Ci::CompareTestReportsService do let(:service) { described_class.new(project) } let(:project) { create(:project, :repository) } diff --git a/spec/services/ci/create_cross_project_pipeline_service_spec.rb b/spec/services/ci/create_cross_project_pipeline_service_spec.rb index 9e2497854bc..1aabdb85afd 100644 --- a/spec/services/ci/create_cross_project_pipeline_service_spec.rb +++ b/spec/services/ci/create_cross_project_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::CreateCrossProjectPipelineService, '#execute' do +RSpec.describe Ci::CreateCrossProjectPipelineService, '#execute' do let_it_be(:user) { create(:user) } let(:upstream_project) { create(:project, :repository) } let_it_be(:downstream_project) { create(:project, :repository) } diff --git a/spec/services/ci/create_job_artifacts_service_spec.rb b/spec/services/ci/create_job_artifacts_service_spec.rb index 4d49923a184..3f5cf079025 100644 --- a/spec/services/ci/create_job_artifacts_service_spec.rb +++ b/spec/services/ci/create_job_artifacts_service_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' -describe Ci::CreateJobArtifactsService do +RSpec.describe Ci::CreateJobArtifactsService do let_it_be(:project) { create(:project) } - let(:service) { described_class.new(project) } + let(:service) { described_class.new(job) } let(:job) { create(:ci_build, project: project) } let(:artifacts_sha256) { '0' * 64 } let(:metadata_file) { nil } @@ -17,7 +17,7 @@ describe Ci::CreateJobArtifactsService do { 'artifact_type' => 'archive', 'artifact_format' => 'zip' - } + }.with_indifferent_access end def file_to_upload(path, params = {}) @@ -28,27 +28,7 @@ describe Ci::CreateJobArtifactsService do end describe '#execute' do - subject { service.execute(job, artifacts_file, params, metadata_file: metadata_file) } - - context 'locking' do - let(:old_job) { create(:ci_build, pipeline: create(:ci_pipeline, project: job.project, ref: job.ref)) } - let!(:latest_artifact) { create(:ci_job_artifact, job: old_job, locked: true) } - let!(:other_artifact) { create(:ci_job_artifact, locked: true) } - - it 'locks the new artifact' do - subject - - expect(Ci::JobArtifact.last).to have_attributes(locked: true) - end - - it 'unlocks all other artifacts for the same ref' do - expect { subject }.to change { latest_artifact.reload.locked }.from(true).to(false) - end - - it 'does not unlock artifacts for other refs' do - expect { subject }.not_to change { other_artifact.reload.locked }.from(true) - end - end + subject { service.execute(artifacts_file, params, metadata_file: metadata_file) } context 'when artifacts file is uploaded' do it 'saves artifact for the given type' do @@ -150,7 +130,7 @@ describe Ci::CreateJobArtifactsService do { 'artifact_type' => 'dotenv', 'artifact_format' => 'gzip' - } + }.with_indifferent_access end it 'calls parse service' do @@ -186,7 +166,7 @@ describe Ci::CreateJobArtifactsService do { 'artifact_type' => 'cluster_applications', 'artifact_format' => 'gzip' - } + }.with_indifferent_access end it 'calls cluster applications parse service' do diff --git a/spec/services/ci/create_pipeline_service/cache_spec.rb b/spec/services/ci/create_pipeline_service/cache_spec.rb index 4e0567132ff..614e46f1b1a 100644 --- a/spec/services/ci/create_pipeline_service/cache_spec.rb +++ b/spec/services/ci/create_pipeline_service/cache_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::CreatePipelineService do +RSpec.describe Ci::CreatePipelineService do context 'cache' do let(:user) { create(:admin) } let(:ref) { 'refs/heads/master' } diff --git a/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb b/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb new file mode 100644 index 00000000000..16205529f1c --- /dev/null +++ b/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb @@ -0,0 +1,114 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::CreatePipelineService do + describe 'creation errors and warnings' do + let_it_be(:user) { create(:admin) } + let_it_be(:project) { create(:project, :repository, creator: user) } + + let(:ref) { 'refs/heads/master' } + let(:source) { :push } + let(:service) { described_class.new(project, user, { ref: ref }) } + let(:pipeline) { service.execute(source) } + + before do + stub_ci_pipeline_yaml_file(config) + stub_feature_flags(ci_raise_job_rules_without_workflow_rules_warning: true) + end + + context 'when created successfully' do + context 'when warnings are raised' do + let(:config) do + <<~YAML + test: + script: rspec + rules: + - if: '$CI_COMMIT_BRANCH' + YAML + end + + it 'contains only warnings' do + expect(pipeline.error_messages.map(&:content)).to be_empty + + expect(pipeline.warning_messages.map(&:content)).to contain_exactly( + 'jobs:test uses `rules` without defining `workflow:rules`' + ) + end + + context 'when feature flag is disabled for the particular warning' do + before do + stub_feature_flags(ci_raise_job_rules_without_workflow_rules_warning: false) + end + + it 'does not contain warnings' do + expect(pipeline.error_messages.map(&:content)).to be_empty + + expect(pipeline.warning_messages.map(&:content)).to be_empty + end + end + end + + context 'when no warnings are raised' do + let(:config) do + <<~YAML + test: + script: rspec + YAML + end + + it 'contains no warnings' do + expect(pipeline.error_messages).to be_empty + + expect(pipeline.warning_messages).to be_empty + end + end + end + + context 'when failed to create the pipeline' do + context 'when warnings are raised' do + let(:config) do + <<~YAML + build: + stage: build + script: echo + needs: [test] + test: + stage: test + script: echo + rules: + - if: '$CI_COMMIT_BRANCH' + YAML + end + + it 'contains both errors and warnings' do + error_message = 'build job: need test is not defined in prior stages' + warning_message = 'jobs:test uses `rules` without defining `workflow:rules`' + + expect(pipeline.yaml_errors).to eq(error_message) + expect(pipeline.error_messages.map(&:content)).to contain_exactly(error_message) + expect(pipeline.errors.full_messages).to contain_exactly(error_message) + + expect(pipeline.warning_messages.map(&:content)).to contain_exactly(warning_message) + end + end + + context 'when no warnings are raised' do + let(:config) do + <<~YAML + invalid: yaml + YAML + end + + it 'contains only errors' do + error_message = 'root config contains unknown keys: invalid' + expect(pipeline.yaml_errors).to eq(error_message) + expect(pipeline.error_messages.map(&:content)).to contain_exactly(error_message) + expect(pipeline.errors.full_messages).to contain_exactly(error_message) + + expect(pipeline.warning_messages).to be_empty + end + end + end + end +end diff --git a/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb b/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb index 5980260a08a..122870e0f3a 100644 --- a/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb +++ b/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Ci::CreatePipelineService do +RSpec.describe Ci::CreatePipelineService do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:admin) } let(:ref) { 'refs/heads/master' } diff --git a/spec/services/ci/create_pipeline_service/needs_spec.rb b/spec/services/ci/create_pipeline_service/needs_spec.rb index 17b9cf80cc1..915dc46d664 100644 --- a/spec/services/ci/create_pipeline_service/needs_spec.rb +++ b/spec/services/ci/create_pipeline_service/needs_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::CreatePipelineService do +RSpec.describe Ci::CreatePipelineService do context 'needs' do let_it_be(:user) { create(:admin) } let_it_be(:project) { create(:project, :repository, creator: user) } diff --git a/spec/services/ci/create_pipeline_service/parameter_content_spec.rb b/spec/services/ci/create_pipeline_service/parameter_content_spec.rb new file mode 100644 index 00000000000..5157574ea04 --- /dev/null +++ b/spec/services/ci/create_pipeline_service/parameter_content_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::CreatePipelineService do + let_it_be(:project) { create(:project, :repository) } + let_it_be(:user) { create(:admin) } + let(:service) { described_class.new(project, user, { ref: 'refs/heads/master' }) } + let(:content) do + <<~EOY + --- + stages: + - dast + + variables: + DAST_VERSION: 1 + SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers" + + dast: + stage: dast + image: + name: "$SECURE_ANALYZERS_PREFIX/dast:$DAST_VERSION" + variables: + GIT_STRATEGY: none + script: + - /analyze + EOY + end + + describe '#execute' do + context 'when source is a dangling build' do + subject { service.execute(:ondemand_dast_scan, content: content) } + + context 'parameter config content' do + it 'creates a pipeline' do + expect(subject).to be_persisted + end + + it 'creates builds with the correct names' do + expect(subject.builds.pluck(:name)).to match_array %w[dast] + end + + it 'creates stages with the correct names' do + expect(subject.stages.pluck(:name)).to match_array %w[dast] + end + + it 'sets the correct config source' do + expect(subject.config_source).to eq 'parameter_source' + end + end + end + + context 'when source is not a dangling build' do + subject { service.execute(:web, content: content) } + + it 'raises an exception' do + klass = Gitlab::Ci::Pipeline::Chain::Config::Content::Parameter::UnsupportedSourceError + expect { subject }.to raise_error(klass) + end + end + end +end diff --git a/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb b/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb index a76e83f2d60..016a5dfd18b 100644 --- a/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb +++ b/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::CreatePipelineService, '#execute' do +RSpec.describe Ci::CreatePipelineService, '#execute' do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } let(:ref_name) { 'master' } diff --git a/spec/services/ci/create_pipeline_service/pre_post_stages_spec.rb b/spec/services/ci/create_pipeline_service/pre_post_stages_spec.rb index 2b11b98f58c..00a2dd74968 100644 --- a/spec/services/ci/create_pipeline_service/pre_post_stages_spec.rb +++ b/spec/services/ci/create_pipeline_service/pre_post_stages_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Ci::CreatePipelineService do +RSpec.describe Ci::CreatePipelineService do describe '.pre/.post stages' do let_it_be(:user) { create(:admin) } let_it_be(:project) { create(:project, :repository, creator: user) } diff --git a/spec/services/ci/create_pipeline_service/rules_spec.rb b/spec/services/ci/create_pipeline_service/rules_spec.rb index 713d230731b..1a1fa6e8f5d 100644 --- a/spec/services/ci/create_pipeline_service/rules_spec.rb +++ b/spec/services/ci/create_pipeline_service/rules_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Ci::CreatePipelineService do +RSpec.describe Ci::CreatePipelineService do let(:user) { create(:admin) } let(:ref) { 'refs/heads/master' } let(:source) { :push } diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index b9456d5fcd4..9dc518be996 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::CreatePipelineService do +RSpec.describe Ci::CreatePipelineService do include ProjectForksHelper let_it_be(:project, reload: true) { create(:project, :repository) } @@ -80,7 +80,7 @@ describe Ci::CreatePipelineService do it 'records pipeline size in a prometheus histogram' do histogram = spy('pipeline size histogram') - allow(Gitlab::Ci::Pipeline::Chain::Metrics) + allow(Gitlab::Ci::Pipeline::Metrics) .to receive(:new).and_return(histogram) execute_service @@ -194,6 +194,7 @@ describe Ci::CreatePipelineService do expect(head_pipeline).to be_persisted expect(head_pipeline.yaml_errors).to be_present + expect(head_pipeline.messages).to be_present expect(merge_request.reload.head_pipeline).to eq head_pipeline end end @@ -511,7 +512,7 @@ describe Ci::CreatePipelineService do it 'pull it from Auto-DevOps' do pipeline = execute_service expect(pipeline).to be_auto_devops_source - expect(pipeline.builds.map(&:name)).to match_array(%w[test code_quality build]) + expect(pipeline.builds.map(&:name)).to match_array(%w[build code_quality eslint-sast test]) end end @@ -1683,6 +1684,12 @@ describe Ci::CreatePipelineService do expect(pipeline).to be_persisted expect(pipeline.builds.pluck(:name)).to contain_exactly("build_a", "test_a") end + + it 'bulk inserts all needs' do + expect(Ci::BuildNeed).to receive(:bulk_insert!).and_call_original + + expect(pipeline).to be_persisted + end end context 'when pipeline on feature is created' do @@ -1695,6 +1702,7 @@ describe Ci::CreatePipelineService do expect(pipeline).to be_persisted expect(pipeline.builds).to be_empty expect(pipeline.yaml_errors).to eq("test_a: needs 'build_a'") + expect(pipeline.messages.pluck(:content)).to contain_exactly("test_a: needs 'build_a'") expect(pipeline.errors[:base]).to contain_exactly("test_a: needs 'build_a'") end end @@ -1706,6 +1714,7 @@ describe Ci::CreatePipelineService do expect(pipeline).not_to be_persisted expect(pipeline.builds).to be_empty expect(pipeline.yaml_errors).to be_nil + expect(pipeline.messages).not_to be_empty expect(pipeline.errors[:base]).to contain_exactly("test_a: needs 'build_a'") end end @@ -2205,6 +2214,83 @@ describe Ci::CreatePipelineService do expect(find_job('job-7').when).to eq('on_failure') end end + + context 'with deploy freeze period `if:` clause' do + # '0 23 * * 5' == "At 23:00 on Friday."", '0 7 * * 1' == "At 07:00 on Monday."" + let!(:freeze_period) { create(:ci_freeze_period, project: project, freeze_start: '0 23 * * 5', freeze_end: '0 7 * * 1') } + + context 'with 2 jobs' do + let(:config) do + <<-EOY + stages: + - test + - deploy + + test-job: + script: + - echo 'running TEST stage' + + deploy-job: + stage: deploy + script: + - echo 'running DEPLOY stage' + rules: + - if: $CI_DEPLOY_FREEZE == null + EOY + end + + context 'when outside freeze period' do + it 'creates two jobs' do + Timecop.freeze(2020, 4, 10, 22, 59) do + expect(pipeline).to be_persisted + expect(build_names).to contain_exactly('test-job', 'deploy-job') + end + end + end + + context 'when inside freeze period' do + it 'creates one job' do + Timecop.freeze(2020, 4, 10, 23, 1) do + expect(pipeline).to be_persisted + expect(build_names).to contain_exactly('test-job') + end + end + end + end + + context 'with 1 job' do + let(:config) do + <<-EOY + stages: + - deploy + + deploy-job: + stage: deploy + script: + - echo 'running DEPLOY stage' + rules: + - if: $CI_DEPLOY_FREEZE == null + EOY + end + + context 'when outside freeze period' do + it 'creates two jobs' do + Timecop.freeze(2020, 4, 10, 22, 59) do + expect(pipeline).to be_persisted + expect(build_names).to contain_exactly('deploy-job') + end + end + end + + context 'when inside freeze period' do + it 'does not create the pipeline' do + Timecop.freeze(2020, 4, 10, 23, 1) do + expect(pipeline).not_to be_persisted + end + end + end + end + end end end diff --git a/spec/services/ci/create_web_ide_terminal_service_spec.rb b/spec/services/ci/create_web_ide_terminal_service_spec.rb index 2cc67c7cd1d..c1c94e30018 100644 --- a/spec/services/ci/create_web_ide_terminal_service_spec.rb +++ b/spec/services/ci/create_web_ide_terminal_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::CreateWebIdeTerminalService do +RSpec.describe Ci::CreateWebIdeTerminalService do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } let(:ref) { 'master' } diff --git a/spec/services/ci/daily_build_group_report_result_service_spec.rb b/spec/services/ci/daily_build_group_report_result_service_spec.rb index f0b72b8fd86..7d181a5c2ba 100644 --- a/spec/services/ci/daily_build_group_report_result_service_spec.rb +++ b/spec/services/ci/daily_build_group_report_result_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::DailyBuildGroupReportResultService, '#execute' do +RSpec.describe Ci::DailyBuildGroupReportResultService, '#execute' do let!(:pipeline) { create(:ci_pipeline, created_at: '2020-02-06 00:01:10') } let!(:rspec_job) { create(:ci_build, pipeline: pipeline, name: '3/3 rspec', coverage: 80) } let!(:karma_job) { create(:ci_build, pipeline: pipeline, name: '2/2 karma', coverage: 90) } diff --git a/spec/services/ci/destroy_expired_job_artifacts_service_spec.rb b/spec/services/ci/destroy_expired_job_artifacts_service_spec.rb index 4b9f12d8fdf..79443f16276 100644 --- a/spec/services/ci/destroy_expired_job_artifacts_service_spec.rb +++ b/spec/services/ci/destroy_expired_job_artifacts_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared_state do +RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared_state do include ExclusiveLeaseHelpers describe '.execute' do @@ -14,7 +14,7 @@ describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared_state context 'when artifact is expired' do context 'when artifact is not locked' do before do - artifact.update!(locked: false) + artifact.job.pipeline.unlocked! end it 'destroys job artifact' do @@ -24,7 +24,7 @@ describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared_state context 'when artifact is locked' do before do - artifact.update!(locked: true) + artifact.job.pipeline.artifacts_locked! end it 'does not destroy job artifact' do diff --git a/spec/services/ci/destroy_pipeline_service_spec.rb b/spec/services/ci/destroy_pipeline_service_spec.rb index bff2b3179fb..23cbe683d2f 100644 --- a/spec/services/ci/destroy_pipeline_service_spec.rb +++ b/spec/services/ci/destroy_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ::Ci::DestroyPipelineService do +RSpec.describe ::Ci::DestroyPipelineService do let(:project) { create(:project, :repository) } let!(:pipeline) { create(:ci_pipeline, :success, project: project, sha: project.commit.id) } diff --git a/spec/services/ci/ensure_stage_service_spec.rb b/spec/services/ci/ensure_stage_service_spec.rb index 8a270d77bae..3ede214cdd4 100644 --- a/spec/services/ci/ensure_stage_service_spec.rb +++ b/spec/services/ci/ensure_stage_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::EnsureStageService, '#execute' do +RSpec.describe Ci::EnsureStageService, '#execute' do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } diff --git a/spec/services/ci/expire_pipeline_cache_service_spec.rb b/spec/services/ci/expire_pipeline_cache_service_spec.rb index 2962e9dd31e..b5d664947de 100644 --- a/spec/services/ci/expire_pipeline_cache_service_spec.rb +++ b/spec/services/ci/expire_pipeline_cache_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::ExpirePipelineCacheService do +RSpec.describe Ci::ExpirePipelineCacheService do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb b/spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb index 5048f2b71b3..e2bdfae27f0 100644 --- a/spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb +++ b/spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::ExternalPullRequests::CreatePipelineService do +RSpec.describe Ci::ExternalPullRequests::CreatePipelineService do describe '#execute' do let_it_be(:project) { create(:project, :auto_devops, :repository) } let_it_be(:user) { create(:user) } diff --git a/spec/services/ci/extract_sections_from_build_trace_service_spec.rb b/spec/services/ci/extract_sections_from_build_trace_service_spec.rb index 03c67c611fe..c6ffcdcc6a8 100644 --- a/spec/services/ci/extract_sections_from_build_trace_service_spec.rb +++ b/spec/services/ci/extract_sections_from_build_trace_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::ExtractSectionsFromBuildTraceService, '#execute' do +RSpec.describe Ci::ExtractSectionsFromBuildTraceService, '#execute' do let(:user) { create(:user) } let(:project) { create(:project) } let(:build) { create(:ci_build, project: project) } diff --git a/spec/services/ci/find_exposed_artifacts_service_spec.rb b/spec/services/ci/find_exposed_artifacts_service_spec.rb index 16e23253c34..287f5c4b929 100644 --- a/spec/services/ci/find_exposed_artifacts_service_spec.rb +++ b/spec/services/ci/find_exposed_artifacts_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::FindExposedArtifactsService do +RSpec.describe Ci::FindExposedArtifactsService do include Gitlab::Routing let(:metadata) do diff --git a/spec/services/ci/generate_coverage_reports_service_spec.rb b/spec/services/ci/generate_coverage_reports_service_spec.rb index b64b682a00b..a3ed2eec713 100644 --- a/spec/services/ci/generate_coverage_reports_service_spec.rb +++ b/spec/services/ci/generate_coverage_reports_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::GenerateCoverageReportsService do +RSpec.describe Ci::GenerateCoverageReportsService do let(:service) { described_class.new(project) } let(:project) { create(:project, :repository) } diff --git a/spec/services/ci/generate_terraform_reports_service_spec.rb b/spec/services/ci/generate_terraform_reports_service_spec.rb index 008ecf17b3e..25bf96035b2 100644 --- a/spec/services/ci/generate_terraform_reports_service_spec.rb +++ b/spec/services/ci/generate_terraform_reports_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::GenerateTerraformReportsService do +RSpec.describe Ci::GenerateTerraformReportsService do let_it_be(:project) { create(:project, :repository) } describe '#execute' do @@ -33,19 +33,36 @@ describe Ci::GenerateTerraformReportsService do end context 'when head pipeline has corrupted terraform reports' do - it 'returns status and error message' do + it 'returns a report with error messages' do build = create(:ci_build, pipeline: merge_request.head_pipeline, project: project) create(:ci_job_artifact, :terraform_with_corrupted_data, job: build, project: project) result = subject.execute(nil, merge_request.head_pipeline) expect(result).to match( - status: :error, - status_reason: 'An error occurred while fetching terraform reports.', + status: :parsed, + data: match( + a_hash_including(build.id.to_s => hash_including( + 'tf_report_error' => :invalid_json_format + )) + ), key: an_instance_of(Array) ) end end + + context 'when head pipeline is corrupted' do + it 'returns status and error message' do + result = subject.execute(nil, nil) + + expect(result).to match( + a_hash_including( + status: :error, + status_reason: 'An error occurred while fetching terraform reports.' + ) + ) + end + end end describe '#latest?' do diff --git a/spec/services/ci/parse_dotenv_artifact_service_spec.rb b/spec/services/ci/parse_dotenv_artifact_service_spec.rb index fc4131d262b..a5f01187a83 100644 --- a/spec/services/ci/parse_dotenv_artifact_service_spec.rb +++ b/spec/services/ci/parse_dotenv_artifact_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::ParseDotenvArtifactService do +RSpec.describe Ci::ParseDotenvArtifactService do let_it_be(:project) { create(:project) } let_it_be(:pipeline) { create(:ci_pipeline, project: project) } let(:build) { create(:ci_build, pipeline: pipeline, project: project) } diff --git a/spec/services/ci/pipeline_bridge_status_service_spec.rb b/spec/services/ci/pipeline_bridge_status_service_spec.rb index 7e79d222349..584b23bb3aa 100644 --- a/spec/services/ci/pipeline_bridge_status_service_spec.rb +++ b/spec/services/ci/pipeline_bridge_status_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::PipelineBridgeStatusService do +RSpec.describe Ci::PipelineBridgeStatusService do let(:user) { build(:user) } let_it_be(:project) { create(:project) } let(:pipeline) { build(:ci_pipeline, project: project) } diff --git a/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb b/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb index de3c7713ac8..7868629d34d 100644 --- a/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb +++ b/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection do +RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection do using RSpec::Parameterized::TableSyntax let_it_be(:pipeline) { create(:ci_pipeline) } diff --git a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb index 3b66ecff196..a10a333b462 100644 --- a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb +++ b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require_relative 'shared_processing_service.rb' require_relative 'shared_processing_service_tests_with_yaml.rb' -describe Ci::PipelineProcessing::AtomicProcessingService do +RSpec.describe Ci::PipelineProcessing::AtomicProcessingService do before do stub_feature_flags(ci_atomic_processing: true) diff --git a/spec/services/ci/pipeline_processing/legacy_processing_service_spec.rb b/spec/services/ci/pipeline_processing/legacy_processing_service_spec.rb index fd491bf461b..569a6d62dc1 100644 --- a/spec/services/ci/pipeline_processing/legacy_processing_service_spec.rb +++ b/spec/services/ci/pipeline_processing/legacy_processing_service_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' require_relative 'shared_processing_service.rb' require_relative 'shared_processing_service_tests_with_yaml.rb' -describe Ci::PipelineProcessing::LegacyProcessingService do +RSpec.describe Ci::PipelineProcessing::LegacyProcessingService do before do stub_feature_flags(ci_atomic_processing: false) end diff --git a/spec/services/ci/pipeline_processing/shared_processing_service.rb b/spec/services/ci/pipeline_processing/shared_processing_service.rb index 29fa43001ae..224066885b6 100644 --- a/spec/services/ci/pipeline_processing/shared_processing_service.rb +++ b/spec/services/ci/pipeline_processing/shared_processing_service.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -shared_examples 'Pipeline Processing Service' do +RSpec.shared_examples 'Pipeline Processing Service' do let(:user) { create(:user) } let(:project) { create(:project) } diff --git a/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb b/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb index 93f83f0ea3b..17d254ba48e 100644 --- a/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb +++ b/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -shared_context 'Pipeline Processing Service Tests With Yaml' do +RSpec.shared_context 'Pipeline Processing Service Tests With Yaml' do where(:test_file_path) do Dir.glob(Rails.root.join('spec/services/ci/pipeline_processing/test_cases/*.yml')) end diff --git a/spec/services/ci/pipeline_schedule_service_spec.rb b/spec/services/ci/pipeline_schedule_service_spec.rb index 867ed0acc0d..65bbd13c5e7 100644 --- a/spec/services/ci/pipeline_schedule_service_spec.rb +++ b/spec/services/ci/pipeline_schedule_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::PipelineScheduleService do +RSpec.describe Ci::PipelineScheduleService do let(:project) { create(:project) } let(:user) { create(:user) } let(:service) { described_class.new(project, user) } diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb index 44ce1ff699b..18fab9623ec 100644 --- a/spec/services/ci/pipeline_trigger_service_spec.rb +++ b/spec/services/ci/pipeline_trigger_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::PipelineTriggerService do +RSpec.describe Ci::PipelineTriggerService do let(:project) { create(:project, :repository) } before do diff --git a/spec/services/ci/play_build_service_spec.rb b/spec/services/ci/play_build_service_spec.rb index cf39f3da4fe..c9ecbad3167 100644 --- a/spec/services/ci/play_build_service_spec.rb +++ b/spec/services/ci/play_build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::PlayBuildService, '#execute' do +RSpec.describe Ci::PlayBuildService, '#execute' do let(:user) { create(:user, developer_projects: [project]) } let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/services/ci/play_manual_stage_service_spec.rb b/spec/services/ci/play_manual_stage_service_spec.rb index e2946111a13..e30ec8bfda5 100644 --- a/spec/services/ci/play_manual_stage_service_spec.rb +++ b/spec/services/ci/play_manual_stage_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::PlayManualStageService, '#execute' do +RSpec.describe Ci::PlayManualStageService, '#execute' do let(:current_user) { create(:user) } let(:pipeline) { create(:ci_pipeline, user: current_user) } let(:project) { pipeline.project } diff --git a/spec/services/ci/prepare_build_service_spec.rb b/spec/services/ci/prepare_build_service_spec.rb index 02928b58ff8..f75cb322fe9 100644 --- a/spec/services/ci/prepare_build_service_spec.rb +++ b/spec/services/ci/prepare_build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::PrepareBuildService do +RSpec.describe Ci::PrepareBuildService do describe '#execute' do let(:build) { create(:ci_build, :preparing) } diff --git a/spec/services/ci/process_build_service_spec.rb b/spec/services/ci/process_build_service_spec.rb index abc5c18a523..a6e8732f5ff 100644 --- a/spec/services/ci/process_build_service_spec.rb +++ b/spec/services/ci/process_build_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Ci::ProcessBuildService, '#execute' do +RSpec.describe Ci::ProcessBuildService, '#execute' do let(:user) { create(:user) } let(:project) { create(:project) } diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index 40ae1c4029b..a7889f0644d 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::ProcessPipelineService do +RSpec.describe Ci::ProcessPipelineService do let(:user) { create(:user) } let(:project) { create(:project) } @@ -10,38 +10,52 @@ describe Ci::ProcessPipelineService do create(:ci_empty_pipeline, ref: 'master', project: project) end + subject { described_class.new(pipeline) } + before do stub_ci_pipeline_to_return_yaml_file - stub_not_protect_default_branch project.add_developer(user) end - context 'updates a list of retried builds' do - subject { described_class.retried.order(:id) } + describe 'processing events counter' do + let(:metrics) { double('pipeline metrics') } + let(:counter) { double('events counter') } + + before do + allow(subject) + .to receive(:metrics).and_return(metrics) + allow(metrics) + .to receive(:pipeline_processing_events_counter) + .and_return(counter) + end + + it 'increments processing events counter' do + expect(counter).to receive(:increment) + + subject.execute + end + end + describe 'updating a list of retried builds' do let!(:build_retried) { create_build('build') } let!(:build) { create_build('build') } let!(:test) { create_build('test') } it 'returns unique statuses' do - process_pipeline + subject.execute expect(all_builds.latest).to contain_exactly(build, test) expect(all_builds.retried).to contain_exactly(build_retried) end - end - - def process_pipeline - described_class.new(pipeline).execute - end - def create_build(name, **opts) - create(:ci_build, :created, pipeline: pipeline, name: name, **opts) - end + def create_build(name, **opts) + create(:ci_build, :created, pipeline: pipeline, name: name, **opts) + end - def all_builds - pipeline.builds.order(:stage_idx, :id) + def all_builds + pipeline.builds.order(:stage_idx, :id) + end end end diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb index c0f854df9b7..921f5ba4c7e 100644 --- a/spec/services/ci/register_job_service_spec.rb +++ b/spec/services/ci/register_job_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' module Ci - describe RegisterJobService do + RSpec.describe RegisterJobService do let_it_be(:group) { create(:group) } let_it_be(:project, reload: true) { create(:project, group: group, shared_runners_enabled: false, group_runners_enabled: false) } let_it_be(:pipeline) { create(:ci_pipeline, project: project) } @@ -109,12 +109,14 @@ module Ci end context 'shared runner' do - let(:build) { execute(shared_runner) } + let(:response) { described_class.new(shared_runner).execute } + let(:build) { response.build } it { expect(build).to be_kind_of(Build) } it { expect(build).to be_valid } it { expect(build).to be_running } it { expect(build.runner).to eq(shared_runner) } + it { expect(Gitlab::Json.parse(response.build_json)['id']).to eq(build.id) } end context 'specific runner' do @@ -356,13 +358,8 @@ module Ci end context 'runner feature set is verified' do - let!(:pending_job) { create(:ci_build, :pending, pipeline: pipeline) } - - before do - expect_any_instance_of(Ci::Build).to receive(:runner_required_feature_names) do - [:runner_required_feature] - end - end + let(:options) { { artifacts: { reports: { junit: "junit.xml" } } } } + let!(:pending_job) { create(:ci_build, :pending, pipeline: pipeline, options: options) } subject { execute(specific_runner, params) } @@ -378,7 +375,7 @@ module Ci context 'when feature is supported by runner' do let(:params) do - { info: { features: { runner_required_feature: true } } } + { info: { features: { upload_multiple_artifacts: true } } } end it 'does pick job' do diff --git a/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb b/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb index 50d312647ae..6c69a7f3b11 100644 --- a/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb +++ b/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::ResourceGroups::AssignResourceFromResourceGroupService do +RSpec.describe Ci::ResourceGroups::AssignResourceFromResourceGroupService do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } let(:service) { described_class.new(project, user) } diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 90c53d4a346..5a245415b32 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::RetryBuildService do +RSpec.describe Ci::RetryBuildService do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :repository) } let_it_be(:pipeline) do @@ -33,13 +33,13 @@ describe Ci::RetryBuildService do job_artifacts_sast job_artifacts_secret_detection job_artifacts_dependency_scanning job_artifacts_container_scanning job_artifacts_dast job_artifacts_license_management job_artifacts_license_scanning - job_artifacts_performance job_artifacts_lsif - job_artifacts_terraform job_artifacts_cluster_applications + job_artifacts_performance job_artifacts_browser_performance job_artifacts_load_performance + job_artifacts_lsif job_artifacts_terraform job_artifacts_cluster_applications job_artifacts_codequality job_artifacts_metrics scheduled_at job_variables waiting_for_resource_at job_artifacts_metrics_referee job_artifacts_network_referee job_artifacts_dotenv job_artifacts_cobertura needs job_artifacts_accessibility - job_artifacts_requirements].freeze + job_artifacts_requirements job_artifacts_coverage_fuzzing].freeze ignore_accessors = %i[type lock_version target_url base_tags trace_sections @@ -279,25 +279,16 @@ describe Ci::RetryBuildService do end end - context 'when scheduling_type of build is nil' do + context 'when build has needs' do before do - build.update_columns(scheduling_type: nil) + create(:ci_build_need, build: build, name: 'build1') + create(:ci_build_need, build: build, name: 'build2') end - context 'when build has not needs' do - it 'sets scheduling_type as :stage' do - expect(new_build.scheduling_type).to eq('stage') - end - end + it 'bulk inserts all needs' do + expect(Ci::BuildNeed).to receive(:bulk_insert!).and_call_original - context 'when build has needs' do - before do - create(:ci_build_need, build: build) - end - - it 'sets scheduling_type as :dag' do - expect(new_build.scheduling_type).to eq('dag') - end + new_build end end end diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb index 8e85e68d4fc..fa46d6c4d1d 100644 --- a/spec/services/ci/retry_pipeline_service_spec.rb +++ b/spec/services/ci/retry_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::RetryPipelineService, '#execute' do +RSpec.describe Ci::RetryPipelineService, '#execute' do include ProjectForksHelper let(:user) { create(:user) } diff --git a/spec/services/ci/run_scheduled_build_service_spec.rb b/spec/services/ci/run_scheduled_build_service_spec.rb index 43d110cbc8f..27d25e88944 100644 --- a/spec/services/ci/run_scheduled_build_service_spec.rb +++ b/spec/services/ci/run_scheduled_build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::RunScheduledBuildService do +RSpec.describe Ci::RunScheduledBuildService do let(:user) { create(:user) } let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/services/ci/stop_environments_service_spec.rb b/spec/services/ci/stop_environments_service_spec.rb index ebbe6c37b87..5a0b7f23556 100644 --- a/spec/services/ci/stop_environments_service_spec.rb +++ b/spec/services/ci/stop_environments_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::StopEnvironmentsService do +RSpec.describe Ci::StopEnvironmentsService do include CreateEnvironmentsHelpers let(:project) { create(:project, :private, :repository) } diff --git a/spec/services/ci/unlock_artifacts_service_spec.rb b/spec/services/ci/unlock_artifacts_service_spec.rb new file mode 100644 index 00000000000..8d289a867ba --- /dev/null +++ b/spec/services/ci/unlock_artifacts_service_spec.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::UnlockArtifactsService do + describe '#execute' do + subject(:execute) { described_class.new(pipeline.project, pipeline.user).execute(ci_ref, before_pipeline) } + + before do + stub_const("#{described_class}::BATCH_SIZE", 1) + end + + [true, false].each do |tag| + context "when tag is #{tag}" do + let(:ref) { 'master' } + let(:ref_path) { tag ? "#{::Gitlab::Git::TAG_REF_PREFIX}#{ref}" : "#{::Gitlab::Git::BRANCH_REF_PREFIX}#{ref}" } + let(:ci_ref) { create(:ci_ref, ref_path: ref_path) } + + let!(:old_unlocked_pipeline) { create(:ci_pipeline, ref: ref, tag: tag, project: ci_ref.project, locked: :unlocked) } + let!(:older_pipeline) { create(:ci_pipeline, ref: ref, tag: tag, project: ci_ref.project, locked: :artifacts_locked) } + let!(:older_ambiguous_pipeline) { create(:ci_pipeline, ref: ref, tag: !tag, project: ci_ref.project, locked: :artifacts_locked) } + let!(:pipeline) { create(:ci_pipeline, ref: ref, tag: tag, project: ci_ref.project, locked: :artifacts_locked) } + let!(:child_pipeline) { create(:ci_pipeline, ref: ref, tag: tag, project: ci_ref.project, locked: :artifacts_locked) } + let!(:newer_pipeline) { create(:ci_pipeline, ref: ref, tag: tag, project: ci_ref.project, locked: :artifacts_locked) } + let!(:other_ref_pipeline) { create(:ci_pipeline, ref: 'other_ref', tag: tag, project: ci_ref.project, locked: :artifacts_locked) } + + before do + create(:ci_sources_pipeline, + source_job: create(:ci_build, pipeline: pipeline), + source_project: ci_ref.project, + pipeline: child_pipeline, + project: ci_ref.project) + end + + context 'when running on a ref before a pipeline' do + let(:before_pipeline) { pipeline } + + it 'unlocks artifacts from older pipelines' do + expect { execute }.to change { older_pipeline.reload.locked }.from('artifacts_locked').to('unlocked') + end + + it 'does not unlock artifacts for tag or branch with same name as ref' do + expect { execute }.not_to change { older_ambiguous_pipeline.reload.locked }.from('artifacts_locked') + end + + it 'does not unlock artifacts from newer pipelines' do + expect { execute }.not_to change { newer_pipeline.reload.locked }.from('artifacts_locked') + end + + it 'does not lock artifacts from old unlocked pipelines' do + expect { execute }.not_to change { old_unlocked_pipeline.reload.locked }.from('unlocked') + end + + it 'does not unlock artifacts from the same pipeline' do + expect { execute }.not_to change { pipeline.reload.locked }.from('artifacts_locked') + end + + it 'does not unlock artifacts for other refs' do + expect { execute }.not_to change { other_ref_pipeline.reload.locked }.from('artifacts_locked') + end + + it 'does not unlock artifacts for child pipeline' do + expect { execute }.not_to change { child_pipeline.reload.locked }.from('artifacts_locked') + end + end + + context 'when running on just the ref' do + let(:before_pipeline) { nil } + + it 'unlocks artifacts from older pipelines' do + expect { execute }.to change { older_pipeline.reload.locked }.from('artifacts_locked').to('unlocked') + end + + it 'unlocks artifacts from newer pipelines' do + expect { execute }.to change { newer_pipeline.reload.locked }.from('artifacts_locked').to('unlocked') + end + + it 'unlocks artifacts from the same pipeline' do + expect { execute }.to change { pipeline.reload.locked }.from('artifacts_locked').to('unlocked') + end + + it 'does not unlock artifacts for tag or branch with same name as ref' do + expect { execute }.not_to change { older_ambiguous_pipeline.reload.locked }.from('artifacts_locked') + end + + it 'does not lock artifacts from old unlocked pipelines' do + expect { execute }.not_to change { old_unlocked_pipeline.reload.locked }.from('unlocked') + end + + it 'does not unlock artifacts for other refs' do + expect { execute }.not_to change { other_ref_pipeline.reload.locked }.from('artifacts_locked') + end + end + end + end + end +end diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb index 522dd1ba1c2..0f4c0fa5ecb 100644 --- a/spec/services/ci/update_build_queue_service_spec.rb +++ b/spec/services/ci/update_build_queue_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::UpdateBuildQueueService do +RSpec.describe Ci::UpdateBuildQueueService do let(:project) { create(:project, :repository) } let(:build) { create(:ci_build, pipeline: pipeline) } let(:pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/services/ci/update_instance_variables_service_spec.rb b/spec/services/ci/update_instance_variables_service_spec.rb index 93f6e5d3ea8..f235d006e34 100644 --- a/spec/services/ci/update_instance_variables_service_spec.rb +++ b/spec/services/ci/update_instance_variables_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::UpdateInstanceVariablesService do +RSpec.describe Ci::UpdateInstanceVariablesService do let(:params) { { variables_attributes: variables_attributes } } subject { described_class.new(params) } diff --git a/spec/services/ci/update_runner_service_spec.rb b/spec/services/ci/update_runner_service_spec.rb index abe575eebc8..cad9e893335 100644 --- a/spec/services/ci/update_runner_service_spec.rb +++ b/spec/services/ci/update_runner_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::UpdateRunnerService do +RSpec.describe Ci::UpdateRunnerService do let(:runner) { create(:ci_runner) } describe '#update' do diff --git a/spec/services/ci/web_ide_config_service_spec.rb b/spec/services/ci/web_ide_config_service_spec.rb index 7522103ccb7..437b468cec8 100644 --- a/spec/services/ci/web_ide_config_service_spec.rb +++ b/spec/services/ci/web_ide_config_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Ci::WebIdeConfigService do +RSpec.describe Ci::WebIdeConfigService do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } let(:sha) { 'sha' } diff --git a/spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb b/spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb index 84bca76e69b..605d9e67ab6 100644 --- a/spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb +++ b/spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::CheckIngressIpAddressService do +RSpec.describe Clusters::Applications::CheckIngressIpAddressService do include ExclusiveLeaseHelpers let(:application) { create(:clusters_applications_ingress, :installed) } diff --git a/spec/services/clusters/applications/check_installation_progress_service_spec.rb b/spec/services/clusters/applications/check_installation_progress_service_spec.rb index 4b8db405101..13f7cd62002 100644 --- a/spec/services/clusters/applications/check_installation_progress_service_spec.rb +++ b/spec/services/clusters/applications/check_installation_progress_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::CheckInstallationProgressService, '#execute' do +RSpec.describe Clusters::Applications::CheckInstallationProgressService, '#execute' do RESCHEDULE_PHASES = Gitlab::Kubernetes::Pod::PHASES - [Gitlab::Kubernetes::Pod::SUCCEEDED, Gitlab::Kubernetes::Pod::FAILED].freeze let(:application) { create(:clusters_applications_helm, :installing) } diff --git a/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb b/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb index 9dede1947f8..4b8893429cf 100644 --- a/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb +++ b/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::CheckUninstallProgressService do +RSpec.describe Clusters::Applications::CheckUninstallProgressService do reschedule_phases = Gitlab::Kubernetes::Pod::PHASES - [Gitlab::Kubernetes::Pod::SUCCEEDED, Gitlab::Kubernetes::Pod::FAILED].freeze let(:application) { create(:clusters_applications_prometheus, :uninstalling) } diff --git a/spec/services/clusters/applications/check_upgrade_progress_service_spec.rb b/spec/services/clusters/applications/check_upgrade_progress_service_spec.rb index 29ee897454a..dbde8cec9b9 100644 --- a/spec/services/clusters/applications/check_upgrade_progress_service_spec.rb +++ b/spec/services/clusters/applications/check_upgrade_progress_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::CheckUpgradeProgressService do +RSpec.describe Clusters::Applications::CheckUpgradeProgressService do reschedule_phashes = ::Gitlab::Kubernetes::Pod::PHASES - [::Gitlab::Kubernetes::Pod::SUCCEEDED, ::Gitlab::Kubernetes::Pod::FAILED, ::Gitlab].freeze diff --git a/spec/services/clusters/applications/create_service_spec.rb b/spec/services/clusters/applications/create_service_spec.rb index 0b48af408e1..f93ae2c62f3 100644 --- a/spec/services/clusters/applications/create_service_spec.rb +++ b/spec/services/clusters/applications/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::CreateService do +RSpec.describe Clusters::Applications::CreateService do include TestRequestHelpers let(:cluster) { create(:cluster, :project, :provided_by_gcp) } diff --git a/spec/services/clusters/applications/destroy_service_spec.rb b/spec/services/clusters/applications/destroy_service_spec.rb index 8d9dc6a0f11..7306256e68e 100644 --- a/spec/services/clusters/applications/destroy_service_spec.rb +++ b/spec/services/clusters/applications/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::DestroyService, '#execute' do +RSpec.describe Clusters::Applications::DestroyService, '#execute' do let(:cluster) { create(:cluster, :project, :provided_by_gcp) } let(:user) { create(:user) } let(:params) { { application: 'prometheus' } } diff --git a/spec/services/clusters/applications/install_service_spec.rb b/spec/services/clusters/applications/install_service_spec.rb index 2441cc595a3..d34b4dd943c 100644 --- a/spec/services/clusters/applications/install_service_spec.rb +++ b/spec/services/clusters/applications/install_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::InstallService do +RSpec.describe Clusters::Applications::InstallService do describe '#execute' do let(:application) { create(:clusters_applications_helm, :scheduled) } let!(:install_command) { application.install_command } diff --git a/spec/services/clusters/applications/patch_service_spec.rb b/spec/services/clusters/applications/patch_service_spec.rb index dc9843a5116..281da62b80b 100644 --- a/spec/services/clusters/applications/patch_service_spec.rb +++ b/spec/services/clusters/applications/patch_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::PatchService do +RSpec.describe Clusters::Applications::PatchService do describe '#execute' do let(:application) { create(:clusters_applications_knative, :scheduled) } let!(:update_command) { application.update_command } diff --git a/spec/services/clusters/applications/prometheus_config_service_spec.rb b/spec/services/clusters/applications/prometheus_config_service_spec.rb index b9032e665ec..7399f250248 100644 --- a/spec/services/clusters/applications/prometheus_config_service_spec.rb +++ b/spec/services/clusters/applications/prometheus_config_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::PrometheusConfigService do +RSpec.describe Clusters::Applications::PrometheusConfigService do include Gitlab::Routing.url_helpers let_it_be(:project) { create(:project) } diff --git a/spec/services/clusters/applications/prometheus_health_check_service_spec.rb b/spec/services/clusters/applications/prometheus_health_check_service_spec.rb index 5c4127e4938..fc5a80688e6 100644 --- a/spec/services/clusters/applications/prometheus_health_check_service_spec.rb +++ b/spec/services/clusters/applications/prometheus_health_check_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::PrometheusHealthCheckService, '#execute' do +RSpec.describe Clusters::Applications::PrometheusHealthCheckService, '#execute' do let(:service) { described_class.new(cluster) } subject { service.execute } diff --git a/spec/services/clusters/applications/prometheus_update_service_spec.rb b/spec/services/clusters/applications/prometheus_update_service_spec.rb index 078b01d2777..076ff0210c9 100644 --- a/spec/services/clusters/applications/prometheus_update_service_spec.rb +++ b/spec/services/clusters/applications/prometheus_update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::PrometheusUpdateService do +RSpec.describe Clusters::Applications::PrometheusUpdateService do describe '#execute' do let(:project) { create(:project) } let(:environment) { create(:environment, project: project) } diff --git a/spec/services/clusters/applications/schedule_update_service_spec.rb b/spec/services/clusters/applications/schedule_update_service_spec.rb index eb1006ce8e0..f559fb1b7aa 100644 --- a/spec/services/clusters/applications/schedule_update_service_spec.rb +++ b/spec/services/clusters/applications/schedule_update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::ScheduleUpdateService do +RSpec.describe Clusters::Applications::ScheduleUpdateService do describe '#execute' do let(:project) { create(:project) } diff --git a/spec/services/clusters/applications/uninstall_service_spec.rb b/spec/services/clusters/applications/uninstall_service_spec.rb index 6d7f0478b20..50d7e82c47e 100644 --- a/spec/services/clusters/applications/uninstall_service_spec.rb +++ b/spec/services/clusters/applications/uninstall_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::UninstallService, '#execute' do +RSpec.describe Clusters::Applications::UninstallService, '#execute' do let(:application) { create(:clusters_applications_prometheus, :scheduled) } let(:service) { described_class.new(application) } let(:helm_client) { instance_double(Gitlab::Kubernetes::Helm::API) } diff --git a/spec/services/clusters/applications/update_service_spec.rb b/spec/services/clusters/applications/update_service_spec.rb index 4676951faff..4c05a12a4a1 100644 --- a/spec/services/clusters/applications/update_service_spec.rb +++ b/spec/services/clusters/applications/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::UpdateService do +RSpec.describe Clusters::Applications::UpdateService do include TestRequestHelpers let(:cluster) { create(:cluster, :project, :provided_by_gcp) } diff --git a/spec/services/clusters/applications/upgrade_service_spec.rb b/spec/services/clusters/applications/upgrade_service_spec.rb index 86fb06375f1..22fbb7ca6e3 100644 --- a/spec/services/clusters/applications/upgrade_service_spec.rb +++ b/spec/services/clusters/applications/upgrade_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Applications::UpgradeService do +RSpec.describe Clusters::Applications::UpgradeService do describe '#execute' do let(:application) { create(:clusters_applications_helm, :scheduled) } let!(:install_command) { application.install_command } diff --git a/spec/services/clusters/aws/authorize_role_service_spec.rb b/spec/services/clusters/aws/authorize_role_service_spec.rb index 3ef332558a2..530268340b7 100644 --- a/spec/services/clusters/aws/authorize_role_service_spec.rb +++ b/spec/services/clusters/aws/authorize_role_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Aws::AuthorizeRoleService do +RSpec.describe Clusters::Aws::AuthorizeRoleService do let(:user) { create(:user) } let(:credentials) { instance_double(Aws::Credentials) } let(:credentials_service) { instance_double(Clusters::Aws::FetchCredentialsService, execute: credentials) } diff --git a/spec/services/clusters/aws/fetch_credentials_service_spec.rb b/spec/services/clusters/aws/fetch_credentials_service_spec.rb index 9194947c67f..a0e63d96a5c 100644 --- a/spec/services/clusters/aws/fetch_credentials_service_spec.rb +++ b/spec/services/clusters/aws/fetch_credentials_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Aws::FetchCredentialsService do +RSpec.describe Clusters::Aws::FetchCredentialsService do describe '#execute' do let(:user) { create(:user) } let(:provider) { create(:cluster_provider_aws, region: 'ap-southeast-2') } diff --git a/spec/services/clusters/aws/finalize_creation_service_spec.rb b/spec/services/clusters/aws/finalize_creation_service_spec.rb index 8d7341483e3..6b0cb86eff0 100644 --- a/spec/services/clusters/aws/finalize_creation_service_spec.rb +++ b/spec/services/clusters/aws/finalize_creation_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Aws::FinalizeCreationService do +RSpec.describe Clusters::Aws::FinalizeCreationService do describe '#execute' do let(:provider) { create(:cluster_provider_aws, :creating) } let(:platform) { provider.cluster.platform_kubernetes } diff --git a/spec/services/clusters/aws/provision_service_spec.rb b/spec/services/clusters/aws/provision_service_spec.rb index 15571c64e13..529e1d26575 100644 --- a/spec/services/clusters/aws/provision_service_spec.rb +++ b/spec/services/clusters/aws/provision_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Aws::ProvisionService do +RSpec.describe Clusters::Aws::ProvisionService do describe '#execute' do let(:provider) { create(:cluster_provider_aws) } diff --git a/spec/services/clusters/aws/verify_provision_status_service_spec.rb b/spec/services/clusters/aws/verify_provision_status_service_spec.rb index b62b0875bf3..b9a58b97842 100644 --- a/spec/services/clusters/aws/verify_provision_status_service_spec.rb +++ b/spec/services/clusters/aws/verify_provision_status_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Aws::VerifyProvisionStatusService do +RSpec.describe Clusters::Aws::VerifyProvisionStatusService do describe '#execute' do let(:provider) { create(:cluster_provider_aws) } diff --git a/spec/services/clusters/build_kubernetes_namespace_service_spec.rb b/spec/services/clusters/build_kubernetes_namespace_service_spec.rb index 36c05469542..4ee933374f6 100644 --- a/spec/services/clusters/build_kubernetes_namespace_service_spec.rb +++ b/spec/services/clusters/build_kubernetes_namespace_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::BuildKubernetesNamespaceService do +RSpec.describe Clusters::BuildKubernetesNamespaceService do let(:cluster) { create(:cluster, :project, :provided_by_gcp) } let(:environment) { create(:environment) } let(:project) { environment.project } diff --git a/spec/services/clusters/build_service_spec.rb b/spec/services/clusters/build_service_spec.rb index f3e852726f4..c7a64435d3b 100644 --- a/spec/services/clusters/build_service_spec.rb +++ b/spec/services/clusters/build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::BuildService do +RSpec.describe Clusters::BuildService do describe '#execute' do subject { described_class.new(cluster_subject).execute } diff --git a/spec/services/clusters/cleanup/app_service_spec.rb b/spec/services/clusters/cleanup/app_service_spec.rb index 14bfca02fee..ba1be7448a4 100644 --- a/spec/services/clusters/cleanup/app_service_spec.rb +++ b/spec/services/clusters/cleanup/app_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Cleanup::AppService do +RSpec.describe Clusters::Cleanup::AppService do describe '#execute' do let!(:cluster) { create(:cluster, :project, :cleanup_uninstalling_applications, provider_type: :gcp) } let(:service) { described_class.new(cluster) } diff --git a/spec/services/clusters/cleanup/project_namespace_service_spec.rb b/spec/services/clusters/cleanup/project_namespace_service_spec.rb index 22e29cc57d1..761ad8dd8c8 100644 --- a/spec/services/clusters/cleanup/project_namespace_service_spec.rb +++ b/spec/services/clusters/cleanup/project_namespace_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Cleanup::ProjectNamespaceService do +RSpec.describe Clusters::Cleanup::ProjectNamespaceService do describe '#execute' do subject { service.execute } diff --git a/spec/services/clusters/cleanup/service_account_service_spec.rb b/spec/services/clusters/cleanup/service_account_service_spec.rb index ecaf0da9fa3..6fe3d0c286e 100644 --- a/spec/services/clusters/cleanup/service_account_service_spec.rb +++ b/spec/services/clusters/cleanup/service_account_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Cleanup::ServiceAccountService do +RSpec.describe Clusters::Cleanup::ServiceAccountService do describe '#execute' do subject { service.execute } diff --git a/spec/services/clusters/create_service_spec.rb b/spec/services/clusters/create_service_spec.rb index 3dd25be2a3d..6e252bee7c0 100644 --- a/spec/services/clusters/create_service_spec.rb +++ b/spec/services/clusters/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::CreateService do +RSpec.describe Clusters::CreateService do let(:access_token) { 'xxx' } let(:project) { create(:project) } let(:user) { create(:user) } @@ -53,13 +53,54 @@ describe Clusters::CreateService do include_context 'valid cluster create params' let!(:cluster) { create(:cluster, :provided_by_gcp, :production_environment, projects: [project]) } - it 'does not create a cluster' do - expect(ClusterProvisionWorker).not_to receive(:perform_async) - expect { subject }.to raise_error(ArgumentError).and change { Clusters::Cluster.count }.by(0) + it 'creates another cluster' do + expect(ClusterProvisionWorker).to receive(:perform_async) + expect { subject }.to change { Clusters::Cluster.count }.by(1) end end end + context 'when another cluster exists' do + let!(:cluster) { create(:cluster, :provided_by_gcp, :production_environment, projects: [project]) } + + context 'when correct params' do + let(:params) do + { + name: 'test-cluster', + provider_type: :gcp, + provider_gcp_attributes: { + gcp_project_id: 'gcp-project', + zone: 'us-central1-a', + num_nodes: 1, + machine_type: 'machine_type-a', + legacy_abac: 'true' + }, + clusterable: project + } + end + + include_examples 'create cluster service success' + end + + context 'when invalid params' do + let(:params) do + { + name: 'test-cluster', + provider_type: :gcp, + provider_gcp_attributes: { + gcp_project_id: '!!!!!!!', + zone: 'us-central1-a', + num_nodes: 1, + machine_type: 'machine_type-a' + }, + clusterable: project + } + end + + include_examples 'create cluster service error' + end + end + context 'when params includes :management_project_id' do subject(:cluster) { described_class.new(user, params).execute(access_token: access_token) } diff --git a/spec/services/clusters/destroy_service_spec.rb b/spec/services/clusters/destroy_service_spec.rb index 43ebf8f499e..76d9cc34b5d 100644 --- a/spec/services/clusters/destroy_service_spec.rb +++ b/spec/services/clusters/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::DestroyService do +RSpec.describe Clusters::DestroyService do describe '#execute' do subject { described_class.new(cluster.user, params).execute(cluster) } diff --git a/spec/services/clusters/gcp/fetch_operation_service_spec.rb b/spec/services/clusters/gcp/fetch_operation_service_spec.rb index 23da8004a7d..990cc745382 100644 --- a/spec/services/clusters/gcp/fetch_operation_service_spec.rb +++ b/spec/services/clusters/gcp/fetch_operation_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Gcp::FetchOperationService do +RSpec.describe Clusters::Gcp::FetchOperationService do include GoogleApi::CloudPlatformHelpers describe '#execute' do diff --git a/spec/services/clusters/gcp/finalize_creation_service_spec.rb b/spec/services/clusters/gcp/finalize_creation_service_spec.rb index 4d1548c9786..be362dc6e23 100644 --- a/spec/services/clusters/gcp/finalize_creation_service_spec.rb +++ b/spec/services/clusters/gcp/finalize_creation_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Gcp::FinalizeCreationService, '#execute' do +RSpec.describe Clusters::Gcp::FinalizeCreationService, '#execute' do include GoogleApi::CloudPlatformHelpers include KubernetesHelpers diff --git a/spec/services/clusters/gcp/provision_service_spec.rb b/spec/services/clusters/gcp/provision_service_spec.rb index dfd15690a1f..c5778db6001 100644 --- a/spec/services/clusters/gcp/provision_service_spec.rb +++ b/spec/services/clusters/gcp/provision_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Gcp::ProvisionService do +RSpec.describe Clusters::Gcp::ProvisionService do include GoogleApi::CloudPlatformHelpers describe '#execute' do diff --git a/spec/services/clusters/gcp/verify_provision_status_service_spec.rb b/spec/services/clusters/gcp/verify_provision_status_service_spec.rb index 584f9b8367f..ccb4b3b6c15 100644 --- a/spec/services/clusters/gcp/verify_provision_status_service_spec.rb +++ b/spec/services/clusters/gcp/verify_provision_status_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Gcp::VerifyProvisionStatusService do +RSpec.describe Clusters::Gcp::VerifyProvisionStatusService do include GoogleApi::CloudPlatformHelpers describe '#execute' do diff --git a/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb b/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb index e9f7f015293..b4402aadc88 100644 --- a/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb +++ b/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Kubernetes::ConfigureIstioIngressService, '#execute' do +RSpec.describe Clusters::Kubernetes::ConfigureIstioIngressService, '#execute' do include KubernetesHelpers let(:cluster) { create(:cluster, :project, :provided_by_gcp) } diff --git a/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb b/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb index 6d8b1617c17..ee10c59390e 100644 --- a/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb +++ b/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Kubernetes::CreateOrUpdateNamespaceService, '#execute' do +RSpec.describe Clusters::Kubernetes::CreateOrUpdateNamespaceService, '#execute' do include KubernetesHelpers let(:cluster) { create(:cluster, :project, :provided_by_gcp) } diff --git a/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb b/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb index 4bcd5c6933e..f3fa6c2c0bb 100644 --- a/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb +++ b/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do +RSpec.describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do include KubernetesHelpers let(:api_url) { 'http://111.111.111.111' } diff --git a/spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb b/spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb index fa4b6e497e5..c4daae9dbf0 100644 --- a/spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb +++ b/spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Kubernetes::FetchKubernetesTokenService do +RSpec.describe Clusters::Kubernetes::FetchKubernetesTokenService do include KubernetesHelpers describe '#execute' do diff --git a/spec/services/clusters/kubernetes_spec.rb b/spec/services/clusters/kubernetes_spec.rb index 09cc304debe..12af63890fc 100644 --- a/spec/services/clusters/kubernetes_spec.rb +++ b/spec/services/clusters/kubernetes_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Kubernetes do +RSpec.describe Clusters::Kubernetes do it { is_expected.to be_const_defined(:GITLAB_SERVICE_ACCOUNT_NAME) } it { is_expected.to be_const_defined(:GITLAB_SERVICE_ACCOUNT_NAMESPACE) } it { is_expected.to be_const_defined(:GITLAB_ADMIN_TOKEN_NAME) } diff --git a/spec/services/clusters/management/create_project_service_spec.rb b/spec/services/clusters/management/create_project_service_spec.rb index b7764b7840c..5d8cc71faa4 100644 --- a/spec/services/clusters/management/create_project_service_spec.rb +++ b/spec/services/clusters/management/create_project_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Management::CreateProjectService do +RSpec.describe Clusters::Management::CreateProjectService do let(:cluster) { create(:cluster, :project) } let(:current_user) { create(:user) } diff --git a/spec/services/clusters/management/validate_management_project_permissions_service_spec.rb b/spec/services/clusters/management/validate_management_project_permissions_service_spec.rb index 1bcebe2e2ac..a21c378d3d1 100644 --- a/spec/services/clusters/management/validate_management_project_permissions_service_spec.rb +++ b/spec/services/clusters/management/validate_management_project_permissions_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::Management::ValidateManagementProjectPermissionsService do +RSpec.describe Clusters::Management::ValidateManagementProjectPermissionsService do describe '#execute' do subject { described_class.new(user).execute(cluster, management_project_id) } diff --git a/spec/services/clusters/parse_cluster_applications_artifact_service_spec.rb b/spec/services/clusters/parse_cluster_applications_artifact_service_spec.rb index bb0b107eba6..3b155d95345 100644 --- a/spec/services/clusters/parse_cluster_applications_artifact_service_spec.rb +++ b/spec/services/clusters/parse_cluster_applications_artifact_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Clusters::ParseClusterApplicationsArtifactService do +RSpec.describe Clusters::ParseClusterApplicationsArtifactService do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } @@ -120,90 +120,9 @@ describe Clusters::ParseClusterApplicationsArtifactService do end end - context 'release is missing' do - let(:fixture) { 'spec/fixtures/helm/helm_list_v2_prometheus_missing.json.gz' } - let(:file) { fixture_file_upload(Rails.root.join(fixture)) } - let(:artifact) { create(:ci_job_artifact, :cluster_applications, job: job, file: file) } - - context 'application does not exist' do - it 'does not create or destroy an application' do - expect do - described_class.new(job, user).execute(artifact) - end.not_to change(Clusters::Applications::Prometheus, :count) - end - end - - context 'application exists' do - before do - create(:clusters_applications_prometheus, :installed, cluster: cluster) - end - - it 'marks the application as uninstalled' do - described_class.new(job, user).execute(artifact) - - cluster.application_prometheus.reload - expect(cluster.application_prometheus).to be_uninstalled - end - end - end - - context 'release is deployed' do - let(:fixture) { 'spec/fixtures/helm/helm_list_v2_prometheus_deployed.json.gz' } - let(:file) { fixture_file_upload(Rails.root.join(fixture)) } - let(:artifact) { create(:ci_job_artifact, :cluster_applications, job: job, file: file) } - - context 'application does not exist' do - it 'creates an application and marks it as installed' do - expect do - described_class.new(job, user).execute(artifact) - end.to change(Clusters::Applications::Prometheus, :count) - - expect(cluster.application_prometheus).to be_persisted - expect(cluster.application_prometheus).to be_installed - end - end - - context 'application exists' do - before do - create(:clusters_applications_prometheus, :errored, cluster: cluster) - end - - it 'marks the application as installed' do - described_class.new(job, user).execute(artifact) - - expect(cluster.application_prometheus).to be_installed - end - end - end - - context 'release is failed' do - let(:fixture) { 'spec/fixtures/helm/helm_list_v2_prometheus_failed.json.gz' } - let(:file) { fixture_file_upload(Rails.root.join(fixture)) } - let(:artifact) { create(:ci_job_artifact, :cluster_applications, job: job, file: file) } - - context 'application does not exist' do - it 'creates an application and marks it as errored' do - expect do - described_class.new(job, user).execute(artifact) - end.to change(Clusters::Applications::Prometheus, :count) - - expect(cluster.application_prometheus).to be_persisted - expect(cluster.application_prometheus).to be_errored - expect(cluster.application_prometheus.status_reason).to eq('Helm release failed to install') - end - end - - context 'application exists' do - before do - create(:clusters_applications_prometheus, :installed, cluster: cluster) - end - - it 'marks the application as errored' do - described_class.new(job, user).execute(artifact) - - expect(cluster.application_prometheus).to be_errored - expect(cluster.application_prometheus.status_reason).to eq('Helm release failed to install') - end + Clusters::ParseClusterApplicationsArtifactService::RELEASE_NAMES.each do |release_name| + context release_name do + include_examples 'parse cluster applications artifact', release_name end end end diff --git a/spec/services/clusters/update_service_spec.rb b/spec/services/clusters/update_service_spec.rb index 5a7726eded8..e496ccd5c23 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 +RSpec.describe Clusters::UpdateService do include KubernetesHelpers describe '#execute' do diff --git a/spec/services/cohorts_service_spec.rb b/spec/services/cohorts_service_spec.rb index b2f82a1153c..dce8d4f80f2 100644 --- a/spec/services/cohorts_service_spec.rb +++ b/spec/services/cohorts_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe CohortsService do +RSpec.describe CohortsService do describe '#execute' do def month_start(months_ago) months_ago.months.ago.beginning_of_month.to_date diff --git a/spec/services/commits/cherry_pick_service_spec.rb b/spec/services/commits/cherry_pick_service_spec.rb index 3b797b8ac02..8fad5164b77 100644 --- a/spec/services/commits/cherry_pick_service_spec.rb +++ b/spec/services/commits/cherry_pick_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Commits::CherryPickService do +RSpec.describe Commits::CherryPickService do let(:project) { create(:project, :repository) } # * ddd0f15ae83993f5cb66a927a28673882e99100b (HEAD -> master, origin/master, origin/HEAD) Merge branch 'po-fix-test-en # |\ diff --git a/spec/services/commits/commit_patch_service_spec.rb b/spec/services/commits/commit_patch_service_spec.rb index f4fcec2fbc2..c8c0cbe23b2 100644 --- a/spec/services/commits/commit_patch_service_spec.rb +++ b/spec/services/commits/commit_patch_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Commits::CommitPatchService do +RSpec.describe Commits::CommitPatchService do describe '#execute' do let(:patches) do patches_folder = Rails.root.join('spec/fixtures/patchfiles') diff --git a/spec/services/commits/tag_service_spec.rb b/spec/services/commits/tag_service_spec.rb index 82377a8dace..dd742ebe469 100644 --- a/spec/services/commits/tag_service_spec.rb +++ b/spec/services/commits/tag_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Commits::TagService do +RSpec.describe Commits::TagService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } diff --git a/spec/services/compare_service_spec.rb b/spec/services/compare_service_spec.rb index f6d8eb348d0..e96a7f2f4f4 100644 --- a/spec/services/compare_service_spec.rb +++ b/spec/services/compare_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe CompareService do +RSpec.describe CompareService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:service) { described_class.new(project, 'feature') } diff --git a/spec/services/concerns/exclusive_lease_guard_spec.rb b/spec/services/concerns/exclusive_lease_guard_spec.rb index a38facc7520..d54ba6abadd 100644 --- a/spec/services/concerns/exclusive_lease_guard_spec.rb +++ b/spec/services/concerns/exclusive_lease_guard_spec.rb @@ -51,7 +51,7 @@ RSpec.describe ExclusiveLeaseGuard, :clean_gitlab_redis_shared_state do it 'does not call internal_method but logs error', :aggregate_failures do expect(subject).not_to receive(:internal_method) - expect(Gitlab::AppLogger).to receive(:error).with('Cannot obtain an exclusive lease. There must be another instance already in execution.') + expect(Gitlab::AppLogger).to receive(:error).with("Cannot obtain an exclusive lease for #{subject.class.name}. There must be another instance already in execution.") subject.call end diff --git a/spec/services/concerns/merge_requests/assigns_merge_params_spec.rb b/spec/services/concerns/merge_requests/assigns_merge_params_spec.rb index 9cf7f354191..5b1e8fca31b 100644 --- a/spec/services/concerns/merge_requests/assigns_merge_params_spec.rb +++ b/spec/services/concerns/merge_requests/assigns_merge_params_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::AssignsMergeParams do +RSpec.describe MergeRequests::AssignsMergeParams do it 'raises an error when used from an instance that does not respond to #current_user' do define_class = -> { Class.new { include MergeRequests::AssignsMergeParams }.new } diff --git a/spec/services/container_expiration_policies/update_service_spec.rb b/spec/services/container_expiration_policies/update_service_spec.rb index ec178f3830f..d4b6715ae86 100644 --- a/spec/services/container_expiration_policies/update_service_spec.rb +++ b/spec/services/container_expiration_policies/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ContainerExpirationPolicies::UpdateService do +RSpec.describe ContainerExpirationPolicies::UpdateService do using RSpec::Parameterized::TableSyntax let_it_be(:project, reload: true) { create(:project) } diff --git a/spec/services/container_expiration_policy_service_spec.rb b/spec/services/container_expiration_policy_service_spec.rb index 97715b990ef..dfce51d73ad 100644 --- a/spec/services/container_expiration_policy_service_spec.rb +++ b/spec/services/container_expiration_policy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ContainerExpirationPolicyService do +RSpec.describe ContainerExpirationPolicyService do let_it_be(:user) { create(:user) } let_it_be(:container_expiration_policy) { create(:container_expiration_policy, :runnable) } let(:project) { container_expiration_policy.project } diff --git a/spec/services/deploy_keys/collect_keys_service_spec.rb b/spec/services/deploy_keys/collect_keys_service_spec.rb new file mode 100644 index 00000000000..3442e5e456a --- /dev/null +++ b/spec/services/deploy_keys/collect_keys_service_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe DeployKeys::CollectKeysService do + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, :private) } + + subject { DeployKeys::CollectKeysService.new(project, user) } + + before do + project&.add_developer(user) + end + + context 'when no project is passed in' do + let(:project) { nil } + + it 'returns an empty Array' do + expect(subject.execute).to be_empty + end + end + + context 'when no user is passed in' do + let(:user) { nil } + + it 'returns an empty Array' do + expect(subject.execute).to be_empty + end + end + + context 'when a project is passed in' do + let_it_be(:deploy_keys_project) { create(:deploy_keys_project, :write_access, project: project) } + let_it_be(:deploy_key) { deploy_keys_project.deploy_key } + + it 'only returns deploy keys with write access' do + create(:deploy_keys_project, project: project) + + expect(subject.execute).to contain_exactly(deploy_key) + end + + it 'returns deploy keys only for this project' do + other_project = create(:project) + create(:deploy_keys_project, :write_access, project: other_project) + + expect(subject.execute).to contain_exactly(deploy_key) + end + end + + context 'when the user cannot read the project' do + before do + project.members.delete_all + end + + it 'returns an empty Array' do + expect(subject.execute).to be_empty + end + end +end diff --git a/spec/services/deploy_keys/create_service_spec.rb b/spec/services/deploy_keys/create_service_spec.rb index a55f1561194..2e3318236f5 100644 --- a/spec/services/deploy_keys/create_service_spec.rb +++ b/spec/services/deploy_keys/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe DeployKeys::CreateService do +RSpec.describe DeployKeys::CreateService do let(:user) { create(:user) } let(:params) { attributes_for(:deploy_key) } diff --git a/spec/services/deployments/after_create_service_spec.rb b/spec/services/deployments/after_create_service_spec.rb index 5a69ffd8b9c..3287eed03b7 100644 --- a/spec/services/deployments/after_create_service_spec.rb +++ b/spec/services/deployments/after_create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Deployments::AfterCreateService do +RSpec.describe Deployments::AfterCreateService do let(:user) { create(:user) } let(:project) { create(:project, :repository) } let(:options) { { name: 'production' } } diff --git a/spec/services/deployments/create_service_spec.rb b/spec/services/deployments/create_service_spec.rb index 6ab1f8635f7..d1f977c28d3 100644 --- a/spec/services/deployments/create_service_spec.rb +++ b/spec/services/deployments/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Deployments::CreateService do +RSpec.describe Deployments::CreateService do let(:user) { create(:user) } describe '#execute' do diff --git a/spec/services/deployments/link_merge_requests_service_spec.rb b/spec/services/deployments/link_merge_requests_service_spec.rb index aa2cecbf897..e2ac2273b8c 100644 --- a/spec/services/deployments/link_merge_requests_service_spec.rb +++ b/spec/services/deployments/link_merge_requests_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Deployments::LinkMergeRequestsService do +RSpec.describe Deployments::LinkMergeRequestsService do let(:project) { create(:project, :repository) } # * ddd0f15 Merge branch 'po-fix-test-env-path' into 'master' diff --git a/spec/services/deployments/older_deployments_drop_service_spec.rb b/spec/services/deployments/older_deployments_drop_service_spec.rb index 4c9bcf90533..6152a95cc3c 100644 --- a/spec/services/deployments/older_deployments_drop_service_spec.rb +++ b/spec/services/deployments/older_deployments_drop_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Deployments::OlderDeploymentsDropService do +RSpec.describe Deployments::OlderDeploymentsDropService do let(:environment) { create(:environment) } let(:deployment) { create(:deployment, environment: environment) } let(:service) { described_class.new(deployment) } diff --git a/spec/services/deployments/update_service_spec.rb b/spec/services/deployments/update_service_spec.rb index 471e90de467..16b24d0dee8 100644 --- a/spec/services/deployments/update_service_spec.rb +++ b/spec/services/deployments/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Deployments::UpdateService do +RSpec.describe Deployments::UpdateService do let(:deploy) { create(:deployment) } describe '#execute' do diff --git a/spec/services/design_management/delete_designs_service_spec.rb b/spec/services/design_management/delete_designs_service_spec.rb index bf5d6b443e6..ace63b6e59c 100644 --- a/spec/services/design_management/delete_designs_service_spec.rb +++ b/spec/services/design_management/delete_designs_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe DesignManagement::DeleteDesignsService do +RSpec.describe DesignManagement::DeleteDesignsService do include DesignManagementTestHelpers let_it_be(:project) { create(:project) } diff --git a/spec/services/design_management/design_user_notes_count_service_spec.rb b/spec/services/design_management/design_user_notes_count_service_spec.rb index 62211a4dd0f..37806d3461c 100644 --- a/spec/services/design_management/design_user_notes_count_service_spec.rb +++ b/spec/services/design_management/design_user_notes_count_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe DesignManagement::DesignUserNotesCountService, :use_clean_rails_memory_store_caching do +RSpec.describe DesignManagement::DesignUserNotesCountService, :use_clean_rails_memory_store_caching do let_it_be(:design) { create(:design, :with_file) } subject { described_class.new(design) } diff --git a/spec/services/design_management/generate_image_versions_service_spec.rb b/spec/services/design_management/generate_image_versions_service_spec.rb index cd021c8d7d3..631eec97e5a 100644 --- a/spec/services/design_management/generate_image_versions_service_spec.rb +++ b/spec/services/design_management/generate_image_versions_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe DesignManagement::GenerateImageVersionsService do +RSpec.describe DesignManagement::GenerateImageVersionsService do let_it_be(:project) { create(:project) } let_it_be(:issue) { create(:issue, project: project) } let_it_be(:version) { create(:design, :with_lfs_file, issue: issue).versions.first } diff --git a/spec/services/design_management/save_designs_service_spec.rb b/spec/services/design_management/save_designs_service_spec.rb index 3be3ac9daca..24639632566 100644 --- a/spec/services/design_management/save_designs_service_spec.rb +++ b/spec/services/design_management/save_designs_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe DesignManagement::SaveDesignsService do +RSpec.describe DesignManagement::SaveDesignsService do include DesignManagementTestHelpers include ConcurrentHelpers diff --git a/spec/services/discussions/capture_diff_note_position_service_spec.rb b/spec/services/discussions/capture_diff_note_position_service_spec.rb index bc71e170e92..0913ddd8ef2 100644 --- a/spec/services/discussions/capture_diff_note_position_service_spec.rb +++ b/spec/services/discussions/capture_diff_note_position_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Discussions::CaptureDiffNotePositionService do +RSpec.describe Discussions::CaptureDiffNotePositionService do subject { described_class.new(note.noteable, paths) } context 'image note on diff' do diff --git a/spec/services/discussions/capture_diff_note_positions_service_spec.rb b/spec/services/discussions/capture_diff_note_positions_service_spec.rb index 7b1e207f3eb..dede5a4c354 100644 --- a/spec/services/discussions/capture_diff_note_positions_service_spec.rb +++ b/spec/services/discussions/capture_diff_note_positions_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Discussions::CaptureDiffNotePositionsService do +RSpec.describe Discussions::CaptureDiffNotePositionsService do context 'when merge request has a discussion' do let(:source_branch) { 'compare-with-merge-head-source' } let(:target_branch) { 'compare-with-merge-head-target' } diff --git a/spec/services/discussions/resolve_service_spec.rb b/spec/services/discussions/resolve_service_spec.rb index 7461934b455..5ff0d535b46 100644 --- a/spec/services/discussions/resolve_service_spec.rb +++ b/spec/services/discussions/resolve_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Discussions::ResolveService do +RSpec.describe Discussions::ResolveService do describe '#execute' do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user, developer_projects: [project]) } diff --git a/spec/services/discussions/update_diff_position_service_spec.rb b/spec/services/discussions/update_diff_position_service_spec.rb index 60ec83e9062..85020e95c83 100644 --- a/spec/services/discussions/update_diff_position_service_spec.rb +++ b/spec/services/discussions/update_diff_position_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Discussions::UpdateDiffPositionService do +RSpec.describe Discussions::UpdateDiffPositionService do let(:project) { create(:project, :repository) } let(:current_user) { project.owner } let(:create_commit) { project.commit("913c66a37b4a45b9769037c55c2d238bd0942d2e") } diff --git a/spec/services/draft_notes/create_service_spec.rb b/spec/services/draft_notes/create_service_spec.rb index 8f244ed386b..f0291067777 100644 --- a/spec/services/draft_notes/create_service_spec.rb +++ b/spec/services/draft_notes/create_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe DraftNotes::CreateService do +RSpec.describe DraftNotes::CreateService do let(:merge_request) { create(:merge_request) } let(:project) { merge_request.target_project } let(:user) { merge_request.author } diff --git a/spec/services/draft_notes/destroy_service_spec.rb b/spec/services/draft_notes/destroy_service_spec.rb index d0bf88dcdbe..f725f08f3c7 100644 --- a/spec/services/draft_notes/destroy_service_spec.rb +++ b/spec/services/draft_notes/destroy_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe DraftNotes::DestroyService do +RSpec.describe DraftNotes::DestroyService do let(:merge_request) { create(:merge_request) } let(:project) { merge_request.target_project } let(:user) { merge_request.author } diff --git a/spec/services/draft_notes/publish_service_spec.rb b/spec/services/draft_notes/publish_service_spec.rb index 4ebae2f9aa2..ae0c8113904 100644 --- a/spec/services/draft_notes/publish_service_spec.rb +++ b/spec/services/draft_notes/publish_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe DraftNotes::PublishService do +RSpec.describe DraftNotes::PublishService do include RepoHelpers let(:merge_request) { create(:merge_request) } @@ -237,7 +237,8 @@ describe DraftNotes::PublishService do it 'resolves the thread' do publish(draft: draft_note) - expect(note.discussion.resolved?).to be true + # discussion is memoized and reload doesn't clear the memoization + expect(Note.find(note.id).discussion.resolved?).to be true end it 'sends notifications if all threads are resolved' do diff --git a/spec/services/emails/confirm_service_spec.rb b/spec/services/emails/confirm_service_spec.rb index 973d2731b2f..935a673f548 100644 --- a/spec/services/emails/confirm_service_spec.rb +++ b/spec/services/emails/confirm_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Emails::ConfirmService do +RSpec.describe Emails::ConfirmService do let(:user) { create(:user) } subject(:service) { described_class.new(user) } diff --git a/spec/services/emails/create_service_spec.rb b/spec/services/emails/create_service_spec.rb index 23c2f53dca0..1396a1fce30 100644 --- a/spec/services/emails/create_service_spec.rb +++ b/spec/services/emails/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Emails::CreateService do +RSpec.describe Emails::CreateService do let(:user) { create(:user) } let(:opts) { { email: 'new@email.com', user: user } } diff --git a/spec/services/emails/destroy_service_spec.rb b/spec/services/emails/destroy_service_spec.rb index 9e14a13aa4f..f8407be41e7 100644 --- a/spec/services/emails/destroy_service_spec.rb +++ b/spec/services/emails/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Emails::DestroyService do +RSpec.describe Emails::DestroyService do let!(:user) { create(:user) } let!(:email) { create(:email, user: user) } diff --git a/spec/services/environments/auto_stop_service_spec.rb b/spec/services/environments/auto_stop_service_spec.rb index b34d15889d3..8e56c7e642c 100644 --- a/spec/services/environments/auto_stop_service_spec.rb +++ b/spec/services/environments/auto_stop_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Environments::AutoStopService, :clean_gitlab_redis_shared_state do +RSpec.describe Environments::AutoStopService, :clean_gitlab_redis_shared_state do include CreateEnvironmentsHelpers include ExclusiveLeaseHelpers diff --git a/spec/services/environments/reset_auto_stop_service_spec.rb b/spec/services/environments/reset_auto_stop_service_spec.rb index 53a20dd906e..cab1bf2cc26 100644 --- a/spec/services/environments/reset_auto_stop_service_spec.rb +++ b/spec/services/environments/reset_auto_stop_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Environments::ResetAutoStopService do +RSpec.describe Environments::ResetAutoStopService do let_it_be(:project) { create(:project) } let_it_be(:developer) { create(:user).tap { |user| project.add_developer(user) } } let_it_be(:reporter) { create(:user).tap { |user| project.add_reporter(user) } } diff --git a/spec/services/error_tracking/base_service_spec.rb b/spec/services/error_tracking/base_service_spec.rb index 68deb2e2a73..ffbda37d417 100644 --- a/spec/services/error_tracking/base_service_spec.rb +++ b/spec/services/error_tracking/base_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ErrorTracking::BaseService do +RSpec.describe ErrorTracking::BaseService do describe '#compose_response' do let(:project) { double('project') } let(:user) { double('user') } diff --git a/spec/services/error_tracking/issue_details_service_spec.rb b/spec/services/error_tracking/issue_details_service_spec.rb index 66b8988f8e3..1954640a512 100644 --- a/spec/services/error_tracking/issue_details_service_spec.rb +++ b/spec/services/error_tracking/issue_details_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ErrorTracking::IssueDetailsService do +RSpec.describe ErrorTracking::IssueDetailsService do include_context 'sentry error tracking context' subject { described_class.new(project, user, params) } diff --git a/spec/services/error_tracking/issue_latest_event_service_spec.rb b/spec/services/error_tracking/issue_latest_event_service_spec.rb index 078d7511850..b7560762ae4 100644 --- a/spec/services/error_tracking/issue_latest_event_service_spec.rb +++ b/spec/services/error_tracking/issue_latest_event_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ErrorTracking::IssueLatestEventService do +RSpec.describe ErrorTracking::IssueLatestEventService do include_context 'sentry error tracking context' subject { described_class.new(project, user) } diff --git a/spec/services/error_tracking/issue_update_service_spec.rb b/spec/services/error_tracking/issue_update_service_spec.rb index a13d42ec141..9ed24038ed8 100644 --- a/spec/services/error_tracking/issue_update_service_spec.rb +++ b/spec/services/error_tracking/issue_update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ErrorTracking::IssueUpdateService do +RSpec.describe ErrorTracking::IssueUpdateService do include_context 'sentry error tracking context' let(:arguments) { { issue_id: non_existing_record_id, status: 'resolved' } } diff --git a/spec/services/error_tracking/list_issues_service_spec.rb b/spec/services/error_tracking/list_issues_service_spec.rb index 5f6e071e10d..518f2a80826 100644 --- a/spec/services/error_tracking/list_issues_service_spec.rb +++ b/spec/services/error_tracking/list_issues_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ErrorTracking::ListIssuesService do +RSpec.describe ErrorTracking::ListIssuesService do include_context 'sentry error tracking context' let(:params) { { search_term: 'something', sort: 'last_seen', cursor: 'some-cursor' } } diff --git a/spec/services/error_tracking/list_projects_service_spec.rb b/spec/services/error_tracking/list_projects_service_spec.rb index 565610c64ac..8bc632349fa 100644 --- a/spec/services/error_tracking/list_projects_service_spec.rb +++ b/spec/services/error_tracking/list_projects_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ErrorTracking::ListProjectsService do +RSpec.describe ErrorTracking::ListProjectsService do let_it_be(:user) { create(:user) } let_it_be(:project, reload: true) { create(:project) } diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb index 73c089334ed..d10ed7d6640 100644 --- a/spec/services/event_create_service_spec.rb +++ b/spec/services/event_create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe EventCreateService do +RSpec.describe EventCreateService do let(:service) { described_class.new } let_it_be(:user, reload: true) { create :user } @@ -16,7 +16,6 @@ describe EventCreateService do it "creates new event" do expect { service.open_issue(issue, issue.author) }.to change { Event.count } - expect { service.open_issue(issue, issue.author) }.to change { ResourceStateEvent.count } end end @@ -27,7 +26,6 @@ describe EventCreateService do it "creates new event" do expect { service.close_issue(issue, issue.author) }.to change { Event.count } - expect { service.close_issue(issue, issue.author) }.to change { ResourceStateEvent.count } end end @@ -38,7 +36,6 @@ describe EventCreateService do it "creates new event" do expect { service.reopen_issue(issue, issue.author) }.to change { Event.count } - expect { service.reopen_issue(issue, issue.author) }.to change { ResourceStateEvent.count } end end end @@ -51,7 +48,6 @@ describe EventCreateService do it "creates new event" do expect { service.open_mr(merge_request, merge_request.author) }.to change { Event.count } - expect { service.open_mr(merge_request, merge_request.author) }.to change { ResourceStateEvent.count } end end @@ -62,7 +58,6 @@ describe EventCreateService do it "creates new event" do expect { service.close_mr(merge_request, merge_request.author) }.to change { Event.count } - expect { service.close_mr(merge_request, merge_request.author) }.to change { ResourceStateEvent.count } end end @@ -73,7 +68,6 @@ describe EventCreateService do it "creates new event" do expect { service.merge_mr(merge_request, merge_request.author) }.to change { Event.count } - expect { service.merge_mr(merge_request, merge_request.author) }.to change { ResourceStateEvent.count } end end @@ -84,7 +78,18 @@ describe EventCreateService do it "creates new event" do expect { service.reopen_mr(merge_request, merge_request.author) }.to change { Event.count } - expect { service.reopen_mr(merge_request, merge_request.author) }.to change { ResourceStateEvent.count } + end + end + + describe '#approve_mr' do + let(:merge_request) { create(:merge_request) } + + it { expect(service.approve_mr(merge_request, user)).to be_truthy } + + it 'creates new event' do + service.approve_mr(merge_request, user) + + change { Event.approved_action.where(target: merge_request).count }.by(1) end end end @@ -161,7 +166,7 @@ describe EventCreateService do end end - describe '#wiki_event' do + describe '#wiki_event', :clean_gitlab_redis_shared_state do let_it_be(:user) { create(:user) } let_it_be(:wiki_page) { create(:wiki_page) } let_it_be(:meta) { create(:wiki_page_meta, :for_wiki_page, wiki_page: wiki_page) } @@ -181,6 +186,16 @@ describe EventCreateService do ) end + it 'records the event in the event counter' do + stub_feature_flags(Gitlab::UsageDataCounters::TrackUniqueActions::FEATURE_FLAG => true) + counter_class = Gitlab::UsageDataCounters::TrackUniqueActions + tracking_params = { event_action: counter_class::WIKI_ACTION, date_from: Date.yesterday, date_to: Date.today } + + expect { event } + .to change { counter_class.count_unique_events(tracking_params) } + .from(0).to(1) + end + it 'is idempotent', :aggregate_failures do expect { event }.to change(Event, :count).by(1) duplicate = nil @@ -188,16 +203,6 @@ describe EventCreateService do expect(duplicate).to eq(event) end - - context 'the feature is disabled' do - before do - stub_feature_flags(wiki_events: false) - end - - it 'does not create the event' do - expect { event }.not_to change(Event, :count) - end - end end end @@ -229,6 +234,16 @@ describe EventCreateService do subject { service.push(project, user, push_data) } it_behaves_like 'service for creating a push event', PushEventPayloadService + + it 'records the event in the event counter' do + stub_feature_flags(Gitlab::UsageDataCounters::TrackUniqueActions::FEATURE_FLAG => true) + counter_class = Gitlab::UsageDataCounters::TrackUniqueActions + tracking_params = { event_action: counter_class::PUSH_ACTION, date_from: Date.yesterday, date_to: Date.today } + + expect { subject } + .to change { counter_class.count_unique_events(tracking_params) } + .from(0).to(1) + end end describe '#bulk_push', :clean_gitlab_redis_shared_state do @@ -243,6 +258,16 @@ describe EventCreateService do subject { service.bulk_push(project, user, push_data) } it_behaves_like 'service for creating a push event', BulkPushEventPayloadService + + it 'records the event in the event counter' do + stub_feature_flags(Gitlab::UsageDataCounters::TrackUniqueActions::FEATURE_FLAG => true) + counter_class = Gitlab::UsageDataCounters::TrackUniqueActions + tracking_params = { event_action: counter_class::PUSH_ACTION, date_from: Date.yesterday, date_to: Date.today } + + expect { subject } + .to change { counter_class.count_unique_events(tracking_params) } + .from(0).to(1) + end end describe 'Project' do @@ -261,31 +286,10 @@ describe EventCreateService do end end - describe 'design events' do + describe 'design events', :clean_gitlab_redis_shared_state do let_it_be(:design) { create(:design, project: project) } let_it_be(:author) { user } - shared_examples 'feature flag gated multiple event creation' do - context 'the feature flag is off' do - before do - stub_feature_flags(design_activity_events: false) - end - - specify { expect(result).to be_empty } - specify { expect { result }.not_to change { Event.count } } - specify { expect { result }.not_to exceed_query_limit(0) } - end - - context 'the feature flag is enabled for a single project' do - before do - stub_feature_flags(design_activity_events: project) - end - - specify { expect(result).not_to be_empty } - specify { expect { result }.to change { Event.count }.by(1) } - end - end - describe '#save_designs' do let_it_be(:updated) { create_list(:design, 5) } let_it_be(:created) { create_list(:design, 3) } @@ -310,8 +314,14 @@ describe EventCreateService do expect(events.map(&:design)).to match_array(updated) end - it_behaves_like 'feature flag gated multiple event creation' do - let(:project) { created.first.project } + it 'records the event in the event counter' do + stub_feature_flags(Gitlab::UsageDataCounters::TrackUniqueActions::FEATURE_FLAG => true) + counter_class = Gitlab::UsageDataCounters::TrackUniqueActions + tracking_params = { event_action: counter_class::DESIGN_ACTION, date_from: Date.yesterday, date_to: Date.today } + + expect { result } + .to change { counter_class.count_unique_events(tracking_params) } + .from(0).to(1) end end @@ -332,8 +342,14 @@ describe EventCreateService do expect(events.map(&:design)).to match_array(designs) end - it_behaves_like 'feature flag gated multiple event creation' do - let(:project) { designs.first.project } + it 'records the event in the event counter' do + stub_feature_flags(Gitlab::UsageDataCounters::TrackUniqueActions::FEATURE_FLAG => true) + counter_class = Gitlab::UsageDataCounters::TrackUniqueActions + tracking_params = { event_action: counter_class::DESIGN_ACTION, date_from: Date.yesterday, date_to: Date.today } + + expect { result } + .to change { counter_class.count_unique_events(tracking_params) } + .from(0).to(1) end end end diff --git a/spec/services/events/render_service_spec.rb b/spec/services/events/render_service_spec.rb index a623a05a56d..24a3b9abe14 100644 --- a/spec/services/events/render_service_spec.rb +++ b/spec/services/events/render_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Events::RenderService do +RSpec.describe Events::RenderService do describe '#execute' do let!(:note) { build(:note) } let!(:event) { build(:event, target: note, project: note.project) } diff --git a/spec/services/files/create_service_spec.rb b/spec/services/files/create_service_spec.rb index 195f56a2909..3b3dbd1fcfe 100644 --- a/spec/services/files/create_service_spec.rb +++ b/spec/services/files/create_service_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -describe Files::CreateService do +RSpec.describe Files::CreateService do let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:user) { create(:user, :commit_email) } diff --git a/spec/services/files/delete_service_spec.rb b/spec/services/files/delete_service_spec.rb index b849def06fc..17e4645fde6 100644 --- a/spec/services/files/delete_service_spec.rb +++ b/spec/services/files/delete_service_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -describe Files::DeleteService do +RSpec.describe Files::DeleteService do subject { described_class.new(project, user, commit_params) } let(:project) { create(:project, :repository) } diff --git a/spec/services/files/multi_service_spec.rb b/spec/services/files/multi_service_spec.rb index 0f51c72019e..6a5c7d2749d 100644 --- a/spec/services/files/multi_service_spec.rb +++ b/spec/services/files/multi_service_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -describe Files::MultiService do +RSpec.describe Files::MultiService do subject { described_class.new(project, user, commit_params) } let(:project) { create(:project, :repository) } diff --git a/spec/services/files/update_service_spec.rb b/spec/services/files/update_service_spec.rb index 37869b176ef..84d78b4c2bc 100644 --- a/spec/services/files/update_service_spec.rb +++ b/spec/services/files/update_service_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -describe Files::UpdateService do +RSpec.describe Files::UpdateService do subject { described_class.new(project, user, commit_params) } let(:project) { create(:project, :repository) } diff --git a/spec/services/git/base_hooks_service_spec.rb b/spec/services/git/base_hooks_service_spec.rb index 07ce560bd88..661c77b56bb 100644 --- a/spec/services/git/base_hooks_service_spec.rb +++ b/spec/services/git/base_hooks_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Git::BaseHooksService do +RSpec.describe Git::BaseHooksService do include RepoHelpers include GitHelpers diff --git a/spec/services/git/branch_hooks_service_spec.rb b/spec/services/git/branch_hooks_service_spec.rb index 908b9772c40..7f22af8bfc6 100644 --- a/spec/services/git/branch_hooks_service_spec.rb +++ b/spec/services/git/branch_hooks_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Git::BranchHooksService do +RSpec.describe Git::BranchHooksService do include RepoHelpers include ProjectForksHelper diff --git a/spec/services/git/branch_push_service_spec.rb b/spec/services/git/branch_push_service_spec.rb index 6ecc1a62ff3..6ccf2d03e4a 100644 --- a/spec/services/git/branch_push_service_spec.rb +++ b/spec/services/git/branch_push_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Git::BranchPushService, services: true do +RSpec.describe Git::BranchPushService, services: true do include RepoHelpers let_it_be(:user) { create(:user) } @@ -635,6 +635,37 @@ describe Git::BranchPushService, services: true do end end + describe 'artifacts' do + context 'create branch' do + let(:oldrev) { blankrev } + + it 'does nothing' do + expect(::Ci::RefDeleteUnlockArtifactsWorker).not_to receive(:perform_async) + + execute_service(project, user, oldrev: oldrev, newrev: newrev, ref: ref) + end + end + + context 'update branch' do + it 'does nothing' do + expect(::Ci::RefDeleteUnlockArtifactsWorker).not_to receive(:perform_async) + + execute_service(project, user, oldrev: oldrev, newrev: newrev, ref: ref) + end + end + + context 'delete branch' do + let(:newrev) { blankrev } + + it 'unlocks artifacts' do + expect(::Ci::RefDeleteUnlockArtifactsWorker) + .to receive(:perform_async).with(project.id, user.id, "refs/heads/#{branch}") + + execute_service(project, user, oldrev: oldrev, newrev: newrev, ref: ref) + end + end + end + describe 'Hooks' do context 'run on a branch' do it 'delegates to Git::BranchHooksService' do diff --git a/spec/services/git/process_ref_changes_service_spec.rb b/spec/services/git/process_ref_changes_service_spec.rb index 924e913a9ec..c2fb40a0ed0 100644 --- a/spec/services/git/process_ref_changes_service_spec.rb +++ b/spec/services/git/process_ref_changes_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Git::ProcessRefChangesService do +RSpec.describe Git::ProcessRefChangesService do let(:project) { create(:project, :repository) } let(:user) { project.owner } let(:params) { { changes: git_changes } } diff --git a/spec/services/git/tag_hooks_service_spec.rb b/spec/services/git/tag_hooks_service_spec.rb index 094ccd8c9f0..4443c46a414 100644 --- a/spec/services/git/tag_hooks_service_spec.rb +++ b/spec/services/git/tag_hooks_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Git::TagHooksService, :service do +RSpec.describe Git::TagHooksService, :service do let(:user) { create(:user) } let(:project) { create(:project, :repository) } diff --git a/spec/services/git/tag_push_service_spec.rb b/spec/services/git/tag_push_service_spec.rb index 9688041c08c..87dbf79a245 100644 --- a/spec/services/git/tag_push_service_spec.rb +++ b/spec/services/git/tag_push_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Git::TagPushService do +RSpec.describe Git::TagPushService do include RepoHelpers include GitHelpers @@ -10,9 +10,11 @@ describe Git::TagPushService do let(:project) { create(:project, :repository) } let(:service) { described_class.new(project, user, change: { oldrev: oldrev, newrev: newrev, ref: ref }) } - let(:oldrev) { Gitlab::Git::BLANK_SHA } + let(:blankrev) { Gitlab::Git::BLANK_SHA } + let(:oldrev) { blankrev } let(:newrev) { "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b" } # gitlab-test: git rev-parse refs/tags/v1.1.0 - let(:ref) { 'refs/tags/v1.1.0' } + let(:tag) { 'v1.1.0' } + let(:ref) { "refs/tags/#{tag}" } describe "Push tags" do subject do @@ -58,4 +60,35 @@ describe Git::TagPushService do end end end + + describe 'artifacts' do + context 'create tag' do + let(:oldrev) { blankrev } + + it 'does nothing' do + expect(::Ci::RefDeleteUnlockArtifactsWorker).not_to receive(:perform_async) + + service.execute + end + end + + context 'update tag' do + it 'does nothing' do + expect(::Ci::RefDeleteUnlockArtifactsWorker).not_to receive(:perform_async) + + service.execute + end + end + + context 'delete tag' do + let(:newrev) { blankrev } + + it 'unlocks artifacts' do + expect(::Ci::RefDeleteUnlockArtifactsWorker) + .to receive(:perform_async).with(project.id, user.id, "refs/tags/#{tag}") + + service.execute + end + end + end end diff --git a/spec/services/git/wiki_push_service/change_spec.rb b/spec/services/git/wiki_push_service/change_spec.rb index 4da3f0fc738..3616bf62b20 100644 --- a/spec/services/git/wiki_push_service/change_spec.rb +++ b/spec/services/git/wiki_push_service/change_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Git::WikiPushService::Change do +RSpec.describe Git::WikiPushService::Change do subject { described_class.new(project_wiki, change, raw_change) } let(:project_wiki) { double('ProjectWiki') } diff --git a/spec/services/git/wiki_push_service_spec.rb b/spec/services/git/wiki_push_service_spec.rb index b2234c81c24..f338b7a5709 100644 --- a/spec/services/git/wiki_push_service_spec.rb +++ b/spec/services/git/wiki_push_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Git::WikiPushService, services: true do +RSpec.describe Git::WikiPushService, services: true do include RepoHelpers let_it_be(:key_id) { create(:key, user: current_user).shell_id } @@ -247,14 +247,6 @@ describe Git::WikiPushService, services: true do end end - context 'the wiki_events feature is disabled' do - before do - stub_feature_flags(wiki_events: false) - end - - it_behaves_like 'a no-op push' - end - context 'the wiki_events_on_git_push feature is disabled' do before do stub_feature_flags(wiki_events_on_git_push: false) diff --git a/spec/services/gpg_keys/create_service_spec.rb b/spec/services/gpg_keys/create_service_spec.rb index 8dfc9f19439..9ac56355b4b 100644 --- a/spec/services/gpg_keys/create_service_spec.rb +++ b/spec/services/gpg_keys/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe GpgKeys::CreateService do +RSpec.describe GpgKeys::CreateService do let(:user) { create(:user) } let(:params) { attributes_for(:gpg_key) } diff --git a/spec/services/gpg_keys/destroy_service_spec.rb b/spec/services/gpg_keys/destroy_service_spec.rb new file mode 100644 index 00000000000..b9aa3e351c9 --- /dev/null +++ b/spec/services/gpg_keys/destroy_service_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GpgKeys::DestroyService do + let(:user) { create(:user) } + + subject { described_class.new(user) } + + it 'destroys the GPG key' do + gpg_key = create(:gpg_key) + + expect { subject.execute(gpg_key) }.to change(GpgKey, :count).by(-1) + end +end diff --git a/spec/services/grafana/proxy_service_spec.rb b/spec/services/grafana/proxy_service_spec.rb index 8cb7210524a..7ddc31d45d9 100644 --- a/spec/services/grafana/proxy_service_spec.rb +++ b/spec/services/grafana/proxy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Grafana::ProxyService do +RSpec.describe Grafana::ProxyService do include ReactiveCachingHelpers let_it_be(:project) { create(:project) } diff --git a/spec/services/gravatar_service_spec.rb b/spec/services/gravatar_service_spec.rb index 9ce1df0f76f..a6418b02f78 100644 --- a/spec/services/gravatar_service_spec.rb +++ b/spec/services/gravatar_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe GravatarService do +RSpec.describe GravatarService do describe '#execute' do let(:url) { 'http://example.com/avatar?hash=%{hash}&size=%{size}&email=%{email}&username=%{username}' } diff --git a/spec/services/groups/auto_devops_service_spec.rb b/spec/services/groups/auto_devops_service_spec.rb index 63fbdc70c1b..3d89ee96823 100644 --- a/spec/services/groups/auto_devops_service_spec.rb +++ b/spec/services/groups/auto_devops_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Groups::AutoDevopsService, '#execute' do +RSpec.describe Groups::AutoDevopsService, '#execute' do let_it_be(:group) { create(:group) } let_it_be(:user) { create(:user) } let(:group_params) { { auto_devops_enabled: '0' } } diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb index c0e876cce33..fc877f45a39 100644 --- a/spec/services/groups/create_service_spec.rb +++ b/spec/services/groups/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Groups::CreateService, '#execute' do +RSpec.describe Groups::CreateService, '#execute' do let!(:user) { create(:user) } let!(:group_params) { { path: "group_path", visibility_level: Gitlab::VisibilityLevel::PUBLIC } } @@ -129,4 +129,13 @@ describe Groups::CreateService, '#execute' do expect { subject }.to change { ChatTeam.count }.from(0).to(1) end end + + describe 'creating a setting record' do + let(:service) { described_class.new(user, group_params) } + + it 'create the settings record connected to the group' do + group = subject + expect(group.namespace_settings).to be_persisted + end + end end diff --git a/spec/services/groups/deploy_tokens/create_service_spec.rb b/spec/services/groups/deploy_tokens/create_service_spec.rb index 20c609bc828..0c28075f998 100644 --- a/spec/services/groups/deploy_tokens/create_service_spec.rb +++ b/spec/services/groups/deploy_tokens/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Groups::DeployTokens::CreateService do +RSpec.describe Groups::DeployTokens::CreateService do it_behaves_like 'a deploy token creation service' do let(:entity) { create(:group) } let(:deploy_token_class) { GroupDeployToken } diff --git a/spec/services/groups/deploy_tokens/destroy_service_spec.rb b/spec/services/groups/deploy_tokens/destroy_service_spec.rb index d4ef5963558..28e60b12993 100644 --- a/spec/services/groups/deploy_tokens/destroy_service_spec.rb +++ b/spec/services/groups/deploy_tokens/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Groups::DeployTokens::DestroyService do +RSpec.describe Groups::DeployTokens::DestroyService do it_behaves_like 'a deploy token deletion service' do let_it_be(:entity) { create(:group) } let_it_be(:deploy_token_class) { GroupDeployToken } diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb index bf639153b99..31afdba8192 100644 --- a/spec/services/groups/destroy_service_spec.rb +++ b/spec/services/groups/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Groups::DestroyService do +RSpec.describe Groups::DestroyService do include DatabaseConnectionHelpers let!(:user) { create(:user) } diff --git a/spec/services/groups/group_links/create_service_spec.rb b/spec/services/groups/group_links/create_service_spec.rb index 36faa69577e..bca03863d1e 100644 --- a/spec/services/groups/group_links/create_service_spec.rb +++ b/spec/services/groups/group_links/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Groups::GroupLinks::CreateService, '#execute' do +RSpec.describe Groups::GroupLinks::CreateService, '#execute' do let(:parent_group_user) { create(:user) } let(:group_user) { create(:user) } let(:child_group_user) { create(:user) } diff --git a/spec/services/groups/group_links/destroy_service_spec.rb b/spec/services/groups/group_links/destroy_service_spec.rb index 8989f024262..22fe8a1d58b 100644 --- a/spec/services/groups/group_links/destroy_service_spec.rb +++ b/spec/services/groups/group_links/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Groups::GroupLinks::DestroyService, '#execute' do +RSpec.describe Groups::GroupLinks::DestroyService, '#execute' do let(:user) { create(:user) } let_it_be(:group) { create(:group, :private) } diff --git a/spec/services/groups/group_links/update_service_spec.rb b/spec/services/groups/group_links/update_service_spec.rb index 446364c9799..e4ff83d7926 100644 --- a/spec/services/groups/group_links/update_service_spec.rb +++ b/spec/services/groups/group_links/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Groups::GroupLinks::UpdateService, '#execute' do +RSpec.describe Groups::GroupLinks::UpdateService, '#execute' do let(:user) { create(:user) } let_it_be(:group) { create(:group, :private) } diff --git a/spec/services/groups/import_export/export_service_spec.rb b/spec/services/groups/import_export/export_service_spec.rb index ea49b26cc7c..690bcb94556 100644 --- a/spec/services/groups/import_export/export_service_spec.rb +++ b/spec/services/groups/import_export/export_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Groups::ImportExport::ExportService do +RSpec.describe Groups::ImportExport::ExportService do describe '#async_execute' do let(:user) { create(:user) } let(:group) { create(:group) } diff --git a/spec/services/groups/import_export/import_service_spec.rb b/spec/services/groups/import_export/import_service_spec.rb index 1f7eaccbdbd..4aac602a6da 100644 --- a/spec/services/groups/import_export/import_service_spec.rb +++ b/spec/services/groups/import_export/import_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Groups::ImportExport::ImportService do +RSpec.describe Groups::ImportExport::ImportService do describe '#async_execute' do let_it_be(:user) { create(:user) } let_it_be(:group) { create(:group) } diff --git a/spec/services/groups/nested_create_service_spec.rb b/spec/services/groups/nested_create_service_spec.rb index b30392c1b12..a43c1d8d9c3 100644 --- a/spec/services/groups/nested_create_service_spec.rb +++ b/spec/services/groups/nested_create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Groups::NestedCreateService do +RSpec.describe Groups::NestedCreateService do let(:user) { create(:user) } subject(:service) { described_class.new(user, params) } diff --git a/spec/services/groups/transfer_service_spec.rb b/spec/services/groups/transfer_service_spec.rb index d7f6bececfe..fa254bba6a9 100644 --- a/spec/services/groups/transfer_service_spec.rb +++ b/spec/services/groups/transfer_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Groups::TransferService do +RSpec.describe Groups::TransferService do let(:user) { create(:user) } let(:new_parent_group) { create(:group, :public) } let!(:group_member) { create(:group_member, :owner, group: group, user: user) } diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb index b17d78505d1..25c79d9e600 100644 --- a/spec/services/groups/update_service_spec.rb +++ b/spec/services/groups/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Groups::UpdateService do +RSpec.describe Groups::UpdateService do let!(:user) { create(:user) } let!(:private_group) { create(:group, :private) } let!(:internal_group) { create(:group, :internal) } diff --git a/spec/services/groups/update_shared_runners_service_spec.rb b/spec/services/groups/update_shared_runners_service_spec.rb new file mode 100644 index 00000000000..9fd8477a455 --- /dev/null +++ b/spec/services/groups/update_shared_runners_service_spec.rb @@ -0,0 +1,230 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Groups::UpdateSharedRunnersService do + let(:user) { create(:user) } + let(:group) { create(:group) } + let(:params) { {} } + + describe '#execute' do + subject { described_class.new(group, user, params).execute } + + context 'when current_user is not the group owner' do + let_it_be(:group) { create(:group) } + + let(:params) { { shared_runners_enabled: '0' } } + + before do + group.add_maintainer(user) + end + + it 'results error and does not call any method' do + expect(group).not_to receive(:enable_shared_runners!) + expect(group).not_to receive(:disable_shared_runners!) + expect(group).not_to receive(:allow_descendants_override_disabled_shared_runners!) + expect(group).not_to receive(:disallow_descendants_override_disabled_shared_runners!) + + expect(subject[:status]).to eq(:error) + expect(subject[:message]).to eq('Operation not allowed') + expect(subject[:http_status]).to eq(403) + end + end + + context 'when current_user is the group owner' do + before do + group.add_owner(user) + end + + context 'enable shared Runners' do + where(:desired_params) do + ['1', true] + end + + with_them do + let(:params) { { shared_runners_enabled: desired_params } } + + context 'group that its ancestors have shared runners disabled' do + let_it_be(:parent) { create(:group, :shared_runners_disabled) } + let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) } + + it 'results error' do + expect(subject[:status]).to eq(:error) + expect(subject[:message]).to eq('Shared Runners disabled for the parent group') + end + end + + context 'root group with shared runners disabled' do + let_it_be(:group) { create(:group, :shared_runners_disabled) } + + it 'receives correct method and succeeds' do + expect(group).to receive(:enable_shared_runners!) + expect(group).not_to receive(:disable_shared_runners!) + expect(group).not_to receive(:allow_descendants_override_disabled_shared_runners!) + expect(group).not_to receive(:disallow_descendants_override_disabled_shared_runners!) + + expect(subject[:status]).to eq(:success) + end + end + end + end + + context 'disable shared Runners' do + let_it_be(:group) { create(:group) } + + where(:desired_params) do + ['0', false] + end + + with_them do + let(:params) { { shared_runners_enabled: desired_params } } + + it 'receives correct method and succeeds' do + expect(group).to receive(:disable_shared_runners!) + expect(group).not_to receive(:enable_shared_runners!) + expect(group).not_to receive(:allow_descendants_override_disabled_shared_runners!) + expect(group).not_to receive(:disallow_descendants_override_disabled_shared_runners!) + + expect(subject[:status]).to eq(:success) + end + end + end + + context 'allow descendants to override' do + where(:desired_params) do + ['1', true] + end + + with_them do + let(:params) { { allow_descendants_override_disabled_shared_runners: desired_params } } + + context 'top level group' do + let_it_be(:group) { create(:group, :shared_runners_disabled) } + + it 'receives correct method and succeeds' do + expect(group).to receive(:allow_descendants_override_disabled_shared_runners!) + expect(group).not_to receive(:disallow_descendants_override_disabled_shared_runners!) + expect(group).not_to receive(:enable_shared_runners!) + expect(group).not_to receive(:disable_shared_runners!) + + expect(subject[:status]).to eq(:success) + end + end + + context 'when parent does not allow' do + let_it_be(:parent) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false ) } + let_it_be(:group) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent: parent) } + + it 'results error' do + expect(subject[:status]).to eq(:error) + expect(subject[:message]).to eq('Group level shared Runners not allowed') + end + end + end + end + + context 'disallow descendants to override' do + where(:desired_params) do + ['0', false] + end + + with_them do + let(:params) { { allow_descendants_override_disabled_shared_runners: desired_params } } + + context 'top level group' do + let_it_be(:group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners ) } + + it 'receives correct method and succeeds' do + expect(group).to receive(:disallow_descendants_override_disabled_shared_runners!) + expect(group).not_to receive(:allow_descendants_override_disabled_shared_runners!) + expect(group).not_to receive(:enable_shared_runners!) + expect(group).not_to receive(:disable_shared_runners!) + + expect(subject[:status]).to eq(:success) + end + end + + context 'top level group that has shared Runners enabled' do + let_it_be(:group) { create(:group, shared_runners_enabled: true) } + + it 'results error' do + expect(subject[:status]).to eq(:error) + expect(subject[:message]).to eq('Shared Runners enabled') + end + end + end + end + + context 'both params are present' do + context 'shared_runners_enabled: 1 and allow_descendants_override_disabled_shared_runners' do + let_it_be(:group) { create(:group, :shared_runners_disabled) } + let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) } + let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) } + + where(:allow_descendants_override) do + ['1', true, '0', false] + end + + with_them do + let(:params) { { shared_runners_enabled: '1', allow_descendants_override_disabled_shared_runners: allow_descendants_override } } + + it 'results in an error because shared Runners are enabled' do + expect { subject } + .to not_change { group.reload.shared_runners_enabled } + .and not_change { sub_group.reload.shared_runners_enabled } + .and not_change { project.reload.shared_runners_enabled } + .and not_change { group.reload.allow_descendants_override_disabled_shared_runners } + .and not_change { sub_group.reload.allow_descendants_override_disabled_shared_runners } + expect(subject[:status]).to eq(:error) + expect(subject[:message]).to eq('Cannot set shared_runners_enabled to true and allow_descendants_override_disabled_shared_runners') + end + end + end + + context 'shared_runners_enabled: 0 and allow_descendants_override_disabled_shared_runners: 0' do + let_it_be(:group) { create(:group, :allow_descendants_override_disabled_shared_runners) } + let_it_be(:sub_group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent: group) } + let_it_be(:sub_group_2) { create(:group, parent: group) } + let_it_be(:project) { create(:project, group: group, shared_runners_enabled: true) } + let_it_be(:project_2) { create(:project, group: sub_group_2, shared_runners_enabled: true) } + + let(:params) { { shared_runners_enabled: '0', allow_descendants_override_disabled_shared_runners: '0' } } + + it 'disables shared Runners and disable allow_descendants_override_disabled_shared_runners' do + expect { subject } + .to change { group.reload.shared_runners_enabled }.from(true).to(false) + .and change { group.reload.allow_descendants_override_disabled_shared_runners }.from(true).to(false) + .and not_change { sub_group.reload.shared_runners_enabled } + .and change { sub_group.reload.allow_descendants_override_disabled_shared_runners }.from(true).to(false) + .and change { sub_group_2.reload.shared_runners_enabled }.from(true).to(false) + .and not_change { sub_group_2.reload.allow_descendants_override_disabled_shared_runners } + .and change { project.reload.shared_runners_enabled }.from(true).to(false) + .and change { project_2.reload.shared_runners_enabled }.from(true).to(false) + end + end + + context 'shared_runners_enabled: 0 and allow_descendants_override_disabled_shared_runners: 1' do + let_it_be(:group) { create(:group) } + let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) } + let_it_be(:sub_group_2) { create(:group, parent: group) } + let_it_be(:project) { create(:project, group: group, shared_runners_enabled: true) } + let_it_be(:project_2) { create(:project, group: sub_group_2, shared_runners_enabled: true) } + + let(:params) { { shared_runners_enabled: '0', allow_descendants_override_disabled_shared_runners: '1' } } + + it 'disables shared Runners and enable allow_descendants_override_disabled_shared_runners only for itself' do + expect { subject } + .to change { group.reload.shared_runners_enabled }.from(true).to(false) + .and change { group.reload.allow_descendants_override_disabled_shared_runners }.from(false).to(true) + .and not_change { sub_group.reload.shared_runners_enabled } + .and not_change { sub_group.reload.allow_descendants_override_disabled_shared_runners } + .and change { sub_group_2.reload.shared_runners_enabled }.from(true).to(false) + .and not_change { sub_group_2.reload.allow_descendants_override_disabled_shared_runners } + .and change { project.reload.shared_runners_enabled }.from(true).to(false) + .and change { project_2.reload.shared_runners_enabled }.from(true).to(false) + end + end + end + end + end +end diff --git a/spec/services/import/bitbucket_server_service_spec.rb b/spec/services/import/bitbucket_server_service_spec.rb new file mode 100644 index 00000000000..c548e87b040 --- /dev/null +++ b/spec/services/import/bitbucket_server_service_spec.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Import::BitbucketServerService do + let_it_be(:user) { create(:user) } + let(:base_uri) { "https://test:7990" } + let(:token) { "asdasd12345" } + let(:secret) { "sekrettt" } + let(:project_key) { 'TES' } + let(:repo_slug) { 'vim' } + let(:repo) do + { + name: 'vim', + description: 'test', + visibility_level: Gitlab::VisibilityLevel::PUBLIC, + browse_url: 'http://repo.com/repo/repo', + clone_url: 'http://repo.com/repo/repo.git' + } + end + + let(:client) { double(BitbucketServer::Client) } + + let(:credentials) { { base_uri: base_uri, user: user, password: token } } + let(:params) { { bitbucket_server_url: base_uri, bitbucket_server_username: user, personal_access_token: token, bitbucket_server_project: project_key, bitbucket_server_repo: repo_slug } } + + subject { described_class.new(client, user, params) } + + before do + allow(subject).to receive(:authorized?).and_return(true) + end + + context 'when no repo is found' do + before do + allow(subject).to receive(:authorized?).and_return(true) + allow(client).to receive(:repo).and_return(nil) + end + + it 'returns an error' do + result = subject.execute(credentials) + + expect(result).to include( + message: "Project #{project_key}/#{repo_slug} could not be found", + status: :error, + http_status: :unprocessable_entity + ) + end + end + + context 'when user is unauthorized' do + before do + allow(subject).to receive(:authorized?).and_return(false) + end + + it 'returns an error' do + result = subject.execute(credentials) + + expect(result).to include( + message: "You don't have permissions to create this project", + status: :error, + http_status: :unauthorized + ) + end + end + + context 'verify url' do + shared_examples 'denies local request' do + before do + allow(client).to receive(:repo).with(project_key, repo_slug).and_return(double(repo)) + end + + it 'does not allow requests' do + result = subject.execute(credentials) + expect(result[:status]).to eq(:error) + expect(result[:message]).to include("Invalid URL:") + end + end + + context 'when host is localhost' do + before do + allow(subject).to receive(:url).and_return('https://localhost:3000') + end + + include_examples 'denies local request' + end + + context 'when host is on local network' do + before do + allow(subject).to receive(:url).and_return('https://192.168.0.191') + end + + include_examples 'denies local request' + end + + context 'when host is ftp protocol' do + before do + allow(subject).to receive(:url).and_return('ftp://testing') + end + + include_examples 'denies local request' + end + end + + it 'raises an exception for unknown error causes' do + exception = StandardError.new('Not Implemented') + + allow(client).to receive(:repo).and_raise(exception) + + expect(Gitlab::Import::Logger).not_to receive(:error) + + expect { subject.execute(credentials) }.to raise_error(exception) + end +end diff --git a/spec/services/import/github_service_spec.rb b/spec/services/import/github_service_spec.rb index 461b17e0e33..266ff309662 100644 --- a/spec/services/import/github_service_spec.rb +++ b/spec/services/import/github_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Import::GithubService do +RSpec.describe Import::GithubService do let_it_be(:user) { create(:user) } let_it_be(:token) { 'complex-token' } let_it_be(:access_params) { { github_access_token: 'github-complex-token' } } diff --git a/spec/services/import_export_clean_up_service_spec.rb b/spec/services/import_export_clean_up_service_spec.rb index 9f811f56f50..4101b13adf9 100644 --- a/spec/services/import_export_clean_up_service_spec.rb +++ b/spec/services/import_export_clean_up_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ImportExportCleanUpService do +RSpec.describe ImportExportCleanUpService do describe '#execute' do let(:service) { described_class.new } diff --git a/spec/services/incident_management/create_incident_label_service_spec.rb b/spec/services/incident_management/create_incident_label_service_spec.rb new file mode 100644 index 00000000000..2f11bcf397e --- /dev/null +++ b/spec/services/incident_management/create_incident_label_service_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe IncidentManagement::CreateIncidentLabelService do + let_it_be(:project) { create(:project, :private) } + let_it_be(:user) { User.alert_bot } + let(:service) { described_class.new(project, user) } + + subject(:execute) { service.execute } + + describe 'execute' do + let(:title) { described_class::LABEL_PROPERTIES[:title] } + let(:color) { described_class::LABEL_PROPERTIES[:color] } + let(:description) { described_class::LABEL_PROPERTIES[:description] } + + shared_examples 'existing label' do + it 'returns the existing label' do + expect { execute }.not_to change(Label, :count) + + expect(execute).to be_success + expect(execute.payload).to eq(label: label) + end + end + + shared_examples 'new label' do + it 'creates a new label' do + expect { execute }.to change(Label, :count).by(1) + + label = project.reload.labels.last + expect(execute).to be_success + expect(execute.payload).to eq(label: label) + expect(label.title).to eq(title) + expect(label.color).to eq(color) + expect(label.description).to eq(description) + end + end + + context 'with predefined project label' do + it_behaves_like 'existing label' do + let!(:label) { create(:label, project: project, title: title) } + end + end + + context 'with predefined group label' do + let(:project) { create(:project, group: group) } + let(:group) { create(:group) } + + it_behaves_like 'existing label' do + let!(:label) { create(:group_label, group: group, title: title) } + end + end + + context 'without label' do + it_behaves_like 'new label' + end + end +end diff --git a/spec/services/incident_management/create_issue_service_spec.rb b/spec/services/incident_management/create_issue_service_spec.rb index 5a3721f00b8..dab9a149458 100644 --- a/spec/services/incident_management/create_issue_service_spec.rb +++ b/spec/services/incident_management/create_issue_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe IncidentManagement::CreateIssueService do +RSpec.describe IncidentManagement::CreateIssueService do let(:project) { create(:project, :repository, :private) } let_it_be(:user) { User.alert_bot } let(:service) { described_class.new(project, alert_payload) } @@ -199,80 +199,7 @@ describe IncidentManagement::CreateIssueService do end describe "label `incident`" do - let(:title) { 'incident' } - let(:color) { '#CC0033' } - let(:description) do - <<~DESCRIPTION.chomp - Denotes a disruption to IT services and \ - the associated issues require immediate attention - DESCRIPTION - end - - shared_examples 'existing label' do - it 'adds the existing label' do - expect { subject }.not_to change(Label, :count) - - expect(issue.labels).to eq([label]) - end - end - - shared_examples 'new label' do - it 'adds newly created label' do - expect { subject }.to change(Label, :count).by(1) - - label = project.reload.labels.last - expect(issue.labels).to eq([label]) - expect(label.title).to eq(title) - expect(label.color).to eq(color) - expect(label.description).to eq(description) - end - end - - context 'with predefined project label' do - it_behaves_like 'existing label' do - let!(:label) { create(:label, project: project, title: title) } - end - end - - context 'with predefined group label' do - let(:project) { create(:project, group: group) } - let(:group) { create(:group) } - - it_behaves_like 'existing label' do - let!(:label) { create(:group_label, group: group, title: title) } - end - end - - context 'without label' do - it_behaves_like 'new label' - end - - context 'with duplicate labels', issue: 'https://gitlab.com/gitlab-org/gitlab-foss/issues/65042' do - before do - # Replicate race condition to create duplicates - build(:label, project: project, title: title).save!(validate: false) - build(:label, project: project, title: title).save!(validate: false) - end - - it 'create an issue without labels' do - # Verify we have duplicates - expect(project.labels.size).to eq(2) - expect(project.labels.map(&:title)).to all(eq(title)) - - message = <<~MESSAGE.chomp - Cannot create incident issue with labels ["#{title}"] for \ - "#{project.full_name}": Labels is invalid. - Retrying without labels. - MESSAGE - - expect(service) - .to receive(:log_info) - .with(message) - - expect(subject).to include(status: :success) - expect(issue.labels).to be_empty - end - end + it_behaves_like 'create alert issue sets issue labels' end end @@ -281,22 +208,12 @@ describe IncidentManagement::CreateIssueService do setting.update!(create_issue: false) end - context 'when skip_settings_check is false (default)' do - it 'returns an error' do - expect(service) - .to receive(:log_error) - .with(error_message('setting disabled')) + it 'returns an error' do + expect(service) + .to receive(:log_error) + .with(error_message('setting disabled')) - expect(subject).to eq(status: :error, message: 'setting disabled') - end - end - - context 'when skip_settings_check is true' do - subject { service.execute(skip_settings_check: true) } - - it 'creates an issue' do - expect { subject }.to change(Issue, :count).by(1) - end + expect(subject).to eq(status: :error, message: 'setting disabled') end end diff --git a/spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb b/spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb new file mode 100644 index 00000000000..cf43ed2411d --- /dev/null +++ b/spec/services/incident_management/pager_duty/create_incident_issue_service_spec.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe IncidentManagement::PagerDuty::CreateIncidentIssueService do + let_it_be(:project, reload: true) { create(:project) } + let_it_be(:user) { User.alert_bot } + let(:webhook_payload) { Gitlab::Json.parse(fixture_file('pager_duty/webhook_incident_trigger.json')) } + let(:parsed_payload) { ::PagerDuty::WebhookPayloadParser.call(webhook_payload) } + let(:incident_payload) { parsed_payload.first['incident'] } + + subject(:execute) { described_class.new(project, incident_payload).execute } + + describe '#execute' do + context 'when pagerduty_webhook feature enabled' do + before do + stub_feature_flags(pagerduty_webhook: project) + end + + context 'when PagerDuty webhook setting is active' do + let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: true) } + + context 'when issue can be created' do + it 'creates a new issue' do + expect { execute }.to change(Issue, :count).by(1) + end + + it 'responds with success' do + response = execute + + expect(response).to be_success + expect(response.payload[:issue]).to be_kind_of(Issue) + end + + it 'the issue author is Alert bot' do + expect(execute.payload[:issue].author).to eq(User.alert_bot) + end + + it 'issue has a correct title' do + expect(execute.payload[:issue].title).to eq(incident_payload['title']) + end + + it 'issue has a correct description' do + markdown_line_break = ' ' + + expect(execute.payload[:issue].description).to eq( + <<~MARKDOWN.chomp + **Incident:** [My new incident](https://webdemo.pagerduty.com/incidents/PRORDTY)#{markdown_line_break} + **Incident number:** 33#{markdown_line_break} + **Urgency:** high#{markdown_line_break} + **Status:** triggered#{markdown_line_break} + **Incident key:** #{markdown_line_break} + **Created at:** 26 September 2017, 3:14PM (UTC)#{markdown_line_break} + **Assignees:** [Laura Haley](https://webdemo.pagerduty.com/users/P553OPV)#{markdown_line_break} + **Impacted services:** [Production XDB Cluster](https://webdemo.pagerduty.com/services/PN49J75) + MARKDOWN + ) + end + end + + context 'when the payload does not contain a title' do + let(:incident_payload) { {} } + + it 'does not create a GitLab issue' do + expect { execute }.not_to change(Issue, :count) + end + + it 'responds with error' do + expect(execute).to be_error + expect(execute.message).to eq("Title can't be blank") + end + end + end + + context 'when PagerDuty webhook setting is not active' do + let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: false) } + + it 'does not create a GitLab issue' do + expect { execute }.not_to change(Issue, :count) + end + + it 'responds with forbidden' do + expect(execute).to be_error + expect(execute.http_status).to eq(:forbidden) + end + end + end + + context 'when pagerduty_webhook feature disabled' do + before do + stub_feature_flags(pagerduty_webhook: false) + end + + it 'does not create a GitLab issue' do + expect { execute }.not_to change(Issue, :count) + end + + it 'responds with forbidden' do + expect(execute).to be_error + expect(execute.http_status).to eq(:forbidden) + end + end + end +end diff --git a/spec/services/incident_management/pager_duty/process_webhook_service_spec.rb b/spec/services/incident_management/pager_duty/process_webhook_service_spec.rb new file mode 100644 index 00000000000..11ce8388427 --- /dev/null +++ b/spec/services/incident_management/pager_duty/process_webhook_service_spec.rb @@ -0,0 +1,148 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe IncidentManagement::PagerDuty::ProcessWebhookService do + let_it_be(:project, reload: true) { create(:project) } + + describe '#execute' do + shared_examples 'does not process incidents' do + it 'does not process incidents' do + expect(::IncidentManagement::PagerDuty::ProcessIncidentWorker).not_to receive(:perform_async) + + execute + end + end + + let(:webhook_payload) { Gitlab::Json.parse(fixture_file('pager_duty/webhook_incident_trigger.json')) } + let(:token) { nil } + + subject(:execute) { described_class.new(project, nil, webhook_payload).execute(token) } + + context 'when pagerduty_webhook feature is enabled' do + before do + stub_feature_flags(pagerduty_webhook: project) + end + + context 'when PagerDuty webhook setting is active' do + let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: true) } + + context 'when token is valid' do + let(:token) { incident_management_setting.pagerduty_token } + + context 'when webhook payload has acceptable size' do + it 'responds with Accepted' do + result = execute + + expect(result).to be_success + expect(result.http_status).to eq(:accepted) + end + + it 'processes issues' do + incident_payload = ::PagerDuty::WebhookPayloadParser.call(webhook_payload).first['incident'] + + expect(::IncidentManagement::PagerDuty::ProcessIncidentWorker) + .to receive(:perform_async) + .with(project.id, incident_payload) + .once + + execute + end + end + + context 'when webhook payload is too big' do + let(:deep_size) { instance_double(Gitlab::Utils::DeepSize, valid?: false) } + + before do + allow(Gitlab::Utils::DeepSize) + .to receive(:new) + .with(webhook_payload, max_size: described_class::PAGER_DUTY_PAYLOAD_SIZE_LIMIT) + .and_return(deep_size) + end + + it 'responds with Bad Request' do + result = execute + + expect(result).to be_error + expect(result.http_status).to eq(:bad_request) + end + + it_behaves_like 'does not process incidents' + end + + context 'when webhook payload is blank' do + let(:webhook_payload) { nil } + + it 'responds with Accepted' do + result = execute + + expect(result).to be_success + expect(result.http_status).to eq(:accepted) + end + + it_behaves_like 'does not process incidents' + end + end + + context 'when token is invalid' do + let(:token) { 'invalid-token' } + + it 'responds with Unauthorized' do + result = execute + + expect(result).to be_error + expect(result.http_status).to eq(:unauthorized) + end + + it_behaves_like 'does not process incidents' + end + end + + context 'when both tokens are nil' do + let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: false) } + let(:token) { nil } + + before do + incident_management_setting.update_column(:pagerduty_active, true) + end + + it 'responds with Unauthorized' do + result = execute + + expect(result).to be_error + expect(result.http_status).to eq(:unauthorized) + end + + it_behaves_like 'does not process incidents' + end + + context 'when PagerDuty webhook setting is not active' do + let_it_be(:incident_management_setting) { create(:project_incident_management_setting, project: project, pagerduty_active: false) } + + it 'responds with Forbidden' do + result = execute + + expect(result).to be_error + expect(result.http_status).to eq(:forbidden) + end + + it_behaves_like 'does not process incidents' + end + end + + context 'when pagerduty_webhook feature is disabled' do + before do + stub_feature_flags(pagerduty_webhook: false) + end + + it 'responds with Forbidden' do + result = execute + + expect(result).to be_error + expect(result.http_status).to eq(:forbidden) + end + + it_behaves_like 'does not process incidents' + end + end +end diff --git a/spec/services/integrations/test/project_service_spec.rb b/spec/services/integrations/test/project_service_spec.rb index fdb43ca345a..dd603765d59 100644 --- a/spec/services/integrations/test/project_service_spec.rb +++ b/spec/services/integrations/test/project_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Integrations::Test::ProjectService do +RSpec.describe Integrations::Test::ProjectService do let(:user) { double('user') } describe '#execute' do diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb index c791c454d70..168a80a97c0 100644 --- a/spec/services/issuable/bulk_update_service_spec.rb +++ b/spec/services/issuable/bulk_update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issuable::BulkUpdateService do +RSpec.describe Issuable::BulkUpdateService do let(:user) { create(:user) } let(:project) { create(:project, :repository, namespace: user.namespace) } @@ -18,8 +18,8 @@ describe Issuable::BulkUpdateService do it 'succeeds' do result = bulk_update(issuables, milestone_id: milestone.id) - expect(result[:success]).to be_truthy - expect(result[:count]).to eq(issuables.count) + expect(result.success?).to be_truthy + expect(result.payload[:count]).to eq(issuables.count) end it 'updates the issuables milestone' do @@ -121,8 +121,8 @@ describe Issuable::BulkUpdateService do it 'succeeds and returns the correct number of issues updated' do result = bulk_update(issues, state_event: 'close') - expect(result[:success]).to be_truthy - expect(result[:count]).to eq(issues.count) + expect(result.success?).to be_truthy + expect(result.payload[:count]).to eq(issues.count) end it 'closes all the issues passed' do @@ -139,8 +139,8 @@ describe Issuable::BulkUpdateService do it 'succeeds and returns the correct number of issues updated' do result = bulk_update(issues, state_event: 'reopen') - expect(result[:success]).to be_truthy - expect(result[:count]).to eq(issues.count) + expect(result.success?).to be_truthy + expect(result.payload[:count]).to eq(issues.count) end it 'reopens all the issues passed' do @@ -161,8 +161,8 @@ describe Issuable::BulkUpdateService do result = bulk_update(merge_request, assignee_ids: [user.id, new_assignee.id]) - expect(result[:success]).to be_truthy - expect(result[:count]).to eq(1) + expect(result.success?).to be_truthy + expect(result.payload[:count]).to eq(1) end it 'updates the assignee to the user ID passed' do @@ -199,8 +199,8 @@ describe Issuable::BulkUpdateService do result = bulk_update(issue, assignee_ids: [new_assignee.id]) - expect(result[:success]).to be_truthy - expect(result[:count]).to eq(1) + expect(result.success?).to be_truthy + expect(result.payload[:count]).to eq(1) end it 'updates the assignee to the user ID passed' do @@ -273,8 +273,8 @@ describe Issuable::BulkUpdateService do issue2 = create(:issue, project: create(:project)) result = bulk_update([issue1, issue2], assignee_ids: [user.id]) - expect(result[:success]).to be_truthy - expect(result[:count]).to eq(1) + expect(result.success?).to be_truthy + expect(result.payload[:count]).to eq(1) expect(issue1.reload.assignees).to eq([user]) expect(issue2.reload.assignees).to be_empty @@ -332,8 +332,8 @@ describe Issuable::BulkUpdateService do milestone = create(:milestone, group: group) result = bulk_update([issue1, issue2, issue3], milestone_id: milestone.id) - expect(result[:success]).to be_truthy - expect(result[:count]).to eq(2) + expect(result.success?).to be_truthy + expect(result.payload[:count]).to eq(2) expect(issue1.reload.milestone).to eq(milestone) expect(issue2.reload.milestone).to be_nil diff --git a/spec/services/issuable/clone/attributes_rewriter_spec.rb b/spec/services/issuable/clone/attributes_rewriter_spec.rb index fb520f828fa..372e6d480e3 100644 --- a/spec/services/issuable/clone/attributes_rewriter_spec.rb +++ b/spec/services/issuable/clone/attributes_rewriter_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issuable::Clone::AttributesRewriter do +RSpec.describe Issuable::Clone::AttributesRewriter do let(:user) { create(:user) } let(:group) { create(:group) } let(:project1) { create(:project, :public, group: group) } diff --git a/spec/services/issuable/clone/content_rewriter_spec.rb b/spec/services/issuable/clone/content_rewriter_spec.rb index 3479c20862a..f39439b7c2f 100644 --- a/spec/services/issuable/clone/content_rewriter_spec.rb +++ b/spec/services/issuable/clone/content_rewriter_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issuable::Clone::ContentRewriter do +RSpec.describe Issuable::Clone::ContentRewriter do let(:user) { create(:user) } let(:group) { create(:group) } let(:project1) { create(:project, :public, group: group) } diff --git a/spec/services/issuable/common_system_notes_service_spec.rb b/spec/services/issuable/common_system_notes_service_spec.rb index 771e7ca42c9..daf4f68208e 100644 --- a/spec/services/issuable/common_system_notes_service_spec.rb +++ b/spec/services/issuable/common_system_notes_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issuable::CommonSystemNotesService do +RSpec.describe Issuable::CommonSystemNotesService do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } @@ -43,23 +43,23 @@ describe Issuable::CommonSystemNotesService do it_behaves_like 'system note creation', {}, 'changed milestone' end - context 'with merge requests WIP note' do - context 'adding WIP note' do + context 'with merge requests Draft note' do + context 'adding Draft note' do let(:issuable) { create(:merge_request, title: "merge request") } - it_behaves_like 'system note creation', { title: "WIP merge request" }, 'marked as a **Work In Progress**' + it_behaves_like 'system note creation', { title: "Draft: merge request" }, 'marked as a **Work In Progress**' context 'and changing title' do before do - issuable.update_attribute(:title, "WIP changed title") + issuable.update_attribute(:title, "Draft: changed title") end - it_behaves_like 'WIP notes creation', 'marked' + it_behaves_like 'draft notes creation', 'marked' end end - context 'removing WIP note' do - let(:issuable) { create(:merge_request, title: "WIP merge request") } + context 'removing Draft note' do + let(:issuable) { create(:merge_request, title: "Draft: merge request") } it_behaves_like 'system note creation', { title: "merge request" }, 'unmarked as a **Work In Progress**' @@ -68,7 +68,7 @@ describe Issuable::CommonSystemNotesService do issuable.update_attribute(:title, "changed title") end - it_behaves_like 'WIP notes creation', 'unmarked' + it_behaves_like 'draft notes creation', 'unmarked' end end end diff --git a/spec/services/issuable/destroy_service_spec.rb b/spec/services/issuable/destroy_service_spec.rb index dd6a966c145..8d62932f986 100644 --- a/spec/services/issuable/destroy_service_spec.rb +++ b/spec/services/issuable/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issuable::DestroyService do +RSpec.describe Issuable::DestroyService do let(:user) { create(:user) } let(:project) { create(:project, :public) } diff --git a/spec/services/issues/build_service_spec.rb b/spec/services/issues/build_service_spec.rb index 140b78f9b7a..68b226b02da 100644 --- a/spec/services/issues/build_service_spec.rb +++ b/spec/services/issues/build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper.rb' -describe Issues::BuildService do +RSpec.describe Issues::BuildService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb index 78eba565de4..6678d831775 100644 --- a/spec/services/issues/close_service_spec.rb +++ b/spec/services/issues/close_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issues::CloseService do +RSpec.describe Issues::CloseService do let(:project) { create(:project, :repository) } let(:user) { create(:user, email: "user@example.com") } let(:user2) { create(:user, email: "user2@example.com") } diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb index bb02941576a..fdf2326b75e 100644 --- a/spec/services/issues/create_service_spec.rb +++ b/spec/services/issues/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issues::CreateService do +RSpec.describe Issues::CreateService do let(:project) { create(:project) } let(:user) { create(:user) } @@ -284,7 +284,9 @@ describe Issues::CreateService do end end - it_behaves_like 'new issuable record that supports quick actions' + it_behaves_like 'issuable record that supports quick actions' do + let(:issuable) { described_class.new(project, user, params).execute } + end context 'Quick actions' do context 'with assignee and milestone in params and command' do diff --git a/spec/services/issues/duplicate_service_spec.rb b/spec/services/issues/duplicate_service_spec.rb index 41a151b0ca1..78e030e6ac7 100644 --- a/spec/services/issues/duplicate_service_spec.rb +++ b/spec/services/issues/duplicate_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issues::DuplicateService do +RSpec.describe Issues::DuplicateService do let(:user) { create(:user) } let(:canonical_project) { create(:project) } let(:duplicate_project) { create(:project) } diff --git a/spec/services/issues/export_csv_service_spec.rb b/spec/services/issues/export_csv_service_spec.rb index 419e29d92a8..76381fe525b 100644 --- a/spec/services/issues/export_csv_service_spec.rb +++ b/spec/services/issues/export_csv_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issues::ExportCsvService do +RSpec.describe Issues::ExportCsvService do let_it_be(:user) { create(:user) } let(:group) { create(:group) } let(:project) { create(:project, :public, group: group) } diff --git a/spec/services/issues/import_csv_service_spec.rb b/spec/services/issues/import_csv_service_spec.rb index 92b88489af9..cc3e1d23a74 100644 --- a/spec/services/issues/import_csv_service_spec.rb +++ b/spec/services/issues/import_csv_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issues::ImportCsvService do +RSpec.describe Issues::ImportCsvService do let(:project) { create(:project) } let(:user) { create(:user) } diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb index a449541f459..8929907a179 100644 --- a/spec/services/issues/move_service_spec.rb +++ b/spec/services/issues/move_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issues::MoveService do +RSpec.describe Issues::MoveService do let(:user) { create(:user) } let(:author) { create(:user) } let(:title) { 'Some issue' } @@ -210,4 +210,49 @@ describe Issues::MoveService do end end end + + context 'updating sent notifications' do + let!(:old_issue_notification_1) { create(:sent_notification, project: old_issue.project, noteable: old_issue) } + let!(:old_issue_notification_2) { create(:sent_notification, project: old_issue.project, noteable: old_issue) } + let!(:other_issue_notification) { create(:sent_notification, project: old_issue.project) } + + include_context 'user can move issue' + + context 'when issue is from service desk' do + before do + allow(old_issue).to receive(:from_service_desk?).and_return(true) + end + + it 'updates moved issue sent notifications' do + new_issue = move_service.execute(old_issue, new_project) + + old_issue_notification_1.reload + old_issue_notification_2.reload + expect(old_issue_notification_1.project_id).to eq(new_issue.project_id) + expect(old_issue_notification_1.noteable_id).to eq(new_issue.id) + expect(old_issue_notification_2.project_id).to eq(new_issue.project_id) + expect(old_issue_notification_2.noteable_id).to eq(new_issue.id) + end + + it 'does not update other issues sent notifications' do + expect do + move_service.execute(old_issue, new_project) + other_issue_notification.reload + end.not_to change { other_issue_notification.noteable_id } + end + end + + context 'when issue is not from service desk' do + it 'does not update sent notifications' do + move_service.execute(old_issue, new_project) + + old_issue_notification_1.reload + old_issue_notification_2.reload + expect(old_issue_notification_1.project_id).to eq(old_issue.project_id) + expect(old_issue_notification_1.noteable_id).to eq(old_issue.id) + expect(old_issue_notification_2.project_id).to eq(old_issue.project_id) + expect(old_issue_notification_2.noteable_id).to eq(old_issue.id) + end + end + end end diff --git a/spec/services/issues/referenced_merge_requests_service_spec.rb b/spec/services/issues/referenced_merge_requests_service_spec.rb index 2c5af11d2e6..bf7a4c97e48 100644 --- a/spec/services/issues/referenced_merge_requests_service_spec.rb +++ b/spec/services/issues/referenced_merge_requests_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper.rb' -describe Issues::ReferencedMergeRequestsService do +RSpec.describe Issues::ReferencedMergeRequestsService do def create_referencing_mr(attributes = {}) create(:merge_request, attributes).tap do |merge_request| create(:note, :system, project: project, noteable: issue, author: user, note: merge_request.to_reference(full: true)) diff --git a/spec/services/issues/related_branches_service_spec.rb b/spec/services/issues/related_branches_service_spec.rb index 9f72e499414..d79132d98db 100644 --- a/spec/services/issues/related_branches_service_spec.rb +++ b/spec/services/issues/related_branches_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issues::RelatedBranchesService do +RSpec.describe Issues::RelatedBranchesService do let_it_be(:developer) { create(:user) } let_it_be(:issue) { create(:issue) } let(:user) { developer } diff --git a/spec/services/issues/reopen_service_spec.rb b/spec/services/issues/reopen_service_spec.rb index ca878ee947a..f7416203259 100644 --- a/spec/services/issues/reopen_service_spec.rb +++ b/spec/services/issues/reopen_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issues::ReopenService do +RSpec.describe Issues::ReopenService do let(:project) { create(:project) } let(:issue) { create(:issue, :closed, project: project) } diff --git a/spec/services/issues/reorder_service_spec.rb b/spec/services/issues/reorder_service_spec.rb index 6d72d698b1d..b6ad488a48c 100644 --- a/spec/services/issues/reorder_service_spec.rb +++ b/spec/services/issues/reorder_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issues::ReorderService do +RSpec.describe Issues::ReorderService do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:group) { create(:group) } diff --git a/spec/services/issues/resolve_discussions_spec.rb b/spec/services/issues/resolve_discussions_spec.rb index ec6624db6fc..a541d92feb2 100644 --- a/spec/services/issues/resolve_discussions_spec.rb +++ b/spec/services/issues/resolve_discussions_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper.rb' -describe Issues::ResolveDiscussions do +RSpec.describe Issues::ResolveDiscussions do let(:project) { create(:project, :repository) } let(:user) { create(:user) } diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index 33ae2682d01..77bd540e22f 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issues::UpdateService, :mailer do +RSpec.describe Issues::UpdateService, :mailer do let_it_be(:user) { create(:user) } let_it_be(:user2) { create(:user) } let_it_be(:user3) { create(:user) } @@ -866,5 +866,10 @@ describe Issues::UpdateService, :mailer do end end end + + it_behaves_like 'issuable record that supports quick actions' do + let(:existing_issue) { create(:issue, project: project) } + let(:issuable) { described_class.new(project, user, params).execute(existing_issue) } + end end end diff --git a/spec/services/issues/zoom_link_service_spec.rb b/spec/services/issues/zoom_link_service_spec.rb index 3fb1eae361a..56aec4fe564 100644 --- a/spec/services/issues/zoom_link_service_spec.rb +++ b/spec/services/issues/zoom_link_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Issues::ZoomLinkService do +RSpec.describe Issues::ZoomLinkService do let_it_be(:user) { create(:user) } let_it_be(:issue) { create(:issue) } diff --git a/spec/services/jira/requests/projects_spec.rb b/spec/services/jira/requests/projects/list_service_spec.rb index f7b9aa7c00c..51e67dd821d 100644 --- a/spec/services/jira/requests/projects_spec.rb +++ b/spec/services/jira/requests/projects/list_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Jira::Requests::Projects do +RSpec.describe Jira::Requests::Projects::ListService do let(:jira_service) { create(:jira_service) } let(:params) { {} } @@ -32,14 +32,6 @@ describe Jira::Requests::Projects do end context 'with jira_service' do - context 'when limit is invalid' do - let(:params) { { limit: 0 } } - - it 'returns a paylod with no projects returned' do - expect(subject.payload[:projects]).to be_empty - end - end - context 'when validations and params are ok' do let(:client) { double(options: { site: 'https://jira.example.com' }) } @@ -60,7 +52,7 @@ describe Jira::Requests::Projects do context 'when the request does not return any values' do before do - expect(client).to receive(:get).and_return({ 'someKey' => 'value' }) + expect(client).to receive(:get).and_return([]) end it 'returns a paylod with no projects returned' do @@ -74,19 +66,15 @@ describe Jira::Requests::Projects do context 'when the request returns values' do before do - expect(client).to receive(:get).and_return( - { 'values' => %w(project1 project2), 'isLast' => false } - ) - expect(JIRA::Resource::Project).to receive(:build).with(client, 'project1').and_return('jira_project1') - expect(JIRA::Resource::Project).to receive(:build).with(client, 'project2').and_return('jira_project2') + expect(client).to receive(:get).and_return([{ "key" => 'project1' }, { "key" => 'project2' }]) end it 'returns a paylod with jira projets' do payload = subject.payload expect(subject.success?).to be_truthy - expect(payload[:projects]).to eq(%w(jira_project1 jira_project2)) - expect(payload[:is_last]).to be_falsey + expect(payload[:projects].map(&:key)).to eq(%w(project1 project2)) + expect(payload[:is_last]).to be_truthy end end end diff --git a/spec/services/jira_import/start_import_service_spec.rb b/spec/services/jira_import/start_import_service_spec.rb index 9dc8cdb1475..a10928355ef 100644 --- a/spec/services/jira_import/start_import_service_spec.rb +++ b/spec/services/jira_import/start_import_service_spec.rb @@ -2,14 +2,21 @@ require 'spec_helper' -describe JiraImport::StartImportService do +RSpec.describe JiraImport::StartImportService do include JiraServiceHelper let_it_be(:user) { create(:user) } let_it_be(:project, reload: true) { create(:project) } let(:key) { 'KEY' } + let(:mapping) do + [ + { jira_account_id: 'abc', gitlab_id: 12 }, + { jira_account_id: 'def', gitlab_id: nil }, + { jira_account_id: nil, gitlab_id: 1 } + ] + end - subject { described_class.new(user, project, key).execute } + subject { described_class.new(user, project, key, mapping).execute } context 'when an error is returned from the project validation' do before do @@ -37,7 +44,7 @@ describe JiraImport::StartImportService do context 'when correct data provided' do let(:fake_key) { 'some-key' } - subject { described_class.new(user, project, fake_key).execute } + subject { described_class.new(user, project, fake_key, mapping).execute } context 'when import is already running' do let_it_be(:jira_import_state) { create(:jira_import_state, :started, project: project) } @@ -62,35 +69,68 @@ describe JiraImport::StartImportService do end context 'when everything is ok' do - it 'returns success response' do - expect(subject).to be_a(ServiceResponse) - expect(subject).to be_success - end + context 'with complete mapping' do + before do + expect(Gitlab::JiraImport).to receive(:cache_users_mapping).with(project.id, { 'abc' => 12 }) + end - it 'schedules Jira import' do - subject + it 'returns success response' do + expect(subject).to be_a(ServiceResponse) + expect(subject).to be_success + end - expect(project.latest_jira_import).to be_scheduled - end + it 'schedules Jira import' do + subject - it 'creates Jira import data', :aggregate_failures do - jira_import = subject.payload[:import_data] + expect(project.latest_jira_import).to be_scheduled + end + + it 'creates Jira import data', :aggregate_failures do + jira_import = subject.payload[:import_data] + + expect(jira_import.jira_project_xid).to eq(0) + expect(jira_import.jira_project_name).to eq(fake_key) + expect(jira_import.jira_project_key).to eq(fake_key) + expect(jira_import.user).to eq(user) + end + + it 'creates Jira import label' do + expect { subject }.to change { Label.count }.by(1) + end + + it 'creates Jira label title with correct number' do + jira_import = subject.payload[:import_data] + label_title = "jira-import::#{jira_import.jira_project_key}-1" - expect(jira_import.jira_project_xid).to eq(0) - expect(jira_import.jira_project_name).to eq(fake_key) - expect(jira_import.jira_project_key).to eq(fake_key) - expect(jira_import.user).to eq(user) + expect(jira_import.label.title).to eq(label_title) + end end - it 'creates Jira import label' do - expect { subject }.to change { Label.count }.by(1) + context 'when mapping is nil' do + let(:mapping) { nil } + + it 'returns success response' do + expect(Gitlab::JiraImport).not_to receive(:cache_users_mapping) + + expect(subject).to be_a(ServiceResponse) + expect(subject).to be_success + end end - it 'creates Jira label title with correct number' do - jira_import = subject.payload[:import_data] - label_title = "jira-import::#{jira_import.jira_project_key}-1" + context 'when no mapping value is complete' do + let(:mapping) do + [ + { jira_account_id: 'def', gitlab_id: nil }, + { jira_account_id: nil, gitlab_id: 1 } + ] + end - expect(jira_import.label.title).to eq(label_title) + it 'returns success response' do + expect(Gitlab::JiraImport).not_to receive(:cache_users_mapping) + + expect(subject).to be_a(ServiceResponse) + expect(subject).to be_success + end end end diff --git a/spec/services/jira_import/users_importer_spec.rb b/spec/services/jira_import/users_importer_spec.rb index 28ce5f1b44b..64cdc70f612 100644 --- a/spec/services/jira_import/users_importer_spec.rb +++ b/spec/services/jira_import/users_importer_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe JiraImport::UsersImporter do +RSpec.describe JiraImport::UsersImporter do include JiraServiceHelper let_it_be(:user) { create(:user) } diff --git a/spec/services/jira_import/users_mapper_spec.rb b/spec/services/jira_import/users_mapper_spec.rb index 75dbc41aa2e..e5e8279a6fb 100644 --- a/spec/services/jira_import/users_mapper_spec.rb +++ b/spec/services/jira_import/users_mapper_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe JiraImport::UsersMapper do +RSpec.describe JiraImport::UsersMapper do let_it_be(:project) { create(:project) } subject { described_class.new(project, jira_users).execute } @@ -29,9 +29,9 @@ describe JiraImport::UsersMapper do # mapping is tracked in https://gitlab.com/gitlab-org/gitlab/-/issues/219023 let(:mapped_users) do [ - { jira_account_id: 'abcd', jira_display_name: 'user1', jira_email: nil, gitlab_id: nil }, - { jira_account_id: 'efg', jira_display_name: nil, jira_email: nil, gitlab_id: nil }, - { jira_account_id: 'hij', jira_display_name: 'user3', jira_email: 'user3@example.com', gitlab_id: nil } + { jira_account_id: 'abcd', jira_display_name: 'user1', jira_email: nil, gitlab_id: nil, gitlab_username: nil, gitlab_name: nil }, + { jira_account_id: 'efg', jira_display_name: nil, jira_email: nil, gitlab_id: nil, gitlab_username: nil, gitlab_name: nil }, + { jira_account_id: 'hij', jira_display_name: 'user3', jira_email: 'user3@example.com', gitlab_id: nil, gitlab_username: nil, gitlab_name: nil } ] end diff --git a/spec/services/keys/create_service_spec.rb b/spec/services/keys/create_service_spec.rb index 1f8b402cf08..1dbe383ad8e 100644 --- a/spec/services/keys/create_service_spec.rb +++ b/spec/services/keys/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Keys::CreateService do +RSpec.describe Keys::CreateService do let(:user) { create(:user) } let(:params) { attributes_for(:key) } diff --git a/spec/services/keys/destroy_service_spec.rb b/spec/services/keys/destroy_service_spec.rb index ca4bbd50c03..59ce4a941c7 100644 --- a/spec/services/keys/destroy_service_spec.rb +++ b/spec/services/keys/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Keys::DestroyService do +RSpec.describe Keys::DestroyService do let(:user) { create(:user) } subject { described_class.new(user) } diff --git a/spec/services/keys/last_used_service_spec.rb b/spec/services/keys/last_used_service_spec.rb index c675df39f4d..82b6b05975b 100644 --- a/spec/services/keys/last_used_service_spec.rb +++ b/spec/services/keys/last_used_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Keys::LastUsedService do +RSpec.describe Keys::LastUsedService do describe '#execute', :clean_gitlab_redis_shared_state do it 'updates the key when it has not been used recently' do key = create(:key, last_used_at: 1.year.ago) diff --git a/spec/services/labels/available_labels_service_spec.rb b/spec/services/labels/available_labels_service_spec.rb index 56826257d6f..9912f2cf469 100644 --- a/spec/services/labels/available_labels_service_spec.rb +++ b/spec/services/labels/available_labels_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Labels::AvailableLabelsService do +RSpec.describe Labels::AvailableLabelsService do let(:user) { create(:user) } let(:project) { create(:project, :public, group: group) } let(:group) { create(:group) } diff --git a/spec/services/labels/create_service_spec.rb b/spec/services/labels/create_service_spec.rb index f057c4401e7..7a31a5a7cae 100644 --- a/spec/services/labels/create_service_spec.rb +++ b/spec/services/labels/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Labels::CreateService do +RSpec.describe Labels::CreateService do describe '#execute' do let(:project) { create(:project) } let(:group) { create(:group) } diff --git a/spec/services/labels/find_or_create_service_spec.rb b/spec/services/labels/find_or_create_service_spec.rb index 438d895392b..aa9eb0e6a0d 100644 --- a/spec/services/labels/find_or_create_service_spec.rb +++ b/spec/services/labels/find_or_create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Labels::FindOrCreateService do +RSpec.describe Labels::FindOrCreateService do describe '#execute' do let(:group) { create(:group) } let(:project) { create(:project, namespace: group) } diff --git a/spec/services/labels/promote_service_spec.rb b/spec/services/labels/promote_service_spec.rb index d86281b751c..7674ec36331 100644 --- a/spec/services/labels/promote_service_spec.rb +++ b/spec/services/labels/promote_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Labels::PromoteService do +RSpec.describe Labels::PromoteService do describe '#execute' do let!(:user) { create(:user) } diff --git a/spec/services/labels/transfer_service_spec.rb b/spec/services/labels/transfer_service_spec.rb index a2a9c8dddf2..2c0c82ed976 100644 --- a/spec/services/labels/transfer_service_spec.rb +++ b/spec/services/labels/transfer_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Labels::TransferService do +RSpec.describe Labels::TransferService do describe '#execute' do let_it_be(:user) { create(:admin) } diff --git a/spec/services/labels/update_service_spec.rb b/spec/services/labels/update_service_spec.rb index 045e8af1135..af2403656af 100644 --- a/spec/services/labels/update_service_spec.rb +++ b/spec/services/labels/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Labels::UpdateService do +RSpec.describe Labels::UpdateService do describe '#execute' do let(:project) { create(:project) } diff --git a/spec/services/lfs/file_transformer_spec.rb b/spec/services/lfs/file_transformer_spec.rb index 13d9c369c42..e87c80b4c6c 100644 --- a/spec/services/lfs/file_transformer_spec.rb +++ b/spec/services/lfs/file_transformer_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -describe Lfs::FileTransformer do +RSpec.describe Lfs::FileTransformer do let(:project) { create(:project, :repository, :wiki_repo) } let(:repository) { project.repository } let(:file_content) { 'Test file content' } diff --git a/spec/services/lfs/lock_file_service_spec.rb b/spec/services/lfs/lock_file_service_spec.rb index 2bd62b96083..b3a121866c8 100644 --- a/spec/services/lfs/lock_file_service_spec.rb +++ b/spec/services/lfs/lock_file_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Lfs::LockFileService do +RSpec.describe Lfs::LockFileService do let(:project) { create(:project) } let(:current_user) { create(:user) } diff --git a/spec/services/lfs/locks_finder_service_spec.rb b/spec/services/lfs/locks_finder_service_spec.rb index fdc60e2c03f..1167212eb69 100644 --- a/spec/services/lfs/locks_finder_service_spec.rb +++ b/spec/services/lfs/locks_finder_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Lfs::LocksFinderService do +RSpec.describe Lfs::LocksFinderService do let(:project) { create(:project) } let(:user) { create(:user) } let(:params) { {} } diff --git a/spec/services/lfs/unlock_file_service_spec.rb b/spec/services/lfs/unlock_file_service_spec.rb index 1334b074e84..7ab269f897a 100644 --- a/spec/services/lfs/unlock_file_service_spec.rb +++ b/spec/services/lfs/unlock_file_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Lfs::UnlockFileService do +RSpec.describe Lfs::UnlockFileService do let(:project) { create(:project) } let(:current_user) { create(:user) } let(:lock_author) { create(:user) } diff --git a/spec/services/members/approve_access_request_service_spec.rb b/spec/services/members/approve_access_request_service_spec.rb index 5bbceac3dd0..e6a94fdaf84 100644 --- a/spec/services/members/approve_access_request_service_spec.rb +++ b/spec/services/members/approve_access_request_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Members::ApproveAccessRequestService do +RSpec.describe Members::ApproveAccessRequestService do let(:project) { create(:project, :public) } let(:group) { create(:group, :public) } let(:current_user) { create(:user) } diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb index 674fe0f666e..00b5ff59e48 100644 --- a/spec/services/members/create_service_spec.rb +++ b/spec/services/members/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Members::CreateService do +RSpec.describe Members::CreateService do let(:project) { create(:project) } let(:user) { create(:user) } let(:project_user) { create(:user) } diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb index 73ac0bd7716..13e7b4c1006 100644 --- a/spec/services/members/destroy_service_spec.rb +++ b/spec/services/members/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Members::DestroyService do +RSpec.describe Members::DestroyService do let(:current_user) { create(:user) } let(:member_user) { create(:user) } let(:group) { create(:group, :public) } @@ -25,6 +25,7 @@ describe Members::DestroyService do before do type = member.is_a?(GroupMember) ? 'Group' : 'Project' expect(TodosDestroyer::EntityLeaveWorker).to receive(:perform_in).with(Todo::WAIT_FOR_DELETE, member.user_id, member.source_id, type) + expect(MembersDestroyer::UnassignIssuablesWorker).to receive(:perform_async).with(member.user_id, member.source_id, type) if opts[:unassign_issuables] end it 'destroys the member' do @@ -56,12 +57,23 @@ describe Members::DestroyService do expect(member_user.todos_pending_count).to be(1) expect(member_user.todos_done_count).to be(1) - described_class.new(current_user).execute(member, opts) + service = described_class.new(current_user) + + if opts[:unassign_issuables] + expect(service).to receive(:enqueue_unassign_issuables).with(member) + end + + service.execute(member, opts) expect(member_user.assigned_open_merge_requests_count).to be(0) expect(member_user.assigned_open_issues_count).to be(0) expect(member_user.todos_pending_count).to be(0) expect(member_user.todos_done_count).to be(0) + + unless opts[:unassign_issuables] + expect(member_user.assigned_merge_requests.opened.count).to be(1) + expect(member_user.assigned_issues.opened.count).to be(1) + end end end @@ -100,7 +112,7 @@ describe Members::DestroyService do it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' it_behaves_like 'a service destroying a member with access' do - let(:opts) { { skip_authorization: true } } + let(:opts) { { skip_authorization: true, unassign_issuables: true } } end end @@ -114,7 +126,7 @@ describe Members::DestroyService do it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' it_behaves_like 'a service destroying a member with access' do - let(:opts) { { skip_authorization: true } } + let(:opts) { { skip_authorization: true, unassign_issuables: true } } end end end @@ -133,6 +145,31 @@ describe Members::DestroyService do end it_behaves_like 'a service destroying a member with access' + + context 'unassign issuables' do + it_behaves_like 'a service destroying a member with access' do + let(:opts) { { unassign_issuables: true } } + end + end + end + + context 'with a project bot member' do + let(:member) { group_project.members.find_by(user_id: member_user.id) } + let(:member_user) { create(:user, :project_bot) } + + before do + group_project.add_maintainer(member_user) + end + + context 'when the destroy_bot flag is true' do + it_behaves_like 'a service destroying a member with access' do + let(:opts) { { destroy_bot: true } } + end + end + + context 'when the destroy_bot flag is not specified' do + it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' + end end context 'with a group member' do @@ -143,6 +180,12 @@ describe Members::DestroyService do end it_behaves_like 'a service destroying a member with access' + + context 'unassign issuables' do + it_behaves_like 'a service destroying a member with access' do + let(:opts) { { unassign_issuables: true } } + end + end end end end diff --git a/spec/services/members/request_access_service_spec.rb b/spec/services/members/request_access_service_spec.rb index a0f7ae91bdb..69eea2aea4b 100644 --- a/spec/services/members/request_access_service_spec.rb +++ b/spec/services/members/request_access_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Members::RequestAccessService do +RSpec.describe Members::RequestAccessService do let(:user) { create(:user) } shared_examples 'a service raising Gitlab::Access::AccessDeniedError' do diff --git a/spec/services/members/unassign_issuables_service_spec.rb b/spec/services/members/unassign_issuables_service_spec.rb new file mode 100644 index 00000000000..3f7ccb7bab3 --- /dev/null +++ b/spec/services/members/unassign_issuables_service_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Members::UnassignIssuablesService do + let_it_be(:group) { create(:group, :private) } + let_it_be(:project) { create(:project, group: group) } + let_it_be(:user, reload: true) { create(:user) } + let_it_be(:assigned_issue1, reload: true) { create(:issue, project: project, assignees: [user]) } + let_it_be(:assigned_issue2, reload: true) { create(:issue, project: project, assignees: [user]) } + + let!(:assigned_merge_request1) { create(:merge_request, :simple, :closed, target_project: project, source_project: project, assignees: [user], title: 'Test1') } + let!(:assigned_merge_request2) { create(:merge_request, :simple, :opened, target_project: project, source_project: project, assignees: [user], title: 'Test2') } + + describe '#execute' do + RSpec.shared_examples 'un-assigning issuables' do |issue_count, mr_count, open_issue_count, open_mr_count| + it 'removes issuable assignments', :aggregate_failures do + expect(user.assigned_issues.count).to eq(issue_count) + expect(user.assigned_merge_requests.count).to eq(mr_count) + + subject + + expect(user.assigned_issues.count).to eq(0) + expect(user.assigned_merge_requests.count).to eq(0) + end + + it 'invalidates user cache', :aggregate_failures, :clean_gitlab_redis_cache do + expect(user.assigned_open_merge_requests_count).to eq(open_mr_count) + expect(user.assigned_open_issues_count).to eq(open_issue_count) + + subject + + expect(user.assigned_open_merge_requests_count).to eq(0) + expect(user.assigned_open_issues_count).to eq(0) + end + end + + context 'when a user leaves a project' do + before do + project.add_maintainer(user) + end + + subject { described_class.new(user, project).execute } + + it_behaves_like 'un-assigning issuables', 2, 2, 2, 1 + end + + context 'when a user leaves a group' do + let_it_be(:project2) { create(:project, group: group) } + + let_it_be(:assigned_issue3, reload: true) { create(:issue, project: project2, assignees: [user]) } + let_it_be(:assigned_issue4, reload: true) { create(:issue, project: project2, assignees: [user]) } + + let!(:assigned_merge_request3) { create(:merge_request, :simple, :closed, target_project: project2, source_project: project2, assignees: [user], title: 'Test1') } + let!(:assigned_merge_request4) { create(:merge_request, :simple, :opened, target_project: project2, source_project: project2, assignees: [user], title: 'Test2') } + + before do + group.add_maintainer(user) + end + + subject { described_class.new(user, group).execute } + + it_behaves_like 'un-assigning issuables', 4, 4, 4, 2 + end + end +end diff --git a/spec/services/members/update_service_spec.rb b/spec/services/members/update_service_spec.rb index a8b28127df2..f510916558b 100644 --- a/spec/services/members/update_service_spec.rb +++ b/spec/services/members/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Members::UpdateService do +RSpec.describe Members::UpdateService do let(:project) { create(:project, :public) } let(:group) { create(:group, :public) } let(:current_user) { create(:user) } diff --git a/spec/services/merge_requests/add_context_service_spec.rb b/spec/services/merge_requests/add_context_service_spec.rb index d4e95c2f1ea..58ed91218d1 100644 --- a/spec/services/merge_requests/add_context_service_spec.rb +++ b/spec/services/merge_requests/add_context_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::AddContextService do +RSpec.describe MergeRequests::AddContextService do let(:project) { create(:project, :repository) } let(:admin) { create(:admin) } let(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: admin) } diff --git a/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb b/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb index 0cec1e7be22..3c81ad6722d 100644 --- a/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb +++ b/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::AddTodoWhenBuildFailsService do +RSpec.describe MergeRequests::AddTodoWhenBuildFailsService do let(:user) { create(:user) } let(:project) { create(:project, :repository) } let(:sha) { '1234567890abcdef1234567890abcdef12345678' } diff --git a/spec/services/merge_requests/after_create_service_spec.rb b/spec/services/merge_requests/after_create_service_spec.rb index 4aefe5f7dae..840b7bc0a1c 100644 --- a/spec/services/merge_requests/after_create_service_spec.rb +++ b/spec/services/merge_requests/after_create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::AfterCreateService do +RSpec.describe MergeRequests::AfterCreateService do let_it_be(:merge_request) { create(:merge_request) } subject(:after_create_service) do diff --git a/spec/services/merge_requests/approval_service_spec.rb b/spec/services/merge_requests/approval_service_spec.rb new file mode 100644 index 00000000000..124501f17d5 --- /dev/null +++ b/spec/services/merge_requests/approval_service_spec.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe MergeRequests::ApprovalService do + describe '#execute' do + let(:user) { create(:user) } + let(:merge_request) { create(:merge_request) } + let(:project) { merge_request.project } + let!(:todo) { create(:todo, user: user, project: project, target: merge_request) } + + subject(:service) { described_class.new(project, user) } + + before do + project.add_developer(user) + end + + context 'with invalid approval' do + before do + allow(merge_request.approvals).to receive(:new).and_return(double(save: false)) + end + + it 'does not create an approval note' do + expect(SystemNoteService).not_to receive(:approve_mr) + + service.execute(merge_request) + end + + it 'does not mark pending todos as done' do + service.execute(merge_request) + + expect(todo.reload).to be_pending + end + end + + context 'with valid approval' do + it 'creates an approval note and marks pending todos as done' do + expect(SystemNoteService).to receive(:approve_mr).with(merge_request, user) + expect(merge_request.approvals).to receive(:reset) + + service.execute(merge_request) + + expect(todo.reload).to be_done + end + + it 'creates approve MR event' do + expect_next_instance_of(EventCreateService) do |instance| + expect(instance).to receive(:approve_mr) + .with(merge_request, user) + end + + service.execute(merge_request) + end + + context 'with remaining approvals' do + it 'fires an approval webhook' do + expect(service).to receive(:execute_hooks).with(merge_request, 'approved') + + service.execute(merge_request) + end + end + end + + context 'user cannot update the merge request' do + before do + project.add_guest(user) + end + + it 'does not update approvals' do + expect { service.execute(merge_request) }.not_to change { merge_request.approvals.size } + end + end + end +end diff --git a/spec/services/merge_requests/assign_issues_service_spec.rb b/spec/services/merge_requests/assign_issues_service_spec.rb index c0b57b9092d..6398e8c533e 100644 --- a/spec/services/merge_requests/assign_issues_service_spec.rb +++ b/spec/services/merge_requests/assign_issues_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::AssignIssuesService do +RSpec.describe MergeRequests::AssignIssuesService do let(:user) { create(:user) } let(:project) { create(:project, :public, :repository) } let(:issue) { create(:issue, project: project) } diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb index 9b358839c06..f99be26927d 100644 --- a/spec/services/merge_requests/build_service_spec.rb +++ b/spec/services/merge_requests/build_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe MergeRequests::BuildService do +RSpec.describe MergeRequests::BuildService do using RSpec::Parameterized::TableSyntax include RepoHelpers include ProjectForksHelper @@ -189,8 +189,8 @@ describe MergeRequests::BuildService do it_behaves_like 'allows the merge request to be created' - it 'adds a WIP prefix to the merge request title' do - expect(merge_request.title).to eq('WIP: Feature branch') + it 'adds a Draft prefix to the merge request title' do + expect(merge_request.title).to eq('Draft: Feature branch') end end diff --git a/spec/services/merge_requests/close_service_spec.rb b/spec/services/merge_requests/close_service_spec.rb index 0e51de48fb1..e518e439a84 100644 --- a/spec/services/merge_requests/close_service_spec.rb +++ b/spec/services/merge_requests/close_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::CloseService do +RSpec.describe MergeRequests::CloseService do let(:user) { create(:user) } let(:user2) { create(:user) } let(:guest) { create(:user) } diff --git a/spec/services/merge_requests/conflicts/list_service_spec.rb b/spec/services/merge_requests/conflicts/list_service_spec.rb index 13d69307084..14133731e37 100644 --- a/spec/services/merge_requests/conflicts/list_service_spec.rb +++ b/spec/services/merge_requests/conflicts/list_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::Conflicts::ListService do +RSpec.describe MergeRequests::Conflicts::ListService do describe '#can_be_resolved_in_ui?' do def create_merge_request(source_branch, target_branch = 'conflict-start') create(:merge_request, source_branch: source_branch, target_branch: target_branch, merge_status: :unchecked) do |mr| @@ -30,6 +30,7 @@ describe MergeRequests::Conflicts::ListService do it 'returns a falsey value when one of the MR branches is missing' do merge_request = create_merge_request('conflict-resolvable') merge_request.project.repository.rm_branch(merge_request.author, 'conflict-resolvable') + merge_request.clear_memoized_source_branch_exists expect(conflicts_service(merge_request).can_be_resolved_in_ui?).to be_falsey end diff --git a/spec/services/merge_requests/conflicts/resolve_service_spec.rb b/spec/services/merge_requests/conflicts/resolve_service_spec.rb index 74f20094081..c4d50124ca9 100644 --- a/spec/services/merge_requests/conflicts/resolve_service_spec.rb +++ b/spec/services/merge_requests/conflicts/resolve_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::Conflicts::ResolveService do +RSpec.describe MergeRequests::Conflicts::ResolveService do include ProjectForksHelper let(:user) { create(:user) } let(:project) { create(:project, :public, :repository) } diff --git a/spec/services/merge_requests/create_from_issue_service_spec.rb b/spec/services/merge_requests/create_from_issue_service_spec.rb index fb1bb308170..fa70ad8c559 100644 --- a/spec/services/merge_requests/create_from_issue_service_spec.rb +++ b/spec/services/merge_requests/create_from_issue_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::CreateFromIssueService do +RSpec.describe MergeRequests::CreateFromIssueService do include ProjectForksHelper let(:project) { create(:project, :repository) } @@ -163,10 +163,10 @@ describe MergeRequests::CreateFromIssueService do expect(result[:merge_request].milestone_id).to eq(milestone_id) end - it 'sets the merge request title to: "WIP: Resolves "$issue-title"' do + it 'sets the merge request title to: "Draft: Resolves "$issue-title"' do result = service.execute - expect(result[:merge_request].title).to eq("WIP: Resolve \"#{issue.title}\"") + expect(result[:merge_request].title).to eq("Draft: Resolve \"#{issue.title}\"") end end @@ -193,10 +193,10 @@ describe MergeRequests::CreateFromIssueService do it_behaves_like 'a service that creates a merge request from an issue' - it 'sets the merge request title to: "WIP: $issue-branch-name', :sidekiq_might_not_need_inline do + it 'sets the merge request title to: "Draft: $issue-branch-name', :sidekiq_might_not_need_inline do result = service.execute - expect(result[:merge_request].title).to eq("WIP: #{issue.to_branch_name.titleize.humanize}") + expect(result[:merge_request].title).to eq("Draft: #{issue.to_branch_name.titleize.humanize}") end end end diff --git a/spec/services/merge_requests/create_pipeline_service_spec.rb b/spec/services/merge_requests/create_pipeline_service_spec.rb index 9eb28759061..db46bd37eea 100644 --- a/spec/services/merge_requests/create_pipeline_service_spec.rb +++ b/spec/services/merge_requests/create_pipeline_service_spec.rb @@ -2,10 +2,13 @@ require 'spec_helper' -describe MergeRequests::CreatePipelineService do +RSpec.describe MergeRequests::CreatePipelineService do + include ProjectForksHelper + let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } - let(:service) { described_class.new(project, user, params) } + let(:service) { described_class.new(project, actor, params) } + let(:actor) { user } let(:params) { {} } before do @@ -26,11 +29,13 @@ describe MergeRequests::CreatePipelineService do let(:merge_request) do create(:merge_request, source_branch: 'feature', - source_project: project, + source_project: source_project, target_branch: 'master', target_project: project) end + let(:source_project) { project } + it 'creates a detached merge request pipeline' do expect { subject }.to change { Ci::Pipeline.count }.by(1) @@ -42,6 +47,50 @@ describe MergeRequests::CreatePipelineService do expect(subject.source).to eq('merge_request_event') end + context 'with fork merge request' do + let_it_be(:forked_project) { fork_project(project, nil, repository: true, target_project: create(:project, :private, :repository)) } + let(:source_project) { forked_project } + + context 'when actor has permission to create pipelines in target project' do + let(:actor) { user } + + it 'creates a pipeline in the target project' do + expect(subject.project).to eq(project) + end + + context 'when ci_allow_to_create_merge_request_pipelines_in_target_project feature flag is disabled' do + before do + stub_feature_flags(ci_allow_to_create_merge_request_pipelines_in_target_project: false) + end + + it 'creates a pipeline in the source project' do + expect(subject.project).to eq(source_project) + end + end + end + + context 'when actor has permission to create pipelines in forked project' do + let(:actor) { fork_user } + let(:fork_user) { create(:user) } + + before do + source_project.add_developer(fork_user) + end + + it 'creates a pipeline in the source project' do + expect(subject.project).to eq(source_project) + end + end + + context 'when actor does not have permission to create pipelines' do + let(:actor) { create(:user) } + + it 'returns nothing' do + expect(subject.full_error_messages).to include('Insufficient permissions to create a new pipeline') + end + end + end + context 'when service is called multiple times' do it 'creates a pipeline once' do expect do diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb index bb40c399b6e..a8661f027e8 100644 --- a/spec/services/merge_requests/create_service_spec.rb +++ b/spec/services/merge_requests/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do +RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do include ProjectForksHelper let(:project) { create(:project, :repository) } @@ -216,11 +216,12 @@ describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do target_project.add_maintainer(user) end - it 'create legacy detached merge request pipeline for fork merge request' do + it 'create detached merge request pipeline for fork merge request' do merge_request.reload - expect(merge_request.actual_head_pipeline) - .to be_legacy_detached_merge_request_pipeline + head_pipeline = merge_request.actual_head_pipeline + expect(head_pipeline).to be_detached_merge_request_pipeline + expect(head_pipeline.project).to eq(target_project) end end @@ -339,13 +340,14 @@ describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do end end - it_behaves_like 'new issuable record that supports quick actions' do + it_behaves_like 'issuable record that supports quick actions' do let(:default_params) do { source_branch: 'feature', target_branch: 'master' } end + let(:issuable) { described_class.new(project, user, params).execute } end context 'Quick actions' do diff --git a/spec/services/merge_requests/delete_non_latest_diffs_service_spec.rb b/spec/services/merge_requests/delete_non_latest_diffs_service_spec.rb index 2adf808619d..377615bbc6f 100644 --- a/spec/services/merge_requests/delete_non_latest_diffs_service_spec.rb +++ b/spec/services/merge_requests/delete_non_latest_diffs_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::DeleteNonLatestDiffsService, :clean_gitlab_redis_shared_state do +RSpec.describe MergeRequests::DeleteNonLatestDiffsService, :clean_gitlab_redis_shared_state do let(:merge_request) { create(:merge_request) } let!(:subject) { described_class.new(merge_request) } diff --git a/spec/services/merge_requests/ff_merge_service_spec.rb b/spec/services/merge_requests/ff_merge_service_spec.rb index 415b351e13a..c3da02273a4 100644 --- a/spec/services/merge_requests/ff_merge_service_spec.rb +++ b/spec/services/merge_requests/ff_merge_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::FfMergeService do +RSpec.describe MergeRequests::FfMergeService do let(:user) { create(:user) } let(:user2) { create(:user) } let(:merge_request) do diff --git a/spec/services/merge_requests/get_urls_service_spec.rb b/spec/services/merge_requests/get_urls_service_spec.rb index 8cc627b64d9..053752626dc 100644 --- a/spec/services/merge_requests/get_urls_service_spec.rb +++ b/spec/services/merge_requests/get_urls_service_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -describe MergeRequests::GetUrlsService do +RSpec.describe MergeRequests::GetUrlsService do include ProjectForksHelper let(:project) { create(:project, :public, :repository) } diff --git a/spec/services/merge_requests/link_lfs_objects_service_spec.rb b/spec/services/merge_requests/link_lfs_objects_service_spec.rb index f07cf13e4f2..c1765e3a2ab 100644 --- a/spec/services/merge_requests/link_lfs_objects_service_spec.rb +++ b/spec/services/merge_requests/link_lfs_objects_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::LinkLfsObjectsService, :sidekiq_inline do +RSpec.describe MergeRequests::LinkLfsObjectsService, :sidekiq_inline do include ProjectForksHelper include RepoHelpers diff --git a/spec/services/merge_requests/merge_orchestration_service_spec.rb b/spec/services/merge_requests/merge_orchestration_service_spec.rb index c50f20d7703..67dbb5a1a01 100644 --- a/spec/services/merge_requests/merge_orchestration_service_spec.rb +++ b/spec/services/merge_requests/merge_orchestration_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::MergeOrchestrationService do +RSpec.describe MergeRequests::MergeOrchestrationService do let_it_be(:maintainer) { create(:user) } let(:merge_params) { { sha: merge_request.diff_head_sha } } let(:user) { maintainer } diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb index 2274d917527..11e341994f7 100644 --- a/spec/services/merge_requests/merge_service_spec.rb +++ b/spec/services/merge_requests/merge_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::MergeService do +RSpec.describe MergeRequests::MergeService do let_it_be(:user) { create(:user) } let_it_be(:user2) { create(:user) } let(:merge_request) { create(:merge_request, :simple, author: user2, assignees: [user2]) } @@ -360,6 +360,25 @@ describe MergeRequests::MergeService do expect(Gitlab::AppLogger).to have_received(:error).with(a_string_matching(error_message)) end + context 'when squashing is required' do + before do + merge_request.update!(source_branch: 'master', target_branch: 'feature') + merge_request.target_project.project_setting.squash_always! + end + + it 'raises an error if squashing is not done' do + error_message = 'requires squashing commits' + + service.execute(merge_request) + + expect(merge_request).to be_open + + expect(merge_request.merge_commit_sha).to be_nil + expect(merge_request.merge_error).to include(error_message) + expect(Gitlab::AppLogger).to have_received(:error).with(a_string_matching(error_message)) + end + end + context 'when squashing' do before do merge_request.update!(source_branch: 'master', target_branch: 'feature') diff --git a/spec/services/merge_requests/merge_to_ref_service_spec.rb b/spec/services/merge_requests/merge_to_ref_service_spec.rb index 596d46f3c43..b482e8d6724 100644 --- a/spec/services/merge_requests/merge_to_ref_service_spec.rb +++ b/spec/services/merge_requests/merge_to_ref_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::MergeToRefService do +RSpec.describe MergeRequests::MergeToRefService do shared_examples_for 'MergeService for target ref' do it 'target_ref has the same state of target branch' do repo = merge_request.target_project.repository diff --git a/spec/services/merge_requests/mergeability_check_service_spec.rb b/spec/services/merge_requests/mergeability_check_service_spec.rb index 45519ddf3d3..543da46f883 100644 --- a/spec/services/merge_requests/mergeability_check_service_spec.rb +++ b/spec/services/merge_requests/mergeability_check_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::MergeabilityCheckService, :clean_gitlab_redis_shared_state do +RSpec.describe MergeRequests::MergeabilityCheckService, :clean_gitlab_redis_shared_state do shared_examples_for 'unmergeable merge request' do it 'updates or keeps merge status as cannot_be_merged' do subject diff --git a/spec/services/merge_requests/migrate_external_diffs_service_spec.rb b/spec/services/merge_requests/migrate_external_diffs_service_spec.rb index 233b944624f..6ea8626ba73 100644 --- a/spec/services/merge_requests/migrate_external_diffs_service_spec.rb +++ b/spec/services/merge_requests/migrate_external_diffs_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::MigrateExternalDiffsService do +RSpec.describe MergeRequests::MigrateExternalDiffsService do let(:merge_request) { create(:merge_request) } let(:diff) { merge_request.merge_request_diff } diff --git a/spec/services/merge_requests/post_merge_service_spec.rb b/spec/services/merge_requests/post_merge_service_spec.rb index fff6ddf3928..a51a896ca96 100644 --- a/spec/services/merge_requests/post_merge_service_spec.rb +++ b/spec/services/merge_requests/post_merge_service_spec.rb @@ -2,11 +2,13 @@ require 'spec_helper' -describe MergeRequests::PostMergeService do +RSpec.describe MergeRequests::PostMergeService do let(:user) { create(:user) } let(:merge_request) { create(:merge_request, assignees: [user]) } let(:project) { merge_request.project } + subject { described_class.new(project, user).execute(merge_request) } + before do project.add_maintainer(user) end @@ -19,10 +21,7 @@ describe MergeRequests::PostMergeService do project.open_merge_requests_count merge_request.update!(state: 'merged') - service = described_class.new(project, user, {}) - - expect { service.execute(merge_request) } - .to change { project.open_merge_requests_count }.from(1).to(0) + expect { subject }.to change { project.open_merge_requests_count }.from(1).to(0) end it 'updates metrics' do @@ -35,7 +34,7 @@ describe MergeRequests::PostMergeService do expect(metrics_service).to receive(:merge) - described_class.new(project, user, {}).execute(merge_request) + subject end it 'deletes non-latest diffs' do @@ -45,7 +44,7 @@ describe MergeRequests::PostMergeService do .to receive(:new).with(merge_request) .and_return(diff_removal_service) - described_class.new(project, user, {}).execute(merge_request) + subject expect(diff_removal_service).to have_received(:execute) end @@ -56,21 +55,63 @@ describe MergeRequests::PostMergeService do issue = create(:issue, project: project) allow(merge_request).to receive(:visible_closing_issues_for).and_return([issue]) - expect_next_instance_of(Issues::CloseService) do |service| - allow(service).to receive(:execute).with(issue, commit: merge_request).and_raise(RuntimeError) + expect_next_instance_of(Issues::CloseService) do |close_service| + allow(close_service).to receive(:execute).with(issue, commit: merge_request).and_raise(RuntimeError) end - expect { described_class.new(project, user).execute(merge_request) }.to raise_error(RuntimeError) + expect { subject }.to raise_error(RuntimeError) expect(merge_request.reload).to be_merged end it 'clean up environments for the merge request' do - expect_next_instance_of(Ci::StopEnvironmentsService) do |service| - expect(service).to receive(:execute_for_merge_request).with(merge_request) + expect_next_instance_of(Ci::StopEnvironmentsService) do |stop_environment_service| + expect(stop_environment_service).to receive(:execute_for_merge_request).with(merge_request) end - described_class.new(project, user).execute(merge_request) + subject + end + + context 'when the merge request has review apps' do + it 'cancels all review app deployments' do + pipeline = create(:ci_pipeline, + source: :merge_request_event, + merge_request: merge_request, + project: project, + sha: merge_request.diff_head_sha, + merge_requests_as_head_pipeline: [merge_request]) + + review_env_a = create(:environment, project: project, state: :available, name: 'review/a') + review_env_b = create(:environment, project: project, state: :available, name: 'review/b') + review_env_c = create(:environment, project: project, state: :stopped, name: 'review/c') + deploy_env = create(:environment, project: project, state: :available, name: 'deploy') + + review_job_a1 = create(:ci_build, :with_deployment, :start_review_app, + pipeline: pipeline, project: project, environment: review_env_a.name) + review_job_a2 = create(:ci_build, :with_deployment, :start_review_app, + pipeline: pipeline, project: project, environment: review_env_a.name) + finished_review_job_a = create(:ci_build, :with_deployment, :start_review_app, + pipeline: pipeline, project: project, status: :success, environment: review_env_a.name) + review_job_b1 = create(:ci_build, :with_deployment, :start_review_app, + pipeline: pipeline, project: project, environment: review_env_b.name) + review_job_b2 = create(:ci_build, :start_review_app, + pipeline: pipeline, project: project, environment: review_env_b.name) + review_job_c1 = create(:ci_build, :with_deployment, :start_review_app, + pipeline: pipeline, project: project, environment: review_env_c.name) + deploy_job = create(:ci_build, :with_deployment, :deploy_to_production, + pipeline: pipeline, project: project, environment: deploy_env.name) + + subject + + expect(review_job_a1.reload.canceled?).to be true + expect(review_job_a2.reload.canceled?).to be true + expect(finished_review_job_a.reload.status).to eq "success" + expect(finished_review_job_a.reload.canceled?).to be false + expect(review_job_b1.reload.canceled?).to be true + expect(review_job_b2.reload.canceled?).to be false + expect(review_job_c1.reload.canceled?).to be false + expect(deploy_job.reload.canceled?).to be false + end end end end diff --git a/spec/services/merge_requests/push_options_handler_service_spec.rb b/spec/services/merge_requests/push_options_handler_service_spec.rb index 420c8513c72..55f92d6bd0a 100644 --- a/spec/services/merge_requests/push_options_handler_service_spec.rb +++ b/spec/services/merge_requests/push_options_handler_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::PushOptionsHandlerService do +RSpec.describe MergeRequests::PushOptionsHandlerService do include ProjectForksHelper let(:user) { create(:user) } diff --git a/spec/services/merge_requests/pushed_branches_service_spec.rb b/spec/services/merge_requests/pushed_branches_service_spec.rb index 7b5d505f4d9..6e9c77bd3b6 100644 --- a/spec/services/merge_requests/pushed_branches_service_spec.rb +++ b/spec/services/merge_requests/pushed_branches_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::PushedBranchesService do +RSpec.describe MergeRequests::PushedBranchesService do let(:project) { create(:project) } let!(:service) { described_class.new(project, nil, changes: pushed_branches) } diff --git a/spec/services/merge_requests/rebase_service_spec.rb b/spec/services/merge_requests/rebase_service_spec.rb index 69d555f838d..2e525f2ed01 100644 --- a/spec/services/merge_requests/rebase_service_spec.rb +++ b/spec/services/merge_requests/rebase_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::RebaseService do +RSpec.describe MergeRequests::RebaseService do include ProjectForksHelper let(:user) { create(:user) } diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index e60ff6eb98a..18c4cef7087 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::RefreshService do +RSpec.describe MergeRequests::RefreshService do include ProjectForksHelper include ProjectHelpers @@ -225,12 +225,13 @@ describe MergeRequests::RefreshService do context 'when service runs on forked project' do let(:project) { @fork_project } - it 'creates legacy detached merge request pipeline for fork merge request', :sidekiq_might_not_need_inline do + it 'creates detached merge request pipeline for fork merge request', :sidekiq_inline do expect { subject } .to change { @fork_merge_request.pipelines_for_merge_request.count }.by(1) - expect(@fork_merge_request.pipelines_for_merge_request.first) - .to be_legacy_detached_merge_request_pipeline + merge_request_pipeline = @fork_merge_request.pipelines_for_merge_request.first + expect(merge_request_pipeline).to be_detached_merge_request_pipeline + expect(merge_request_pipeline.project).to eq(@project) end end diff --git a/spec/services/merge_requests/reload_diffs_service_spec.rb b/spec/services/merge_requests/reload_diffs_service_spec.rb index d2444af1b0f..3d5b65207e6 100644 --- a/spec/services/merge_requests/reload_diffs_service_spec.rb +++ b/spec/services/merge_requests/reload_diffs_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::ReloadDiffsService, :use_clean_rails_memory_store_caching do +RSpec.describe MergeRequests::ReloadDiffsService, :use_clean_rails_memory_store_caching do let(:current_user) { create(:user) } let(:merge_request) { create(:merge_request) } let(:subject) { described_class.new(merge_request, current_user) } @@ -34,10 +34,8 @@ describe MergeRequests::ReloadDiffsService, :use_clean_rails_memory_store_cachin context 'cache clearing' do it 'clears the cache for older diffs on the merge request' do - old_diff = merge_request.merge_request_diff - old_cache_key = old_diff.diffs_collection.cache_key - - expect_any_instance_of(Redis).to receive(:del).with(old_cache_key).and_call_original + expect_any_instance_of(Redis).to receive(:del).once.and_call_original + expect(Rails.cache).to receive(:delete).once.and_call_original subject.execute end diff --git a/spec/services/merge_requests/remove_approval_service_spec.rb b/spec/services/merge_requests/remove_approval_service_spec.rb new file mode 100644 index 00000000000..40da928e832 --- /dev/null +++ b/spec/services/merge_requests/remove_approval_service_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe MergeRequests::RemoveApprovalService do + describe '#execute' do + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:merge_request) { create(:merge_request, source_project: project) } + let!(:existing_approval) { create(:approval, merge_request: merge_request) } + + subject(:service) { described_class.new(project, user) } + + def execute! + service.execute(merge_request) + end + + before do + project.add_developer(user) + end + + context 'with a user who has approved' do + let!(:approval) { create(:approval, user: user, merge_request: merge_request) } + + it 'removes the approval' do + expect { execute! }.to change { merge_request.approvals.size }.from(2).to(1) + end + + it 'creates an unapproval note and triggers web hook' do + expect(service).to receive(:execute_hooks).with(merge_request, 'unapproved') + expect(SystemNoteService).to receive(:unapprove_mr) + + execute! + end + end + + context 'with a user who has not approved' do + it 'does not create an unapproval note and triggers web hook' do + expect(service).not_to receive(:execute_hooks) + expect(SystemNoteService).not_to receive(:unapprove_mr) + + execute! + end + end + end +end diff --git a/spec/services/merge_requests/reopen_service_spec.rb b/spec/services/merge_requests/reopen_service_spec.rb index 3807c44b01f..0066834180e 100644 --- a/spec/services/merge_requests/reopen_service_spec.rb +++ b/spec/services/merge_requests/reopen_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::ReopenService do +RSpec.describe MergeRequests::ReopenService do let(:user) { create(:user) } let(:user2) { create(:user) } let(:guest) { create(:user) } diff --git a/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb b/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb index 29896db58ac..874cf66659a 100644 --- a/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb +++ b/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::ResolvedDiscussionNotificationService do +RSpec.describe MergeRequests::ResolvedDiscussionNotificationService do let(:merge_request) { create(:merge_request) } let(:user) { create(:user) } let(:project) { merge_request.project } diff --git a/spec/services/merge_requests/squash_service_spec.rb b/spec/services/merge_requests/squash_service_spec.rb index a53314ed737..1ec1dc0f6eb 100644 --- a/spec/services/merge_requests/squash_service_spec.rb +++ b/spec/services/merge_requests/squash_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::SquashService do +RSpec.describe MergeRequests::SquashService do include GitHelpers let(:service) { described_class.new(project, user, { merge_request: merge_request }) } @@ -131,6 +131,42 @@ describe MergeRequests::SquashService do include_examples 'the squash succeeds' end + context 'when squashing is disabled by default on the project' do + # Squashing is disabled by default, but it should still allow you + # to squash-and-merge if selected through the UI + let(:merge_request) { merge_request_with_only_new_files } + + before do + merge_request.project.project_setting.squash_default_off! + end + + include_examples 'the squash succeeds' + end + + context 'when squashing is forbidden on the project' do + let(:merge_request) { merge_request_with_only_new_files } + + before do + merge_request.project.project_setting.squash_never! + end + + it 'raises a squash error' do + expect(service.execute).to match( + status: :error, + message: a_string_including('does not allow squashing commits when merge requests are accepted')) + end + end + + context 'when squashing is enabled by default on the project' do + let(:merge_request) { merge_request_with_only_new_files } + + before do + merge_request.project.project_setting.squash_always! + end + + include_examples 'the squash succeeds' + end + context 'when squashing with files too large to display' do let(:merge_request) { merge_request_with_large_files } diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 2b934b24757..c3433c8c9d2 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequests::UpdateService, :mailer do +RSpec.describe MergeRequests::UpdateService, :mailer do include ProjectForksHelper let(:group) { create(:group, :public) } @@ -737,5 +737,10 @@ describe MergeRequests::UpdateService, :mailer do .to change { merge_request.reload.force_remove_source_branch? }.from(nil).to(true) end end + + it_behaves_like 'issuable record that supports quick actions' do + let(:existing_merge_request) { create(:merge_request, source_project: project) } + let(:issuable) { described_class.new(project, user, params).execute(existing_merge_request) } + end end end diff --git a/spec/services/metrics/dashboard/annotations/create_service_spec.rb b/spec/services/metrics/dashboard/annotations/create_service_spec.rb index 7dabca3c860..c3fe7238047 100644 --- a/spec/services/metrics/dashboard/annotations/create_service_spec.rb +++ b/spec/services/metrics/dashboard/annotations/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Metrics::Dashboard::Annotations::CreateService do +RSpec.describe Metrics::Dashboard::Annotations::CreateService do let_it_be(:user) { create(:user) } let(:description) { 'test annotation' } let(:dashboard_path) { 'config/prometheus/common_metrics.yml' } diff --git a/spec/services/metrics/dashboard/annotations/delete_service_spec.rb b/spec/services/metrics/dashboard/annotations/delete_service_spec.rb index 95825db6902..ec2bd3772bf 100644 --- a/spec/services/metrics/dashboard/annotations/delete_service_spec.rb +++ b/spec/services/metrics/dashboard/annotations/delete_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Metrics::Dashboard::Annotations::DeleteService do +RSpec.describe Metrics::Dashboard::Annotations::DeleteService do let(:user) { create(:user) } let(:service_instance) { described_class.new(user, annotation) } diff --git a/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb b/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb index 3d26ab2ede5..4a226fe386c 100644 --- a/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb +++ b/spec/services/metrics/dashboard/clone_dashboard_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_store_caching do +RSpec.describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_store_caching do include MetricsDashboardHelpers let_it_be(:user) { create(:user) } @@ -81,7 +81,22 @@ describe Metrics::Dashboard::CloneDashboardService, :use_clean_rails_memory_stor allow(::Gitlab::Metrics::Dashboard::Processor).to receive(:new).and_return(double(process: file_content_hash)) end - it_behaves_like 'valid dashboard cloning process', ::Metrics::Dashboard::SystemDashboardService::DASHBOARD_PATH, [::Gitlab::Metrics::Dashboard::Stages::CommonMetricsInserter, ::Gitlab::Metrics::Dashboard::Stages::CustomMetricsInserter, ::Gitlab::Metrics::Dashboard::Stages::Sorter] + it_behaves_like 'valid dashboard cloning process', ::Metrics::Dashboard::SystemDashboardService::DASHBOARD_PATH, + [ + ::Gitlab::Metrics::Dashboard::Stages::CommonMetricsInserter, + ::Gitlab::Metrics::Dashboard::Stages::CustomMetricsInserter, + ::Gitlab::Metrics::Dashboard::Stages::Sorter + ] + + it_behaves_like 'valid dashboard cloning process', ::Metrics::Dashboard::ClusterDashboardService::DASHBOARD_PATH, + [ + ::Gitlab::Metrics::Dashboard::Stages::CommonMetricsInserter, + ::Gitlab::Metrics::Dashboard::Stages::Sorter + ] + + it_behaves_like 'valid dashboard cloning process', + ::Metrics::Dashboard::SelfMonitoringDashboardService::DASHBOARD_PATH, + [::Gitlab::Metrics::Dashboard::Stages::CustomMetricsInserter] context 'selected branch already exists' do let(:branch) { 'existing_branch' } diff --git a/spec/services/metrics/dashboard/cluster_dashboard_service_spec.rb b/spec/services/metrics/dashboard/cluster_dashboard_service_spec.rb new file mode 100644 index 00000000000..f2e32d5eb35 --- /dev/null +++ b/spec/services/metrics/dashboard/cluster_dashboard_service_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Metrics::Dashboard::ClusterDashboardService, :use_clean_rails_memory_store_caching do + include MetricsDashboardHelpers + + let_it_be(:user) { create(:user) } + let_it_be(:cluster_project) { create(:cluster_project) } + let_it_be(:cluster) { cluster_project.cluster } + let_it_be(:project) { cluster_project.project } + + before do + project.add_maintainer(user) + end + + describe '.valid_params?' do + let(:params) { { cluster: cluster, embedded: 'false' } } + + subject { described_class.valid_params?(params) } + + it { is_expected.to be_truthy } + + context 'with matching dashboard_path' do + let(:params) { { dashboard_path: ::Metrics::Dashboard::ClusterDashboardService::DASHBOARD_PATH } } + + it { is_expected.to be_truthy } + end + + context 'missing cluster without dashboard_path' do + let(:params) { {} } + + it { is_expected.to be_falsey } + end + end + + describe '#get_dashboard' do + let(:service_params) { [project, user, { cluster: cluster, cluster_type: :project }] } + let(:service_call) { subject.get_dashboard } + + subject { described_class.new(*service_params) } + + it_behaves_like 'valid dashboard service response' + it_behaves_like 'caches the unprocessed dashboard for subsequent calls' + it_behaves_like 'refreshes cache when dashboard_version is changed' + + it_behaves_like 'dashboard_version contains SHA256 hash of dashboard file content' do + let(:dashboard_path) { described_class::DASHBOARD_PATH } + let(:dashboard_version) { subject.send(:dashboard_version) } + end + + context 'when called with a non-system dashboard' do + let(:dashboard_path) { 'garbage/dashboard/path' } + + # We want to always return the cluster dashboard. + it_behaves_like 'valid dashboard service response' + end + end +end diff --git a/spec/services/metrics/dashboard/cluster_metrics_embed_service_spec.rb b/spec/services/metrics/dashboard/cluster_metrics_embed_service_spec.rb new file mode 100644 index 00000000000..e80911d6265 --- /dev/null +++ b/spec/services/metrics/dashboard/cluster_metrics_embed_service_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Metrics::Dashboard::ClusterMetricsEmbedService, :use_clean_rails_memory_store_caching do + include MetricsDashboardHelpers + using RSpec::Parameterized::TableSyntax + + let_it_be(:user) { create(:user) } + let_it_be(:cluster_project) { create(:cluster_project) } + let_it_be(:cluster) { cluster_project.cluster } + let_it_be(:project) { cluster_project.project } + + before do + project.add_maintainer(user) + end + + describe '.valid_params?' do + let(:valid_params) { { cluster: 1, embedded: 'true', group: 'hello', title: 'world', y_label: 'countries' } } + + subject { described_class } + + it { expect(subject.valid_params?(valid_params)).to be_truthy } + + context 'missing all params' do + let(:params) { {} } + + it { expect(subject.valid_params?(params)).to be_falsy } + end + + [:cluster, :embedded, :group, :title, :y_label].each do |param_key| + it 'returns false with missing param' do + params = valid_params.except(param_key) + + expect(subject.valid_params?(params)).to be_falsy + end + end + end + + describe '#get_dashboard' do + let(:service_params) do + [ + project, + user, + { + cluster: cluster, + cluster_type: :project, + embedded: 'true', + group: 'Cluster Health', + title: 'CPU Usage', + y_label: 'CPU (cores)' + } + ] + end + let(:service_call) { described_class.new(*service_params).get_dashboard } + let(:panel_groups) { service_call[:dashboard][:panel_groups] } + let(:panel) { panel_groups.first[:panels].first } + + it_behaves_like 'valid embedded dashboard service response' + it_behaves_like 'caches the unprocessed dashboard for subsequent calls' + + it 'returns one panel' do + expect(panel_groups.size).to eq 1 + expect(panel_groups.first[:panels].size).to eq 1 + end + + it 'returns panel by title and y_label' do + expect(panel[:title]).to eq(service_params.last[:title]) + expect(panel[:y_label]).to eq(service_params.last[:y_label]) + end + end +end diff --git a/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb b/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb index 4966b83bbab..d4391ecb6b9 100644 --- a/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb +++ b/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb @@ -2,24 +2,31 @@ require 'spec_helper' -describe Metrics::Dashboard::CustomDashboardService, :use_clean_rails_memory_store_caching do +RSpec.describe Metrics::Dashboard::CustomDashboardService, :use_clean_rails_memory_store_caching do include MetricsDashboardHelpers let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:environment) { create(:environment, project: project) } + let(:dashboard_path) { '.gitlab/dashboards/test.yml' } + let(:service_params) { [project, user, { environment: environment, dashboard_path: dashboard_path }] } + + subject { described_class.new(*service_params) } + before do project.add_maintainer(user) end + describe '#raw_dashboard' do + let(:project) { project_with_dashboard(dashboard_path) } + + it_behaves_like '#raw_dashboard raises error if dashboard loading fails' + end + describe '#get_dashboard' do - let(:dashboard_path) { '.gitlab/dashboards/test.yml' } - let(:service_params) { [project, user, { environment: environment, dashboard_path: dashboard_path }] } let(:service_call) { subject.get_dashboard } - subject { described_class.new(*service_params) } - context 'when the dashboard does not exist' do it_behaves_like 'misconfigured dashboard service response', :not_found @@ -92,7 +99,8 @@ describe Metrics::Dashboard::CustomDashboardService, :use_clean_rails_memory_sto path: dashboard_path, display_name: 'test.yml', default: false, - system_dashboard: false + system_dashboard: false, + out_of_the_box_dashboard: false }] ) end diff --git a/spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb b/spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb index 1a9ddc87ab0..a5f7c2ab8ab 100644 --- a/spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb +++ b/spec/services/metrics/dashboard/custom_metric_embed_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Metrics::Dashboard::CustomMetricEmbedService do +RSpec.describe Metrics::Dashboard::CustomMetricEmbedService do include MetricsDashboardHelpers let_it_be(:project, reload: true) { build(:project) } diff --git a/spec/services/metrics/dashboard/default_embed_service_spec.rb b/spec/services/metrics/dashboard/default_embed_service_spec.rb index 8e32316433d..2ce10eac026 100644 --- a/spec/services/metrics/dashboard/default_embed_service_spec.rb +++ b/spec/services/metrics/dashboard/default_embed_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Metrics::Dashboard::DefaultEmbedService, :use_clean_rails_memory_store_caching do +RSpec.describe Metrics::Dashboard::DefaultEmbedService, :use_clean_rails_memory_store_caching do include MetricsDashboardHelpers let_it_be(:project) { build(:project) } diff --git a/spec/services/metrics/dashboard/dynamic_embed_service_spec.rb b/spec/services/metrics/dashboard/dynamic_embed_service_spec.rb index ee75284b4ce..72b356be60f 100644 --- a/spec/services/metrics/dashboard/dynamic_embed_service_spec.rb +++ b/spec/services/metrics/dashboard/dynamic_embed_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Metrics::Dashboard::DynamicEmbedService, :use_clean_rails_memory_store_caching do +RSpec.describe Metrics::Dashboard::DynamicEmbedService, :use_clean_rails_memory_store_caching do include MetricsDashboardHelpers let_it_be(:project) { build(:project) } diff --git a/spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb b/spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb index a66150be42c..29c941826b5 100644 --- a/spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb +++ b/spec/services/metrics/dashboard/gitlab_alert_embed_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Metrics::Dashboard::GitlabAlertEmbedService do +RSpec.describe Metrics::Dashboard::GitlabAlertEmbedService do include MetricsDashboardHelpers let_it_be(:alert) { create(:prometheus_alert) } diff --git a/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb b/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb index 3547e1f0f8c..ee3c55cb642 100644 --- a/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb +++ b/spec/services/metrics/dashboard/grafana_metric_embed_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Metrics::Dashboard::GrafanaMetricEmbedService do +RSpec.describe Metrics::Dashboard::GrafanaMetricEmbedService do include MetricsDashboardHelpers include ReactiveCachingHelpers include GrafanaApiHelpers @@ -182,7 +182,7 @@ describe Metrics::Dashboard::GrafanaMetricEmbedService do end end -describe Metrics::Dashboard::GrafanaUidParser do +RSpec.describe Metrics::Dashboard::GrafanaUidParser do let_it_be(:grafana_integration) { create(:grafana_integration) } let_it_be(:project) { grafana_integration.project } @@ -213,7 +213,7 @@ describe Metrics::Dashboard::GrafanaUidParser do end end -describe Metrics::Dashboard::DatasourceNameParser do +RSpec.describe Metrics::Dashboard::DatasourceNameParser do include GrafanaApiHelpers let(:grafana_url) { valid_grafana_dashboard_link('https://gitlab.grafana.net') } diff --git a/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb b/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb index 1e62a5504a9..ae0e38a04b2 100644 --- a/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb +++ b/spec/services/metrics/dashboard/pod_dashboard_service_spec.rb @@ -2,17 +2,26 @@ require 'spec_helper' -describe Metrics::Dashboard::PodDashboardService, :use_clean_rails_memory_store_caching do +RSpec.describe Metrics::Dashboard::PodDashboardService, :use_clean_rails_memory_store_caching do include MetricsDashboardHelpers let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:environment) { create(:environment, project: project) } + let(:dashboard_path) { described_class::DASHBOARD_PATH } + let(:service_params) { [project, user, { environment: environment, dashboard_path: dashboard_path }] } + before do project.add_maintainer(user) end + subject { described_class.new(*service_params) } + + describe '#raw_dashboard' do + it_behaves_like '#raw_dashboard raises error if dashboard loading fails' + end + describe '.valid_params?' do let(:params) { { dashboard_path: described_class::DASHBOARD_PATH } } @@ -34,14 +43,15 @@ describe Metrics::Dashboard::PodDashboardService, :use_clean_rails_memory_store_ end describe '#get_dashboard' do - let(:dashboard_path) { described_class::DASHBOARD_PATH } - let(:service_params) { [project, user, { environment: environment, dashboard_path: dashboard_path }] } let(:service_call) { subject.get_dashboard } - subject { described_class.new(*service_params) } - it_behaves_like 'valid dashboard service response' it_behaves_like 'caches the unprocessed dashboard for subsequent calls' + it_behaves_like 'refreshes cache when dashboard_version is changed' it_behaves_like 'updates gitlab_metrics_dashboard_processing_time_ms metric' + + it_behaves_like 'dashboard_version contains SHA256 hash of dashboard file content' do + let(:dashboard_version) { subject.send(:dashboard_version) } + end end end diff --git a/spec/services/metrics/dashboard/self_monitoring_dashboard_service_spec.rb b/spec/services/metrics/dashboard/self_monitoring_dashboard_service_spec.rb index 6c9a380a470..aea3e41a013 100644 --- a/spec/services/metrics/dashboard/self_monitoring_dashboard_service_spec.rb +++ b/spec/services/metrics/dashboard/self_monitoring_dashboard_service_spec.rb @@ -2,20 +2,29 @@ require 'spec_helper' -describe Metrics::Dashboard::SelfMonitoringDashboardService, :use_clean_rails_memory_store_caching do +RSpec.describe Metrics::Dashboard::SelfMonitoringDashboardService, :use_clean_rails_memory_store_caching do include MetricsDashboardHelpers let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:environment) { create(:environment, project: project) } + let(:service_params) { [project, user, { environment: environment }] } + before do project.add_maintainer(user) stub_application_setting(self_monitoring_project_id: project.id) end + subject do + described_class.new(service_params) + end + + describe '#raw_dashboard' do + it_behaves_like '#raw_dashboard raises error if dashboard loading fails' + end + describe '#get_dashboard' do - let(:service_params) { [project, user, { environment: environment }] } let(:service_call) { subject.get_dashboard } subject { described_class.new(*service_params) } @@ -23,7 +32,13 @@ describe Metrics::Dashboard::SelfMonitoringDashboardService, :use_clean_rails_me it_behaves_like 'valid dashboard service response' it_behaves_like 'raises error for users with insufficient permissions' it_behaves_like 'caches the unprocessed dashboard for subsequent calls' + it_behaves_like 'refreshes cache when dashboard_version is changed' it_behaves_like 'updates gitlab_metrics_dashboard_processing_time_ms metric' + + it_behaves_like 'dashboard_version contains SHA256 hash of dashboard file content' do + let(:dashboard_path) { described_class::DASHBOARD_PATH } + let(:dashboard_version) { subject.send(:dashboard_version) } + end end describe '.all_dashboard_paths' do @@ -35,7 +50,8 @@ describe Metrics::Dashboard::SelfMonitoringDashboardService, :use_clean_rails_me path: described_class::DASHBOARD_PATH, display_name: described_class::DASHBOARD_NAME, default: true, - system_dashboard: false + system_dashboard: false, + out_of_the_box_dashboard: true }] ) end diff --git a/spec/services/metrics/dashboard/system_dashboard_service_spec.rb b/spec/services/metrics/dashboard/system_dashboard_service_spec.rb index 7d58501ae3f..ced7c29b507 100644 --- a/spec/services/metrics/dashboard/system_dashboard_service_spec.rb +++ b/spec/services/metrics/dashboard/system_dashboard_service_spec.rb @@ -2,29 +2,39 @@ require 'spec_helper' -describe Metrics::Dashboard::SystemDashboardService, :use_clean_rails_memory_store_caching do +RSpec.describe Metrics::Dashboard::SystemDashboardService, :use_clean_rails_memory_store_caching do include MetricsDashboardHelpers let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:environment) { create(:environment, project: project) } + let(:dashboard_path) { described_class::DASHBOARD_PATH } + let(:service_params) { [project, user, { environment: environment, dashboard_path: dashboard_path }] } + + subject { described_class.new(*service_params) } + before do project.add_maintainer(user) end + describe '#raw_dashboard' do + it_behaves_like '#raw_dashboard raises error if dashboard loading fails' + end + describe '#get_dashboard' do - let(:dashboard_path) { described_class::DASHBOARD_PATH } - let(:service_params) { [project, user, { environment: environment, dashboard_path: dashboard_path }] } let(:service_call) { subject.get_dashboard } - subject { described_class.new(*service_params) } - it_behaves_like 'valid dashboard service response' it_behaves_like 'raises error for users with insufficient permissions' it_behaves_like 'caches the unprocessed dashboard for subsequent calls' + it_behaves_like 'refreshes cache when dashboard_version is changed' it_behaves_like 'updates gitlab_metrics_dashboard_processing_time_ms metric' + it_behaves_like 'dashboard_version contains SHA256 hash of dashboard file content' do + let(:dashboard_version) { subject.send(:dashboard_version) } + end + context 'when called with a non-system dashboard' do let(:dashboard_path) { 'garbage/dashboard/path' } @@ -42,7 +52,8 @@ describe Metrics::Dashboard::SystemDashboardService, :use_clean_rails_memory_sto path: described_class::DASHBOARD_PATH, display_name: described_class::DASHBOARD_NAME, default: true, - system_dashboard: true + system_dashboard: true, + out_of_the_box_dashboard: true }] ) end diff --git a/spec/services/metrics/dashboard/transient_embed_service_spec.rb b/spec/services/metrics/dashboard/transient_embed_service_spec.rb index 125fff7c23c..3fd0c97d909 100644 --- a/spec/services/metrics/dashboard/transient_embed_service_spec.rb +++ b/spec/services/metrics/dashboard/transient_embed_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Metrics::Dashboard::TransientEmbedService, :use_clean_rails_memory_store_caching do +RSpec.describe Metrics::Dashboard::TransientEmbedService, :use_clean_rails_memory_store_caching do let_it_be(:project) { build(:project) } let_it_be(:user) { create(:user) } let_it_be(:environment) { create(:environment, project: project) } diff --git a/spec/services/metrics/dashboard/update_dashboard_service_spec.rb b/spec/services/metrics/dashboard/update_dashboard_service_spec.rb index fce027688d9..148005480ea 100644 --- a/spec/services/metrics/dashboard/update_dashboard_service_spec.rb +++ b/spec/services/metrics/dashboard/update_dashboard_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Metrics::Dashboard::UpdateDashboardService, :use_clean_rails_memory_store_caching do +RSpec.describe Metrics::Dashboard::UpdateDashboardService, :use_clean_rails_memory_store_caching do include MetricsDashboardHelpers let_it_be(:user) { create(:user) } diff --git a/spec/services/metrics/sample_metrics_service_spec.rb b/spec/services/metrics/sample_metrics_service_spec.rb index 3b4f7cb8062..b94345500f0 100644 --- a/spec/services/metrics/sample_metrics_service_spec.rb +++ b/spec/services/metrics/sample_metrics_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Metrics::SampleMetricsService do +RSpec.describe Metrics::SampleMetricsService do describe 'query' do let(:range_start) { '2019-12-02T23:31:45.000Z' } let(:range_end) { '2019-12-03T00:01:45.000Z' } diff --git a/spec/services/metrics/users_starred_dashboards/create_service_spec.rb b/spec/services/metrics/users_starred_dashboards/create_service_spec.rb index eac4965ba44..910b556b8dd 100644 --- a/spec/services/metrics/users_starred_dashboards/create_service_spec.rb +++ b/spec/services/metrics/users_starred_dashboards/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Metrics::UsersStarredDashboards::CreateService do +RSpec.describe Metrics::UsersStarredDashboards::CreateService do let_it_be(:user) { create(:user) } let(:dashboard_path) { 'config/prometheus/common_metrics.yml' } let(:service_instance) { described_class.new(user, project, dashboard_path) } diff --git a/spec/services/metrics/users_starred_dashboards/delete_service_spec.rb b/spec/services/metrics/users_starred_dashboards/delete_service_spec.rb index 68a2fef5931..5cdffe681eb 100644 --- a/spec/services/metrics/users_starred_dashboards/delete_service_spec.rb +++ b/spec/services/metrics/users_starred_dashboards/delete_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Metrics::UsersStarredDashboards::DeleteService do +RSpec.describe Metrics::UsersStarredDashboards::DeleteService do subject(:service_instance) { described_class.new(user, project, dashboard_path) } let_it_be(:user) { create(:user) } diff --git a/spec/services/milestones/close_service_spec.rb b/spec/services/milestones/close_service_spec.rb index 55e705063b2..53751b40667 100644 --- a/spec/services/milestones/close_service_spec.rb +++ b/spec/services/milestones/close_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Milestones::CloseService do +RSpec.describe Milestones::CloseService do let(:user) { create(:user) } let(:project) { create(:project) } let(:milestone) { create(:milestone, title: "Milestone v1.2", project: project) } diff --git a/spec/services/milestones/closed_issues_count_service_spec.rb b/spec/services/milestones/closed_issues_count_service_spec.rb index b86eede2e22..a3865d08972 100644 --- a/spec/services/milestones/closed_issues_count_service_spec.rb +++ b/spec/services/milestones/closed_issues_count_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Milestones::ClosedIssuesCountService, :use_clean_rails_memory_store_caching do +RSpec.describe Milestones::ClosedIssuesCountService, :use_clean_rails_memory_store_caching do let(:project) { create(:project) } let(:milestone) { create(:milestone, project: project) } diff --git a/spec/services/milestones/create_service_spec.rb b/spec/services/milestones/create_service_spec.rb index 97f6e947539..93ca4ff653f 100644 --- a/spec/services/milestones/create_service_spec.rb +++ b/spec/services/milestones/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Milestones::CreateService do +RSpec.describe Milestones::CreateService do let(:project) { create(:project) } let(:user) { create(:user) } diff --git a/spec/services/milestones/destroy_service_spec.rb b/spec/services/milestones/destroy_service_spec.rb index 4f16421c39f..66c5c504c64 100644 --- a/spec/services/milestones/destroy_service_spec.rb +++ b/spec/services/milestones/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Milestones::DestroyService do +RSpec.describe Milestones::DestroyService do let(:user) { create(:user) } let(:project) { create(:project, :repository) } let(:milestone) { create(:milestone, title: 'Milestone v1.0', project: project) } diff --git a/spec/services/milestones/find_or_create_service_spec.rb b/spec/services/milestones/find_or_create_service_spec.rb index ae3def30982..1bcaf578441 100644 --- a/spec/services/milestones/find_or_create_service_spec.rb +++ b/spec/services/milestones/find_or_create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Milestones::FindOrCreateService do +RSpec.describe Milestones::FindOrCreateService do describe '#execute' do subject(:service) { described_class.new(project, user, params) } diff --git a/spec/services/milestones/issues_count_service_spec.rb b/spec/services/milestones/issues_count_service_spec.rb index 22aea884424..c944055e4e7 100644 --- a/spec/services/milestones/issues_count_service_spec.rb +++ b/spec/services/milestones/issues_count_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Milestones::IssuesCountService, :use_clean_rails_memory_store_caching do +RSpec.describe Milestones::IssuesCountService, :use_clean_rails_memory_store_caching do let(:project) { create(:project) } let(:milestone) { create(:milestone, project: project) } diff --git a/spec/services/milestones/promote_service_spec.rb b/spec/services/milestones/promote_service_spec.rb index fa893b86cdb..f0a34241c74 100644 --- a/spec/services/milestones/promote_service_spec.rb +++ b/spec/services/milestones/promote_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Milestones::PromoteService do +RSpec.describe Milestones::PromoteService do let(:group) { create(:group) } let(:project) { create(:project, namespace: group) } let(:user) { create(:user) } diff --git a/spec/services/milestones/transfer_service_spec.rb b/spec/services/milestones/transfer_service_spec.rb index 9f94d2d320b..4a626fe688a 100644 --- a/spec/services/milestones/transfer_service_spec.rb +++ b/spec/services/milestones/transfer_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Milestones::TransferService do +RSpec.describe Milestones::TransferService do describe '#execute' do subject(:service) { described_class.new(user, old_group, project) } diff --git a/spec/services/milestones/update_service_spec.rb b/spec/services/milestones/update_service_spec.rb index 3b91442c0ba..85fd89c11ac 100644 --- a/spec/services/milestones/update_service_spec.rb +++ b/spec/services/milestones/update_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Milestones::UpdateService do +RSpec.describe Milestones::UpdateService do let(:project) { create(:project) } let(:user) { build(:user) } let(:milestone) { create(:milestone, project: project) } diff --git a/spec/services/namespaces/check_storage_size_service_spec.rb b/spec/services/namespaces/check_storage_size_service_spec.rb deleted file mode 100644 index e192f897cf9..00000000000 --- a/spec/services/namespaces/check_storage_size_service_spec.rb +++ /dev/null @@ -1,165 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Namespaces::CheckStorageSizeService, '#execute' do - let(:namespace) { build_stubbed(:namespace) } - let(:user) { build(:user, namespace: namespace) } - let(:service) { described_class.new(namespace, user) } - let(:current_size) { 150.megabytes } - let(:limit) { 100.megabytes } - - subject(:response) { service.execute } - - before do - allow(namespace).to receive(:root_ancestor).and_return(namespace) - - root_storage_size = instance_double("RootStorageSize", - current_size: current_size, - limit: limit, - usage_ratio: limit == 0 ? 0 : current_size.to_f / limit.to_f, - above_size_limit?: current_size > limit - ) - - expect(Namespace::RootStorageSize).to receive(:new).and_return(root_storage_size) - end - - context 'feature flag' do - it 'is successful when disabled' do - stub_feature_flags(namespace_storage_limit: false) - - expect(response).to be_success - end - - it 'errors when enabled' do - stub_feature_flags(namespace_storage_limit: true) - - expect(response).to be_error - end - - it 'is successful when feature flag is activated for another namespace' do - stub_feature_flags(namespace_storage_limit: build(:namespace)) - - expect(response).to be_success - end - - it 'errors when feature flag is activated for the current namespace' do - stub_feature_flags(namespace_storage_limit: namespace) - - expect(response).to be_error - expect(response.message).to be_present - end - end - - context 'when limit is set to 0' do - let(:limit) { 0 } - - it 'is successful and has no payload' do - expect(response).to be_success - expect(response.payload).to be_empty - end - end - - context 'when current size is below threshold' do - let(:current_size) { 10.megabytes } - - it 'is successful and has no payload' do - expect(response).to be_success - expect(response.payload).to be_empty - end - end - - context 'when not admin of the namespace' do - let(:other_namespace) { build_stubbed(:namespace) } - - subject(:response) { described_class.new(other_namespace, user).execute } - - before do - allow(other_namespace).to receive(:root_ancestor).and_return(other_namespace) - end - - it 'errors and has no payload' do - expect(response).to be_error - expect(response.payload).to be_empty - end - end - - context 'when providing the child namespace' do - let(:namespace) { build_stubbed(:group) } - let(:child_namespace) { build_stubbed(:group, parent: namespace) } - - subject(:response) { described_class.new(child_namespace, user).execute } - - before do - allow(child_namespace).to receive(:root_ancestor).and_return(namespace) - namespace.add_owner(user) - end - - it 'uses the root namespace' do - expect(response).to be_error - end - end - - describe 'payload alert_level' do - subject { service.execute.payload[:alert_level] } - - context 'when above info threshold' do - let(:current_size) { 50.megabytes } - - it { is_expected.to eq(:info) } - end - - context 'when above warning threshold' do - let(:current_size) { 75.megabytes } - - it { is_expected.to eq(:warning) } - end - - context 'when above alert threshold' do - let(:current_size) { 95.megabytes } - - it { is_expected.to eq(:alert) } - end - - context 'when above error threshold' do - let(:current_size) { 100.megabytes } - - it { is_expected.to eq(:error) } - end - end - - describe 'payload explanation_message' do - subject(:response) { service.execute.payload[:explanation_message] } - - context 'when above limit' do - let(:current_size) { 110.megabytes } - - it 'returns message with read-only warning' do - expect(response).to include("#{namespace.name} is now read-only") - end - end - - context 'when below limit' do - let(:current_size) { 60.megabytes } - - it { is_expected.to include('If you reach 100% storage capacity') } - end - end - - describe 'payload usage_message' do - let(:current_size) { 60.megabytes } - - subject(:response) { service.execute.payload[:usage_message] } - - it 'returns current usage information' do - expect(response).to include("60 MB of 100 MB") - expect(response).to include("60%") - end - end - - describe 'payload root_namespace' do - subject(:response) { service.execute.payload[:root_namespace] } - - it { is_expected.to eq(namespace) } - end -end diff --git a/spec/services/namespaces/statistics_refresher_service_spec.rb b/spec/services/namespaces/statistics_refresher_service_spec.rb index 1fa0a794edd..d3379e843ec 100644 --- a/spec/services/namespaces/statistics_refresher_service_spec.rb +++ b/spec/services/namespaces/statistics_refresher_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Namespaces::StatisticsRefresherService, '#execute' do +RSpec.describe Namespaces::StatisticsRefresherService, '#execute' do let(:group) { create(:group) } let(:projects) { create_list(:project, 5, namespace: group) } let(:service) { described_class.new } diff --git a/spec/services/note_summary_spec.rb b/spec/services/note_summary_spec.rb index 038e0cdb703..38174748b19 100644 --- a/spec/services/note_summary_spec.rb +++ b/spec/services/note_summary_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe NoteSummary do +RSpec.describe NoteSummary do let(:project) { build(:project) } let(:noteable) { build(:issue) } let(:user) { build(:user) } diff --git a/spec/services/notes/build_service_spec.rb b/spec/services/notes/build_service_spec.rb index 984658cbd19..90548cf9a99 100644 --- a/spec/services/notes/build_service_spec.rb +++ b/spec/services/notes/build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Notes::BuildService do +RSpec.describe Notes::BuildService do let(:note) { create(:discussion_note_on_issue) } let(:project) { note.project } let(:author) { note.author } diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb index 39d6fd26e31..fd824621db7 100644 --- a/spec/services/notes/create_service_spec.rb +++ b/spec/services/notes/create_service_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' -describe Notes::CreateService do +RSpec.describe Notes::CreateService do let_it_be(:project) { create(:project, :repository) } let_it_be(:issue) { create(:issue, project: project) } let_it_be(:user) { create(:user) } let(:opts) do - { note: 'Awesome comment', noteable_type: 'Issue', noteable_id: issue.id } + { note: 'Awesome comment', noteable_type: 'Issue', noteable_id: issue.id, confidential: true } end describe '#execute' do diff --git a/spec/services/notes/destroy_service_spec.rb b/spec/services/notes/destroy_service_spec.rb index 258e5c68265..d1076f77cec 100644 --- a/spec/services/notes/destroy_service_spec.rb +++ b/spec/services/notes/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Notes::DestroyService do +RSpec.describe Notes::DestroyService do let_it_be(:project) { create(:project, :public) } let_it_be(:issue) { create(:issue, project: project) } let(:user) { issue.author } diff --git a/spec/services/notes/post_process_service_spec.rb b/spec/services/notes/post_process_service_spec.rb index d564cacd2d8..07ef08d36c4 100644 --- a/spec/services/notes/post_process_service_spec.rb +++ b/spec/services/notes/post_process_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Notes::PostProcessService do +RSpec.describe Notes::PostProcessService do let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let(:user) { create(:user) } diff --git a/spec/services/notes/quick_actions_service_spec.rb b/spec/services/notes/quick_actions_service_spec.rb index 7eea2a7afc6..d20824efaaa 100644 --- a/spec/services/notes/quick_actions_service_spec.rb +++ b/spec/services/notes/quick_actions_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Notes::QuickActionsService do +RSpec.describe Notes::QuickActionsService do shared_context 'note on noteable' do let(:project) { create(:project, :repository) } let(:maintainer) { create(:user).tap { |u| project.add_maintainer(u) } } diff --git a/spec/services/notes/render_service_spec.rb b/spec/services/notes/render_service_spec.rb index ad69721d876..09cd7dc572b 100644 --- a/spec/services/notes/render_service_spec.rb +++ b/spec/services/notes/render_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Notes::RenderService do +RSpec.describe Notes::RenderService do describe '#execute' do it 'renders a Note' do note = double(:note) diff --git a/spec/services/notes/resolve_service_spec.rb b/spec/services/notes/resolve_service_spec.rb index c98384c226e..1c5b308aed1 100644 --- a/spec/services/notes/resolve_service_spec.rb +++ b/spec/services/notes/resolve_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Notes::ResolveService do +RSpec.describe Notes::ResolveService do let(:merge_request) { create(:merge_request) } let(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: merge_request.project) } let(:user) { merge_request.author } diff --git a/spec/services/notes/update_service_spec.rb b/spec/services/notes/update_service_spec.rb index ab28e08ec83..70dea99de4a 100644 --- a/spec/services/notes/update_service_spec.rb +++ b/spec/services/notes/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Notes::UpdateService do +RSpec.describe Notes::UpdateService do let(:group) { create(:group, :public) } let(:project) { create(:project, :public, group: group) } let(:private_group) { create(:group, :private) } @@ -59,6 +59,45 @@ describe Notes::UpdateService do end end + context 'setting confidentiality' do + let(:opts) { { confidential: true } } + + context 'simple note' do + it 'updates the confidentiality' do + expect { update_note(opts) }.to change { note.reload.confidential }.from(nil).to(true) + end + end + + context 'discussion notes' do + let(:note) { create(:discussion_note, project: project, noteable: issue, author: user, note: "Old note #{user2.to_reference}") } + let!(:response_note_1) { create(:discussion_note, project: project, noteable: issue, in_reply_to: note) } + let!(:response_note_2) { create(:discussion_note, project: project, noteable: issue, in_reply_to: note, confidential: false) } + let!(:other_note) { create(:note, project: project, noteable: issue) } + + context 'when updating the root note' do + it 'updates the confidentiality of the root note and all the responses' do + update_note(opts) + + expect(note.reload.confidential).to be_truthy + expect(response_note_1.reload.confidential).to be_truthy + expect(response_note_2.reload.confidential).to be_truthy + expect(other_note.reload.confidential).to be_falsey + end + end + + context 'when updating one of the response notes' do + it 'updates only the confidentiality of the note that is being updated' do + Notes::UpdateService.new(project, user, opts).execute(response_note_1) + + expect(note.reload.confidential).to be_falsey + expect(response_note_1.reload.confidential).to be_truthy + expect(response_note_2.reload.confidential).to be_falsey + expect(other_note.reload.confidential).to be_falsey + end + end + end + end + context 'todos' do shared_examples 'does not update todos' do it 'keep todos' do diff --git a/spec/services/notification_recipients/build_service_spec.rb b/spec/services/notification_recipients/build_service_spec.rb index e203093623d..5c8add250c2 100644 --- a/spec/services/notification_recipients/build_service_spec.rb +++ b/spec/services/notification_recipients/build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe NotificationRecipients::BuildService do +RSpec.describe NotificationRecipients::BuildService do let(:service) { described_class } let(:assignee) { create(:user) } let(:project) { create(:project, :public) } diff --git a/spec/services/notification_recipients/builder/default_spec.rb b/spec/services/notification_recipients/builder/default_spec.rb index 307ca40248e..d25410235c2 100644 --- a/spec/services/notification_recipients/builder/default_spec.rb +++ b/spec/services/notification_recipients/builder/default_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe NotificationRecipients::Builder::Default do +RSpec.describe NotificationRecipients::Builder::Default do describe '#build!' do let_it_be(:group) { create(:group, :public) } let_it_be(:project) { create(:project, :public, group: group).tap { |p| p.add_developer(project_watcher) } } diff --git a/spec/services/notification_recipients/builder/new_note_spec.rb b/spec/services/notification_recipients/builder/new_note_spec.rb index f88e8b2dfb0..7d2a4f682c5 100644 --- a/spec/services/notification_recipients/builder/new_note_spec.rb +++ b/spec/services/notification_recipients/builder/new_note_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe NotificationRecipients::Builder::NewNote do +RSpec.describe NotificationRecipients::Builder::NewNote do describe '#notification_recipients' do let_it_be(:group) { create(:group, :public) } let_it_be(:project) { create(:project, :public, group: group) } diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 3c1c3e2dfc3..2fe7a46de4b 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe NotificationService, :mailer do +RSpec.describe NotificationService, :mailer do include EmailSpec::Matchers include ExternalAuthorizationServiceHelpers include NotificationHelpers @@ -343,6 +343,79 @@ describe NotificationService, :mailer do end end + context 'on service desk issue' do + before do + allow(Notify).to receive(:service_desk_new_note_email) + .with(Integer, Integer).and_return(mailer) + + allow(::Gitlab::IncomingEmail).to receive(:enabled?) { true } + allow(::Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true } + end + + let(:subject) { NotificationService.new } + let(:mailer) { double(deliver_later: true) } + + def should_email! + expect(Notify).to receive(:service_desk_new_note_email) + .with(issue.id, note.id) + end + + def should_not_email! + expect(Notify).not_to receive(:service_desk_new_note_email) + end + + def execute! + subject.new_note(note) + end + + def self.it_should_email! + it 'sends the email' do + should_email! + execute! + end + end + + def self.it_should_not_email! + it 'doesn\'t send the email' do + should_not_email! + execute! + end + end + + let(:issue) { create(:issue, author: User.support_bot) } + let(:project) { issue.project } + let(:note) { create(:note, noteable: issue, project: project) } + + context 'a non-service-desk issue' do + it_should_not_email! + end + + context 'a service-desk issue' do + before do + issue.update!(service_desk_reply_to: 'service.desk@example.com') + project.update!(service_desk_enabled: true) + end + + it_should_email! + + context 'where the project has disabled the feature' do + before do + project.update(service_desk_enabled: false) + end + + it_should_not_email! + end + + context 'when the support bot has unsubscribed' do + before do + issue.unsubscribe(User.support_bot, project) + end + + it_should_not_email! + end + end + end + describe 'new note on issue in project that belongs to a group' do before do note.project.namespace_id = group.id @@ -1950,6 +2023,26 @@ describe NotificationService, :mailer do let(:notification_trigger) { notification.resolve_all_discussions(merge_request, @u_disabled) } end end + + describe '#merge_when_pipeline_succeeds' do + it 'send notification that merge will happen when pipeline succeeds' do + notification.merge_when_pipeline_succeeds(merge_request, assignee) + should_email(merge_request.author) + should_email(@u_watcher) + should_email(@subscriber) + end + + it_behaves_like 'participating notifications' do + let(:participant) { create(:user, username: 'user-participant') } + let(:issuable) { merge_request } + let(:notification_trigger) { notification.merge_when_pipeline_succeeds(merge_request, @u_disabled) } + end + + it_behaves_like 'project emails are disabled' do + let(:notification_target) { merge_request } + let(:notification_trigger) { notification.merge_when_pipeline_succeeds(merge_request, @u_disabled) } + end + end end describe 'Projects', :deliver_mails_inline do diff --git a/spec/services/packages/composer/composer_json_service_spec.rb b/spec/services/packages/composer/composer_json_service_spec.rb new file mode 100644 index 00000000000..3996fcea679 --- /dev/null +++ b/spec/services/packages/composer/composer_json_service_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::Composer::ComposerJsonService do + describe '#execute' do + let(:branch) { project.repository.find_branch('master') } + let(:target) { branch.target } + + subject { described_class.new(project, target).execute } + + context 'with an existing file' do + let(:project) { create(:project, :custom_repo, files: { 'composer.json' => json } ) } + + context 'with a valid file' do + let(:json) { '{ "name": "package-name"}' } + + it 'returns the parsed json' do + expect(subject).to eq({ 'name' => 'package-name' }) + end + end + + context 'with an invalid file' do + let(:json) { '{ name": "package-name"}' } + + it 'raises an error' do + expect { subject }.to raise_error(/Invalid/) + end + end + end + + context 'without the composer.json file' do + let(:project) { create(:project, :repository) } + + it 'raises an error' do + expect { subject }.to raise_error(/not found/) + end + end + end +end diff --git a/spec/services/packages/composer/create_package_service_spec.rb b/spec/services/packages/composer/create_package_service_spec.rb new file mode 100644 index 00000000000..3f9da31cf6e --- /dev/null +++ b/spec/services/packages/composer/create_package_service_spec.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::Composer::CreatePackageService do + include PackagesManagerApiSpecHelpers + + let_it_be(:package_name) { 'composer-package-name' } + let_it_be(:json) { { name: package_name }.to_json } + let_it_be(:project) { create(:project, :custom_repo, files: { 'composer.json' => json } ) } + let_it_be(:user) { create(:user) } + let(:params) do + { + branch: branch, + tag: tag + } + end + + describe '#execute' do + let(:tag) { nil } + let(:branch) { nil } + + subject { described_class.new(project, user, params).execute } + + let(:created_package) { Packages::Package.composer.last } + + context 'without an existing package' do + context 'with a branch' do + let(:branch) { project.repository.find_branch('master') } + + it 'creates the package' do + expect { subject } + .to change { Packages::Package.composer.count }.by(1) + .and change { Packages::Composer::Metadatum.count }.by(1) + + expect(created_package.name).to eq package_name + expect(created_package.version).to eq 'dev-master' + expect(created_package.composer_metadatum.target_sha).to eq branch.target + expect(created_package.composer_metadatum.composer_json.to_json).to eq json + end + end + + context 'with a tag' do + let(:tag) { project.repository.find_tag('v1.2.3') } + + before do + project.repository.add_tag(user, 'v1.2.3', 'master') + end + + it 'creates the package' do + expect { subject } + .to change { Packages::Package.composer.count }.by(1) + .and change { Packages::Composer::Metadatum.count }.by(1) + + expect(created_package.name).to eq package_name + expect(created_package.version).to eq '1.2.3' + end + end + end + + context 'with an existing package' do + let(:branch) { project.repository.find_branch('master') } + + context 'belonging to the same project' do + before do + described_class.new(project, user, params).execute + end + + it 'does not create a new package' do + expect { subject } + .to change { Packages::Package.composer.count }.by(0) + .and change { Packages::Composer::Metadatum.count }.by(0) + end + end + + context 'belonging to another project' do + let(:other_project) { create(:project) } + let!(:other_package) { create(:composer_package, name: package_name, version: 'dev-master', project: other_project) } + + it 'fails with an error' do + expect { subject } + .to raise_error(/is already taken/) + end + end + + context 'same name but of different type' do + let(:other_project) { create(:project) } + let!(:other_package) { create(:package, name: package_name, version: 'dev-master', project: other_project) } + + it 'creates the package' do + expect { subject } + .to change { Packages::Package.composer.count }.by(1) + .and change { Packages::Composer::Metadatum.count }.by(1) + end + end + end + end +end diff --git a/spec/services/packages/composer/version_parser_service_spec.rb b/spec/services/packages/composer/version_parser_service_spec.rb new file mode 100644 index 00000000000..904c75ab0a1 --- /dev/null +++ b/spec/services/packages/composer/version_parser_service_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::Composer::VersionParserService do + let_it_be(:params) { {} } + + describe '#execute' do + using RSpec::Parameterized::TableSyntax + + subject { described_class.new(tag_name: tagname, branch_name: branchname).execute } + + where(:tagname, :branchname, :expected_version) do + nil | 'master' | 'dev-master' + nil | 'my-feature' | 'dev-my-feature' + nil | 'v1' | '1.x-dev' + nil | 'v1.x' | '1.x-dev' + nil | 'v1.7.x' | '1.7.x-dev' + nil | 'v1.7' | '1.7.x-dev' + nil | '1.7.x' | '1.7.x-dev' + 'v1.0.0' | nil | '1.0.0' + 'v1.0' | nil | '1.0' + '1.0' | nil | '1.0' + '1.0.2' | nil | '1.0.2' + '1.0.2-beta2' | nil | '1.0.2-beta2' + end + + with_them do + it { is_expected.to eq expected_version } + end + end +end diff --git a/spec/services/packages/conan/create_package_file_service_spec.rb b/spec/services/packages/conan/create_package_file_service_spec.rb new file mode 100644 index 00000000000..0e9cbba5fc1 --- /dev/null +++ b/spec/services/packages/conan/create_package_file_service_spec.rb @@ -0,0 +1,130 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::Conan::CreatePackageFileService do + include WorkhorseHelpers + + let_it_be(:package) { create(:conan_package) } + + describe '#execute' do + let(:file_name) { 'foo.tgz' } + + subject { described_class.new(package, file, params) } + + shared_examples 'a valid package_file' do + let(:params) do + { + file_name: file_name, + 'file.md5': '12345', + 'file.sha1': '54321', + 'file.size': '128', + 'file.type': 'txt', + recipe_revision: '0', + package_revision: '0', + conan_package_reference: '123456789', + conan_file_type: :package_file + }.with_indifferent_access + end + + it 'creates a new package file' do + package_file = subject.execute + + expect(package_file).to be_valid + expect(package_file.file_name).to eq(file_name) + expect(package_file.file_md5).to eq('12345') + expect(package_file.size).to eq(128) + expect(package_file.conan_file_metadatum).to be_valid + expect(package_file.conan_file_metadatum.recipe_revision).to eq('0') + expect(package_file.conan_file_metadatum.package_revision).to eq('0') + expect(package_file.conan_file_metadatum.conan_package_reference).to eq('123456789') + expect(package_file.conan_file_metadatum.conan_file_type).to eq('package_file') + expect(package_file.file.read).to eq('content') + end + end + + shared_examples 'a valid recipe_file' do + let(:params) do + { + file_name: file_name, + 'file.md5': '12345', + 'file.sha1': '54321', + 'file.size': '128', + 'file.type': 'txt', + recipe_revision: '0', + conan_file_type: :recipe_file + }.with_indifferent_access + end + + it 'creates a new recipe file' do + package_file = subject.execute + + expect(package_file).to be_valid + expect(package_file.file_name).to eq(file_name) + expect(package_file.file_md5).to eq('12345') + expect(package_file.size).to eq(128) + expect(package_file.conan_file_metadatum).to be_valid + expect(package_file.conan_file_metadatum.recipe_revision).to eq('0') + expect(package_file.conan_file_metadatum.package_revision).to be_nil + expect(package_file.conan_file_metadatum.conan_package_reference).to be_nil + expect(package_file.conan_file_metadatum.conan_file_type).to eq('recipe_file') + expect(package_file.file.read).to eq('content') + end + end + + context 'with temp file' do + let!(:file) do + upload_path = ::Packages::PackageFileUploader.workhorse_local_upload_path + file_path = upload_path + '/' + file_name + + FileUtils.mkdir_p(upload_path) + File.write(file_path, 'content') + + UploadedFile.new(file_path, filename: File.basename(file_path)) + end + + before do + allow_any_instance_of(Packages::PackageFileUploader).to receive(:size).and_return(128) + end + + it_behaves_like 'a valid package_file' + it_behaves_like 'a valid recipe_file' + end + + context 'with remote file' do + let!(:fog_connection) do + stub_package_file_object_storage(direct_upload: true) + end + + before do + allow_any_instance_of(Packages::PackageFileUploader).to receive(:size).and_return(128) + end + + let(:tmp_object) do + fog_connection.directories.new(key: 'packages').files.create( + key: "tmp/uploads/#{file_name}", + body: 'content' + ) + end + + let(:file) { fog_to_uploaded_file(tmp_object) } + + it_behaves_like 'a valid package_file' + it_behaves_like 'a valid recipe_file' + end + + context 'file is missing' do + let(:file) { nil } + let(:params) do + { + file_name: file_name, + recipe_revision: '0', + conan_file_type: :recipe_file + } + end + + it 'raises an error' do + expect { subject.execute }.to raise_error(ActiveRecord::RecordInvalid) + end + end + end +end diff --git a/spec/services/packages/conan/create_package_service_spec.rb b/spec/services/packages/conan/create_package_service_spec.rb new file mode 100644 index 00000000000..f8068f6e57b --- /dev/null +++ b/spec/services/packages/conan/create_package_service_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::Conan::CreatePackageService do + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } + + subject { described_class.new(project, user, params) } + + describe '#execute' do + context 'valid params' do + let(:params) do + { + package_name: 'my-pkg', + package_version: '1.0.0', + package_username: ::Packages::Conan::Metadatum.package_username_from(full_path: project.full_path), + package_channel: 'stable' + } + end + + it 'creates a new package' do + package = subject.execute + + expect(package).to be_valid + expect(package.name).to eq(params[:package_name]) + expect(package.version).to eq(params[:package_version]) + expect(package.package_type).to eq('conan') + expect(package.conan_metadatum.package_username).to eq(params[:package_username]) + expect(package.conan_metadatum.package_channel).to eq(params[:package_channel]) + end + end + + context 'invalid params' do + let(:params) do + { + package_name: 'my-pkg', + package_version: '1.0.0', + package_username: 'foo/bar', + package_channel: 'stable' + } + end + + it 'fails' do + expect { subject.execute }.to raise_exception(ActiveRecord::RecordInvalid) + end + end + end +end diff --git a/spec/services/packages/conan/search_service_spec.rb b/spec/services/packages/conan/search_service_spec.rb new file mode 100644 index 00000000000..39d284ee088 --- /dev/null +++ b/spec/services/packages/conan/search_service_spec.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Packages::Conan::SearchService do + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, :public) } + let!(:conan_package) { create(:conan_package, project: project) } + let!(:conan_package2) { create(:conan_package, project: project) } + + subject { described_class.new(user, query: query) } + + before do + project.add_developer(user) + end + + describe '#execute' do + context 'with wildcard' do + let(:partial_name) { conan_package.name.first[0, 3] } + let(:query) { "#{partial_name}*" } + + it 'makes a wildcard query' do + result = subject.execute + + expect(result.status).to eq :success + expect(result.payload).to eq(results: [conan_package.conan_recipe, conan_package2.conan_recipe]) + end + end + + context 'with only wildcard' do + let(:query) { '*' } + + it 'returns empty' do + result = subject.execute + + expect(result.status).to eq :success + expect(result.payload).to eq(results: []) + end + end + + context 'with no wildcard' do + let(:query) { conan_package.name } + + it 'makes a search using the beginning of the recipe' do + result = subject.execute + + expect(result.status).to eq :success + expect(result.payload).to eq(results: [conan_package.conan_recipe]) + end + end + + context 'with full recipe match' do + let(:query) { conan_package.conan_recipe } + + it 'makes an exact search' do + result = subject.execute + + expect(result.status).to eq :success + expect(result.payload).to eq(results: [conan_package.conan_recipe]) + end + end + + context 'with malicious query' do + let(:query) { 'DROP TABLE foo;' } + + it 'returns empty' do + result = subject.execute + + expect(result.status).to eq :success + expect(result.payload).to eq(results: []) + end + end + end +end diff --git a/spec/services/packages/create_dependency_service_spec.rb b/spec/services/packages/create_dependency_service_spec.rb new file mode 100644 index 00000000000..00e5e5c6d96 --- /dev/null +++ b/spec/services/packages/create_dependency_service_spec.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::CreateDependencyService do + describe '#execute' do + let_it_be(:namespace) {create(:namespace)} + let_it_be(:version) { '1.0.1' } + let_it_be(:package_name) { "@#{namespace.path}/my-app".freeze } + + context 'when packages are published' do + let(:json_file) { 'packages/npm/payload.json' } + let(:params) do + Gitlab::Json.parse(fixture_file(json_file) + .gsub('@root/npm-test', package_name) + .gsub('1.0.1', version)) + .with_indifferent_access + end + let(:package_version) { params[:versions].each_key.first } + let(:dependencies) { params[:versions][package_version] } + let(:package) { create(:npm_package) } + let(:dependency_names) { package.dependency_links.flat_map(&:dependency).map(&:name).sort } + let(:dependency_link_types) { package.dependency_links.map(&:dependency_type).sort } + + subject { described_class.new(package, dependencies).execute } + + it 'creates dependencies and links' do + expect(Packages::Dependency) + .to receive(:ids_for_package_names_and_version_patterns) + .once + .and_call_original + + expect { subject } + .to change { Packages::Dependency.count }.by(1) + .and change { Packages::DependencyLink.count }.by(1) + expect(dependency_names).to match_array(%w(express)) + expect(dependency_link_types).to match_array(%w(dependencies)) + end + + context 'with repeated packages' do + let(:json_file) { 'packages/npm/payload_with_duplicated_packages.json' } + + it 'creates dependencies and links' do + expect(Packages::Dependency) + .to receive(:ids_for_package_names_and_version_patterns) + .exactly(4).times + .and_call_original + + expect { subject } + .to change { Packages::Dependency.count }.by(4) + .and change { Packages::DependencyLink.count }.by(6) + expect(dependency_names).to match_array(%w(d3 d3 d3 dagre-d3 dagre-d3 express)) + expect(dependency_link_types).to match_array(%w(bundleDependencies dependencies dependencies devDependencies devDependencies peerDependencies)) + end + end + + context 'with dependencies bulk insert conflicts' do + let_it_be(:rows) { [{ name: 'express', version_pattern: '^4.16.4' }] } + + it 'creates dependences and links' do + original_bulk_insert = ::Gitlab::Database.method(:bulk_insert) + expect(::Gitlab::Database) + .to receive(:bulk_insert) do |table, rows, return_ids: false, disable_quote: [], on_conflict: nil| + call_count = table == Packages::Dependency.table_name ? 2 : 1 + call_count.times { original_bulk_insert.call(table, rows, return_ids: return_ids, disable_quote: disable_quote, on_conflict: on_conflict) } + end.twice + expect(Packages::Dependency) + .to receive(:ids_for_package_names_and_version_patterns) + .twice + .and_call_original + + expect { subject } + .to change { Packages::Dependency.count }.by(1) + .and change { Packages::DependencyLink.count }.by(1) + expect(dependency_names).to match_array(%w(express)) + expect(dependency_link_types).to match_array(%w(dependencies)) + end + end + + context 'with existing dependencies' do + let(:other_package) { create(:npm_package) } + + before do + described_class.new(other_package, dependencies).execute + end + + it 'reuses them' do + expect { subject } + .to not_change { Packages::Dependency.count } + .and change { Packages::DependencyLink.count }.by(1) + end + end + + context 'with a dependency not described with a hash' do + let(:invalid_dependencies) { dependencies.tap { |d| d['bundleDependencies'] = false } } + + subject { described_class.new(package, invalid_dependencies).execute } + + it 'creates dependencies and links' do + expect(Packages::Dependency) + .to receive(:ids_for_package_names_and_version_patterns) + .once + .and_call_original + + expect { subject } + .to change { Packages::Dependency.count }.by(1) + .and change { Packages::DependencyLink.count }.by(1) + expect(dependency_names).to match_array(%w(express)) + expect(dependency_link_types).to match_array(%w(dependencies)) + end + end + end + end +end diff --git a/spec/services/packages/create_package_file_service_spec.rb b/spec/services/packages/create_package_file_service_spec.rb new file mode 100644 index 00000000000..93dde54916a --- /dev/null +++ b/spec/services/packages/create_package_file_service_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::CreatePackageFileService do + let(:package) { create(:maven_package) } + + describe '#execute' do + context 'with valid params' do + let(:params) do + { + file: Tempfile.new, + file_name: 'foo.jar' + } + end + + it 'creates a new package file' do + package_file = described_class.new(package, params).execute + + expect(package_file).to be_valid + expect(package_file.file_name).to eq('foo.jar') + end + end + + context 'file is missing' do + let(:params) do + { + file_name: 'foo.jar' + } + end + + it 'raises an error' do + service = described_class.new(package, params) + + expect { service.execute }.to raise_error(ActiveRecord::RecordInvalid) + end + end + end +end diff --git a/spec/services/packages/maven/create_package_service_spec.rb b/spec/services/packages/maven/create_package_service_spec.rb new file mode 100644 index 00000000000..bfdf62008ba --- /dev/null +++ b/spec/services/packages/maven/create_package_service_spec.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::Maven::CreatePackageService do + let(:project) { create(:project) } + let(:user) { create(:user) } + let(:app_name) { 'my-app' } + let(:version) { '1.0-SNAPSHOT' } + let(:path) { "my/company/app/#{app_name}" } + let(:path_with_version) { "#{path}/#{version}" } + + describe '#execute' do + subject(:package) { described_class.new(project, user, params).execute } + + context 'with version' do + let(:params) do + { + path: path_with_version, + name: path, + version: version + } + end + + it 'creates a new package with metadatum' do + expect(package).to be_valid + expect(package.name).to eq(path) + expect(package.version).to eq(version) + expect(package.package_type).to eq('maven') + expect(package.maven_metadatum).to be_valid + expect(package.maven_metadatum.path).to eq(path_with_version) + expect(package.maven_metadatum.app_group).to eq('my.company.app') + expect(package.maven_metadatum.app_name).to eq(app_name) + expect(package.maven_metadatum.app_version).to eq(version) + end + + it_behaves_like 'assigns build to package' + end + + context 'without version' do + let(:params) do + { + path: path, + name: path, + version: nil + } + end + + it 'creates a new package with metadatum' do + package = described_class.new(project, user, params).execute + + expect(package).to be_valid + expect(package.name).to eq(path) + expect(package.version).to be nil + expect(package.maven_metadatum).to be_valid + expect(package.maven_metadatum.path).to eq(path) + expect(package.maven_metadatum.app_group).to eq('my.company.app') + expect(package.maven_metadatum.app_name).to eq(app_name) + expect(package.maven_metadatum.app_version).to be nil + end + end + + context 'path is missing' do + let(:params) do + { + name: path, + version: version + } + end + + it 'raises an error' do + service = described_class.new(project, user, params) + + expect { service.execute }.to raise_error(ActiveRecord::RecordInvalid) + end + end + end +end diff --git a/spec/services/packages/maven/find_or_create_package_service_spec.rb b/spec/services/packages/maven/find_or_create_package_service_spec.rb new file mode 100644 index 00000000000..c9441324216 --- /dev/null +++ b/spec/services/packages/maven/find_or_create_package_service_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::Maven::FindOrCreatePackageService do + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } + let_it_be(:app_name) { 'my-app' } + let_it_be(:version) { '1.0-SNAPSHOT' } + let_it_be(:path) { "my/company/app/#{app_name}" } + let_it_be(:path_with_version) { "#{path}/#{version}" } + let_it_be(:params) do + { + path: path_with_version, + name: path, + version: version + } + end + + describe '#execute' do + subject { described_class.new(project, user, params).execute } + + context 'without any existing package' do + it 'creates a package' do + expect { subject }.to change { Packages::Package.count }.by(1) + end + end + + context 'with an existing package' do + let_it_be(:existing_package) { create(:maven_package, name: path, version: version, project: project) } + + it { is_expected.to eq existing_package } + it "doesn't create a new package" do + expect { subject } + .to not_change { Packages::Package.count } + end + end + end +end diff --git a/spec/services/packages/npm/create_package_service_spec.rb b/spec/services/packages/npm/create_package_service_spec.rb new file mode 100644 index 00000000000..25bbbf82bec --- /dev/null +++ b/spec/services/packages/npm/create_package_service_spec.rb @@ -0,0 +1,96 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::Npm::CreatePackageService do + let(:namespace) {create(:namespace)} + let(:project) { create(:project, namespace: namespace) } + let(:user) { create(:user) } + let(:version) { '1.0.1' } + + let(:params) do + Gitlab::Json.parse(fixture_file('packages/npm/payload.json') + .gsub('@root/npm-test', package_name) + .gsub('1.0.1', version)).with_indifferent_access + .merge!(override) + end + let(:override) { {} } + let(:package_name) { "@#{namespace.path}/my-app".freeze } + + subject { described_class.new(project, user, params).execute } + + shared_examples 'valid package' do + it 'creates a package' do + expect { subject } + .to change { Packages::Package.count }.by(1) + .and change { Packages::Package.npm.count }.by(1) + .and change { Packages::Tag.count }.by(1) + end + + it { is_expected.to be_valid } + + it 'creates a package with name and version' do + package = subject + + expect(package.name).to eq(package_name) + expect(package.version).to eq(version) + end + + it { expect(subject.name).to eq(package_name) } + it { expect(subject.version).to eq(version) } + end + + describe '#execute' do + context 'scoped package' do + it_behaves_like 'valid package' + + it_behaves_like 'assigns build to package' + end + + context 'invalid package name' do + let(:package_name) { "@#{namespace.path}/my-group/my-app".freeze } + + it { expect { subject }.to raise_error(ActiveRecord::RecordInvalid) } + end + + context 'package already exists' do + let(:package_name) { "@#{namespace.path}/my_package" } + let!(:existing_package) { create(:npm_package, project: project, name: package_name, version: '1.0.1') } + + it { expect(subject[:http_status]).to eq 403 } + it { expect(subject[:message]).to be 'Package already exists.' } + end + + context 'with incorrect namespace' do + let(:package_name) { '@my_other_namespace/my-app' } + + it 'raises a RecordInvalid error' do + expect { subject }.to raise_error(ActiveRecord::RecordInvalid) + end + end + + context 'with empty versions' do + let(:override) { { versions: {} } } + + it { expect(subject[:http_status]).to eq 400 } + it { expect(subject[:message]).to eq 'Version is empty.' } + end + + context 'with invalid versions' do + using RSpec::Parameterized::TableSyntax + + where(:version) do + [ + '1', + '1.2', + '1./2.3', + '../../../../../1.2.3', + '%2e%2e%2f1.2.3' + ] + end + + with_them do + it { expect { subject }.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Version is invalid') } + end + end + end +end diff --git a/spec/services/packages/npm/create_tag_service_spec.rb b/spec/services/packages/npm/create_tag_service_spec.rb new file mode 100644 index 00000000000..e7a784068fa --- /dev/null +++ b/spec/services/packages/npm/create_tag_service_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::Npm::CreateTagService do + let(:package) { create(:npm_package) } + let(:tag_name) { 'test-tag' } + + describe '#execute' do + subject { described_class.new(package, tag_name).execute } + + shared_examples 'it creates the tag' do + it { expect { subject }.to change { Packages::Tag.count }.by(1) } + it { expect(subject.name).to eq(tag_name) } + it 'adds tag to the package' do + tag = subject + expect(package.reload.tags).to match_array([tag]) + end + end + + context 'with no existing tag name' do + it_behaves_like 'it creates the tag' + end + + context 'with exisiting tag name' do + let!(:package_tag2) { create(:packages_tag, package: package2, name: tag_name) } + + context 'on package with different name' do + let!(:package2) { create(:npm_package, project: package.project) } + + it_behaves_like 'it creates the tag' + end + + context 'on different package type' do + let!(:package2) { create(:conan_package, project: package.project, name: 'conan_package_name', version: package.version) } + + it_behaves_like 'it creates the tag' + end + + context 'on same package with different version' do + let!(:package2) { create(:npm_package, project: package.project, name: package.name, version: '5.0.0-testing') } + + it { expect { subject }.to not_change { Packages::Tag.count } } + it { expect(subject.name).to eq(tag_name) } + + it 'adds tag to the package' do + tag = subject + expect(package.reload.tags).to match_array([tag]) + expect(package2.reload.tags).to be_empty + end + end + end + end +end diff --git a/spec/services/packages/nuget/create_dependency_service_spec.rb b/spec/services/packages/nuget/create_dependency_service_spec.rb new file mode 100644 index 00000000000..268c8837e25 --- /dev/null +++ b/spec/services/packages/nuget/create_dependency_service_spec.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::Nuget::CreateDependencyService do + let_it_be(:package, reload: true) { create(:nuget_package) } + + describe '#execute' do + RSpec.shared_examples 'creating dependencies, links and nuget metadata for' do |expected_dependency_names, dependency_count, dependency_link_count| + let(:dependencies_with_metadata) { dependencies.select { |dep| dep[:target_framework].present? } } + + it 'creates dependencies, links and nuget metadata' do + expect { subject } + .to change { Packages::Dependency.count }.by(dependency_count) + .and change { Packages::DependencyLink.count }.by(dependency_link_count) + .and change { Packages::Nuget::DependencyLinkMetadatum.count }.by(dependencies_with_metadata.size) + expect(expected_dependency_names).to contain_exactly(*dependency_names) + expect(package.dependency_links.map(&:dependency_type).uniq).to contain_exactly('dependencies') + + dependencies_with_metadata.each do |dependency| + name = dependency[:name] + version_pattern = service.send(:version_or_empty_string, dependency[:version]) + metadatum = package.dependency_links.joins(:dependency) + .find_by(packages_dependencies: { name: name, version_pattern: version_pattern }) + .nuget_metadatum + expect(metadatum.target_framework).to eq dependency[:target_framework] + end + end + end + + let_it_be(:dependencies) do + [ + { name: 'Moqi', version: '2.5.6' }, + { name: 'Castle.Core' }, + { name: 'Test.Dependency', version: '2.3.7', target_framework: '.NETStandard2.0' }, + { name: 'Newtonsoft.Json', version: '12.0.3', target_framework: '.NETStandard2.0' } + ] + end + + let(:dependency_names) { package.dependency_links.flat_map(&:dependency).map(&:name) } + let(:service) { described_class.new(package, dependencies) } + + subject { service.execute } + + it_behaves_like 'creating dependencies, links and nuget metadata for', %w(Castle.Core Moqi Newtonsoft.Json Test.Dependency), 4, 4 + + context 'with existing dependencies' do + let_it_be(:exisiting_dependency) { create(:packages_dependency, name: 'Moqi', version_pattern: '2.5.6') } + + it_behaves_like 'creating dependencies, links and nuget metadata for', %w(Castle.Core Moqi Newtonsoft.Json Test.Dependency), 3, 4 + end + + context 'with dependencies with no target framework' do + let_it_be(:dependencies) do + [ + { name: 'Moqi', version: '2.5.6' }, + { name: 'Castle.Core' }, + { name: 'Test.Dependency', version: '2.3.7' }, + { name: 'Newtonsoft.Json', version: '12.0.3' } + ] + end + + it_behaves_like 'creating dependencies, links and nuget metadata for', %w(Castle.Core Moqi Newtonsoft.Json Test.Dependency), 4, 4 + end + + context 'with empty dependencies' do + let_it_be(:dependencies) { [] } + + it 'is a no op' do + expect(service).not_to receive(:create_dependency_links) + expect(service).not_to receive(:create_dependency_link_metadata) + + subject + end + end + end +end diff --git a/spec/services/packages/nuget/create_package_service_spec.rb b/spec/services/packages/nuget/create_package_service_spec.rb new file mode 100644 index 00000000000..1579b42d9ad --- /dev/null +++ b/spec/services/packages/nuget/create_package_service_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::Nuget::CreatePackageService do + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } + let_it_be(:params) { {} } + + describe '#execute' do + subject { described_class.new(project, user, params).execute } + + it 'creates the package' do + expect { subject }.to change { Packages::Package.count }.by(1) + package = Packages::Package.last + + expect(package).to be_valid + expect(package.name).to eq(Packages::Nuget::CreatePackageService::TEMPORARY_PACKAGE_NAME) + expect(package.version).to start_with(Packages::Nuget::CreatePackageService::PACKAGE_VERSION) + expect(package.package_type).to eq('nuget') + end + + it 'can create two packages in a row' do + expect { subject }.to change { Packages::Package.count }.by(1) + expect { described_class.new(project, user, params).execute }.to change { Packages::Package.count }.by(1) + + package = Packages::Package.last + + expect(package).to be_valid + expect(package.name).to eq(Packages::Nuget::CreatePackageService::TEMPORARY_PACKAGE_NAME) + expect(package.version).to start_with(Packages::Nuget::CreatePackageService::PACKAGE_VERSION) + expect(package.package_type).to eq('nuget') + end + end +end diff --git a/spec/services/packages/nuget/metadata_extraction_service_spec.rb b/spec/services/packages/nuget/metadata_extraction_service_spec.rb new file mode 100644 index 00000000000..39fc0f9e6a1 --- /dev/null +++ b/spec/services/packages/nuget/metadata_extraction_service_spec.rb @@ -0,0 +1,106 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Packages::Nuget::MetadataExtractionService do + let(:package_file) { create(:nuget_package).package_files.first } + let(:service) { described_class.new(package_file.id) } + + describe '#execute' do + subject { service.execute } + + context 'with valid package file id' do + expected_metadata = { + package_name: 'DummyProject.DummyPackage', + package_version: '1.0.0', + package_dependencies: [ + { + name: 'Newtonsoft.Json', + target_framework: '.NETCoreApp3.0', + version: '12.0.3' + } + ], + package_tags: [] + } + + it { is_expected.to eq(expected_metadata) } + end + + context 'with nuspec file' do + before do + allow(service).to receive(:nuspec_file).and_return(fixture_file(nuspec_filepath)) + end + + context 'with dependencies' do + let(:nuspec_filepath) { 'packages/nuget/with_dependencies.nuspec' } + + it { is_expected.to have_key(:package_dependencies) } + + it 'extracts dependencies' do + dependencies = subject[:package_dependencies] + + expect(dependencies).to include(name: 'Moqi', version: '2.5.6') + expect(dependencies).to include(name: 'Castle.Core') + expect(dependencies).to include(name: 'Test.Dependency', version: '2.3.7', target_framework: '.NETStandard2.0') + expect(dependencies).to include(name: 'Newtonsoft.Json', version: '12.0.3', target_framework: '.NETStandard2.0') + end + end + + context 'with a nuspec file with metadata' do + let(:nuspec_filepath) { 'packages/nuget/with_metadata.nuspec' } + + it { expect(subject[:package_tags].sort).to eq(%w(foo bar test tag1 tag2 tag3 tag4 tag5).sort) } + end + end + + context 'with a nuspec file with metadata' do + let_it_be(:nuspec_filepath) { 'packages/nuget/with_metadata.nuspec' } + + before do + allow(service).to receive(:nuspec_file).and_return(fixture_file(nuspec_filepath)) + end + + it { expect(subject[:license_url]).to eq('https://opensource.org/licenses/MIT') } + it { expect(subject[:project_url]).to eq('https://gitlab.com/gitlab-org/gitlab') } + it { expect(subject[:icon_url]).to eq('https://opensource.org/files/osi_keyhole_300X300_90ppi_0.png') } + end + + context 'with invalid package file id' do + let(:package_file) { OpenStruct.new(id: 555) } + + it { expect { subject }.to raise_error(::Packages::Nuget::MetadataExtractionService::ExtractionError, 'invalid package file') } + end + + context 'linked to a non nuget package' do + before do + package_file.package.maven! + end + + it { expect { subject }.to raise_error(::Packages::Nuget::MetadataExtractionService::ExtractionError, 'invalid package file') } + end + + context 'with a 0 byte package file id' do + before do + allow_any_instance_of(Packages::PackageFileUploader).to receive(:size).and_return(0) + end + + it { expect { subject }.to raise_error(::Packages::Nuget::MetadataExtractionService::ExtractionError, 'invalid package file') } + end + + context 'without the nuspec file' do + before do + allow_any_instance_of(Zip::File).to receive(:glob).and_return([]) + end + + it { expect { subject }.to raise_error(::Packages::Nuget::MetadataExtractionService::ExtractionError, 'nuspec file not found') } + end + + context 'with a too big nuspec file' do + before do + allow_any_instance_of(Zip::File).to receive(:glob).and_return([OpenStruct.new(size: 6.megabytes)]) + end + + it { expect { subject }.to raise_error(::Packages::Nuget::MetadataExtractionService::ExtractionError, 'nuspec file too big') } + end + end +end diff --git a/spec/services/packages/nuget/search_service_spec.rb b/spec/services/packages/nuget/search_service_spec.rb new file mode 100644 index 00000000000..d163e7087e4 --- /dev/null +++ b/spec/services/packages/nuget/search_service_spec.rb @@ -0,0 +1,116 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::Nuget::SearchService do + let_it_be(:project) { create(:project) } + let_it_be(:package_a) { create(:nuget_package, project: project, name: 'DummyPackageA') } + let_it_be(:packages_b) { create_list(:nuget_package, 5, project: project, name: 'DummyPackageB') } + let_it_be(:packages_c) { create_list(:nuget_package, 5, project: project, name: 'DummyPackageC') } + let_it_be(:package_d) { create(:nuget_package, project: project, name: 'FooBarD') } + let_it_be(:other_package_a) { create(:nuget_package, name: 'DummyPackageA') } + let_it_be(:other_package_a) { create(:nuget_package, name: 'DummyPackageB') } + let(:search_term) { 'ummy' } + let(:per_page) { 5 } + let(:padding) { 0 } + let(:include_prerelease_versions) { true } + let(:options) { { include_prerelease_versions: include_prerelease_versions, per_page: per_page, padding: padding } } + + describe '#execute' do + subject { described_class.new(project, search_term, options).execute } + + it { expect_search_results 3, package_a, packages_b, packages_c } + + context 'with a smaller per page count' do + let(:per_page) { 2 } + + it { expect_search_results 3, package_a, packages_b } + end + + context 'with 0 per page count' do + let(:per_page) { 0 } + + it { expect_search_results 3, [] } + end + + context 'with a negative per page count' do + let(:per_page) { -1 } + + it { expect { subject }.to raise_error(ArgumentError, 'negative per_page') } + end + + context 'with a padding' do + let(:padding) { 2 } + + it { expect_search_results 3, packages_c } + end + + context 'with a too big padding' do + let(:padding) { 5 } + + it { expect_search_results 3, [] } + end + + context 'with a negative padding' do + let(:padding) { -1 } + + it { expect { subject }.to raise_error(ArgumentError, 'negative padding') } + end + + context 'with search term' do + let(:search_term) { 'umm' } + + it { expect_search_results 3, package_a, packages_b, packages_c } + end + + context 'with nil search term' do + let(:search_term) { nil } + + it { expect_search_results 4, package_a, packages_b, packages_c, package_d } + end + + context 'with empty search term' do + let(:search_term) { '' } + + it { expect_search_results 4, package_a, packages_b, packages_c, package_d } + end + + context 'with prefix search term' do + let(:search_term) { 'dummy' } + + it { expect_search_results 3, package_a, packages_b, packages_c } + end + + context 'with suffix search term' do + let(:search_term) { 'packagec' } + + it { expect_search_results 1, packages_c } + end + + context 'with pre release packages' do + let_it_be(:package_e) { create(:nuget_package, project: project, name: 'DummyPackageE', version: '3.2.1-alpha') } + + context 'including them' do + it { expect_search_results 4, package_a, packages_b, packages_c, package_e } + end + + context 'excluding them' do + let(:include_prerelease_versions) { false } + + it { expect_search_results 3, package_a, packages_b, packages_c } + + context 'when mixed with release versions' do + let_it_be(:package_e_release) { create(:nuget_package, project: project, name: 'DummyPackageE', version: '3.2.1') } + + it { expect_search_results 4, package_a, packages_b, packages_c, package_e_release } + end + end + end + + def expect_search_results(total_count, *results) + search = subject + + expect(search.total_count).to eq total_count + expect(search.results).to match_array(Array.wrap(results).flatten) + end + end +end diff --git a/spec/services/packages/nuget/sync_metadatum_service_spec.rb b/spec/services/packages/nuget/sync_metadatum_service_spec.rb new file mode 100644 index 00000000000..32093c48b76 --- /dev/null +++ b/spec/services/packages/nuget/sync_metadatum_service_spec.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Packages::Nuget::SyncMetadatumService do + let_it_be(:package, reload: true) { create(:nuget_package) } + let_it_be(:metadata) do + { + project_url: 'https://test.org/test', + license_url: 'https://test.org/MIT', + icon_url: 'https://test.org/icon.png' + } + end + + let(:service) { described_class.new(package, metadata) } + let(:nuget_metadatum) { package.nuget_metadatum } + + describe '#execute' do + subject { service.execute } + + RSpec.shared_examples 'saving metadatum attributes' do + it 'saves nuget metadatum' do + subject + + metadata.each do |attribute, expected_value| + expect(nuget_metadatum.send(attribute)).to eq(expected_value) + end + end + end + + it 'creates a nuget metadatum' do + expect { subject } + .to change { package.nuget_metadatum.present? }.from(false).to(true) + end + + it_behaves_like 'saving metadatum attributes' + + context 'with exisiting nuget metadatum' do + let_it_be(:package) { create(:nuget_package, :with_metadatum) } + + it 'does not create a nuget metadatum' do + expect { subject }.to change { ::Packages::Nuget::Metadatum.count }.by(0) + end + + it_behaves_like 'saving metadatum attributes' + + context 'with empty metadata' do + let_it_be(:metadata) { {} } + + it 'destroys the nuget metadatum' do + expect { subject } + .to change { package.reload.nuget_metadatum.present? }.from(true).to(false) + end + end + end + end +end diff --git a/spec/services/packages/nuget/update_package_from_metadata_service_spec.rb b/spec/services/packages/nuget/update_package_from_metadata_service_spec.rb new file mode 100644 index 00000000000..b7c780c1ee2 --- /dev/null +++ b/spec/services/packages/nuget/update_package_from_metadata_service_spec.rb @@ -0,0 +1,237 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Packages::Nuget::UpdatePackageFromMetadataService, :clean_gitlab_redis_shared_state do + include ExclusiveLeaseHelpers + + let(:package) { create(:nuget_package) } + let(:package_file) { package.package_files.first } + let(:service) { described_class.new(package_file) } + let(:package_name) { 'DummyProject.DummyPackage' } + let(:package_version) { '1.0.0' } + let(:package_file_name) { 'dummyproject.dummypackage.1.0.0.nupkg' } + + RSpec.shared_examples 'raising an' do |error_class| + it "raises an #{error_class}" do + expect { subject }.to raise_error(error_class) + end + end + + describe '#execute' do + subject { service.execute } + + before do + stub_package_file_object_storage(enabled: true, direct_upload: true) + end + + RSpec.shared_examples 'taking the lease' do + before do + allow(service).to receive(:lease_release?).and_return(false) + end + + it 'takes the lease' do + expect(service).to receive(:try_obtain_lease).and_call_original + + subject + + expect(service.exclusive_lease.exists?).to be_truthy + end + end + + RSpec.shared_examples 'not updating the package if the lease is taken' do + context 'without obtaining the exclusive lease' do + let(:lease_key) { "packages:nuget:update_package_from_metadata_service:package:#{package_id}" } + let(:metadata) { { package_name: package_name, package_version: package_version } } + let(:package_from_package_file) { package_file.package } + + before do + stub_exclusive_lease_taken(lease_key, timeout: 1.hour) + # to allow the above stub, we need to stub the metadata function as the + # original implementation will try to get an exclusive lease on the + # file in object storage + allow(service).to receive(:metadata).and_return(metadata) + end + + it 'does not update the package' do + expect(service).to receive(:try_obtain_lease).and_call_original + + expect { subject } + .to change { ::Packages::Package.count }.by(0) + .and change { Packages::DependencyLink.count }.by(0) + expect(package_file.reload.file_name).not_to eq(package_file_name) + expect(package_file.package.reload.name).not_to eq(package_name) + expect(package_file.package.version).not_to eq(package_version) + end + end + end + + context 'with no existing package' do + let(:package_id) { package.id } + + it 'updates package and package file' do + expect { subject } + .to change { ::Packages::Package.count }.by(1) + .and change { Packages::Dependency.count }.by(1) + .and change { Packages::DependencyLink.count }.by(1) + .and change { ::Packages::Nuget::Metadatum.count }.by(0) + + expect(package.reload.name).to eq(package_name) + expect(package.version).to eq(package_version) + expect(package_file.reload.file_name).to eq(package_file_name) + # hard reset needed to properly reload package_file.file + expect(Packages::PackageFile.find(package_file.id).file.size).not_to eq 0 + end + + it_behaves_like 'taking the lease' + + it_behaves_like 'not updating the package if the lease is taken' + end + + context 'with existing package' do + let!(:existing_package) { create(:nuget_package, project: package.project, name: package_name, version: package_version) } + let(:package_id) { existing_package.id } + + it 'link existing package and updates package file' do + expect(service).to receive(:try_obtain_lease).and_call_original + + expect { subject } + .to change { ::Packages::Package.count }.by(-1) + .and change { Packages::Dependency.count }.by(0) + .and change { Packages::DependencyLink.count }.by(0) + .and change { Packages::Nuget::DependencyLinkMetadatum.count }.by(0) + .and change { ::Packages::Nuget::Metadatum.count }.by(0) + expect(package_file.reload.file_name).to eq(package_file_name) + expect(package_file.package).to eq(existing_package) + end + + it_behaves_like 'taking the lease' + + it_behaves_like 'not updating the package if the lease is taken' + end + + context 'with a nuspec file with metadata' do + let(:nuspec_filepath) { 'packages/nuget/with_metadata.nuspec' } + let(:expected_tags) { %w(foo bar test tag1 tag2 tag3 tag4 tag5) } + + before do + allow_any_instance_of(Packages::Nuget::MetadataExtractionService) + .to receive(:nuspec_file) + .and_return(fixture_file(nuspec_filepath)) + end + + it 'creates tags' do + expect(service).to receive(:try_obtain_lease).and_call_original + expect { subject }.to change { ::Packages::Tag.count }.by(8) + expect(package.reload.tags.map(&:name)).to contain_exactly(*expected_tags) + end + + context 'with existing package and tags' do + let!(:existing_package) { create(:nuget_package, project: package.project, name: 'DummyProject.WithMetadata', version: '1.2.3') } + let!(:tag1) { create(:packages_tag, package: existing_package, name: 'tag1') } + let!(:tag2) { create(:packages_tag, package: existing_package, name: 'tag2') } + let!(:tag3) { create(:packages_tag, package: existing_package, name: 'tag_not_in_metadata') } + + it 'creates tags and deletes those not in metadata' do + expect(service).to receive(:try_obtain_lease).and_call_original + expect { subject }.to change { ::Packages::Tag.count }.by(5) + expect(existing_package.tags.map(&:name)).to contain_exactly(*expected_tags) + end + end + + it 'creates nuget metadatum' do + expect { subject } + .to change { ::Packages::Package.count }.by(1) + .and change { ::Packages::Nuget::Metadatum.count }.by(1) + + metadatum = package_file.reload.package.nuget_metadatum + expect(metadatum.license_url).to eq('https://opensource.org/licenses/MIT') + expect(metadatum.project_url).to eq('https://gitlab.com/gitlab-org/gitlab') + expect(metadatum.icon_url).to eq('https://opensource.org/files/osi_keyhole_300X300_90ppi_0.png') + end + + context 'with too long url' do + let_it_be(:too_long_url) { "http://localhost/#{'bananas' * 50}" } + + let(:metadata) { { package_name: package_name, package_version: package_version, license_url: too_long_url } } + + before do + allow(service).to receive(:metadata).and_return(metadata) + end + + it_behaves_like 'raising an', ::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError + end + end + + context 'with nuspec file with dependencies' do + let(:nuspec_filepath) { 'packages/nuget/with_dependencies.nuspec' } + let(:package_name) { 'Test.Package' } + let(:package_version) { '3.5.2' } + let(:package_file_name) { 'test.package.3.5.2.nupkg' } + + before do + allow_any_instance_of(Packages::Nuget::MetadataExtractionService) + .to receive(:nuspec_file) + .and_return(fixture_file(nuspec_filepath)) + end + + it 'updates package and package file' do + expect { subject } + .to change { ::Packages::Package.count }.by(1) + .and change { Packages::Dependency.count }.by(4) + .and change { Packages::DependencyLink.count }.by(4) + .and change { Packages::Nuget::DependencyLinkMetadatum.count }.by(2) + + expect(package.reload.name).to eq(package_name) + expect(package.version).to eq(package_version) + expect(package_file.reload.file_name).to eq(package_file_name) + # hard reset needed to properly reload package_file.file + expect(Packages::PackageFile.find(package_file.id).file.size).not_to eq 0 + end + end + + context 'with package file not containing a nuspec file' do + before do + allow_any_instance_of(Zip::File).to receive(:glob).and_return([]) + end + + it_behaves_like 'raising an', ::Packages::Nuget::MetadataExtractionService::ExtractionError + end + + context 'with package file with a blank package name' do + before do + allow(service).to receive(:package_name).and_return('') + end + + it_behaves_like 'raising an', ::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError + end + + context 'with package file with a blank package version' do + before do + allow(service).to receive(:package_version).and_return('') + end + + it_behaves_like 'raising an', ::Packages::Nuget::UpdatePackageFromMetadataService::InvalidMetadataError + end + + context 'with an invalid package version' do + invalid_versions = [ + '555', + '1.2', + '1./2.3', + '../../../../../1.2.3', + '%2e%2e%2f1.2.3' + ] + + invalid_versions.each do |invalid_version| + it "raises an error for version #{invalid_version}" do + allow(service).to receive(:package_version).and_return(invalid_version) + + expect { subject }.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Version is invalid') + expect(package_file.file_name).not_to include(invalid_version) + expect(package_file.file.file.path).not_to include(invalid_version) + end + end + end + end +end diff --git a/spec/services/packages/pypi/create_package_service_spec.rb b/spec/services/packages/pypi/create_package_service_spec.rb new file mode 100644 index 00000000000..250b43d1f75 --- /dev/null +++ b/spec/services/packages/pypi/create_package_service_spec.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::Pypi::CreatePackageService do + include PackagesManagerApiSpecHelpers + + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } + let_it_be(:params) do + { + name: 'foo', + version: '1.0', + content: temp_file('foo.tgz'), + requires_python: '>=2.7', + sha256_digest: '123', + md5_digest: '567' + } + end + + describe '#execute' do + subject { described_class.new(project, user, params).execute } + + let(:created_package) { Packages::Package.pypi.last } + + context 'without an existing package' do + it 'creates the package' do + expect { subject }.to change { Packages::Package.pypi.count }.by(1) + + expect(created_package.name).to eq 'foo' + expect(created_package.version).to eq '1.0' + + expect(created_package.pypi_metadatum.required_python).to eq '>=2.7' + expect(created_package.package_files.size).to eq 1 + expect(created_package.package_files.first.file_name).to eq 'foo.tgz' + expect(created_package.package_files.first.file_sha256).to eq '123' + expect(created_package.package_files.first.file_md5).to eq '567' + end + end + + context 'with an existing package' do + before do + described_class.new(project, user, params).execute + end + + context 'with an existing file' do + before do + params[:content] = temp_file('foo.tgz') + params[:sha256_digest] = 'abc' + params[:md5_digest] = 'def' + end + + it 'replaces the file' do + expect { subject } + .to change { Packages::Package.pypi.count }.by(0) + .and change { Packages::PackageFile.count }.by(1) + + expect(created_package.package_files.size).to eq 2 + expect(created_package.package_files.first.file_name).to eq 'foo.tgz' + expect(created_package.package_files.first.file_sha256).to eq '123' + expect(created_package.package_files.first.file_md5).to eq '567' + expect(created_package.package_files.last.file_name).to eq 'foo.tgz' + expect(created_package.package_files.last.file_sha256).to eq 'abc' + expect(created_package.package_files.last.file_md5).to eq 'def' + end + end + + context 'without an existing file' do + before do + params[:content] = temp_file('another.tgz') + end + + it 'adds the file' do + expect { subject } + .to change { Packages::Package.pypi.count }.by(0) + .and change { Packages::PackageFile.count }.by(1) + + expect(created_package.package_files.size).to eq 2 + expect(created_package.package_files.map(&:file_name).sort).to eq ['another.tgz', 'foo.tgz'] + end + end + end + end +end diff --git a/spec/services/packages/remove_tag_service_spec.rb b/spec/services/packages/remove_tag_service_spec.rb new file mode 100644 index 00000000000..084635824e5 --- /dev/null +++ b/spec/services/packages/remove_tag_service_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::RemoveTagService do + let!(:package_tag) { create(:packages_tag) } + + describe '#execute' do + subject { described_class.new(package_tag).execute } + + context 'with existing tag' do + it { expect { subject }.to change { Packages::Tag.count }.by(-1) } + end + + context 'with nil' do + subject { described_class.new(nil) } + + it { expect { subject }.to raise_error(ArgumentError) } + end + end +end diff --git a/spec/services/packages/update_tags_service_spec.rb b/spec/services/packages/update_tags_service_spec.rb new file mode 100644 index 00000000000..4a122d1c718 --- /dev/null +++ b/spec/services/packages/update_tags_service_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Packages::UpdateTagsService do + let_it_be(:package, reload: true) { create(:nuget_package) } + + let(:tags) { %w(test-tag tag1 tag2 tag3) } + let(:service) { described_class.new(package, tags) } + + describe '#execute' do + subject { service.execute } + + RSpec.shared_examples 'updating tags' do |tags_count| + it 'updates a tag' do + expect { subject }.to change { Packages::Tag.count }.by(tags_count) + expect(package.reload.tags.map(&:name)).to contain_exactly(*tags) + end + end + + it_behaves_like 'updating tags', 4 + + context 'with an existing tag' do + before do + create(:packages_tag, package: package2, name: 'test-tag') + end + + context 'on the same package' do + let_it_be(:package2) { package } + + it_behaves_like 'updating tags', 3 + + context 'with different name' do + before do + create(:packages_tag, package: package2, name: 'to_be_destroyed') + end + + it_behaves_like 'updating tags', 2 + end + end + + context 'on a different package' do + let_it_be(:package2) { create(:nuget_package) } + + it_behaves_like 'updating tags', 4 + end + end + + context 'with empty tags' do + let(:tags) { [] } + + it 'is a no op' do + expect(package).not_to receive(:tags) + expect(::Gitlab::Database).not_to receive(:bulk_insert) + + subject + end + end + end +end diff --git a/spec/services/pages/delete_services_spec.rb b/spec/services/pages/delete_services_spec.rb index c253f294e80..f6d4694b4dd 100644 --- a/spec/services/pages/delete_services_spec.rb +++ b/spec/services/pages/delete_services_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Pages::DeleteService do +RSpec.describe Pages::DeleteService do let_it_be(:project) { create(:project, path: "my.project")} let_it_be(:admin) { create(:admin) } let_it_be(:domain) { create(:pages_domain, project: project) } diff --git a/spec/services/pages_domains/create_acme_order_service_spec.rb b/spec/services/pages_domains/create_acme_order_service_spec.rb index d59aa9b979e..35b2cc56973 100644 --- a/spec/services/pages_domains/create_acme_order_service_spec.rb +++ b/spec/services/pages_domains/create_acme_order_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe PagesDomains::CreateAcmeOrderService do +RSpec.describe PagesDomains::CreateAcmeOrderService do include LetsEncryptHelpers let(:pages_domain) { create(:pages_domain) } diff --git a/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb b/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb index 22fcc6b9a79..4d489d7fe4b 100644 --- a/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb +++ b/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe PagesDomains::ObtainLetsEncryptCertificateService do +RSpec.describe PagesDomains::ObtainLetsEncryptCertificateService do include LetsEncryptHelpers let(:pages_domain) { create(:pages_domain, :without_certificate, :without_key) } diff --git a/spec/services/pages_domains/retry_acme_order_service_spec.rb b/spec/services/pages_domains/retry_acme_order_service_spec.rb index 0185f10864c..601de24e766 100644 --- a/spec/services/pages_domains/retry_acme_order_service_spec.rb +++ b/spec/services/pages_domains/retry_acme_order_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe PagesDomains::RetryAcmeOrderService do +RSpec.describe PagesDomains::RetryAcmeOrderService do let(:domain) { create(:pages_domain, auto_ssl_enabled: true, auto_ssl_failed: true) } let(:service) { described_class.new(domain) } diff --git a/spec/services/personal_access_tokens/create_service_spec.rb b/spec/services/personal_access_tokens/create_service_spec.rb index 9190434b96a..475ade95948 100644 --- a/spec/services/personal_access_tokens/create_service_spec.rb +++ b/spec/services/personal_access_tokens/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe PersonalAccessTokens::CreateService do +RSpec.describe PersonalAccessTokens::CreateService do describe '#execute' do context 'with valid params' do it 'creates personal access token record' do diff --git a/spec/services/personal_access_tokens/last_used_service_spec.rb b/spec/services/personal_access_tokens/last_used_service_spec.rb new file mode 100644 index 00000000000..6fc74e27dd9 --- /dev/null +++ b/spec/services/personal_access_tokens/last_used_service_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe PersonalAccessTokens::LastUsedService do + describe '#execute' do + subject { described_class.new(personal_access_token).execute } + + context 'when the personal access token has not been used recently' do + let_it_be(:personal_access_token) { create(:personal_access_token, last_used_at: 1.year.ago) } + + it 'updates the last_used_at timestamp' do + expect { subject }.to change { personal_access_token.last_used_at } + end + + it 'does not run on read-only GitLab instances' do + allow(::Gitlab::Database).to receive(:read_only?).and_return(true) + + expect { subject }.not_to change { personal_access_token.last_used_at } + end + end + + context 'when the personal access token has been used recently' do + let_it_be(:personal_access_token) { create(:personal_access_token, last_used_at: 1.minute.ago) } + + it 'does not update the last_used_at timestamp' do + expect { subject }.not_to change { personal_access_token.last_used_at } + end + end + + context 'when the last_used_at timestamp is nil' do + let_it_be(:personal_access_token) { create(:personal_access_token, last_used_at: nil) } + + it 'updates the last_used_at timestamp' do + expect { subject }.to change { personal_access_token.last_used_at } + end + end + + context 'when not a personal access token' do + let_it_be(:personal_access_token) { create(:oauth_access_token) } + + it 'does not execute' do + expect(subject).to be_nil + end + end + end +end diff --git a/spec/services/pod_logs/base_service_spec.rb b/spec/services/pod_logs/base_service_spec.rb index bc4989b59d9..6f7731fda3a 100644 --- a/spec/services/pod_logs/base_service_spec.rb +++ b/spec/services/pod_logs/base_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ::PodLogs::BaseService do +RSpec.describe ::PodLogs::BaseService do include KubernetesHelpers let_it_be(:cluster) { create(:cluster, :provided_by_gcp, environment_scope: '*') } diff --git a/spec/services/pod_logs/elasticsearch_service_spec.rb b/spec/services/pod_logs/elasticsearch_service_spec.rb index 8060d07461a..9431e47c6f2 100644 --- a/spec/services/pod_logs/elasticsearch_service_spec.rb +++ b/spec/services/pod_logs/elasticsearch_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ::PodLogs::ElasticsearchService do +RSpec.describe ::PodLogs::ElasticsearchService do let_it_be(:cluster) { create(:cluster, :provided_by_gcp, environment_scope: '*') } let(:namespace) { 'autodevops-deploy-9-production' } diff --git a/spec/services/pod_logs/kubernetes_service_spec.rb b/spec/services/pod_logs/kubernetes_service_spec.rb index a1f7645323b..3e31ff15c1b 100644 --- a/spec/services/pod_logs/kubernetes_service_spec.rb +++ b/spec/services/pod_logs/kubernetes_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ::PodLogs::KubernetesService do +RSpec.describe ::PodLogs::KubernetesService do include KubernetesHelpers let_it_be(:cluster) { create(:cluster, :provided_by_gcp, environment_scope: '*') } diff --git a/spec/services/post_receive_service_spec.rb b/spec/services/post_receive_service_spec.rb index 25f4122f134..c726e1851a7 100644 --- a/spec/services/post_receive_service_spec.rb +++ b/spec/services/post_receive_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe PostReceiveService do +RSpec.describe PostReceiveService do include Gitlab::Routing let_it_be(:user) { create(:user) } @@ -166,41 +166,6 @@ describe PostReceiveService do expect(subject).to include(build_alert_message(message)) end end - - context 'storage size limit alerts' do - let(:check_storage_size_response) { ServiceResponse.success } - - before do - expect_next_instance_of(Namespaces::CheckStorageSizeService, project.namespace, user) do |check_storage_size_service| - expect(check_storage_size_service).to receive(:execute).and_return(check_storage_size_response) - end - end - - context 'when there is no payload' do - it 'adds no alert' do - expect(subject.size).to eq(1) - end - end - - context 'when there is payload' do - let(:check_storage_size_response) do - ServiceResponse.success( - payload: { - alert_level: :info, - usage_message: "Usage", - explanation_message: "Explanation" - } - ) - end - - it 'adds an alert' do - response = subject - - expect(response.size).to eq(2) - expect(response).to include(build_alert_message("##### INFO #####\nUsage\nExplanation")) - end - end - end end context 'with PersonalSnippet' do diff --git a/spec/services/preview_markdown_service_spec.rb b/spec/services/preview_markdown_service_spec.rb index d25e9958831..2509d1300b3 100644 --- a/spec/services/preview_markdown_service_spec.rb +++ b/spec/services/preview_markdown_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe PreviewMarkdownService do +RSpec.describe PreviewMarkdownService do let(:user) { create(:user) } let(:project) { create(:project, :repository) } diff --git a/spec/services/projects/after_import_service_spec.rb b/spec/services/projects/after_import_service_spec.rb index 82f654cea10..a109348ea19 100644 --- a/spec/services/projects/after_import_service_spec.rb +++ b/spec/services/projects/after_import_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::AfterImportService do +RSpec.describe Projects::AfterImportService do include GitHelpers subject { described_class.new(project) } @@ -72,6 +72,26 @@ describe Projects::AfterImportService do end end + context 'when housekeeping service lease is taken' do + let(:exception) { Projects::HousekeepingService::LeaseTaken.new } + + it 'logs the error message' do + allow_next_instance_of(Projects::HousekeepingService) do |instance| + expect(instance).to receive(:execute).and_raise(exception) + end + + expect(Gitlab::Import::Logger).to receive(:info).with( + { + message: 'Project housekeeping failed', + project_full_path: project.full_path, + project_id: project.id, + 'error.message' => exception.to_s + }).and_call_original + + subject.execute + end + end + context 'when after import action throw retriable exception one time' do let(:exception) { GRPC::DeadlineExceeded.new } diff --git a/spec/services/projects/after_rename_service_spec.rb b/spec/services/projects/after_rename_service_spec.rb index b81dd3d7e3f..52136b37c66 100644 --- a/spec/services/projects/after_rename_service_spec.rb +++ b/spec/services/projects/after_rename_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::AfterRenameService do +RSpec.describe Projects::AfterRenameService do let(:rugged_config) { rugged_repo(project.repository).config } let(:legacy_storage) { Storage::LegacyProject.new(project) } let(:hashed_storage) { Storage::Hashed.new(project) } diff --git a/spec/services/projects/alerting/notify_service_spec.rb b/spec/services/projects/alerting/notify_service_spec.rb index 2f8c2049f85..123b0bad2a8 100644 --- a/spec/services/projects/alerting/notify_service_spec.rb +++ b/spec/services/projects/alerting/notify_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::Alerting::NotifyService do +RSpec.describe Projects::Alerting::NotifyService do let_it_be(:project, reload: true) { create(:project) } before do @@ -21,7 +21,7 @@ describe Projects::Alerting::NotifyService do it 'processes issues' do expect(IncidentManagement::ProcessAlertWorker) .to receive(:perform_async) - .with(project.id, kind_of(Hash), kind_of(Integer)) + .with(nil, nil, kind_of(Integer)) .once Sidekiq::Testing.inline! do @@ -64,12 +64,6 @@ describe Projects::Alerting::NotifyService do end end - shared_examples 'NotifyService does not create alert' do - it 'does not create alert' do - expect { subject }.not_to change(AlertManagement::Alert, :count) - end - end - describe '#execute' do let(:token) { 'invalid-token' } let(:starts_at) { Time.current.change(usec: 0) } @@ -107,60 +101,64 @@ describe Projects::Alerting::NotifyService do end context 'with valid payload' do + shared_examples 'assigns the alert properties' do + it 'ensure that created alert has all data properly assigned' do + subject + + expect(last_alert_attributes).to match( + project_id: project.id, + title: payload_raw.fetch(:title), + started_at: Time.zone.parse(payload_raw.fetch(:start_time)), + severity: payload_raw.fetch(:severity), + status: AlertManagement::Alert::STATUSES[:triggered], + events: 1, + hosts: payload_raw.fetch(:hosts), + payload: payload_raw.with_indifferent_access, + issue_id: nil, + description: payload_raw.fetch(:description), + monitoring_tool: payload_raw.fetch(:monitoring_tool), + service: payload_raw.fetch(:service), + fingerprint: Digest::SHA1.hexdigest(fingerprint), + ended_at: nil, + prometheus_alert_id: nil, + environment_id: nil + ) + end + end + let(:last_alert_attributes) do AlertManagement::Alert.last.attributes .except('id', 'iid', 'created_at', 'updated_at') .with_indifferent_access end - it 'creates AlertManagement::Alert' do - expect { subject }.to change(AlertManagement::Alert, :count).by(1) - end - - it 'created alert has all data properly assigned' do - subject - - expect(last_alert_attributes).to match( - project_id: project.id, - title: payload_raw.fetch(:title), - started_at: Time.zone.parse(payload_raw.fetch(:start_time)), - severity: payload_raw.fetch(:severity), - status: AlertManagement::Alert::STATUSES[:triggered], - events: 1, - hosts: payload_raw.fetch(:hosts), - payload: payload_raw.with_indifferent_access, - issue_id: nil, - description: payload_raw.fetch(:description), - monitoring_tool: payload_raw.fetch(:monitoring_tool), - service: payload_raw.fetch(:service), - fingerprint: Digest::SHA1.hexdigest(fingerprint), - ended_at: nil - ) - end - - it 'executes the alert service hooks' do - slack_service = create(:service, type: 'SlackService', project: project, alert_events: true, active: true) - subject - - expect(ProjectServiceWorker).to have_received(:perform_async).with(slack_service.id, an_instance_of(Hash)) - end + it_behaves_like 'creates an alert management alert' + it_behaves_like 'assigns the alert properties' context 'existing alert with same fingerprint' do let(:fingerprint_sha) { Digest::SHA1.hexdigest(fingerprint) } - let!(:existing_alert) { create(:alert_management_alert, project: project, fingerprint: fingerprint_sha) } + let!(:alert) { create(:alert_management_alert, project: project, fingerprint: fingerprint_sha) } + + it_behaves_like 'adds an alert management alert event' + + context 'existing alert is resolved' do + let!(:alert) { create(:alert_management_alert, :resolved, project: project, fingerprint: fingerprint_sha) } - it 'does not create AlertManagement::Alert' do - expect { subject }.not_to change(AlertManagement::Alert, :count) + it_behaves_like 'creates an alert management alert' + it_behaves_like 'assigns the alert properties' end - it 'increments the existing alert count' do - expect { subject }.to change { existing_alert.reload.events }.from(1).to(2) + context 'existing alert is ignored' do + let!(:alert) { create(:alert_management_alert, :ignored, project: project, fingerprint: fingerprint_sha) } + + it_behaves_like 'adds an alert management alert event' end - it 'does not executes the alert service hooks' do - subject + context 'two existing alerts, one resolved one open' do + let!(:resolved_existing_alert) { create(:alert_management_alert, :resolved, project: project, fingerprint: fingerprint_sha) } + let!(:alert) { create(:alert_management_alert, project: project, fingerprint: fingerprint_sha) } - expect(ProjectServiceWorker).not_to have_received(:perform_async) + it_behaves_like 'adds an alert management alert event' end end @@ -172,9 +170,7 @@ describe Projects::Alerting::NotifyService do } end - it 'creates AlertManagement::Alert' do - expect { subject }.to change(AlertManagement::Alert, :count).by(1) - end + it_behaves_like 'creates an alert management alert' it 'created alert has all data properly assigned' do subject @@ -193,7 +189,9 @@ describe Projects::Alerting::NotifyService do monitoring_tool: nil, service: nil, fingerprint: nil, - ended_at: nil + ended_at: nil, + prometheus_alert_id: nil, + environment_id: nil ) end end @@ -214,19 +212,19 @@ describe Projects::Alerting::NotifyService do end it_behaves_like 'does not process incident issues due to error', http_status: :bad_request - it_behaves_like 'NotifyService does not create alert' + it_behaves_like 'does not an create alert management alert' end context 'when alert already exists' do let(:fingerprint_sha) { Digest::SHA1.hexdigest(fingerprint) } - let!(:existing_alert) { create(:alert_management_alert, project: project, fingerprint: fingerprint_sha) } + let!(:alert) { create(:alert_management_alert, project: project, fingerprint: fingerprint_sha) } context 'when existing alert does not have an associated issue' do it_behaves_like 'processes incident issues' end context 'when existing alert has an associated issue' do - let!(:existing_alert) { create(:alert_management_alert, :with_issue, project: project, fingerprint: fingerprint_sha) } + let!(:alert) { create(:alert_management_alert, :with_issue, project: project, fingerprint: fingerprint_sha) } it_behaves_like 'does not process incident issues' end @@ -242,14 +240,14 @@ describe Projects::Alerting::NotifyService do context 'with invalid token' do it_behaves_like 'does not process incident issues due to error', http_status: :unauthorized - it_behaves_like 'NotifyService does not create alert' + it_behaves_like 'does not an create alert management alert' end context 'with deactivated Alerts Service' do let!(:alerts_service) { create(:alerts_service, :inactive, project: project) } it_behaves_like 'does not process incident issues due to error', http_status: :forbidden - it_behaves_like 'NotifyService does not create alert' + it_behaves_like 'does not an create alert management alert' end end end diff --git a/spec/services/projects/auto_devops/disable_service_spec.rb b/spec/services/projects/auto_devops/disable_service_spec.rb index fb1ab3f9949..1f161990fb2 100644 --- a/spec/services/projects/auto_devops/disable_service_spec.rb +++ b/spec/services/projects/auto_devops/disable_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Projects::AutoDevops::DisableService, '#execute' do +RSpec.describe Projects::AutoDevops::DisableService, '#execute' do let(:project) { create(:project, :repository, :auto_devops) } let(:auto_devops) { project.auto_devops } diff --git a/spec/services/projects/autocomplete_service_spec.rb b/spec/services/projects/autocomplete_service_spec.rb index b625653bc77..336aa37096a 100644 --- a/spec/services/projects/autocomplete_service_spec.rb +++ b/spec/services/projects/autocomplete_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::AutocompleteService do +RSpec.describe Projects::AutocompleteService do describe '#issues' do describe 'confidential issues' do let(:author) { create(:user) } diff --git a/spec/services/projects/batch_open_issues_count_service_spec.rb b/spec/services/projects/batch_open_issues_count_service_spec.rb index 8cb0ce03fba..82d50604309 100644 --- a/spec/services/projects/batch_open_issues_count_service_spec.rb +++ b/spec/services/projects/batch_open_issues_count_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::BatchOpenIssuesCountService do +RSpec.describe Projects::BatchOpenIssuesCountService do let!(:project_1) { create(:project) } let!(:project_2) { create(:project) } diff --git a/spec/services/projects/cleanup_service_spec.rb b/spec/services/projects/cleanup_service_spec.rb index 5c246854eb7..528f31456a9 100644 --- a/spec/services/projects/cleanup_service_spec.rb +++ b/spec/services/projects/cleanup_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::CleanupService do +RSpec.describe Projects::CleanupService do let(:project) { create(:project, :repository, bfg_object_map: fixture_file_upload('spec/fixtures/bfg_object_map.txt')) } let(:object_map) { project.bfg_object_map } diff --git a/spec/services/projects/container_repository/cleanup_tags_service_spec.rb b/spec/services/projects/container_repository/cleanup_tags_service_spec.rb index 11ea7d51673..2c708e75a25 100644 --- a/spec/services/projects/container_repository/cleanup_tags_service_spec.rb +++ b/spec/services/projects/container_repository/cleanup_tags_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::ContainerRepository::CleanupTagsService do +RSpec.describe Projects::ContainerRepository::CleanupTagsService do let_it_be(:user) { create(:user) } let_it_be(:project, reload: true) { create(:project, :private) } let_it_be(:repository) { create(:container_repository, :root, project: project) } diff --git a/spec/services/projects/container_repository/delete_tags_service_spec.rb b/spec/services/projects/container_repository/delete_tags_service_spec.rb index e17e4b6f7c9..3d065deefdf 100644 --- a/spec/services/projects/container_repository/delete_tags_service_spec.rb +++ b/spec/services/projects/container_repository/delete_tags_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::ContainerRepository::DeleteTagsService do +RSpec.describe Projects::ContainerRepository::DeleteTagsService do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :private) } let_it_be(:repository) { create(:container_repository, :root, project: project) } @@ -20,6 +20,31 @@ describe Projects::ContainerRepository::DeleteTagsService do tags: %w(latest A Ba Bb C D E)) end + RSpec.shared_examples 'logging a success response' do + it 'logs an info message' do + expect(service).to receive(:log_info).with( + service_class: 'Projects::ContainerRepository::DeleteTagsService', + message: 'deleted tags', + container_repository_id: repository.id, + deleted_tags_count: tags.size + ) + + subject + end + end + + RSpec.shared_examples 'logging an error response' do |message: 'could not delete tags'| + it 'logs an error message' do + expect(service).to receive(:log_error).with( + service_class: 'Projects::ContainerRepository::DeleteTagsService', + message: message, + container_repository_id: repository.id + ) + + subject + end + end + describe '#execute' do let(:tags) { %w[A] } @@ -47,11 +72,8 @@ describe Projects::ContainerRepository::DeleteTagsService do let_it_be(:tags) { %w[A Ba] } it 'deletes the tags by name' do - stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/tags/reference/A") - .to_return(status: 200, body: "") - - stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/tags/reference/Ba") - .to_return(status: 200, body: "") + stub_delete_reference_request('A') + stub_delete_reference_request('Ba') expect_delete_tag_by_name('A') expect_delete_tag_by_name('Ba') @@ -60,26 +82,29 @@ describe Projects::ContainerRepository::DeleteTagsService do end it 'succeeds when tag delete returns 404' do - stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/tags/reference/A") - .to_return(status: 200, body: "") - - stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/tags/reference/Ba") - .to_return(status: 404, body: "") + stub_delete_reference_request('A') + stub_delete_reference_request('Ba', 404) is_expected.to include(status: :success) end + it_behaves_like 'logging a success response' do + before do + stub_delete_reference_request('A') + stub_delete_reference_request('Ba') + end + end + context 'with failures' do context 'when the delete request fails' do before do - stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/tags/reference/A") - .to_return(status: 500, body: "") - - stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/tags/reference/Ba") - .to_return(status: 500, body: "") + stub_delete_reference_request('A', 500) + stub_delete_reference_request('Ba', 500) end it { is_expected.to include(status: :error) } + + it_behaves_like 'logging an error response' end end end @@ -104,19 +129,35 @@ describe Projects::ContainerRepository::DeleteTagsService do end end end + context 'and the feature is disabled' do + let_it_be(:tags) { %w[A Ba] } + before do stub_feature_flags(container_registry_fast_tag_delete: false) + stub_upload("{\n \"config\": {\n }\n}", 'sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3') + stub_put_manifest_request('A') + stub_put_manifest_request('Ba') end it 'fallbacks to slow delete' do expect(service).not_to receive(:fast_delete) - expect(service).to receive(:slow_delete).with(repository, tags) + expect(service).to receive(:slow_delete).with(repository, tags).and_call_original + + expect_delete_tag_by_digest('sha256:dummy') subject end + + it_behaves_like 'logging a success response' do + before do + allow(service).to receive(:slow_delete).and_call_original + expect_delete_tag_by_digest('sha256:dummy') + end + end end end + context 'when the registry does not support fast delete' do let_it_be(:project) { create(:project, :private) } let_it_be(:repository) { create(:container_repository, :root, project: project) } @@ -155,11 +196,8 @@ describe Projects::ContainerRepository::DeleteTagsService do it 'deletes the tags using a dummy image' do stub_upload("{\n \"config\": {\n }\n}", 'sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3') - stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/A") - .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' }) - - stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/Ba") - .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' }) + stub_put_manifest_request('A') + stub_put_manifest_request('Ba') expect_delete_tag_by_digest('sha256:dummy') @@ -169,11 +207,8 @@ describe Projects::ContainerRepository::DeleteTagsService do it 'succeeds when tag delete returns 404' do stub_upload("{\n \"config\": {\n }\n}", 'sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3') - stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/A") - .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' }) - - stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/Ba") - .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' }) + stub_put_manifest_request('A') + stub_put_manifest_request('Ba') stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/manifests/sha256:dummy") .to_return(status: 404, body: "", headers: {}) @@ -181,6 +216,15 @@ describe Projects::ContainerRepository::DeleteTagsService do is_expected.to include(status: :success) end + it_behaves_like 'logging a success response' do + before do + stub_upload("{\n \"config\": {\n }\n}", 'sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3') + stub_put_manifest_request('A') + stub_put_manifest_request('Ba') + expect_delete_tag_by_digest('sha256:dummy') + end + end + context 'with failures' do context 'when the dummy manifest generation fails' do before do @@ -188,23 +232,23 @@ describe Projects::ContainerRepository::DeleteTagsService do end it { is_expected.to include(status: :error) } + + it_behaves_like 'logging an error response', message: 'could not generate manifest' end context 'when updating the tags fails' do before do stub_upload("{\n \"config\": {\n }\n}", 'sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3') - stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/A") - .to_return(status: 500, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' }) - - stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/Ba") - .to_return(status: 500, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' }) + stub_put_manifest_request('A', 500) + stub_put_manifest_request('Ba', 500) stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/manifests/sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3") .to_return(status: 200, body: "", headers: {}) end it { is_expected.to include(status: :error) } + it_behaves_like 'logging an error response' end end end @@ -214,6 +258,16 @@ describe Projects::ContainerRepository::DeleteTagsService do private + def stub_delete_reference_request(tag, status = 200) + stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/tags/reference/#{tag}") + .to_return(status: status, body: '') + end + + def stub_put_manifest_request(tag, status = 200, headers = { 'docker-content-digest' => 'sha256:dummy' }) + stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/#{tag}") + .to_return(status: status, body: '', headers: headers) + end + def stub_tag_digest(tag, digest) stub_request(:head, "http://registry.gitlab/v2/#{repository.path}/manifests/#{tag}") .to_return(status: 200, body: "", headers: { 'docker-content-digest' => digest }) diff --git a/spec/services/projects/container_repository/destroy_service_spec.rb b/spec/services/projects/container_repository/destroy_service_spec.rb index 753b7540d7f..20e75d94e05 100644 --- a/spec/services/projects/container_repository/destroy_service_spec.rb +++ b/spec/services/projects/container_repository/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::ContainerRepository::DestroyService do +RSpec.describe Projects::ContainerRepository::DestroyService do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :private) } diff --git a/spec/services/projects/count_service_spec.rb b/spec/services/projects/count_service_spec.rb index e345b508f53..11b2b57a277 100644 --- a/spec/services/projects/count_service_spec.rb +++ b/spec/services/projects/count_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::CountService do +RSpec.describe Projects::CountService do let(:project) { build(:project, id: 1) } let(:service) { described_class.new(project) } diff --git a/spec/services/projects/create_from_template_service_spec.rb b/spec/services/projects/create_from_template_service_spec.rb index 0b4772e8f02..7e23daabcd3 100644 --- a/spec/services/projects/create_from_template_service_spec.rb +++ b/spec/services/projects/create_from_template_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::CreateFromTemplateService do +RSpec.describe Projects::CreateFromTemplateService do let(:user) { create(:user) } let(:template_name) { 'rails' } let(:project_params) do diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb index e70ee05ed31..9eb7cacbbcb 100644 --- a/spec/services/projects/create_service_spec.rb +++ b/spec/services/projects/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::CreateService, '#execute' do +RSpec.describe Projects::CreateService, '#execute' do include ExternalAuthorizationServiceHelpers include GitHelpers @@ -240,13 +240,21 @@ describe Projects::CreateService, '#execute' do end context 'import data' do - it 'stores import data and URL' do - import_data = { data: { 'test' => 'some data' } } - project = create_project(user, { name: 'test', import_url: 'http://import-url', import_data: import_data }) + let(:import_data) { { data: { 'test' => 'some data' } } } + let(:imported_project) { create_project(user, { name: 'test', import_url: 'http://import-url', import_data: import_data }) } + + it 'does not write repository config' do + expect_next_instance_of(Project) do |project| + expect(project).not_to receive(:write_repository_config) + end - expect(project.import_data).to be_persisted - expect(project.import_data.data).to eq(import_data[:data]) - expect(project.import_url).to eq('http://import-url') + imported_project + end + + it 'stores import data and URL' do + expect(imported_project.import_data).to be_persisted + expect(imported_project.import_data.data).to eq(import_data[:data]) + expect(imported_project.import_url).to eq('http://import-url') end end @@ -438,14 +446,35 @@ describe Projects::CreateService, '#execute' do end context 'when readme initialization is requested' do - it 'creates README.md' do + let(:project) { create_project(user, opts) } + + before do opts[:initialize_with_readme] = '1' + end - project = create_project(user, opts) + shared_examples 'creates README.md' do + it { expect(project.repository.commit_count).to be(1) } + it { expect(project.repository.readme.name).to eql('README.md') } + it { expect(project.repository.readme.data).to include('# GitLab') } + end - expect(project.repository.commit_count).to be(1) - expect(project.repository.readme.name).to eql('README.md') - expect(project.repository.readme.data).to include('# GitLab') + it_behaves_like 'creates README.md' + + context 'and a default_branch_name is specified' do + before do + allow(Gitlab::CurrentSettings) + .to receive(:default_branch_name) + .and_return('example_branch') + end + + it_behaves_like 'creates README.md' + + it 'creates README.md within the specified branch rather than master' do + branches = project.repository.branches + + expect(branches.size).to eq(1) + expect(branches.collect(&:name)).to contain_exactly('example_branch') + end end end @@ -647,10 +676,6 @@ describe Projects::CreateService, '#execute' do end it 'updates authorization for current_user' do - expect(Users::RefreshAuthorizedProjectsService).to( - receive(:new).with(user).and_call_original - ) - project = create_project(user, opts) expect( @@ -682,10 +707,6 @@ describe Projects::CreateService, '#execute' do end it 'updates authorization for current_user' do - expect(Users::RefreshAuthorizedProjectsService).to( - receive(:new).with(user).and_call_original - ) - project = create_project(user, opts) expect( diff --git a/spec/services/projects/deploy_tokens/create_service_spec.rb b/spec/services/projects/deploy_tokens/create_service_spec.rb index 5c3ada8af4e..831dbc06588 100644 --- a/spec/services/projects/deploy_tokens/create_service_spec.rb +++ b/spec/services/projects/deploy_tokens/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::DeployTokens::CreateService do +RSpec.describe Projects::DeployTokens::CreateService do it_behaves_like 'a deploy token creation service' do let(:entity) { create(:project) } let(:deploy_token_class) { ProjectDeployToken } diff --git a/spec/services/projects/deploy_tokens/destroy_service_spec.rb b/spec/services/projects/deploy_tokens/destroy_service_spec.rb index 24407f46615..edb2345aa6c 100644 --- a/spec/services/projects/deploy_tokens/destroy_service_spec.rb +++ b/spec/services/projects/deploy_tokens/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::DeployTokens::DestroyService do +RSpec.describe Projects::DeployTokens::DestroyService do it_behaves_like 'a deploy token deletion service' do let_it_be(:entity) { create(:project) } let_it_be(:deploy_token_class) { ProjectDeployToken } diff --git a/spec/services/projects/destroy_rollback_service_spec.rb b/spec/services/projects/destroy_rollback_service_spec.rb index 8facf17dc45..f63939337b8 100644 --- a/spec/services/projects/destroy_rollback_service_spec.rb +++ b/spec/services/projects/destroy_rollback_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::DestroyRollbackService do +RSpec.describe Projects::DestroyRollbackService do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :repository, namespace: user.namespace) } let(:repository) { project.repository } diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index 58c40d04fe9..56b19c33ece 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::DestroyService do +RSpec.describe Projects::DestroyService do include ProjectForksHelper let_it_be(:user) { create(:user) } diff --git a/spec/services/projects/detect_repository_languages_service_spec.rb b/spec/services/projects/detect_repository_languages_service_spec.rb index 76600b0e77c..cf4c7a5024d 100644 --- a/spec/services/projects/detect_repository_languages_service_spec.rb +++ b/spec/services/projects/detect_repository_languages_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::DetectRepositoryLanguagesService, :clean_gitlab_redis_shared_state do +RSpec.describe Projects::DetectRepositoryLanguagesService, :clean_gitlab_redis_shared_state do let_it_be(:project, reload: true) { create(:project, :repository) } subject { described_class.new(project) } diff --git a/spec/services/projects/download_service_spec.rb b/spec/services/projects/download_service_spec.rb index 06efc2ff825..0f743eaa7f5 100644 --- a/spec/services/projects/download_service_spec.rb +++ b/spec/services/projects/download_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::DownloadService do +RSpec.describe Projects::DownloadService do describe 'File service' do before do @user = create(:user) diff --git a/spec/services/projects/enable_deploy_key_service_spec.rb b/spec/services/projects/enable_deploy_key_service_spec.rb index 64de373d7f6..f297ec374cf 100644 --- a/spec/services/projects/enable_deploy_key_service_spec.rb +++ b/spec/services/projects/enable_deploy_key_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::EnableDeployKeyService do +RSpec.describe Projects::EnableDeployKeyService do let(:deploy_key) { create(:deploy_key, public: true) } let(:project) { create(:project) } let(:user) { project.creator} diff --git a/spec/services/projects/fetch_statistics_increment_service_spec.rb b/spec/services/projects/fetch_statistics_increment_service_spec.rb index fcfb138aad6..16121a42c39 100644 --- a/spec/services/projects/fetch_statistics_increment_service_spec.rb +++ b/spec/services/projects/fetch_statistics_increment_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' module Projects - describe FetchStatisticsIncrementService do + RSpec.describe FetchStatisticsIncrementService do let(:project) { create(:project) } describe '#execute' do diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb index 112a41c773b..c49aa42b147 100644 --- a/spec/services/projects/fork_service_spec.rb +++ b/spec/services/projects/fork_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::ForkService do +RSpec.describe Projects::ForkService do include ProjectForksHelper shared_examples 'forks count cache refresh' do @@ -10,6 +10,7 @@ describe Projects::ForkService do expect(from_project.forks_count).to be_zero fork_project(from_project, to_user) + BatchLoader::Executor.clear_current expect(from_project.forks_count).to eq(1) end @@ -327,7 +328,7 @@ describe Projects::ForkService do destination_storage_name: 'test_second_storage' ) Projects::UpdateRepositoryStorageService.new(storage_move).execute - fork_after_move = fork_project(project) + fork_after_move = fork_project(project.reload) pool_repository_before_move = PoolRepository.joins(:shard) .find_by(source_project: project, shards: { name: 'default' }) pool_repository_after_move = PoolRepository.joins(:shard) @@ -405,6 +406,7 @@ describe Projects::ForkService do expect(fork_from_project.forks_count).to be_zero subject.execute(fork_to_project) + BatchLoader::Executor.clear_current expect(fork_from_project.forks_count).to eq(1) end diff --git a/spec/services/projects/forks_count_service_spec.rb b/spec/services/projects/forks_count_service_spec.rb index 21a75eafc7a..31662f78973 100644 --- a/spec/services/projects/forks_count_service_spec.rb +++ b/spec/services/projects/forks_count_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::ForksCountService, :use_clean_rails_memory_store_caching do +RSpec.describe Projects::ForksCountService, :use_clean_rails_memory_store_caching do let(:project) { build(:project) } subject { described_class.new(project) } diff --git a/spec/services/projects/git_deduplication_service_spec.rb b/spec/services/projects/git_deduplication_service_spec.rb index 9e6279da7de..b98db5bc41b 100644 --- a/spec/services/projects/git_deduplication_service_spec.rb +++ b/spec/services/projects/git_deduplication_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::GitDeduplicationService do +RSpec.describe Projects::GitDeduplicationService do include ExclusiveLeaseHelpers let(:pool) { create(:pool_repository, :ready) } @@ -139,7 +139,7 @@ describe Projects::GitDeduplicationService do end it 'fails when a lease is already out' do - expect(service).to receive(:log_error).with('Cannot obtain an exclusive lease. There must be another instance already in execution.') + expect(service).to receive(:log_error).with("Cannot obtain an exclusive lease for #{service.class.name}. There must be another instance already in execution.") service.execute end diff --git a/spec/services/projects/gitlab_projects_import_service_spec.rb b/spec/services/projects/gitlab_projects_import_service_spec.rb index 1662d4577aa..09d093a9916 100644 --- a/spec/services/projects/gitlab_projects_import_service_spec.rb +++ b/spec/services/projects/gitlab_projects_import_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::GitlabProjectsImportService do +RSpec.describe Projects::GitlabProjectsImportService do let_it_be(:namespace) { create(:namespace) } let(:path) { 'test-path' } let(:file) { fixture_file_upload('spec/fixtures/project_export.tar.gz') } diff --git a/spec/services/projects/group_links/create_service_spec.rb b/spec/services/projects/group_links/create_service_spec.rb index 22f7c8bdcb4..6468e3007c2 100644 --- a/spec/services/projects/group_links/create_service_spec.rb +++ b/spec/services/projects/group_links/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::GroupLinks::CreateService, '#execute' do +RSpec.describe Projects::GroupLinks::CreateService, '#execute' do let_it_be(:user) { create :user } let_it_be(:group) { create :group } let_it_be(:project) { create :project } @@ -23,7 +23,7 @@ describe Projects::GroupLinks::CreateService, '#execute' do expect { subject.execute(group) }.to change { project.project_group_links.count }.from(0).to(1) end - it 'updates authorization' do + it 'updates authorization', :sidekiq_inline do expect { subject.execute(group) }.to( change { Ability.allowed?(user, :read_project, project) } .from(false).to(true)) @@ -36,4 +36,50 @@ describe Projects::GroupLinks::CreateService, '#execute' do it 'returns error if user is not allowed to share with a group' do expect { subject.execute(create(:group)) }.not_to change { project.project_group_links.count } end + + context 'with specialized_project_authorization_workers' do + let_it_be(:other_user) { create(:user) } + + before do + group.add_developer(other_user) + end + + it 'schedules authorization update for users with access to group' do + expect(AuthorizedProjectsWorker).not_to( + receive(:bulk_perform_async) + ) + expect(AuthorizedProjectUpdate::ProjectGroupLinkCreateWorker).to( + receive(:perform_async).and_call_original + ) + expect(AuthorizedProjectUpdate::UserRefreshWithLowUrgencyWorker).to( + receive(:bulk_perform_in) + .with(1.hour, + array_including([user.id], [other_user.id]), + batch_delay: 30.seconds, batch_size: 100) + .and_call_original + ) + + subject.execute(group) + end + + context 'when feature is disabled' do + before do + stub_feature_flags(specialized_project_authorization_project_share_worker: false) + end + + it 'uses AuthorizedProjectsWorker' do + expect(AuthorizedProjectsWorker).to( + receive(:bulk_perform_async).with(array_including([user.id], [other_user.id])).and_call_original + ) + expect(AuthorizedProjectUpdate::ProjectCreateWorker).not_to( + receive(:perform_async) + ) + expect(AuthorizedProjectUpdate::UserRefreshWithLowUrgencyWorker).not_to( + receive(:bulk_perform_in) + ) + + subject.execute(group) + end + end + end end diff --git a/spec/services/projects/group_links/destroy_service_spec.rb b/spec/services/projects/group_links/destroy_service_spec.rb index 0a8c9580e70..459b79b2d7d 100644 --- a/spec/services/projects/group_links/destroy_service_spec.rb +++ b/spec/services/projects/group_links/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::GroupLinks::DestroyService, '#execute' do +RSpec.describe Projects::GroupLinks::DestroyService, '#execute' do let_it_be(:user) { create :user } let_it_be(:project) { create(:project, :private) } let_it_be(:group) { create(:group) } diff --git a/spec/services/projects/group_links/update_service_spec.rb b/spec/services/projects/group_links/update_service_spec.rb index 5be2ae1e0f7..053c5eb611e 100644 --- a/spec/services/projects/group_links/update_service_spec.rb +++ b/spec/services/projects/group_links/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::GroupLinks::UpdateService, '#execute' do +RSpec.describe Projects::GroupLinks::UpdateService, '#execute' do let_it_be(:user) { create :user } let_it_be(:group) { create :group } let_it_be(:project) { create :project } diff --git a/spec/services/projects/hashed_storage/base_attachment_service_spec.rb b/spec/services/projects/hashed_storage/base_attachment_service_spec.rb index 070dd5fc1b8..5e1b6f2e404 100644 --- a/spec/services/projects/hashed_storage/base_attachment_service_spec.rb +++ b/spec/services/projects/hashed_storage/base_attachment_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::HashedStorage::BaseAttachmentService do +RSpec.describe Projects::HashedStorage::BaseAttachmentService do let(:project) { create(:project, :repository, storage_version: 0, skip_disk_validation: true) } subject(:service) { described_class.new(project: project, old_disk_path: project.full_path, logger: nil) } diff --git a/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb b/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb index 7c7e188a12d..c8f24c6ce00 100644 --- a/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb +++ b/spec/services/projects/hashed_storage/migrate_attachments_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::HashedStorage::MigrateAttachmentsService do +RSpec.describe Projects::HashedStorage::MigrateAttachmentsService do subject(:service) { described_class.new(project: project, old_disk_path: project.full_path, logger: nil) } let(:project) { create(:project, :repository, storage_version: 1, skip_disk_validation: true) } diff --git a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb index f1eaf8324e0..e03e75653ff 100644 --- a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb +++ b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::HashedStorage::MigrateRepositoryService do +RSpec.describe Projects::HashedStorage::MigrateRepositoryService do include GitHelpers let(:gitlab_shell) { Gitlab::Shell.new } diff --git a/spec/services/projects/hashed_storage/migration_service_spec.rb b/spec/services/projects/hashed_storage/migration_service_spec.rb index 0a7975305dc..ef96c17dd85 100644 --- a/spec/services/projects/hashed_storage/migration_service_spec.rb +++ b/spec/services/projects/hashed_storage/migration_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::HashedStorage::MigrationService do +RSpec.describe Projects::HashedStorage::MigrationService do let(:project) { create(:project, :empty_repo, :wiki_repo, :legacy_storage) } let(:logger) { double } let!(:project_attachment) { build(:file_uploader, project: project) } diff --git a/spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb b/spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb index 54695e6e48f..d4cb46c82ad 100644 --- a/spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb +++ b/spec/services/projects/hashed_storage/rollback_attachments_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::HashedStorage::RollbackAttachmentsService do +RSpec.describe Projects::HashedStorage::RollbackAttachmentsService do subject(:service) { described_class.new(project: project, old_disk_path: project.disk_path, logger: nil) } let(:project) { create(:project, :repository, skip_disk_validation: true) } diff --git a/spec/services/projects/hashed_storage/rollback_repository_service_spec.rb b/spec/services/projects/hashed_storage/rollback_repository_service_spec.rb index 1c0f446d9cf..f2b1ce30a54 100644 --- a/spec/services/projects/hashed_storage/rollback_repository_service_spec.rb +++ b/spec/services/projects/hashed_storage/rollback_repository_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::HashedStorage::RollbackRepositoryService, :clean_gitlab_redis_shared_state do +RSpec.describe Projects::HashedStorage::RollbackRepositoryService, :clean_gitlab_redis_shared_state do include GitHelpers let(:gitlab_shell) { Gitlab::Shell.new } diff --git a/spec/services/projects/hashed_storage/rollback_service_spec.rb b/spec/services/projects/hashed_storage/rollback_service_spec.rb index e6b7daba99e..0bd63f2da2a 100644 --- a/spec/services/projects/hashed_storage/rollback_service_spec.rb +++ b/spec/services/projects/hashed_storage/rollback_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::HashedStorage::RollbackService do +RSpec.describe Projects::HashedStorage::RollbackService do let(:project) { create(:project, :empty_repo, :wiki_repo) } let(:logger) { double } let!(:project_attachment) { build(:file_uploader, project: project) } diff --git a/spec/services/projects/housekeeping_service_spec.rb b/spec/services/projects/housekeeping_service_spec.rb index 98a27a71c26..18871f010f8 100644 --- a/spec/services/projects/housekeeping_service_spec.rb +++ b/spec/services/projects/housekeeping_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::HousekeepingService do +RSpec.describe Projects::HousekeepingService do subject { described_class.new(project) } let_it_be(:project) { create(:project, :repository) } diff --git a/spec/services/projects/import_error_filter_spec.rb b/spec/services/projects/import_error_filter_spec.rb index 312b658de89..fd31cd52cc4 100644 --- a/spec/services/projects/import_error_filter_spec.rb +++ b/spec/services/projects/import_error_filter_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::ImportErrorFilter do +RSpec.describe Projects::ImportErrorFilter do it 'filters any full paths' do message = 'Error importing into /my/folder Permission denied @ unlink_internal - /var/opt/gitlab/gitlab-rails/shared/a/b/c/uploads/file' diff --git a/spec/services/projects/import_export/export_service_spec.rb b/spec/services/projects/import_export/export_service_spec.rb index 19891341311..111c1264777 100644 --- a/spec/services/projects/import_export/export_service_spec.rb +++ b/spec/services/projects/import_export/export_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::ImportExport::ExportService do +RSpec.describe Projects::ImportExport::ExportService do describe '#execute' do let!(:user) { create(:user) } let(:project) { create(:project) } diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb index ca6750b373d..92e18b6cb46 100644 --- a/spec/services/projects/import_service_spec.rb +++ b/spec/services/projects/import_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::ImportService do +RSpec.describe Projects::ImportService do let!(:project) { create(:project) } let(:user) { project.creator } diff --git a/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb index 99d35fdc7f7..66a450bd734 100644 --- a/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb +++ b/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Projects::LfsPointers::LfsDownloadLinkListService do +RSpec.describe Projects::LfsPointers::LfsDownloadLinkListService do let(:import_url) { 'http://www.gitlab.com/demo/repo.git' } let(:lfs_endpoint) { "#{import_url}/info/lfs/objects/batch" } let!(:project) { create(:project, import_url: import_url) } diff --git a/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb index 496d1fe67f2..a606371099d 100644 --- a/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb +++ b/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Projects::LfsPointers::LfsDownloadService do +RSpec.describe Projects::LfsPointers::LfsDownloadService do include StubRequests let(:project) { create(:project) } diff --git a/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb index 016028a96bf..b36b0b8d6b2 100644 --- a/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb +++ b/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Projects::LfsPointers::LfsImportService do +RSpec.describe Projects::LfsPointers::LfsImportService do let(:project) { create(:project) } let(:user) { project.creator } let(:import_url) { 'http://www.gitlab.com/demo/repo.git' } diff --git a/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb index b64662f3782..d59f5dbae19 100644 --- a/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb +++ b/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Projects::LfsPointers::LfsLinkService do +RSpec.describe Projects::LfsPointers::LfsLinkService do let!(:project) { create(:project, lfs_enabled: true) } let!(:lfs_objects_project) { create_list(:lfs_objects_project, 2, project: project) } let(:new_oids) { { 'oid1' => 123, 'oid2' => 125 } } diff --git a/spec/services/projects/lfs_pointers/lfs_object_download_list_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_object_download_list_service_spec.rb index e94d8a85987..0799a33f856 100644 --- a/spec/services/projects/lfs_pointers/lfs_object_download_list_service_spec.rb +++ b/spec/services/projects/lfs_pointers/lfs_object_download_list_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Projects::LfsPointers::LfsObjectDownloadListService do +RSpec.describe Projects::LfsPointers::LfsObjectDownloadListService do let(:import_url) { 'http://www.gitlab.com/demo/repo.git' } let(:default_endpoint) { "#{import_url}/info/lfs/objects/batch"} let(:group) { create(:group, lfs_enabled: true)} diff --git a/spec/services/projects/move_access_service_spec.rb b/spec/services/projects/move_access_service_spec.rb index efa34c84522..de3871414af 100644 --- a/spec/services/projects/move_access_service_spec.rb +++ b/spec/services/projects/move_access_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::MoveAccessService do +RSpec.describe Projects::MoveAccessService do let(:user) { create(:user) } let(:group) { create(:group) } let(:project_with_access) { create(:project, namespace: user.namespace) } diff --git a/spec/services/projects/move_deploy_keys_projects_service_spec.rb b/spec/services/projects/move_deploy_keys_projects_service_spec.rb index a5d28fb0fbf..e69b4dd4fc7 100644 --- a/spec/services/projects/move_deploy_keys_projects_service_spec.rb +++ b/spec/services/projects/move_deploy_keys_projects_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::MoveDeployKeysProjectsService do +RSpec.describe Projects::MoveDeployKeysProjectsService do let!(:user) { create(:user) } let!(:project_with_deploy_keys) { create(:project, namespace: user.namespace) } let!(:target_project) { create(:project, namespace: user.namespace) } diff --git a/spec/services/projects/move_forks_service_spec.rb b/spec/services/projects/move_forks_service_spec.rb index 8f9f048d5ff..7d3637b7758 100644 --- a/spec/services/projects/move_forks_service_spec.rb +++ b/spec/services/projects/move_forks_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::MoveForksService do +RSpec.describe Projects::MoveForksService do include ProjectForksHelper let!(:user) { create(:user) } diff --git a/spec/services/projects/move_lfs_objects_projects_service_spec.rb b/spec/services/projects/move_lfs_objects_projects_service_spec.rb index 114509229c5..b73286fba9a 100644 --- a/spec/services/projects/move_lfs_objects_projects_service_spec.rb +++ b/spec/services/projects/move_lfs_objects_projects_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::MoveLfsObjectsProjectsService do +RSpec.describe Projects::MoveLfsObjectsProjectsService do let!(:user) { create(:user) } let!(:project_with_lfs_objects) { create(:project, namespace: user.namespace) } let!(:target_project) { create(:project, namespace: user.namespace) } diff --git a/spec/services/projects/move_notification_settings_service_spec.rb b/spec/services/projects/move_notification_settings_service_spec.rb index 54d85404bf6..7c9f1dd30d2 100644 --- a/spec/services/projects/move_notification_settings_service_spec.rb +++ b/spec/services/projects/move_notification_settings_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::MoveNotificationSettingsService do +RSpec.describe Projects::MoveNotificationSettingsService do let(:user) { create(:user) } let(:project_with_notifications) { create(:project, namespace: user.namespace) } let(:target_project) { create(:project, namespace: user.namespace) } diff --git a/spec/services/projects/move_project_authorizations_service_spec.rb b/spec/services/projects/move_project_authorizations_service_spec.rb index fe3ba31c881..a37b4d807a0 100644 --- a/spec/services/projects/move_project_authorizations_service_spec.rb +++ b/spec/services/projects/move_project_authorizations_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::MoveProjectAuthorizationsService do +RSpec.describe Projects::MoveProjectAuthorizationsService do let!(:user) { create(:user) } let(:project_with_users) { create(:project, namespace: user.namespace) } let(:target_project) { create(:project, namespace: user.namespace) } diff --git a/spec/services/projects/move_project_group_links_service_spec.rb b/spec/services/projects/move_project_group_links_service_spec.rb index 6140d679929..196a8f2b339 100644 --- a/spec/services/projects/move_project_group_links_service_spec.rb +++ b/spec/services/projects/move_project_group_links_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::MoveProjectGroupLinksService do +RSpec.describe Projects::MoveProjectGroupLinksService do let!(:user) { create(:user) } let(:project_with_groups) { create(:project, namespace: user.namespace) } let(:target_project) { create(:project, namespace: user.namespace) } diff --git a/spec/services/projects/move_project_members_service_spec.rb b/spec/services/projects/move_project_members_service_spec.rb index bdd5cd6a87a..f14f00e3866 100644 --- a/spec/services/projects/move_project_members_service_spec.rb +++ b/spec/services/projects/move_project_members_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::MoveProjectMembersService do +RSpec.describe Projects::MoveProjectMembersService do let!(:user) { create(:user) } let(:project_with_users) { create(:project, namespace: user.namespace) } let(:target_project) { create(:project, namespace: user.namespace) } diff --git a/spec/services/projects/move_users_star_projects_service_spec.rb b/spec/services/projects/move_users_star_projects_service_spec.rb index cde188f9f5f..0f766ebd0ec 100644 --- a/spec/services/projects/move_users_star_projects_service_spec.rb +++ b/spec/services/projects/move_users_star_projects_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::MoveUsersStarProjectsService do +RSpec.describe Projects::MoveUsersStarProjectsService do let!(:user) { create(:user) } let!(:project_with_stars) { create(:project, namespace: user.namespace) } let!(:target_project) { create(:project, namespace: user.namespace) } diff --git a/spec/services/projects/open_issues_count_service_spec.rb b/spec/services/projects/open_issues_count_service_spec.rb index c1d49befeb9..c739fea5ecf 100644 --- a/spec/services/projects/open_issues_count_service_spec.rb +++ b/spec/services/projects/open_issues_count_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::OpenIssuesCountService, :use_clean_rails_memory_store_caching do +RSpec.describe Projects::OpenIssuesCountService, :use_clean_rails_memory_store_caching do let(:project) { create(:project) } subject { described_class.new(project) } diff --git a/spec/services/projects/open_merge_requests_count_service_spec.rb b/spec/services/projects/open_merge_requests_count_service_spec.rb index 7d848f9f2c3..6caef181e77 100644 --- a/spec/services/projects/open_merge_requests_count_service_spec.rb +++ b/spec/services/projects/open_merge_requests_count_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::OpenMergeRequestsCountService, :use_clean_rails_memory_store_caching do +RSpec.describe Projects::OpenMergeRequestsCountService, :use_clean_rails_memory_store_caching do let_it_be(:project) { create(:project) } subject { described_class.new(project) } diff --git a/spec/services/projects/operations/update_service_spec.rb b/spec/services/projects/operations/update_service_spec.rb index f4d62b48fe5..3cfc9844d65 100644 --- a/spec/services/projects/operations/update_service_spec.rb +++ b/spec/services/projects/operations/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::Operations::UpdateService do +RSpec.describe Projects::Operations::UpdateService do let_it_be(:user) { create(:user) } let_it_be(:project, refind: true) { create(:project) } diff --git a/spec/services/projects/overwrite_project_service_spec.rb b/spec/services/projects/overwrite_project_service_spec.rb index def39ad3789..e4495da9807 100644 --- a/spec/services/projects/overwrite_project_service_spec.rb +++ b/spec/services/projects/overwrite_project_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::OverwriteProjectService do +RSpec.describe Projects::OverwriteProjectService do include ProjectForksHelper let(:user) { create(:user) } diff --git a/spec/services/projects/participants_service_spec.rb b/spec/services/projects/participants_service_spec.rb index f4a04159db4..33a3e37a2d2 100644 --- a/spec/services/projects/participants_service_spec.rb +++ b/spec/services/projects/participants_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::ParticipantsService do +RSpec.describe Projects::ParticipantsService do describe '#groups' do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :public) } diff --git a/spec/services/projects/prometheus/alerts/create_events_service_spec.rb b/spec/services/projects/prometheus/alerts/create_events_service_spec.rb deleted file mode 100644 index 61236b5bbdb..00000000000 --- a/spec/services/projects/prometheus/alerts/create_events_service_spec.rb +++ /dev/null @@ -1,312 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Projects::Prometheus::Alerts::CreateEventsService do - let(:user) { create(:user) } - let_it_be(:project) { create(:project) } - let(:metric) { create(:prometheus_metric, project: project) } - let(:service) { described_class.new(project, user, alerts_payload) } - - shared_examples 'events persisted' do |expected_count| - subject { service.execute } - - it 'returns proper amount of created events' do - expect(subject.size).to eq(expected_count) - end - - it 'increments event count' do - expect { subject }.to change { PrometheusAlertEvent.count }.to(expected_count) - end - end - - shared_examples 'no events persisted' do - subject { service.execute } - - it 'returns no created events' do - expect(subject).to be_empty - end - - it 'does not change event count' do - expect { subject }.not_to change { PrometheusAlertEvent.count } - end - end - - shared_examples 'self managed events persisted' do - subject { service.execute } - - it 'returns created events' do - expect(subject).not_to be_empty - end - - it 'does change self managed event count' do - expect { subject }.to change { SelfManagedPrometheusAlertEvent.count } - end - end - - context 'with valid alerts_payload' do - let!(:alert) { create(:prometheus_alert, prometheus_metric: metric, project: project) } - - let(:events) { service.execute } - - context 'with a firing payload' do - let(:started_at) { truncate_to_second(Time.current) } - let(:firing_event) { alert_payload(status: 'firing', started_at: started_at) } - let(:alerts_payload) { { 'alerts' => [firing_event] } } - - it_behaves_like 'events persisted', 1 - - it 'returns created event' do - event = events.first - - expect(event).to be_firing - expect(event.started_at).to eq(started_at) - expect(event.ended_at).to be_nil - end - - context 'with 2 different firing events' do - let(:another_firing_event) { alert_payload(status: 'firing', started_at: started_at + 1) } - let(:alerts_payload) { { 'alerts' => [firing_event, another_firing_event] } } - - it_behaves_like 'events persisted', 2 - end - - context 'with already persisted firing event' do - before do - service.execute - end - - it_behaves_like 'no events persisted' - end - - context 'with duplicate payload' do - let(:alerts_payload) { { 'alerts' => [firing_event, firing_event] } } - - it_behaves_like 'events persisted', 1 - end - end - - context 'with a resolved payload' do - let(:started_at) { truncate_to_second(Time.current) } - let(:ended_at) { started_at + 1 } - let(:resolved_event) { alert_payload(status: 'resolved', started_at: started_at, ended_at: ended_at) } - let(:alerts_payload) { { 'alerts' => [resolved_event] } } - let(:payload_key) { Gitlab::Alerting::Alert.new(project: project, payload: resolved_event).gitlab_fingerprint } - - context 'with a matching firing event' do - before do - create(:prometheus_alert_event, - prometheus_alert: alert, - payload_key: payload_key, - started_at: started_at) - end - - it 'does not create an additional event' do - expect { service.execute }.not_to change { PrometheusAlertEvent.count } - end - - it 'marks firing event as `resolved`' do - expect(events.size).to eq(1) - - event = events.first - expect(event).to be_resolved - expect(event.started_at).to eq(started_at) - expect(event.ended_at).to eq(ended_at) - end - - context 'with duplicate payload' do - let(:alerts_payload) { { 'alerts' => [resolved_event, resolved_event] } } - - it 'does not create an additional event' do - expect { service.execute }.not_to change { PrometheusAlertEvent.count } - end - - it 'marks firing event as `resolved` only once' do - expect(events.size).to eq(1) - end - end - end - - context 'without a matching firing event' do - context 'due to payload_key' do - let(:payload_key) { 'some other payload_key' } - - before do - create(:prometheus_alert_event, - prometheus_alert: alert, - payload_key: payload_key, - started_at: started_at) - end - - it_behaves_like 'no events persisted' - end - - context 'due to status' do - before do - create(:prometheus_alert_event, :resolved, - prometheus_alert: alert, - started_at: started_at) - end - - it_behaves_like 'no events persisted' - end - end - - context 'with already resolved event' do - before do - service.execute - end - - it_behaves_like 'no events persisted' - end - end - - context 'with a metric from another project' do - let(:another_project) { create(:project) } - let(:metric) { create(:prometheus_metric, project: another_project) } - let(:alerts_payload) { { 'alerts' => [alert_payload] } } - - let!(:alert) do - create(:prometheus_alert, - prometheus_metric: metric, - project: another_project) - end - - it_behaves_like 'no events persisted' - end - end - - context 'with invalid payload' do - let(:alert) { create(:prometheus_alert, prometheus_metric: metric, project: project) } - - describe '`alerts` key' do - context 'is missing' do - let(:alerts_payload) { {} } - - it_behaves_like 'no events persisted' - end - - context 'is nil' do - let(:alerts_payload) { { 'alerts' => nil } } - - it_behaves_like 'no events persisted' - end - - context 'is empty' do - let(:alerts_payload) { { 'alerts' => [] } } - - it_behaves_like 'no events persisted' - end - - context 'is not a Hash' do - let(:alerts_payload) { { 'alerts' => [:not_a_hash] } } - - it_behaves_like 'no events persisted' - end - - describe '`status`' do - context 'is missing' do - let(:alerts_payload) { { 'alerts' => [alert_payload(status: nil)] } } - - it_behaves_like 'no events persisted' - end - - context 'is invalid' do - let(:alerts_payload) { { 'alerts' => [alert_payload(status: 'invalid')] } } - - it_behaves_like 'no events persisted' - end - end - - describe '`started_at`' do - context 'is missing' do - let(:alerts_payload) { { 'alerts' => [alert_payload(started_at: nil)] } } - - it_behaves_like 'no events persisted' - end - - context 'is invalid' do - let(:alerts_payload) { { 'alerts' => [alert_payload(started_at: 'invalid date')] } } - - it_behaves_like 'no events persisted' - end - end - - describe '`ended_at`' do - context 'is missing and status is resolved' do - let(:alerts_payload) { { 'alerts' => [alert_payload(ended_at: nil, status: 'resolved')] } } - - it_behaves_like 'no events persisted' - end - - context 'is invalid and status is resolved' do - let(:alerts_payload) { { 'alerts' => [alert_payload(ended_at: 'invalid date', status: 'resolved')] } } - - it_behaves_like 'no events persisted' - end - end - - describe '`labels`' do - describe '`gitlab_alert_id`' do - context 'is missing' do - let(:alerts_payload) { { 'alerts' => [alert_payload(gitlab_alert_id: nil)] } } - - it_behaves_like 'no events persisted' - end - - context 'is missing but title is given' do - let(:alerts_payload) { { 'alerts' => [alert_payload(gitlab_alert_id: nil, title: 'alert')] } } - - it_behaves_like 'self managed events persisted' - end - - context 'is missing and environment name is given' do - let(:environment) { create(:environment, project: project) } - let(:alerts_payload) { { 'alerts' => [alert_payload(gitlab_alert_id: nil, title: 'alert', environment: environment.name)] } } - - it_behaves_like 'self managed events persisted' - - it 'associates the environment to the alert event' do - service.execute - - expect(SelfManagedPrometheusAlertEvent.last.environment).to eq environment - end - end - - context 'is invalid' do - let(:alerts_payload) { { 'alerts' => [alert_payload(gitlab_alert_id: '-1')] } } - - it_behaves_like 'no events persisted' - end - end - end - end - end - - private - - def alert_payload(status: 'firing', started_at: Time.current, ended_at: Time.current, gitlab_alert_id: alert.prometheus_metric_id, title: nil, environment: nil) - payload = {} - - payload['status'] = status if status - payload['startsAt'] = utc_rfc3339(started_at) if started_at - payload['endsAt'] = utc_rfc3339(ended_at) if ended_at - payload['labels'] = {} - payload['labels']['gitlab_alert_id'] = gitlab_alert_id.to_s if gitlab_alert_id - payload['labels']['alertname'] = title if title - payload['labels']['gitlab_environment_name'] = environment if environment - - payload - end - - # Example: 2018-09-27T18:25:31.079079416Z - def utc_rfc3339(date) - date.utc.rfc3339 - rescue - date - end - - def truncate_to_second(date) - date.change(usec: 0) - end -end diff --git a/spec/services/projects/prometheus/alerts/create_service_spec.rb b/spec/services/projects/prometheus/alerts/create_service_spec.rb index 50c776df734..c0bc9336558 100644 --- a/spec/services/projects/prometheus/alerts/create_service_spec.rb +++ b/spec/services/projects/prometheus/alerts/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::Prometheus::Alerts::CreateService do +RSpec.describe Projects::Prometheus::Alerts::CreateService do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } diff --git a/spec/services/projects/prometheus/alerts/destroy_service_spec.rb b/spec/services/projects/prometheus/alerts/destroy_service_spec.rb index 7205ace8308..573711051b7 100644 --- a/spec/services/projects/prometheus/alerts/destroy_service_spec.rb +++ b/spec/services/projects/prometheus/alerts/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::Prometheus::Alerts::DestroyService do +RSpec.describe Projects::Prometheus::Alerts::DestroyService do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } let_it_be(:alert) { create(:prometheus_alert, project: project) } diff --git a/spec/services/projects/prometheus/alerts/notify_service_spec.rb b/spec/services/projects/prometheus/alerts/notify_service_spec.rb index 95acedb1e76..aae257e3e3a 100644 --- a/spec/services/projects/prometheus/alerts/notify_service_spec.rb +++ b/spec/services/projects/prometheus/alerts/notify_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::Prometheus::Alerts::NotifyService do +RSpec.describe Projects::Prometheus::Alerts::NotifyService do include PrometheusHelpers let_it_be(:project, reload: true) { create(:project) } @@ -36,48 +36,8 @@ describe Projects::Prometheus::Alerts::NotifyService do end end - shared_examples 'processes incident issues' do |amount| - let(:create_incident_service) { spy } - - it 'processes issues' do - expect(IncidentManagement::ProcessPrometheusAlertWorker) - .to receive(:perform_async) - .with(project.id, kind_of(Hash)) - .exactly(amount).times - - Sidekiq::Testing.inline! do - expect(subject).to be_success - end - end - end - - shared_examples 'does not process incident issues' do - it 'does not process issues' do - expect(IncidentManagement::ProcessPrometheusAlertWorker) - .not_to receive(:perform_async) - - expect(subject).to be_success - end - end - - shared_examples 'persists events' do - let(:create_events_service) { spy } - - it 'persists events' do - expect(Projects::Prometheus::Alerts::CreateEventsService) - .to receive(:new) - .and_return(create_events_service) - - expect(create_events_service) - .to receive(:execute) - - expect(subject).to be_success - end - end - shared_examples 'notifies alerts' do it_behaves_like 'sends notification email' - it_behaves_like 'persists events' end shared_examples 'no notifications' do |http_status:| @@ -102,6 +62,41 @@ describe Projects::Prometheus::Alerts::NotifyService do let(:payload_alert_firing) { payload_raw['alerts'].first } let(:token) { 'token' } + context 'with environment specific clusters' do + let(:prd_cluster) do + cluster + end + + let(:stg_cluster) do + create(:cluster, :provided_by_user, projects: [project], enabled: true, environment_scope: 'stg/*') + end + + let(:stg_environment) do + create(:environment, project: project, name: 'stg/1') + end + + let(:alert_firing) do + create(:prometheus_alert, project: project, environment: stg_environment) + end + + before do + create(:clusters_applications_prometheus, :installed, + cluster: prd_cluster, alert_manager_token: token) + create(:clusters_applications_prometheus, :installed, + cluster: stg_cluster, alert_manager_token: nil) + end + + context 'without token' do + let(:token_input) { nil } + + it_behaves_like 'notifies alerts' + end + + context 'with token' do + it_behaves_like 'no notifications', http_status: :unauthorized + end + end + context 'with project specific cluster' do using RSpec::Parameterized::TableSyntax @@ -222,8 +217,6 @@ describe Projects::Prometheus::Alerts::NotifyService do context 'when incident_management_setting does not exist' do let!(:setting) { nil } - it_behaves_like 'persists events' - it 'does not send notification email', :sidekiq_might_not_need_inline do expect_any_instance_of(NotificationService) .not_to receive(:async) @@ -241,8 +234,6 @@ describe Projects::Prometheus::Alerts::NotifyService do create(:project_incident_management_setting, send_email: false, project: project) end - it_behaves_like 'persists events' - it 'does not send notification' do expect(NotificationService).not_to receive(:new) @@ -276,45 +267,6 @@ describe Projects::Prometheus::Alerts::NotifyService do end end end - - context 'process incident issues' do - before do - create(:prometheus_service, project: project) - create(:project_alerting_setting, project: project, token: token) - end - - context 'with create_issue setting enabled' do - before do - setting.update!(create_issue: true) - end - - it_behaves_like 'processes incident issues', 2 - - context 'multiple firing alerts' do - let(:payload_raw) do - prometheus_alert_payload(firing: [alert_firing, alert_firing], resolved: []) - end - - it_behaves_like 'processes incident issues', 2 - end - - context 'without firing alerts' do - let(:payload_raw) do - prometheus_alert_payload(firing: [], resolved: [alert_resolved]) - end - - it_behaves_like 'processes incident issues', 1 - end - end - - context 'with create_issue setting disabled' do - before do - setting.update!(create_issue: false) - end - - it_behaves_like 'does not process incident issues' - end - end end context 'with invalid payload' do @@ -345,13 +297,6 @@ describe Projects::Prometheus::Alerts::NotifyService do subject end - - it 'does not process issues' do - expect(IncidentManagement::ProcessPrometheusAlertWorker) - .not_to receive(:perform_async) - - subject - end end end diff --git a/spec/services/projects/prometheus/alerts/update_service_spec.rb b/spec/services/projects/prometheus/alerts/update_service_spec.rb index 8a99c2679f7..e831d001838 100644 --- a/spec/services/projects/prometheus/alerts/update_service_spec.rb +++ b/spec/services/projects/prometheus/alerts/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::Prometheus::Alerts::UpdateService do +RSpec.describe Projects::Prometheus::Alerts::UpdateService do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } let_it_be(:environment) { create(:environment, project: project) } diff --git a/spec/services/projects/prometheus/metrics/destroy_service_spec.rb b/spec/services/projects/prometheus/metrics/destroy_service_spec.rb index 81fce82cf46..17cc88b27b6 100644 --- a/spec/services/projects/prometheus/metrics/destroy_service_spec.rb +++ b/spec/services/projects/prometheus/metrics/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::Prometheus::Metrics::DestroyService do +RSpec.describe Projects::Prometheus::Metrics::DestroyService do let(:metric) { create(:prometheus_metric) } subject { described_class.new(metric) } diff --git a/spec/services/projects/prometheus/metrics/update_service_spec.rb b/spec/services/projects/prometheus/metrics/update_service_spec.rb index a53c6ae37cd..bf87093150c 100644 --- a/spec/services/projects/prometheus/metrics/update_service_spec.rb +++ b/spec/services/projects/prometheus/metrics/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::Prometheus::Metrics::UpdateService do +RSpec.describe Projects::Prometheus::Metrics::UpdateService do let(:metric) { create(:prometheus_metric) } it 'updates the prometheus metric' do diff --git a/spec/services/projects/propagate_service_template_spec.rb b/spec/services/projects/propagate_service_template_spec.rb index ddc27c037f8..266bf2cc213 100644 --- a/spec/services/projects/propagate_service_template_spec.rb +++ b/spec/services/projects/propagate_service_template_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::PropagateServiceTemplate do +RSpec.describe Projects::PropagateServiceTemplate do describe '.propagate' do let!(:service_template) do PushoverService.create( diff --git a/spec/services/projects/protect_default_branch_service_spec.rb b/spec/services/projects/protect_default_branch_service_spec.rb index c0b819ab17b..a485a64ca35 100644 --- a/spec/services/projects/protect_default_branch_service_spec.rb +++ b/spec/services/projects/protect_default_branch_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::ProtectDefaultBranchService do +RSpec.describe Projects::ProtectDefaultBranchService do let(:service) { described_class.new(project) } let(:project) { create(:project) } diff --git a/spec/services/projects/repository_languages_service_spec.rb b/spec/services/projects/repository_languages_service_spec.rb index 46c5095327d..cb61a7a1a3e 100644 --- a/spec/services/projects/repository_languages_service_spec.rb +++ b/spec/services/projects/repository_languages_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::RepositoryLanguagesService do +RSpec.describe Projects::RepositoryLanguagesService do let(:service) { described_class.new(project, project.owner) } context 'when detected_repository_languages flag is set' do diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 0e2431c0e44..72426a6f6ec 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::TransferService do +RSpec.describe Projects::TransferService do include GitHelpers let(:user) { create(:user) } diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb index a6bdc69cdca..6a2c55a5e55 100644 --- a/spec/services/projects/unlink_fork_service_spec.rb +++ b/spec/services/projects/unlink_fork_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::UnlinkForkService, :use_clean_rails_memory_store_caching do +RSpec.describe Projects::UnlinkForkService, :use_clean_rails_memory_store_caching do include ProjectForksHelper subject { described_class.new(forked_project, user) } @@ -53,6 +53,7 @@ describe Projects::UnlinkForkService, :use_clean_rails_memory_store_caching do expect(source.forks_count).to eq(1) subject.execute + BatchLoader::Executor.clear_current expect(source.forks_count).to be_zero end @@ -146,6 +147,7 @@ describe Projects::UnlinkForkService, :use_clean_rails_memory_store_caching do expect(project.forks_count).to eq(2) subject.execute + BatchLoader::Executor.clear_current expect(project.forks_count).to be_zero end @@ -212,6 +214,7 @@ describe Projects::UnlinkForkService, :use_clean_rails_memory_store_caching do expect(forked_project.forks_count).to eq(1) subject.execute + BatchLoader::Executor.clear_current expect(project.forks_count).to eq(1) expect(forked_project.forks_count).to eq(0) diff --git a/spec/services/projects/update_pages_configuration_service_spec.rb b/spec/services/projects/update_pages_configuration_service_spec.rb index 363d3df0f84..c4c9fc779fa 100644 --- a/spec/services/projects/update_pages_configuration_service_spec.rb +++ b/spec/services/projects/update_pages_configuration_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::UpdatePagesConfigurationService do +RSpec.describe Projects::UpdatePagesConfigurationService do let(:project) { create(:project) } let(:service) { described_class.new(project) } diff --git a/spec/services/projects/update_pages_service_spec.rb b/spec/services/projects/update_pages_service_spec.rb index 29c3c300d1b..2e02cb56668 100644 --- a/spec/services/projects/update_pages_service_spec.rb +++ b/spec/services/projects/update_pages_service_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" -describe Projects::UpdatePagesService do +RSpec.describe Projects::UpdatePagesService do let_it_be(:project, refind: true) { create(:project, :repository) } let_it_be(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit('HEAD').sha) } let(:build) { create(:ci_build, pipeline: pipeline, ref: 'HEAD') } diff --git a/spec/services/projects/update_remote_mirror_service_spec.rb b/spec/services/projects/update_remote_mirror_service_spec.rb index 418973fb0a6..f0a8074f46c 100644 --- a/spec/services/projects/update_remote_mirror_service_spec.rb +++ b/spec/services/projects/update_remote_mirror_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::UpdateRemoteMirrorService do +RSpec.describe Projects::UpdateRemoteMirrorService do let(:project) { create(:project, :repository) } let(:remote_project) { create(:forked_project_with_submodules) } let(:remote_mirror) { create(:remote_mirror, project: project, enabled: true) } diff --git a/spec/services/projects/update_repository_storage_service_spec.rb b/spec/services/projects/update_repository_storage_service_spec.rb index e37580e7367..57e02c26b71 100644 --- a/spec/services/projects/update_repository_storage_service_spec.rb +++ b/spec/services/projects/update_repository_storage_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::UpdateRepositoryStorageService do +RSpec.describe Projects::UpdateRepositoryStorageService do include Gitlab::ShellAdapter subject { described_class.new(repository_storage_move) } @@ -37,14 +37,15 @@ describe Projects::UpdateRepositoryStorageService do project.repository.path_to_repo end - expect(project_repository_double).to receive(:create_repository) - .and_return(true) expect(project_repository_double).to receive(:replicate) .with(project.repository.raw) expect(project_repository_double).to receive(:checksum) .and_return(checksum) + expect(GitlabShellWorker).to receive(:perform_async).with(:mv_repository, 'default', anything, anything) + .and_call_original result = subject.execute + project.reload expect(result).to be_success expect(project).not_to be_repository_read_only @@ -70,8 +71,6 @@ describe Projects::UpdateRepositoryStorageService do allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('default').and_call_original allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('test_second_storage').and_return(SecureRandom.uuid) - expect(project_repository_double).to receive(:create_repository) - .and_return(true) expect(project_repository_double).to receive(:replicate) .with(project.repository.raw) .and_raise(Gitlab::Git::CommandError) @@ -90,8 +89,6 @@ describe Projects::UpdateRepositoryStorageService do allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('default').and_call_original allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('test_second_storage').and_return(SecureRandom.uuid) - expect(project_repository_double).to receive(:create_repository) - .and_return(true) expect(project_repository_double).to receive(:replicate) .with(project.repository.raw) expect(project_repository_double).to receive(:checksum) @@ -113,20 +110,43 @@ describe Projects::UpdateRepositoryStorageService do allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('default').and_call_original allow(Gitlab::GitalyClient).to receive(:filesystem_id).with('test_second_storage').and_return(SecureRandom.uuid) - expect(project_repository_double).to receive(:create_repository) - .and_return(true) expect(project_repository_double).to receive(:replicate) .with(project.repository.raw) expect(project_repository_double).to receive(:checksum) .and_return(checksum) result = subject.execute + project.reload expect(result).to be_success expect(project.repository_storage).to eq('test_second_storage') expect(project.reload_pool_repository).to be_nil end end + + context 'when the repository move is finished' do + let(:repository_storage_move) { create(:project_repository_storage_move, :finished, project: project, destination_storage_name: destination) } + + it 'is idempotent' do + expect do + result = subject.execute + + expect(result).to be_success + end.not_to change(repository_storage_move, :state) + end + end + + context 'when the repository move is failed' do + let(:repository_storage_move) { create(:project_repository_storage_move, :failed, project: project, destination_storage_name: destination) } + + it 'is idempotent' do + expect do + result = subject.execute + + expect(result).to be_success + end.not_to change(repository_storage_move, :state) + end + end end context 'with wiki repository' do diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb index 8a17884f641..6620ee6e697 100644 --- a/spec/services/projects/update_service_spec.rb +++ b/spec/services/projects/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::UpdateService do +RSpec.describe Projects::UpdateService do include ExternalAuthorizationServiceHelpers include ProjectForksHelper diff --git a/spec/services/projects/update_statistics_service_spec.rb b/spec/services/projects/update_statistics_service_spec.rb index 8534853fbc7..92e97186be3 100644 --- a/spec/services/projects/update_statistics_service_spec.rb +++ b/spec/services/projects/update_statistics_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Projects::UpdateStatisticsService do +RSpec.describe Projects::UpdateStatisticsService do let(:service) { described_class.new(project, nil, statistics: statistics)} let(:statistics) { %w(repository_size) } diff --git a/spec/services/prometheus/create_default_alerts_service_spec.rb b/spec/services/prometheus/create_default_alerts_service_spec.rb index a28c38491de..e149161d881 100644 --- a/spec/services/prometheus/create_default_alerts_service_spec.rb +++ b/spec/services/prometheus/create_default_alerts_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Prometheus::CreateDefaultAlertsService do +RSpec.describe Prometheus::CreateDefaultAlertsService do let_it_be(:project) { create(:project, :repository) } let(:instance) { described_class.new(project: project) } let(:expected_alerts) { described_class::DEFAULT_ALERTS } diff --git a/spec/services/prometheus/proxy_service_spec.rb b/spec/services/prometheus/proxy_service_spec.rb index bd451ff00a1..f22ea361fde 100644 --- a/spec/services/prometheus/proxy_service_spec.rb +++ b/spec/services/prometheus/proxy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Prometheus::ProxyService do +RSpec.describe Prometheus::ProxyService do include ReactiveCachingHelpers let_it_be(:project) { create(:project) } diff --git a/spec/services/prometheus/proxy_variable_substitution_service_spec.rb b/spec/services/prometheus/proxy_variable_substitution_service_spec.rb index 2435dda07b4..d8c1fdffb98 100644 --- a/spec/services/prometheus/proxy_variable_substitution_service_spec.rb +++ b/spec/services/prometheus/proxy_variable_substitution_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Prometheus::ProxyVariableSubstitutionService do +RSpec.describe Prometheus::ProxyVariableSubstitutionService do describe '#execute' do let_it_be(:environment) { create(:environment) } diff --git a/spec/services/protected_branches/create_service_spec.rb b/spec/services/protected_branches/create_service_spec.rb index 82d24ec43f6..986322e4d87 100644 --- a/spec/services/protected_branches/create_service_spec.rb +++ b/spec/services/protected_branches/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ProtectedBranches::CreateService do +RSpec.describe ProtectedBranches::CreateService do let(:project) { create(:project) } let(:user) { project.owner } let(:params) do diff --git a/spec/services/protected_branches/destroy_service_spec.rb b/spec/services/protected_branches/destroy_service_spec.rb index 3287eb9a59b..98d31147754 100644 --- a/spec/services/protected_branches/destroy_service_spec.rb +++ b/spec/services/protected_branches/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ProtectedBranches::DestroyService do +RSpec.describe ProtectedBranches::DestroyService do let(:protected_branch) { create(:protected_branch) } let(:project) { protected_branch.project } let(:user) { project.owner } diff --git a/spec/services/protected_branches/update_service_spec.rb b/spec/services/protected_branches/update_service_spec.rb index 7967ff81075..fdfbdf2e6ae 100644 --- a/spec/services/protected_branches/update_service_spec.rb +++ b/spec/services/protected_branches/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ProtectedBranches::UpdateService do +RSpec.describe ProtectedBranches::UpdateService do let(:protected_branch) { create(:protected_branch) } let(:project) { protected_branch.project } let(:user) { project.owner } diff --git a/spec/services/protected_tags/create_service_spec.rb b/spec/services/protected_tags/create_service_spec.rb index e58a539eb6f..e85a43eb51c 100644 --- a/spec/services/protected_tags/create_service_spec.rb +++ b/spec/services/protected_tags/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ProtectedTags::CreateService do +RSpec.describe ProtectedTags::CreateService do let(:project) { create(:project) } let(:user) { project.owner } let(:params) do diff --git a/spec/services/protected_tags/destroy_service_spec.rb b/spec/services/protected_tags/destroy_service_spec.rb index 52d1d1caa34..fbd1452a8d1 100644 --- a/spec/services/protected_tags/destroy_service_spec.rb +++ b/spec/services/protected_tags/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ProtectedTags::DestroyService do +RSpec.describe ProtectedTags::DestroyService do let(:protected_tag) { create(:protected_tag) } let(:project) { protected_tag.project } let(:user) { project.owner } diff --git a/spec/services/protected_tags/update_service_spec.rb b/spec/services/protected_tags/update_service_spec.rb index ca5109aca9c..ed151ca2347 100644 --- a/spec/services/protected_tags/update_service_spec.rb +++ b/spec/services/protected_tags/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ProtectedTags::UpdateService do +RSpec.describe ProtectedTags::UpdateService do let(:protected_tag) { create(:protected_tag) } let(:project) { protected_tag.project } let(:user) { project.owner } diff --git a/spec/services/push_event_payload_service_spec.rb b/spec/services/push_event_payload_service_spec.rb index 855b10c0259..de2bec21a3c 100644 --- a/spec/services/push_event_payload_service_spec.rb +++ b/spec/services/push_event_payload_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe PushEventPayloadService do +RSpec.describe PushEventPayloadService do let(:event) { create(:push_event) } describe '#execute' do diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index 1bd402e38be..57e32b1aea9 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe QuickActions::InterpretService do +RSpec.describe QuickActions::InterpretService do let(:project) { create(:project, :public) } let(:developer) { create(:user) } let(:developer2) { create(:user) } @@ -792,7 +792,7 @@ describe QuickActions::InterpretService do let(:issuable) { issue } end - it_behaves_like 'assign command', :quarantine do + it_behaves_like 'assign command', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/27989' do let(:content) { "/assign @#{developer.username} @#{developer2.username}" } let(:issuable) { merge_request } end diff --git a/spec/services/quick_actions/target_service_spec.rb b/spec/services/quick_actions/target_service_spec.rb index 0aeb29cbeec..d960678f809 100644 --- a/spec/services/quick_actions/target_service_spec.rb +++ b/spec/services/quick_actions/target_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe QuickActions::TargetService do +RSpec.describe QuickActions::TargetService do let(:project) { create(:project) } let(:user) { create(:user) } let(:service) { described_class.new(project, user) } diff --git a/spec/services/releases/create_evidence_service_spec.rb b/spec/services/releases/create_evidence_service_spec.rb index caa36a6b21d..818d20f0468 100644 --- a/spec/services/releases/create_evidence_service_spec.rb +++ b/spec/services/releases/create_evidence_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Releases::CreateEvidenceService do +RSpec.describe Releases::CreateEvidenceService do let_it_be(:project) { create(:project) } let(:release) { create(:release, project: project) } let(:service) { described_class.new(release) } diff --git a/spec/services/releases/create_service_spec.rb b/spec/services/releases/create_service_spec.rb index 4e3d9d5f108..3c0698aa203 100644 --- a/spec/services/releases/create_service_spec.rb +++ b/spec/services/releases/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Releases::CreateService do +RSpec.describe Releases::CreateService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:tag_name) { project.repository.tag_names.first } diff --git a/spec/services/releases/destroy_service_spec.rb b/spec/services/releases/destroy_service_spec.rb index 9d027767cd2..bc5bff0b31d 100644 --- a/spec/services/releases/destroy_service_spec.rb +++ b/spec/services/releases/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Releases::DestroyService do +RSpec.describe Releases::DestroyService do let(:project) { create(:project, :repository) } let(:mainatiner) { create(:user) } let(:repoter) { create(:user) } diff --git a/spec/services/releases/update_service_spec.rb b/spec/services/releases/update_service_spec.rb index 7f1849e39a4..00544b820cb 100644 --- a/spec/services/releases/update_service_spec.rb +++ b/spec/services/releases/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Releases::UpdateService do +RSpec.describe Releases::UpdateService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:new_name) { 'A new name' } diff --git a/spec/services/repositories/destroy_rollback_service_spec.rb b/spec/services/repositories/destroy_rollback_service_spec.rb index c3cdae17de7..9cc41a4c7f8 100644 --- a/spec/services/repositories/destroy_rollback_service_spec.rb +++ b/spec/services/repositories/destroy_rollback_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Repositories::DestroyRollbackService do +RSpec.describe Repositories::DestroyRollbackService do let_it_be(:user) { create(:user) } let!(:project) { create(:project, :repository, namespace: user.namespace) } let(:repository) { project.repository } diff --git a/spec/services/repositories/destroy_service_spec.rb b/spec/services/repositories/destroy_service_spec.rb index 9c2694483c1..30ec84b44e7 100644 --- a/spec/services/repositories/destroy_service_spec.rb +++ b/spec/services/repositories/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Repositories::DestroyService do +RSpec.describe Repositories::DestroyService do let_it_be(:user) { create(:user) } let!(:project) { create(:project, :repository, namespace: user.namespace) } let(:repository) { project.repository } @@ -34,6 +34,21 @@ describe Repositories::DestroyService do project.touch end + context 'on a read-only instance' do + before do + allow(Gitlab::Database).to receive(:read_only?).and_return(true) + end + + it 'schedules the repository deletion' do + expect(Repositories::ShellDestroyService).to receive(:new).with(repository).and_call_original + + expect(GitlabShellWorker).to receive(:perform_in) + .with(Repositories::ShellDestroyService::REPO_REMOVAL_DELAY, :remove_repository, project.repository_storage, remove_path) + + subject + end + end + it 'removes the repository', :sidekiq_inline do subject diff --git a/spec/services/repositories/shell_destroy_service_spec.rb b/spec/services/repositories/shell_destroy_service_spec.rb index 9419977f6fe..9020ef7b209 100644 --- a/spec/services/repositories/shell_destroy_service_spec.rb +++ b/spec/services/repositories/shell_destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Repositories::ShellDestroyService do +RSpec.describe Repositories::ShellDestroyService do let_it_be(:user) { create(:user) } let!(:project) { create(:project, :repository, namespace: user.namespace) } let(:path) { project.repository.disk_path } diff --git a/spec/services/repository_archive_clean_up_service_spec.rb b/spec/services/repository_archive_clean_up_service_spec.rb index 80b177a0174..c6d673fb1b5 100644 --- a/spec/services/repository_archive_clean_up_service_spec.rb +++ b/spec/services/repository_archive_clean_up_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe RepositoryArchiveCleanUpService do +RSpec.describe RepositoryArchiveCleanUpService do subject(:service) { described_class.new } describe '#execute (new archive locations)' do diff --git a/spec/services/reset_project_cache_service_spec.rb b/spec/services/reset_project_cache_service_spec.rb index a4db4481c36..3e79270da8d 100644 --- a/spec/services/reset_project_cache_service_spec.rb +++ b/spec/services/reset_project_cache_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ResetProjectCacheService do +RSpec.describe ResetProjectCacheService do let(:project) { create(:project) } let(:user) { create(:user) } diff --git a/spec/services/resource_access_tokens/create_service_spec.rb b/spec/services/resource_access_tokens/create_service_spec.rb index 57e7e4e66de..f22c379cd30 100644 --- a/spec/services/resource_access_tokens/create_service_spec.rb +++ b/spec/services/resource_access_tokens/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ResourceAccessTokens::CreateService do +RSpec.describe ResourceAccessTokens::CreateService do subject { described_class.new(user, resource, params).execute } let_it_be(:user) { create(:user) } @@ -45,6 +45,27 @@ describe ResourceAccessTokens::CreateService do expect(access_token.user.reload.user_type).to eq("#{resource_type}_bot") end + context 'email confirmation status' do + shared_examples_for 'creates a user that has their email confirmed' do + it 'creates a user that has their email confirmed' do + response = subject + access_token = response.payload[:access_token] + + expect(access_token.user.reload.confirmed?).to eq(true) + end + end + + context 'when created by an admin' do + it_behaves_like 'creates a user that has their email confirmed' do + let(:user) { create(:admin) } + end + end + + context 'when created by a non-admin' do + it_behaves_like 'creates a user that has their email confirmed' + end + end + context 'bot name' do context 'when no value is passed' do it 'uses default value' do diff --git a/spec/services/resource_access_tokens/revoke_service_spec.rb b/spec/services/resource_access_tokens/revoke_service_spec.rb index 3ce82745b9e..ffc06d770f8 100644 --- a/spec/services/resource_access_tokens/revoke_service_spec.rb +++ b/spec/services/resource_access_tokens/revoke_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ResourceAccessTokens::RevokeService do +RSpec.describe ResourceAccessTokens::RevokeService do subject { described_class.new(user, resource, access_token).execute } let_it_be(:user) { create(:user) } diff --git a/spec/services/resource_events/change_labels_service_spec.rb b/spec/services/resource_events/change_labels_service_spec.rb index 2b987b7fec9..efee185669e 100644 --- a/spec/services/resource_events/change_labels_service_spec.rb +++ b/spec/services/resource_events/change_labels_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ResourceEvents::ChangeLabelsService do +RSpec.describe ResourceEvents::ChangeLabelsService do let_it_be(:project) { create(:project) } let_it_be(:author) { create(:user) } let(:resource) { create(:issue, project: project) } diff --git a/spec/services/resource_events/change_milestone_service_spec.rb b/spec/services/resource_events/change_milestone_service_spec.rb index dec01d0db8d..9c0f9420f7a 100644 --- a/spec/services/resource_events/change_milestone_service_spec.rb +++ b/spec/services/resource_events/change_milestone_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ResourceEvents::ChangeMilestoneService do +RSpec.describe ResourceEvents::ChangeMilestoneService do [:issue, :merge_request].each do |issuable| it_behaves_like 'a milestone events creator' do let(:resource) { create(issuable) } diff --git a/spec/services/resource_events/change_state_service_spec.rb b/spec/services/resource_events/change_state_service_spec.rb index e5d2a4ab11e..5b5379b241b 100644 --- a/spec/services/resource_events/change_state_service_spec.rb +++ b/spec/services/resource_events/change_state_service_spec.rb @@ -2,38 +2,95 @@ require 'spec_helper' -describe ResourceEvents::ChangeStateService do +RSpec.describe ResourceEvents::ChangeStateService do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } let(:issue) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, source_project: project) } + let(:source_commit) { create(:commit, project: project) } + let(:source_merge_request) { create(:merge_request, source_project: project, target_project: project, target_branch: 'foo') } - describe '#execute' do - context 'when resource is an issue' do - %w[opened reopened closed locked].each do |state| - it "creates the expected event if issue has #{state} state" do - described_class.new(user: user, resource: issue).execute(state) + shared_examples 'a state event' do + %w[opened reopened closed locked].each do |state| + it "creates the expected event if resource has #{state} state" do + described_class.new(user: user, resource: resource).execute(status: state, mentionable_source: source) + + event = resource.resource_state_events.last - event = issue.resource_state_events.last - expect(event.issue).to eq(issue) + if resource.is_a?(Issue) + expect(event.issue).to eq(resource) expect(event.merge_request).to be_nil - expect(event.state).to eq(state) + elsif resource.is_a?(MergeRequest) + expect(event.issue).to be_nil + expect(event.merge_request).to eq(resource) end + + expect(event.state).to eq(state) + + expect_event_source(event, source) end end + end - context 'when resource is a merge request' do - %w[opened reopened closed locked merged].each do |state| - it "creates the expected event if merge request has #{state} state" do - described_class.new(user: user, resource: merge_request).execute(state) + describe '#execute' do + context 'when resource is an Issue' do + context 'when no source is given' do + it_behaves_like 'a state event' do + let(:resource) { issue } + let(:source) { nil } + end + end - event = merge_request.resource_state_events.last - expect(event.issue).to be_nil - expect(event.merge_request).to eq(merge_request) - expect(event.state).to eq(state) + context 'when source commit is given' do + it_behaves_like 'a state event' do + let(:resource) { issue } + let(:source) { source_commit } + end + end + + context 'when source merge request is given' do + it_behaves_like 'a state event' do + let(:resource) { issue } + let(:source) { source_merge_request } end end end + + context 'when resource is a MergeRequest' do + context 'when no source is given' do + it_behaves_like 'a state event' do + let(:resource) { merge_request } + let(:source) { nil } + end + end + + context 'when source commit is given' do + it_behaves_like 'a state event' do + let(:resource) { merge_request } + let(:source) { source_commit } + end + end + + context 'when source merge request is given' do + it_behaves_like 'a state event' do + let(:resource) { merge_request } + let(:source) { source_merge_request } + end + end + end + end + + def expect_event_source(event, source) + if source.is_a?(MergeRequest) + expect(event.source_commit).to be_nil + expect(event.source_merge_request).to eq(source) + elsif source.is_a?(Commit) + expect(event.source_commit).to eq(source.id) + expect(event.source_merge_request).to be_nil + else + expect(event.source_merge_request).to be_nil + expect(event.source_commit).to be_nil + end 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 2664a27244d..6209294f4ce 100644 --- a/spec/services/resource_events/merge_into_notes_service_spec.rb +++ b/spec/services/resource_events/merge_into_notes_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ResourceEvents::MergeIntoNotesService do +RSpec.describe ResourceEvents::MergeIntoNotesService do def create_event(params) event_params = { action: :add, label: label, issue: resource, user: user } @@ -61,7 +61,7 @@ describe ResourceEvents::MergeIntoNotesService do event = create_event(created_at: 1.day.ago) notes = described_class.new(resource, user, - last_fetched_at: 2.days.ago.to_i).execute + last_fetched_at: 2.days.ago).execute expect(notes.count).to eq 1 expect(notes.first.discussion_id).to eq event.discussion_id diff --git a/spec/services/resource_events/synthetic_label_notes_builder_service_spec.rb b/spec/services/resource_events/synthetic_label_notes_builder_service_spec.rb index 41902bc1da1..cb42ad5b617 100644 --- a/spec/services/resource_events/synthetic_label_notes_builder_service_spec.rb +++ b/spec/services/resource_events/synthetic_label_notes_builder_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ResourceEvents::SyntheticLabelNotesBuilderService do +RSpec.describe ResourceEvents::SyntheticLabelNotesBuilderService do describe '#execute' do let!(:user) { create(:user) } diff --git a/spec/services/resource_events/synthetic_milestone_notes_builder_service_spec.rb b/spec/services/resource_events/synthetic_milestone_notes_builder_service_spec.rb index e98b8bd00dc..5e3afeabee7 100644 --- a/spec/services/resource_events/synthetic_milestone_notes_builder_service_spec.rb +++ b/spec/services/resource_events/synthetic_milestone_notes_builder_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ResourceEvents::SyntheticMilestoneNotesBuilderService do +RSpec.describe ResourceEvents::SyntheticMilestoneNotesBuilderService do describe '#execute' do let_it_be(:user) { create(:user) } let_it_be(:issue) { create(:issue, author: user) } diff --git a/spec/services/search/global_service_spec.rb b/spec/services/search/global_service_spec.rb index 0f829df90b3..90ad18e5571 100644 --- a/spec/services/search/global_service_spec.rb +++ b/spec/services/search/global_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Search::GlobalService do +RSpec.describe Search::GlobalService do let(:user) { create(:user) } let(:internal_user) { create(:user) } diff --git a/spec/services/search/group_service_spec.rb b/spec/services/search/group_service_spec.rb index cfb672753b8..d3026d158d4 100644 --- a/spec/services/search/group_service_spec.rb +++ b/spec/services/search/group_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Search::GroupService do +RSpec.describe Search::GroupService do shared_examples_for 'group search' do context 'finding projects by name' do let(:user) { create(:user) } diff --git a/spec/services/search/snippet_service_spec.rb b/spec/services/search/snippet_service_spec.rb index cb2bb0c43fd..ceaf3d055bf 100644 --- a/spec/services/search/snippet_service_spec.rb +++ b/spec/services/search/snippet_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Search::SnippetService do +RSpec.describe Search::SnippetService do let_it_be(:author) { create(:author) } let_it_be(:project) { create(:project, :public) } diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb index 0333eb85fb6..52aef73ac77 100644 --- a/spec/services/search_service_spec.rb +++ b/spec/services/search_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe SearchService do +RSpec.describe SearchService do let_it_be(:user) { create(:user) } let_it_be(:accessible_group) { create(:group, :private) } diff --git a/spec/services/serverless/associate_domain_service_spec.rb b/spec/services/serverless/associate_domain_service_spec.rb index 3d1a878bcf5..3b5231989bc 100644 --- a/spec/services/serverless/associate_domain_service_spec.rb +++ b/spec/services/serverless/associate_domain_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Serverless::AssociateDomainService do +RSpec.describe Serverless::AssociateDomainService do subject { described_class.new(knative, pages_domain_id: pages_domain_id, creator: creator) } let(:sdc) { create(:serverless_domain_cluster, pages_domain: create(:pages_domain, :instance_serverless)) } diff --git a/spec/services/service_desk_settings/update_service_spec.rb b/spec/services/service_desk_settings/update_service_spec.rb new file mode 100644 index 00000000000..8b920d536b4 --- /dev/null +++ b/spec/services/service_desk_settings/update_service_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe ServiceDeskSettings::UpdateService do + describe '#execute' do + let_it_be(:settings) { create(:service_desk_setting, outgoing_name: 'original name') } + let_it_be(:user) { create(:user) } + + context 'with valid params' do + let(:params) { { outgoing_name: 'some name', project_key: 'foo' } } + + it 'updates service desk settings' do + result = described_class.new(settings.project, user, params).execute + + expect(result[:status]).to eq :success + expect(settings.reload.outgoing_name).to eq 'some name' + expect(settings.reload.project_key).to eq 'foo' + end + + context 'when service_desk_custom_address is disabled' do + before do + stub_feature_flags(service_desk_custom_address: false) + end + + it 'ignores project_key parameter' do + result = described_class.new(settings.project, user, params).execute + + expect(result[:status]).to eq :success + expect(settings.reload.project_key).to be_nil + end + end + end + + context 'with invalid params' do + let(:params) { { outgoing_name: 'x' * 256 } } + + it 'does not update service desk settings' do + result = described_class.new(settings.project, user, params).execute + + expect(result[:status]).to eq :error + expect(result[:message]).to eq 'Outgoing name is too long (maximum is 255 characters)' + expect(settings.reload.outgoing_name).to eq 'original name' + end + end + end +end diff --git a/spec/services/service_response_spec.rb b/spec/services/service_response_spec.rb index 2c944a63ebb..986b26e67d7 100644 --- a/spec/services/service_response_spec.rb +++ b/spec/services/service_response_spec.rb @@ -4,7 +4,7 @@ require 'fast_spec_helper' ActiveSupport::Dependencies.autoload_paths << 'app/services' -describe ServiceResponse do +RSpec.describe ServiceResponse do describe '.success' do it 'creates a successful response without a message' do expect(described_class.success).to be_success diff --git a/spec/services/snippets/bulk_destroy_service_spec.rb b/spec/services/snippets/bulk_destroy_service_spec.rb index 6e5623e575f..8a6250a8b45 100644 --- a/spec/services/snippets/bulk_destroy_service_spec.rb +++ b/spec/services/snippets/bulk_destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Snippets::BulkDestroyService do +RSpec.describe Snippets::BulkDestroyService do let_it_be(:project) { create(:project) } let(:user) { create(:user) } let!(:personal_snippet) { create(:personal_snippet, :repository, author: user) } diff --git a/spec/services/snippets/count_service_spec.rb b/spec/services/snippets/count_service_spec.rb index 4137e65dcca..5ce637d0bac 100644 --- a/spec/services/snippets/count_service_spec.rb +++ b/spec/services/snippets/count_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Snippets::CountService do +RSpec.describe Snippets::CountService do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :public) } diff --git a/spec/services/snippets/create_service_spec.rb b/spec/services/snippets/create_service_spec.rb index fa8cbc87563..62eef00b67f 100644 --- a/spec/services/snippets/create_service_spec.rb +++ b/spec/services/snippets/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Snippets::CreateService do +RSpec.describe Snippets::CreateService do describe '#execute' do let_it_be(:user) { create(:user) } let_it_be(:admin) { create(:user, :admin) } @@ -177,10 +177,8 @@ describe Snippets::CreateService do end it 'returns a generic error' do - response = subject - - expect(response).to be_error - expect(response.payload[:snippet].errors[:repository]).to eq ['Error creating the snippet'] + expect(subject).to be_error + expect(snippet.errors[:repository]).to eq ['Error creating the snippet'] end end @@ -230,15 +228,15 @@ describe Snippets::CreateService do end end - shared_examples 'when snippet_files param is present' do + shared_examples 'when snippet_actions param is present' do let(:file_path) { 'snippet_file_path.rb' } let(:content) { 'snippet_content' } - let(:snippet_files) { [{ action: 'create', file_path: file_path, content: content }] } + let(:snippet_actions) { [{ action: 'create', file_path: file_path, content: content }] } let(:base_opts) do { title: 'Test snippet', visibility_level: Gitlab::VisibilityLevel::PRIVATE, - snippet_files: snippet_files + snippet_actions: snippet_actions } end @@ -250,7 +248,7 @@ describe Snippets::CreateService do end it 'commit the files to the repository' do - subject + expect(subject).to be_success blob = snippet.repository.blob_at('master', file_path) @@ -261,28 +259,42 @@ describe Snippets::CreateService do let(:extra_opts) { { content: 'foo', file_name: 'path' } } it 'a validation error is raised' do - response = subject - snippet = response.payload[:snippet] - - expect(response).to be_error + expect(subject).to be_error expect(snippet.errors.full_messages_for(:content)).to eq ['Content and snippet files cannot be used together'] expect(snippet.errors.full_messages_for(:file_name)).to eq ['File name and snippet files cannot be used together'] expect(snippet.repository.exists?).to be_falsey end end - context 'when snippet_files param is invalid' do - let(:snippet_files) { [{ action: 'invalid_action', file_path: 'snippet_file_path.rb', content: 'snippet_content' }] } + context 'when snippet_actions param is invalid' do + let(:snippet_actions) { [{ action: 'invalid_action', file_path: 'snippet_file_path.rb', content: 'snippet_content' }] } it 'a validation error is raised' do - response = subject - snippet = response.payload[:snippet] + expect(subject).to be_error + expect(snippet.errors.full_messages_for(:snippet_actions)).to eq ['Snippet actions have invalid data'] + expect(snippet.repository.exists?).to be_falsey + end + end - expect(response).to be_error - expect(snippet.errors.full_messages_for(:snippet_files)).to eq ['Snippet files have invalid data'] + context 'when snippet_actions contain an action different from "create"' do + let(:snippet_actions) { [{ action: 'delete', file_path: 'snippet_file_path.rb' }] } + + it 'a validation error is raised' do + expect(subject).to be_error + expect(snippet.errors.full_messages_for(:snippet_actions)).to eq ['Snippet actions have invalid data'] expect(snippet.repository.exists?).to be_falsey end end + + context 'when "create" operation does not have file_path or is empty' do + let(:snippet_actions) { [{ action: 'create', content: content }, { action: 'create', content: content, file_path: '' }] } + + it 'generates the file path for the files' do + expect(subject).to be_success + expect(snippet.repository.blob_at('master', 'snippetfile1.txt').data).to eq content + expect(snippet.repository.blob_at('master', 'snippetfile2.txt').data).to eq content + end + end end context 'when ProjectSnippet' do @@ -299,7 +311,7 @@ describe Snippets::CreateService do it_behaves_like 'an error service response when save fails' it_behaves_like 'creates repository and files' it_behaves_like 'after_save callback to store_mentions', ProjectSnippet - it_behaves_like 'when snippet_files param is present' + it_behaves_like 'when snippet_actions param is present' context 'when uploaded files are passed to the service' do let(:extra_opts) { { files: ['foo'] } } @@ -326,7 +338,7 @@ describe Snippets::CreateService do it_behaves_like 'an error service response when save fails' it_behaves_like 'creates repository and files' it_behaves_like 'after_save callback to store_mentions', PersonalSnippet - it_behaves_like 'when snippet_files param is present' + it_behaves_like 'when snippet_actions param is present' context 'when the snippet description contains files' do include FileMoverHelpers diff --git a/spec/services/snippets/destroy_service_spec.rb b/spec/services/snippets/destroy_service_spec.rb index 840dc11a740..e53d00b9ca1 100644 --- a/spec/services/snippets/destroy_service_spec.rb +++ b/spec/services/snippets/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Snippets::DestroyService do +RSpec.describe Snippets::DestroyService do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } let_it_be(:other_user) { create(:user) } @@ -105,6 +105,26 @@ describe Snippets::DestroyService do it_behaves_like 'a successful destroy' it_behaves_like 'deletes the snippet repository' + + context 'project statistics' do + before do + snippet.statistics.refresh! + end + + it 'updates stats after deletion' do + expect(project.reload.statistics.snippets_size).not_to be_zero + + subject + + expect(project.reload.statistics.snippets_size).to be_zero + end + + it 'schedules a namespace statistics update' do + expect(Namespaces::ScheduleAggregationWorker).to receive(:perform_async).with(project.namespace_id).once + + subject + end + end end context 'when user is not able to admin_project_snippet' do @@ -122,6 +142,12 @@ describe Snippets::DestroyService do it_behaves_like 'a successful destroy' it_behaves_like 'deletes the snippet repository' + + it 'schedules a namespace statistics update' do + expect(Namespaces::ScheduleAggregationWorker).to receive(:perform_async).with(author.namespace_id) + + subject + end end context 'when user is not able to admin_personal_snippet' do diff --git a/spec/services/snippets/repository_validation_service_spec.rb b/spec/services/snippets/repository_validation_service_spec.rb index 1c139d8c223..e2a0d0faa18 100644 --- a/spec/services/snippets/repository_validation_service_spec.rb +++ b/spec/services/snippets/repository_validation_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Snippets::RepositoryValidationService do +RSpec.describe Snippets::RepositoryValidationService do describe '#execute' do let_it_be(:user) { create(:user) } let_it_be(:snippet) { create(:personal_snippet, :empty_repo, author: user) } diff --git a/spec/services/snippets/update_service_spec.rb b/spec/services/snippets/update_service_spec.rb index 7e6441ad2f9..66dddcc49de 100644 --- a/spec/services/snippets/update_service_spec.rb +++ b/spec/services/snippets/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Snippets::UpdateService do +RSpec.describe Snippets::UpdateService do describe '#execute' do let_it_be(:user) { create(:user) } let_it_be(:admin) { create :user, admin: true } @@ -302,22 +302,22 @@ describe Snippets::UpdateService do end end - shared_examples 'when snippet_files param is present' do + shared_examples 'when snippet_actions param is present' do let(:file_path) { 'CHANGELOG' } let(:content) { 'snippet_content' } let(:new_title) { 'New title' } - let(:snippet_files) { [{ action: 'update', previous_path: file_path, file_path: file_path, content: content }] } + let(:snippet_actions) { [{ action: 'update', previous_path: file_path, file_path: file_path, content: content }] } let(:base_opts) do { title: new_title, - snippet_files: snippet_files + snippet_actions: snippet_actions } end it 'updates a snippet with the provided attributes' do file_path = 'foo' - snippet_files[0][:action] = 'move' - snippet_files[0][:file_path] = file_path + snippet_actions[0][:action] = 'move' + snippet_actions[0][:file_path] = file_path response = subject snippet = response.payload[:snippet] @@ -328,7 +328,7 @@ describe Snippets::UpdateService do expect(snippet.content).to eq(content) end - it 'commit the files to the repository' do + it 'commits the files to the repository' do subject blob = snippet.repository.blob_at('master', file_path) @@ -349,15 +349,27 @@ describe Snippets::UpdateService do end end - context 'when snippet_files param is invalid' do - let(:snippet_files) { [{ action: 'invalid_action' }] } + context 'when snippet_file content is not present' do + let(:snippet_actions) { [{ action: :move, previous_path: file_path, file_path: 'new_file_path' }] } + + it 'does not update snippet content' do + content = snippet.content + + expect(subject).to be_success + + expect(snippet.reload.content).to eq content + end + end + + context 'when snippet_actions param is invalid' do + let(:snippet_actions) { [{ action: 'invalid_action' }] } it 'raises a validation error' do response = subject snippet = response.payload[:snippet] expect(response).to be_error - expect(snippet.errors.full_messages_for(:snippet_files)).to eq ['Snippet files have invalid data'] + expect(snippet.errors.full_messages_for(:snippet_actions)).to eq ['Snippet actions have invalid data'] end end @@ -376,6 +388,226 @@ describe Snippets::UpdateService do expect(snippet.content).to eq(content) end end + + context 'commit actions' do + let(:new_path) { 'created_new_file' } + let(:base_opts) { { snippet_actions: snippet_actions } } + + shared_examples 'returns an error' do |error_msg| + specify do + response = subject + + expect(response).to be_error + expect(response.message).to eq error_msg + end + end + + context 'update action' do + let(:snippet_actions) { [{ action: :update, file_path: file_path, content: content }] } + + it 'updates the file content' do + expect(subject).to be_success + + blob = blob(file_path) + + expect(blob.data).to eq content + end + + context 'when previous_path is present' do + let(:snippet_actions) { [{ action: :update, previous_path: file_path, file_path: file_path, content: content }] } + + it 'updates the file content' do + expect(subject).to be_success + + blob = blob(file_path) + + expect(blob.data).to eq content + end + end + + context 'when content is not present' do + let(:snippet_actions) { [{ action: :update, file_path: file_path }] } + + it_behaves_like 'returns an error', 'Snippet actions have invalid data' + end + + context 'when file_path does not exist' do + let(:snippet_actions) { [{ action: :update, file_path: 'makeup_name', content: content }] } + + it_behaves_like 'returns an error', 'Repository Error updating the snippet' + end + end + + context 'move action' do + context 'when file_path and previous_path are the same' do + let(:snippet_actions) { [{ action: :move, previous_path: file_path, file_path: file_path }] } + + it_behaves_like 'returns an error', 'Snippet actions have invalid data' + end + + context 'when file_path and previous_path are different' do + let(:snippet_actions) { [{ action: :move, previous_path: file_path, file_path: new_path }] } + + it 'renames the file' do + old_blob = blob(file_path) + + expect(subject).to be_success + + blob = blob(new_path) + + expect(blob).to be_present + expect(blob.data).to eq old_blob.data + end + end + + context 'when previous_path does not exist' do + let(:snippet_actions) { [{ action: :move, previous_path: 'makeup_name', file_path: new_path }] } + + it_behaves_like 'returns an error', 'Repository Error updating the snippet' + end + + context 'when user wants to rename the file and update content' do + let(:snippet_actions) { [{ action: :move, previous_path: file_path, file_path: new_path, content: content }] } + + it 'performs both operations' do + expect(subject).to be_success + + blob = blob(new_path) + + expect(blob).to be_present + expect(blob.data).to eq content + end + end + end + + context 'delete action' do + let(:snippet_actions) { [{ action: :delete, file_path: file_path }] } + + shared_examples 'deletes the file' do + specify do + old_blob = blob(file_path) + expect(old_blob).to be_present + + expect(subject).to be_success + expect(blob(file_path)).to be_nil + end + end + + it_behaves_like 'deletes the file' + + context 'when previous_path is present and same as file_path' do + let(:snippet_actions) { [{ action: :delete, previous_path: file_path, file_path: file_path }] } + + it_behaves_like 'deletes the file' + end + + context 'when previous_path is present and is different from file_path' do + let(:snippet_actions) { [{ action: :delete, previous_path: 'foo', file_path: file_path }] } + + it_behaves_like 'deletes the file' + end + + context 'when content is present' do + let(:snippet_actions) { [{ action: :delete, file_path: file_path, content: 'foo' }] } + + it_behaves_like 'deletes the file' + end + + context 'when file_path does not exist' do + let(:snippet_actions) { [{ action: :delete, file_path: 'makeup_name' }] } + + it_behaves_like 'returns an error', 'Repository Error updating the snippet' + end + end + + context 'create action' do + let(:snippet_actions) { [{ action: :create, file_path: new_path, content: content }] } + + it 'creates the file' do + expect(subject).to be_success + + blob = blob(new_path) + expect(blob).to be_present + expect(blob.data).to eq content + end + + context 'when content is not present' do + let(:snippet_actions) { [{ action: :create, file_path: new_path }] } + + it_behaves_like 'returns an error', 'Snippet actions have invalid data' + end + + context 'when file_path is not present or empty' do + let(:snippet_actions) { [{ action: :create, content: content }, { action: :create, file_path: '', content: content }] } + + it 'generates the file path for the files' do + expect(blob('snippetfile1.txt')).to be_nil + expect(blob('snippetfile2.txt')).to be_nil + + expect(subject).to be_success + + expect(blob('snippetfile1.txt').data).to eq content + expect(blob('snippetfile2.txt').data).to eq content + end + end + + context 'when file_path already exists in the repository' do + let(:snippet_actions) { [{ action: :create, file_path: file_path, content: content }] } + + it_behaves_like 'returns an error', 'Repository Error updating the snippet' + end + + context 'when previous_path is present' do + let(:snippet_actions) { [{ action: :create, previous_path: 'foo', file_path: new_path, content: content }] } + + it 'creates the file' do + expect(subject).to be_success + + blob = blob(new_path) + expect(blob).to be_present + expect(blob.data).to eq content + end + end + end + + context 'combination of actions' do + let(:delete_file_path) { 'CHANGELOG' } + let(:create_file_path) { 'created_new_file' } + let(:update_file_path) { 'LICENSE' } + let(:move_previous_path) { 'VERSION' } + let(:move_file_path) { 'VERSION_new' } + + let(:snippet_actions) do + [ + { action: :create, file_path: create_file_path, content: content }, + { action: :update, file_path: update_file_path, content: content }, + { action: :delete, file_path: delete_file_path }, + { action: :move, previous_path: move_previous_path, file_path: move_file_path, content: content } + ] + end + + it 'performs all operations' do + expect(subject).to be_success + + expect(blob(delete_file_path)).to be_nil + + created_blob = blob(create_file_path) + expect(created_blob.data).to eq content + + updated_blob = blob(update_file_path) + expect(updated_blob.data).to eq content + + expect(blob(move_previous_path)).to be_nil + + moved_blob = blob(move_file_path) + expect(moved_blob.data).to eq content + end + end + + def blob(path) + snippet.repository.blob_at('master', path) + end + end end shared_examples 'only file_name is present' do @@ -446,7 +678,7 @@ describe Snippets::UpdateService do it_behaves_like 'updates repository content' it_behaves_like 'commit operation fails' it_behaves_like 'committable attributes' - it_behaves_like 'when snippet_files param is present' + it_behaves_like 'when snippet_actions param is present' it_behaves_like 'only file_name is present' it_behaves_like 'only content is present' it_behaves_like 'snippets spam check is performed' do @@ -473,7 +705,7 @@ describe Snippets::UpdateService do it_behaves_like 'updates repository content' it_behaves_like 'commit operation fails' it_behaves_like 'committable attributes' - it_behaves_like 'when snippet_files param is present' + it_behaves_like 'when snippet_actions param is present' it_behaves_like 'only file_name is present' it_behaves_like 'only content is present' it_behaves_like 'snippets spam check is performed' do diff --git a/spec/services/snippets/update_statistics_service_spec.rb b/spec/services/snippets/update_statistics_service_spec.rb new file mode 100644 index 00000000000..27ae054676a --- /dev/null +++ b/spec/services/snippets/update_statistics_service_spec.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Snippets::UpdateStatisticsService do + describe '#execute' do + subject { described_class.new(snippet).execute } + + shared_examples 'updates statistics' do + it 'returns a successful response' do + expect(subject).to be_success + end + + it 'expires statistics cache' do + expect(snippet.repository).to receive(:expire_statistics_caches) + + subject + end + + context 'when snippet statistics does not exist' do + it 'creates snippet statistics' do + snippet.statistics.delete + snippet.reload + + expect do + subject + end.to change(SnippetStatistics, :count).by(1) + + expect(snippet.statistics.commit_count).not_to be_zero + expect(snippet.statistics.file_count).not_to be_zero + expect(snippet.statistics.repository_size).not_to be_zero + end + end + + context 'when snippet statistics exists' do + it 'updates snippet statistics' do + expect(snippet.statistics.commit_count).to be_zero + expect(snippet.statistics.file_count).to be_zero + expect(snippet.statistics.repository_size).to be_zero + + subject + + expect(snippet.statistics.commit_count).not_to be_zero + expect(snippet.statistics.file_count).not_to be_zero + expect(snippet.statistics.repository_size).not_to be_zero + end + end + + context 'when snippet does not have a repository' do + it 'returns an error response' do + expect(snippet).to receive(:repository_exists?).and_return(false) + + expect(subject).to be_error + end + end + + it 'schedules a namespace storage statistics update' do + expect(Namespaces::ScheduleAggregationWorker) + .to receive(:perform_async).once + + subject + end + end + + context 'with PersonalSnippet' do + let!(:snippet) { create(:personal_snippet, :repository) } + + it_behaves_like 'updates statistics' + end + + context 'with ProjectSnippet' do + let!(:snippet) { create(:project_snippet, :repository) } + let(:project_statistics) { snippet.project.statistics } + + it_behaves_like 'updates statistics' + + it 'updates projects statistics "snippets_size"' do + expect(project_statistics.snippets_size).to be_zero + + subject + + expect(snippet.reload.statistics.repository_size).to eq project_statistics.reload.snippets_size + end + end + end +end diff --git a/spec/services/spam/akismet_service_spec.rb b/spec/services/spam/akismet_service_spec.rb index 413b43d0156..f75b0216b78 100644 --- a/spec/services/spam/akismet_service_spec.rb +++ b/spec/services/spam/akismet_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Spam::AkismetService do +RSpec.describe Spam::AkismetService do let(:fake_akismet_client) { double(:akismet_client) } let_it_be(:text) { "Would you like to buy some tinned meat product?" } diff --git a/spec/services/spam/ham_service_spec.rb b/spec/services/spam/ham_service_spec.rb index 9848f48def2..c947de6cf92 100644 --- a/spec/services/spam/ham_service_spec.rb +++ b/spec/services/spam/ham_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Spam::HamService do +RSpec.describe Spam::HamService do let_it_be(:user) { create(:user) } let!(:spam_log) { create(:spam_log, user: user, submitted_as_ham: false) } let(:fake_akismet_service) { double(:akismet_service) } diff --git a/spec/services/spam/mark_as_spam_service_spec.rb b/spec/services/spam/mark_as_spam_service_spec.rb index 9978005279a..308a66c3a48 100644 --- a/spec/services/spam/mark_as_spam_service_spec.rb +++ b/spec/services/spam/mark_as_spam_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Spam::MarkAsSpamService do +RSpec.describe Spam::MarkAsSpamService do let(:user_agent_detail) { build(:user_agent_detail) } let(:spammable) { build(:issue, user_agent_detail: user_agent_detail) } let(:fake_akismet_service) { double(:akismet_service, submit_spam: true) } diff --git a/spec/services/spam/spam_action_service_spec.rb b/spec/services/spam/spam_action_service_spec.rb index 7b6b65c82b1..abb8e49ec52 100644 --- a/spec/services/spam/spam_action_service_spec.rb +++ b/spec/services/spam/spam_action_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Spam::SpamActionService do +RSpec.describe Spam::SpamActionService do include_context 'includes Spam constants' let(:fake_ip) { '1.2.3.4' } diff --git a/spec/services/spam/spam_verdict_service_spec.rb b/spec/services/spam/spam_verdict_service_spec.rb index f6d9cd96da5..d775e1bdfb5 100644 --- a/spec/services/spam/spam_verdict_service_spec.rb +++ b/spec/services/spam/spam_verdict_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Spam::SpamVerdictService do +RSpec.describe Spam::SpamVerdictService do include_context 'includes Spam constants' let(:fake_ip) { '1.2.3.4' } @@ -27,7 +27,7 @@ describe Spam::SpamVerdictService do before do allow(service).to receive(:akismet_verdict).and_return(nil) - allow(service).to receive(:spam_verdict_verdict).and_return(nil) + allow(service).to receive(:external_verdict).and_return(nil) end context 'if all services return nil' do @@ -62,7 +62,7 @@ describe Spam::SpamVerdictService do context 'and they are supported' do before do allow(service).to receive(:akismet_verdict).and_return(DISALLOW) - allow(service).to receive(:spam_verdict).and_return(BLOCK_USER) + allow(service).to receive(:external_verdict).and_return(BLOCK_USER) end it 'renders the more restrictive verdict' do @@ -73,18 +73,7 @@ describe Spam::SpamVerdictService do context 'and one is supported' do before do allow(service).to receive(:akismet_verdict).and_return('nonsense') - allow(service).to receive(:spam_verdict).and_return(BLOCK_USER) - end - - it 'renders the more restrictive verdict' do - expect(subject).to eq BLOCK_USER - end - end - - context 'and one is supported' do - before do - allow(service).to receive(:akismet_verdict).and_return('nonsense') - allow(service).to receive(:spam_verdict).and_return(BLOCK_USER) + allow(service).to receive(:external_verdict).and_return(BLOCK_USER) end it 'renders the more restrictive verdict' do @@ -95,7 +84,7 @@ describe Spam::SpamVerdictService do context 'and none are supported' do before do allow(service).to receive(:akismet_verdict).and_return('nonsense') - allow(service).to receive(:spam_verdict).and_return('rubbish') + allow(service).to receive(:external_verdict).and_return('rubbish') end it 'renders the more restrictive verdict' do @@ -160,8 +149,8 @@ describe Spam::SpamVerdictService do end end - describe '#spam_verdict' do - subject { service.send(:spam_verdict) } + describe '#external_verdict' do + subject { service.send(:external_verdict) } context 'if a Spam Check endpoint enabled and set to a URL' do let(:spam_check_body) { {} } @@ -192,8 +181,8 @@ describe Spam::SpamVerdictService do context 'the verdict is an unexpected string' do let(:verdict) { 'this is fine' } - it 'returns nil' do - expect(subject).to be_nil + it 'returns the string' do + expect(subject).to eq verdict end end @@ -209,7 +198,7 @@ describe Spam::SpamVerdictService do let(:verdict) { '' } it 'returns nil' do - expect(subject).to be_nil + expect(subject).to eq verdict end end diff --git a/spec/services/submit_usage_ping_service_spec.rb b/spec/services/submit_usage_ping_service_spec.rb index 981ea0dbec1..4885ef99c13 100644 --- a/spec/services/submit_usage_ping_service_spec.rb +++ b/spec/services/submit_usage_ping_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe SubmitUsagePingService do +RSpec.describe SubmitUsagePingService do include StubRequests include UsageDataHelpers diff --git a/spec/services/submodules/update_service_spec.rb b/spec/services/submodules/update_service_spec.rb index 47b31d4bcbf..e7f92d5ba28 100644 --- a/spec/services/submodules/update_service_spec.rb +++ b/spec/services/submodules/update_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Submodules::UpdateService do +RSpec.describe Submodules::UpdateService do let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:user) { create(:user, :commit_email) } diff --git a/spec/services/suggestions/apply_service_spec.rb b/spec/services/suggestions/apply_service_spec.rb index 678e2129181..aa9caf35987 100644 --- a/spec/services/suggestions/apply_service_spec.rb +++ b/spec/services/suggestions/apply_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Suggestions::ApplyService do +RSpec.describe Suggestions::ApplyService do include ProjectForksHelper def build_position(**optional_args) diff --git a/spec/services/suggestions/create_service_spec.rb b/spec/services/suggestions/create_service_spec.rb index d95f9e3349b..54e7c5cc127 100644 --- a/spec/services/suggestions/create_service_spec.rb +++ b/spec/services/suggestions/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Suggestions::CreateService do +RSpec.describe Suggestions::CreateService do let(:project_with_repo) { create(:project, :repository) } let(:merge_request) do create(:merge_request, source_project: project_with_repo, diff --git a/spec/services/suggestions/outdate_service_spec.rb b/spec/services/suggestions/outdate_service_spec.rb index bcc627013d8..e8891f88548 100644 --- a/spec/services/suggestions/outdate_service_spec.rb +++ b/spec/services/suggestions/outdate_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Suggestions::OutdateService do +RSpec.describe Suggestions::OutdateService do describe '#execute' do let(:merge_request) { create(:merge_request) } let(:project) { merge_request.target_project } diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb index d72e5cc2b16..bdc40a92e91 100644 --- a/spec/services/system_hooks_service_spec.rb +++ b/spec/services/system_hooks_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe SystemHooksService do +RSpec.describe SystemHooksService do let(:user) { create(:user) } let(:project) { create(:project) } let(:project_member) { create(:project_member) } diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index 66f9b5d092f..58fa772fefb 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe SystemNoteService do +RSpec.describe SystemNoteService do include Gitlab::Routing include RepoHelpers include AssetsHelpers @@ -661,4 +661,48 @@ describe SystemNoteService do described_class.design_discussion_added(discussion_note) end end + + describe '.approve_mr' do + it 'calls MergeRequestsService' do + expect_next_instance_of(::SystemNotes::MergeRequestsService) do |service| + expect(service).to receive(:approve_mr) + end + + described_class.approve_mr(noteable, author) + end + end + + describe '.unapprove_mr' do + it 'calls MergeRequestsService' do + expect_next_instance_of(::SystemNotes::MergeRequestsService) do |service| + expect(service).to receive(:unapprove_mr) + end + + described_class.unapprove_mr(noteable, author) + end + end + + describe '.change_alert_status' do + let(:alert) { build(:alert_management_alert) } + + it 'calls AlertManagementService' do + expect_next_instance_of(SystemNotes::AlertManagementService) do |service| + expect(service).to receive(:change_alert_status).with(alert) + end + + described_class.change_alert_status(alert, author) + end + end + + describe '.new_alert_issue' do + let(:alert) { build(:alert_management_alert, :with_issue) } + + it 'calls AlertManagementService' do + expect_next_instance_of(SystemNotes::AlertManagementService) do |service| + expect(service).to receive(:new_alert_issue).with(alert, alert.issue) + end + + described_class.new_alert_issue(alert, alert.issue, author) + end + end end diff --git a/spec/services/system_notes/alert_management_service_spec.rb b/spec/services/system_notes/alert_management_service_spec.rb new file mode 100644 index 00000000000..403763d5fd9 --- /dev/null +++ b/spec/services/system_notes/alert_management_service_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::SystemNotes::AlertManagementService do + let_it_be(:author) { create(:user) } + let_it_be(:project) { create(:project, :repository) } + let_it_be(:noteable) { create(:alert_management_alert, :with_issue, :acknowledged, project: project) } + + describe '#change_alert_status' do + subject { described_class.new(noteable: noteable, project: project, author: author).change_alert_status(noteable) } + + it_behaves_like 'a system note' do + let(:action) { 'status' } + end + + it 'has the appropriate message' do + expect(subject.note).to eq("changed the status to **Acknowledged**") + end + end + + describe '#new_alert_issue' do + let_it_be(:issue) { noteable.issue } + + subject { described_class.new(noteable: noteable, project: project, author: author).new_alert_issue(noteable, issue) } + + it_behaves_like 'a system note' do + let(:action) { 'alert_issue_added' } + end + + it 'has the appropriate message' do + expect(subject.note).to eq("created issue #{issue.to_reference(project)} for this alert") + end + end +end diff --git a/spec/services/system_notes/base_service_spec.rb b/spec/services/system_notes/base_service_spec.rb index 96788b05829..efb165f8e4c 100644 --- a/spec/services/system_notes/base_service_spec.rb +++ b/spec/services/system_notes/base_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe SystemNotes::BaseService do +RSpec.describe SystemNotes::BaseService do let(:noteable) { double } let(:project) { double } let(:author) { double } diff --git a/spec/services/system_notes/commit_service_spec.rb b/spec/services/system_notes/commit_service_spec.rb index 5839a17e4a0..bd6b3ec953a 100644 --- a/spec/services/system_notes/commit_service_spec.rb +++ b/spec/services/system_notes/commit_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe SystemNotes::CommitService do +RSpec.describe SystemNotes::CommitService do let_it_be(:group) { create(:group) } let_it_be(:project) { create(:project, :repository, group: group) } let_it_be(:author) { create(:user) } diff --git a/spec/services/system_notes/design_management_service_spec.rb b/spec/services/system_notes/design_management_service_spec.rb index 08511e62341..6267ad2aaad 100644 --- a/spec/services/system_notes/design_management_service_spec.rb +++ b/spec/services/system_notes/design_management_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe SystemNotes::DesignManagementService do +RSpec.describe SystemNotes::DesignManagementService do let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } diff --git a/spec/services/system_notes/issuables_service_spec.rb b/spec/services/system_notes/issuables_service_spec.rb index c3b3c877583..1b5b26d90da 100644 --- a/spec/services/system_notes/issuables_service_spec.rb +++ b/spec/services/system_notes/issuables_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ::SystemNotes::IssuablesService do +RSpec.describe ::SystemNotes::IssuablesService do include ProjectForksHelper let_it_be(:group) { create(:group) } @@ -161,7 +161,9 @@ describe ::SystemNotes::IssuablesService do let(:status) { 'reopened' } let(:source) { nil } - it { is_expected.to be_nil } + it 'does not change note count' do + expect { subject }.not_to change { Note.count } + end end context 'with status reopened' do @@ -660,25 +662,67 @@ describe ::SystemNotes::IssuablesService do describe '#close_after_error_tracking_resolve' do subject { service.close_after_error_tracking_resolve } - it_behaves_like 'a system note' do - let(:action) { 'closed' } + context 'when state tracking is enabled' do + before do + stub_feature_flags(track_resource_state_change_events: true) + end + + it 'creates the expected state event' do + subject + + event = ResourceStateEvent.last + + expect(event.close_after_error_tracking_resolve).to eq(true) + expect(event.state).to eq('closed') + end end - it 'creates the expected system note' do - expect(subject.note) + context 'when state tracking is disabled' do + before do + stub_feature_flags(track_resource_state_change_events: false) + end + + it_behaves_like 'a system note' do + let(:action) { 'closed' } + end + + it 'creates the expected system note' do + expect(subject.note) .to eq('resolved the corresponding error and closed the issue.') + end end end describe '#auto_resolve_prometheus_alert' do subject { service.auto_resolve_prometheus_alert } - it_behaves_like 'a system note' do - let(:action) { 'closed' } + context 'when state tracking is enabled' do + before do + stub_feature_flags(track_resource_state_change_events: true) + end + + it 'creates the expected state event' do + subject + + event = ResourceStateEvent.last + + expect(event.close_auto_resolve_prometheus_alert).to eq(true) + expect(event.state).to eq('closed') + end end - it 'creates the expected system note' do - expect(subject.note).to eq('automatically closed this issue because the alert resolved.') + context 'when state tracking is disabled' do + before do + stub_feature_flags(track_resource_state_change_events: false) + end + + it_behaves_like 'a system note' do + let(:action) { 'closed' } + end + + it 'creates the expected system note' do + expect(subject.note).to eq('automatically closed this issue because the alert resolved.') + end end end end diff --git a/spec/services/system_notes/merge_requests_service_spec.rb b/spec/services/system_notes/merge_requests_service_spec.rb index 13d6367a585..067e1cef64d 100644 --- a/spec/services/system_notes/merge_requests_service_spec.rb +++ b/spec/services/system_notes/merge_requests_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ::SystemNotes::MergeRequestsService do +RSpec.describe ::SystemNotes::MergeRequestsService do include Gitlab::Routing let_it_be(:group) { create(:group) } @@ -52,8 +52,8 @@ describe ::SystemNotes::MergeRequestsService do end describe '.handle_merge_request_wip' do - context 'adding wip note' do - let(:noteable) { create(:merge_request, source_project: project, title: 'WIP Lorem ipsum') } + context 'adding draft note' do + let(:noteable) { create(:merge_request, source_project: project, title: 'Draft: Lorem ipsum') } subject { service.handle_merge_request_wip } @@ -261,4 +261,18 @@ describe ::SystemNotes::MergeRequestsService do expect(subject.commit_id).to eq(commit_sha) end end + + describe '#approve_mr' do + subject { described_class.new(noteable: noteable, project: project, author: author).approve_mr } + + it_behaves_like 'a system note' do + let(:action) { 'approved' } + end + + context 'when merge request approved' do + it 'sets the note text' do + expect(subject.note).to eq "approved this merge request" + end + end + end end diff --git a/spec/services/system_notes/time_tracking_service_spec.rb b/spec/services/system_notes/time_tracking_service_spec.rb index 7e3e6a75cdf..f671e66cdcd 100644 --- a/spec/services/system_notes/time_tracking_service_spec.rb +++ b/spec/services/system_notes/time_tracking_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ::SystemNotes::TimeTrackingService do +RSpec.describe ::SystemNotes::TimeTrackingService do let_it_be(:author) { create(:user) } let_it_be(:project) { create(:project, :repository) } diff --git a/spec/services/system_notes/zoom_service_spec.rb b/spec/services/system_notes/zoom_service_spec.rb index 435cdb5748e..986324c9664 100644 --- a/spec/services/system_notes/zoom_service_spec.rb +++ b/spec/services/system_notes/zoom_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe ::SystemNotes::ZoomService do +RSpec.describe ::SystemNotes::ZoomService do let_it_be(:project) { create(:project, :repository) } let_it_be(:author) { create(:user) } diff --git a/spec/services/tags/create_service_spec.rb b/spec/services/tags/create_service_spec.rb index e505960d3c7..b1c6623308e 100644 --- a/spec/services/tags/create_service_spec.rb +++ b/spec/services/tags/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Tags::CreateService do +RSpec.describe Tags::CreateService do let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:user) { create(:user) } diff --git a/spec/services/tags/destroy_service_spec.rb b/spec/services/tags/destroy_service_spec.rb index b46bd77eafe..6160f337552 100644 --- a/spec/services/tags/destroy_service_spec.rb +++ b/spec/services/tags/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Tags::DestroyService do +RSpec.describe Tags::DestroyService do let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:user) { create(:user) } @@ -11,6 +11,10 @@ describe Tags::DestroyService do describe '#execute' do subject { service.execute(tag_name) } + before do + allow(Ci::RefDeleteUnlockArtifactsWorker).to receive(:perform_async) + end + it 'removes the tag' do expect(repository).to receive(:before_remove_tag) expect(service).to receive(:success) @@ -18,6 +22,12 @@ describe Tags::DestroyService do service.execute('v1.1.0') end + it 'calls the RefDeleteUnlockArtifactsWorker' do + expect(Ci::RefDeleteUnlockArtifactsWorker).to receive(:perform_async).with(project.id, user.id, 'refs/tags/v1.1.0') + + service.execute('v1.1.0') + end + context 'when there is an associated release on the tag' do let(:tag) { repository.tags.first } let(:tag_name) { tag.name } diff --git a/spec/services/task_list_toggle_service_spec.rb b/spec/services/task_list_toggle_service_spec.rb index 82a5446dcb8..276f2ae435e 100644 --- a/spec/services/task_list_toggle_service_spec.rb +++ b/spec/services/task_list_toggle_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe TaskListToggleService do +RSpec.describe TaskListToggleService do let(:markdown) do <<-EOT.strip_heredoc * [ ] Task 1 diff --git a/spec/services/terraform/remote_state_handler_spec.rb b/spec/services/terraform/remote_state_handler_spec.rb index f4e1831b2e8..c47367feb14 100644 --- a/spec/services/terraform/remote_state_handler_spec.rb +++ b/spec/services/terraform/remote_state_handler_spec.rb @@ -2,9 +2,12 @@ require 'spec_helper' -describe Terraform::RemoteStateHandler do +RSpec.describe Terraform::RemoteStateHandler do let_it_be(:project) { create(:project) } - let_it_be(:user) { create(:user) } + let_it_be(:developer) { create(:user, developer_projects: [project]) } + let_it_be(:maintainer) { create(:user, maintainer_projects: [project]) } + + let_it_be(:user) { maintainer } describe '#find_with_lock' do context 'without a state name' do @@ -34,33 +37,6 @@ describe Terraform::RemoteStateHandler do end end - describe '#create_or_find!' do - it 'requires passing a state name' do - handler = described_class.new(project, user) - - expect { handler.create_or_find! }.to raise_error(ArgumentError) - end - - it 'allows to create states with same name in different projects' do - project_b = create(:project) - - state_a = described_class.new(project, user, name: 'my-state').create_or_find! - state_b = described_class.new(project_b, user, name: 'my-state').create_or_find! - - expect(state_a).to be_persisted - expect(state_b).to be_persisted - expect(state_a.id).not_to eq state_b.id - end - - it 'loads the same state upon subsequent call in the project scope' do - state_a = described_class.new(project, user, name: 'my-state').create_or_find! - state_b = described_class.new(project, user, name: 'my-state').create_or_find! - - expect(state_a).to be_persisted - expect(state_a.id).to eq state_b.id - end - end - context 'when state locking is not being used' do subject { described_class.new(project, user, name: 'my-state') } @@ -74,7 +50,7 @@ describe Terraform::RemoteStateHandler do end it 'returns the state object itself' do - state = subject.create_or_find! + state = subject.handle_with_lock expect(state.name).to eq 'my-state' end @@ -89,10 +65,9 @@ describe Terraform::RemoteStateHandler do context 'when using locking' do describe '#handle_with_lock' do - it 'handles a locked state using exclusive read lock' do - handler = described_class - .new(project, user, name: 'new-state', lock_id: 'abc-abc') + subject(:handler) { described_class.new(project, user, name: 'new-state', lock_id: 'abc-abc') } + it 'handles a locked state using exclusive read lock' do handler.lock! state = handler.handle_with_lock do |state| @@ -101,20 +76,35 @@ describe Terraform::RemoteStateHandler do expect(state.name).to eq 'new-name' end - end - it 'raises exception if lock has not been acquired before' do - handler = described_class - .new(project, user, name: 'new-state', lock_id: 'abc-abc') + it 'raises exception if lock has not been acquired before' do + expect { handler.handle_with_lock } + .to raise_error(described_class::StateLockedError) + end + + context 'user does not have permission to modify state' do + let(:user) { developer } - expect { handler.handle_with_lock } - .to raise_error(described_class::StateLockedError) + it 'raises an exception' do + expect { handler.handle_with_lock } + .to raise_error(described_class::UnauthorizedError) + end + end end describe '#lock!' do - it 'allows to lock state if it does not exist yet' do - handler = described_class.new(project, user, name: 'new-state', lock_id: 'abc-abc') + let(:lock_id) { 'abc-abc' } + + subject(:handler) do + described_class.new( + project, + user, + name: 'new-state', + lock_id: lock_id + ) + end + it 'allows to lock state if it does not exist yet' do state = handler.lock! expect(state).to be_persisted @@ -122,22 +112,61 @@ describe Terraform::RemoteStateHandler do end it 'allows to lock state if it exists and is not locked' do - state = described_class.new(project, user, name: 'new-state').create_or_find! - handler = described_class.new(project, user, name: 'new-state', lock_id: 'abc-abc') + state = create(:terraform_state, project: project, name: 'new-state') handler.lock! - expect(state.reload.lock_xid).to eq 'abc-abc' + expect(state.reload.lock_xid).to eq lock_id expect(state).to be_locked end it 'raises an exception when trying to unlocked state locked by someone else' do - described_class.new(project, user, name: 'new-state', lock_id: 'abc-abc').lock! - - handler = described_class.new(project, user, name: 'new-state', lock_id: '12a-23f') + described_class.new(project, user, name: 'new-state', lock_id: '12a-23f').lock! expect { handler.lock! }.to raise_error(described_class::StateLockedError) end end + + describe '#unlock!' do + let(:lock_id) { 'abc-abc' } + + subject(:handler) do + described_class.new( + project, + user, + name: 'new-state', + lock_id: lock_id + ) + end + + before do + create(:terraform_state, :locked, project: project, name: 'new-state', lock_xid: 'abc-abc') + end + + it 'unlocks the state' do + state = handler.unlock! + + expect(state.lock_xid).to be_nil + end + + context 'with no lock ID (force-unlock)' do + let(:lock_id) { } + + it 'unlocks the state' do + state = handler.unlock! + + expect(state.lock_xid).to be_nil + end + end + + context 'with different lock ID' do + let(:lock_id) { 'other' } + + it 'raises an exception' do + expect { handler.unlock! } + .to raise_error(described_class::StateLockedError) + end + end + end end end diff --git a/spec/services/test_hooks/project_service_spec.rb b/spec/services/test_hooks/project_service_spec.rb index 3c5bc0d85f2..e4cc3a2d652 100644 --- a/spec/services/test_hooks/project_service_spec.rb +++ b/spec/services/test_hooks/project_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe TestHooks::ProjectService do +RSpec.describe TestHooks::ProjectService do let(:current_user) { create(:user) } describe '#execute' do diff --git a/spec/services/test_hooks/system_service_spec.rb b/spec/services/test_hooks/system_service_spec.rb index 8a86b14a2a1..34dd2173b09 100644 --- a/spec/services/test_hooks/system_service_spec.rb +++ b/spec/services/test_hooks/system_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe TestHooks::SystemService do +RSpec.describe TestHooks::SystemService do let(:current_user) { create(:user) } describe '#execute' do diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb index f6e1608acbe..b187025eb11 100644 --- a/spec/services/todo_service_spec.rb +++ b/spec/services/todo_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe TodoService do +RSpec.describe TodoService do let(:author) { create(:user) } let(:assignee) { create(:user) } let(:non_member) { create(:user) } diff --git a/spec/services/todos/destroy/confidential_issue_service_spec.rb b/spec/services/todos/destroy/confidential_issue_service_spec.rb index 9f7e656f7d3..ddce45e7968 100644 --- a/spec/services/todos/destroy/confidential_issue_service_spec.rb +++ b/spec/services/todos/destroy/confidential_issue_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Todos::Destroy::ConfidentialIssueService do +RSpec.describe Todos::Destroy::ConfidentialIssueService do let(:project) { create(:project, :public) } let(:user) { create(:user) } let(:author) { create(:user) } diff --git a/spec/services/todos/destroy/entity_leave_service_spec.rb b/spec/services/todos/destroy/entity_leave_service_spec.rb index 45e3bf381fb..ccafe3bb7a8 100644 --- a/spec/services/todos/destroy/entity_leave_service_spec.rb +++ b/spec/services/todos/destroy/entity_leave_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Todos::Destroy::EntityLeaveService do +RSpec.describe Todos::Destroy::EntityLeaveService do let(:group) { create(:group, :private) } let(:project) { create(:project, group: group) } let(:user) { create(:user) } diff --git a/spec/services/todos/destroy/group_private_service_spec.rb b/spec/services/todos/destroy/group_private_service_spec.rb index 7dd495847b3..30d02cb7400 100644 --- a/spec/services/todos/destroy/group_private_service_spec.rb +++ b/spec/services/todos/destroy/group_private_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Todos::Destroy::GroupPrivateService do +RSpec.describe Todos::Destroy::GroupPrivateService do let(:group) { create(:group, :public) } let(:project) { create(:project, group: group) } let(:user) { create(:user) } diff --git a/spec/services/todos/destroy/private_features_service_spec.rb b/spec/services/todos/destroy/private_features_service_spec.rb index dfe9f42e8b1..6dbd7574b80 100644 --- a/spec/services/todos/destroy/private_features_service_spec.rb +++ b/spec/services/todos/destroy/private_features_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Todos::Destroy::PrivateFeaturesService do +RSpec.describe Todos::Destroy::PrivateFeaturesService do let(:project) { create(:project, :public) } let(:user) { create(:user) } let(:another_user) { create(:user) } diff --git a/spec/services/todos/destroy/project_private_service_spec.rb b/spec/services/todos/destroy/project_private_service_spec.rb index 7c0c76b6c29..1d1c010535d 100644 --- a/spec/services/todos/destroy/project_private_service_spec.rb +++ b/spec/services/todos/destroy/project_private_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Todos::Destroy::ProjectPrivateService do +RSpec.describe Todos::Destroy::ProjectPrivateService do let(:group) { create(:group, :public) } let(:project) { create(:project, :public, group: group) } let(:user) { create(:user) } diff --git a/spec/services/update_container_registry_info_service_spec.rb b/spec/services/update_container_registry_info_service_spec.rb new file mode 100644 index 00000000000..740e53b0472 --- /dev/null +++ b/spec/services/update_container_registry_info_service_spec.rb @@ -0,0 +1,115 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe UpdateContainerRegistryInfoService do + let_it_be(:application_settings) { Gitlab::CurrentSettings } + let_it_be(:api_url) { 'http://registry.gitlab' } + + describe '#execute' do + before do + stub_access_token + stub_container_registry_config(enabled: true, api_url: api_url) + end + + subject { described_class.new.execute } + + shared_examples 'invalid config' do + it 'does not update the application settings' do + expect(application_settings).not_to receive(:update!) + + subject + end + + it 'does not raise an error' do + expect { subject }.not_to raise_error + end + end + + context 'when container registry is disabled' do + before do + stub_container_registry_config(enabled: false) + end + + it_behaves_like 'invalid config' + end + + context 'when container registry api_url is blank' do + before do + stub_container_registry_config(api_url: '') + end + + it_behaves_like 'invalid config' + end + + context 'when creating a registry client instance' do + let(:token) { 'foo' } + let(:client) { ContainerRegistry::Client.new(api_url, token: token) } + + before do + stub_registry_info({}) + end + + it 'uses a token with no access permissions' do + expect(Auth::ContainerRegistryAuthenticationService) + .to receive(:access_token).with([], []).and_return(token) + expect(ContainerRegistry::Client) + .to receive(:new).with(api_url, token: token).and_return(client) + + subject + end + end + + context 'when unabled to detect the container registry type' do + it 'sets the application settings to their defaults' do + stub_registry_info({}) + + subject + + application_settings.reload + expect(application_settings.container_registry_vendor).to be_blank + expect(application_settings.container_registry_version).to be_blank + expect(application_settings.container_registry_features).to eq([]) + end + end + + context 'when able to detect the container registry type' do + context 'when using the GitLab container registry' do + it 'updates application settings accordingly' do + stub_registry_info(vendor: 'gitlab', version: '2.9.1-gitlab', features: %w[a,b,c]) + + subject + + application_settings.reload + expect(application_settings.container_registry_vendor).to eq('gitlab') + expect(application_settings.container_registry_version).to eq('2.9.1-gitlab') + expect(application_settings.container_registry_features).to eq(%w[a,b,c]) + end + end + + context 'when using a third-party container registry' do + it 'updates application settings accordingly' do + stub_registry_info(vendor: 'other', version: nil, features: nil) + + subject + + application_settings.reload + expect(application_settings.container_registry_vendor).to eq('other') + expect(application_settings.container_registry_version).to be_blank + expect(application_settings.container_registry_features).to eq([]) + end + end + end + end + + def stub_access_token + allow(Auth::ContainerRegistryAuthenticationService) + .to receive(:access_token).with([], []).and_return('foo') + end + + def stub_registry_info(output) + allow_next_instance_of(ContainerRegistry::Client) do |client| + allow(client).to receive(:registry_info).and_return(output) + end + end +end diff --git a/spec/services/update_merge_request_metrics_service_spec.rb b/spec/services/update_merge_request_metrics_service_spec.rb index 1aaf5e712f9..a07fcee91e4 100644 --- a/spec/services/update_merge_request_metrics_service_spec.rb +++ b/spec/services/update_merge_request_metrics_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe MergeRequestMetricsService do +RSpec.describe MergeRequestMetricsService do let(:metrics) { create(:merge_request).metrics } describe '#merge' do diff --git a/spec/services/upload_service_spec.rb b/spec/services/upload_service_spec.rb index 504e61f9903..89a28e6a098 100644 --- a/spec/services/upload_service_spec.rb +++ b/spec/services/upload_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe UploadService do +RSpec.describe UploadService do describe 'File service' do before do @user = create(:user) diff --git a/spec/services/user_project_access_changed_service_spec.rb b/spec/services/user_project_access_changed_service_spec.rb index e5ecdd123f7..070782992e7 100644 --- a/spec/services/user_project_access_changed_service_spec.rb +++ b/spec/services/user_project_access_changed_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe UserProjectAccessChangedService do +RSpec.describe UserProjectAccessChangedService do describe '#execute' do it 'schedules the user IDs' do expect(AuthorizedProjectsWorker).to receive(:bulk_perform_and_wait) diff --git a/spec/services/users/activity_service_spec.rb b/spec/services/users/activity_service_spec.rb index 5f068a2033c..4bbf6a2bcb8 100644 --- a/spec/services/users/activity_service_spec.rb +++ b/spec/services/users/activity_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::ActivityService do +RSpec.describe Users::ActivityService do include ExclusiveLeaseHelpers let(:user) { create(:user, last_activity_on: last_activity_on) } diff --git a/spec/services/users/block_service_spec.rb b/spec/services/users/block_service_spec.rb index c3a65a08c0d..e170a5494aa 100644 --- a/spec/services/users/block_service_spec.rb +++ b/spec/services/users/block_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::BlockService do +RSpec.describe Users::BlockService do let(:current_user) { create(:admin) } subject(:service) { described_class.new(current_user) } diff --git a/spec/services/users/build_service_spec.rb b/spec/services/users/build_service_spec.rb index 7588be833ae..c14fdb35bfa 100644 --- a/spec/services/users/build_service_spec.rb +++ b/spec/services/users/build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::BuildService do +RSpec.describe Users::BuildService do describe '#execute' do let(:params) do { name: 'John Doe', username: 'jduser', email: 'jd@example.com', password: 'mydummypass' } diff --git a/spec/services/users/create_service_spec.rb b/spec/services/users/create_service_spec.rb index c783a1403df..69d2d6ca9ff 100644 --- a/spec/services/users/create_service_spec.rb +++ b/spec/services/users/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::CreateService do +RSpec.describe Users::CreateService do describe '#execute' do let(:admin_user) { create(:admin) } diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb index 3db5e66fe05..ff919257b3c 100644 --- a/spec/services/users/destroy_service_spec.rb +++ b/spec/services/users/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::DestroyService do +RSpec.describe Users::DestroyService do describe "Deletes a user and all their personal projects" do let!(:user) { create(:user) } let!(:admin) { create(:admin) } diff --git a/spec/services/users/keys_count_service_spec.rb b/spec/services/users/keys_count_service_spec.rb index 83af051e728..aff267cce5e 100644 --- a/spec/services/users/keys_count_service_spec.rb +++ b/spec/services/users/keys_count_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::KeysCountService, :use_clean_rails_memory_store_caching do +RSpec.describe Users::KeysCountService, :use_clean_rails_memory_store_caching do let(:user) { create(:user) } subject { described_class.new(user) } diff --git a/spec/services/users/last_push_event_service_spec.rb b/spec/services/users/last_push_event_service_spec.rb index 424e9e2f8ef..5b755db407f 100644 --- a/spec/services/users/last_push_event_service_spec.rb +++ b/spec/services/users/last_push_event_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::LastPushEventService do +RSpec.describe Users::LastPushEventService do let(:user) { build(:user, id: 1) } let(:project) { build(:project, id: 2) } let(:event) { build(:push_event, id: 3, author: user, project: project) } diff --git a/spec/services/users/migrate_to_ghost_user_service_spec.rb b/spec/services/users/migrate_to_ghost_user_service_spec.rb index c2a793b2368..c9c8f9a74d3 100644 --- a/spec/services/users/migrate_to_ghost_user_service_spec.rb +++ b/spec/services/users/migrate_to_ghost_user_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::MigrateToGhostUserService do +RSpec.describe Users::MigrateToGhostUserService do let!(:user) { create(:user) } let!(:project) { create(:project, :repository) } let(:service) { described_class.new(user) } diff --git a/spec/services/users/refresh_authorized_projects_service_spec.rb b/spec/services/users/refresh_authorized_projects_service_spec.rb index d7ba7f5f69e..e45cb05a6c5 100644 --- a/spec/services/users/refresh_authorized_projects_service_spec.rb +++ b/spec/services/users/refresh_authorized_projects_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::RefreshAuthorizedProjectsService do +RSpec.describe Users::RefreshAuthorizedProjectsService do include ExclusiveLeaseHelpers # We're using let! here so that any expectations for the service class are not diff --git a/spec/services/users/repair_ldap_blocked_service_spec.rb b/spec/services/users/repair_ldap_blocked_service_spec.rb index bf80cc79d62..b33dcb92f45 100644 --- a/spec/services/users/repair_ldap_blocked_service_spec.rb +++ b/spec/services/users/repair_ldap_blocked_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::RepairLdapBlockedService do +RSpec.describe Users::RepairLdapBlockedService do let(:user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') } let(:identity) { user.ldap_identity } diff --git a/spec/services/users/respond_to_terms_service_spec.rb b/spec/services/users/respond_to_terms_service_spec.rb index d840706e8a5..1997dcd0e04 100644 --- a/spec/services/users/respond_to_terms_service_spec.rb +++ b/spec/services/users/respond_to_terms_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::RespondToTermsService do +RSpec.describe Users::RespondToTermsService do let(:user) { create(:user) } let(:term) { create(:term) } diff --git a/spec/services/users/set_status_service_spec.rb b/spec/services/users/set_status_service_spec.rb index 554f5e9dc5e..54489adceb0 100644 --- a/spec/services/users/set_status_service_spec.rb +++ b/spec/services/users/set_status_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::SetStatusService do +RSpec.describe Users::SetStatusService do let(:current_user) { create(:user) } subject(:service) { described_class.new(current_user, params) } diff --git a/spec/services/users/signup_service_spec.rb b/spec/services/users/signup_service_spec.rb index 7d3cd614142..cc234309817 100644 --- a/spec/services/users/signup_service_spec.rb +++ b/spec/services/users/signup_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::SignupService do +RSpec.describe Users::SignupService do let(:user) { create(:user, setup_for_company: true) } describe '#execute' do diff --git a/spec/services/users/update_canonical_email_service_spec.rb b/spec/services/users/update_canonical_email_service_spec.rb index 68ba1b75b6c..1dead13d338 100644 --- a/spec/services/users/update_canonical_email_service_spec.rb +++ b/spec/services/users/update_canonical_email_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::UpdateCanonicalEmailService do +RSpec.describe Users::UpdateCanonicalEmailService do let(:other_email) { "differentaddress@includeddomain.com" } before do diff --git a/spec/services/users/update_highest_member_role_service_spec.rb b/spec/services/users/update_highest_member_role_service_spec.rb index 8063abffc2a..89ddd635bb6 100644 --- a/spec/services/users/update_highest_member_role_service_spec.rb +++ b/spec/services/users/update_highest_member_role_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::UpdateHighestMemberRoleService do +RSpec.describe Users::UpdateHighestMemberRoleService do let(:user) { create(:user) } let(:execute_service) { described_class.new(user).execute } diff --git a/spec/services/users/update_service_spec.rb b/spec/services/users/update_service_spec.rb index 8e13e7d9c0c..274c44394f3 100644 --- a/spec/services/users/update_service_spec.rb +++ b/spec/services/users/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe Users::UpdateService do +RSpec.describe Users::UpdateService do let(:user) { create(:user) } describe '#execute' do diff --git a/spec/services/verify_pages_domain_service_spec.rb b/spec/services/verify_pages_domain_service_spec.rb index 3f08ae84c14..29ad85a16ce 100644 --- a/spec/services/verify_pages_domain_service_spec.rb +++ b/spec/services/verify_pages_domain_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe VerifyPagesDomainService do +RSpec.describe VerifyPagesDomainService do using RSpec::Parameterized::TableSyntax include EmailHelpers diff --git a/spec/services/web_hook_service_spec.rb b/spec/services/web_hook_service_spec.rb index 4a917ecdbb5..2be481c5b62 100644 --- a/spec/services/web_hook_service_spec.rb +++ b/spec/services/web_hook_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe WebHookService do +RSpec.describe WebHookService do include StubRequests let(:project) { create(:project) } diff --git a/spec/services/wiki_pages/base_service_spec.rb b/spec/services/wiki_pages/base_service_spec.rb index fede86a5192..6ccc796014c 100644 --- a/spec/services/wiki_pages/base_service_spec.rb +++ b/spec/services/wiki_pages/base_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe WikiPages::BaseService do +RSpec.describe WikiPages::BaseService do let(:project) { double('project') } let(:user) { double('user') } diff --git a/spec/services/wiki_pages/create_service_spec.rb b/spec/services/wiki_pages/create_service_spec.rb index 2a17805110e..44b57088319 100644 --- a/spec/services/wiki_pages/create_service_spec.rb +++ b/spec/services/wiki_pages/create_service_spec.rb @@ -2,6 +2,6 @@ require 'spec_helper' -describe WikiPages::CreateService do +RSpec.describe WikiPages::CreateService do it_behaves_like 'WikiPages::CreateService#execute', :project end diff --git a/spec/services/wiki_pages/destroy_service_spec.rb b/spec/services/wiki_pages/destroy_service_spec.rb index b6fee1fd896..9384ea1cd43 100644 --- a/spec/services/wiki_pages/destroy_service_spec.rb +++ b/spec/services/wiki_pages/destroy_service_spec.rb @@ -2,6 +2,6 @@ require 'spec_helper' -describe WikiPages::DestroyService do +RSpec.describe WikiPages::DestroyService do it_behaves_like 'WikiPages::DestroyService#execute', :project end diff --git a/spec/services/wiki_pages/event_create_service_spec.rb b/spec/services/wiki_pages/event_create_service_spec.rb index c725c67d7a7..abf3bcb4c4d 100644 --- a/spec/services/wiki_pages/event_create_service_spec.rb +++ b/spec/services/wiki_pages/event_create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe WikiPages::EventCreateService do +RSpec.describe WikiPages::EventCreateService do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } @@ -14,21 +14,6 @@ describe WikiPages::EventCreateService do let(:action) { :created } let(:response) { subject.execute(slug, page, action) } - context 'feature flag is not enabled' do - before do - stub_feature_flags(wiki_events: false) - end - - it 'does not error' do - expect(response).to be_success - .and have_attributes(message: /No event created/) - end - - it 'does not create an event' do - expect { response }.not_to change(Event, :count) - end - end - context 'the user is nil' do subject { described_class.new(nil) } diff --git a/spec/services/wiki_pages/update_service_spec.rb b/spec/services/wiki_pages/update_service_spec.rb index ac629a96f9a..33ac98e764d 100644 --- a/spec/services/wiki_pages/update_service_spec.rb +++ b/spec/services/wiki_pages/update_service_spec.rb @@ -2,6 +2,6 @@ require 'spec_helper' -describe WikiPages::UpdateService do +RSpec.describe WikiPages::UpdateService do it_behaves_like 'WikiPages::UpdateService#execute', :project end diff --git a/spec/services/wikis/create_attachment_service_spec.rb b/spec/services/wikis/create_attachment_service_spec.rb index 4adfaa24874..50cb9ac111c 100644 --- a/spec/services/wikis/create_attachment_service_spec.rb +++ b/spec/services/wikis/create_attachment_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -describe Wikis::CreateAttachmentService do +RSpec.describe Wikis::CreateAttachmentService do let(:container) { create(:project, :wiki_repo) } let(:user) { create(:user) } let(:file_name) { 'filename.txt' } diff --git a/spec/services/x509_certificate_revoke_service_spec.rb b/spec/services/x509_certificate_revoke_service_spec.rb index c2b2576904c..adad3281c13 100644 --- a/spec/services/x509_certificate_revoke_service_spec.rb +++ b/spec/services/x509_certificate_revoke_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -describe X509CertificateRevokeService do +RSpec.describe X509CertificateRevokeService do describe '#execute' do let(:service) { described_class.new } let!(:x509_signature_1) { create(:x509_commit_signature, x509_certificate: x509_certificate, verification_status: :verified ) } |