Skip to content
Snippets Groups Projects
Commit d466ee50 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 6a9d7c00
No related branches found
No related tags found
No related merge requests found
Showing
with 570 additions and 105 deletions
# frozen_string_literal: true
module API
module Entities
class NotificationSetting < Grape::Entity
expose :level
expose :events, if: ->(notification_setting, _) { notification_setting.custom? } do
::NotificationSetting.email_events.each do |event|
expose event
end
end
end
end
end
# frozen_string_literal: true
module API
module Entities
class PagesDomain < Grape::Entity
expose :domain
expose :url
expose :verified?, as: :verified
expose :verification_code, as: :verification_code
expose :enabled_until
expose :auto_ssl_enabled
expose :certificate,
if: ->(pages_domain, _) { pages_domain.certificate? },
using: Entities::PagesDomainCertificate do |pages_domain|
pages_domain
end
end
end
end
# frozen_string_literal: true
module API
module Entities
class PagesDomainBasic < Grape::Entity
expose :domain
expose :url
expose :project_id
expose :verified?, as: :verified
expose :verification_code, as: :verification_code
expose :enabled_until
expose :auto_ssl_enabled
expose :certificate,
as: :certificate_expiration,
if: ->(pages_domain, _) { pages_domain.certificate? },
using: Entities::PagesDomainCertificateExpiration do |pages_domain|
pages_domain
end
end
end
end
# frozen_string_literal: true
module API
module Entities
class PagesDomainCertificate < Grape::Entity
expose :subject
expose :expired?, as: :expired
expose :certificate
expose :certificate_text
end
end
end
# frozen_string_literal: true
module API
module Entities
class ProjectAccess < Entities::MemberAccess
end
end
end
# frozen_string_literal: true
module API
module Entities
class ResourceLabelEvent < Grape::Entity
expose :id
expose :user, using: Entities::UserBasic
expose :created_at
expose :resource_type do |event, options|
event.issuable.class.name
end
expose :resource_id do |event, options|
event.issuable.id
end
expose :label, using: Entities::LabelBasic
expose :action
end
end
end
# frozen_string_literal: true
module API
module Entities
class Suggestion < Grape::Entity
expose :id
expose :from_line
expose :to_line
expose :appliable?, as: :appliable
expose :applied
expose :from_content
expose :to_content
end
end
end
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# rubocop:disable Style/Documentation
class RecalculateProjectAuthorizations
def perform(user_ids)
user_ids.each do |user_id|
user = User.find_by(id: user_id)
next unless user
service = Users::RefreshAuthorizedProjectsService.new(
user,
incorrect_auth_found_callback:
->(project_id, access_level) do
logger.info(message: 'Removing ProjectAuthorizations',
user_id: user.id,
project_id: project_id,
access_level: access_level)
end,
missing_auth_found_callback:
->(project_id, access_level) do
logger.info(message: 'Creating ProjectAuthorizations',
user_id: user.id,
project_id: project_id,
access_level: access_level)
end
)
service.execute
end
end
private
def logger
@logger ||= Gitlab::BackgroundMigration::Logger.build
end
end
end
end
Loading
Loading
@@ -353,11 +353,7 @@ module Gitlab
def fetch_blob(sha, path)
return unless sha
 
# Load only patch_hard_limit_bytes number of bytes for the blob
# Because otherwise, it is too large to be displayed
Blob.lazy(
repository.project, sha, path,
blob_size_limit: Gitlab::Git::Diff.patch_hard_limit_bytes)
Blob.lazy(repository.project, sha, path)
end
 
def total_blob_lines(blob)
Loading
Loading
Loading
Loading
@@ -130,8 +130,7 @@ module Gitlab
# :skip is the number of commits to skip
# :order is the commits order and allowed value is :none (default), :date,
# :topo, or any combination of them (in an array). Commit ordering types
# are documented here:
# http://www.rubydoc.info/github/libgit2/rugged/Rugged#SORT_NONE-constant)
# are documented here: https://git-scm.com/docs/git-log#_commit_ordering
def find_all(repo, options = {})
wrapped_gitaly_errors do
Gitlab::GitalyClient::CommitService.new(repo).find_all_commits(options)
Loading
Loading
Loading
Loading
@@ -324,6 +324,7 @@ module Gitlab
request.after = GitalyClient.timestamp(options[:after]) if options[:after]
request.before = GitalyClient.timestamp(options[:before]) if options[:before]
request.revision = encode_binary(options[:ref]) if options[:ref]
request.order = options[:order].upcase if options[:order].present?
 
