Commit 13395b51 authored by Jarka Kadlecova's avatar Jarka Kadlecova

Add epics to EEU license

parent 16eb31b1
---
title: Introduce EEU lincese with epics as the first feature
merge_request:
author:
type: added
class Groups::EpicIssuesController < Groups::EpicsController class Groups::EpicIssuesController < Groups::EpicsController
include IssuableLinks include IssuableLinks
before_action :check_epics_available!
skip_before_action :authorize_destroy_issuable! skip_before_action :authorize_destroy_issuable!
before_action :authorize_admin_epic!, only: [:create, :destroy] before_action :authorize_admin_epic!, only: [:create, :destroy]
before_action :authorize_issue_link_association!, only: :destroy before_action :authorize_issue_link_association!, only: :destroy
......
...@@ -2,6 +2,7 @@ class Groups::EpicsController < Groups::ApplicationController ...@@ -2,6 +2,7 @@ class Groups::EpicsController < Groups::ApplicationController
include IssuableActions include IssuableActions
include IssuableCollections include IssuableCollections
before_action :check_epics_available!
before_action :epic, except: :index before_action :epic, except: :index
before_action :set_issuables_index, only: :index before_action :set_issuables_index, only: :index
before_action :authorize_update_issuable!, only: :update before_action :authorize_update_issuable!, only: :update
......
...@@ -52,7 +52,9 @@ class License < ActiveRecord::Base ...@@ -52,7 +52,9 @@ class License < ActiveRecord::Base
commit_committer_check commit_committer_check
].freeze ].freeze
EEU_FEATURES = EEP_FEATURES EEU_FEATURES = EEP_FEATURES + %i[
epics
]
# List all features available for early adopters, # List all features available for early adopters,
# i.e. users that started using GitLab.com before # i.e. users that started using GitLab.com before
......
...@@ -5,6 +5,7 @@ module EE ...@@ -5,6 +5,7 @@ module EE
prepended do prepended do
with_scope :subject with_scope :subject
condition(:ldap_synced) { @subject.ldap_synced? } condition(:ldap_synced) { @subject.ldap_synced? }
condition(:epics_disabled) { !@subject.feature_available?(:epics) }
rule { reporter }.policy do rule { reporter }.policy do
enable :admin_list enable :admin_list
...@@ -46,6 +47,14 @@ module EE ...@@ -46,6 +47,14 @@ module EE
rule { ldap_synced & (admin | owner) }.enable :update_group_member rule { ldap_synced & (admin | owner) }.enable :update_group_member
rule { ldap_synced & (admin | (can_owners_manage_ldap & owner)) }.enable :override_group_member rule { ldap_synced & (admin | (can_owners_manage_ldap & owner)) }.enable :override_group_member
rule { epics_disabled }.policy do
prevent :read_epic
prevent :create_epic
prevent :admin_epic
prevent :update_epic
prevent :destroy_epic
end
end end
end end
end end
...@@ -3,6 +3,8 @@ module EpicIssues ...@@ -3,6 +3,8 @@ module EpicIssues
private private
def issues def issues
return [] unless issuable&.group&.feature_available?(:epics)
issuable.issues(current_user) issuable.issues(current_user)
end end
......
...@@ -11,134 +11,140 @@ describe Groups::EpicIssuesController do ...@@ -11,134 +11,140 @@ describe Groups::EpicIssuesController do
sign_in(user) sign_in(user)
end end
describe 'GET #index' do context 'when epics feature is enabled' do
let!(:epic_issues) { create(:epic_issue, epic: epic, issue: issue) }
before do before do
group.add_developer(user) stub_licensed_features(epics: true)
get :index, group_id: group, epic_id: epic.to_param
end
it 'returns status 200' do
expect(response.status).to eq(200)
end
it 'returns the correct json' do
expected_result = [
{
'id' => issue.id,
'title' => issue.title,
'state' => issue.state,
'reference' => "#{project.full_path}##{issue.iid}",
'path' => "/#{project.full_path}/issues/#{issue.iid}",
'destroy_relation_path' => "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issues.id}"
}
]
expect(JSON.parse(response.body)).to eq(expected_result)
end end
end
describe 'POST #create' do describe 'GET #index' do
subject do let!(:epic_issues) { create(:epic_issue, epic: epic, issue: issue) }
reference = [issue.to_reference(full: true)]
post :create, group_id: group, epic_id: epic.to_param, issue_references: reference
end
context 'when user has permissions to create requested association' do
before do before do
group.add_developer(user) group.add_developer(user)
end
it 'returns correct response for the correct issue reference' do get :index, group_id: group, epic_id: epic.to_param
subject end
list_service_response = EpicIssues::ListService.new(epic, user).execute
expect(response).to have_gitlab_http_status(200) it 'returns status 200' do
expect(json_response).to eq('message' => nil, 'issues' => list_service_response.as_json) expect(response.status).to eq(200)
end end
it 'creates a new EpicIssue record' do it 'returns the correct json' do
expect { subject }.to change { EpicIssue.count }.from(0).to(1) expected_result = [
{
'id' => issue.id,
'title' => issue.title,
'state' => issue.state,
'reference' => "#{project.full_path}##{issue.iid}",
'path' => "/#{project.full_path}/issues/#{issue.iid}",
'destroy_relation_path' => "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issues.id}"
}
]
expect(JSON.parse(response.body)).to eq(expected_result)
end end
end end
context 'when user does not have permissions to create requested association' do describe 'POST #create' do
it 'returns correct response for the correct issue reference' do subject do
subject reference = [issue.to_reference(full: true)]
expect(response).to have_gitlab_http_status(403) post :create, group_id: group, epic_id: epic.to_param, issue_references: reference
end end
it 'does not create a new EpicIssue record' do context 'when user has permissions to create requested association' do
expect { subject }.not_to change { EpicIssue.count }.from(0) before do
end group.add_developer(user)
end end
end
describe 'DELETE #destroy' do it 'returns correct response for the correct issue reference' do
let!(:epic_issue) { create(:epic_issue, epic: epic, issue: issue) } subject
list_service_response = EpicIssues::ListService.new(epic, user).execute
subject do expect(response).to have_gitlab_http_status(200)
delete :destroy, group_id: group, epic_id: epic.to_param, id: epic_issue.id expect(json_response).to eq('message' => nil, 'issues' => list_service_response.as_json)
end end
context 'when user has permissions to detele the link' do it 'creates a new EpicIssue record' do
before do expect { subject }.to change { EpicIssue.count }.from(0).to(1)
group.add_developer(user) end
end end
it 'returns status 200' do context 'when user does not have permissions to create requested association' do
subject it 'returns correct response for the correct issue reference' do
subject
expect(response.status).to eq(200) expect(response).to have_gitlab_http_status(403)
end end
it 'destroys the link' do it 'does not create a new EpicIssue record' do
expect { subject }.to change { EpicIssue.count }.from(1).to(0) expect { subject }.not_to change { EpicIssue.count }.from(0)
end
end end
end end
context 'when user does not have permissions to delete the link' do describe 'DELETE #destroy' do
it 'returns status 404' do let!(:epic_issue) { create(:epic_issue, epic: epic, issue: issue) }
subject
expect(response.status).to eq(403) subject do
delete :destroy, group_id: group, epic_id: epic.to_param, id: epic_issue.id
end end
it 'does not destroy the link' do context 'when user has permissions to detele the link' do
expect { subject }.not_to change { EpicIssue.count }.from(1) before do
end group.add_developer(user)
end end
context 'when the epic from the association does not equal epic from the path' do it 'returns status 200' do
subject do subject
delete :destroy, group_id: group, epic_id: another_epic.to_param, id: epic_issue.id
end
let(:another_epic) { create(:epic, group: group) } expect(response.status).to eq(200)
end
before do it 'destroys the link' do
group.add_developer(user) expect { subject }.to change { EpicIssue.count }.from(1).to(0)
end
end end
it 'returns status 404' do context 'when user does not have permissions to delete the link' do
subject it 'returns status 404' do
subject
expect(response.status).to eq(403)
end
expect(response.status).to eq(404) it 'does not destroy the link' do
expect { subject }.not_to change { EpicIssue.count }.from(1)
end
end end
it 'does not destroy the link' do context 'when the epic from the association does not equal epic from the path' do
expect { subject }.not_to change { EpicIssue.count }.from(1) subject do
delete :destroy, group_id: group, epic_id: another_epic.to_param, id: epic_issue.id
end
let(:another_epic) { create(:epic, group: group) }
before do
group.add_developer(user)
end
it 'returns status 404' do
subject
expect(response.status).to eq(404)
end
it 'does not destroy the link' do
expect { subject }.not_to change { EpicIssue.count }.from(1)
end
end end
end
context 'when the epic_issue record does not exists' do context 'when the epic_issue record does not exists' do
it 'returns status 404' do it 'returns status 404' do
delete :destroy, group_id: group, epic_id: epic.to_param, id: 9999 delete :destroy, group_id: group, epic_id: epic.to_param, id: 9999
expect(response.status).to eq(403) expect(response.status).to eq(403)
end
end end
end end
end end
......
...@@ -9,138 +9,172 @@ describe Groups::EpicsController do ...@@ -9,138 +9,172 @@ describe Groups::EpicsController do
sign_in(user) sign_in(user)
end end
describe "GET #index" do context 'when epics feature is disabled' do
let!(:epic_list) { create_list(:epic, 2, group: group) } shared_examples '404 status' do
it 'returns 404 status' do
subject
before do expect(response).to have_gitlab_http_status(404)
sign_in(user) end
group.add_developer(user)
end end
it "returns index" do describe 'GET #index' do
get :index, group_id: group subject { get :index, group_id: group }
expect(response).to have_gitlab_http_status(200) it_behaves_like '404 status'
end end
context 'with page param' do describe 'GET #show' do
let(:last_page) { group.epics.page.total_pages } subject { get :show, group_id: group, id: epic.to_param }
before do it_behaves_like '404 status'
allow(Kaminari.config).to receive(:default_per_page).and_return(1) end
end
describe 'PUT #update' do
subject { put :update, group_id: group, id: epic.to_param }
it_behaves_like '404 status'
end
end
it 'redirects to last_page if page number is larger than number of pages' do context 'when epics feature is enabled' do
get :index, group_id: group, page: (last_page + 1).to_param before do
stub_licensed_features(epics: true)
end
expect(response).to redirect_to(group_epics_path(page: last_page, state: controller.params[:state], scope: controller.params[:scope])) describe "GET #index" do
let!(:epic_list) { create_list(:epic, 2, group: group) }
before do
sign_in(user)
group.add_developer(user)
end end
it 'renders the specified page' do it "returns index" do
get :index, group_id: group, page: last_page.to_param get :index, group_id: group
expect(assigns(:epics).current_page).to eq(last_page)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(200)
end end
end
end
describe 'GET #show' do context 'with page param' do
def show_epic(format = :html) let(:last_page) { group.epics.page.total_pages }
get :show, group_id: group, id: epic.to_param, format: format
end
context 'when format is HTML' do before do
it 'renders template' do allow(Kaminari.config).to receive(:default_per_page).and_return(1)
group.add_developer(user) end
show_epic
it 'redirects to last_page if page number is larger than number of pages' do
get :index, group_id: group, page: (last_page + 1).to_param
expect(response).to redirect_to(group_epics_path(page: last_page, state: controller.params[:state], scope: controller.params[:scope]))
end
expect(response.content_type).to eq 'text/html' it 'renders the specified page' do
expect(response).to render_template 'groups/epics/show' get :index, group_id: group, page: last_page.to_param
expect(assigns(:epics).current_page).to eq(last_page)
expect(response).to have_gitlab_http_status(200)
end
end end
end
context 'with unauthorized user' do describe 'GET #show' do
it 'returns a not found 404 response' do def show_epic(format = :html)
get :show, group_id: group, id: epic.to_param, format: format
end
context 'when format is HTML' do
it 'renders template' do
group.add_developer(user)
show_epic show_epic
expect(response).to have_http_status(404)
expect(response.content_type).to eq 'text/html' expect(response.content_type).to eq 'text/html'
expect(response).to render_template 'groups/epics/show'
end end
end
end
context 'when format is JSON' do context 'with unauthorized user' do
it 'returns epic' do it 'returns a not found 404 response' do
group.add_developer(user) show_epic
show_epic(:json)
expect(response).to have_http_status(200) expect(response).to have_http_status(404)
expect(response).to match_response_schema('entities/epic') expect(response.content_type).to eq 'text/html'
end
end
end end
context 'with unauthorized user' do context 'when format is JSON' do
it 'returns a not found 404 response' do it 'returns epic' do
group.add_developer(user)
show_epic(:json) show_epic(:json)
expect(response).to have_http_status(404) expect(response).to have_http_status(200)
expect(response.content_type).to eq 'application/json' expect(response).to match_response_schema('entities/epic')
end end
end
end
end
describe 'PUT #update' do context 'with unauthorized user' do
before do it 'returns a not found 404 response' do
group.add_developer(user) show_epic(:json)
put :update, group_id: group, id: epic.to_param, epic: { title: 'New title' }, format: :json
end
it 'returns status 200' do expect(response).to have_http_status(404)
expect(response.status).to eq(200) expect(response.content_type).to eq 'application/json'
end
end
end
end end
it 'updates the epic correctly' do describe 'PUT #update' do
expect(epic.reload.title).to eq('New title') before do
end group.add_developer(user)
end put :update, group_id: group, id: epic.to_param, epic: { title: 'New title' }, format: :json
end
describe 'GET #realtime_changes' do it 'returns status 200' do
subject { get :realtime_changes, group_id: group, id: epic.to_param } expect(response.status).to eq(200)
it 'returns epic' do end
group.add_developer(user)
subject
expect(response.content_type).to eq 'application/json' it 'updates the epic correctly' do
expect(JSON.parse(response.body)).to include('title_text', 'title', 'description', 'description_text') expect(epic.reload.title).to eq('New title')
end
end end
context 'with unauthorized user' do describe 'GET #realtime_changes' do
it 'returns a not found 404 response' do subject { get :realtime_changes, group_id: group, id: epic.to_param }
it 'returns epic' do
group.add_developer(user)
subject subject
expect(response).to have_http_status(404) expect(response.content_type).to eq 'application/json'
expect(JSON.parse(response.body)).to include('title_text', 'title', 'description', 'description_text')
end end
end
end
describe "DELETE #destroy" do context 'with unauthorized user' do
before do it 'returns a not found 404 response' do
sign_in(user) subject
expect(response).to have_http_status(404)
end
end
end end
it "rejects a developer to destroy an epic" do describe "DELETE #destroy" do
group.add_developer(user) before do
delete :destroy, group_id: group, id: epic.to_param sign_in(user)
end
expect(response).to have_gitlab_http_status(404) it "rejects a developer to destroy an epic" do
end group.add_developer(user)
delete :destroy, group_id: group, id: epic.to_param
expect(response).to have_gitlab_http_status(404)
end
it "deletes the epic" do it "deletes the epic" do
group.add_owner(user) group.add_owner(user)
delete :destroy, group_id: group, id: epic.to_param delete :destroy, group_id: group, id: epic.to_param
expect(response).to have_gitlab_http_status(302) expect(response).to have_gitlab_http_status(302)
expect(controller).to set_flash[:notice].to(/The epic was successfully deleted\./) expect(controller).to set_flash[:notice].to(/The epic was successfully deleted\./)
end
end end
end end
end end
...@@ -7,6 +7,8 @@ feature 'Delete Epic', :js do ...@@ -7,6 +7,8 @@ feature 'Delete Epic', :js do
let!(:epic2) { create(:epic, group: group) } let!(:epic2) { create(:epic, group: group) }
before do before do
stub_licensed_features(epics: true)
sign_in(user) sign_in(user)
end end
......
...@@ -17,6 +17,8 @@ describe 'Epic Issues', :js do ...@@ -17,6 +17,8 @@ describe 'Epic Issues', :js do
end end
def visit_epic def visit_epic
stub_licensed_features(epics: true)
sign_in(user) sign_in(user)
visit group_epic_path(group, epic) visit group_epic_path(group, epic)
wait_for_requests wait_for_requests
......
...@@ -5,6 +5,8 @@ describe 'epics list', :js do ...@@ -5,6 +5,8 @@ describe 'epics list', :js do
let(:user) { create(:user) } let(:user) { create(:user) }
before do before do
stub_licensed_features(epics: true)
sign_in(user) sign_in(user)
end end
......
...@@ -6,6 +6,8 @@ feature 'Update Epic', :js do ...@@ -6,6 +6,8 @@ feature 'Update Epic', :js do
let(:epic) { create(:epic, group: group) } let(:epic) { create(:epic, group: group) }
before do before do
stub_licensed_features(epics: true)
sign_in(user) sign_in(user)
end end
......
...@@ -17,56 +17,72 @@ describe EpicsFinder do ...@@ -17,56 +17,72 @@ describe EpicsFinder do
described_class.new(search_user, params).execute described_class.new(search_user, params).execute
end end
context 'without param' do context 'when epics feature is disabled' do
it 'raises an error when group_id param is missing' do before do
expect { described_class.new(search_user).execute }.to raise_error { ArgumentError } group.add_developer(search_user)
end end
end
context 'when user can not read epics of a group' do it 'raises an exception' do
it 'raises an error when group_id param is missing' do expect { described_class.new(search_user).execute }.to raise_error { ArgumentError }
expect { epics }.to raise_error { ArgumentError }
end end
end end
context 'wtih correct params' do context 'when epics feature is enabled' do
before do before do
group.add_developer(search_user) stub_licensed_features(epics: true)
end end
it 'returns all epics that belong to the given group' do context 'without param' do
expect(epics).to contain_exactly(epic1, epic2, epic3) it 'raises an error when group_id param is missing' do
expect { described_class.new(search_user).execute }.to raise_error { ArgumentError }
end
end end
context 'by created_at' do context 'when user can not read epics of a group' do
it 'returns all epics created before the given date' do it 'raises an error when group_id param is missing' do
expect(epics(created_before: 2.days.ago)).to contain_exactly(epic1, epic2) expect { epics }.to raise_error { ArgumentError }
end end
end
it 'returns all epics created after the given date' do context 'wtih correct params' do
expect(epics(created_after: 2.days.ago)).to contain_exactly(epic3) before do
group.add_developer(search_user)
end end
it 'returns all epics created within the given interval' do it 'returns all epics that belong to the given group' do
expect(epics(created_after: 5.days.ago, created_before: 1.day.ago)).to contain_exactly(epic2) expect(epics).to contain_exactly(epic1, epic2, epic3)
end end
end
context 'by search' do context 'by created_at' do
it 'returns all epics that match the search' do it 'returns all epics created before the given date' do
expect(epics(search: 'awesome')).to contain_exactly(epic1, epic3) expect(epics(created_before: 2.days.ago)).to contain_exactly(epic1, epic2)
end
it 'returns all epics created after the given date' do
expect(epics(created_after: 2.days.ago)).to contain_exactly(epic3)
end
it 'returns all epics created within the given interval' do
expect(epics(created_after: 5.days.ago, created_before: 1.day.ago)).to contain_exactly(epic2)
end
end end
end
context 'by author' do context 'by search' do
it 'returns all epics authored by the given user' do it 'returns all epics that match the search' do
expect(epics(author_id: user.id)).to contain_exactly(epic2) expect(epics(search: 'awesome')).to contain_exactly(epic1, epic3)
end
end
context 'by author' do
it 'returns all epics authored by the given user' do
expect(epics(author_id: user.id)).to contain_exactly(epic2)
end
end end
end
context 'by iids' do context 'by iids' do
it 'returns all epics by the given iids' do it 'returns all epics by the given iids' do
expect(epics(iids: [epic1.iid, epic3.iid])).to contain_exactly(epic1, epic3) expect(epics(iids: [epic1.iid, epic3.iid])).to contain_exactly(epic1, epic3)
end
end end
end end
end end
......
...@@ -9,111 +9,128 @@ describe EpicPolicy do ...@@ -9,111 +9,128 @@ describe EpicPolicy do
described_class.new(user, epic) described_class.new(user, epic)
end end
context 'when an epic is in a private group' do context 'when epics feature is disabled' do
let(:group) { create(:group, :private) } let(:group) { create(:group, :public) }
it 'anonymous user can not read epics' do it 'no one can read epics' do
expect(permissions(nil, group)) group.add_owner(user)
.to be_disallowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'user who is not a group member can not read epics' do
expect(permissions(user, group)) expect(permissions(user, group))
.to be_disallowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic) .to be_disallowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end end
end
it 'guest group member can only read epics' do context 'when epics feature is enabled' do
group.add_guest(user) before do
stub_licensed_features(epics: true)
expect(permissions(user, group)).to be_allowed(:read_epic)
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end end
it 'reporter group member can manage epics' do context 'when an epic is in a private group' do
group.add_reporter(user) let(:group) { create(:group, :private) }
expect(permissions(user, group)).to be_disallowed(:destroy_epic) it 'anonymous user can not read epics' do
expect(permissions(user, group)) expect(permissions(nil, group))
.to be_allowed(:read_epic, :update_epic, :admin_epic, :create_epic) .to be_disallowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end end
it 'only group owner can destroy epics' do it 'user who is not a group member can not read epics' do
group.add_owner(user) expect(permissions(user, group))
.to be_disallowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
expect(permissions(user, group)) it 'guest group member can only read epics' do
.to be_allowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic) group.add_guest(user)
end
end
context 'when an epic is in an internal group' do expect(permissions(user, group)).to be_allowed(:read_epic)
let(:group) { create(:group, :internal) } expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'anonymous user can not read epics' do it 'reporter group member can manage epics' do
expect(permissions(nil, group)) group.add_reporter(user)
.to be_disallowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'user who is not a group member can only read epics' do expect(permissions(user, group)).to be_disallowed(:destroy_epic)
expect(permissions(user, group)).to be_allowed(:read_epic) expect(permissions(user, group))
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic) .to be_allowed(:read_epic, :update_epic, :admin_epic, :create_epic)
end end
it 'guest group member can only read epics' do it 'only group owner can destroy epics' do
group.add_guest(user) group.add_owner(user)
expect(permissions(user, group)).to be_allowed(:read_epic) expect(permissions(user, group))
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic) .to be_allowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
end end
it 'reporter group member can manage epics' do context 'when an epic is in an internal group' do
group.add_reporter(user) let(:group) { create(:group, :internal) }
expect(permissions(user, group)).to be_disallowed(:destroy_epic) it 'anonymous user can not read epics' do
expect(permissions(user, group)) expect(permissions(nil, group))
.to be_allowed(:read_epic, :update_epic, :admin_epic, :create_epic) .to be_disallowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end end
it 'only group owner can destroy epics' do it 'user who is not a group member can only read epics' do
group.add_owner(user) expect(permissions(user, group)).to be_allowed(:read_epic)
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
expect(permissions(user, group)) it 'guest group member can only read epics' do
.to be_allowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic) group.add_guest(user)
end
end
context 'when an epic is in a public group' do expect(permissions(user, group)).to be_allowed(:read_epic)
let(:group) { create(:group, :public) } expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'anonymous user can only read epics' do it 'reporter group member can manage epics' do
expect(permissions(nil, group)).to be_allowed(:read_epic) group.add_reporter(user)
expect(permissions(nil, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'user who is not a group member can only read epics' do expect(permissions(user, group)).to be_disallowed(:destroy_epic)
expect(permissions(user, group)).to be_allowed(:read_epic) expect(permissions(user, group))
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic) .to be_allowed(:read_epic, :update_epic, :admin_epic, :create_epic)
end end
it 'guest group member can only read epics' do it 'only group owner can destroy epics' do
group.add_guest(user) group.add_owner(user)
expect(permissions(user, group)).to be_allowed(:read_epic) expect(permissions(user, group))
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic) .to be_allowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
end end
it 'reporter group member can manage epics' do context 'when an epic is in a public group' do
group.add_reporter(user) let(:group) { create(:group, :public) }
expect(permissions(user, group)).to be_disallowed(:destroy_epic) it 'anonymous user can only read epics' do
expect(permissions(user, group)) expect(permissions(nil, group)).to be_allowed(:read_epic)
.to be_allowed(:read_epic, :update_epic, :admin_epic, :create_epic) expect(permissions(nil, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end end
it 'only group owner can destroy epics' do it 'user who is not a group member can only read epics' do
group.add_owner(user) expect(permissions(user, group)).to be_allowed(:read_epic)
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
expect(permissions(user, group)) it 'guest group member can only read epics' do
.to be_allowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic) group.add_guest(user)
expect(permissions(user, group)).to be_allowed(:read_epic)
expect(permissions(user, group)).to be_disallowed(:update_epic, :destroy_epic, :admin_epic, :create_epic)
end
it 'reporter group member can manage epics' do
group.add_reporter(user)
expect(permissions(user, group)).to be_disallowed(:destroy_epic)
expect(permissions(user, group))
.to be_allowed(:read_epic, :update_epic, :admin_epic, :create_epic)
end
it 'only group owner can destroy epics' do
group.add_owner(user)
expect(permissions(user, group))
.to be_allowed(:read_epic, :update_epic, :destroy_epic, :admin_epic, :create_epic)
end
end end
end end
end end
...@@ -20,6 +20,22 @@ describe GroupPolicy do ...@@ -20,6 +20,22 @@ describe GroupPolicy do
subject { described_class.new(current_user, group) } subject { described_class.new(current_user, group) }
context 'when epics feature is disabled' do
let(:current_user) { owner }
it { is_expected.to be_disallowed(:read_epic, :create_epic, :admin_epic, :destroy_epic) }
end
context 'when epics feature is enabled' do
before do
stub_licensed_features(epics: true)
end
let(:current_user) { owner }
it { is_expected.to be_allowed(:read_epic, :create_epic, :admin_epic, :destroy_epic) }
end
context 'when LDAP sync is not enabled' do context 'when LDAP sync is not enabled' do
context 'owner' do context 'owner' do
let(:current_user) { owner } let(:current_user) { owner }
......
...@@ -37,98 +37,110 @@ describe EpicIssues::CreateService do ...@@ -37,98 +37,110 @@ describe EpicIssues::CreateService do
end end
end end
context 'when user has permissions to link the issue' do context 'when epics feature is disabled' do
subject { assign_issue([valid_reference]) }
include_examples 'returns an error'
end
context 'when epics feature is enabled' do
before do before do
group.add_developer(user) stub_licensed_features(epics: true)
end end
context 'when the reference list is empty' do context 'when user has permissions to link the issue' do
it 'returns an error' do before do
expect(assign_issue([])).to eq(message: 'No Issue found for given params', status: :error, http_status: 404) group.add_developer(user)
end end
end
context 'when there is an issue to relate' do
context 'when shortcut for Issue is given' do
subject { assign_issue([issue.to_reference]) }
include_examples 'returns an error' context 'when the reference list is empty' do
it 'returns an error' do
expect(assign_issue([])).to eq(message: 'No Issue found for given params', status: :error, http_status: 404)
end
end end
context 'when a full reference is given' do context 'when there is an issue to relate' do
subject { assign_issue([valid_reference]) } context 'when shortcut for Issue is given' do
subject { assign_issue([issue.to_reference]) }
include_examples 'returns an error'
end
context 'when a full reference is given' do
subject { assign_issue([valid_reference]) }
include_examples 'returns success' include_examples 'returns success'
it 'does not perofrm N + 1 queries' do it 'does not perofrm N + 1 queries' do
params = { issue_references: [valid_reference] } params = { issue_references: [valid_reference] }
control_count = ActiveRecord::QueryRecorder.new { described_class.new(epic, user, params).execute }.count control_count = ActiveRecord::QueryRecorder.new { described_class.new(epic, user, params).execute }.count
user = create(:user) user = create(:user)
group = create(:group) group = create(:group)
project = create(:project, group: group) project = create(:project, group: group)
issues = create_list(:issue, 5, project: project) issues = create_list(:issue, 5, project: project)
epic = create(:epic, group: group) epic = create(:epic, group: group)
group.add_developer(user) group.add_developer(user)
params = { issue_references: issues.map { |i| i.to_reference(full: true) } } params = { issue_references: issues.map { |i| i.to_reference(full: true) } }
expect { described_class.new(epic, user, params).execute }.not_to exceed_query_limit(control_count) expect { described_class.new(epic, user, params).execute }.not_to exceed_query_limit(control_count)
end
end end
end
context 'when an issue links is given' do context 'when an issue links is given' do
subject { assign_issue([IssuesHelper.url_for_issue(issue.iid, issue.project)]) } subject { assign_issue([IssuesHelper.url_for_issue(issue.iid, issue.project)]) }
include_examples 'returns success' include_examples 'returns success'
end
end end
end end
end
context 'when user does not have permissions to link the issue' do context 'when user does not have permissions to link the issue' do
subject { assign_issue([valid_reference]) } subject { assign_issue([valid_reference]) }
include_examples 'returns an error'
end
context 'when an issue is already assigned to another epic' do include_examples 'returns an error'
before do
group.add_developer(user)
create(:epic_issue, epic: epic, issue: issue)
end end
let(:another_epic) { create(:epic, group: group) } context 'when an issue is already assigned to another epic' do
before do
group.add_developer(user)
create(:epic_issue, epic: epic, issue: issue)
end
subject do let(:another_epic) { create(:epic, group: group) }
params = { issue_references: [valid_reference] }
described_class.new(another_epic, user, params).execute subject do
end params = { issue_references: [valid_reference] }
it 'does not create a new association' do described_class.new(another_epic, user, params).execute
expect { subject }.not_to change(EpicIssue, :count).from(1) end
end
it 'updates the existing association' do it 'does not create a new association' do
expect { subject }.to change { EpicIssue.last.epic }.from(epic).to(another_epic) expect { subject }.not_to change(EpicIssue, :count).from(1)
end end
it 'returns success status' do it 'updates the existing association' do
is_expected.to eq(status: :success) expect { subject }.to change { EpicIssue.last.epic }.from(epic).to(another_epic)
end
it 'returns success status' do
is_expected.to eq(status: :success)
end
end end
end
context 'when issue from non group project is given' do context 'when issue from non group project is given' do
subject { assign_issue([another_issue.to_reference(full: true)]) } subject { assign_issue([another_issue.to_reference(full: true)]) }
let(:another_issue) { create :issue } let(:another_issue) { create :issue }
before do before do
group.add_developer(user) group.add_developer(user)
another_issue.project.add_developer(user) another_issue.project.add_developer(user)
end end
include_examples 'returns an error' include_examples 'returns an error'
end
end end
end end
end end
...@@ -11,27 +11,43 @@ describe EpicIssues::DestroyService do ...@@ -11,27 +11,43 @@ describe EpicIssues::DestroyService do
subject { described_class.new(epic_issue, user).execute } subject { described_class.new(epic_issue, user).execute }
context 'when user has permissions to remove associations' do context 'when epics feature is disabled' do
before do before do
group.add_reporter(user) group.add_reporter(user)
end end
it 'removes related issue' do it 'returns an error' do
expect { subject }.to change { EpicIssue.count }.from(1).to(0) is_expected.to eq(message: 'No Issue Link found', status: :error, http_status: 404)
end end
end
it 'returns success message' do context 'when epics feature is enabled' do
is_expected.to eq(message: 'Relation was removed', status: :success) before do
stub_licensed_features(epics: true)
end end
end
context 'user does not have permissions to remove associations' do context 'when user has permissions to remove associations' do
it 'does not remove relation' do before do
expect { subject }.not_to change { EpicIssue.count }.from(1) group.add_reporter(user)
end
it 'removes related issue' do
expect { subject }.to change { EpicIssue.count }.from(1).to(0)
end
it 'returns success message' do
is_expected.to eq(message: 'Relation was removed', status: :success)
end
end end
it 'returns error message' do context 'user does not have permissions to remove associations' do
is_expected.to eq(message: 'No Issue Link found', status: :error, http_status: 404) it 'does not remove relation' do
expect { subject }.not_to change { EpicIssue.count }.from(1)
end
it 'returns error message' do
is_expected.to eq(message: 'No Issue Link found', status: :error, http_status: 404)
end
end end
end end
end end
......
...@@ -18,69 +18,82 @@ describe EpicIssues::ListService do ...@@ -18,69 +18,82 @@ describe EpicIssues::ListService do
describe '#execute' do describe '#execute' do
subject { described_class.new(epic, user).execute } subject { described_class.new(epic, user).execute }
context 'user can see all issues and destroy their associations' do context 'when epics feature is disabled' do
before do it 'returns an empty array' do
group.add_developer(user) group.add_developer(user)
end
it 'returns related issues JSON' do expect(subject).to be_empty
expected_result = [
{
id: issue1.id,
title: issue1.title,
state: issue1.state,
reference: issue1.to_reference(full: true),
path: "/#{project.full_path}/issues/#{issue1.iid}",
destroy_relation_path: "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issue1.id}"
},
{
id: issue2.id,
title: issue2.title,
state: issue2.state,
reference: issue2.to_reference(full: true),
path: "/#{project.full_path}/issues/#{issue2.iid}",
destroy_relation_path: "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issue2.id}"
},
{
id: issue3.id,
title: issue3.title,
state: issue3.state,
reference: issue3.to_reference(full: true),
path: "/#{other_project.full_path}/issues/#{issue3.iid}",
destroy_relation_path: "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issue3.id}"
}
]
expect(subject).to match_array(expected_result)
end end
end end
context 'user can see only some issues' do context 'when epics feature is enabled' do
before do before do
project.add_developer(user) stub_licensed_features(epics: true)
end end
it 'returns related issues JSON' do context 'owner can see all issues and destroy their associations' do
expected_result = [ before do
{ group.add_developer(user)
id: issue1.id, end
title: issue1.title,
state: issue1.state, it 'returns related issues JSON' do
reference: issue1.to_reference(full: true), expected_result = [
path: "/#{project.full_path}/issues/#{issue1.iid}", {
destroy_relation_path: nil id: issue1.id,
}, title: issue1.title,
{ state: issue1.state,
id: issue2.id, reference: issue1.to_reference(full: true),
title: issue2.title, path: "/#{project.full_path}/issues/#{issue1.iid}",
state: issue2.state, destroy_relation_path: "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issue1.id}"
reference: issue2.to_reference(full: true), },
path: "/#{project.full_path}/issues/#{issue2.iid}", {
destroy_relation_path: nil id: issue2.id,
} title: issue2.title,
] state: issue2.state,
reference: issue2.to_reference(full: true),
path: "/#{project.full_path}/issues/#{issue2.iid}",
destroy_relation_path: "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issue2.id}"
},
{
id: issue3.id,
title: issue3.title,
state: issue3.state,
reference: issue3.to_reference(full: true),
path: "/#{other_project.full_path}/issues/#{issue3.iid}",
destroy_relation_path: "/groups/#{group.full_path}/-/epics/#{epic.iid}/issues/#{epic_issue3.id}"
}
]
expect(subject).to match_array(expected_result)
end
end
context 'user can see only some issues' do
before do
project.add_developer(user)
end
it 'returns related issues JSON' do
expected_result = [
{
id: issue1.id,
title: issue1.title,
state: issue1.state,
reference: issue1.to_reference(full: true),
path: "/#{project.full_path}/issues/#{issue1.iid}",
destroy_relation_path: nil
},
{
id: issue2.id,
title: issue2.title,
state: issue2.state,
reference: issue2.to_reference(full: true),
path: "/#{project.full_path}/issues/#{issue2.iid}",
destroy_relation_path: nil
}
]
expect(subject).to match_array(expected_result) expect(subject).to match_array(expected_result)
end
end end
end end
end end
......
This diff is collapsed.
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