sortable_events_spec.rb 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. require 'rails_helper'
  2. describe SortableEvents do
  3. let(:agent_class) {
  4. Class.new(Agent) do
  5. include SortableEvents
  6. default_schedule 'never'
  7. def self.valid_type?(name)
  8. true
  9. end
  10. end
  11. }
  12. def new_agent(events_order = nil)
  13. options = {}
  14. options['events_order'] = events_order if events_order
  15. agent_class.new(name: 'test', options: options) { |agent|
  16. agent.user = users(:bob)
  17. }
  18. end
  19. describe 'validations' do
  20. let(:agent_class) {
  21. Class.new(Agent) do
  22. include SortableEvents
  23. default_schedule 'never'
  24. def self.valid_type?(name)
  25. true
  26. end
  27. end
  28. }
  29. def new_agent(events_order = nil)
  30. options = {}
  31. options['events_order'] = events_order if events_order
  32. agent_class.new(name: 'test', options: options) { |agent|
  33. agent.user = users(:bob)
  34. }
  35. end
  36. it 'should allow events_order to be unspecified, null or an empty array' do
  37. expect(new_agent()).to be_valid
  38. expect(new_agent(nil)).to be_valid
  39. expect(new_agent([])).to be_valid
  40. end
  41. it 'should not allow events_order to be a non-array object' do
  42. agent = new_agent(0)
  43. expect(agent).not_to be_valid
  44. expect(agent.errors[:base]).to include(/events_order/)
  45. agent = new_agent('')
  46. expect(agent).not_to be_valid
  47. expect(agent.errors[:base]).to include(/events_order/)
  48. agent = new_agent({})
  49. expect(agent).not_to be_valid
  50. expect(agent.errors[:base]).to include(/events_order/)
  51. end
  52. it 'should not allow events_order to be an array containing unexpected objects' do
  53. agent = new_agent(['{{key}}', 1])
  54. expect(agent).not_to be_valid
  55. expect(agent.errors[:base]).to include(/events_order/)
  56. agent = new_agent(['{{key1}}', ['{{key2}}', 'unknown']])
  57. expect(agent).not_to be_valid
  58. expect(agent.errors[:base]).to include(/events_order/)
  59. end
  60. it 'should allow events_order to be an array containing strings and valid tuples' do
  61. agent = new_agent(['{{key1}}', ['{{key2}}'], ['{{key3}}', 'number']])
  62. expect(agent).to be_valid
  63. agent = new_agent(['{{key1}}', ['{{key2}}'], ['{{key3}}', 'number'], ['{{key4}}', 'time', true]])
  64. expect(agent).to be_valid
  65. end
  66. end
  67. describe 'sort_events' do
  68. let(:payloads) {
  69. [
  70. { 'title' => 'TitleA', 'score' => 4, 'updated_on' => '7 Jul 2015' },
  71. { 'title' => 'TitleB', 'score' => 2, 'updated_on' => '25 Jun 2014' },
  72. { 'title' => 'TitleD', 'score' => 10, 'updated_on' => '10 Jan 2015' },
  73. { 'title' => 'TitleC', 'score' => 10, 'updated_on' => '9 Feb 2015' },
  74. ]
  75. }
  76. let(:events) {
  77. payloads.map { |payload| Event.new(payload: payload) }
  78. }
  79. it 'should sort events by a given key' do
  80. agent = new_agent(['{{title}}'])
  81. expect(agent.__send__(:sort_events, events).map { |e| e.payload['title'] }).to eq(%w[TitleA TitleB TitleC TitleD])
  82. agent = new_agent([['{{title}}', 'string', true]])
  83. expect(agent.__send__(:sort_events, events).map { |e| e.payload['title'] }).to eq(%w[TitleD TitleC TitleB TitleA])
  84. end
  85. it 'should sort events by multiple keys' do
  86. agent = new_agent([['{{score}}', 'number'], '{{title}}'])
  87. expect(agent.__send__(:sort_events, events).map { |e| e.payload['title'] }).to eq(%w[TitleB TitleA TitleC TitleD])
  88. agent = new_agent([['{{score}}', 'number'], ['{{title}}', 'string', true]])
  89. expect(agent.__send__(:sort_events, events).map { |e| e.payload['title'] }).to eq(%w[TitleB TitleA TitleD TitleC])
  90. end
  91. it 'should sort events by time' do
  92. agent = new_agent([['{{updated_on}}', 'time']])
  93. expect(agent.__send__(:sort_events, events).map { |e| e.payload['title'] }).to eq(%w[TitleB TitleD TitleC TitleA])
  94. end
  95. it 'should sort events stably' do
  96. agent = new_agent(['<constant>'])
  97. expect(agent.__send__(:sort_events, events).map { |e| e.payload['title'] }).to eq(%w[TitleA TitleB TitleD TitleC])
  98. agent = new_agent([['<constant>', 'string', true]])
  99. expect(agent.__send__(:sort_events, events).map { |e| e.payload['title'] }).to eq(%w[TitleA TitleB TitleD TitleC])
  100. end
  101. it 'should support _index_' do
  102. agent = new_agent([['{{_index_}}', 'number', true]])
  103. expect(agent.__send__(:sort_events, events).map { |e| e.payload['title'] }).to eq(%w[TitleC TitleD TitleB TitleA])
  104. end
  105. end
  106. describe 'automatic event sorter' do
  107. describe 'declaration' do
  108. let(:passive_agent_class) {
  109. Class.new(Agent) do
  110. include SortableEvents
  111. cannot_create_events!
  112. end
  113. }
  114. let(:active_agent_class) {
  115. Class.new(Agent) do
  116. include SortableEvents
  117. end
  118. }
  119. describe 'can_order_created_events!' do
  120. it 'should refuse to work if called from an Agent that cannot create events' do
  121. expect {
  122. passive_agent_class.class_eval do
  123. can_order_created_events!
  124. end
  125. }.to raise_error('Cannot order events for agent that cannot create events')
  126. end
  127. it 'should work if called from an Agent that can create events' do
  128. expect {
  129. active_agent_class.class_eval do
  130. can_order_created_events!
  131. end
  132. }.not_to raise_error()
  133. end
  134. end
  135. describe 'can_order_created_events?' do
  136. it 'should return false unless an Agent declares can_order_created_events!' do
  137. expect(active_agent_class.can_order_created_events?).to eq(false)
  138. expect(active_agent_class.new.can_order_created_events?).to eq(false)
  139. end
  140. it 'should return true if an Agent declares can_order_created_events!' do
  141. active_agent_class.class_eval do
  142. can_order_created_events!
  143. end
  144. expect(active_agent_class.can_order_created_events?).to eq(true)
  145. expect(active_agent_class.new.can_order_created_events?).to eq(true)
  146. end
  147. end
  148. end
  149. describe 'behavior' do
  150. class Agents::EventOrderableAgent < Agent
  151. include SortableEvents
  152. default_schedule 'never'
  153. can_order_created_events!
  154. attr_accessor :payloads_to_emit
  155. def self.valid_type?(name)
  156. true
  157. end
  158. def check
  159. payloads_to_emit.each do |payload|
  160. create_event payload: payload
  161. end
  162. end
  163. def receive(events)
  164. events.each do |event|
  165. payloads_to_emit.each do |payload|
  166. create_event payload: payload.merge('title' => payload['title'] + event.payload['title_suffix'])
  167. end
  168. end
  169. end
  170. end
  171. def new_agent(events_order = nil)
  172. options = {}
  173. options['events_order'] = events_order if events_order
  174. Agents::EventOrderableAgent.new(name: 'test', options: options) { |agent|
  175. agent.user = users(:bob)
  176. agent.payloads_to_emit = payloads
  177. }
  178. end
  179. let(:payloads) {
  180. [
  181. { 'title' => 'TitleA', 'score' => 4, 'updated_on' => '7 Jul 2015' },
  182. { 'title' => 'TitleB', 'score' => 2, 'updated_on' => '25 Jun 2014' },
  183. { 'title' => 'TitleD', 'score' => 10, 'updated_on' => '10 Jan 2015' },
  184. { 'title' => 'TitleC', 'score' => 10, 'updated_on' => '9 Feb 2015' },
  185. ]
  186. }
  187. it 'should keep the order of created events unless events_order is specified' do
  188. [[], [nil], [[]]].each do |args|
  189. agent = new_agent(*args)
  190. agent.save!
  191. expect { agent.check }.to change { Event.count }.by(4)
  192. events = agent.events.last(4).sort_by(&:id)
  193. expect(events.map { |event| event.payload['title'] }).to eq(%w[TitleA TitleB TitleD TitleC])
  194. end
  195. end
  196. it 'should sort events created in check() in the order specified in events_order' do
  197. agent = new_agent([['{{score}}', 'number'], ['{{title}}', 'string', true]])
  198. agent.save!
  199. expect { agent.check }.to change { Event.count }.by(4)
  200. events = agent.events.last(4).sort_by(&:id)
  201. expect(events.map { |event| event.payload['title'] }).to eq(%w[TitleB TitleA TitleD TitleC])
  202. end
  203. it 'should sort events created in receive() in the order specified in events_order' do
  204. agent = new_agent([['{{score}}', 'number'], ['{{title}}', 'string', true]])
  205. agent.save!
  206. expect {
  207. agent.receive([Event.new(payload: { 'title_suffix' => ' [new]' }),
  208. Event.new(payload: { 'title_suffix' => ' [popular]' })])
  209. }.to change { Event.count }.by(8)
  210. events = agent.events.last(8).sort_by(&:id)
  211. expect(events.map { |event| event.payload['title'] }).to eq([
  212. 'TitleB [new]', 'TitleA [new]', 'TitleD [new]', 'TitleC [new]',
  213. 'TitleB [popular]', 'TitleA [popular]', 'TitleD [popular]', 'TitleC [popular]',
  214. ])
  215. end
  216. end
  217. end
  218. end