Commit e19aecad authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-05-16

# Conflicts:
#	app/models/group.rb
#	spec/models/project_spec.rb

[ci skip]
parents 5816a885 60b14e52
...@@ -69,7 +69,7 @@ module Projects ...@@ -69,7 +69,7 @@ module Projects
@project_runners = @project.runners.ordered @project_runners = @project.runners.ordered
@assignable_runners = current_user @assignable_runners = current_user
.ci_authorized_runners .ci_owned_runners
.assignable_for(project) .assignable_for(project)
.ordered .ordered
.page(params[:page]).per(20) .page(params[:page]).per(20)
......
...@@ -2,6 +2,7 @@ class Appearance < ActiveRecord::Base ...@@ -2,6 +2,7 @@ class Appearance < ActiveRecord::Base
include CacheMarkdownField include CacheMarkdownField
include AfterCommitQueue include AfterCommitQueue
include ObjectStorage::BackgroundMove include ObjectStorage::BackgroundMove
include WithUploads
prepend EE::Appearance prepend EE::Appearance
...@@ -16,8 +17,6 @@ class Appearance < ActiveRecord::Base ...@@ -16,8 +17,6 @@ class Appearance < ActiveRecord::Base
mount_uploader :logo, AttachmentUploader mount_uploader :logo, AttachmentUploader
mount_uploader :header_logo, AttachmentUploader mount_uploader :header_logo, AttachmentUploader
has_many :uploads, as: :model, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
CACHE_KEY = "current_appearance:#{Gitlab::VERSION}".freeze CACHE_KEY = "current_appearance:#{Gitlab::VERSION}".freeze
after_commit :flush_redis_cache after_commit :flush_redis_cache
......
...@@ -53,7 +53,7 @@ module Ci ...@@ -53,7 +53,7 @@ module Ci
# Without that, placeholders would miss one and couldn't match. # Without that, placeholders would miss one and couldn't match.
where(locked: false) where(locked: false)
.where.not("ci_runners.id IN (#{project.runners.select(:id).to_sql})") .where.not("ci_runners.id IN (#{project.runners.select(:id).to_sql})")
.specific .project_type
end end
validate :tag_constraints validate :tag_constraints
......
# Mounted uploaders are destroyed by carrierwave's after_commit
# hook. This hook fetches upload location (local vs remote) from
# Upload model. So it's neccessary to make sure that during that
# after_commit hook model's associated uploads are not deleted yet.
# IOW we can not use dependent: :destroy :
# has_many :uploads, as: :model, dependent: :destroy
#
# And because not-mounted uploads require presence of upload's
# object model when destroying them (FileUploader's `build_upload` method
# references `model` on delete), we can not use after_commit hook for these
# uploads.
#
# Instead FileUploads are destroyed in before_destroy hook and remaining uploads
# are destroyed by the carrierwave's after_commit hook.
module WithUploads
extend ActiveSupport::Concern
# Currently there is no simple way how to select only not-mounted
# uploads, it should be all FileUploaders so we select them by
# `uploader` class
FILE_UPLOADERS = %w(PersonalFileUploader NamespaceFileUploader FileUploader).freeze
included do
has_many :uploads, as: :model
before_destroy :destroy_file_uploads
end
# mounted uploads are deleted in carrierwave's after_commit hook,
# but FileUploaders which are not mounted must be deleted explicitly and
# it can not be done in after_commit because FileUploader requires loads
# associated model on destroy (which is already deleted in after_commit)
def destroy_file_uploads
self.uploads.where(uploader: FILE_UPLOADERS).find_each do |upload|
upload.destroy
end
end
end
...@@ -13,6 +13,7 @@ class Group < Namespace ...@@ -13,6 +13,7 @@ class Group < Namespace
include LoadedInGroupList include LoadedInGroupList
include GroupDescendant include GroupDescendant
include TokenAuthenticatable include TokenAuthenticatable
include WithUploads
has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent
alias_method :members, :group_members alias_method :members, :group_members
...@@ -33,10 +34,13 @@ class Group < Namespace ...@@ -33,10 +34,13 @@ class Group < Namespace
has_many :variables, class_name: 'Ci::GroupVariable' has_many :variables, class_name: 'Ci::GroupVariable'
has_many :custom_attributes, class_name: 'GroupCustomAttribute' has_many :custom_attributes, class_name: 'GroupCustomAttribute'
<<<<<<< HEAD
has_many :ldap_group_links, foreign_key: 'group_id', dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :ldap_group_links, foreign_key: 'group_id', dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :hooks, dependent: :destroy, class_name: 'GroupHook' # rubocop:disable Cop/ActiveRecordDependent has_many :hooks, dependent: :destroy, class_name: 'GroupHook' # rubocop:disable Cop/ActiveRecordDependent
has_many :uploads, as: :model, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :uploads, as: :model, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
=======
>>>>>>> upstream/master
has_many :boards has_many :boards
# We cannot simply set `has_many :audit_events, as: :entity, dependent: :destroy` # We cannot simply set `has_many :audit_events, as: :entity, dependent: :destroy`
......
...@@ -23,6 +23,7 @@ class Project < ActiveRecord::Base ...@@ -23,6 +23,7 @@ class Project < ActiveRecord::Base
include ::Gitlab::Utils::StrongMemoize include ::Gitlab::Utils::StrongMemoize
include ChronicDurationAttribute include ChronicDurationAttribute
include FastDestroyAll::Helpers include FastDestroyAll::Helpers
include WithUploads
# EE specific modules # EE specific modules
prepend EE::Project prepend EE::Project
...@@ -308,8 +309,6 @@ class Project < ActiveRecord::Base ...@@ -308,8 +309,6 @@ class Project < ActiveRecord::Base
inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } } inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } }
validates :variables, variable_duplicates: { scope: :environment_scope } validates :variables, variable_duplicates: { scope: :environment_scope }
has_many :uploads, as: :model, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
# Scopes # Scopes
scope :pending_delete, -> { where(pending_delete: true) } scope :pending_delete, -> { where(pending_delete: true) }
scope :without_deleted, -> { where(pending_delete: false) } scope :without_deleted, -> { where(pending_delete: false) }
......
...@@ -17,6 +17,7 @@ class User < ActiveRecord::Base ...@@ -17,6 +17,7 @@ class User < ActiveRecord::Base
include IgnorableColumn include IgnorableColumn
include BulkMemberAccessLoad include BulkMemberAccessLoad
include BlocksJsonSerialization include BlocksJsonSerialization
include WithUploads
prepend EE::User prepend EE::User
...@@ -139,7 +140,6 @@ class User < ActiveRecord::Base ...@@ -139,7 +140,6 @@ class User < ActiveRecord::Base
has_many :custom_attributes, class_name: 'UserCustomAttribute' has_many :custom_attributes, class_name: 'UserCustomAttribute'
has_many :callouts, class_name: 'UserCallout' has_many :callouts, class_name: 'UserCallout'
has_many :uploads, as: :model, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :term_agreements has_many :term_agreements
belongs_to :accepted_term, class_name: 'ApplicationSetting::Term' belongs_to :accepted_term, class_name: 'ApplicationSetting::Term'
...@@ -1021,12 +1021,19 @@ class User < ActiveRecord::Base ...@@ -1021,12 +1021,19 @@ class User < ActiveRecord::Base
!solo_owned_groups.present? !solo_owned_groups.present?
end end
def ci_authorized_runners def ci_owned_runners
@ci_authorized_runners ||= begin @ci_owned_runners ||= begin
runner_ids = Ci::RunnerProject project_runner_ids = Ci::RunnerProject
.where(project: authorized_projects(Gitlab::Access::MASTER)) .where(project: authorized_projects(Gitlab::Access::MASTER))
.select(:runner_id) .select(:runner_id)
Ci::Runner.specific.where(id: runner_ids)
group_runner_ids = Ci::RunnerNamespace
.where(namespace_id: owned_or_masters_groups.select(:id))
.select(:runner_id)
union = Gitlab::SQL::Union.new([project_runner_ids, group_runner_ids])
Ci::Runner.specific.where("ci_runners.id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
end end
end end
...@@ -1227,6 +1234,11 @@ class User < ActiveRecord::Base ...@@ -1227,6 +1234,11 @@ class User < ActiveRecord::Base
!terms_accepted? !terms_accepted?
end end
def owned_or_masters_groups
union = Gitlab::SQL::Union.new([owned_groups, masters_groups])
Group.from("(#{union.to_sql}) namespaces")
end
protected protected
# override, from Devise::Validatable # override, from Devise::Validatable
......
module Ci module Ci
class RunnerPolicy < BasePolicy class RunnerPolicy < BasePolicy
with_options scope: :subject, score: 0
condition(:shared) { @subject.is_shared? }
with_options scope: :subject, score: 0 with_options scope: :subject, score: 0
condition(:locked, scope: :subject) { @subject.locked? } condition(:locked, scope: :subject) { @subject.locked? }
condition(:authorized_runner) { @user.ci_authorized_runners.include?(@subject) } condition(:owned_runner) { @user.ci_owned_runners.exists?(@subject.id) }
rule { anonymous }.prevent_all rule { anonymous }.prevent_all
rule { admin | authorized_runner }.enable :assign_runner
rule { ~admin & shared }.prevent :assign_runner rule { admin | owned_runner }.policy do
enable :assign_runner
enable :read_runner
enable :update_runner
enable :delete_runner
end
rule { ~admin & locked }.prevent :assign_runner rule { ~admin & locked }.prevent :assign_runner
end end
end end
---
title: Fix deletion of Object Store uploads
merge_request:
author:
type: fixed
...@@ -201,6 +201,7 @@ module API ...@@ -201,6 +201,7 @@ module API
group = find_group!(params[:id]) group = find_group!(params[:id])
authorize! :admin_group, group authorize! :admin_group, group
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/46285')
destroy_conditionally!(group) do |group| destroy_conditionally!(group) do |group|
::Groups::DestroyService.new(group, current_user).execute ::Groups::DestroyService.new(group, current_user).execute
end end
......
...@@ -14,7 +14,7 @@ module API ...@@ -14,7 +14,7 @@ module API
use :pagination use :pagination
end end
get do get do
runners = filter_runners(current_user.ci_authorized_runners, params[:scope], without: %w(specific shared)) runners = filter_runners(current_user.ci_owned_runners, params[:scope], without: %w(specific shared))
present paginate(runners), with: Entities::Runner present paginate(runners), with: Entities::Runner
end end
...@@ -184,40 +184,35 @@ module API ...@@ -184,40 +184,35 @@ module API
def authenticate_show_runner!(runner) def authenticate_show_runner!(runner)
return if runner.is_shared || current_user.admin? return if runner.is_shared || current_user.admin?
forbidden!("No access granted") unless user_can_access_runner?(runner) forbidden!("No access granted") unless can?(current_user, :read_runner, runner)
end end
def authenticate_update_runner!(runner) def authenticate_update_runner!(runner)
return if current_user.admin? return if current_user.admin?
forbidden!("Runner is shared") if runner.is_shared? forbidden!("No access granted") unless can?(current_user, :update_runner, runner)
forbidden!("No access granted") unless user_can_access_runner?(runner)
end end
def authenticate_delete_runner!(runner) def authenticate_delete_runner!(runner)
return if current_user.admin? return if current_user.admin?
forbidden!("Runner is shared") if runner.is_shared?
forbidden!("Runner associated with more than one project") if runner.projects.count > 1 forbidden!("Runner associated with more than one project") if runner.projects.count > 1
forbidden!("No access granted") unless user_can_access_runner?(runner) forbidden!("No access granted") unless can?(current_user, :delete_runner, runner)
end end
def authenticate_enable_runner!(runner) def authenticate_enable_runner!(runner)
forbidden!("Runner is shared") if runner.is_shared? forbidden!("Runner is a group runner") if runner.group_type?
forbidden!("Runner is locked") if runner.locked?
return if current_user.admin? return if current_user.admin?
forbidden!("No access granted") unless user_can_access_runner?(runner) forbidden!("Runner is locked") if runner.locked?
forbidden!("No access granted") unless can?(current_user, :assign_runner, runner)
end end
def authenticate_list_runners_jobs!(runner) def authenticate_list_runners_jobs!(runner)
return if current_user.admin? return if current_user.admin?
forbidden!("No access granted") unless user_can_access_runner?(runner) forbidden!("No access granted") unless can?(current_user, :read_runner, runner)
end
def user_can_access_runner?(runner)
current_user.ci_authorized_runners.exists?(runner.id)
end end
end end
end end
......
...@@ -155,6 +155,7 @@ module API ...@@ -155,6 +155,7 @@ module API
group = find_group!(params[:id]) group = find_group!(params[:id])
authorize! :admin_group, group authorize! :admin_group, group
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/46285')
present ::Groups::DestroyService.new(group, current_user).execute, with: Entities::GroupDetail, current_user: current_user present ::Groups::DestroyService.new(group, current_user).execute, with: Entities::GroupDetail, current_user: current_user
end end
......
...@@ -58,7 +58,7 @@ module API ...@@ -58,7 +58,7 @@ module API
end end
def user_can_access_runner?(runner) def user_can_access_runner?(runner)
current_user.ci_authorized_runners.exists?(runner.id) current_user.ci_owned_runners.exists?(runner.id)
end end
end end
end end
......
...@@ -19,11 +19,11 @@ describe Projects::Settings::CiCdController do ...@@ -19,11 +19,11 @@ describe Projects::Settings::CiCdController do
end end
context 'with group runners' do context 'with group runners' do
let(:group_runner) { create(:ci_runner) } let(:group_runner) { create(:ci_runner, runner_type: :group_type) }
let(:parent_group) { create(:group) } let(:parent_group) { create(:group) }
let(:group) { create(:group, runners: [group_runner], parent: parent_group) } let(:group) { create(:group, runners: [group_runner], parent: parent_group) }
let(:other_project) { create(:project, group: group) } let(:other_project) { create(:project, group: group) }
let!(:project_runner) { create(:ci_runner, projects: [other_project]) } let!(:project_runner) { create(:ci_runner, projects: [other_project], runner_type: :project_type) }
let!(:shared_runner) { create(:ci_runner, :shared) } let!(:shared_runner) { create(:ci_runner, :shared) }
it 'sets assignable project runners only' do it 'sets assignable project runners only' do
...@@ -31,7 +31,7 @@ describe Projects::Settings::CiCdController do ...@@ -31,7 +31,7 @@ describe Projects::Settings::CiCdController do
get :show, namespace_id: project.namespace, project_id: project get :show, namespace_id: project.namespace, project_id: project
expect(assigns(:assignable_runners)).to eq [project_runner] expect(assigns(:assignable_runners)).to contain_exactly(project_runner)
end end
end end
end end
......
...@@ -5,7 +5,7 @@ describe Appearance do ...@@ -5,7 +5,7 @@ describe Appearance do
it { is_expected.to be_valid } it { is_expected.to be_valid }
it { is_expected.to have_many(:uploads).dependent(:destroy) } it { is_expected.to have_many(:uploads) }
describe '.current', :use_clean_rails_memory_store_caching do describe '.current', :use_clean_rails_memory_store_caching do
let!(:appearance) { create(:appearance) } let!(:appearance) { create(:appearance) }
...@@ -41,4 +41,12 @@ describe Appearance do ...@@ -41,4 +41,12 @@ describe Appearance do
expect(new_row.valid?).to eq(false) expect(new_row.valid?).to eq(false)
end end
end end
context 'with uploads' do
it_behaves_like 'model with mounted uploader', false do
let(:model_object) { create(:appearance, :with_logo) }
let(:upload_attribute) { :logo }
let(:uploader_class) { AttachmentUploader }
end
end
end end
...@@ -626,62 +626,26 @@ describe Ci::Runner do ...@@ -626,62 +626,26 @@ describe Ci::Runner do
end end
describe '.assignable_for' do describe '.assignable_for' do
let(:runner) { create(:ci_runner) } let!(:unlocked_project_runner) { create(:ci_runner, runner_type: :project_type, projects: [project]) }
let!(:locked_project_runner) { create(:ci_runner, runner_type: :project_type, locked: true, projects: [project]) }
let!(:group_runner) { create(:ci_runner, runner_type: :group_type) }
let!(:instance_runner) { create(:ci_runner, :shared) }
let(:project) { create(:project) } let(:project) { create(:project) }
let(:another_project) { create(:project) } let(:another_project) { create(:project) }
before do context 'with already assigned project' do
project.runners << runner subject { described_class.assignable_for(project) }
end
context 'with shared runners' do
before do
runner.update(is_shared: true)
end
context 'does not give owned runner' do
subject { described_class.assignable_for(project) }
it { is_expected.to be_empty }
end
context 'does not give shared runner' do
subject { described_class.assignable_for(another_project) }
it { is_expected.to be_empty }
end
end
context 'with unlocked runner' do
context 'does not give owned runner' do
subject { described_class.assignable_for(project) }
it { is_expected.to be_empty }
end
context 'does give a specific runner' do it { is_expected.to be_empty }
subject { described_class.assignable_for(another_project) }
it { is_expected.to contain_exactly(runner) }
end
end end
context 'with locked runner' do context 'with a different project' do
before do subject { described_class.assignable_for(another_project) }
runner.update(locked: true)
end
context 'does not give owned runner' do
subject { described_class.assignable_for(project) }
it { is_expected.to be_empty }
end
context 'does not give a locked runner' do
subject { described_class.assignable_for(another_project) }
it { is_expected.to be_empty } it { is_expected.to include(unlocked_project_runner) }
end it { is_expected.not_to include(group_runner) }
it { is_expected.not_to include(locked_project_runner) }
it { is_expected.not_to include(instance_runner) }
end end
end end
......
...@@ -15,7 +15,7 @@ describe Group do ...@@ -15,7 +15,7 @@ describe Group do
it { is_expected.to have_many(:notification_settings).dependent(:destroy) } it { is_expected.to have_many(:notification_settings).dependent(:destroy) }
it { is_expected.to have_many(:labels).class_name('GroupLabel') } it { is_expected.to have_many(:labels).class_name('GroupLabel') }
it { is_expected.to have_many(:variables).class_name('Ci::GroupVariable') } it { is_expected.to have_many(:variables).class_name('Ci::GroupVariable') }
it { is_expected.to have_many(:uploads).dependent(:destroy) } it { is_expected.to have_many(:uploads) }
it { is_expected.to have_one(:chat_team) } it { is_expected.to have_one(:chat_team) }
it { is_expected.to have_many(:custom_attributes).class_name('GroupCustomAttribute') } it { is_expected.to have_many(:custom_attributes).class_name('GroupCustomAttribute') }
it { is_expected.to have_many(:audit_events).dependent(false) } it { is_expected.to have_many(:audit_events).dependent(false) }
...@@ -692,4 +692,12 @@ describe Group do ...@@ -692,4 +692,12 @@ describe Group do
end end
end end
end end
context 'with uploads' do
it_behaves_like 'model with mounted uploader', true do
let(:model_object) { create(:group, :with_avatar) }
let(:upload_attribute) { :avatar }
let(:uploader_class) { AttachmentUploader }
end
end
end end
...@@ -77,8 +77,12 @@ describe Project do ...@@ -77,8 +77,12 @@ describe Project do
it { is_expected.to have_many(:project_group_links) } it { is_expected.to have_many(:project_group_links) }
it { is_expected.to have_many(:notification_settings).dependent(:delete_all) } it { is_expected.to have_many(:notification_settings).dependent(:delete_all) }
it { is_expected.to have_many(:forks).through(:forked_project_links) } it { is_expected.to have_many(:forks).through(:forked_project_links) }
<<<<<<< HEAD
it { is_expected.to have_many(:approver_groups).dependent(:destroy) } it { is_expected.to have_many(:approver_groups).dependent(:destroy) }
it { is_expected.to have_many(:uploads).dependent(:destroy) } it { is_expected.to have_many(:uploads).dependent(:destroy) }
=======
it { is_expected.to have_many(:uploads) }
>>>>>>> upstream/master
it { is_expected.to have_many(:pipeline_schedules) } it { is_expected.to have_many(:pipeline_schedules) }
it { is_expected.to have_many(:members_and_requesters) } it { is_expected.to have_many(:members_and_requesters) }
it { is_expected.to have_many(:clusters) } it { is_expected.to have_many(:clusters) }
...@@ -4125,4 +4129,12 @@ describe Project do ...@@ -4125,4 +4129,12 @@ describe Project do
it { is_expected.to be_nil } it { is_expected.to be_nil }
end end
end end
context 'with uploads' do
it_behaves_like 'model with mounted uploader', true do
let(:model_object) { create(:project, :with_avatar) }
let(:upload_attribute) { :avatar }
let(:uploader_class) { AttachmentUploader }
end
end
end end
...@@ -44,7 +44,7 @@ describe User do ...@@ -44,7 +44,7 @@ describe User do
it { is_expected.to have_many(:builds).dependent(:nullify) } it { is_expected.to have_many(:builds).dependent(:nullify) }
it { is_expected.to have_many(:pipelines).dependent(:nullify) } it { is_expected.to have_many(:pipelines).dependent(:nullify) }
it { is_expected.to have_many(:chat_names).dependent(:destroy) } it { is_expected.to have_many(:chat_names).dependent(:destroy) }
it { is_expected.to have_many(:uploads).dependent(:destroy) } it { is_expected.to have_many(:uploads) }
it { is_expected.to have_many(:reported_abuse_reports).dependent(:destroy).class_name('AbuseReport') } it { is_expected.to have_many(:reported_abuse_reports).dependent(:destroy).class_name('AbuseReport') }
it { is_expected.to have_many(:custom_attributes).class_name('UserCustomAttribute') } it { is_expected.to have_many(:custom_attributes).class_name('UserCustomAttribute') }
...@@ -1835,28 +1835,54 @@ describe User do ...@@ -1835,28 +1835,54 @@ describe User do
end end
end end
describe '#ci_authorized_runners' do describe '#ci_owned_runners' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:runner) { create(:ci_runner) } let(:runner_1) { create(:ci_runner) }
let(:runner_2) { create(:ci_runner) }
before do context 'without any projects nor groups' do
project.runners << runner let!(:project) { create(:project, runners: [runner_1]) }
end let!(:group) { create(:group) }
context 'without any projects' do
let(:project) { create(:project) }
it 'does not load' do it 'does not load' do
expect(user.ci_authorized_runners).to be_empty expect(user.ci_owned_runners).to be_empty
end end
end end
context 'with personal projects runners' do context 'with personal projects runners' do
let(:namespace) { create(:namespace, owner: user) } let(:namespace) { create(:namespace, owner: user) }
let(:project) { create(:project, namespace: namespace) } let!(:project) { create(:project, namespace: namespace, runners: [runner_1]) }
it 'loads' do
expect(user.ci_owned_runners).to contain_exactly(runner_1)
end
end
context 'with personal group runner' do
let!(:project) { create(:project, runners: [runner_1]) }
let!(:group) do
create(:group, runners: [runner_2]).tap do |group|
group.add_owner(user)
end
end
it 'loads' do
expect(user.ci_owned_runners).to contain_exactly(runner_2)
end
end
context 'with personal project and group runner' do
let(:namespace) { create(:namespace, owner: user) }
let!(:project) { create(:project, namespace: namespace, runners: [runner_1]) }
let!(:group) do
create(:group, runners: [runner_2]).tap do |group|
group.add_owner(user)
end
end
it 'loads' do it 'loads' do
expect(user.ci_authorized_runners).to contain_exactly(runner) expect(user.ci_owned_runners).to contain_exactly(runner_1, runner_2)
end end
end end
...@@ -1867,7 +1893,7 @@ describe User do ...@@ -1867,7 +1893,7 @@ describe User do
end end
it 'loads' do it 'loads' do
expect(user.ci_authorized_runners).to contain_exactly(runner) expect(user.ci_owned_runners).to contain_exactly(runner_1)
end end
end end
...@@ -1877,14 +1903,28 @@ describe User do ...@@ -1877,14 +1903,28 @@ describe User do
end end
it 'does not load' do it 'does not load' do
expect(user.ci_authorized_runners).to be_empty expect(user.ci_owned_runners).to be_empty
end end
end end
end end
context 'with groups projects runners' do context 'with groups projects runners' do
let(:group) { create(:group) } let(:group) { create(:group) }
let(:project) { create(:project, group: group) } let!(:project) { create(:project, group: group, runners: [runner_1]) }
def add_user(access)
group.add_user(user, access)
end
it_behaves_like :member
end
context 'with groups runners' do
let!(:group) do
create(:group, runners: [runner_1]).tap do |group|
group.add_owner(user)
end
end
def add_user(access) def add_user(access)
group.add_user(user, access) group.add_user(user, access)
...@@ -1894,7 +1934,7 @@ describe User do ...@@ -1894,7 +1934,7 @@ describe User do
end end
context 'with other projects runners' do context 'with other projects runners' do
let(:project) { create(:project) } let!(:project) { create(:project, runners: [runner_1]) }
def add_user(access) def add_user(access)
project.add_role(user, access) project.add_role(user, access)
...@@ -1907,7 +1947,7 @@ describe User do ...@@ -1907,7 +1947,7 @@ describe User do
let(:group) { create(:group) } let(:group) { create(:group) }
let(:another_user) { create(:user) } let(:another_user) { create(:user) }
let(:subgroup) { create(:group, parent: group) } let(:subgroup) { create(:group, parent: group) }
let(:project) { create(:project, group: subgroup) } let!(:project) { create(:project, group: subgroup, runners: [runner_1]) }
def add_user(access) def add_user(access)
group.add_user(user, access) group.add_user(user, access)
...@@ -2872,4 +2912,12 @@ describe User do ...@@ -2872,4 +2912,12 @@ describe User do
expect { user.increment_failed_attempts! }.not_to change(user, :failed_attempts) expect { user.increment_failed_attempts! }.not_to change(user, :failed_attempts)
end end
end end
context 'with uploads' do
it_behaves_like 'model with mounted uploader', false do
let(:model_object) { create(:user, :with_avatar) }
let(:upload_attribute) { :avatar }
let(:uploader_class) { AttachmentUploader }
end
end
end end
...@@ -27,7 +27,7 @@ describe API::Runners do ...@@ -27,7 +27,7 @@ describe API::Runners do
end end
end end
let!(:group_runner) { create(:ci_runner, description: 'Group runner', groups: [group]) } let!(:group_runner) { create(:ci_runner, description: 'Group runner', groups: [group], runner_type: :group_type) }
before do before do
# Set project access for users # Set project access for users
...@@ -48,7 +48,7 @@ describe API::Runners do ...@@ -48,7 +48,7 @@ describe API::Runners do
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response[0]).to have_key('ip_address') expect(json_response[0]).to have_key('ip_address')
expect(descriptions).to contain_exactly( expect(descriptions).to contain_exactly(
'Project runner', 'Two projects runner' 'Project runner', 'Two projects runner', 'Group runner'
) )
expect(shared).to be_falsey expect(shared).to be_falsey
end end
...@@ -592,6 +592,15 @@ describe API::Runners do ...@@ -592,6 +592,15 @@ describe API::Runners do
end.to change { project.runners.count }.by(+1) end.to change { project.runners.count }.by(+1)
expect(response).to have_gitlab_http_status(201) expect(response).to have_gitlab_http_status(201)
end end
it 'enables a shared runner' do
expect do
post api("/projects/#{project.id}/runners", admin), runner_id: shared_runner.id
end.to change { project.runners.count }.by(1)
expect(shared_runner.reload).not_to be_shared
expect(response).to have_gitlab_http_status(201)
end
end end
context 'user is not admin' do context 'user is not admin' do
......
require 'spec_helper'
shared_examples_for 'model with mounted uploader' do |supports_fileuploads|
describe '.destroy' do
before do
stub_uploads_object_storage(uploader_class)
model_object.public_send(upload_attribute).migrate!(ObjectStorage::Store::REMOTE)
end
it 'deletes remote uploads' do
expect_any_instance_of(CarrierWave::Storage::Fog::File).to receive(:delete).and_call_original
expect { model_object.destroy }.to change { Upload.count }.by(-1)
end
it 'deletes any FileUploader uploads which are not mounted', skip: !supports_fileuploads do
create(:upload, uploader: FileUploader, model: model_object)
expect { model_object.destroy }.to change { Upload.count }.by(-2)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment