houdini/spec/lib/insert/insert_custom_field_joins_spec.rb

287 lines
14 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
2020-06-12 20:03:43 +00:00
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
require 'rails_helper'
describe InsertCustomFieldJoins do
describe '.find_or_create' do
let(:nonprofit) { force_create(:nm_justice) }
let(:other_nonprofit) { force_create(:fv_poverty) }
let(:supporter) { force_create(:supporter, nonprofit: nonprofit) }
let(:other_supporter) { force_create(:supporter, nonprofit: other_nonprofit) }
let(:initial_custom_field_master) { force_create(:custom_field_master, nonprofit: nonprofit, name: 'CFM Name') }
describe 'param validation' do
it 'basic validation' do
expect { InsertCustomFieldJoins.find_or_create(nil, nil, nil) }.to(raise_error do |error|
expect(error).to be_a ParamValidation::ValidationError
expect_validation_errors(error.data, [
{ key: :np_id, name: :required },
{ key: :np_id, name: :is_integer },
{ key: :supporter_ids, name: :required },
{ key: :supporter_ids, name: :is_array },
{ key: :supporter_ids, name: :min_length },
{ key: :field_data, name: :required },
{ key: :field_data, name: :is_array },
{ key: :field_data, name: :min_length }
])
end)
end
it 'validate nonprofit existence' do
expect { InsertCustomFieldJoins.find_or_create(5, [555], [[1, 1]]) }.to(raise_error do |error|
expect(error).to be_a ParamValidation::ValidationError
expect_validation_errors(error.data, [
{ key: :np_id }
])
expect(error.message).to eq '5 is not a valid non-profit'
end)
end
it 'validate supporter in nonprofit' do
expect { InsertCustomFieldJoins.find_or_create(nonprofit.id, [other_supporter.id], [[1, 1]]) }.to(raise_error do |error|
expect(error).to be_a ParamValidation::ValidationError
expect_validation_errors(error.data, [
{ key: :supporter_ids }
])
expect(error.message).to eq "#{other_supporter.id} is not a valid supporter for nonprofit #{nonprofit.id}"
end)
end
end
it 'run insert' do
new_cf_name = 'new cf name'
new_cf_value = 'value'
old_cf_value = 'old_cf_value'
expect(InsertCustomFieldJoins).to receive(:in_bulk) do |np_id, supporters_id, field_data|
expect(np_id).to eq nonprofit.id
expect(supporters_id).to eq [supporter.id]
expect(field_data.length).to eq 2
expect(field_data).to include(custom_field_master_id: initial_custom_field_master.id, value: old_cf_value)
expect(field_data).to include(custom_field_master_id: CustomFieldMaster.where(name: new_cf_name).first.id, value: new_cf_value)
end
result = InsertCustomFieldJoins.find_or_create(nonprofit.id, [supporter.id], [
[
initial_custom_field_master.name,
old_cf_value
],
[
new_cf_name,
new_cf_value
]
])
expect(CustomFieldMaster.count).to eq 2
end
end
describe '.in_bulk' do
context 'parameter validation' do
it 'should validate parameters' do
response = InsertCustomFieldJoins.in_bulk(nil, nil, nil)
errors = response[:json][:errors]
expect(errors.length).to eq(6)
expect(response[:status]).to eq :unprocessable_entity
expect_validation_errors(errors, [
{ key: :np_id, name: :required },
{ key: :np_id, name: :is_integer },
{ key: :supporter_ids, name: :required },
{ key: :supporter_ids, name: :is_array },
{ key: :field_data, name: :is_array },
{ key: :field_data, name: :required }
])
end
context 'requiring db' do
before(:each) do
@nonprofit = force_create(:nm_justice)
@bad_nonprofit = force_create(:fv_poverty, id: 50)
end
it 'nonprofit must be valid' do
response = InsertCustomFieldJoins.in_bulk(@nonprofit.id + 1, [], [])
expect(response[:status]).to eq :unprocessable_entity
expect(response[:json][:error]).to include("Nonprofit #{@nonprofit.id + 1} is not valid")
end
it 'supporters if empty should do nothing' do
response = InsertCustomFieldJoins.in_bulk(@nonprofit.id, [], [])
expect(response).to eq(successful_json(0, 0))
end
it 'supporters if empty should do nothing' do
response = InsertCustomFieldJoins.in_bulk(@nonprofit.id, [50], [])
expect(response).to eq(successful_json(0, 0))
end
end
end
context 'main testing' do
before(:each) do
@nonprofit = force_create(:nm_justice)
@other_nonprofit = force_create(:fv_poverty)
@random_supporter = create(:supporter, nonprofit: @other_nonprofit)
@delete_cfm = [20, 40, 60]
@add_cfm = [25, 35]
@supporters = {
np_supporter_with_add: {
cfm_ids: [65, 75, 85]
},
np_supporter_with_cfms_to_delete: {
cfm_ids: [40, 75, 85]
},
np_supporter_with_no_changes: {
cfm_ids: @add_cfm
},
np_supporter_with_some_of_both: {
cfm_ids: [20, 35]
},
supporter_from_other_np: {
cfm_ids: [100, 150, 200],
other_np: true
}
}
@supporters.each_key do |k|
i = @supporters[k]
nonprofit_for_supporter = i[:other_np] ? @other_nonprofit : @nonprofit
i[:entity] = create(:supporter, nonprofit: nonprofit_for_supporter)
i[:cfm_ids].each do |j|
cfm = CustomFieldMaster.exists?(id: j) ? CustomFieldMaster.find(j) : create(:custom_field_master, id: j, nonprofit: nonprofit_for_supporter, name: "CFM #{j}")
create(:custom_field_join, :value_from_id, supporter_id: i[:entity].id, custom_field_master: cfm)
end
end
end
it 'invalid nonprofit-supporter combo returns okay' do
results = InsertCustomFieldJoins.in_bulk(@nonprofit.id, [@supporters[:supporter_from_other_np][:entity].id], [])
expect(results).to eq(successful_json(0, 0))
end
it 'strips cfms which dont belong to nonprofit' do
results = InsertCustomFieldJoins.in_bulk(@nonprofit.id, [@supporters[:np_supporter_with_add][:entity].id],
create_cfm_data([100], [150]))
expect(results).to eq(successful_json(0, 0))
expect(CustomFieldJoin.where('supporter_id = ? and custom_field_master_id = ?', @supporters[:np_supporter_with_add][:entity].id, 100).count).to eq 0
end
it 'delete' do
expect(CustomFieldJoin.count).to eq 13
@supporters[:np_supporter_with_some_of_both][:entity].id
results = InsertCustomFieldJoins.in_bulk(@nonprofit.id,
[@supporters[:np_supporter_with_some_of_both][:entity].id, @supporters[:np_supporter_with_cfms_to_delete][:entity].id, @supporters[:np_supporter_with_add][:entity].id, @supporters[:supporter_from_other_np][:entity].id, @supporters[:np_supporter_with_no_changes][:entity].id],
create_cfm_data(@add_cfm, @delete_cfm))
expect(CustomFieldJoin.where('supporter_id = ? ', @supporters[:np_supporter_with_some_of_both][:entity].id).count).to eq 2
expect(CustomFieldJoin.where('supporter_id = ?', @supporters[:np_supporter_with_add][:entity].id).count).to eq 5
expect(CustomFieldJoin.where('supporter_id = ?', @supporters[:np_supporter_with_cfms_to_delete][:entity].id).count).to eq 4
expect(CustomFieldJoin.where('supporter_id = ?', @supporters[:supporter_from_other_np][:entity].id).count).to eq 3
expect(CustomFieldJoin.where('supporter_id = ?', @supporters[:np_supporter_with_no_changes][:entity].id).count).to eq 2
expect(CustomFieldJoin.count).to eq 16
end
it 'id, updated_at, created_at changes are stripped' do
invalid_id = 10_000_000
Timecop.freeze(2020, 9, 1, 12, 0, 0) do
results = InsertCustomFieldJoins.in_bulk(@nonprofit.id,
[@supporters[:np_supporter_with_add][:entity].id],
[{ custom_field_master_id: 25, value: 'CFM value 25', id: invalid_id, created_at: Time.now.ago(3000), updated_at: Time.now.ago(2999) }])
expected = { custom_field_master_id: 25, value: 'CFM value 25', created_at: Time.now, updated_at: Time.now, supporter_id: @supporters[:np_supporter_with_add][:entity].id }.with_indifferent_access
expect(results).to eq(successful_json(1, 0))
result_tag = @supporters[:np_supporter_with_add][:entity].custom_field_joins.where('custom_field_master_id = ?', 25).first
expect(result_tag.attributes.with_indifferent_access.reject { |k, _| k == 'id' }).to eq(expected)
expect(result_tag.attributes[:id]).to_not eq invalid_id
end
end
it 'add_to_one' do
expect(CustomFieldJoin.count).to eq 13
np_supporter_with_add_cfms = @supporters[:np_supporter_with_add][:entity].custom_field_joins.to_a
np_supporter_with_some_of_both_cfms = @supporters[:np_supporter_with_some_of_both][:entity].custom_field_joins.to_a
np_supporter_with_no_changes_cfms = @supporters[:np_supporter_with_no_changes][:entity].custom_field_joins.to_a
Timecop.travel(20) do
results = InsertCustomFieldJoins.in_bulk(@nonprofit.id,
[
@supporters[:np_supporter_with_add][:entity].id, # add 2
@supporters[:np_supporter_with_no_changes][:entity], # update 2
@supporters[:np_supporter_with_some_of_both][:entity].id
], # add 2, delete 1
create_cfm_data(@add_cfm, @delete_cfm))
expect(results).to eq(successful_json(6, 1))
expect(@supporters[:np_supporter_with_no_changes][:entity].custom_field_joins).to match_array(np_supporter_with_no_changes_cfms)
expect(CustomFieldJoin.where('supporter_id = ? ', @supporters[:np_supporter_with_add][:entity].id).count).to eq 5
original_db_pairs = get_original_and_db(np_supporter_with_add_cfms, CustomFieldJoin.where('supporter_id = ? and custom_field_master_id in (?)',
@supporters[:np_supporter_with_add][:entity].id,
@supporters[:np_supporter_with_add][:cfm_ids]).pluck(:id))
original_db_pairs.each do |orig, db|
expect(db.attributes.length).to eq(orig.attributes.length)
expect(db.attributes).to eq(orig.attributes)
end
expect(CustomFieldJoin.where('supporter_id = ?', @supporters[:np_supporter_with_some_of_both][:entity].id).count).to eq 2
original_db_pairs = get_original_and_db(np_supporter_with_some_of_both_cfms, CustomFieldJoin.where('supporter_id = ? and custom_field_master_id in (?)',
@supporters[:np_supporter_with_some_of_both][:entity].id,
[35]).pluck(:id))
skip_attribs = %w[updated_at value]
original_db_pairs.each do |orig, db|
expect(db.attributes.length).to eq(orig.attributes.length)
expect(db.attributes.reject { |key, _value| skip_attribs.include?(key) }).to eq(orig.attributes.reject { |key, _value| skip_attribs.include?(key) })
expect(db.attributes['updated_at']).to be > orig.attributes['updated_at']
expect(db.attributes['value']).to eq 'CFM value 35'
end
expect(CustomFieldJoin.count).to eq 15
end
end
end
end
def successful_json(inserted, deleted)
{ json: { inserted_count: inserted, removed_count: deleted }, status: :ok }
end
def create_cfm_data(cfm_to_add = [], cfm_to_delete = [])
use_nil = true
cfm_to_add.map { |cfm| { custom_field_master_id: cfm, value: "CFM value #{cfm}" } } + cfm_to_delete.map do |cfm|
value = use_nil ? nil : ''
use_nil = !use_nil
{ custom_field_master_id: cfm, value: value }
end
end
def get_original_and_db(original_items, ids_to_verify)
ids_to_verify.map do |i|
original_item = original_items.find { |oi| oi[:id] == i }
db_item = CustomFieldJoin.find(i)
[original_item, db_item]
end
end
end