From 4a1477b1ff402ec249d74d85ca0fa1ab444df0ec Mon Sep 17 00:00:00 2001 From: Ryan Lue Date: Fri, 28 Jun 2019 15:07:14 +0200 Subject: [PATCH] Refactoring: Migrate history_test to RSpec --- app/models/history.rb | 101 ++--- spec/models/concerns/has_history_examples.rb | 123 ++++++ spec/models/history_spec.rb | 184 ++++++++ spec/models/organization_spec.rb | 2 + spec/models/ticket/article_spec.rb | 2 + spec/models/ticket_spec.rb | 2 + spec/models/user_spec.rb | 2 + test/unit/history_test.rb | 432 ------------------- 8 files changed, 349 insertions(+), 499 deletions(-) create mode 100644 spec/models/concerns/has_history_examples.rb delete mode 100644 test/unit/history_test.rb diff --git a/app/models/history.rb b/app/models/history.rb index e6f96ba0c..2575ec568 100644 --- a/app/models/history.rb +++ b/app/models/history.rb @@ -149,73 +149,54 @@ returns =end def self.list(requested_object, requested_object_id, related_history_object = nil, assets = nil) - if related_history_object.blank? - history_object = object_lookup(requested_object) - history = History.where(history_object_id: history_object.id) - .where(o_id: requested_object_id) - .order(created_at: :asc) - else - history_object_requested = object_lookup(requested_object) - history_object_related = object_lookup(related_history_object) - history = History.where( - '((history_object_id = ? AND o_id = ?) OR (history_object_id = ? AND related_o_id = ? ))', - history_object_requested.id, - requested_object_id, - history_object_related.id, - requested_object_id, + histories = History.where( + history_object_id: object_lookup(requested_object).id, + o_id: requested_object_id + ) + + if related_history_object.present? + histories = histories.or( + History.where( + history_object_id: object_lookup(related_history_object).id, + related_o_id: requested_object_id + ) ) - .order(created_at: :asc) end - asset_list = {} - list = [] - history.each do |item| - if assets - asset_list = item.assets(asset_list) - end + histories = histories.order(:created_at) - data = item.attributes - data['object'] = object_lookup_id(data['history_object_id']).name - data['type'] = type_lookup_id(data['history_type_id']).name - data.delete('history_object_id') - data.delete('history_type_id') + list = histories.map(&:attributes).each do |data| + data['object'] = History::Object.lookup(id: data.delete('history_object_id'))&.name + data['type'] = History::Type.lookup(id: data.delete('history_type_id'))&.name if data['history_attribute_id'] - data['attribute'] = attribute_lookup_id(data['history_attribute_id']).name + data['attribute'] = History::Attribute.lookup(id: data.delete('history_attribute_id'))&.name + end + + if data['related_history_object_id'] + data['related_object'] = History::Object.lookup(id: data.delete('related_history_object_id'))&.name end - data.delete('history_attribute_id') data.delete('updated_at') + data.delete('related_o_id') if data['related_o_id'].nil? + if data['id_to'].nil? && data['id_from'].nil? - data.delete('id_to') data.delete('id_from') + data.delete('id_to') end + if data['value_to'].nil? && data['value_from'].nil? - data.delete('value_to') data.delete('value_from') + data.delete('value_to') end - if !data['related_history_object_id'].nil? - data['related_object'] = object_lookup_id(data['related_history_object_id']).name - end - data.delete('related_history_object_id') - - if data['related_o_id'].nil? - data.delete('related_o_id') - end - - list.push data end - if assets - return { - list: list, - assets: asset_list, - } - end - list - end - def self.type_lookup_id(id) - History::Type.lookup(id: id) + return list if !assets + + { + list: list, + assets: histories.reduce({}) { |memo, obj| obj.assets(memo) } + } end def self.type_lookup(name) @@ -227,10 +208,6 @@ returns History::Type.create!(name: name) end - def self.object_lookup_id(id) - History::Object.lookup(id: id) - end - def self.object_lookup(name) # lookup history_object = History::Object.lookup(name: name) @@ -240,10 +217,6 @@ returns History::Object.create!(name: name) end - def self.attribute_lookup_id(id) - History::Attribute.lookup(id: id) - end - def self.attribute_lookup(name) # lookup history_attribute = History::Attribute.lookup(name: name) @@ -253,13 +226,7 @@ returns History::Attribute.create!(name: name) end - class Object < ApplicationModel - end - - class Type < ApplicationModel - end - - class Attribute < ApplicationModel - end - + class Object < ApplicationModel; end + class Type < ApplicationModel; end + class Attribute < ApplicationModel; end end diff --git a/spec/models/concerns/has_history_examples.rb b/spec/models/concerns/has_history_examples.rb new file mode 100644 index 000000000..4e01283d5 --- /dev/null +++ b/spec/models/concerns/has_history_examples.rb @@ -0,0 +1,123 @@ +RSpec.shared_examples 'HasHistory' do |history_relation_object: nil| + describe 'auto-creation of history records' do + let(:histories) { History.where(history_object_id: History::Object.find_by(name: described_class.name)) } + + context 'on creation' do + it 'creates a History record for it' do + expect { subject }.to change(histories, :count).by(1) + expect(histories.last.history_type.name).to eq('created') + end + end + + context 'on update' do + let(:histories) do + History.where(history_object_id: History::Object.lookup(name: described_class.name).id, + history_type_id: History::Type.lookup(name: 'updated').id, + history_attribute_id: History::Attribute.find_or_create_by(name: attribute).id) + end + + let!(:old_value) { subject.send(attribute) } + + shared_examples 'attribute update' do + it 'creates a History record for it' do + expect { subject.update(attribute => new_value) }.to change(histories, :count).by(1) + expect(histories.last.attributes).to include(attributes) + end + end + + describe 'of #active' do + let(:attribute) { 'active' } + let(:new_value) { !subject.active } + let(:attributes) { { 'value_from' => old_value.to_s, 'value_to' => new_value.to_s } } + + include_examples 'attribute update' if described_class.attribute_names.include?('active') + end + + describe 'of #body' do + let(:attribute) { 'body' } + let(:new_value) { 'Lorem ipsum dolor' } + let(:attributes) { { 'value_from' => old_value, 'value_to' => new_value } } + + include_examples 'attribute update' if described_class.attribute_names.include?('body') + end + + describe 'of #email' do + let(:attribute) { 'email' } + let(:new_value) { Faker::Internet.email } + let(:attributes) { { 'value_from' => old_value, 'value_to' => new_value } } + + include_examples 'attribute update' if described_class.attribute_names.include?('email') + end + + describe 'of #lastname' do + let(:attribute) { 'lastname' } + let(:new_value) { 'Foo' } + let(:attributes) { { 'value_from' => old_value, 'value_to' => new_value } } + + include_examples 'attribute update' if described_class.attribute_names.include?('lastname') + end + + describe 'of #name' do + let(:attribute) { 'name' } + let(:new_value) { 'Foo' } + let(:attributes) { { 'value_from' => old_value, 'value_to' => new_value } } + + include_examples 'attribute update' if described_class.attribute_names.include?('name') + end + + describe 'of #state' do + let(:attribute) { 'state' } + let(:new_value) { state_class.where.not(id: old_value.id).first } + let(:state_class) { "#{described_class.name}::State".constantize } + let(:attributes) { { 'value_from' => old_value.name, 'value_to' => new_value.name } } + + include_examples 'attribute update' if described_class.attribute_names.include?('state_id') + end + + describe 'of #title' do + let(:attribute) { 'title' } + let(:new_value) { 'foo' } + let(:attributes) { { 'value_from' => old_value, 'value_to' => new_value } } + + include_examples 'attribute update' if described_class.attribute_names.include?('title') + end + + context 'when validations or callbacks prevent update' do + shared_examples 'failed attribute update' do + it 'does not create a History record for it' do + expect { subject.update(attribute => new_value) }.not_to change(histories, :count) + end + end + + describe 'of #owner' do + let(:attribute) { 'owner' } + let(:new_value) { create(:customer_user) } # Ticket#owner is restricted to active agents of the same group + + include_examples 'failed attribute update' if described_class.attribute_names.include?('owner_id') + end + end + end + end + + describe '#history_get' do + context 'without "full" flag' do + it 'delegates to History.list for self' do + expect(History).to receive(:list).with(described_class.name, subject.id, history_relation_object) + + subject.history_get + end + end + + context 'with "full" flag' do + it 'returns a hash including History.list for self' do + expect(subject.history_get(true)) + .to include(history: History.list(described_class.name, subject.id, history_relation_object)) + end + + it 'returns a hash including FE assets of self and related objects' do + expect(subject.history_get(true)) + .to include(assets: hash_including(subject.assets({}))) + end + end + end +end diff --git a/spec/models/history_spec.rb b/spec/models/history_spec.rb index 7cccb1010..8550666b9 100644 --- a/spec/models/history_spec.rb +++ b/spec/models/history_spec.rb @@ -5,4 +5,188 @@ require 'models/concerns/can_be_imported_examples' RSpec.describe History, type: :model do it_behaves_like 'ApplicationModel', can_assets: { own_attributes: false } it_behaves_like 'CanBeImported' + + describe '.list' do + context 'when given an object with no histories' do + let!(:object) { create(:'cti/log') } + + it 'returns an empty array' do + expect(History.list(object.class.name, object.id)) + .to be_an(Array).and be_empty + end + end + + context 'when given an object with histories' do + context 'and called without "related_history_object" argument' do + let!(:object) { create(:user) } + + before { object.update(email: 'foo@example.com') } + + context 'or "assets" flag' do + let(:list) { History.list(object.class.name, object.id) } + + it 'returns an array of attribute hashes for those histories' do + expect(list).to match_array( + [ + hash_including( + 'o_id' => object.id, + ), + hash_including( + 'o_id' => object.id, + 'value_to' => 'foo@example.com', + ) + ] + ) + end + + it 'replaces *_id attributes with the corresponding association #name' do + expect(list.first) + .to not_include('history_object_id', 'history_type_id') + .and include( + 'object' => object.class.name, + 'type' => 'created', + ) + + expect(list.second) + .to not_include('history_object_id', 'history_type_id', 'history_attribute_id') + .and include( + 'object' => object.class.name, + 'type' => 'updated', + 'attribute' => 'email', + ) + end + end + + context 'but with "assets" flag' do + let(:list) { History.list(object.class.name, object.id, nil, true) } + let(:matching_histories) do + History.where( + o_id: object.id, + history_object_id: History::Object.lookup(name: object.class.name).id + ) + end + + it 'returns a hash including an array of history attribute hashes' do + expect(list).to include( + list: [ + hash_including( + 'o_id' => object.id, + 'object' => object.class.name, + 'type' => 'created', + ), + hash_including( + 'o_id' => object.id, + 'object' => object.class.name, + 'type' => 'updated', + 'attribute' => 'email', + 'value_to' => 'foo@example.com', + ) + ] + ) + end + + it 'returns a hash including each history record’s FE assets' do + expect(list).to include( + assets: matching_histories.reduce({}) { |assets, h| h.assets(assets) } + ) + end + end + end + + context 'with "related_history_object" argument' do + let!(:object) { related_object.ticket } + let!(:related_object) { create(:ticket_article, internal: true) } # MUST be internal, or else callbacks will create additional histories + + before { object.update(title: 'Lorem ipsum dolor') } + + context 'but no "assets" flag' do + let(:list) { History.list(object.class.name, object.id, 'Ticket::Article') } + + it 'returns an array of attribute hashes for those histories' do + expect(list).to match_array( + [ + hash_including( + 'o_id' => object.id, + ), + hash_including( + 'o_id' => related_object.id, + ), + hash_including( + 'o_id' => object.id, + 'value_to' => 'Lorem ipsum dolor', + ) + ] + ) + end + + it 'replaces *_id attributes with the corresponding association #name' do + expect(list.first) + .to not_include('history_object_id', 'history_type_id') + .and include( + 'object' => object.class.name, + 'type' => 'created', + ) + + expect(list.second) + .to not_include('history_object_id', 'history_type_id') + .and include( + 'object' => related_object.class.name, + 'type' => 'created', + ) + + expect(list.third) + .to not_include('history_object_id', 'history_type_id', 'history_attribute_id') + .and include( + 'object' => object.class.name, + 'type' => 'updated', + 'attribute' => 'title', + ) + end + end + + context 'and "assets" flag' do + let(:list) { History.list(object.class.name, object.id, 'Ticket::Article', true) } + let(:matching_histories) do + History.where( + o_id: object.id, + history_object_id: History::Object.lookup(name: object.class.name).id + ) + History.where( + o_id: related_object.id, + history_object_id: History::Object.lookup(name: related_object.class.name).id + ) + end + + it 'returns a hash including an array of history attribute hashes' do + expect(list).to include( + list: [ + hash_including( + 'o_id' => object.id, + 'object' => object.class.name, + 'type' => 'created', + ), + hash_including( + 'o_id' => related_object.id, + 'object' => related_object.class.name, + 'type' => 'created', + ), + hash_including( + 'o_id' => object.id, + 'object' => object.class.name, + 'type' => 'updated', + 'attribute' => 'title', + 'value_to' => 'Lorem ipsum dolor', + ) + ] + ) + end + + it 'returns a hash including each history record’s FE assets' do + expect(list).to include( + assets: matching_histories.reduce({}) { |assets, h| h.assets(assets) } + ) + end + end + end + end + end end diff --git a/spec/models/organization_spec.rb b/spec/models/organization_spec.rb index 4baa7a7cf..2b2a19cb8 100644 --- a/spec/models/organization_spec.rb +++ b/spec/models/organization_spec.rb @@ -1,6 +1,7 @@ require 'rails_helper' require 'models/application_model_examples' require 'models/concerns/can_lookup_examples' +require 'models/concerns/has_history_examples' require 'models/concerns/has_search_index_backend_examples' require 'models/concerns/has_xss_sanitized_note_examples' require 'models/concerns/has_object_manager_attributes_validation_examples' @@ -8,6 +9,7 @@ require 'models/concerns/has_object_manager_attributes_validation_examples' RSpec.describe Organization, type: :model do it_behaves_like 'ApplicationModel', can_assets: { associations: :members } it_behaves_like 'CanLookup' + it_behaves_like 'HasHistory' it_behaves_like 'HasSearchIndexBackend', indexed_factory: :organization it_behaves_like 'HasXssSanitizedNote', model_factory: :organization it_behaves_like 'HasObjectManagerAttributesValidation' diff --git a/spec/models/ticket/article_spec.rb b/spec/models/ticket/article_spec.rb index 61413e5a1..a7020931f 100644 --- a/spec/models/ticket/article_spec.rb +++ b/spec/models/ticket/article_spec.rb @@ -1,11 +1,13 @@ require 'rails_helper' require 'models/application_model_examples' require 'models/concerns/can_be_imported_examples' +require 'models/concerns/has_history_examples' require 'models/concerns/has_object_manager_attributes_validation_examples' RSpec.describe Ticket::Article, type: :model do it_behaves_like 'ApplicationModel' it_behaves_like 'CanBeImported' + it_behaves_like 'HasHistory' it_behaves_like 'HasObjectManagerAttributesValidation' subject(:article) { create(:ticket_article) } diff --git a/spec/models/ticket_spec.rb b/spec/models/ticket_spec.rb index e57827263..1f635e5bb 100644 --- a/spec/models/ticket_spec.rb +++ b/spec/models/ticket_spec.rb @@ -2,6 +2,7 @@ require 'rails_helper' require 'models/application_model_examples' require 'models/concerns/can_be_imported_examples' require 'models/concerns/can_lookup_examples' +require 'models/concerns/has_history_examples' require 'models/concerns/has_xss_sanitized_note_examples' require 'models/concerns/has_object_manager_attributes_validation_examples' @@ -9,6 +10,7 @@ RSpec.describe Ticket, type: :model do it_behaves_like 'ApplicationModel' it_behaves_like 'CanBeImported' it_behaves_like 'CanLookup' + it_behaves_like 'HasHistory', history_relation_object: 'Ticket::Article' it_behaves_like 'HasXssSanitizedNote', model_factory: :ticket it_behaves_like 'HasObjectManagerAttributesValidation' diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index e0b68c2f8..36e6adf4a 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,6 +1,7 @@ require 'rails_helper' require 'models/application_model_examples' require 'models/concerns/has_groups_examples' +require 'models/concerns/has_history_examples' require 'models/concerns/has_roles_examples' require 'models/concerns/has_groups_permissions_examples' require 'models/concerns/has_xss_sanitized_note_examples' @@ -17,6 +18,7 @@ RSpec.describe User, type: :model do it_behaves_like 'ApplicationModel', can_assets: { associations: :organization } it_behaves_like 'HasGroups', group_access_factory: :agent_user + it_behaves_like 'HasHistory' it_behaves_like 'HasRoles', group_access_factory: :agent_user it_behaves_like 'HasXssSanitizedNote', model_factory: :user it_behaves_like 'HasGroups and Permissions', group_access_no_permission_factory: :user diff --git a/test/unit/history_test.rb b/test/unit/history_test.rb deleted file mode 100644 index 3563633db..000000000 --- a/test/unit/history_test.rb +++ /dev/null @@ -1,432 +0,0 @@ -require 'test_helper' - -class HistoryTest < ActiveSupport::TestCase - - test 'ticket' do - current_user = User.lookup(email: 'nicole.braun@zammad.org') - tests = [ - - # test 1 - { - ticket_create: { - ticket: { - group_id: Group.lookup(name: 'Users').id, - customer_id: current_user.id, - owner_id: User.lookup(login: '-').id, - title: 'Unit Test 1 (äöüß)!', - state_id: Ticket::State.lookup(name: 'new').id, - priority_id: Ticket::Priority.lookup(name: '2 normal').id, - updated_by_id: current_user.id, - created_by_id: current_user.id, - }, - article: { - updated_by_id: current_user.id, - created_by_id: current_user.id, - type_id: Ticket::Article::Type.lookup(name: 'phone').id, - sender_id: Ticket::Article::Sender.lookup(name: 'Customer').id, - from: 'Unit Test ', - body: 'Unit Test 123', - internal: false, - }, - }, - ticket_update: { - ticket: { - title: 'Unit Test 1 (äöüß) - update!', - state_id: Ticket::State.lookup(name: 'open').id, - priority_id: Ticket::Priority.lookup(name: '1 low').id, - }, - }, - history_check: [ - { - result: true, - history_object: 'Ticket', - history_type: 'created', - }, - { - result: true, - history_object: 'Ticket', - history_type: 'updated', - history_attribute: 'title', - value_from: 'Unit Test 1 (äöüß)!', - value_to: 'Unit Test 1 (äöüß) - update!', - }, - { - result: true, - history_object: 'Ticket', - history_type: 'updated', - history_attribute: 'state', - value_from: 'new', - value_to: 'open', - id_from: Ticket::State.lookup(name: 'new').id, - id_to: Ticket::State.lookup(name: 'open').id, - }, - { - result: true, - history_object: 'Ticket::Article', - history_type: 'created', - }, - { - result: false, - history_object: 'User', - history_type: 'updated', - }, - ] - }, - - # test 2 - { - ticket_create: { - ticket: { - group_id: Group.lookup(name: 'Users').id, - customer_id: current_user.id, - owner_id: User.lookup(login: '-').id, - title: 'Unit Test 2 (äöüß)!', - state_id: Ticket::State.lookup(name: 'new').id, - priority_id: Ticket::Priority.lookup(name: '2 normal').id, - updated_by_id: current_user.id, - created_by_id: current_user.id, - }, - article: { - created_by_id: current_user.id, - updated_by_id: current_user.id, - type_id: Ticket::Article::Type.lookup(name: 'phone').id, - sender_id: Ticket::Article::Sender.lookup(name: 'Customer').id, - from: 'Unit Test ', - body: 'Unit Test 123', - internal: false, - }, - }, - ticket_update: { - ticket: { - title: 'Unit Test 2 (äöüß) - update!', - state_id: Ticket::State.lookup(name: 'open').id, - owner_id: current_user.id, - }, - article: { - body: 'Unit Test 123 - 2', - }, - }, - history_check: [ - { - result: true, - history_object: 'Ticket', - history_type: 'created', - }, - { - result: true, - history_object: 'Ticket', - history_type: 'updated', - history_attribute: 'title', - value_from: 'Unit Test 2 (äöüß)!', - value_to: 'Unit Test 2 (äöüß) - update!', - }, - { - result: false, - history_object: 'Ticket', - history_type: 'updated', - history_attribute: 'owner', - value_from: '-', - value_to: 'Nicole Braun', - id_from: User.lookup(login: '-').id, - id_to: current_user.id, - }, - { - result: true, - history_object: 'Ticket::Article', - history_type: 'created', - }, - { - result: true, - history_object: 'Ticket::Article', - history_type: 'updated', - history_attribute: 'body', - value_from: 'Unit Test 123', - value_to: 'Unit Test 123 - 2', - }, - ] - }, - ] - tickets = [] - tests.each do |test| - - ticket = nil - article = nil - - # use transaction - ActiveRecord::Base.transaction do - ticket = Ticket.create!(test[:ticket_create][:ticket]) - test[:ticket_create][:article][:ticket_id] = ticket.id - article = Ticket::Article.create!(test[:ticket_create][:article]) - - assert_equal(ticket.class, Ticket) - assert_equal(article.class, Ticket::Article) - - # update ticket - if test[:ticket_update][:ticket] - ticket.update!(test[:ticket_update][:ticket]) - end - if test[:ticket_update][:article] - article.update!(test[:ticket_update][:article]) - end - end - - # execute object transaction - Observer::Transaction.commit - - # execute background jobs - Scheduler.worker(true) - - # remember ticket - tickets.push ticket - - # check history - history_check(ticket.history_get, test[:history_check]) - end - - # delete tickets - tickets.each(&:destroy!) - end - - test 'user' do - current_user = User.lookup(email: 'nicole.braun@zammad.org') - name = rand(999_999) - tests = [ - - # test 1 - { - user_create: { - user: { - login: "some_login_test-#{name}", - firstname: 'Bob', - lastname: 'Smith', - email: "somebody-#{name}@example.com", - active: true, - updated_by_id: current_user.id, - created_by_id: current_user.id, - }, - }, - user_update: { - user: { - firstname: 'Bob', - lastname: 'Master', - email: "master-#{name}@example.com", - active: false, - }, - }, - history_check: [ - { - result: true, - history_object: 'User', - history_type: 'created', - }, - { - result: true, - history_object: 'User', - history_type: 'updated', - history_attribute: 'lastname', - value_from: 'Smith', - value_to: 'Master', - }, - { - result: true, - history_object: 'User', - history_type: 'updated', - history_attribute: 'email', - value_from: "somebody-#{name}@example.com", - value_to: "master-#{name}@example.com", - }, - { - result: true, - history_object: 'User', - history_type: 'updated', - history_attribute: 'active', - value_from: 'true', - value_to: 'false', - }, - ], - }, - - ] - users = [] - tests.each do |test| - - user = nil - - # user transaction - ActiveRecord::Base.transaction do - user = User.create!(test[:user_create][:user]) - assert_equal(user.class, User) - - # update user - if test[:user_update][:user] - test[:user_update][:user][:active] = false - user.update!(test[:user_update][:user]) - end - end - - # remember user - users.push user - - # check history - history_check(user.history_get, test[:history_check]) - end - - # delete user - users.each(&:destroy!) - end - - test 'organization' do - current_user = User.lookup(email: 'nicole.braun@zammad.org') - tests = [ - - # test 1 - { - organization_create: { - organization: { - name: 'Org äöüß', - note: 'some note', - updated_by_id: current_user.id, - created_by_id: current_user.id, - }, - }, - organization_update: { - organization: { - name: 'Org 123', - note: 'some note', - }, - }, - history_check: [ - { - result: true, - history_object: 'Organization', - history_type: 'created', - }, - { - result: true, - history_object: 'Organization', - history_type: 'updated', - history_attribute: 'name', - value_from: 'Org äöüß', - value_to: 'Org 123', - }, - ], - }, - ] - organizations = [] - tests.each do |test| - - organization = nil - - # user transaction - ActiveRecord::Base.transaction do - organization = Organization.create!(test[:organization_create][:organization]) - assert_equal(organization.class, Organization) - - # update organization - if test[:organization_update][:organization] - organization.update!(test[:organization_update][:organization]) - end - end - - # remember user - organizations.push organization - - # check history - history_check(organization.history_get, test[:history_check]) - end - - # delete user - organizations.each(&:destroy!) - end - - test 'ticket assets' do - UserInfo.current_user_id = 1 - agent1 = User.create!( - login: 'agent1@example.com', - firstname: 'agent', - lastname: '1', - email: 'agent1@example.com', - password: 'agentpw', - active: true, - roles: Role.where(name: %w[Agent Admin]), - groups: Group.all, - ) - current_user = User.lookup(email: 'nicole.braun@zammad.org') - UserInfo.current_user_id = current_user.id - - ticket = Ticket.create!( - title: 'test 1', - group: Group.first, - customer_id: current_user.id, - state: Ticket::State.lookup(name: 'new'), - priority: Ticket::Priority.lookup(name: '2 normal'), - ) - article = Ticket::Article.create!( - ticket_id: ticket.id, - from: 'some_customer_com-1@example.com', - to: 'some_zammad_com-1@example.com', - subject: 'com test 1', - message_id: 'some@id_com_1', - body: 'some message 123', - internal: false, - sender: Ticket::Article::Sender.find_by(name: 'Customer'), - type: Ticket::Article::Type.find_by(name: 'email'), - ) - - # verify if user of history record is in assets - UserInfo.current_user_id = agent1.id - ticket.state = Ticket::State.find_by(name: 'closed') - ticket.save! - - # update updated_by (to not include agent1 in assets by ticket) - UserInfo.current_user_id = current_user.id - ticket.priority = Ticket::Priority.find_by(name: '3 high') - ticket.save! - - history = ticket.history_get(true) - assert(history[:assets][:User][current_user.id]) - assert(history[:assets][:User][agent1.id]) - assert(history[:assets][:Ticket][ticket.id]) - assert(history[:assets][:TicketArticle][article.id]) - end - - def history_check(history_list, history_check) - history_check.each do |check_item| - match = false - history_list.each do |history_item| - next if match - next if history_item['object'] != check_item[:history_object] - next if history_item['type'] != check_item[:history_type] - - if check_item[:history_attribute] - next if check_item[:history_attribute] != history_item['attribute'] - end - match = true - if history_item['type'] == check_item[:history_type] - assert(true, "History type #{history_item['type']} found!") - end - if check_item[:history_attribute] - assert_equal(check_item[:history_attribute], history_item['attribute'], "check history attribute #{check_item[:history_attribute]}") - end - if check_item[:value_from] - assert_equal(check_item[:value_from], history_item['value_from'], "check history :value_from #{history_item['value_from']} ok") - end - if check_item[:value_to] - assert_equal(check_item[:value_to], history_item['value_to'], "check history :value_to #{history_item['value_to']} ok") - end - if check_item[:id_from] - assert_equal(check_item[:id_from], history_item['id_from'], "check history :id_from #{history_item['id_from']} ok") - end - if check_item[:id_to] - assert_equal(check_item[:id_to], history_item['id_to'], "check history :id_to #{history_item['id_to']} ok") - end - end - if check_item[:result] - assert(match, "history check not matched! #{check_item.inspect}") - else - assert_not(match, "history check matched but should not! #{check_item.inspect}") - end - end - end - -end