Refactor user_spec.rb
This commit is contained in:
parent
d056feae94
commit
ad19b532a9
6 changed files with 501 additions and 604 deletions
|
@ -1,6 +1,6 @@
|
||||||
FactoryBot.define do
|
FactoryBot.define do
|
||||||
factory :token do
|
factory :token do
|
||||||
user_id { FactoryBot.create(:user).id }
|
user
|
||||||
end
|
end
|
||||||
|
|
||||||
factory :token_password_reset, parent: :token do
|
factory :token_password_reset, parent: :token do
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
# Requires: let(:group_access_instance) { ... }
|
RSpec.shared_examples 'HasGroups' do |group_access_factory:|
|
||||||
# Requires: let(:new_group_access_instance) { ... }
|
|
||||||
RSpec.shared_examples 'HasGroups' do
|
|
||||||
|
|
||||||
context 'group' do
|
context 'group' do
|
||||||
let(:group_access_instance_inactive) do
|
subject { create(group_access_factory) }
|
||||||
group_access_instance.update!(active: false)
|
|
||||||
group_access_instance
|
|
||||||
end
|
|
||||||
let(:group_full) { create(:group) }
|
let(:group_full) { create(:group) }
|
||||||
let(:group_read) { create(:group) }
|
let(:group_read) { create(:group) }
|
||||||
let(:group_inactive) { create(:group, active: false) }
|
let(:group_inactive) { create(:group, active: false) }
|
||||||
|
@ -22,7 +16,7 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'instance responds to group_through_identifier method' do
|
it 'instance responds to group_through_identifier method' do
|
||||||
expect(group_access_instance).to respond_to(described_class.group_through_identifier)
|
expect(subject).to respond_to(described_class.group_through_identifier)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -40,19 +34,19 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
context '#groups' do
|
context '#groups' do
|
||||||
|
|
||||||
it 'responds to groups' do
|
it 'responds to groups' do
|
||||||
expect(group_access_instance).to respond_to(:groups)
|
expect(subject).to respond_to(:groups)
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#groups.access' do
|
context '#groups.access' do
|
||||||
|
|
||||||
it 'responds to groups.access' do
|
it 'responds to groups.access' do
|
||||||
expect(group_access_instance.groups).to respond_to(:access)
|
expect(subject.groups).to respond_to(:access)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'result' do
|
context 'result' do
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_full.name => 'full',
|
group_full.name => 'full',
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
group_inactive.name => 'change',
|
group_inactive.name => 'change',
|
||||||
|
@ -60,23 +54,23 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns all related Groups' do
|
it 'returns all related Groups' do
|
||||||
expect(group_access_instance.groups.access.size).to eq(3)
|
expect(subject.groups.access.size).to eq(3)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'adds join table attribute(s like) access' do
|
it 'adds join table attribute(s like) access' do
|
||||||
expect(group_access_instance.groups.access.first).to respond_to(:access)
|
expect(subject.groups.access.first).to respond_to(:access)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'filters for given access parameter' do
|
it 'filters for given access parameter' do
|
||||||
expect(group_access_instance.groups.access('read')).to include(group_read)
|
expect(subject.groups.access('read')).to include(group_read)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'filters for given access list parameter' do
|
it 'filters for given access list parameter' do
|
||||||
expect(group_access_instance.groups.access('read', 'change')).to include(group_read, group_inactive)
|
expect(subject.groups.access('read', 'change')).to include(group_read, group_inactive)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'always includes full access groups' do
|
it 'always includes full access groups' do
|
||||||
expect(group_access_instance.groups.access('read')).to include(group_full)
|
expect(subject.groups.access('read')).to include(group_full)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -85,11 +79,11 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
context '#group_access?' do
|
context '#group_access?' do
|
||||||
|
|
||||||
it 'responds to group_access?' do
|
it 'responds to group_access?' do
|
||||||
expect(group_access_instance).to respond_to(:group_access?)
|
expect(subject).to respond_to(:group_access?)
|
||||||
end
|
end
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -107,61 +101,65 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'prevents inactive Group' do
|
it 'prevents inactive Group' do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_inactive.name => 'read',
|
group_inactive.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(group_access_instance.group_access?(group_inactive.id, 'read')).to be false
|
expect(subject.group_access?(group_inactive.id, 'read')).to be false
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'prevents inactive instances' do
|
it 'prevents inactive instances' do
|
||||||
group_access_instance_inactive.group_names_access_map = {
|
subject.update!(active: false)
|
||||||
|
|
||||||
|
subject.group_names_access_map = {
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(group_access_instance_inactive.group_access?(group_read.id, 'read')).to be false
|
expect(subject.group_access?(group_read.id, 'read')).to be false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#group_ids_access' do
|
context '#group_ids_access' do
|
||||||
|
|
||||||
it 'responds to group_ids_access' do
|
it 'responds to group_ids_access' do
|
||||||
expect(group_access_instance).to respond_to(:group_ids_access)
|
expect(subject).to respond_to(:group_ids_access)
|
||||||
end
|
end
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'lists only active Group IDs' do
|
it 'lists only active Group IDs' do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
group_inactive.name => 'read',
|
group_inactive.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
result = group_access_instance.group_ids_access('read')
|
result = subject.group_ids_access('read')
|
||||||
expect(result).not_to include(group_inactive.id)
|
expect(result).not_to include(group_inactive.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't list for inactive instances" do
|
it "doesn't list for inactive instances" do
|
||||||
group_access_instance_inactive.group_names_access_map = {
|
subject.update!(active: false)
|
||||||
|
|
||||||
|
subject.group_names_access_map = {
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(group_access_instance_inactive.group_ids_access('read')).to be_empty
|
expect(subject.group_ids_access('read')).to be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'single access' do
|
context 'single access' do
|
||||||
|
|
||||||
it 'lists access Group IDs' do
|
it 'lists access Group IDs' do
|
||||||
result = group_access_instance.group_ids_access('read')
|
result = subject.group_ids_access('read')
|
||||||
expect(result).to include(group_read.id)
|
expect(result).to include(group_read.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't list for no access" do
|
it "doesn't list for no access" do
|
||||||
result = group_access_instance.group_ids_access('change')
|
result = subject.group_ids_access('change')
|
||||||
expect(result).not_to include(group_read.id)
|
expect(result).not_to include(group_read.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -169,12 +167,12 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
context 'access list' do
|
context 'access list' do
|
||||||
|
|
||||||
it 'lists access Group IDs' do
|
it 'lists access Group IDs' do
|
||||||
result = group_access_instance.group_ids_access(%w[read change])
|
result = subject.group_ids_access(%w[read change])
|
||||||
expect(result).to include(group_read.id)
|
expect(result).to include(group_read.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't list for no access" do
|
it "doesn't list for no access" do
|
||||||
result = group_access_instance.group_ids_access(%w[change create])
|
result = subject.group_ids_access(%w[change create])
|
||||||
expect(result).not_to include(group_read.id)
|
expect(result).not_to include(group_read.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -183,19 +181,19 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
context '#groups_access' do
|
context '#groups_access' do
|
||||||
|
|
||||||
it 'responds to groups_access' do
|
it 'responds to groups_access' do
|
||||||
expect(group_access_instance).to respond_to(:groups_access)
|
expect(subject).to respond_to(:groups_access)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'wraps #group_ids_access' do
|
it 'wraps #group_ids_access' do
|
||||||
expect(group_access_instance).to receive(:group_ids_access)
|
expect(subject).to receive(:group_ids_access)
|
||||||
group_access_instance.groups_access('read')
|
subject.groups_access('read')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns Groups' do
|
it 'returns Groups' do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
}
|
}
|
||||||
result = group_access_instance.groups_access('read')
|
result = subject.groups_access('read')
|
||||||
expect(result).to include(group_read)
|
expect(result).to include(group_read)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -203,14 +201,14 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
context '#group_names_access_map=' do
|
context '#group_names_access_map=' do
|
||||||
|
|
||||||
it 'responds to group_names_access_map=' do
|
it 'responds to group_names_access_map=' do
|
||||||
expect(group_access_instance).to respond_to(:group_names_access_map=)
|
expect(subject).to respond_to(:group_names_access_map=)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'existing instance' do
|
context 'existing instance' do
|
||||||
|
|
||||||
it 'stores Hash with String values' do
|
it 'stores Hash with String values' do
|
||||||
expect do
|
expect do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_full.name => 'full',
|
group_full.name => 'full',
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
}
|
}
|
||||||
|
@ -221,7 +219,7 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
|
|
||||||
it 'stores Hash with Array<String> values' do
|
it 'stores Hash with Array<String> values' do
|
||||||
expect do
|
expect do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_full.name => 'full',
|
group_full.name => 'full',
|
||||||
group_read.name => %w[read change],
|
group_read.name => %w[read change],
|
||||||
}
|
}
|
||||||
|
@ -231,13 +229,13 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'allows empty Hash value' do
|
it 'allows empty Hash value' do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_full.name => 'full',
|
group_full.name => 'full',
|
||||||
group_read.name => %w[read change],
|
group_read.name => %w[read change],
|
||||||
}
|
}
|
||||||
|
|
||||||
expect do
|
expect do
|
||||||
group_access_instance.group_names_access_map = {}
|
subject.group_names_access_map = {}
|
||||||
end.to change {
|
end.to change {
|
||||||
described_class.group_through.klass.count
|
described_class.group_through.klass.count
|
||||||
}.by(-3)
|
}.by(-3)
|
||||||
|
@ -249,13 +247,13 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
exception = ActiveRecord::RecordInvalid
|
exception = ActiveRecord::RecordInvalid
|
||||||
|
|
||||||
expect do
|
expect do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_full.name => invalid_combination,
|
group_full.name => invalid_combination,
|
||||||
}
|
}
|
||||||
end.to raise_error(exception)
|
end.to raise_error(exception)
|
||||||
|
|
||||||
expect do
|
expect do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_full.name => invalid_combination.reverse,
|
group_full.name => invalid_combination.reverse,
|
||||||
}
|
}
|
||||||
end.to raise_error(exception)
|
end.to raise_error(exception)
|
||||||
|
@ -263,10 +261,11 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'new instance' do
|
context 'new instance' do
|
||||||
|
subject { build(group_access_factory) }
|
||||||
|
|
||||||
it "doesn't store directly" do
|
it "doesn't store directly" do
|
||||||
expect do
|
expect do
|
||||||
new_group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_full.name => 'full',
|
group_full.name => 'full',
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
}
|
}
|
||||||
|
@ -277,12 +276,12 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
|
|
||||||
it 'stores after save' do
|
it 'stores after save' do
|
||||||
expect do
|
expect do
|
||||||
new_group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_full.name => 'full',
|
group_full.name => 'full',
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
new_group_access_instance.save
|
subject.save
|
||||||
end.to change {
|
end.to change {
|
||||||
described_class.group_through.klass.count
|
described_class.group_through.klass.count
|
||||||
}.by(2)
|
}.by(2)
|
||||||
|
@ -290,9 +289,9 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
|
|
||||||
it 'allows empty Hash value' do
|
it 'allows empty Hash value' do
|
||||||
expect do
|
expect do
|
||||||
new_group_access_instance.group_names_access_map = {}
|
subject.group_names_access_map = {}
|
||||||
|
|
||||||
new_group_access_instance.save
|
subject.save
|
||||||
end.not_to change {
|
end.not_to change {
|
||||||
described_class.group_through.klass.count
|
described_class.group_through.klass.count
|
||||||
}
|
}
|
||||||
|
@ -303,7 +302,7 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
context '#group_names_access_map' do
|
context '#group_names_access_map' do
|
||||||
|
|
||||||
it 'responds to group_names_access_map' do
|
it 'responds to group_names_access_map' do
|
||||||
expect(group_access_instance).to respond_to(:group_names_access_map)
|
expect(subject).to respond_to(:group_names_access_map)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns instance Group name => access relations as Hash' do
|
it 'returns instance Group name => access relations as Hash' do
|
||||||
|
@ -312,44 +311,46 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
group_read.name => ['read'],
|
group_read.name => ['read'],
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance.group_names_access_map = expected
|
subject.group_names_access_map = expected
|
||||||
|
|
||||||
expect(group_access_instance.group_names_access_map).to eq(expected)
|
expect(subject.group_names_access_map).to eq(expected)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't map for inactive instances" do
|
it "doesn't map for inactive instances" do
|
||||||
group_access_instance_inactive.group_names_access_map = {
|
subject.update!(active: false)
|
||||||
|
|
||||||
|
subject.group_names_access_map = {
|
||||||
group_full.name => ['full'],
|
group_full.name => ['full'],
|
||||||
group_read.name => ['read'],
|
group_read.name => ['read'],
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(group_access_instance_inactive.group_names_access_map).to be_empty
|
expect(subject.group_names_access_map).to be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns empty map if none is stored' do
|
it 'returns empty map if none is stored' do
|
||||||
|
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_full.name => 'full',
|
group_full.name => 'full',
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance.group_names_access_map = {}
|
subject.group_names_access_map = {}
|
||||||
|
|
||||||
expect(group_access_instance.group_names_access_map).to be_blank
|
expect(subject.group_names_access_map).to be_blank
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#group_ids_access_map=' do
|
context '#group_ids_access_map=' do
|
||||||
|
|
||||||
it 'responds to group_ids_access_map=' do
|
it 'responds to group_ids_access_map=' do
|
||||||
expect(group_access_instance).to respond_to(:group_ids_access_map=)
|
expect(subject).to respond_to(:group_ids_access_map=)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'existing instance' do
|
context 'existing instance' do
|
||||||
|
|
||||||
it 'stores Hash with String values' do
|
it 'stores Hash with String values' do
|
||||||
expect do
|
expect do
|
||||||
group_access_instance.group_ids_access_map = {
|
subject.group_ids_access_map = {
|
||||||
group_full.id => 'full',
|
group_full.id => 'full',
|
||||||
group_read.id => 'read',
|
group_read.id => 'read',
|
||||||
}
|
}
|
||||||
|
@ -360,7 +361,7 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
|
|
||||||
it 'stores Hash with Array<String> values' do
|
it 'stores Hash with Array<String> values' do
|
||||||
expect do
|
expect do
|
||||||
group_access_instance.group_ids_access_map = {
|
subject.group_ids_access_map = {
|
||||||
group_full.id => 'full',
|
group_full.id => 'full',
|
||||||
group_read.id => %w[read change],
|
group_read.id => %w[read change],
|
||||||
}
|
}
|
||||||
|
@ -370,13 +371,13 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'allows empty Hash value' do
|
it 'allows empty Hash value' do
|
||||||
group_access_instance.group_ids_access_map = {
|
subject.group_ids_access_map = {
|
||||||
group_full.id => 'full',
|
group_full.id => 'full',
|
||||||
group_read.id => %w[read change],
|
group_read.id => %w[read change],
|
||||||
}
|
}
|
||||||
|
|
||||||
expect do
|
expect do
|
||||||
group_access_instance.group_ids_access_map = {}
|
subject.group_ids_access_map = {}
|
||||||
end.to change {
|
end.to change {
|
||||||
described_class.group_through.klass.count
|
described_class.group_through.klass.count
|
||||||
}.by(-3)
|
}.by(-3)
|
||||||
|
@ -384,10 +385,11 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'new instance' do
|
context 'new instance' do
|
||||||
|
subject { build(group_access_factory) }
|
||||||
|
|
||||||
it "doesn't store directly" do
|
it "doesn't store directly" do
|
||||||
expect do
|
expect do
|
||||||
new_group_access_instance.group_ids_access_map = {
|
subject.group_ids_access_map = {
|
||||||
group_full.id => 'full',
|
group_full.id => 'full',
|
||||||
group_read.id => 'read',
|
group_read.id => 'read',
|
||||||
}
|
}
|
||||||
|
@ -398,12 +400,12 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
|
|
||||||
it 'stores after save' do
|
it 'stores after save' do
|
||||||
expect do
|
expect do
|
||||||
new_group_access_instance.group_ids_access_map = {
|
subject.group_ids_access_map = {
|
||||||
group_full.id => 'full',
|
group_full.id => 'full',
|
||||||
group_read.id => 'read',
|
group_read.id => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
new_group_access_instance.save
|
subject.save
|
||||||
end.to change {
|
end.to change {
|
||||||
described_class.group_through.klass.count
|
described_class.group_through.klass.count
|
||||||
}.by(2)
|
}.by(2)
|
||||||
|
@ -411,9 +413,9 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
|
|
||||||
it 'allows empty Hash value' do
|
it 'allows empty Hash value' do
|
||||||
expect do
|
expect do
|
||||||
new_group_access_instance.group_ids_access_map = {}
|
subject.group_ids_access_map = {}
|
||||||
|
|
||||||
new_group_access_instance.save
|
subject.save
|
||||||
end.not_to change {
|
end.not_to change {
|
||||||
described_class.group_through.klass.count
|
described_class.group_through.klass.count
|
||||||
}
|
}
|
||||||
|
@ -424,7 +426,7 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
context '#group_ids_access_map' do
|
context '#group_ids_access_map' do
|
||||||
|
|
||||||
it 'responds to group_ids_access_map' do
|
it 'responds to group_ids_access_map' do
|
||||||
expect(group_access_instance).to respond_to(:group_ids_access_map)
|
expect(subject).to respond_to(:group_ids_access_map)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns instance Group ID => access relations as Hash' do
|
it 'returns instance Group ID => access relations as Hash' do
|
||||||
|
@ -433,30 +435,32 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
group_read.id => ['read'],
|
group_read.id => ['read'],
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance.group_ids_access_map = expected
|
subject.group_ids_access_map = expected
|
||||||
|
|
||||||
expect(group_access_instance.group_ids_access_map).to eq(expected)
|
expect(subject.group_ids_access_map).to eq(expected)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't map for inactive instances" do
|
it "doesn't map for inactive instances" do
|
||||||
group_access_instance_inactive.group_ids_access_map = {
|
subject.update!(active: false)
|
||||||
|
|
||||||
|
subject.group_ids_access_map = {
|
||||||
group_full.id => ['full'],
|
group_full.id => ['full'],
|
||||||
group_read.id => ['read'],
|
group_read.id => ['read'],
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(group_access_instance_inactive.group_ids_access_map).to be_empty
|
expect(subject.group_ids_access_map).to be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns empty map if none is stored' do
|
it 'returns empty map if none is stored' do
|
||||||
|
|
||||||
group_access_instance.group_ids_access_map = {
|
subject.group_ids_access_map = {
|
||||||
group_full.id => 'full',
|
group_full.id => 'full',
|
||||||
group_read.id => 'read',
|
group_read.id => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance.group_ids_access_map = {}
|
subject.group_ids_access_map = {}
|
||||||
|
|
||||||
expect(group_access_instance.group_ids_access_map).to be_blank
|
expect(subject.group_ids_access_map).to be_blank
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -468,8 +472,8 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
group_read.id => ['read'],
|
group_read.id => ['read'],
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance.associations_from_param(group_ids: expected)
|
subject.associations_from_param(group_ids: expected)
|
||||||
expect(group_access_instance.group_ids_access_map).to eq(expected)
|
expect(subject.group_ids_access_map).to eq(expected)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'handles groups parameter as group_names_access_map' do
|
it 'handles groups parameter as group_names_access_map' do
|
||||||
|
@ -478,8 +482,8 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
group_read.name => ['read'],
|
group_read.name => ['read'],
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance.associations_from_param(groups: expected)
|
subject.associations_from_param(groups: expected)
|
||||||
expect(group_access_instance.group_names_access_map).to eq(expected)
|
expect(subject.group_names_access_map).to eq(expected)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -491,9 +495,9 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
group_read.id => ['read'],
|
group_read.id => ['read'],
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance.group_ids_access_map = expected
|
subject.group_ids_access_map = expected
|
||||||
|
|
||||||
result = group_access_instance.attributes_with_association_ids
|
result = subject.attributes_with_association_ids
|
||||||
expect(result['group_ids']).to eq(expected)
|
expect(result['group_ids']).to eq(expected)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -506,9 +510,9 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
group_read.id => ['read'],
|
group_read.id => ['read'],
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance.group_ids_access_map = expected
|
subject.group_ids_access_map = expected
|
||||||
|
|
||||||
result = group_access_instance.attributes_with_association_names
|
result = subject.attributes_with_association_names
|
||||||
expect(result['group_ids']).to eq(expected)
|
expect(result['group_ids']).to eq(expected)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -518,9 +522,9 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
group_read.name => ['read'],
|
group_read.name => ['read'],
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance.group_names_access_map = expected
|
subject.group_names_access_map = expected
|
||||||
|
|
||||||
result = group_access_instance.attributes_with_association_names
|
result = subject.attributes_with_association_names
|
||||||
expect(result['groups']).to eq(expected)
|
expect(result['groups']).to eq(expected)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -532,18 +536,20 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
end
|
end
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'lists only active instances' do
|
it 'lists only active instances' do
|
||||||
group_access_instance_inactive.group_names_access_map = {
|
subject.update!(active: false)
|
||||||
|
|
||||||
|
subject.group_names_access_map = {
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
result = described_class.group_access(group_read.id, 'read')
|
result = described_class.group_access(group_read.id, 'read')
|
||||||
expect(result).not_to include(group_access_instance_inactive)
|
expect(result).not_to include(subject)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'Group ID parameter' do
|
context 'Group ID parameter' do
|
||||||
|
@ -571,24 +577,24 @@ RSpec.shared_examples 'HasGroups' do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns class instances' do
|
it 'returns class instances' do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
result = described_class.group_access_ids(group_read, 'read')
|
result = described_class.group_access_ids(group_read, 'read')
|
||||||
expect(result).to include(group_access_instance.id)
|
expect(result).to include(subject.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'destroys relations before instance gets destroyed' do
|
it 'destroys relations before instance gets destroyed' do
|
||||||
|
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_full.name => 'full',
|
group_full.name => 'full',
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
group_inactive.name => 'change',
|
group_inactive.name => 'change',
|
||||||
}
|
}
|
||||||
expect do
|
expect do
|
||||||
group_access_instance.destroy
|
subject.destroy
|
||||||
end.to change {
|
end.to change {
|
||||||
described_class.group_through.klass.count
|
described_class.group_through.klass.count
|
||||||
}.by(-3)
|
}.by(-3)
|
||||||
|
@ -600,22 +606,22 @@ RSpec.shared_examples '#group_access? call' do
|
||||||
context 'single access' do
|
context 'single access' do
|
||||||
|
|
||||||
it 'checks positive' do
|
it 'checks positive' do
|
||||||
expect(group_access_instance.group_access?(group_parameter, 'read')).to be true
|
expect(subject.group_access?(group_parameter, 'read')).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'checks negative' do
|
it 'checks negative' do
|
||||||
expect(group_access_instance.group_access?(group_parameter, 'change')).to be false
|
expect(subject.group_access?(group_parameter, 'change')).to be false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'access list' do
|
context 'access list' do
|
||||||
|
|
||||||
it 'checks positive' do
|
it 'checks positive' do
|
||||||
expect(group_access_instance.group_access?(group_parameter, %w[read change])).to be true
|
expect(subject.group_access?(group_parameter, %w[read change])).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'checks negative' do
|
it 'checks negative' do
|
||||||
expect(group_access_instance.group_access?(group_parameter, %w[change create])).to be false
|
expect(subject.group_access?(group_parameter, %w[change create])).to be false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -624,22 +630,22 @@ RSpec.shared_examples '.group_access call' do
|
||||||
context 'single access' do
|
context 'single access' do
|
||||||
|
|
||||||
it 'lists access IDs' do
|
it 'lists access IDs' do
|
||||||
expect(described_class.group_access(group_parameter, 'read')).to include(group_access_instance)
|
expect(described_class.group_access(group_parameter, 'read')).to include(subject)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'excludes non access IDs' do
|
it 'excludes non access IDs' do
|
||||||
expect(described_class.group_access(group_parameter, 'change')).not_to include(group_access_instance)
|
expect(described_class.group_access(group_parameter, 'change')).not_to include(subject)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'access list' do
|
context 'access list' do
|
||||||
|
|
||||||
it 'lists access IDs' do
|
it 'lists access IDs' do
|
||||||
expect(described_class.group_access(group_parameter, %w[read change])).to include(group_access_instance)
|
expect(described_class.group_access(group_parameter, %w[read change])).to include(subject)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'excludes non access IDs' do
|
it 'excludes non access IDs' do
|
||||||
expect(described_class.group_access(group_parameter, %w[change create])).not_to include(group_access_instance)
|
expect(described_class.group_access(group_parameter, %w[change create])).not_to include(subject)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
# Requires: let(:group_access_no_permission_instance) { ... }
|
RSpec.shared_examples 'HasGroups and Permissions' do |group_access_no_permission_factory:|
|
||||||
RSpec.shared_examples 'HasGroups and Permissions' do
|
|
||||||
|
|
||||||
context 'group' do
|
context 'group' do
|
||||||
|
subject { build(group_access_no_permission_factory) }
|
||||||
let(:group_read) { create(:group) }
|
let(:group_read) { create(:group) }
|
||||||
|
|
||||||
before(:each) do
|
before(:each) do
|
||||||
group_access_no_permission_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_read.name => 'read',
|
group_read.name => 'read',
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -14,49 +12,49 @@ RSpec.shared_examples 'HasGroups and Permissions' do
|
||||||
context '#group_access?' do
|
context '#group_access?' do
|
||||||
|
|
||||||
it 'prevents instances without permissions' do
|
it 'prevents instances without permissions' do
|
||||||
expect(group_access_no_permission_instance.group_access?(group_read, 'read')).to be false
|
expect(subject.group_access?(group_read, 'read')).to be false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#group_ids_access' do
|
context '#group_ids_access' do
|
||||||
|
|
||||||
it 'prevents instances without permissions' do
|
it 'prevents instances without permissions' do
|
||||||
expect(group_access_no_permission_instance.group_ids_access('read')).to be_empty
|
expect(subject.group_ids_access('read')).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#groups_access' do
|
context '#groups_access' do
|
||||||
|
|
||||||
it 'prevents instances without permissions' do
|
it 'prevents instances without permissions' do
|
||||||
expect(group_access_no_permission_instance.groups_access('read')).to be_empty
|
expect(subject.groups_access('read')).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#group_names_access_map' do
|
context '#group_names_access_map' do
|
||||||
|
|
||||||
it 'prevents instances without permissions' do
|
it 'prevents instances without permissions' do
|
||||||
expect(group_access_no_permission_instance.group_names_access_map).to be_empty
|
expect(subject.group_names_access_map).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#group_ids_access_map' do
|
context '#group_ids_access_map' do
|
||||||
|
|
||||||
it 'prevents instances without permissions' do
|
it 'prevents instances without permissions' do
|
||||||
expect(group_access_no_permission_instance.group_ids_access_map).to be_empty
|
expect(subject.group_ids_access_map).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#attributes_with_association_ids' do
|
context '#attributes_with_association_ids' do
|
||||||
|
|
||||||
it 'prevents instances without permissions' do
|
it 'prevents instances without permissions' do
|
||||||
expect(group_access_no_permission_instance.attributes_with_association_ids['group_ids']).to be_empty
|
expect(subject.attributes_with_association_ids['group_ids']).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#attributes_with_association_names' do
|
context '#attributes_with_association_names' do
|
||||||
|
|
||||||
it 'prevents instances without permissions' do
|
it 'prevents instances without permissions' do
|
||||||
expect(group_access_no_permission_instance.attributes_with_association_names['group_ids']).to be_empty
|
expect(subject.attributes_with_association_names['group_ids']).to be_empty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -64,7 +62,7 @@ RSpec.shared_examples 'HasGroups and Permissions' do
|
||||||
|
|
||||||
it 'prevents instances without permissions' do
|
it 'prevents instances without permissions' do
|
||||||
result = described_class.group_access(group_read.id, 'read')
|
result = described_class.group_access(group_read.id, 'read')
|
||||||
expect(result).not_to include(group_access_no_permission_instance)
|
expect(result).not_to include(subject)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -72,7 +70,7 @@ RSpec.shared_examples 'HasGroups and Permissions' do
|
||||||
|
|
||||||
it 'prevents instances without permissions' do
|
it 'prevents instances without permissions' do
|
||||||
result = described_class.group_access(group_read.id, 'read')
|
result = described_class.group_access(group_read.id, 'read')
|
||||||
expect(result).not_to include(group_access_no_permission_instance.id)
|
expect(result).not_to include(subject.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
# Requires: let(:group_access_instance) { ... }
|
RSpec.shared_examples 'HasRoles' do |group_access_factory:|
|
||||||
# Requires: let(:new_group_access_instance) { ... }
|
|
||||||
RSpec.shared_examples 'HasRoles' do
|
|
||||||
|
|
||||||
context 'role' do
|
context 'role' do
|
||||||
|
subject { create(group_access_factory) }
|
||||||
let(:group_access_instance_inactive) do
|
|
||||||
group_access_instance.update!(active: false)
|
|
||||||
group_access_instance
|
|
||||||
end
|
|
||||||
let(:role) { create(:role) }
|
let(:role) { create(:role) }
|
||||||
let(:group_instance) { create(:group) }
|
let(:group_instance) { create(:group) }
|
||||||
let(:group_role) { create(:group) }
|
let(:group_role) { create(:group) }
|
||||||
|
@ -16,7 +9,7 @@ RSpec.shared_examples 'HasRoles' do
|
||||||
context '#role_access?' do
|
context '#role_access?' do
|
||||||
|
|
||||||
it 'responds to role_access?' do
|
it 'responds to role_access?' do
|
||||||
expect(group_access_instance).to respond_to(:role_access?)
|
expect(subject).to respond_to(:role_access?)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'active Role' do
|
context 'active Role' do
|
||||||
|
@ -25,8 +18,8 @@ RSpec.shared_examples 'HasRoles' do
|
||||||
group_role.name => 'read',
|
group_role.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance.roles.push(role)
|
subject.roles.push(role)
|
||||||
group_access_instance.save
|
subject.save
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'Group ID parameter' do
|
context 'Group ID parameter' do
|
||||||
|
@ -46,7 +39,7 @@ RSpec.shared_examples 'HasRoles' do
|
||||||
group_inactive.name => 'read',
|
group_inactive.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(group_access_instance.group_access?(group_inactive.id, 'read')).to be false
|
expect(subject.group_access?(group_inactive.id, 'read')).to be false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -56,10 +49,10 @@ RSpec.shared_examples 'HasRoles' do
|
||||||
group_role.name => 'read',
|
group_role.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance.roles.push(role_inactive)
|
subject.roles.push(role_inactive)
|
||||||
group_access_instance.save
|
subject.save
|
||||||
|
|
||||||
expect(group_access_instance.group_access?(group_role.id, 'read')).to be false
|
expect(subject.group_access?(group_role.id, 'read')).to be false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -70,8 +63,8 @@ RSpec.shared_examples 'HasRoles' do
|
||||||
group_role.name => 'read',
|
group_role.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance.roles.push(role)
|
subject.roles.push(role)
|
||||||
group_access_instance.save
|
subject.save
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'responds to role_access_ids' do
|
it 'responds to role_access_ids' do
|
||||||
|
@ -79,16 +72,18 @@ RSpec.shared_examples 'HasRoles' do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'lists only active instance IDs' do
|
it 'lists only active instance IDs' do
|
||||||
|
subject.update!(active: false)
|
||||||
|
|
||||||
role.group_names_access_map = {
|
role.group_names_access_map = {
|
||||||
group_role.name => 'read',
|
group_role.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance_inactive.roles.push(role)
|
subject.roles.push(role)
|
||||||
group_access_instance_inactive.save
|
subject.save
|
||||||
group_access_instance_inactive.save
|
subject.save
|
||||||
|
|
||||||
result = described_class.role_access_ids(group_role.id, 'read')
|
result = described_class.role_access_ids(group_role.id, 'read')
|
||||||
expect(result).not_to include(group_access_instance_inactive.id)
|
expect(result).not_to include(subject.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'Group ID parameter' do
|
context 'Group ID parameter' do
|
||||||
|
@ -111,10 +106,10 @@ RSpec.shared_examples 'HasRoles' do
|
||||||
group_role.name => 'read',
|
group_role.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance.roles.push(role)
|
subject.roles.push(role)
|
||||||
group_access_instance.save
|
subject.save
|
||||||
|
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_instance.name => 'read',
|
group_instance.name => 'read',
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -122,13 +117,13 @@ RSpec.shared_examples 'HasRoles' do
|
||||||
context '#group_access?' do
|
context '#group_access?' do
|
||||||
|
|
||||||
it 'falls back to #role_access?' do
|
it 'falls back to #role_access?' do
|
||||||
expect(group_access_instance).to receive(:role_access?)
|
expect(subject).to receive(:role_access?)
|
||||||
group_access_instance.group_access?(group_role, 'read')
|
subject.group_access?(group_role, 'read')
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't fall back to #role_access? if not needed" do
|
it "doesn't fall back to #role_access? if not needed" do
|
||||||
expect(group_access_instance).not_to receive(:role_access?)
|
expect(subject).not_to receive(:role_access?)
|
||||||
group_access_instance.group_access?(group_instance, 'read')
|
subject.group_access?(group_instance, 'read')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -139,10 +134,10 @@ RSpec.shared_examples 'HasRoles' do
|
||||||
group_role.name => 'read',
|
group_role.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
group_access_instance.roles.push(role)
|
subject.roles.push(role)
|
||||||
group_access_instance.save
|
subject.save
|
||||||
|
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_instance.name => 'read',
|
group_instance.name => 'read',
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -153,28 +148,28 @@ RSpec.shared_examples 'HasRoles' do
|
||||||
group_inactive.name => 'read',
|
group_inactive.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
result = group_access_instance.group_ids_access('read')
|
result = subject.group_ids_access('read')
|
||||||
expect(result).not_to include(group_inactive.id)
|
expect(result).not_to include(group_inactive.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'single access' do
|
context 'single access' do
|
||||||
|
|
||||||
it 'lists access Group IDs' do
|
it 'lists access Group IDs' do
|
||||||
result = group_access_instance.group_ids_access('read')
|
result = subject.group_ids_access('read')
|
||||||
expect(result).to include(group_role.id)
|
expect(result).to include(group_role.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't list for no access" do
|
it "doesn't list for no access" do
|
||||||
result = group_access_instance.group_ids_access('change')
|
result = subject.group_ids_access('change')
|
||||||
expect(result).not_to include(group_role.id)
|
expect(result).not_to include(group_role.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't contain duplicate IDs" do
|
it "doesn't contain duplicate IDs" do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_role.name => 'read',
|
group_role.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
result = group_access_instance.group_ids_access('read')
|
result = subject.group_ids_access('read')
|
||||||
expect(result.uniq).to eq(result)
|
expect(result.uniq).to eq(result)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -182,21 +177,21 @@ RSpec.shared_examples 'HasRoles' do
|
||||||
context 'access list' do
|
context 'access list' do
|
||||||
|
|
||||||
it 'lists access Group IDs' do
|
it 'lists access Group IDs' do
|
||||||
result = group_access_instance.group_ids_access(%w[read change])
|
result = subject.group_ids_access(%w[read change])
|
||||||
expect(result).to include(group_role.id)
|
expect(result).to include(group_role.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't list for no access" do
|
it "doesn't list for no access" do
|
||||||
result = group_access_instance.group_ids_access(%w[change create])
|
result = subject.group_ids_access(%w[change create])
|
||||||
expect(result).not_to include(group_role.id)
|
expect(result).not_to include(group_role.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't contain duplicate IDs" do
|
it "doesn't contain duplicate IDs" do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_role.name => 'read',
|
group_role.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
result = group_access_instance.group_ids_access(%w[read create])
|
result = subject.group_ids_access(%w[read create])
|
||||||
expect(result.uniq).to eq(result)
|
expect(result.uniq).to eq(result)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -206,11 +201,11 @@ RSpec.shared_examples 'HasRoles' do
|
||||||
|
|
||||||
it 'includes the result of .role_access_ids' do
|
it 'includes the result of .role_access_ids' do
|
||||||
result = described_class.group_access_ids(group_role, 'read')
|
result = described_class.group_access_ids(group_role, 'read')
|
||||||
expect(result).to include(group_access_instance.id)
|
expect(result).to include(subject.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "doesn't contain duplicate IDs" do
|
it "doesn't contain duplicate IDs" do
|
||||||
group_access_instance.group_names_access_map = {
|
subject.group_names_access_map = {
|
||||||
group_role.name => 'read',
|
group_role.name => 'read',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,22 +221,22 @@ RSpec.shared_examples '#role_access? call' do
|
||||||
context 'single access' do
|
context 'single access' do
|
||||||
|
|
||||||
it 'checks positive' do
|
it 'checks positive' do
|
||||||
expect(group_access_instance.role_access?(group_parameter, 'read')).to be true
|
expect(subject.role_access?(group_parameter, 'read')).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'checks negative' do
|
it 'checks negative' do
|
||||||
expect(group_access_instance.role_access?(group_parameter, 'change')).to be false
|
expect(subject.role_access?(group_parameter, 'change')).to be false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'access list' do
|
context 'access list' do
|
||||||
|
|
||||||
it 'checks positive' do
|
it 'checks positive' do
|
||||||
expect(group_access_instance.role_access?(group_parameter, %w[read change])).to be true
|
expect(subject.role_access?(group_parameter, %w[read change])).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'checks negative' do
|
it 'checks negative' do
|
||||||
expect(group_access_instance.role_access?(group_parameter, %w[change create])).to be false
|
expect(subject.role_access?(group_parameter, %w[change create])).to be false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -250,22 +245,22 @@ RSpec.shared_examples '.role_access_ids call' do
|
||||||
context 'single access' do
|
context 'single access' do
|
||||||
|
|
||||||
it 'lists access IDs' do
|
it 'lists access IDs' do
|
||||||
expect(described_class.role_access_ids(group_parameter, 'read')).to include(group_access_instance.id)
|
expect(described_class.role_access_ids(group_parameter, 'read')).to include(subject.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'excludes non access IDs' do
|
it 'excludes non access IDs' do
|
||||||
expect(described_class.role_access_ids(group_parameter, 'change')).not_to include(group_access_instance.id)
|
expect(described_class.role_access_ids(group_parameter, 'change')).not_to include(subject.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'access list' do
|
context 'access list' do
|
||||||
|
|
||||||
it 'lists access IDs' do
|
it 'lists access IDs' do
|
||||||
expect(described_class.role_access_ids(group_parameter, %w[read change])).to include(group_access_instance.id)
|
expect(described_class.role_access_ids(group_parameter, %w[read change])).to include(subject.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'excludes non access IDs' do
|
it 'excludes non access IDs' do
|
||||||
expect(described_class.role_access_ids(group_parameter, %w[change create])).not_to include(group_access_instance.id)
|
expect(described_class.role_access_ids(group_parameter, %w[change create])).not_to include(subject.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,10 +2,7 @@ require 'rails_helper'
|
||||||
require 'models/concerns/has_groups_examples'
|
require 'models/concerns/has_groups_examples'
|
||||||
|
|
||||||
RSpec.describe Role do
|
RSpec.describe Role do
|
||||||
let(:group_access_instance) { create(:role) }
|
include_examples 'HasGroups', group_access_factory: :role
|
||||||
let(:new_group_access_instance) { build(:role) }
|
|
||||||
|
|
||||||
include_examples 'HasGroups'
|
|
||||||
|
|
||||||
context '#validate_agent_limit_by_attributes' do
|
context '#validate_agent_limit_by_attributes' do
|
||||||
|
|
||||||
|
|
|
@ -5,197 +5,268 @@ require 'models/concerns/has_groups_permissions_examples'
|
||||||
require 'models/concerns/can_lookup_examples'
|
require 'models/concerns/can_lookup_examples'
|
||||||
|
|
||||||
RSpec.describe User do
|
RSpec.describe User do
|
||||||
let(:subject) { create(:user, user_attrs || {}) }
|
include_examples 'HasGroups', group_access_factory: :agent_user
|
||||||
let(:group_access_instance) { create(:agent_user) }
|
include_examples 'HasRoles', group_access_factory: :agent_user
|
||||||
let(:new_group_access_instance) { build(:agent_user) }
|
include_examples 'HasGroups and Permissions', group_access_no_permission_factory: :user
|
||||||
let(:group_access_no_permission_instance) { build(:user) }
|
|
||||||
|
|
||||||
include_examples 'HasGroups'
|
|
||||||
include_examples 'HasRoles'
|
|
||||||
include_examples 'HasGroups and Permissions'
|
|
||||||
include_examples 'CanLookup'
|
include_examples 'CanLookup'
|
||||||
|
|
||||||
let(:new_password) { 'N3W54V3PW!' }
|
subject(:user) { create(:user) }
|
||||||
|
|
||||||
context 'password' do
|
describe 'attributes' do
|
||||||
|
describe '#login_failed' do
|
||||||
|
before { user.update(login_failed: 1) }
|
||||||
|
|
||||||
it 'resets login_failed on password change' do
|
it 'resets failed login count when password is changed' do
|
||||||
|
expect { user.update(password: Faker::Internet.password) }
|
||||||
failed_logins = (Setting.get('password_max_login_failed').to_i || 10) + 1
|
.to change { user.login_failed }.to(0)
|
||||||
user = create(:user, login_failed: failed_logins)
|
|
||||||
|
|
||||||
expect do
|
|
||||||
user.password = new_password
|
|
||||||
user.save
|
|
||||||
end.to change { user.login_failed }.to(0)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#out_of_office_agent' do
|
describe '#password' do
|
||||||
|
context 'when set to plaintext password' do
|
||||||
|
it 'hashes password before saving to DB' do
|
||||||
|
user.password = 'password'
|
||||||
|
|
||||||
it 'responds to out_of_office_agent' do
|
expect { user.save }
|
||||||
user = create(:user)
|
.to change { user.password }.to(PasswordHash.crypt('password'))
|
||||||
expect(user).to respond_to(:out_of_office_agent)
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'replacement' do
|
context 'when set to SHA2 digest (to facilitate OTRS imports)' do
|
||||||
|
it 'does not re-hash before saving' do
|
||||||
|
user.password = "{sha2}#{Digest::SHA2.hexdigest('password')}"
|
||||||
|
|
||||||
it 'finds assigned' do
|
expect { user.save }.not_to change { user.password }
|
||||||
user_replacement = create(:user)
|
end
|
||||||
|
end
|
||||||
|
|
||||||
user_ooo = create(:user,
|
context 'when set to Argon2 digest' do
|
||||||
|
it 'does not re-hash before saving' do
|
||||||
|
user.password = PasswordHash.crypt('password')
|
||||||
|
|
||||||
|
expect { user.save }.not_to change { user.password }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#phone' do
|
||||||
|
subject(:user) { create(:user, phone: orig_number) }
|
||||||
|
|
||||||
|
context 'when included on create' do
|
||||||
|
let(:orig_number) { '1234567890' }
|
||||||
|
|
||||||
|
it 'adds corresponding CallerId record' do
|
||||||
|
expect { user }
|
||||||
|
.to change { Cti::CallerId.where(caller_id: orig_number).count }.by(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when added on update' do
|
||||||
|
let(:orig_number) { nil }
|
||||||
|
let(:new_number) { '1234567890' }
|
||||||
|
|
||||||
|
before { user } # create user
|
||||||
|
|
||||||
|
it 'adds corresponding CallerId record' do
|
||||||
|
expect { user.update(phone: new_number) }
|
||||||
|
.to change { Cti::CallerId.where(caller_id: new_number).count }.by(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when falsely added on update (change: [nil, ""])' do
|
||||||
|
let(:orig_number) { nil }
|
||||||
|
let(:new_number) { '' }
|
||||||
|
|
||||||
|
before { user } # create user
|
||||||
|
|
||||||
|
it 'does not attempt to update CallerId record' do
|
||||||
|
allow(Cti::CallerId).to receive(:build).with(any_args)
|
||||||
|
|
||||||
|
expect(Cti::CallerId.where(object: 'User', o_id: user.id).count)
|
||||||
|
.to eq(0)
|
||||||
|
|
||||||
|
expect { user.update(phone: new_number) }
|
||||||
|
.to change { Cti::CallerId.where(object: 'User', o_id: user.id).count }.by(0)
|
||||||
|
|
||||||
|
expect(Cti::CallerId).not_to have_received(:build)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when removed on update' do
|
||||||
|
let(:orig_number) { '1234567890' }
|
||||||
|
let(:new_number) { nil }
|
||||||
|
|
||||||
|
before { user } # create user
|
||||||
|
|
||||||
|
it 'removes corresponding CallerId record' do
|
||||||
|
expect { user.update(phone: nil) }
|
||||||
|
.to change { Cti::CallerId.where(caller_id: orig_number).count }.by(-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when changed on update' do
|
||||||
|
let(:orig_number) { '1234567890' }
|
||||||
|
let(:new_number) { orig_number.next }
|
||||||
|
|
||||||
|
before { user } # create user
|
||||||
|
|
||||||
|
it 'replaces CallerId record' do
|
||||||
|
# rubocop:disable Layout/MultilineMethodCallIndentation
|
||||||
|
expect { user.update(phone: new_number) }
|
||||||
|
.to change { Cti::CallerId.where(caller_id: orig_number).count }.by(-1)
|
||||||
|
.and change { Cti::CallerId.where(caller_id: new_number).count }.by(1)
|
||||||
|
# rubocop:enable Layout/MultilineMethodCallIndentation
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#max_login_failed?' do
|
||||||
|
it { is_expected.to respond_to(:max_login_failed?) }
|
||||||
|
|
||||||
|
context 'with password_max_login_failed setting' do
|
||||||
|
before { Setting.set('password_max_login_failed', 5) }
|
||||||
|
before { user.update(login_failed: 5) }
|
||||||
|
|
||||||
|
it 'returns true once user’s #login_failed count exceeds the setting' do
|
||||||
|
expect { user.update(login_failed: 6) }
|
||||||
|
.to change { user.max_login_failed? }.to(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without password_max_login_failed setting' do
|
||||||
|
before { Setting.set('password_max_login_failed', nil) }
|
||||||
|
before { user.update(login_failed: 0) }
|
||||||
|
|
||||||
|
it 'defaults to 0' do
|
||||||
|
expect { user.update(login_failed: 1) }
|
||||||
|
.to change { user.max_login_failed? }.to(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#out_of_office_agent' do
|
||||||
|
it { is_expected.to respond_to(:out_of_office_agent) }
|
||||||
|
|
||||||
|
context 'when user has no designated substitute' do
|
||||||
|
it 'returns nil' do
|
||||||
|
expect(user.out_of_office_agent).to be(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when user has designated substitute, and is out of office' do
|
||||||
|
let(:substitute) { create(:user) }
|
||||||
|
subject(:user) do
|
||||||
|
create(:user,
|
||||||
out_of_office: true,
|
out_of_office: true,
|
||||||
out_of_office_start_at: Time.zone.yesterday,
|
out_of_office_start_at: Time.zone.yesterday,
|
||||||
out_of_office_end_at: Time.zone.tomorrow,
|
out_of_office_end_at: Time.zone.tomorrow,
|
||||||
out_of_office_replacement_id: user_replacement.id,)
|
out_of_office_replacement_id: substitute.id,)
|
||||||
|
|
||||||
expect(user_ooo.out_of_office_agent).to eq user_replacement
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'finds none for available users' do
|
it 'returns the designated substitute' do
|
||||||
user = create(:user)
|
expect(user.out_of_office_agent).to eq(substitute)
|
||||||
expect(user.out_of_office_agent).to be nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#max_login_failed?' do
|
describe '.authenticate' do
|
||||||
|
subject(:user) { create(:user, password: password) }
|
||||||
|
let(:password) { Faker::Internet.password }
|
||||||
|
|
||||||
it 'responds to max_login_failed?' do
|
context 'with valid credentials' do
|
||||||
user = create(:user)
|
it 'returns the matching user' do
|
||||||
expect(user).to respond_to(:max_login_failed?)
|
expect(described_class.authenticate(user.login, password))
|
||||||
end
|
.to eq(user)
|
||||||
|
|
||||||
it 'checks if a user has reached the maximum of failed logins' do
|
|
||||||
|
|
||||||
user = create(:user)
|
|
||||||
expect(user.max_login_failed?).to be false
|
|
||||||
|
|
||||||
user.login_failed = 999
|
|
||||||
user.save
|
|
||||||
expect(user.max_login_failed?).to be true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '.identify' do
|
context 'with valid credentials, but exceeding failed login limit' do
|
||||||
|
before { user.update(login_failed: 999) }
|
||||||
|
|
||||||
it 'returns users found by login' do
|
it 'returns nil' do
|
||||||
user = create(:user)
|
expect(described_class.authenticate(user.login, password))
|
||||||
found_user = User.identify(user.login)
|
.to be(nil)
|
||||||
expect(found_user).to be_an(User)
|
|
||||||
expect(found_user.id).to eq user.id
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns users found by email' do
|
|
||||||
user = create(:user)
|
|
||||||
found_user = User.identify(user.email)
|
|
||||||
expect(found_user).to be_an(User)
|
|
||||||
expect(found_user.id).to eq user.id
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '.authenticate' do
|
context 'with valid user and invalid password' do
|
||||||
|
it 'increments failed login count' do
|
||||||
it 'authenticates by username and password' do
|
expect { described_class.authenticate(user.login, password.next) }
|
||||||
password = 'zammad'
|
.to change { user.reload.login_failed }.by(1)
|
||||||
user = create(:user, password: password)
|
|
||||||
result = described_class.authenticate(user.login, password)
|
|
||||||
expect(result).to be_an(User)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'failure' do
|
it 'returns nil' do
|
||||||
|
expect(described_class.authenticate(user.login, password.next)).to be(nil)
|
||||||
it 'increases login_failed on failed logins' do
|
|
||||||
user = create(:user)
|
|
||||||
expect do
|
|
||||||
described_class.authenticate(user.login, 'wrongpw')
|
|
||||||
user.reload
|
|
||||||
end
|
end
|
||||||
.to change { user.login_failed }.by(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'fails for unknown users' do
|
context 'with inactive user’s login' do
|
||||||
result = described_class.authenticate('john.doe', 'zammad')
|
before { user.update(active: false) }
|
||||||
expect(result).to be nil
|
|
||||||
|
it 'returns nil' do
|
||||||
|
expect(described_class.authenticate(user.login, password)).to be(nil)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'fails for inactive users' do
|
context 'with non-existent user login' do
|
||||||
user = create(:user, active: false)
|
it 'returns nil' do
|
||||||
result = described_class.authenticate(user.login, 'zammad')
|
expect(described_class.authenticate('john.doe', password)).to be(nil)
|
||||||
expect(result).to be nil
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'fails for users with too many failed logins' do
|
context 'with empty login string' do
|
||||||
user = create(:user, login_failed: 999)
|
it 'returns nil' do
|
||||||
result = described_class.authenticate(user.login, 'zammad')
|
expect(described_class.authenticate('', password)).to be(nil)
|
||||||
expect(result).to be nil
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'fails for wrong passwords' do
|
context 'with empty password string' do
|
||||||
user = create(:user)
|
it 'returns nil' do
|
||||||
result = described_class.authenticate(user.login, 'wrongpw')
|
expect(described_class.authenticate(user.login, '')).to be(nil)
|
||||||
expect(result).to be nil
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'fails for empty username parameter' do
|
|
||||||
result = described_class.authenticate('', 'zammad')
|
|
||||||
expect(result).to be nil
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'fails for empty password parameter' do
|
|
||||||
result = described_class.authenticate('username', '')
|
|
||||||
expect(result).to be nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#by_reset_token' do
|
describe '#by_reset_token' do
|
||||||
|
let(:token) { create(:token_password_reset) }
|
||||||
|
subject(:user) { token.user }
|
||||||
|
|
||||||
it 'returns a User instance for existing tokens' do
|
context 'with a valid token' do
|
||||||
token = create(:token_password_reset)
|
it 'returns the matching user' do
|
||||||
expect(described_class.by_reset_token(token.name)).to be_instance_of(described_class)
|
expect(described_class.by_reset_token(token.name)).to eq(user)
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns nil for not existing tokens' do
|
|
||||||
expect(described_class.by_reset_token('not-existing')).to be nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#password_reset_via_token' do
|
context 'with an invalid token' do
|
||||||
|
it 'returns nil' do
|
||||||
|
expect(described_class.by_reset_token('not-existing')).to be(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#password_reset_via_token' do
|
||||||
|
let!(:token) { create(:token_password_reset) }
|
||||||
|
subject(:user) { token.user }
|
||||||
|
|
||||||
it 'changes the password of the token user and destroys the token' do
|
it 'changes the password of the token user and destroys the token' do
|
||||||
token = create(:token_password_reset)
|
expect { described_class.password_reset_via_token(token.name, Faker::Internet.password) }
|
||||||
user = User.find(token.user_id)
|
.to change { user.reload.password }
|
||||||
|
.and change { Token.count }.by(-1)
|
||||||
expect do
|
|
||||||
described_class.password_reset_via_token(token.name, new_password)
|
|
||||||
user.reload
|
|
||||||
end.to change {
|
|
||||||
user.password
|
|
||||||
}.and change {
|
|
||||||
Token.count
|
|
||||||
}.by(-1)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'import' do
|
describe '.identify' do
|
||||||
|
it 'returns users by given login' do
|
||||||
|
expect(User.identify(user.login)).to eq(user)
|
||||||
|
end
|
||||||
|
|
||||||
it "doesn't change imported passwords" do
|
it 'returns users by given email' do
|
||||||
|
expect(User.identify(user.email)).to eq(user)
|
||||||
# mock settings calls
|
|
||||||
expect(Setting).to receive(:get).with('import_mode').and_return(true)
|
|
||||||
allow(Setting).to receive(:get)
|
|
||||||
|
|
||||||
user = build(:user, password: '{sha2}dd9c764fa7ea18cd992c8600006d3dc3ac983d1ba22e9ba2d71f6207456be0ba') # zammad
|
|
||||||
expect do
|
|
||||||
user.save
|
|
||||||
end.to_not change {
|
|
||||||
user.password
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '.access?' do
|
describe '#access?' do
|
||||||
|
|
||||||
let(:role_with_admin_user_permissions) do
|
let(:role_with_admin_user_permissions) do
|
||||||
create(:role).tap do |role|
|
create(:role).tap do |role|
|
||||||
|
@ -533,7 +604,7 @@ RSpec.describe User do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'agent limit' do
|
describe 'system-wide agent limit' do
|
||||||
|
|
||||||
def current_agent_count
|
def current_agent_count
|
||||||
User.with_permissions('ticket.agent').count
|
User.with_permissions('ticket.agent').count
|
||||||
|
@ -542,92 +613,52 @@ RSpec.describe User do
|
||||||
let(:agent_role) { Role.lookup(name: 'Agent') }
|
let(:agent_role) { Role.lookup(name: 'Agent') }
|
||||||
let(:admin_role) { Role.lookup(name: 'Admin') }
|
let(:admin_role) { Role.lookup(name: 'Admin') }
|
||||||
|
|
||||||
context '#validate_agent_limit_by_role' do
|
describe '#validate_agent_limit_by_role' do
|
||||||
|
context 'for Integer value of system_agent_limit' do
|
||||||
context 'agent creation limit not reached' do
|
context 'before exceeding the agent limit' do
|
||||||
|
before { Setting.set('system_agent_limit', current_agent_count + 1) }
|
||||||
|
|
||||||
it 'grants agent creation' do
|
it 'grants agent creation' do
|
||||||
Setting.set('system_agent_limit', current_agent_count + 1)
|
expect { create(:agent_user) }
|
||||||
|
.to change { current_agent_count }.by(1)
|
||||||
expect do
|
|
||||||
create(:agent_user)
|
|
||||||
end.to change {
|
|
||||||
current_agent_count
|
|
||||||
}.by(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'grants role change' do
|
it 'grants role change' do
|
||||||
Setting.set('system_agent_limit', current_agent_count + 1)
|
|
||||||
|
|
||||||
future_agent = create(:customer_user)
|
future_agent = create(:customer_user)
|
||||||
|
|
||||||
expect do
|
expect { future_agent.roles = [agent_role] }
|
||||||
future_agent.roles = [agent_role]
|
.to change { current_agent_count }.by(1)
|
||||||
end.to change {
|
|
||||||
current_agent_count
|
|
||||||
}.by(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'role updates' do
|
describe 'role updates' do
|
||||||
|
let(:agent) { create(:agent_user) }
|
||||||
|
|
||||||
it 'grants update by instances' do
|
it 'grants update by instances' do
|
||||||
Setting.set('system_agent_limit', current_agent_count + 1)
|
expect { agent.roles = [admin_role, agent_role] }
|
||||||
|
.not_to raise_error
|
||||||
agent = create(:agent_user)
|
|
||||||
|
|
||||||
expect do
|
|
||||||
agent.roles = [
|
|
||||||
admin_role,
|
|
||||||
agent_role
|
|
||||||
]
|
|
||||||
agent.save!
|
|
||||||
end.not_to raise_error
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'grants update by id (Integer)' do
|
it 'grants update by id (Integer)' do
|
||||||
Setting.set('system_agent_limit', current_agent_count + 1)
|
expect { agent.role_ids = [admin_role.id, agent_role.id] }
|
||||||
|
.not_to raise_error
|
||||||
agent = create(:agent_user)
|
|
||||||
|
|
||||||
expect do
|
|
||||||
agent.role_ids = [
|
|
||||||
admin_role.id,
|
|
||||||
agent_role.id
|
|
||||||
]
|
|
||||||
agent.save!
|
|
||||||
end.not_to raise_error
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'grants update by id (String)' do
|
it 'grants update by id (String)' do
|
||||||
Setting.set('system_agent_limit', current_agent_count + 1)
|
expect { agent.role_ids = [admin_role.id.to_s, agent_role.id.to_s] }
|
||||||
|
.not_to raise_error
|
||||||
agent = create(:agent_user)
|
|
||||||
|
|
||||||
expect do
|
|
||||||
agent.role_ids = [
|
|
||||||
admin_role.id.to_s,
|
|
||||||
agent_role.id.to_s
|
|
||||||
]
|
|
||||||
agent.save!
|
|
||||||
end.not_to raise_error
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'agent creation limit surpassing prevention' do
|
context 'when exceeding the agent limit' do
|
||||||
|
|
||||||
it 'creation of new agents' do
|
it 'creation of new agents' do
|
||||||
Setting.set('system_agent_limit', current_agent_count + 2)
|
Setting.set('system_agent_limit', current_agent_count + 2)
|
||||||
|
|
||||||
create_list(:agent_user, 2)
|
create_list(:agent_user, 2)
|
||||||
|
|
||||||
initial_agent_count = current_agent_count
|
expect { create(:agent_user) }
|
||||||
|
.to raise_error(Exceptions::UnprocessableEntity)
|
||||||
expect do
|
.and change { current_agent_count }.by(0)
|
||||||
create(:agent_user)
|
|
||||||
end.to raise_error(Exceptions::UnprocessableEntity)
|
|
||||||
|
|
||||||
expect(current_agent_count).to eq(initial_agent_count)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'prevents role change' do
|
it 'prevents role change' do
|
||||||
|
@ -635,123 +666,58 @@ RSpec.describe User do
|
||||||
|
|
||||||
future_agent = create(:customer_user)
|
future_agent = create(:customer_user)
|
||||||
|
|
||||||
initial_agent_count = current_agent_count
|
expect { future_agent.roles = [agent_role] }
|
||||||
|
.to raise_error(Exceptions::UnprocessableEntity)
|
||||||
expect do
|
.and change { current_agent_count }.by(0)
|
||||||
future_agent.roles = [agent_role]
|
|
||||||
end.to raise_error(Exceptions::UnprocessableEntity)
|
|
||||||
|
|
||||||
expect(current_agent_count).to eq(initial_agent_count)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#validate_agent_limit_by_attributes' do
|
context 'for String value of system_agent_limit' do
|
||||||
|
context 'before exceeding the agent limit' do
|
||||||
context 'agent creation limit surpassing prevention' do
|
before { Setting.set('system_agent_limit', (current_agent_count + 1).to_s) }
|
||||||
|
|
||||||
it 'prevents re-activation of agents' do
|
|
||||||
Setting.set('system_agent_limit', current_agent_count)
|
|
||||||
|
|
||||||
inactive_agent = create(:agent_user, active: false)
|
|
||||||
|
|
||||||
initial_agent_count = current_agent_count
|
|
||||||
|
|
||||||
expect do
|
|
||||||
inactive_agent.update!(active: true)
|
|
||||||
end.to raise_error(Exceptions::UnprocessableEntity)
|
|
||||||
|
|
||||||
expect(current_agent_count).to eq(initial_agent_count)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '#validate_agent_limit_by_role by string' do
|
|
||||||
|
|
||||||
context 'agent creation limit not reached' do
|
|
||||||
|
|
||||||
it 'grants agent creation' do
|
it 'grants agent creation' do
|
||||||
Setting.set('system_agent_limit', (current_agent_count + 1).to_s)
|
expect { create(:agent_user) }
|
||||||
|
.to change { current_agent_count }.by(1)
|
||||||
expect do
|
|
||||||
create(:agent_user)
|
|
||||||
end.to change {
|
|
||||||
current_agent_count
|
|
||||||
}.by(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'grants role change' do
|
it 'grants role change' do
|
||||||
Setting.set('system_agent_limit', (current_agent_count + 1).to_s)
|
|
||||||
|
|
||||||
future_agent = create(:customer_user)
|
future_agent = create(:customer_user)
|
||||||
|
|
||||||
expect do
|
expect { future_agent.roles = [agent_role] }
|
||||||
future_agent.roles = [agent_role]
|
.to change { current_agent_count }.by(1)
|
||||||
end.to change {
|
|
||||||
current_agent_count
|
|
||||||
}.by(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'role updates' do
|
describe 'role updates' do
|
||||||
|
let(:agent) { create(:agent_user) }
|
||||||
|
|
||||||
it 'grants update by instances' do
|
it 'grants update by instances' do
|
||||||
Setting.set('system_agent_limit', (current_agent_count + 1).to_s)
|
expect { agent.roles = [admin_role, agent_role] }
|
||||||
|
.not_to raise_error
|
||||||
agent = create(:agent_user)
|
|
||||||
|
|
||||||
expect do
|
|
||||||
agent.roles = [
|
|
||||||
admin_role,
|
|
||||||
agent_role
|
|
||||||
]
|
|
||||||
agent.save!
|
|
||||||
end.not_to raise_error
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'grants update by id (Integer)' do
|
it 'grants update by id (Integer)' do
|
||||||
Setting.set('system_agent_limit', (current_agent_count + 1).to_s)
|
expect { agent.role_ids = [admin_role.id, agent_role.id] }
|
||||||
|
.not_to raise_error
|
||||||
agent = create(:agent_user)
|
|
||||||
|
|
||||||
expect do
|
|
||||||
agent.role_ids = [
|
|
||||||
admin_role.id,
|
|
||||||
agent_role.id
|
|
||||||
]
|
|
||||||
agent.save!
|
|
||||||
end.not_to raise_error
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'grants update by id (String)' do
|
it 'grants update by id (String)' do
|
||||||
Setting.set('system_agent_limit', (current_agent_count + 1).to_s)
|
expect { agent.role_ids = [admin_role.id.to_s, agent_role.id.to_s] }
|
||||||
|
.not_to raise_error
|
||||||
agent = create(:agent_user)
|
|
||||||
|
|
||||||
expect do
|
|
||||||
agent.role_ids = [
|
|
||||||
admin_role.id.to_s,
|
|
||||||
agent_role.id.to_s
|
|
||||||
]
|
|
||||||
agent.save!
|
|
||||||
end.not_to raise_error
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'agent creation limit surpassing prevention' do
|
context 'when exceeding the agent limit' do
|
||||||
|
|
||||||
it 'creation of new agents' do
|
it 'creation of new agents' do
|
||||||
Setting.set('system_agent_limit', (current_agent_count + 2).to_s)
|
Setting.set('system_agent_limit', (current_agent_count + 2).to_s)
|
||||||
|
|
||||||
create_list(:agent_user, 2)
|
create_list(:agent_user, 2)
|
||||||
|
|
||||||
initial_agent_count = current_agent_count
|
expect { create(:agent_user) }
|
||||||
|
.to raise_error(Exceptions::UnprocessableEntity)
|
||||||
expect do
|
.and change { current_agent_count }.by(0)
|
||||||
create(:agent_user)
|
|
||||||
end.to raise_error(Exceptions::UnprocessableEntity)
|
|
||||||
|
|
||||||
expect(current_agent_count).to eq(initial_agent_count)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'prevents role change' do
|
it 'prevents role change' do
|
||||||
|
@ -759,106 +725,41 @@ RSpec.describe User do
|
||||||
|
|
||||||
future_agent = create(:customer_user)
|
future_agent = create(:customer_user)
|
||||||
|
|
||||||
initial_agent_count = current_agent_count
|
expect { future_agent.roles = [agent_role] }
|
||||||
|
.to raise_error(Exceptions::UnprocessableEntity)
|
||||||
expect do
|
.and change { current_agent_count }.by(0)
|
||||||
future_agent.roles = [agent_role]
|
end
|
||||||
end.to raise_error(Exceptions::UnprocessableEntity)
|
|
||||||
|
|
||||||
expect(current_agent_count).to eq(initial_agent_count)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '#validate_agent_limit_by_attributes' do
|
describe '#validate_agent_limit_by_attributes' do
|
||||||
|
context 'for Integer value of system_agent_limit' do
|
||||||
context 'agent creation limit surpassing prevention' do
|
before { Setting.set('system_agent_limit', current_agent_count) }
|
||||||
|
|
||||||
|
context 'when exceeding the agent limit' do
|
||||||
it 'prevents re-activation of agents' do
|
it 'prevents re-activation of agents' do
|
||||||
Setting.set('system_agent_limit', current_agent_count.to_s)
|
|
||||||
|
|
||||||
inactive_agent = create(:agent_user, active: false)
|
inactive_agent = create(:agent_user, active: false)
|
||||||
|
|
||||||
initial_agent_count = current_agent_count
|
expect { inactive_agent.update!(active: true) }
|
||||||
|
.to raise_error(Exceptions::UnprocessableEntity)
|
||||||
expect do
|
.and change { current_agent_count }.by(0)
|
||||||
inactive_agent.update!(active: true)
|
|
||||||
end.to raise_error(Exceptions::UnprocessableEntity)
|
|
||||||
|
|
||||||
expect(current_agent_count).to eq(initial_agent_count)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
context 'for String value of system_agent_limit' do
|
||||||
|
before { Setting.set('system_agent_limit', current_agent_count.to_s) }
|
||||||
|
|
||||||
context 'when phone attribute' do
|
context 'when exceeding the agent limit' do
|
||||||
let(:user_attrs) { { phone: orig_number } }
|
it 'prevents re-activation of agents' do
|
||||||
|
inactive_agent = create(:agent_user, active: false)
|
||||||
|
|
||||||
context 'included on create' do
|
expect { inactive_agent.update!(active: true) }
|
||||||
let(:orig_number) { '1234567890' }
|
.to raise_error(Exceptions::UnprocessableEntity)
|
||||||
|
.and change { current_agent_count }.by(0)
|
||||||
it 'adds corresponding CallerId record' do
|
|
||||||
expect { subject }
|
|
||||||
.to change { Cti::CallerId.where(caller_id: orig_number).count }.by(1)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'added on update' do
|
|
||||||
let(:orig_number) { nil }
|
|
||||||
let(:new_number) { '1234567890' }
|
|
||||||
|
|
||||||
before { subject } # create user
|
|
||||||
|
|
||||||
it 'adds corresponding CallerId record' do
|
|
||||||
expect { subject.update(phone: new_number) }
|
|
||||||
.to change { Cti::CallerId.where(caller_id: new_number).count }.by(1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'falsely added on update (change: [nil, ""])' do
|
|
||||||
let(:orig_number) { nil }
|
|
||||||
let(:new_number) { '' }
|
|
||||||
|
|
||||||
before { subject } # create user
|
|
||||||
|
|
||||||
it 'does not attempt to update CallerId record' do
|
|
||||||
allow(Cti::CallerId).to receive(:build).with(any_args)
|
|
||||||
|
|
||||||
expect(Cti::CallerId.where(object: 'User', o_id: subject.id).count)
|
|
||||||
.to eq(0)
|
|
||||||
|
|
||||||
expect { subject.update(phone: new_number) }
|
|
||||||
.to change { Cti::CallerId.where(object: 'User', o_id: subject.id).count }.by(0)
|
|
||||||
|
|
||||||
expect(Cti::CallerId).not_to have_received(:build)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'removed on update' do
|
|
||||||
let(:orig_number) { '1234567890' }
|
|
||||||
let(:new_number) { nil }
|
|
||||||
|
|
||||||
before { subject } # create user
|
|
||||||
|
|
||||||
it 'removes corresponding CallerId record' do
|
|
||||||
expect { subject.update(phone: nil) }
|
|
||||||
.to change { Cti::CallerId.where(caller_id: orig_number).count }.by(-1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'changed on update' do
|
|
||||||
let(:orig_number) { '1234567890' }
|
|
||||||
let(:new_number) { orig_number.next }
|
|
||||||
|
|
||||||
before { subject } # create user
|
|
||||||
|
|
||||||
it 'replaces CallerId record' do
|
|
||||||
# rubocop:disable Layout/MultilineMethodCallIndentation
|
|
||||||
expect { subject.update(phone: new_number) }
|
|
||||||
.to change { Cti::CallerId.where(caller_id: orig_number).count }.by(-1)
|
|
||||||
.and change { Cti::CallerId.where(caller_id: new_number).count }.by(1)
|
|
||||||
# rubocop:enable Layout/MultilineMethodCallIndentation
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue