2019-03-30 03:23:56 -04:00
# frozen_string_literal: true
2011-10-08 17:36:38 -04:00
require 'spec_helper'
2017-07-10 10:24:02 -04:00
describe Issue do
2019-04-09 11:38:58 -04:00
include ExternalAuthorizationServiceHelpers
2011-10-08 17:36:38 -04:00
describe " Associations " do
2015-02-12 13:17:35 -05:00
it { is_expected . to belong_to ( :milestone ) }
2020-04-27 05:09:51 -04:00
it { is_expected . to belong_to ( :sprint ) }
2019-09-13 09:26:31 -04:00
it { is_expected . to belong_to ( :project ) }
it { is_expected . to belong_to ( :moved_to ) . class_name ( 'Issue' ) }
2020-04-23 14:09:46 -04:00
it { is_expected . to have_one ( :moved_from ) . class_name ( 'Issue' ) }
2019-09-13 09:26:31 -04: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 08:11:15 -04:00
it { is_expected . to have_many ( :assignees ) }
2019-12-10 10:07:52 -05:00
it { is_expected . to have_many ( :user_mentions ) . class_name ( " IssueUserMention " ) }
2020-05-04 02:10:10 -04:00
it { is_expected . to have_many ( :designs ) }
it { is_expected . to have_many ( :design_versions ) }
2019-12-10 07:07:55 -05:00
it { is_expected . to have_one ( :sentry_issue ) }
2020-04-22 20:09:41 -04:00
it { is_expected . to have_one ( :alert_management_alert ) }
2020-05-04 02:10:10 -04:00
describe 'versions.most_recent' do
it 'returns the most recent version' do
issue = create ( :issue )
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 17:36:38 -04:00
end
2012-08-29 01:52:19 -04:00
describe 'modules' do
2015-05-02 23:11:21 -04:00
subject { described_class }
2015-02-12 13:17:35 -05:00
it { is_expected . to include_module ( Issuable ) }
2015-05-02 23:11:21 -04:00
it { is_expected . to include_module ( Referable ) }
it { is_expected . to include_module ( Sortable ) }
it { is_expected . to include_module ( Taskable ) }
2018-03-13 14:43:02 -04:00
it_behaves_like 'AtomicInternalId' do
let ( :internal_id_attribute ) { :iid }
let ( :instance ) { build ( :issue ) }
2018-05-14 04:41:56 -04:00
let ( :scope ) { :project }
2018-03-13 14:43:02 -04:00
let ( :scope_attrs ) { { project : instance . project } }
let ( :usage ) { :issues }
end
2012-08-29 01:52:19 -04:00
end
2012-11-05 22:31:55 -05:00
subject { create ( :issue ) }
2012-05-20 14:15:13 -04:00
2017-12-07 12:41:30 -05:00
describe 'callbacks' do
describe '#ensure_metrics' do
it 'creates metrics after saving' do
issue = create ( :issue )
expect ( issue . metrics ) . to be_persisted
expect ( Issue :: Metrics . count ) . to eq ( 1 )
end
it 'does not create duplicate metrics for an issue' do
issue = create ( :issue )
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! )
create ( :issue )
end
end
end
2019-05-06 16:24:23 -04:00
describe 'locking' do
2019-05-06 17:42:21 -04:00
using RSpec :: Parameterized :: TableSyntax
2019-05-06 16:24:23 -04:00
2019-05-06 17:42:21 -04:00
where ( :lock_version ) do
[
[ 0 ] ,
[ " 0 " ]
]
end
with_them do
it 'works when an issue has a NULL lock_version' do
issue = create ( :issue )
2019-05-06 16:24:23 -04:00
2019-05-06 17:42:21 -04:00
described_class . where ( id : issue . id ) . update_all ( 'lock_version = NULL' )
2019-05-06 16:24:23 -04:00
2019-05-06 17:42:21 -04:00
issue . update! ( lock_version : lock_version , title : 'locking test' )
expect ( issue . reload . title ) . to eq ( 'locking test' )
end
2019-05-06 16:24:23 -04:00
end
end
2020-02-04 07:09:00 -05: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
2017-03-07 11:04:44 -05:00
describe '#order_by_position_and_priority' do
2017-08-02 15:55:11 -04:00
let ( :project ) { create :project }
2017-03-07 11:04:44 -05: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 ] ) }
let! ( :issue3 ) { create ( :issue , project : project , relative_position : 100 ) }
let! ( :issue4 ) { create ( :issue , project : project , relative_position : 200 ) }
it 'returns ordered list' do
2017-06-21 09:48:12 -04:00
expect ( project . issues . order_by_position_and_priority )
. to match [ issue3 , issue4 , issue1 , issue2 ]
2017-03-07 11:04:44 -05:00
end
end
2019-05-21 18:46:12 -04:00
describe '#sort' do
let ( :project ) { create ( :project ) }
context " by relative_position " do
let! ( :issue ) { create ( :issue , project : project ) }
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 08:11:15 -04: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 09:48:12 -04:00
expect ( subject . card_attributes )
. to eq ( { 'Author' = > 'Robert' , 'Assignee' = > '' } )
2017-05-04 08:11:15 -04: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 09:48:12 -04:00
expect ( subject . card_attributes )
. to eq ( { 'Author' = > 'Robert' , 'Assignee' = > 'Douwe' } )
2017-05-04 08:11:15 -04:00
end
end
2018-09-24 10:14:11 -04:00
describe '#close' do
subject ( :issue ) { create ( :issue , state : 'opened' ) }
2017-03-15 16:58:09 -04:00
2018-09-24 10:14:11 -04:00
it 'sets closed_at to Time.now when an issue is closed' do
expect { issue . close } . to change { issue . closed_at } . from ( nil )
end
it 'changes the state to closed' do
2019-10-18 07:11:44 -04: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 10:14:11 -04:00
end
end
2017-08-11 06:36:03 -04:00
2018-09-24 10:14:11 -04:00
describe '#reopen' do
let ( :user ) { create ( :user ) }
let ( :issue ) { create ( :issue , state : 'closed' , closed_at : Time . now , closed_by : user ) }
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 16:58:09 -04:00
2018-09-24 10:14:11 -04:00
it 'changes the state to opened' do
2019-10-18 07:11:44 -04:00
expect { issue . reopen } . to change { issue . state_id } . from ( described_class . available_states [ :closed ] ) . to ( described_class . available_states [ :opened ] )
2017-03-15 16:58:09 -04:00
end
end
2015-05-02 23:11:21 -04:00
describe '#to_reference' do
2016-12-15 09:51:50 -05:00
let ( :namespace ) { build ( :namespace , path : 'sample-namespace' ) }
2017-08-02 15:55:11 -04:00
let ( :project ) { build ( :project , name : 'sample-project' , namespace : namespace ) }
2016-12-15 09:51:50 -05:00
let ( :issue ) { build ( :issue , iid : 1 , project : project ) }
2016-11-02 19:49:13 -04:00
2016-12-15 09:51:50 -05:00
context 'when nil argument' do
it 'returns issue id' do
expect ( issue . to_reference ) . to eq " # 1 "
end
2016-12-15 07:50:28 -05:00
2020-02-28 07:09:05 -05: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 09:51:50 -05:00
end
end
2020-02-28 07:09:05 -05: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 09:51:50 -05:00
2020-02-28 07:09:05 -05: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 09:51:50 -05:00
end
2016-12-21 11:41:33 -05:00
2020-02-28 07:09:05 -05: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 09:51:50 -05:00
2020-02-28 07:09:05 -05:00
it 'returns a cross-project reference' do
expect ( issue . to_reference ( another_project ) ) . to eq " sample-project # 1 "
end
2016-12-15 09:51:50 -05:00
end
2020-02-28 07:09:05 -05: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 09:51:50 -05:00
2020-02-28 07:09:05 -05: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 09:51:50 -05:00
end
end
context 'when argument is a namespace' do
2020-02-28 07:09:05 -05:00
context 'when same as issue' do
2016-12-15 09:51:50 -05: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 07:09:05 -05: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 09:51:50 -05:00
end
2020-02-28 07:09:05 -05: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 09:51:50 -05:00
expect ( issue . to_reference ( group ) ) . to eq 'sample-namespace/sample-project#1'
end
end
2016-12-15 07:50:28 -05:00
end
2015-05-02 23:11:21 -04:00
end
2017-05-04 08:11:15 -04:00
describe '#assignee_or_author?' do
let ( :user ) { create ( :user ) }
let ( :issue ) { create ( :issue ) }
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 14:15:13 -04:00
end
2017-05-04 08:11:15 -04: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 14:15:13 -04:00
end
end
2013-02-18 04:41:32 -05:00
2016-03-17 06:11:22 -04:00
describe '#can_move?' do
let ( :user ) { create ( :user ) }
let ( :issue ) { create ( :issue ) }
2019-12-18 19:08:01 -05:00
2016-03-17 06:11:22 -04: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
2017-08-02 15:55:11 -04:00
let ( :project ) { create ( :project ) }
2016-03-17 06:11:22 -04:00
let ( :issue ) { create ( :issue , project : project ) }
2017-06-14 14:18:56 -04:00
before do
2017-12-22 03:18:28 -05:00
project . add_reporter ( user )
2017-06-14 14:18:56 -04:00
end
2016-03-17 06:11:22 -04:00
it { is_expected . to eq true }
2016-03-23 04:39:37 -04:00
context 'issue not persisted' do
let ( :issue ) { build ( :issue , project : project ) }
2019-12-18 19:08:01 -05:00
2016-03-23 04:39:37 -04:00
it { is_expected . to eq false }
end
2016-03-17 06:11:22 -04:00
context 'checking destination project also' do
subject { issue . can_move? ( user , to_project ) }
2019-10-18 07:11:44 -04:00
2017-08-02 15:55:11 -04:00
let ( :to_project ) { create ( :project ) }
2016-03-17 06:11:22 -04:00
context 'destination project allowed' do
2017-06-14 14:18:56 -04:00
before do
2017-12-22 03:18:28 -05:00
to_project . add_reporter ( user )
2017-06-14 14:18:56 -04:00
end
2016-03-17 06:11:22 -04:00
it { is_expected . to eq true }
end
context 'destination project not allowed' do
2017-06-14 14:18:56 -04:00
before do
2017-12-22 03:18:28 -05:00
to_project . add_guest ( user )
2017-06-14 14:18:56 -04:00
end
2016-03-17 06:11:22 -04:00
it { is_expected . to eq false }
end
end
end
end
describe '#moved?' do
2020-03-18 11:09:45 -04:00
context 'when issue has not been moved' do
subject { build_stubbed ( :issue ) }
2016-03-17 06:11:22 -04:00
2020-03-18 11:09:45 -04:00
it { is_expected . not_to be_moved }
2016-03-17 06:11:22 -04:00
end
2020-03-18 11:09:45 -04:00
context 'when issue has already been moved' do
subject { build_stubbed ( :issue , moved_to : build_stubbed ( :issue ) ) }
2016-03-17 06:11:22 -04:00
2020-03-18 11:09:45 -04:00
it { is_expected . to be_moved }
2016-03-17 06:11:22 -04:00
end
end
2019-09-13 09:26:31 -04:00
describe '#duplicated?' do
let ( :issue ) { create ( :issue ) }
2019-12-18 19:08:01 -05:00
2019-09-13 09:26:31 -04:00
subject { issue . duplicated? }
context 'issue not duplicated' do
it { is_expected . to eq false }
end
context 'issue already duplicated' do
let ( :duplicated_to_issue ) { create ( :issue ) }
let ( :issue ) { create ( :issue , duplicated_to : duplicated_to_issue ) }
it { is_expected . to eq true }
end
end
2018-04-05 11:17:02 -04: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 16:08:48 -05:00
describe '#to_branch_name does not exists' do
2018-04-05 11:17:02 -04: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 16:08:48 -05:00
describe '#to_branch_name exists not ending with -index' do
2018-04-05 11:17:02 -04: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 16:08:48 -05:00
describe '#to_branch_name exists ending with -index' do
2018-04-05 11:17:02 -04: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 04:09:21 -04:00
describe '#has_related_branch?' do
let ( :issue ) { create ( :issue , title : " Blue Bell Knoll " ) }
2019-12-18 19:08:01 -05:00
2017-05-04 04:09:21 -04: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 19:16:49 -04:00
it_behaves_like 'an editable mentionable' do
2017-01-25 14:52:12 -05:00
subject { create ( :issue , project : create ( :project , :repository ) ) }
2015-04-16 16:25:25 -04:00
2015-06-17 20:40:26 -04:00
let ( :backref_text ) { " issue #{ subject . to_reference } " }
2017-08-09 05:52:22 -04:00
let ( :set_mentionable_text ) { - > ( txt ) { subject . description = txt } }
2013-05-30 19:16:49 -04:00
end
2014-10-05 22:17:28 -04:00
it_behaves_like 'a Taskable' do
let ( :subject ) { create :issue }
end
2016-02-12 13:42:25 -05:00
describe " # to_branch_name " do
2016-04-12 06:31:44 -04:00
let ( :issue ) { create ( :issue , title : 'testing-issue' ) }
2016-02-12 13:42:25 -05:00
2016-04-13 15:20:03 -04:00
it 'starts with the issue iid' do
2020-03-04 04:08:20 -05:00
expect ( issue . to_branch_name ) . to match ( / \ A #{ issue . iid } -[A-Za-z \ -]+ \ z / )
2016-02-12 13:42:25 -05:00
end
2016-04-12 06:31:44 -04:00
it " contains the issue title if not confidential " do
2020-03-04 04:08:20 -05:00
expect ( issue . to_branch_name ) . to match ( / testing-issue \ z / )
2016-04-12 06:31:44 -04:00
end
it " does not contain the issue title if confidential " do
issue = create ( :issue , title : 'testing-issue' , confidential : true )
2020-03-04 04:08:20 -05:00
expect ( issue . to_branch_name ) . to match ( / confidential-issue \ z / )
2016-04-12 06:31:44 -04:00
end
2019-10-22 11:06:06 -04:00
context 'issue title longer than 100 characters' do
let ( :issue ) { create ( :issue , iid : 999 , title : 'Lorem ipsum dolor sit amet consectetur adipiscing elit Mauris sit amet ipsum id lacus custom fringilla convallis' ) }
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 13:42:25 -05:00
end
2016-05-26 07:38:28 -04:00
2018-04-05 11:17:02 -04:00
describe '#can_be_worked_on?' do
let ( :project ) { build ( :project ) }
2019-12-18 19:08:01 -05:00
2018-04-05 11:17:02 -04: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 07:38:28 -04:00
describe '#participants' do
context 'using a public project' do
2017-08-02 15:55:11 -04:00
let ( :project ) { create ( :project , :public ) }
2016-05-26 07:38:28 -04:00
let ( :issue ) { create ( :issue , project : project ) }
let! ( :note1 ) do
create ( :note_on_issue , noteable : issue , project : project , note : 'a' )
end
let! ( :note2 ) do
create ( :note_on_issue , noteable : issue , project : project , note : 'b' )
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 15:55:11 -04:00
project = create ( :project )
2016-05-26 07:38:28 -04:00
user = create ( :user )
issue = create ( :issue , project : project )
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 09:25:40 -04:00
describe 'cached counts' do
it 'updates when assignees change' do
user1 = create ( :user )
user2 = create ( :user )
2017-08-02 15:55:11 -04:00
project = create ( :project )
2017-05-04 08:11:15 -04:00
issue = create ( :issue , assignees : [ user1 ] , project : project )
2017-04-19 11:17:46 -04:00
project . add_developer ( user1 )
project . add_developer ( user2 )
2016-06-02 09:25:40 -04:00
expect ( user1 . assigned_open_issues_count ) . to eq ( 1 )
expect ( user2 . assigned_open_issues_count ) . to eq ( 0 )
2017-05-04 08:11:15 -04:00
issue . assignees = [ user2 ]
2016-06-02 09:25:40 -04: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 14:13:02 -04:00
describe '#visible_to_user?' do
2020-03-26 14:08:03 -04:00
let ( :project ) { build ( :project ) }
let ( :issue ) { build ( :issue , project : project ) }
let ( :user ) { create ( :user ) }
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 16:18:51 -04:00
context 'without a user' do
2020-03-26 14:08:03 -04:00
let ( :user ) { nil }
2016-11-01 16:18:51 -04:00
it 'returns true when the issue is publicly visible' do
expect ( issue ) . to receive ( :publicly_visible? ) . and_return ( true )
2020-03-26 14:08:03 -04:00
is_expected . to eq ( true )
2016-11-01 16:18:51 -04: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 14:08:03 -04:00
is_expected . to eq ( false )
2016-11-01 16:18:51 -04:00
end
end
2016-07-20 14:13:02 -04:00
context 'with a user' do
2020-03-26 14:08:03 -04:00
shared_examples 'issue readable by user' do
it { is_expected . to eq ( true ) }
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
shared_examples 'issue not readable by user' do
it { is_expected . to eq ( false ) }
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
shared_examples 'confidential issue readable by user' do
specify do
issue . confidential = true
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
is_expected . to eq ( true )
end
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
shared_examples 'confidential issue not readable by user' do
specify do
issue . confidential = true
2016-11-01 16:18:51 -04:00
2020-03-26 14:08:03 -04:00
is_expected . to eq ( false )
end
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
context 'with an admin user' do
let ( :user ) { build ( :admin ) }
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
end
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
context 'with an owner' do
before do
project . add_maintainer ( user )
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
end
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
context 'with a reporter user' do
before do
project . add_reporter ( user )
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
context 'with a guest user' do
before do
project . add_guest ( user )
end
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue not readable by user'
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
context 'when user is an assignee' do
before do
issue . update! ( assignees : [ user ] )
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
context 'when user is the author' do
2016-07-20 14:13:02 -04:00
before do
2020-03-26 14:08:03 -04:00
issue . update! ( author : user )
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue readable by user'
2016-07-20 14:13:02 -04:00
end
end
2020-03-26 14:08:03 -04: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 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue not readable by user'
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
context 'using an internal project' do
let ( :project ) { build ( :project , :internal ) }
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
context 'using an internal user' do
before do
allow ( user ) . to receive ( :external? ) . and_return ( false )
end
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue not readable by user'
2017-06-14 14:18:56 -04:00
end
2016-11-01 16:18:51 -04:00
2020-03-26 14:08:03 -04:00
context 'using an external user' do
before do
allow ( user ) . to receive ( :external? ) . and_return ( true )
end
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
it_behaves_like 'issue not readable by user'
it_behaves_like 'confidential issue not readable by user'
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
end
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
context 'using an external user' do
before do
allow ( user ) . to receive ( :external? ) . and_return ( true )
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
it_behaves_like 'issue not readable by user'
it_behaves_like 'confidential issue not readable by user'
2016-07-20 14:13:02 -04:00
end
end
2020-03-26 14:08:03 -04:00
context 'with an external authentication service' do
2016-07-20 14:13:02 -04:00
before do
2020-03-26 14:08:03 -04:00
enable_external_authorization_service_check
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
it 'is `false` when an external authorization service is enabled' do
issue = build ( :issue , project : build ( :project , :public ) )
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
expect ( issue ) . not_to be_visible_to_user
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04: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 14:13:02 -04:00
2020-03-26 14:08:03 -04: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 14:13:02 -04:00
end
2020-03-26 14:08:03 -04: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 14:13:02 -04:00
issue = build ( :issue , project : project )
2020-03-26 14:08:03 -04:00
user = build ( :user )
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
expect ( :: Gitlab :: ExternalAuthorization ) . not_to receive ( :access_allowed? )
expect ( issue . visible_to_user? ( user ) ) . to be_falsy
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
it 'does not check the external webservice for admins' do
issue = build ( :issue )
user = build ( :admin )
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
expect ( :: Gitlab :: ExternalAuthorization ) . not_to receive ( :access_allowed? )
issue . visible_to_user? ( user )
2016-07-20 14:13:02 -04:00
end
end
2020-03-26 14:08:03 -04:00
context 'when issue is moved to a private project' do
let ( :private_project ) { build ( :project , :private ) }
2016-07-20 14:13:02 -04:00
before do
2020-03-26 14:08:03 -04:00
issue . update ( project : private_project ) # move issue to private project
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04: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 14:13:02 -04:00
2020-03-26 14:08:03 -04: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 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
context 'when user is the author of the original issue' do
before do
issue . update! ( author : user )
end
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
it_behaves_like 'issue visible if user has guest access'
2016-07-20 14:13:02 -04:00
end
2020-03-26 14:08:03 -04:00
context 'when user is an assignee in the original issue' do
before do
issue . update! ( assignees : [ user ] )
end
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
it_behaves_like 'issue visible if user has guest access'
end
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04: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 14:13:02 -04:00
2020-03-26 14:08:03 -04:00
it_behaves_like 'issue readable by user'
it_behaves_like 'confidential issue not readable by user'
end
2016-07-20 14:13:02 -04:00
2020-03-26 14:08:03 -04: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 14:13:02 -04:00
end
end
end
describe '#publicly_visible?' do
context 'using a public project' do
2017-08-02 15:55:11 -04:00
let ( :project ) { create ( :project , :public ) }
2016-07-20 14:13:02 -04:00
it 'returns true for a regular issue' do
issue = build ( :issue , project : project )
2016-11-01 16:18:51 -04:00
expect ( issue ) . to be_truthy
2016-07-20 14:13:02 -04:00
end
it 'returns false for a confidential issue' do
issue = build ( :issue , :confidential , project : project )
2016-11-01 16:18:51 -04:00
expect ( issue ) . not_to be_falsy
2016-07-20 14:13:02 -04:00
end
end
context 'using an internal project' do
2017-08-02 15:55:11 -04:00
let ( :project ) { create ( :project , :internal ) }
2016-07-20 14:13:02 -04:00
it 'returns false for a regular issue' do
issue = build ( :issue , project : project )
2016-11-01 16:18:51 -04:00
expect ( issue ) . not_to be_falsy
2016-07-20 14:13:02 -04:00
end
it 'returns false for a confidential issue' do
issue = build ( :issue , :confidential , project : project )
2016-11-01 16:18:51 -04:00
expect ( issue ) . not_to be_falsy
2016-07-20 14:13:02 -04:00
end
end
context 'using a private project' do
2017-08-02 15:55:11 -04:00
let ( :project ) { create ( :project , :private ) }
2016-07-20 14:13:02 -04:00
it 'returns false for a regular issue' do
issue = build ( :issue , project : project )
2016-11-01 16:18:51 -04:00
expect ( issue ) . not_to be_falsy
2016-07-20 14:13:02 -04:00
end
it 'returns false for a confidential issue' do
issue = build ( :issue , :confidential , project : project )
2016-11-01 16:18:51 -04:00
expect ( issue ) . not_to be_falsy
2016-07-20 14:13:02 -04:00
end
end
end
2017-03-14 12:56:15 -04:00
describe '#hook_attrs' do
2017-10-05 13:02:50 -04: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 08:11:15 -04:00
end
2017-03-14 12:56:15 -04:00
end
2017-03-20 22:37:29 -04:00
2019-01-17 06:39:28 -05:00
describe '#check_for_spam?' do
using RSpec :: Parameterized :: TableSyntax
2017-03-20 22:37:29 -04:00
2019-01-17 06:39:28 -05: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-20 22:37:29 -04:00
end
2019-01-17 06:39:28 -05:00
with_them do
it 'checks for spam on issues that can be seen anonymously' do
project = create ( :project , visibility_level : visibility_level )
issue = create ( :issue , project : project , confidential : confidential , description : 'original description' )
2017-03-20 22:37:29 -04:00
2019-01-17 06:39:28 -05:00
issue . assign_attributes ( new_attributes )
2017-03-20 22:37:29 -04:00
2019-01-17 06:39:28 -05:00
expect ( issue . check_for_spam? ) . to eq ( check_for_spam? )
2017-03-20 22:37:29 -04:00
end
end
end
2017-08-17 11:21:25 -04: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
public_issue = create ( :issue )
create ( :issue , confidential : true )
expect ( described_class . public_only ) . to eq ( [ public_issue ] )
end
end
2017-12-01 08:52:16 -05:00
2019-02-25 06:00:24 -05:00
describe '.confidential_only' do
it 'only returns confidential_only issues' do
create ( :issue )
confidential_issue = create ( :issue , confidential : true )
expect ( described_class . confidential_only ) . to eq ( [ confidential_issue ] )
end
end
2020-04-09 20:10:04 -04:00
describe '.by_project_id_and_iid' do
let_it_be ( :issue_a ) { create ( :issue ) }
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
2017-12-01 08:52:16 -05:00
it_behaves_like 'throttled touch' do
subject { create ( :issue , updated_at : 1 . hour . ago ) }
end
2019-04-09 11:38:58 -04:00
2019-06-24 05:51:34 -04:00
describe " # labels_hook_attrs " do
let ( :label ) { create ( :label ) }
let ( :issue ) { create ( :labeled_issue , labels : [ label ] ) }
it " returns a list of label hook attributes " do
expect ( issue . labels_hook_attrs ) . to eq ( [ label . hook_attrs ] )
end
end
2019-07-22 03:47:29 -04:00
context " relative positioning " do
it_behaves_like " a class that supports relative positioning " do
let ( :project ) { create ( :project ) }
let ( :factory ) { :issue }
let ( :default_params ) { { project : project } }
end
end
2019-10-18 07:11:44 -04:00
it_behaves_like 'versioned description'
2020-03-04 04:08:20 -05:00
describe " # previous_updated_at " do
let_it_be ( :updated_at ) { Time . new ( 2012 , 01 , 06 ) }
let_it_be ( :issue ) { create ( :issue , updated_at : updated_at ) }
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
allow ( issue ) . to receive ( :previous_changes ) . and_return ( { 'updated_at' = > [ nil , Time . new ( 2013 , 02 , 06 ) ] } )
expect ( issue . previous_updated_at ) . to eq ( updated_at )
end
it 'returns previous updated_at when present' do
allow ( issue ) . to receive ( :previous_changes ) . and_return ( { 'updated_at' = > [ Time . new ( 2013 , 02 , 06 ) , Time . new ( 2013 , 03 , 06 ) ] } )
expect ( issue . previous_updated_at ) . to eq ( Time . new ( 2013 , 02 , 06 ) )
end
end
2020-05-04 02:10:10 -04: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
let ( :issue ) { create ( :issue ) }
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
2011-10-08 17:36:38 -04:00
end