2019-03-30 07:23:56 +00:00
# frozen_string_literal: true
2011-10-08 21:36:38 +00:00
require 'spec_helper'
2020-06-24 18:09:03 +00:00
RSpec . describe Issue do
2019-04-09 15:38:58 +00:00
include ExternalAuthorizationServiceHelpers
2020-07-23 09:09:18 +00:00
let_it_be ( :user ) { create ( :user ) }
2020-08-19 12:10:17 +00:00
let_it_be ( :reusable_project ) { create ( :project ) }
2020-07-23 09:09:18 +00:00
2011-10-08 21:36:38 +00:00
describe " Associations " do
2015-02-12 18:17:35 +00:00
it { is_expected . to belong_to ( :milestone ) }
2020-05-14 12:08:21 +00:00
it { is_expected . to belong_to ( :iteration ) }
2019-09-13 13:26:31 +00:00
it { is_expected . to belong_to ( :project ) }
2020-07-23 18:10:06 +00:00
it { is_expected . to have_one ( :namespace ) . through ( :project ) }
2019-09-13 13:26:31 +00:00
it { is_expected . to belong_to ( :moved_to ) . class_name ( 'Issue' ) }
2020-04-23 18:09:46 +00:00
it { is_expected . to have_one ( :moved_from ) . class_name ( 'Issue' ) }
2019-09-13 13:26:31 +00:00
it { is_expected . to belong_to ( :duplicated_to ) . class_name ( 'Issue' ) }
it { is_expected . to belong_to ( :closed_by ) . class_name ( 'User' ) }
2017-05-04 12:11:15 +00:00
it { is_expected . to have_many ( :assignees ) }
2019-12-10 15:07:52 +00:00
it { is_expected . to have_many ( :user_mentions ) . class_name ( " IssueUserMention " ) }
2020-05-04 06:10:10 +00:00
it { is_expected . to have_many ( :designs ) }
it { is_expected . to have_many ( :design_versions ) }
2019-12-10 12:07:55 +00:00
it { is_expected . to have_one ( :sentry_issue ) }
2020-04-23 00:09:41 +00:00
it { is_expected . to have_one ( :alert_management_alert ) }
2020-05-11 15:09:37 +00:00
it { is_expected . to have_many ( :resource_milestone_events ) }
it { is_expected . to have_many ( :resource_state_events ) }
2020-06-06 00:08:18 +00:00
it { is_expected . to have_and_belong_to_many ( :prometheus_alert_events ) }
it { is_expected . to have_and_belong_to_many ( :self_managed_prometheus_alert_events ) }
it { is_expected . to have_many ( :prometheus_alerts ) }
2020-10-02 12:09:03 +00:00
it { is_expected . to have_many ( :issue_email_participants ) }
2020-05-04 06:10:10 +00:00
describe 'versions.most_recent' do
it 'returns the most recent version' do
2020-09-24 12:09:37 +00:00
issue = create ( :issue , project : reusable_project )
2020-05-04 06:10:10 +00:00
create_list ( :design_version , 2 , issue : issue )
last_version = create ( :design_version , issue : issue )
expect ( issue . design_versions . most_recent ) . to eq ( last_version )
end
end
2011-10-08 21:36:38 +00:00
end
2012-08-29 05:52:19 +00:00
describe 'modules' do
2015-05-03 03:11:21 +00:00
subject { described_class }
2015-02-12 18:17:35 +00:00
it { is_expected . to include_module ( Issuable ) }
2015-05-03 03:11:21 +00:00
it { is_expected . to include_module ( Referable ) }
it { is_expected . to include_module ( Sortable ) }
it { is_expected . to include_module ( Taskable ) }
2020-05-11 15:09:37 +00:00
it { is_expected . to include_module ( MilestoneEventable ) }
it { is_expected . to include_module ( StateEventable ) }
2018-03-13 18:43:02 +00:00
it_behaves_like 'AtomicInternalId' do
let ( :internal_id_attribute ) { :iid }
let ( :instance ) { build ( :issue ) }
2018-05-14 08:41:56 +00:00
let ( :scope ) { :project }
2018-03-13 18:43:02 +00:00
let ( :scope_attrs ) { { project : instance . project } }
let ( :usage ) { :issues }
end
2012-08-29 05:52:19 +00:00
end
2020-07-24 03:09:19 +00:00
describe 'validations' do
subject { issue . valid? }
describe 'issue_type' do
let ( :issue ) { build ( :issue , issue_type : issue_type ) }
context 'when a valid type' do
let ( :issue_type ) { :issue }
it { is_expected . to eq ( true ) }
end
context 'empty type' do
let ( :issue_type ) { nil }
it { is_expected . to eq ( false ) }
end
end
end
2020-09-24 12:09:37 +00:00
subject { create ( :issue , project : reusable_project ) }
2012-05-20 18:15:13 +00:00
2017-12-07 17:41:30 +00:00
describe 'callbacks' do
describe '#ensure_metrics' do
it 'creates metrics after saving' do
2020-09-24 12:09:37 +00:00
issue = create ( :issue , project : reusable_project )
2017-12-07 17:41:30 +00:00
expect ( issue . metrics ) . to be_persisted
expect ( Issue :: Metrics . count ) . to eq ( 1 )
end
it 'does not create duplicate metrics for an issue' do
2020-09-24 12:09:37 +00:00
issue = create ( :issue , project : reusable_project )
2017-12-07 17:41:30 +00:00
issue . close!
expect ( issue . metrics ) . to be_persisted
expect ( Issue :: Metrics . count ) . to eq ( 1 )
end
it 'records current metrics' do
expect_any_instance_of ( Issue :: Metrics ) . to receive ( :record! )
2020-09-24 12:09:37 +00:00
create ( :issue , project : reusable_project )
2017-12-07 17:41:30 +00:00
end
end
2020-09-28 12:10:02 +00:00
describe '#record_create_action' do
it 'records the creation action after saving' do
expect ( Gitlab :: UsageDataCounters :: IssueActivityUniqueCounter ) . to receive ( :track_issue_created_action )
create ( :issue )
end
end
2017-12-07 17:41:30 +00:00
end
2020-05-15 18:07:52 +00:00
describe '.with_alert_management_alerts' do
subject { described_class . with_alert_management_alerts }
it 'gets only issues with alerts' do
2020-09-24 12:09:37 +00:00
alert = create ( :alert_management_alert , project : reusable_project , issue : create ( :issue , project : reusable_project ) )
issue = create ( :issue , project : reusable_project )
2020-05-15 18:07:52 +00:00
expect ( subject ) . to contain_exactly ( alert . issue )
expect ( subject ) . not_to include ( issue )
end
end
2020-02-04 12:09:00 +00:00
describe '.simple_sorts' do
it 'includes all keys' do
expect ( described_class . simple_sorts . keys ) . to include (
* %w( created_asc created_at_asc created_date created_desc created_at_desc
closest_future_date closest_future_date_asc due_date due_date_asc due_date_desc
id_asc id_desc relative_position relative_position_asc
updated_desc updated_asc updated_at_asc updated_at_desc ) )
end
end
2020-08-05 00:09:52 +00:00
describe '.with_issue_type' do
2020-09-24 12:09:37 +00:00
let_it_be ( :issue ) { create ( :issue , project : reusable_project ) }
let_it_be ( :incident ) { create ( :incident , project : reusable_project ) }
2020-08-05 00:09:52 +00:00
it 'gives issues with the given issue type' do
expect ( described_class . with_issue_type ( 'issue' ) )
. to contain_exactly ( issue )
end
it 'gives issues with the given issue type' do
2020-11-18 06:09:29 +00:00
expect ( described_class . with_issue_type ( %w( issue incident ) ) )
. to contain_exactly ( issue , incident )
2020-08-05 00:09:52 +00:00
end
end
2020-09-25 09:09:40 +00:00
describe '.order_severity' do
let_it_be ( :issue_high_severity ) { create ( :issuable_severity , severity : :high ) . issue }
let_it_be ( :issue_low_severity ) { create ( :issuable_severity , severity : :low ) . issue }
let_it_be ( :issue_no_severity ) { create ( :incident ) }
context 'sorting ascending' do
subject { described_class . order_severity_asc }
it { is_expected . to eq ( [ issue_no_severity , issue_low_severity , issue_high_severity ] ) }
end
context 'sorting descending' do
subject { described_class . order_severity_desc }
it { is_expected . to eq ( [ issue_high_severity , issue_low_severity , issue_no_severity ] ) }
end
end
2017-03-07 16:04:44 +00:00
describe '#order_by_position_and_priority' do
2020-08-19 12:10:17 +00:00
let ( :project ) { reusable_project }
2017-03-07 16:04:44 +00:00
let ( :p1 ) { create ( :label , title : 'P1' , project : project , priority : 1 ) }
let ( :p2 ) { create ( :label , title : 'P2' , project : project , priority : 2 ) }
let! ( :issue1 ) { create ( :labeled_issue , project : project , labels : [ p1 ] ) }
let! ( :issue2 ) { create ( :labeled_issue , project : project , labels : [ p2 ] ) }
2020-08-19 12:10:17 +00:00
let! ( :issue3 ) { create ( :issue , project : project , relative_position : - 200 ) }
let! ( :issue4 ) { create ( :issue , project : project , relative_position : - 100 ) }
2017-03-07 16:04:44 +00:00
it 'returns ordered list' do
2017-06-21 13:48:12 +00:00
expect ( project . issues . order_by_position_and_priority )
. to match [ issue3 , issue4 , issue1 , issue2 ]
2017-03-07 16:04:44 +00:00
end
end
2019-05-21 22:46:12 +00:00
describe '#sort' do
2020-08-19 12:10:17 +00:00
let ( :project ) { reusable_project }
2019-05-21 22:46:12 +00:00
context " by relative_position " do
2020-08-19 12:10:17 +00:00
let! ( :issue ) { create ( :issue , project : project , relative_position : nil ) }
2019-05-21 22:46:12 +00:00
let! ( :issue2 ) { create ( :issue , project : project , relative_position : 2 ) }
let! ( :issue3 ) { create ( :issue , project : project , relative_position : 1 ) }
it " sorts asc with nulls at the end " do
issues = project . issues . sort_by_attribute ( 'relative_position' )
expect ( issues ) . to eq ( [ issue3 , issue2 , issue ] )
end
end
end
2017-05-04 12:11:15 +00:00
describe '#card_attributes' do
it 'includes the author name' do
allow ( subject ) . to receive ( :author ) . and_return ( double ( name : 'Robert' ) )
allow ( subject ) . to receive ( :assignees ) . and_return ( [ ] )
2017-06-21 13:48:12 +00:00
expect ( subject . card_attributes )
. to eq ( { 'Author' = > 'Robert' , 'Assignee' = > '' } )
2017-05-04 12:11:15 +00:00
end
it 'includes the assignee name' do
allow ( subject ) . to receive ( :author ) . and_return ( double ( name : 'Robert' ) )
allow ( subject ) . to receive ( :assignees ) . and_return ( [ double ( name : 'Douwe' ) ] )
2017-06-21 13:48:12 +00:00
expect ( subject . card_attributes )
. to eq ( { 'Author' = > 'Robert' , 'Assignee' = > 'Douwe' } )
2017-05-04 12:11:15 +00:00
end
end
2018-09-24 14:14:11 +00:00
describe '#close' do
2020-09-24 12:09:37 +00:00
subject ( :issue ) { create ( :issue , project : reusable_project , state : 'opened' ) }
2017-03-15 20:58:09 +00:00
2020-05-22 09:08:09 +00:00
it 'sets closed_at to Time.current when an issue is closed' do
2018-09-24 14:14:11 +00:00
expect { issue . close } . to change { issue . closed_at } . from ( nil )
end
it 'changes the state to closed' do
2019-10-18 11:11:44 +00:00
open_state = described_class . available_states [ :opened ]
closed_state = described_class . available_states [ :closed ]
expect { issue . close } . to change { issue . state_id } . from ( open_state ) . to ( closed_state )
2018-09-24 14:14:11 +00:00
end
end
2017-08-11 10:36:03 +00:00
2018-09-24 14:14:11 +00:00
describe '#reopen' do
2020-09-24 12:09:37 +00:00
let ( :issue ) { create ( :issue , project : reusable_project , state : 'closed' , closed_at : Time . current , closed_by : user ) }
2018-09-24 14:14:11 +00:00
it 'sets closed_at to nil when an issue is reopend' do
expect { issue . reopen } . to change { issue . closed_at } . to ( nil )
end
it 'sets closed_by to nil when an issue is reopend' do
expect { issue . reopen } . to change { issue . closed_by } . from ( user ) . to ( nil )
end
2017-03-15 20:58:09 +00:00
2018-09-24 14:14:11 +00:00
it 'changes the state to opened' do
2019-10-18 11:11:44 +00:00
expect { issue . reopen } . to change { issue . state_id } . from ( described_class . available_states [ :closed ] ) . to ( described_class . available_states [ :opened ] )
2017-03-15 20:58:09 +00:00
end
end
2015-05-03 03:11:21 +00:00
describe '#to_reference' do
2016-12-15 14:51:50 +00:00
let ( :namespace ) { build ( :namespace , path : 'sample-namespace' ) }
2017-08-02 19:55:11 +00:00
let ( :project ) { build ( :project , name : 'sample-project' , namespace : namespace ) }
2016-12-15 14:51:50 +00:00
let ( :issue ) { build ( :issue , iid : 1 , project : project ) }
2016-11-02 23:49:13 +00:00
2016-12-15 14:51:50 +00:00
context 'when nil argument' do
it 'returns issue id' do
expect ( issue . to_reference ) . to eq " # 1 "
end
2016-12-15 12:50:28 +00:00
2020-02-28 12:09:05 +00:00
it 'returns complete path to the issue with full: true' do
expect ( issue . to_reference ( full : true ) ) . to eq 'sample-namespace/sample-project#1'
2016-12-15 14:51:50 +00:00
end
end
2020-02-28 12:09:05 +00:00
context 'when argument is a project' do
context 'when same project' do
it 'returns issue id' do
expect ( issue . to_reference ( project ) ) . to eq ( " # 1 " )
end
2016-12-15 14:51:50 +00:00
2020-02-28 12:09:05 +00:00
it 'returns full reference with full: true' do
expect ( issue . to_reference ( project , full : true ) ) . to eq 'sample-namespace/sample-project#1'
end
2016-12-15 14:51:50 +00:00
end
2016-12-21 16:41:33 +00:00
2020-02-28 12:09:05 +00:00
context 'when cross-project in same namespace' do
let ( :another_project ) do
build ( :project , name : 'another-project' , namespace : project . namespace )
end
2016-12-15 14:51:50 +00:00
2020-02-28 12:09:05 +00:00
it 'returns a cross-project reference' do
expect ( issue . to_reference ( another_project ) ) . to eq " sample-project # 1 "
end
2016-12-15 14:51:50 +00:00
end
2020-02-28 12:09:05 +00:00
context 'when cross-project in different namespace' do
let ( :another_namespace ) { build ( :namespace , path : 'another-namespace' ) }
let ( :another_namespace_project ) { build ( :project , path : 'another-project' , namespace : another_namespace ) }
2016-12-15 14:51:50 +00:00
2020-02-28 12:09:05 +00:00
it 'returns complete path to the issue' do
expect ( issue . to_reference ( another_namespace_project ) ) . to eq 'sample-namespace/sample-project#1'
end
2016-12-15 14:51:50 +00:00
end
end
context 'when argument is a namespace' do
2020-02-28 12:09:05 +00:00
context 'when same as issue' do
2016-12-15 14:51:50 +00:00
it 'returns path to the issue with the project name' do
expect ( issue . to_reference ( namespace ) ) . to eq 'sample-project#1'
end
2020-02-28 12:09:05 +00:00
it 'returns full reference with full: true' do
expect ( issue . to_reference ( namespace , full : true ) ) . to eq 'sample-namespace/sample-project#1'
end
2016-12-15 14:51:50 +00:00
end
2020-02-28 12:09:05 +00:00
context 'when different to issue namespace' do
let ( :group ) { build ( :group , name : 'Group' , path : 'sample-group' ) }
it 'returns full path to the issue with full: true' do
2016-12-15 14:51:50 +00:00
expect ( issue . to_reference ( group ) ) . to eq 'sample-namespace/sample-project#1'
end
end
2016-12-15 12:50:28 +00:00
end
2015-05-03 03:11:21 +00:00
end
2017-05-04 12:11:15 +00:00
describe '#assignee_or_author?' do
2020-09-24 12:09:37 +00:00
let ( :issue ) { create ( :issue , project : reusable_project ) }
2017-05-04 12:11:15 +00:00
it 'returns true for a user that is assigned to an issue' do
issue . assignees << user
expect ( issue . assignee_or_author? ( user ) ) . to be_truthy
2012-05-20 18:15:13 +00:00
end
2017-05-04 12:11:15 +00:00
it 'returns true for a user that is the author of an issue' do
issue . update ( author : user )
expect ( issue . assignee_or_author? ( user ) ) . to be_truthy
end
it 'returns false for a user that is not the assignee or author' do
expect ( issue . assignee_or_author? ( user ) ) . to be_falsey
2012-05-20 18:15:13 +00:00
end
end
2013-02-18 09:41:32 +00:00
2020-08-21 00:10:44 +00:00
describe '#related_issues' do
2020-09-24 12:09:37 +00:00
let_it_be ( :authorized_project ) { create ( :project ) }
let_it_be ( :authorized_project2 ) { create ( :project ) }
let_it_be ( :unauthorized_project ) { create ( :project ) }
2020-08-21 00:10:44 +00:00
2020-09-24 12:09:37 +00:00
let_it_be ( :authorized_issue_a ) { create ( :issue , project : authorized_project ) }
let_it_be ( :authorized_issue_b ) { create ( :issue , project : authorized_project ) }
let_it_be ( :authorized_issue_c ) { create ( :issue , project : authorized_project2 ) }
2020-08-21 00:10:44 +00:00
2020-09-24 12:09:37 +00:00
let_it_be ( :unauthorized_issue ) { create ( :issue , project : unauthorized_project ) }
2020-08-21 00:10:44 +00:00
2020-09-24 12:09:37 +00:00
let_it_be ( :issue_link_a ) { create ( :issue_link , source : authorized_issue_a , target : authorized_issue_b ) }
let_it_be ( :issue_link_b ) { create ( :issue_link , source : authorized_issue_a , target : unauthorized_issue ) }
let_it_be ( :issue_link_c ) { create ( :issue_link , source : authorized_issue_a , target : authorized_issue_c ) }
2020-08-21 00:10:44 +00:00
2020-09-24 12:09:37 +00:00
before_all do
2020-08-21 00:10:44 +00:00
authorized_project . add_developer ( user )
authorized_project2 . add_developer ( user )
end
it 'returns only authorized related issues for given user' do
expect ( authorized_issue_a . related_issues ( user ) )
. to contain_exactly ( authorized_issue_b , authorized_issue_c )
end
it 'returns issues with valid issue_link_type' do
link_types = authorized_issue_a . related_issues ( user ) . map ( & :issue_link_type )
expect ( link_types ) . not_to be_empty
expect ( link_types ) . not_to include ( nil )
end
2020-11-20 00:09:06 +00:00
it 'returns issues including the link creation time' do
dates = authorized_issue_a . related_issues ( user ) . map ( & :issue_link_created_at )
expect ( dates ) . not_to be_empty
expect ( dates ) . not_to include ( nil )
end
it 'returns issues including the link update time' do
dates = authorized_issue_a . related_issues ( user ) . map ( & :issue_link_updated_at )
expect ( dates ) . not_to be_empty
expect ( dates ) . not_to include ( nil )
end
2020-08-21 00:10:44 +00:00
describe 'when a user cannot read cross project' do
it 'only returns issues within the same project' do
expect ( Ability ) . to receive ( :allowed? ) . with ( user , :read_all_resources , :global ) . at_least ( :once ) . and_call_original
expect ( Ability ) . to receive ( :allowed? ) . with ( user , :read_cross_project ) . and_return ( false )
expect ( authorized_issue_a . related_issues ( user ) )
. to contain_exactly ( authorized_issue_b )
end
end
end
2016-03-17 10:11:22 +00:00
describe '#can_move?' do
let ( :issue ) { create ( :issue ) }
2019-12-19 00:08:01 +00:00
2016-03-17 10:11:22 +00:00
subject { issue . can_move? ( user ) }
context 'user is not a member of project issue belongs to' do
it { is_expected . to eq false }
end
context 'user is reporter in project issue belongs to' do
2020-09-24 12:09:37 +00:00
let ( :issue ) { create ( :issue , project : reusable_project ) }
2016-03-17 10:11:22 +00:00
2020-09-24 12:09:37 +00:00
before_all do
reusable_project . add_reporter ( user )
2017-06-14 18:18:56 +00:00
end
2016-03-17 10:11:22 +00:00
it { is_expected . to eq true }
2016-03-23 08:39:37 +00:00
context 'issue not persisted' do
2020-09-24 12:09:37 +00:00
let ( :issue ) { build ( :issue , project : reusable_project ) }
2019-12-19 00:08:01 +00:00
2016-03-23 08:39:37 +00:00
it { is_expected . to eq false }
end
2016-03-17 10:11:22 +00:00
context 'checking destination project also' do
subject { issue . can_move? ( user , to_project ) }
2019-10-18 11:11:44 +00:00
2020-09-24 12:09:37 +00:00
let_it_be ( :to_project ) { create ( :project ) }
2016-03-17 10:11:22 +00:00
context 'destination project allowed' do
2017-06-14 18:18:56 +00:00
before do
2017-12-22 08:18:28 +00:00
to_project . add_reporter ( user )
2017-06-14 18:18:56 +00:00
end
2016-03-17 10:11:22 +00:00
it { is_expected . to eq true }
end
context 'destination project not allowed' do
2017-06-14 18:18:56 +00:00
before do
2017-12-22 08:18:28 +00:00
to_project . add_guest ( user )
2017-06-14 18:18:56 +00:00
end
2016-03-17 10:11:22 +00:00
it { is_expected . to eq false }
end
end
end
end
describe '#moved?' do
2020-03-18 15:09:45 +00:00
context 'when issue has not been moved' do
subject { build_stubbed ( :issue ) }
2016-03-17 10:11:22 +00:00
2020-03-18 15:09:45 +00:00
it { is_expected . not_to be_moved }
2016-03-17 10:11:22 +00:00
end
2020-03-18 15:09:45 +00:00
context 'when issue has already been moved' do
subject { build_stubbed ( :issue , moved_to : build_stubbed ( :issue ) ) }
2016-03-17 10:11:22 +00:00
2020-03-18 15:09:45 +00:00
it { is_expected . to be_moved }
2016-03-17 10:11:22 +00:00
end
end
2019-09-13 13:26:31 +00:00
describe '#duplicated?' do
2020-09-24 12:09:37 +00:00
let ( :issue ) { create ( :issue , project : reusable_project ) }
2019-12-19 00:08:01 +00:00
2019-09-13 13:26:31 +00:00
subject { issue . duplicated? }
context 'issue not duplicated' do
it { is_expected . to eq false }
end
context 'issue already duplicated' do
2020-09-24 12:09:37 +00:00
let ( :duplicated_to_issue ) { create ( :issue , project : reusable_project ) }
2019-09-13 13:26:31 +00:00
let ( :issue ) { create ( :issue , duplicated_to : duplicated_to_issue ) }
it { is_expected . to eq true }
end
end
2020-07-09 09:09:27 +00:00
describe '#from_service_desk?' do
subject { issue . from_service_desk? }
context 'when issue author is support bot' do
2020-09-24 12:09:37 +00:00
let ( :issue ) { create ( :issue , project : reusable_project , author : :: User . support_bot ) }
2020-07-09 09:09:27 +00:00
it { is_expected . to be_truthy }
end
context 'when issue author is not support bot' do
2020-09-24 12:09:37 +00:00
let ( :issue ) { create ( :issue , project : reusable_project ) }
2020-07-09 09:09:27 +00:00
it { is_expected . to be_falsey }
end
end
2018-04-05 15:17:02 +00:00
describe '#suggested_branch_name' do
let ( :repository ) { double }
subject { build ( :issue ) }
before do
allow ( subject . project ) . to receive ( :repository ) . and_return ( repository )
end
2020-02-06 21:08:48 +00:00
describe '#to_branch_name does not exists' do
2018-04-05 15:17:02 +00:00
before do
allow ( repository ) . to receive ( :branch_exists? ) . and_return ( false )
end
it 'returns #to_branch_name' do
expect ( subject . suggested_branch_name ) . to eq ( subject . to_branch_name )
end
end
2020-02-06 21:08:48 +00:00
describe '#to_branch_name exists not ending with -index' do
2018-04-05 15:17:02 +00:00
before do
allow ( repository ) . to receive ( :branch_exists? ) . and_return ( true )
allow ( repository ) . to receive ( :branch_exists? ) . with ( / #{ subject . to_branch_name } - \ d / ) . and_return ( false )
end
it 'returns #to_branch_name ending with -2' do
expect ( subject . suggested_branch_name ) . to eq ( " #{ subject . to_branch_name } -2 " )
end
end
2020-02-06 21:08:48 +00:00
describe '#to_branch_name exists ending with -index' do
2018-04-05 15:17:02 +00:00
before do
allow ( repository ) . to receive ( :branch_exists? ) . and_return ( true )
allow ( repository ) . to receive ( :branch_exists? ) . with ( " #{ subject . to_branch_name } -3 " ) . and_return ( false )
end
it 'returns #to_branch_name ending with max index + 1' do
expect ( subject . suggested_branch_name ) . to eq ( " #{ subject . to_branch_name } -3 " )
end
end
end
2017-05-04 08:09:21 +00:00
describe '#has_related_branch?' do
2020-09-24 12:09:37 +00:00
let ( :issue ) { create ( :issue , project : reusable_project , title : " Blue Bell Knoll " ) }
2019-12-19 00:08:01 +00:00
2017-05-04 08:09:21 +00:00
subject { issue . has_related_branch? }
context 'branch found' do
before do
allow ( issue . project . repository ) . to receive ( :branch_names ) . and_return ( [ " iceblink-luck " , issue . to_branch_name ] )
end
it { is_expected . to eq true }
end
context 'branch not found' do
before do
allow ( issue . project . repository ) . to receive ( :branch_names ) . and_return ( [ " lazy-calm " ] )
end
it { is_expected . to eq false }
end
end
2013-05-30 23:16:49 +00:00
it_behaves_like 'an editable mentionable' do
2017-01-25 19:52:12 +00:00
subject { create ( :issue , project : create ( :project , :repository ) ) }
2015-04-16 20:25:25 +00:00
2015-06-18 00:40:26 +00:00
let ( :backref_text ) { " issue #{ subject . to_reference } " }
2017-08-09 09:52:22 +00:00
let ( :set_mentionable_text ) { - > ( txt ) { subject . description = txt } }
2013-05-30 23:16:49 +00:00
end
2014-10-06 02:17:28 +00:00
it_behaves_like 'a Taskable' do
let ( :subject ) { create :issue }
end
2016-02-12 18:42:25 +00:00
describe " # to_branch_name " do
2020-09-24 12:09:37 +00:00
let_it_be ( :issue ) { create ( :issue , project : reusable_project , title : 'testing-issue' ) }
2016-02-12 18:42:25 +00:00
2016-04-13 19:20:03 +00:00
it 'starts with the issue iid' do
2020-03-04 09:08:20 +00:00
expect ( issue . to_branch_name ) . to match ( / \ A #{ issue . iid } -[A-Za-z \ -]+ \ z / )
2016-02-12 18:42:25 +00:00
end
2016-04-12 10:31:44 +00:00
it " contains the issue title if not confidential " do
2020-03-04 09:08:20 +00:00
expect ( issue . to_branch_name ) . to match ( / testing-issue \ z / )
2016-04-12 10:31:44 +00:00
end
it " does not contain the issue title if confidential " do
2020-09-24 12:09:37 +00:00
issue = create ( :issue , project : reusable_project , title : 'testing-issue' , confidential : true )
2020-03-04 09:08:20 +00:00
expect ( issue . to_branch_name ) . to match ( / confidential-issue \ z / )
2016-04-12 10:31:44 +00:00
end
2019-10-22 15:06:06 +00:00
context 'issue title longer than 100 characters' do
2020-09-24 12:09:37 +00:00
let_it_be ( :issue ) { create ( :issue , project : reusable_project , iid : 999 , title : 'Lorem ipsum dolor sit amet consectetur adipiscing elit Mauris sit amet ipsum id lacus custom fringilla convallis' ) }
2019-10-22 15:06:06 +00:00
it " truncates branch name to at most 100 characters " do
expect ( issue . to_branch_name . length ) . to be < = 100
end
it " truncates dangling parts of the branch name " do
# 100 characters would've got us "999-lorem...lacus-custom-fri".
expect ( issue . to_branch_name ) . to eq ( " 999-lorem-ipsum-dolor-sit-amet-consectetur-adipiscing-elit-mauris-sit-amet-ipsum-id-lacus-custom " )
end
end
2016-02-12 18:42:25 +00:00
end
2016-05-26 11:38:28 +00:00
2018-04-05 15:17:02 +00:00
describe '#can_be_worked_on?' do
let ( :project ) { build ( :project ) }
2019-12-19 00:08:01 +00:00
2018-04-05 15:17:02 +00:00
subject { build ( :issue , :opened , project : project ) }
context 'is closed' do
subject { build ( :issue , :closed ) }
it { is_expected . not_to be_can_be_worked_on }
end
context 'project is forked' do
before do
allow ( project ) . to receive ( :forked? ) . and_return ( true )
end
it { is_expected . not_to be_can_be_worked_on }
end
it { is_expected . to be_can_be_worked_on }
end
2016-05-26 11:38:28 +00:00
describe '#participants' do
context 'using a public project' do
2020-09-24 12:09:37 +00:00
let_it_be ( :issue ) { create ( :issue , project : reusable_project ) }
2016-05-26 11:38:28 +00:00
let! ( :note1 ) do
2020-09-24 12:09:37 +00:00
create ( :note_on_issue , noteable : issue , project : reusable_project , note : 'a' )
2016-05-26 11:38:28 +00:00
end
let! ( :note2 ) do
2020-09-24 12:09:37 +00:00
create ( :note_on_issue , noteable : issue , project : reusable_project , note : 'b' )
2016-05-26 11:38:28 +00:00
end
it 'includes the issue author' do
expect ( issue . participants ) . to include ( issue . author )
end
it 'includes the authors of the notes' do
expect ( issue . participants ) . to include ( note1 . author , note2 . author )
end
end
context 'using a private project' do
it 'does not include mentioned users that do not have access to the project' do
2017-08-02 19:55:11 +00:00
project = create ( :project )
2016-05-26 11:38:28 +00:00
issue = create ( :issue , project : project )
2020-09-24 12:09:37 +00:00
user = create ( :user )
2016-05-26 11:38:28 +00:00
create ( :note_on_issue ,
noteable : issue ,
project : project ,
note : user . to_reference )
expect ( issue . participants ) . not_to include ( user )
end
end
end
2016-06-02 13:25:40 +00:00
describe 'cached counts' do
it 'updates when assignees change' do
user1 = create ( :user )
user2 = create ( :user )
2020-09-24 12:09:37 +00:00
issue = create ( :issue , assignees : [ user1 ] , project : reusable_project )
reusable_project . add_developer ( user1 )
reusable_project . add_developer ( user2 )
2016-06-02 13:25:40 +00:00
expect ( user1 . assigned_open_issues_count ) . to eq ( 1 )
expect ( user2 . assigned_open_issues_count ) . to eq ( 0 )
2017-05-04 12:11:15 +00:00
issue . assignees = [ user2 ]
2016-06-02 13:25:40 +00:00
issue . save
expect ( user1 . assigned_open_issues_count ) . to eq ( 0 )
expect ( user2 . assigned_open_issues_count ) . to eq ( 1 )
end
end
2016-07-20 18:13:02 +00:00
describe '#visible_to_user?' do
2020-09-24 12:09:37 +00:00
let ( :project ) { reusable_project }
2020-03-26 18:08:03 +00:00
let ( :issue ) { build ( :issue , project : project ) }
subject { issue . visible_to_user? ( user ) }
context 'with a project' do
it 'returns false when feature is disabled' do
project . project_feature . update_attribute ( :issues_access_level , ProjectFeature :: DISABLED )
is_expected . to eq ( false )
end
it 'returns false when restricted for members' do
project . project_feature . update_attribute ( :issues_access_level , ProjectFeature :: PRIVATE )
is_expected . to eq ( false )
end
end
2016-11-01 20:18:51 +00:00
context 'without a user' do
2020-03-26 18:08:03 +00:00
let ( :user ) { nil }
2016-11-01 20:18:51 +00:00
2020-09-24 12:09:37 +00:00
before do
project . project_feature . update_attribute ( :issues_access_level , ProjectFeature :: PUBLIC )
end
2016-11-01 20:18:51 +00:00
it 'returns true when the issue is publicly visible' do
expect ( issue ) . to receive ( :publicly_visible? ) . and_return ( true )
2020-03-26 18:08:03 +00:00
is_expected . to eq ( true )
2016-11-01 20:18:51 +00:00
end
it 'returns false when the issue is not publicly visible' do
expect ( issue ) . to receive ( :publicly_visible? ) . and_return ( false )
2020-03-26 18:08:03 +00:00
is_expected . to eq ( false )
2016-11-01 20:18:51 +00:00
end
end
2016-07-20 18:13:02 +00:00
context 'with a user' do
2020-03-26 18:08:03 +00:00
shared_examples 'issue readable by user' do
it { is_expected . to eq ( true ) }
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
shared_examples 'issue not readable by user' do
it { is_expected . to eq ( false ) }
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
shared_examples 'confidential issue readable by user' do
specify do
issue . confidential = true
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
is_expected . to eq ( true )
end
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
shared_examples 'confidential issue not readable by user' do
specify do
issue . confidential = true
2016-11-01 20:18:51 +00:00
2020-03-26 18:08:03 +00:00
is_expected . to eq ( false )
end
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
context 'with an admin user' do
let ( :user ) { build ( :admin ) }
2016-07-20 18:13:02 +00:00
2020-05-15 15:08:04 +00:00
context 'when admin mode is enabled' , :enable_admin_mode do
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
end
context 'when admin mode is disabled' do
it_behaves_like 'issue not readable by user'
it_behaves_like 'confidential issue not readable by user'
end
2020-03-26 18:08:03 +00:00
end
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
context 'with an owner' do
before do
project . add_maintainer ( user )
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
end
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
context 'with a reporter user' do
before do
project . add_reporter ( user )
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
context 'with a guest user' do
before do
project . add_guest ( user )
end
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue not readable by user'
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
context 'when user is an assignee' do
before do
issue . update! ( assignees : [ user ] )
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
context 'when user is the author' do
2016-07-20 18:13:02 +00:00
before do
2020-03-26 18:08:03 +00:00
issue . update! ( author : user )
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
2016-07-20 18:13:02 +00:00
end
end
2020-03-26 18:08:03 +00:00
context 'with a user that is not a member' do
context 'using a public project' do
let ( :project ) { build ( :project , :public ) }
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue not readable by user'
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
context 'using an internal project' do
let ( :project ) { build ( :project , :internal ) }
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
context 'using an internal user' do
before do
allow ( user ) . to receive ( :external? ) . and_return ( false )
end
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue not readable by user'
2017-06-14 18:18:56 +00:00
end
2016-11-01 20:18:51 +00:00
2020-03-26 18:08:03 +00:00
context 'using an external user' do
before do
allow ( user ) . to receive ( :external? ) . and_return ( true )
end
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
it_behaves_like 'issue not readable by user'
it_behaves_like 'confidential issue not readable by user'
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
end
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
context 'using an external user' do
before do
allow ( user ) . to receive ( :external? ) . and_return ( true )
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
it_behaves_like 'issue not readable by user'
it_behaves_like 'confidential issue not readable by user'
2016-07-20 18:13:02 +00:00
end
end
2020-03-26 18:08:03 +00:00
context 'with an external authentication service' do
2016-07-20 18:13:02 +00:00
before do
2020-03-26 18:08:03 +00:00
enable_external_authorization_service_check
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
it 'is `false` when an external authorization service is enabled' do
issue = build ( :issue , project : build ( :project , :public ) )
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
expect ( issue ) . not_to be_visible_to_user
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
it 'checks the external service to determine if an issue is readable by a user' do
project = build ( :project , :public ,
external_authorization_classification_label : 'a-label' )
issue = build ( :issue , project : project )
user = build ( :user )
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
expect ( :: Gitlab :: ExternalAuthorization ) . to receive ( :access_allowed? ) . with ( user , 'a-label' ) { false }
expect ( issue . visible_to_user? ( user ) ) . to be_falsy
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
it 'does not check the external service if a user does not have access to the project' do
project = build ( :project , :private ,
external_authorization_classification_label : 'a-label' )
2016-07-20 18:13:02 +00:00
issue = build ( :issue , project : project )
2020-03-26 18:08:03 +00:00
user = build ( :user )
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
expect ( :: Gitlab :: ExternalAuthorization ) . not_to receive ( :access_allowed? )
expect ( issue . visible_to_user? ( user ) ) . to be_falsy
2016-07-20 18:13:02 +00:00
end
2020-05-15 15:08:04 +00:00
context 'with an admin' do
context 'when admin mode is enabled' , :enable_admin_mode do
it 'does not check the external webservice' do
issue = build ( :issue )
user = build ( :admin )
2016-07-20 18:13:02 +00:00
2020-05-15 15:08:04 +00:00
expect ( :: Gitlab :: ExternalAuthorization ) . not_to receive ( :access_allowed? )
issue . visible_to_user? ( user )
end
end
context 'when admin mode is disabled' do
it 'checks the external service to determine if an issue is readable by the admin' do
project = build ( :project , :public ,
external_authorization_classification_label : 'a-label' )
issue = build ( :issue , project : project )
user = build ( :admin )
2020-03-26 18:08:03 +00:00
2020-05-15 15:08:04 +00:00
expect ( :: Gitlab :: ExternalAuthorization ) . to receive ( :access_allowed? ) . with ( user , 'a-label' ) { false }
expect ( issue . visible_to_user? ( user ) ) . to be_falsy
end
end
2016-07-20 18:13:02 +00:00
end
end
2020-03-26 18:08:03 +00:00
context 'when issue is moved to a private project' do
let ( :private_project ) { build ( :project , :private ) }
2016-07-20 18:13:02 +00:00
before do
2020-03-26 18:08:03 +00:00
issue . update ( project : private_project ) # move issue to private project
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
shared_examples 'issue visible if user has guest access' do
context 'when user is not a member' do
it_behaves_like 'issue not readable by user'
it_behaves_like 'confidential issue not readable by user'
end
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
context 'when user is a guest' do
before do
private_project . add_guest ( user )
end
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
end
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
context 'when user is the author of the original issue' do
before do
issue . update! ( author : user )
end
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
it_behaves_like 'issue visible if user has guest access'
2016-07-20 18:13:02 +00:00
end
2020-03-26 18:08:03 +00:00
context 'when user is an assignee in the original issue' do
before do
issue . update! ( assignees : [ user ] )
end
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
it_behaves_like 'issue visible if user has guest access'
end
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
context 'when user is not the author or an assignee in original issue' do
context 'when user is a guest' do
before do
private_project . add_guest ( user )
end
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue not readable by user'
end
2016-07-20 18:13:02 +00:00
2020-03-26 18:08:03 +00:00
context 'when user is a reporter' do
before do
private_project . add_reporter ( user )
end
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
end
end
2016-07-20 18:13:02 +00:00
end
end
end
describe '#publicly_visible?' do
context 'using a public project' do
2017-08-02 19:55:11 +00:00
let ( :project ) { create ( :project , :public ) }
2016-07-20 18:13:02 +00:00
it 'returns true for a regular issue' do
issue = build ( :issue , project : project )
2016-11-01 20:18:51 +00:00
expect ( issue ) . to be_truthy
2016-07-20 18:13:02 +00:00
end
it 'returns false for a confidential issue' do
issue = build ( :issue , :confidential , project : project )
2016-11-01 20:18:51 +00:00
expect ( issue ) . not_to be_falsy
2016-07-20 18:13:02 +00:00
end
end
context 'using an internal project' do
2017-08-02 19:55:11 +00:00
let ( :project ) { create ( :project , :internal ) }
2016-07-20 18:13:02 +00:00
it 'returns false for a regular issue' do
issue = build ( :issue , project : project )
2016-11-01 20:18:51 +00:00
expect ( issue ) . not_to be_falsy
2016-07-20 18:13:02 +00:00
end
it 'returns false for a confidential issue' do
issue = build ( :issue , :confidential , project : project )
2016-11-01 20:18:51 +00:00
expect ( issue ) . not_to be_falsy
2016-07-20 18:13:02 +00:00
end
end
context 'using a private project' do
2017-08-02 19:55:11 +00:00
let ( :project ) { create ( :project , :private ) }
2016-07-20 18:13:02 +00:00
it 'returns false for a regular issue' do
issue = build ( :issue , project : project )
2016-11-01 20:18:51 +00:00
expect ( issue ) . not_to be_falsy
2016-07-20 18:13:02 +00:00
end
it 'returns false for a confidential issue' do
issue = build ( :issue , :confidential , project : project )
2016-11-01 20:18:51 +00:00
expect ( issue ) . not_to be_falsy
2016-07-20 18:13:02 +00:00
end
end
end
2017-03-14 16:56:15 +00:00
describe '#hook_attrs' do
2017-10-05 17:02:50 +00:00
it 'delegates to Gitlab::HookData::IssueBuilder#build' do
builder = double
expect ( Gitlab :: HookData :: IssueBuilder )
. to receive ( :new ) . with ( subject ) . and_return ( builder )
expect ( builder ) . to receive ( :build )
subject . hook_attrs
2017-05-04 12:11:15 +00:00
end
2017-03-14 16:56:15 +00:00
end
2017-03-21 02:37:29 +00:00
2019-01-17 11:39:28 +00:00
describe '#check_for_spam?' do
using RSpec :: Parameterized :: TableSyntax
2017-03-21 02:37:29 +00:00
2019-01-17 11:39:28 +00:00
where ( :visibility_level , :confidential , :new_attributes , :check_for_spam? ) do
Gitlab :: VisibilityLevel :: PUBLIC | false | { description : 'woo' } | true
Gitlab :: VisibilityLevel :: PUBLIC | false | { title : 'woo' } | true
Gitlab :: VisibilityLevel :: PUBLIC | true | { confidential : false } | true
Gitlab :: VisibilityLevel :: PUBLIC | true | { description : 'woo' } | false
Gitlab :: VisibilityLevel :: PUBLIC | false | { title : 'woo' , confidential : true } | false
Gitlab :: VisibilityLevel :: PUBLIC | false | { description : 'original description' } | false
Gitlab :: VisibilityLevel :: INTERNAL | false | { description : 'woo' } | false
Gitlab :: VisibilityLevel :: PRIVATE | false | { description : 'woo' } | false
2017-03-21 02:37:29 +00:00
end
2019-01-17 11:39:28 +00:00
with_them do
it 'checks for spam on issues that can be seen anonymously' do
2020-09-24 12:09:37 +00:00
project = reusable_project
project . update ( visibility_level : visibility_level )
2019-01-17 11:39:28 +00:00
issue = create ( :issue , project : project , confidential : confidential , description : 'original description' )
2017-03-21 02:37:29 +00:00
2019-01-17 11:39:28 +00:00
issue . assign_attributes ( new_attributes )
2017-03-21 02:37:29 +00:00
2019-01-17 11:39:28 +00:00
expect ( issue . check_for_spam? ) . to eq ( check_for_spam? )
2017-03-21 02:37:29 +00:00
end
end
end
2017-08-17 15:21:25 +00:00
describe 'removing an issue' do
it 'refreshes the number of open issues of the project' do
project = subject . project
expect { subject . destroy }
. to change { project . open_issues_count } . from ( 1 ) . to ( 0 )
end
end
describe '.public_only' do
it 'only returns public issues' do
2020-09-24 12:09:37 +00:00
public_issue = create ( :issue , project : reusable_project )
create ( :issue , project : reusable_project , confidential : true )
2017-08-17 15:21:25 +00:00
expect ( described_class . public_only ) . to eq ( [ public_issue ] )
end
end
2017-12-01 13:52:16 +00:00
2019-02-25 11:00:24 +00:00
describe '.confidential_only' do
it 'only returns confidential_only issues' do
2020-09-24 12:09:37 +00:00
create ( :issue , project : reusable_project )
confidential_issue = create ( :issue , project : reusable_project , confidential : true )
2019-02-25 11:00:24 +00:00
expect ( described_class . confidential_only ) . to eq ( [ confidential_issue ] )
end
end
2020-04-10 00:10:04 +00:00
describe '.by_project_id_and_iid' do
2020-09-24 12:09:37 +00:00
let_it_be ( :issue_a ) { create ( :issue , project : reusable_project ) }
2020-04-10 00:10:04 +00:00
let_it_be ( :issue_b ) { create ( :issue , iid : issue_a . iid ) }
let_it_be ( :issue_c ) { create ( :issue , project : issue_a . project ) }
let_it_be ( :issue_d ) { create ( :issue , project : issue_a . project ) }
it_behaves_like 'a where_composite scope' , :by_project_id_and_iid do
let ( :all_results ) { [ issue_a , issue_b , issue_c , issue_d ] }
let ( :first_result ) { issue_a }
let ( :composite_ids ) do
all_results . map { | issue | { project_id : issue . project_id , iid : issue . iid } }
end
end
end
2020-07-09 09:09:27 +00:00
describe '.service_desk' do
it 'returns the service desk issue' do
2020-09-24 12:09:37 +00:00
service_desk_issue = create ( :issue , project : reusable_project , author : :: User . support_bot )
regular_issue = create ( :issue , project : reusable_project )
2020-07-09 09:09:27 +00:00
expect ( described_class . service_desk ) . to include ( service_desk_issue )
expect ( described_class . service_desk ) . not_to include ( regular_issue )
end
end
2017-12-01 13:52:16 +00:00
it_behaves_like 'throttled touch' do
subject { create ( :issue , updated_at : 1 . hour . ago ) }
end
2019-04-09 15:38:58 +00:00
2019-06-24 09:51:34 +00:00
describe " # labels_hook_attrs " do
let ( :label ) { create ( :label ) }
2020-09-24 12:09:37 +00:00
let ( :issue ) { create ( :labeled_issue , project : reusable_project , labels : [ label ] ) }
2019-06-24 09:51:34 +00:00
it " returns a list of label hook attributes " do
expect ( issue . labels_hook_attrs ) . to eq ( [ label . hook_attrs ] )
end
end
2019-07-22 07:47:29 +00:00
context " relative positioning " do
it_behaves_like " a class that supports relative positioning " do
2020-09-24 12:09:37 +00:00
let_it_be ( :project ) { reusable_project }
2019-07-22 07:47:29 +00:00
let ( :factory ) { :issue }
let ( :default_params ) { { project : project } }
end
end
2019-10-18 11:11:44 +00:00
it_behaves_like 'versioned description'
2020-03-04 09:08:20 +00:00
describe " # previous_updated_at " do
2020-05-22 09:08:09 +00:00
let_it_be ( :updated_at ) { Time . zone . local ( 2012 , 01 , 06 ) }
2020-09-24 12:09:37 +00:00
let_it_be ( :issue ) { create ( :issue , project : reusable_project , updated_at : updated_at ) }
2020-03-04 09:08:20 +00:00
it 'returns updated_at value if updated_at did not change at all' do
allow ( issue ) . to receive ( :previous_changes ) . and_return ( { } )
expect ( issue . previous_updated_at ) . to eq ( updated_at )
end
it 'returns updated_at value if `previous_changes` has nil value for `updated_at`' do
allow ( issue ) . to receive ( :previous_changes ) . and_return ( { 'updated_at' = > nil } )
expect ( issue . previous_updated_at ) . to eq ( updated_at )
end
it 'returns updated_at value if previous updated_at value is not present' do
2020-05-22 09:08:09 +00:00
allow ( issue ) . to receive ( :previous_changes ) . and_return ( { 'updated_at' = > [ nil , Time . zone . local ( 2013 , 02 , 06 ) ] } )
2020-03-04 09:08:20 +00:00
expect ( issue . previous_updated_at ) . to eq ( updated_at )
end
it 'returns previous updated_at when present' do
2020-05-22 09:08:09 +00:00
allow ( issue ) . to receive ( :previous_changes ) . and_return ( { 'updated_at' = > [ Time . zone . local ( 2013 , 02 , 06 ) , Time . zone . local ( 2013 , 03 , 06 ) ] } )
2020-03-04 09:08:20 +00:00
2020-05-22 09:08:09 +00:00
expect ( issue . previous_updated_at ) . to eq ( Time . zone . local ( 2013 , 02 , 06 ) )
2020-03-04 09:08:20 +00:00
end
end
2020-05-04 06:10:10 +00:00
describe '#design_collection' do
it 'returns a design collection' do
issue = build ( :issue )
collection = issue . design_collection
expect ( collection ) . to be_a ( DesignManagement :: DesignCollection )
expect ( collection . issue ) . to eq ( issue )
end
end
describe 'current designs' do
2020-09-24 12:09:37 +00:00
let ( :issue ) { create ( :issue , project : reusable_project ) }
2020-05-04 06:10:10 +00:00
subject { issue . designs . current }
context 'an issue has no designs' do
it { is_expected . to be_empty }
end
context 'an issue only has current designs' do
let! ( :design_a ) { create ( :design , :with_file , issue : issue ) }
let! ( :design_b ) { create ( :design , :with_file , issue : issue ) }
let! ( :design_c ) { create ( :design , :with_file , issue : issue ) }
it { is_expected . to include ( design_a , design_b , design_c ) }
end
context 'an issue only has deleted designs' do
let! ( :design_a ) { create ( :design , :with_file , issue : issue , deleted : true ) }
let! ( :design_b ) { create ( :design , :with_file , issue : issue , deleted : true ) }
let! ( :design_c ) { create ( :design , :with_file , issue : issue , deleted : true ) }
it { is_expected . to be_empty }
end
context 'an issue has a mixture of current and deleted designs' do
let! ( :design_a ) { create ( :design , :with_file , issue : issue ) }
let! ( :design_b ) { create ( :design , :with_file , issue : issue , deleted : true ) }
let! ( :design_c ) { create ( :design , :with_file , issue : issue ) }
it { is_expected . to contain_exactly ( design_a , design_c ) }
end
end
2020-05-15 09:07:59 +00:00
describe '.with_label_attributes' do
subject { described_class . with_label_attributes ( label_attributes ) }
let ( :label_attributes ) { { title : 'hello world' , description : 'hi' } }
it 'gets issues with given label attributes' do
label = create ( :label , ** label_attributes )
labeled_issue = create ( :labeled_issue , project : label . project , labels : [ label ] )
expect ( subject ) . to include ( labeled_issue )
end
it 'excludes issues without given label attributes' do
label = create ( :label , title : 'GitLab' , description : 'tanuki' )
labeled_issue = create ( :labeled_issue , project : label . project , labels : [ label ] )
expect ( subject ) . not_to include ( labeled_issue )
end
end
2020-05-27 06:08:13 +00:00
describe 'banzai_render_context' do
let ( :project ) { build ( :project_empty_repo ) }
let ( :issue ) { build :issue , project : project }
subject ( :context ) { issue . banzai_render_context ( :title ) }
it 'sets the label_url_method in the context' do
expect ( context [ :label_url_method ] ) . to eq ( :project_issues_url )
end
end
2020-08-27 18:10:29 +00:00
describe 'scheduling rebalancing' do
before do
2020-09-16 18:09:47 +00:00
allow_next_instance_of ( RelativePositioning :: Mover ) do | mover |
allow ( mover ) . to receive ( :move ) { raise ActiveRecord :: QueryCanceled }
end
2020-08-27 18:10:29 +00:00
end
2020-09-16 18:09:47 +00:00
let ( :project ) { build_stubbed ( :project_empty_repo ) }
2020-08-27 18:10:29 +00:00
let ( :issue ) { build_stubbed ( :issue , relative_position : 100 , project : project ) }
2020-09-16 18:09:47 +00:00
it 'schedules rebalancing if we time-out when moving' do
lhs = build_stubbed ( :issue , relative_position : 99 , project : project )
to_move = build ( :issue , project : project )
expect ( IssueRebalancingWorker ) . to receive ( :perform_async ) . with ( nil , project . id )
2020-08-27 18:10:29 +00:00
2020-09-16 18:09:47 +00:00
expect { to_move . move_between ( lhs , issue ) } . to raise_error ( ActiveRecord :: QueryCanceled )
2020-08-27 18:10:29 +00:00
end
end
2020-09-07 12:08:27 +00:00
describe '#allows_reviewers?' do
2021-02-05 12:09:31 +00:00
it 'returns false as we do not support reviewers on issues yet' do
2020-09-07 12:08:27 +00:00
issue = build_stubbed ( :issue )
expect ( issue . allows_reviewers? ) . to be ( false )
end
end
2020-09-30 18:09:52 +00:00
describe '#issue_type_supports?' do
let_it_be ( :issue ) { create ( :issue ) }
it 'raises error when feature is invalid' do
expect { issue . issue_type_supports? ( :unkown_feature ) } . to raise_error ( ArgumentError )
end
end
2021-02-22 12:10:38 +00:00
describe '#email_participants_downcase' do
it 'returns a list of emails with all uppercase letters replaced with their lowercase counterparts' do
participant = create ( :issue_email_participant , email : 'SomEoNe@ExamPLe.com' )
expect ( participant . issue . email_participants_downcase ) . to match ( [ participant . email . downcase ] )
end
end
2011-10-08 21:36:38 +00:00
end