@@ -26,7 +27,7 @@ describe('common_utils browser specific specs', () => {
});
it('adds height for fileTitle and compareVersionsHeader screen is large enough', () => {
- spyOn(breakpointInstance, 'isDesktop').and.returnValue(true);
+ jest.spyOn(breakpointInstance, 'isDesktop').mockReturnValue(true);
setFixtures(`
@@ -37,6 +38,8 @@ describe('common_utils browser specific specs', () => {
`);
+ mockOffsetHeight(document.querySelector('.diff-file'), 100);
+ mockOffsetHeight(document.querySelector('.mr-version-controls'), 18);
expect(commonUtils.contentTop()).toBe(18);
});
});
@@ -54,6 +57,17 @@ describe('common_utils browser specific specs', () => {
it('returns true when provided `el` is in viewport', () => {
el.setAttribute('style', `position: absolute; right: ${window.innerWidth + 0.2};`);
+ mockBoundingClientRect(el, {
+ x: 8,
+ y: 8,
+ width: 0,
+ height: 0,
+ top: 8,
+ right: 8,
+ bottom: 8,
+ left: 8,
+ });
+
document.body.appendChild(el);
expect(commonUtils.isInViewport(el)).toBe(true);
@@ -61,6 +75,17 @@ describe('common_utils browser specific specs', () => {
it('returns false when provided `el` is not in viewport', () => {
el.setAttribute('style', 'position: absolute; top: -1000px; left: -1000px;');
+ mockBoundingClientRect(el, {
+ x: -1000,
+ y: -1000,
+ width: 0,
+ height: 0,
+ top: -1000,
+ right: -1000,
+ bottom: -1000,
+ left: -1000,
+ });
+
document.body.appendChild(el);
expect(commonUtils.isInViewport(el)).toBe(false);
diff --git a/spec/lib/gitlab/database/transaction/context_spec.rb b/spec/lib/gitlab/database/transaction/context_spec.rb
index 3c2c5649784..37cfc841d48 100644
--- a/spec/lib/gitlab/database/transaction/context_spec.rb
+++ b/spec/lib/gitlab/database/transaction/context_spec.rb
@@ -62,6 +62,26 @@ RSpec.describe Gitlab::Database::Transaction::Context do
it { expect(data[:queries]).to eq(['SELECT 1', 'SELECT * FROM users']) }
end
+ describe '#track_backtrace' do
+ before do
+ subject.track_backtrace(caller)
+ end
+
+ it { expect(data[:backtraces]).to be_a(Array) }
+ it { expect(data[:backtraces]).to all(be_a(Array)) }
+ it { expect(data[:backtraces].length).to eq(1) }
+ it { expect(data[:backtraces][0][0]).to be_a(String) }
+
+ it 'appends the backtrace' do
+ subject.track_backtrace(caller)
+
+ expect(data[:backtraces].length).to eq(2)
+ expect(subject.backtraces).to be_a(Array)
+ expect(subject.backtraces).to all(be_a(Array))
+ expect(subject.backtraces[1][0]).to be_a(String)
+ end
+ end
+
describe '#duration' do
before do
subject.set_start_time
diff --git a/spec/lib/gitlab/database/transaction/observer_spec.rb b/spec/lib/gitlab/database/transaction/observer_spec.rb
index 7aa24217dc3..e5cc0106c9b 100644
--- a/spec/lib/gitlab/database/transaction/observer_spec.rb
+++ b/spec/lib/gitlab/database/transaction/observer_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe Gitlab::Database::Transaction::Observer do
User.first
expect(transaction_context).to be_a(::Gitlab::Database::Transaction::Context)
- expect(context.keys).to match_array(%i(start_time depth savepoints queries))
+ expect(context.keys).to match_array(%i(start_time depth savepoints queries backtraces))
expect(context[:depth]).to eq(2)
expect(context[:savepoints]).to eq(1)
expect(context[:queries].length).to eq(1)
@@ -35,6 +35,7 @@ RSpec.describe Gitlab::Database::Transaction::Observer do
expect(context[:depth]).to eq(2)
expect(context[:savepoints]).to eq(1)
expect(context[:releases]).to eq(1)
+ expect(context[:backtraces].length).to eq(1)
end
describe '.extract_sql_command' do
diff --git a/spec/migrations/update_integrations_trigger_type_new_on_insert_spec.rb b/spec/migrations/update_integrations_trigger_type_new_on_insert_spec.rb
new file mode 100644
index 00000000000..41cf35b40f4
--- /dev/null
+++ b/spec/migrations/update_integrations_trigger_type_new_on_insert_spec.rb
@@ -0,0 +1,102 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe UpdateIntegrationsTriggerTypeNewOnInsert do
+ let(:migration) { described_class.new }
+ let(:integrations) { table(:integrations) }
+
+ shared_examples 'transforms known types' do
+ # This matches Gitlab::Integrations::StiType at the time the original trigger
+ # was added in db/migrate/20210721135638_add_triggers_to_integrations_type_new.rb
+ let(:namespaced_integrations) do
+ %w[
+ Asana Assembla Bamboo Bugzilla Buildkite Campfire Confluence CustomIssueTracker Datadog
+ Discord DroneCi EmailsOnPush Ewm ExternalWiki Flowdock HangoutsChat Irker Jenkins Jira Mattermost
+ MattermostSlashCommands MicrosoftTeams MockCi MockMonitoring Packagist PipelinesEmail Pivotaltracker
+ Prometheus Pushover Redmine Slack SlackSlashCommands Teamcity UnifyCircuit WebexTeams Youtrack
+
+ Github GitlabSlackApplication
+ ]
+ end
+
+ it 'sets `type_new` to the transformed `type` class name' do
+ namespaced_integrations.each do |type|
+ integration = integrations.create!(type: "#{type}Service")
+
+ expect(integration.reload).to have_attributes(
+ type: "#{type}Service",
+ type_new: "Integrations::#{type}"
+ )
+ end
+ end
+ end
+
+ describe '#up' do
+ before do
+ migrate!
+ end
+
+ describe 'INSERT trigger with dynamic mapping' do
+ it_behaves_like 'transforms known types'
+
+ it 'transforms unknown types if it ends in "Service"' do
+ integration = integrations.create!(type: 'AcmeService')
+
+ expect(integration.reload).to have_attributes(
+ type: 'AcmeService',
+ type_new: 'Integrations::Acme'
+ )
+ end
+
+ it 'ignores "Service" occurring elsewhere in the type' do
+ integration = integrations.create!(type: 'ServiceAcmeService')
+
+ expect(integration.reload).to have_attributes(
+ type: 'ServiceAcmeService',
+ type_new: 'Integrations::ServiceAcme'
+ )
+ end
+
+ it 'copies unknown types if it does not end with "Service"' do
+ integration = integrations.create!(type: 'Integrations::Acme')
+
+ expect(integration.reload).to have_attributes(
+ type: 'Integrations::Acme',
+ type_new: 'Integrations::Acme'
+ )
+ end
+ end
+ end
+
+ describe '#down' do
+ before do
+ migration.up
+ migration.down
+ end
+
+ describe 'INSERT trigger with static mapping' do
+ it_behaves_like 'transforms known types'
+
+ it 'ignores types that are already namespaced' do
+ integration = integrations.create!(type: 'Integrations::Asana')
+
+ expect(integration.reload).to have_attributes(
+ type: 'Integrations::Asana',
+ type_new: nil
+ )
+ end
+
+ it 'ignores types that are unknown' do
+ integration = integrations.create!(type: 'FooBar')
+
+ expect(integration.reload).to have_attributes(
+ type: 'FooBar',
+ type_new: nil
+ )
+ end
+ end
+ end
+end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 26add23bde9..5245df10a71 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1919,15 +1919,15 @@ RSpec.describe User do
user.ban!
end
- it 'activates the user' do
- user.activate
+ it 'unbans the user' do
+ user.unban
expect(user.banned?).to eq(false)
expect(user.active?).to eq(true)
end
it 'deletes the BannedUser record' do
- expect { user.activate }.to change { Users::BannedUser.count }.by(-1)
+ expect { user.unban }.to change { Users::BannedUser.count }.by(-1)
expect(Users::BannedUser.where(user_id: user.id)).not_to exist
end
end
diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml
index c5bcedd491a..26ce484d716 100644
--- a/spec/requests/api/project_attributes.yml
+++ b/spec/requests/api/project_attributes.yml
@@ -149,6 +149,7 @@ build_service_desk_setting: # service_desk_setting
unexposed_attributes:
- project_id
- issue_template_key
+ - file_template_project_id
- outgoing_name
remapped_attributes:
project_key: service_desk_address
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 383940ce34a..bc88fdfcd5d 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -12,6 +12,8 @@ RSpec.describe API::Users do
let(:omniauth_user) { create(:omniauth_user) }
let(:ldap_blocked_user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') }
let(:private_user) { create(:user, private_profile: true) }
+ let(:deactivated_user) { create(:user, state: 'deactivated') }
+ let(:banned_user) { create(:user, :banned) }
context 'admin notes' do
let_it_be(:admin) { create(:admin, note: '2019-10-06 | 2FA added | user requested | www.gitlab.com') }
@@ -2964,6 +2966,169 @@ RSpec.describe API::Users do
end
end
+ describe 'POST /users/:id/ban', :aggregate_failures do
+ context 'when admin' do
+ subject(:ban_user) { post api("/users/#{user_id}/ban", admin) }
+
+ context 'with an active user' do
+ let(:user_id) { user.id }
+
+ it 'bans an active user' do
+ ban_user
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response.body).to eq('true')
+ expect(user.reload.state).to eq('banned')
+ end
+ end
+
+ context 'with an ldap blocked user' do
+ let(:user_id) { ldap_blocked_user.id }
+
+ it 'does not ban ldap blocked users' do
+ ban_user
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('You cannot ban ldap_blocked users.')
+ expect(ldap_blocked_user.reload.state).to eq('ldap_blocked')
+ end
+ end
+
+ context 'with a deactivated user' do
+ let(:user_id) { deactivated_user.id }
+
+ it 'does not ban deactivated users' do
+ ban_user
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('You cannot ban deactivated users.')
+ expect(deactivated_user.reload.state).to eq('deactivated')
+ end
+ end
+
+ context 'with a banned user' do
+ let(:user_id) { banned_user.id }
+
+ it 'does not ban banned users' do
+ ban_user
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('You cannot ban banned users.')
+ expect(banned_user.reload.state).to eq('banned')
+ end
+ end
+
+ context 'with a non existent user' do
+ let(:user_id) { non_existing_record_id }
+
+ it 'does not ban non existent users' do
+ ban_user
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response['message']).to eq('404 User Not Found')
+ end
+ end
+
+ context 'with an invalid id' do
+ let(:user_id) { 'ASDF' }
+
+ it 'does not ban invalid id users' do
+ ban_user
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ it 'is not available for non-admin users' do
+ post api("/users/#{user.id}/ban", user)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(user.reload.state).to eq('active')
+ end
+ end
+
+ describe 'POST /users/:id/unban', :aggregate_failures do
+ context 'when admin' do
+ subject(:unban_user) { post api("/users/#{user_id}/unban", admin) }
+
+ context 'with a banned user' do
+ let(:user_id) { banned_user.id }
+
+ it 'activates a banned user' do
+ unban_user
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(banned_user.reload.state).to eq('active')
+ end
+ end
+
+ context 'with an ldap_blocked user' do
+ let(:user_id) { ldap_blocked_user.id }
+
+ it 'does not unban ldap_blocked users' do
+ unban_user
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('You cannot unban ldap_blocked users.')
+ expect(ldap_blocked_user.reload.state).to eq('ldap_blocked')
+ end
+ end
+
+ context 'with a deactivated user' do
+ let(:user_id) { deactivated_user.id }
+
+ it 'does not unban deactivated users' do
+ unban_user
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('You cannot unban deactivated users.')
+ expect(deactivated_user.reload.state).to eq('deactivated')
+ end
+ end
+
+ context 'with an active user' do
+ let(:user_id) { user.id }
+
+ it 'does not unban active users' do
+ unban_user
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('You cannot unban active users.')
+ expect(user.reload.state).to eq('active')
+ end
+ end
+
+ context 'with a non existent user' do
+ let(:user_id) { non_existing_record_id }
+
+ it 'does not unban non existent users' do
+ unban_user
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response['message']).to eq('404 User Not Found')
+ end
+ end
+
+ context 'with an invalid id user' do
+ let(:user_id) { 'ASDF' }
+
+ it 'does not unban invalid id users' do
+ unban_user
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ it 'is not available for non admin users' do
+ post api("/users/#{banned_user.id}/unban", user)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(user.reload.state).to eq('active')
+ end
+ end
+
describe "GET /users/:id/memberships" do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
diff --git a/spec/services/users/ban_service_spec.rb b/spec/services/users/ban_service_spec.rb
index 6f49ee08782..79f3cbeb46d 100644
--- a/spec/services/users/ban_service_spec.rb
+++ b/spec/services/users/ban_service_spec.rb
@@ -50,7 +50,7 @@ RSpec.describe Users::BanService do
response = ban_user
expect(response[:status]).to eq(:error)
- expect(response[:message]).to match(/State cannot transition/)
+ expect(response[:message]).to match('You cannot ban blocked users.')
end
it_behaves_like 'does not modify the BannedUser record or user state'
diff --git a/spec/services/users/unban_service_spec.rb b/spec/services/users/unban_service_spec.rb
index b2b3140ccb3..d536baafdcc 100644
--- a/spec/services/users/unban_service_spec.rb
+++ b/spec/services/users/unban_service_spec.rb
@@ -50,7 +50,7 @@ RSpec.describe Users::UnbanService do
response = unban_user
expect(response[:status]).to eq(:error)
- expect(response[:message]).to match(/State cannot transition/)
+ expect(response[:message]).to match('You cannot unban active users.')
end
it_behaves_like 'does not modify the BannedUser record or user state'