ticket_overview_list_spec.rb 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. RSpec.describe Sessions::Backend::TicketOverviewList do
  4. it 'inherits #asset_needed? from Sessions::Backend::Base' do
  5. expect(described_class.instance_method(:asset_needed?).owner)
  6. .to be(described_class.superclass)
  7. end
  8. it 'inherits #asset_push from Sessions::Backend::Base' do
  9. expect(described_class.instance_method(:asset_push).owner)
  10. .to be(described_class.superclass)
  11. end
  12. describe '.push' do
  13. let(:admin) { create(:admin, groups: [group]) }
  14. let(:group) { create(:group) }
  15. let(:client_id) { '12345' }
  16. let(:ttl) { 3 } # seconds
  17. context 'when 3rd argument ("client") is false' do
  18. subject(:collection) { described_class.new(admin, {}, false, client_id, ttl) }
  19. it 'returns an array of hashes with :event and :data keys' do
  20. expect(collection.push)
  21. .to be_an(Array)
  22. .and have_attributes(length: Ticket::Overviews.all(current_user: admin).count)
  23. .and all(match({ event: 'ticket_overview_list', data: hash_including(:assets) }))
  24. end
  25. it 'returns one hash for each of the user’s ticket overviews' do
  26. expect(collection.push.map { |hash| hash[:data][:overview][:name] })
  27. .to match_array(Ticket::Overviews.all(current_user: admin).map(&:name))
  28. end
  29. it 'is optimized to not send duplicate asset entries over all events' do
  30. collection_assets = collection.push.map { |hash| hash[:data][:assets] }
  31. # match all event assets against the assets of the other events
  32. # and make sure that each asset entry is unique over all events assets
  33. unique_asssets = collection_assets.each_with_index.all? do |lookup_assets, lookup_index|
  34. collection_assets.each_with_index.none? do |comparison_assets, comparison_index|
  35. # skip assets comparison for same event
  36. next if comparison_index == lookup_index
  37. # check that none of the lookup_assets assets is present
  38. # in the comparison_assets
  39. lookup_assets.keys.any? do |model|
  40. # skip Models that are only present in our lookup_assets entry
  41. next if !comparison_assets.key?(model)
  42. # check if there are no intersect Model record IDs
  43. # aka IDs present in both hashes
  44. intersection_ids = lookup_assets[model].keys & comparison_assets[model].keys
  45. intersection_ids.present?
  46. end
  47. end
  48. end
  49. expect(unique_asssets).to be(true)
  50. end
  51. it 'includes FE assets for all overviews and tickets not pushed in the last two hours' do
  52. # ATTENTION: we can't compare the arrays of assets directly
  53. # because the Ticket::Overviews backend contain an optimization logic that sends an asset entry only once
  54. # while the Sessions::Backend::* classes results contain all assets for each entry.
  55. # Therefore we merge all assets for each of the both arrays to have two big Hashes that contains all assets.
  56. # See previous example for the matching spec.
  57. collection_assets = collection.push.map { |hash| hash[:data][:assets] }
  58. collection_assets_merged = collection_assets.each_with_object({}) { |assets, result| result.deep_merge!(assets) }
  59. overviews_all_assets = Ticket::Overviews.all(current_user: admin).map { |overview| overview.assets({}) }
  60. overviews_all_assets_merged = overviews_all_assets.each_with_object({}) { |assets, result| result.deep_merge!(assets) }
  61. expect(collection_assets_merged).to eq(overviews_all_assets_merged)
  62. end
  63. context 'when called twice, with no changes to Ticket and Overview tables' do
  64. let!(:first_call) { collection.push }
  65. it 'returns nil' do
  66. expect(collection.push).to be_nil
  67. end
  68. context 'even after the TTL has passed' do
  69. before { travel(ttl + 1) }
  70. it 'returns nil' do
  71. expect(collection.push).to be_nil
  72. end
  73. end
  74. context 'even after .reset with the user’s id' do
  75. before { described_class.reset(admin.id) }
  76. it 'returns nil' do
  77. expect(collection.push).to be_nil
  78. end
  79. end
  80. end
  81. context 'when called twice, after changes have occurred to the Ticket table' do
  82. let!(:ticket) { create(:ticket, group: group) }
  83. let!(:first_call) { collection.push }
  84. context 'before the TTL has passed' do
  85. it 'returns nil' do
  86. expect(collection.push).to be_nil
  87. end
  88. context 'after .reset with the user’s id' do
  89. before { described_class.reset(admin.id) }
  90. it 'returns nil because no ticket and no overview has changed' do
  91. expect(collection.push).to be_nil
  92. end
  93. end
  94. end
  95. context 'after the TTL has passed' do
  96. before { travel(ttl + 1) }
  97. it 'returns an empty result' do
  98. expect(collection.push).to be_nil
  99. end
  100. end
  101. context 'after two hours have passed' do
  102. before { travel(2.hours + 1.second) }
  103. it 'returns an empty result' do
  104. expect(collection.push).to be_nil
  105. end
  106. end
  107. end
  108. context 'when called twice, after changes have occurred to the Overviews table' do
  109. let!(:first_call) { collection.push }
  110. before { Overview.first.touch }
  111. context 'before the TTL has passed' do
  112. it 'returns nil' do
  113. expect(collection.push).to be_nil
  114. end
  115. context 'after .reset with the user’s id' do
  116. before { described_class.reset(admin.id) }
  117. it 'returns an updated set of results' do
  118. expect(collection.push)
  119. .to be_an(Array)
  120. .and have_attributes(length: 1)
  121. .and all(match({ event: 'ticket_overview_list', data: hash_including(:assets) }))
  122. end
  123. end
  124. end
  125. context 'after two hours have passed' do
  126. before { travel(2.hours + 1.second) }
  127. it 'returns an empty result' do
  128. expect(collection.push)
  129. .to be_an(Array)
  130. .and have_attributes(length: 1)
  131. .and all(match({ event: 'ticket_overview_list', data: hash_including(:assets) }))
  132. end
  133. end
  134. end
  135. end
  136. end
  137. end