request.paths = encode_repeated(Array(options[:path])) if options[:path].present?
 
Loading
Loading
Loading
Loading
@@ -68,12 +68,10 @@ module Gitlab
.select([namespaces[:id], members[:access_level]])
.except(:order)
 
if Feature.enabled?(:share_group_with_group, default_enabled: true)
# Namespaces shared with any of the group
cte << Group.select([namespaces[:id], 'group_group_links.group_access AS access_level'])
.joins(join_group_group_links)
.joins(join_members_on_group_group_links)
end
# Namespaces shared with any of the group
cte << Group.select([namespaces[:id], 'group_group_links.group_access AS access_level'])
.joins(join_group_group_links)
.joins(join_members_on_group_group_links)
 
# Sub groups of any groups the user is a member of.
cte << Group.select([
Loading
Loading
@@ -114,6 +112,8 @@ module Gitlab
members = Member.arel_table
 
cond = group_group_links[:shared_with_group_id].eq(members[:source_id])
.and(members[:source_type].eq('Namespace'))
.and(members[:requested_at].eq(nil))
.and(members[:user_id].eq(user.id))
Arel::Nodes::InnerJoin.new(members, Arel::Nodes::On.new(cond))
end
Loading
Loading
Loading
Loading
@@ -201,7 +201,6 @@
"yarn-deduplicate": "^1.1.1"
},
"resolutions": {
"at.js": "https://gitlab.com/gitlab-org/frontend/At.js.git#121ce9a557b51c33f5693ac8df52d2bda1e53cbe",
"vue-jest/ts-jest": "24.0.0",
"monaco-editor": "0.18.1"
},
Loading
Loading
# frozen_string_literal: true
 
module QA
context 'Create', :smoke do
context 'Create', :smoke, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/issues/205511', type: :bug } do
describe 'Snippet creation' do
it 'User creates a snippet' do
Flow::Login.sign_in
Loading
Loading
# frozen_string_literal: true
FactoryBot.define do
factory :project_authorization do
user
project
access_level { Gitlab::Access::REPORTER }
end
end
import { shallowMount, createLocalVue } from '@vue/test-utils';
import { mount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { GlLoadingIcon } from '@gitlab/ui';
import ErrorMessage from '~/ide/components/error_message.vue';
Loading
Loading
@@ -15,7 +15,7 @@ describe('IDE error message component', () => {
actions: { setErrorMessage: setErrorMessageMock },
});
 
wrapper = shallowMount(ErrorMessage, {
wrapper = mount(ErrorMessage, {
propsData: {
message: {
text: 'some text',
Loading
Loading
@@ -38,15 +38,18 @@ describe('IDE error message component', () => {
wrapper = null;
});
 
const findDismissButton = () => wrapper.find('button[aria-label=Dismiss]');
const findActionButton = () => wrapper.find('button.gl-alert-action');
it('renders error message', () => {
const text = 'error message';
createComponent({ text });
expect(wrapper.text()).toContain(text);
});
 
it('clears error message on click', () => {
it('clears error message on dismiss click', () => {
createComponent();
wrapper.trigger('click');
findDismissButton().trigger('click');
 
expect(setErrorMessageMock).toHaveBeenCalledWith(expect.any(Object), null, undefined);
});
Loading
Loading
@@ -68,29 +71,27 @@ describe('IDE error message component', () => {
});
 
it('renders action button', () => {
const button = wrapper.find('button');
const button = findActionButton();
 
expect(button.exists()).toBe(true);
expect(button.text()).toContain(message.actionText);
});
 
it('does not clear error message on click', () => {
wrapper.trigger('click');
expect(setErrorMessageMock).not.toHaveBeenCalled();
it('does not show dismiss button', () => {
expect(findDismissButton().exists()).toBe(false);
});
 
it('dispatches action', () => {
wrapper.find('button').trigger('click');
findActionButton().trigger('click');
 
expect(actionMock).toHaveBeenCalledWith(message.actionPayload);
});
 
it('does not dispatch action when already loading', () => {
wrapper.find('button').trigger('click');
findActionButton().trigger('click');
actionMock.mockReset();
return wrapper.vm.$nextTick(() => {
wrapper.find('button').trigger('click');
findActionButton().trigger('click');
 
return wrapper.vm.$nextTick().then(() => {
expect(actionMock).not.toHaveBeenCalled();
Loading
Loading
@@ -106,7 +107,7 @@ describe('IDE error message component', () => {
resolveAction = resolve;
}),
);
wrapper.find('button').trigger('click');
findActionButton().trigger('click');
 
return wrapper.vm.$nextTick(() => {
expect(wrapper.find(GlLoadingIcon).isVisible()).toBe(true);
Loading
Loading
@@ -115,7 +116,7 @@ describe('IDE error message component', () => {
});
 
it('hides loading icon when operation finishes', () => {
wrapper.find('button').trigger('click');
findActionButton().trigger('click');
return actionMock()
.then(() => wrapper.vm.$nextTick())
.then(() => {
Loading
Loading
Loading
Loading
@@ -61,14 +61,14 @@ describe('ide component, non-empty repo', () => {
});
 
it('shows error message when set', done => {
expect(vm.$el.querySelector('.flash-container')).toBe(null);
expect(vm.$el.querySelector('.gl-alert')).toBe(null);
 
vm.$store.state.errorMessage = {
text: 'error',
};
 
vm.$nextTick(() => {
expect(vm.$el.querySelector('.flash-container')).not.toBe(null);
expect(vm.$el.querySelector('.gl-alert')).not.toBe(null);
 
done();
});
Loading
Loading
import { shallowMount, createLocalVue } from '@vue/test-utils';
import { mount, shallowMount } from '@vue/test-utils';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
 
const TEST_TITLE = 'lorem-ipsum-dolar-sit-amit-consectur-adipiscing-elit-sed-do';
const STYLE_TRUNCATED = 'display: inline-block; max-width: 20px;';
const STYLE_NORMAL = 'display: inline-block; max-width: 1000px;';
const TEXT_SHORT = 'lorem';
const TEXT_LONG = 'lorem-ipsum-dolar-sit-amit-consectur-adipiscing-elit-sed-do';
 
const localVue = createLocalVue();
const TEXT_TRUNCATE = 'white-space: nowrap; overflow:hidden;';
const STYLE_NORMAL = `${TEXT_TRUNCATE} display: inline-block; max-width: 1000px;`; // does not overflows
const STYLE_OVERFLOWED = `${TEXT_TRUNCATE} display: inline-block; max-width: 50px;`; // overflowed when text is long
 
const createElementWithStyle = (style, content) => `<a href="#" style="${style}">${content}</a>`;
 
describe('TooltipOnTruncate component', () => {
let wrapper;
let parent;
 
const createComponent = ({ propsData, ...options } = {}) => {
wrapper = shallowMount(localVue.extend(TooltipOnTruncate), {
localVue,
wrapper = shallowMount(TooltipOnTruncate, {
attachToDocument: true,
propsData: {
title: TEST_TITLE,
...propsData,
},
attrs: {
style: STYLE_OVERFLOWED,
},
...options,
});
};
 
const createWrappedComponent = ({ propsData, ...options }) => {
// set a parent around the tested component
parent = mount(
{
props: {
title: { default: '' },
},
template: `
<TooltipOnTruncate :title="title" truncate-target="child" style="${STYLE_OVERFLOWED}">
<div>{{title}}</div>
</TooltipOnTruncate>
`,
components: {
TooltipOnTruncate,
},
},
{
propsData: { ...propsData },
attachToDocument: true,
...options,
},
);
wrapper = parent.find(TooltipOnTruncate);
};
const hasTooltip = () => wrapper.classes('js-show-tooltip');
afterEach(() => {
wrapper.destroy();
});
 
const hasTooltip = () => wrapper.classes('js-show-tooltip');
describe('with default target', () => {
it('renders tooltip if truncated', done => {
it('renders tooltip if truncated', () => {
createComponent({
attrs: {
style: STYLE_TRUNCATED,
propsData: {
title: TEXT_LONG,
},
slots: {
default: [TEST_TITLE],
default: [TEXT_LONG],
},
});
 
wrapper.vm
.$nextTick()
.then(() => {
expect(hasTooltip()).toBe(true);
expect(wrapper.attributes('data-original-title')).toEqual(TEST_TITLE);
expect(wrapper.attributes('data-placement')).toEqual('top');
})
.then(done)
.catch(done.fail);
return wrapper.vm.$nextTick().then(() => {
expect(hasTooltip()).toBe(true);
expect(wrapper.attributes('data-original-title')).toEqual(TEXT_LONG);
expect(wrapper.attributes('data-placement')).toEqual('top');
});
});
 
it('does not render tooltip if normal', done => {
it('does not render tooltip if normal', () => {
createComponent({
attrs: {
style: STYLE_NORMAL,
propsData: {
title: TEXT_SHORT,
},
slots: {
default: [TEST_TITLE],
default: [TEXT_SHORT],
},
});
 
wrapper.vm
.$nextTick()
.then(() => {
expect(hasTooltip()).toBe(false);
})
.then(done)
.catch(done.fail);
return wrapper.vm.$nextTick().then(() => {
expect(hasTooltip()).toBe(false);
});
});
});
 
describe('with child target', () => {
it('renders tooltip if truncated', done => {
it('renders tooltip if truncated', () => {
createComponent({
attrs: {
style: STYLE_NORMAL,
},
propsData: {
title: TEXT_LONG,
truncateTarget: 'child',
},
slots: {
default: createElementWithStyle(STYLE_TRUNCATED, TEST_TITLE),
default: createElementWithStyle(STYLE_OVERFLOWED, TEXT_LONG),
},
});
 
wrapper.vm
.$nextTick()
.then(() => {
expect(hasTooltip()).toBe(true);
})
.then(done)
.catch(done.fail);
return wrapper.vm.$nextTick().then(() => {
expect(hasTooltip()).toBe(true);
});
});
 
it('does not render tooltip if normal', done => {
it('does not render tooltip if normal', () => {
createComponent({
propsData: {
truncateTarget: 'child',
},
slots: {
default: createElementWithStyle(STYLE_NORMAL, TEST_TITLE),
default: createElementWithStyle(STYLE_NORMAL, TEXT_LONG),
},
});
 
wrapper.vm
.$nextTick()
.then(() => {
expect(hasTooltip()).toBe(false);
})
.then(done)
.catch(done.fail);
return wrapper.vm.$nextTick().then(() => {
expect(hasTooltip()).toBe(false);
});
});
});
 
describe('with fn target', () => {
it('renders tooltip if truncated', done => {
it('renders tooltip if truncated', () => {
createComponent({
attrs: {
style: STYLE_NORMAL,
},
propsData: {
title: TEXT_LONG,
truncateTarget: el => el.childNodes[1],
},
slots: {
default: [
createElementWithStyle('', TEST_TITLE),
createElementWithStyle(STYLE_TRUNCATED, TEST_TITLE),
createElementWithStyle('', TEXT_LONG),
createElementWithStyle(STYLE_OVERFLOWED, TEXT_LONG),
],
},
});
 
wrapper.vm
.$nextTick()
.then(() => {
expect(hasTooltip()).toBe(true);
})
.then(done)
.catch(done.fail);
return wrapper.vm.$nextTick().then(() => {
expect(hasTooltip()).toBe(true);
});
});
});
 
describe('placement', () => {
it('sets data-placement when tooltip is rendered', done => {
it('sets data-placement when tooltip is rendered', () => {
const placement = 'bottom';
 
createComponent({
Loading
Loading
@@ -151,21 +162,75 @@ describe('TooltipOnTruncate component', () => {
placement,
},
attrs: {
style: STYLE_TRUNCATED,
style: STYLE_OVERFLOWED,
},
slots: {
default: TEST_TITLE,
default: TEXT_LONG,
},
});
 
wrapper.vm
.$nextTick()
.then(() => {
expect(hasTooltip()).toBe(true);
expect(wrapper.attributes('data-placement')).toEqual(placement);
})
.then(done)
.catch(done.fail);
return wrapper.vm.$nextTick().then(() => {
expect(hasTooltip()).toBe(true);
expect(wrapper.attributes('data-placement')).toEqual(placement);
});
});
});
describe('updates when title and slot content changes', () => {
describe('is initialized with a long text', () => {
beforeEach(() => {
createWrappedComponent({
propsData: { title: TEXT_LONG },
});
return parent.vm.$nextTick();
});
it('renders tooltip', () => {
expect(hasTooltip()).toBe(true);
expect(wrapper.attributes('data-original-title')).toEqual(TEXT_LONG);
expect(wrapper.attributes('data-placement')).toEqual('top');
});
it('does not render tooltip after updated to a short text', () => {
parent.setProps({
title: TEXT_SHORT,
});
return wrapper.vm
.$nextTick()
.then(() => wrapper.vm.$nextTick()) // wait 2 times to get an updated slot
.then(() => {
expect(hasTooltip()).toBe(false);
});
});
});
describe('is initialized with a short text', () => {
beforeEach(() => {
createWrappedComponent({
propsData: { title: TEXT_SHORT },
});
return wrapper.vm.$nextTick();
});
it('does not render tooltip', () => {
expect(hasTooltip()).toBe(false);
});
it('renders tooltip after updated to a long text', () => {
parent.setProps({
title: TEXT_LONG,
});
return wrapper.vm
.$nextTick()
.then(() => wrapper.vm.$nextTick()) // wait 2 times to get an updated slot
.then(() => {
expect(hasTooltip()).toBe(true);
expect(wrapper.attributes('data-original-title')).toEqual(TEXT_LONG);
expect(wrapper.attributes('data-placement')).toEqual('top');
});
});
});
});
});
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::BackgroundMigration::RecalculateProjectAuthorizations, :migration, schema: 20200204113223 do
let(:users_table) { table(:users) }
let(:namespaces_table) { table(:namespaces) }
let(:projects_table) { table(:projects) }
let(:project_authorizations_table) { table(:project_authorizations) }
let(:members_table) { table(:members) }
let(:group_group_links) { table(:group_group_links) }
let(:project_group_links) { table(:project_group_links) }
let(:user) { users_table.create!(id: 1, email: 'user@example.com', projects_limit: 10) }
let(:group) { namespaces_table.create!(type: 'Group', name: 'group', path: 'group') }
subject { described_class.new.perform([user.id]) }
context 'missing authorization' do
context 'personal project' do
before do
user_namespace = namespaces_table.create!(owner_id: user.id, name: 'User', path: 'user')
projects_table.create!(id: 1,
name: 'personal-project',
path: 'personal-project',
visibility_level: 0,
namespace_id: user_namespace.id)
end
it 'creates correct authorization' do
expect { subject }.to change { project_authorizations_table.count }.from(0).to(1)
expect(project_authorizations_table.all).to(
match_array([have_attributes(user_id: 1, project_id: 1, access_level: 40)]))
end
end
context 'group membership' do
before do
projects_table.create!(id: 1, name: 'group-project', path: 'group-project',
visibility_level: 0, namespace_id: group.id)
members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
type: 'GroupMember', access_level: 20, notification_level: 3)
end
it 'creates correct authorization' do
expect { subject }.to change { project_authorizations_table.count }.from(0).to(1)
expect(project_authorizations_table.all).to(
match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)]))
end
end
context 'inherited group membership' do
before do
sub_group = namespaces_table.create!(type: 'Group', name: 'subgroup',
path: 'subgroup', parent_id: group.id)
projects_table.create!(id: 1, name: 'group-project', path: 'group-project',
visibility_level: 0, namespace_id: sub_group.id)
members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
type: 'GroupMember', access_level: 20, notification_level: 3)
end
it 'creates correct authorization' do
expect { subject }.to change { project_authorizations_table.count }.from(0).to(1)
expect(project_authorizations_table.all).to(
match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)]))
end
end
context 'project membership' do
before do
project = projects_table.create!(id: 1, name: 'group-project', path: 'group-project',
visibility_level: 0, namespace_id: group.id)
members_table.create!(user_id: user.id, source_id: project.id, source_type: 'Project',
type: 'ProjectMember', access_level: 20, notification_level: 3)
end
it 'creates correct authorization' do
expect { subject }.to change { project_authorizations_table.count }.from(0).to(1)
expect(project_authorizations_table.all).to(
match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)]))
end
end
context 'shared group' do
before do
members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
type: 'GroupMember', access_level: 30, notification_level: 3)
shared_group = namespaces_table.create!(type: 'Group', name: 'shared group',
path: 'shared-group')
projects_table.create!(id: 1, name: 'project', path: 'project', visibility_level: 0,
namespace_id: shared_group.id)
group_group_links.create(shared_group_id: shared_group.id, shared_with_group_id: group.id,
group_access: 20)
end
it 'creates correct authorization' do
expect { subject }.to change { project_authorizations_table.count }.from(0).to(1)
expect(project_authorizations_table.all).to(
match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)]))
end
end
context 'shared project' do
before do
members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
type: 'GroupMember', access_level: 30, notification_level: 3)
another_group = namespaces_table.create!(type: 'Group', name: 'another group', path: 'another-group')
shared_project = projects_table.create!(id: 1, name: 'shared project', path: 'shared-project',
visibility_level: 0, namespace_id: another_group.id)
project_group_links.create(project_id: shared_project.id, group_id: group.id, group_access: 20)
end
it 'creates correct authorization' do
expect { subject }.to change { project_authorizations_table.count }.from(0).to(1)
expect(project_authorizations_table.all).to(
match_array([have_attributes(user_id: 1, project_id: 1, access_level: 20)]))
end
end
end
context 'unapproved access requests' do
context 'group membership' do
before do
projects_table.create!(id: 1, name: 'group-project', path: 'group-project',
visibility_level: 0, namespace_id: group.id)
members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
type: 'GroupMember', access_level: 20, requested_at: Time.now, notification_level: 3)
end
it 'does not create authorization' do
expect { subject }.not_to change { project_authorizations_table.count }.from(0)
end
end
context 'inherited group membership' do
before do
sub_group = namespaces_table.create!(type: 'Group', name: 'subgroup', path: 'subgroup',
parent_id: group.id)
projects_table.create!(id: 1, name: 'group-project', path: 'group-project',
visibility_level: 0, namespace_id: sub_group.id)
members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
type: 'GroupMember', access_level: 20, requested_at: Time.now, notification_level: 3)
end
it 'does not create authorization' do
expect { subject }.not_to change { project_authorizations_table.count }.from(0)
end
end
context 'project membership' do
before do
project = projects_table.create!(id: 1, name: 'group-project', path: 'group-project',
visibility_level: 0, namespace_id: group.id)
members_table.create!(user_id: user.id, source_id: project.id, source_type: 'Project',
type: 'ProjectMember', access_level: 20, requested_at: Time.now, notification_level: 3)
end
it 'does not create authorization' do
expect { subject }.not_to change { project_authorizations_table.count }.from(0)
end
end
context 'shared group' do
before do
members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
type: 'GroupMember', access_level: 30, requested_at: Time.now, notification_level: 3)
shared_group = namespaces_table.create!(type: 'Group', name: 'shared group',
path: 'shared-group')
projects_table.create!(id: 1, name: 'project', path: 'project', visibility_level: 0,
namespace_id: shared_group.id)
group_group_links.create(shared_group_id: shared_group.id, shared_with_group_id: group.id,
group_access: 20)
end
it 'does not create authorization' do
expect { subject }.not_to change { project_authorizations_table.count }.from(0)
end
end
context 'shared project' do
before do
members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
type: 'GroupMember', access_level: 30, requested_at: Time.now, notification_level: 3)
another_group = namespaces_table.create!(type: 'Group', name: 'another group', path: 'another-group')
shared_project = projects_table.create!(id: 1, name: 'shared project', path: 'shared-project',
visibility_level: 0, namespace_id: another_group.id)
project_group_links.create(project_id: shared_project.id, group_id: group.id, group_access: 20)
end
it 'does not create authorization' do
expect { subject }.not_to change { project_authorizations_table.count }.from(0)
end
end
end
context 'incorrect authorization' do
before do
project = projects_table.create!(id: 1, name: 'group-project', path: 'group-project',
visibility_level: 0, namespace_id: group.id)
members_table.create!(user_id: user.id, source_id: group.id, source_type: 'Namespace',
type: 'GroupMember', access_level: 30, notification_level: 3)
project_authorizations_table.create!(user_id: user.id, project_id: project.id,
access_level: 10)
end
it 'fixes authorization' do
expect { subject }.not_to change { project_authorizations_table.count }.from(1)
expect(project_authorizations_table.all).to(
match_array([have_attributes(user_id: 1, project_id: 1, access_level: 30)]))
end
end
context 'unwanted authorization' do
before do
project = projects_table.create!(name: 'group-project', path: 'group-project',
visibility_level: 0, namespace_id: group.id)
project_authorizations_table.create!(user_id: user.id, project_id: project.id,
access_level: 10)
end
it 'deletes authorization' do
expect { subject }.to change { project_authorizations_table.count }.from(1).to(0)
end
end
context 'deleted user' do
let(:nonexistent_user_id) { User.maximum(:id).to_i + 999 }
it 'does not fail' do
expect { described_class.new.perform([nonexistent_user_id]) }.not_to raise_error
end
end
end
Loading
Loading
@@ -175,7 +175,7 @@ describe Gitlab::Diff::File do
[diff_file.new_content_sha, diff_file.new_path], [diff_file.old_content_sha, diff_file.old_path]
]
 
expect(project.repository).to receive(:blobs_at).with(items, blob_size_limit: 100 * 1024).and_call_original
expect(project.repository).to receive(:blobs_at).with(items, blob_size_limit: 10.megabytes).and_call_original
 
old_data = diff_file.old_blob.data
data = diff_file.new_blob.data
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment