trigger_agent_spec.rb 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. require 'spec_helper'
  2. describe Agents::TriggerAgent do
  3. before do
  4. @valid_params = {
  5. 'name' => "my trigger agent",
  6. 'options' => {
  7. 'expected_receive_period_in_days' => 2,
  8. 'rules' => [{
  9. 'type' => "regex",
  10. 'value' => "a\\db",
  11. 'path' => "foo.bar.baz",
  12. }],
  13. 'message' => "I saw '{{foo.bar.baz}}' from {{name}}"
  14. }
  15. }
  16. @checker = Agents::TriggerAgent.new(@valid_params)
  17. @checker.user = users(:bob)
  18. @checker.save!
  19. @event = Event.new
  20. @event.agent = agents(:bob_rain_notifier_agent)
  21. @event.payload = { 'foo' => { "bar" => { 'baz' => "a2b" }},
  22. 'name' => "Joe" }
  23. end
  24. describe "validation" do
  25. before do
  26. expect(@checker).to be_valid
  27. end
  28. it "should validate presence of message" do
  29. @checker.options['message'] = nil
  30. expect(@checker).not_to be_valid
  31. @checker.options['message'] = ''
  32. expect(@checker).not_to be_valid
  33. end
  34. it "should be valid without a message when 'keep_event' is set" do
  35. @checker.options['keep_event'] = 'true'
  36. @checker.options['message'] = ''
  37. expect(@checker).to be_valid
  38. end
  39. it "if present, 'keep_event' must equal true or false" do
  40. @checker.options['keep_event'] = 'true'
  41. expect(@checker).to be_valid
  42. @checker.options['keep_event'] = 'false'
  43. expect(@checker).to be_valid
  44. @checker.options['keep_event'] = ''
  45. expect(@checker).to be_valid
  46. @checker.options['keep_event'] = 'tralse'
  47. expect(@checker).not_to be_valid
  48. end
  49. it "should validate the three fields in each rule" do
  50. @checker.options['rules'] << { 'path' => "foo", 'type' => "fake", 'value' => "6" }
  51. expect(@checker).not_to be_valid
  52. @checker.options['rules'].last['type'] = "field>=value"
  53. expect(@checker).to be_valid
  54. @checker.options['rules'].last.delete('value')
  55. expect(@checker).not_to be_valid
  56. end
  57. end
  58. describe "#working?" do
  59. it "checks to see if the Agent has received any events in the last 'expected_receive_period_in_days' days" do
  60. @event.save!
  61. expect(@checker).not_to be_working # no events have ever been received
  62. Agents::TriggerAgent.async_receive(@checker.id, [@event.id])
  63. expect(@checker.reload).to be_working # Events received
  64. three_days_from_now = 3.days.from_now
  65. stub(Time).now { three_days_from_now }
  66. expect(@checker.reload).not_to be_working # too much time has passed
  67. end
  68. end
  69. describe "#receive" do
  70. it "handles regex" do
  71. @event.payload['foo']['bar']['baz'] = "a222b"
  72. expect {
  73. @checker.receive([@event])
  74. }.not_to change { Event.count }
  75. @event.payload['foo']['bar']['baz'] = "a2b"
  76. expect {
  77. @checker.receive([@event])
  78. }.to change { Event.count }.by(1)
  79. end
  80. it "handles array of regex" do
  81. @event.payload['foo']['bar']['baz'] = "a222b"
  82. @checker.options['rules'][0] = {
  83. 'type' => "regex",
  84. 'value' => ["a\\db", "a\\Wb"],
  85. 'path' => "foo.bar.baz",
  86. }
  87. expect {
  88. @checker.receive([@event])
  89. }.not_to change { Event.count }
  90. @event.payload['foo']['bar']['baz'] = "a2b"
  91. expect {
  92. @checker.receive([@event])
  93. }.to change { Event.count }.by(1)
  94. @event.payload['foo']['bar']['baz'] = "a b"
  95. expect {
  96. @checker.receive([@event])
  97. }.to change { Event.count }.by(1)
  98. end
  99. it "handles negated regex" do
  100. @event.payload['foo']['bar']['baz'] = "a2b"
  101. @checker.options['rules'][0] = {
  102. 'type' => "!regex",
  103. 'value' => "a\\db",
  104. 'path' => "foo.bar.baz",
  105. }
  106. expect {
  107. @checker.receive([@event])
  108. }.not_to change { Event.count }
  109. @event.payload['foo']['bar']['baz'] = "a22b"
  110. expect {
  111. @checker.receive([@event])
  112. }.to change { Event.count }.by(1)
  113. end
  114. it "handles array of negated regex" do
  115. @event.payload['foo']['bar']['baz'] = "a2b"
  116. @checker.options['rules'][0] = {
  117. 'type' => "!regex",
  118. 'value' => ["a\\db", "a2b"],
  119. 'path' => "foo.bar.baz",
  120. }
  121. expect {
  122. @checker.receive([@event])
  123. }.not_to change { Event.count }
  124. @event.payload['foo']['bar']['baz'] = "a3b"
  125. expect {
  126. @checker.receive([@event])
  127. }.to change { Event.count }.by(1)
  128. end
  129. it "puts can extract values into the message based on paths" do
  130. @checker.receive([@event])
  131. expect(Event.last.payload['message']).to eq("I saw 'a2b' from Joe")
  132. end
  133. it "handles numerical comparisons" do
  134. @event.payload['foo']['bar']['baz'] = "5"
  135. @checker.options['rules'].first['value'] = 6
  136. @checker.options['rules'].first['type'] = "field<value"
  137. expect {
  138. @checker.receive([@event])
  139. }.to change { Event.count }.by(1)
  140. @checker.options['rules'].first['value'] = 3
  141. expect {
  142. @checker.receive([@event])
  143. }.not_to change { Event.count }
  144. end
  145. it "handles array of numerical comparisons" do
  146. @event.payload['foo']['bar']['baz'] = "5"
  147. @checker.options['rules'].first['value'] = [6, 3]
  148. @checker.options['rules'].first['type'] = "field<value"
  149. expect {
  150. @checker.receive([@event])
  151. }.to change { Event.count }.by(1)
  152. @checker.options['rules'].first['value'] = [4, 3]
  153. expect {
  154. @checker.receive([@event])
  155. }.not_to change { Event.count }
  156. end
  157. it "handles exact comparisons" do
  158. @event.payload['foo']['bar']['baz'] = "hello world"
  159. @checker.options['rules'].first['type'] = "field==value"
  160. @checker.options['rules'].first['value'] = "hello there"
  161. expect {
  162. @checker.receive([@event])
  163. }.not_to change { Event.count }
  164. @checker.options['rules'].first['value'] = "hello world"
  165. expect {
  166. @checker.receive([@event])
  167. }.to change { Event.count }.by(1)
  168. end
  169. it "handles array of exact comparisons" do
  170. @event.payload['foo']['bar']['baz'] = "hello world"
  171. @checker.options['rules'].first['type'] = "field==value"
  172. @checker.options['rules'].first['value'] = ["hello there", "hello universe"]
  173. expect {
  174. @checker.receive([@event])
  175. }.not_to change { Event.count }
  176. @checker.options['rules'].first['value'] = ["hello world", "hello universe"]
  177. expect {
  178. @checker.receive([@event])
  179. }.to change { Event.count }.by(1)
  180. end
  181. it "handles negated comparisons" do
  182. @event.payload['foo']['bar']['baz'] = "hello world"
  183. @checker.options['rules'].first['type'] = "field!=value"
  184. @checker.options['rules'].first['value'] = "hello world"
  185. expect {
  186. @checker.receive([@event])
  187. }.not_to change { Event.count }
  188. @checker.options['rules'].first['value'] = "hello there"
  189. expect {
  190. @checker.receive([@event])
  191. }.to change { Event.count }.by(1)
  192. end
  193. it "handles array of negated comparisons" do
  194. @event.payload['foo']['bar']['baz'] = "hello world"
  195. @checker.options['rules'].first['type'] = "field!=value"
  196. @checker.options['rules'].first['value'] = ["hello world", "hello world"]
  197. expect {
  198. @checker.receive([@event])
  199. }.not_to change { Event.count }
  200. @checker.options['rules'].first['value'] = ["hello there", "hello world"]
  201. expect {
  202. @checker.receive([@event])
  203. }.to change { Event.count }.by(1)
  204. end
  205. it "does fine without dots in the path" do
  206. @event.payload = { 'hello' => "world" }
  207. @checker.options['rules'].first['type'] = "field==value"
  208. @checker.options['rules'].first['path'] = "hello"
  209. @checker.options['rules'].first['value'] = "world"
  210. expect {
  211. @checker.receive([@event])
  212. }.to change { Event.count }.by(1)
  213. @checker.options['rules'].first['path'] = "foo"
  214. expect {
  215. @checker.receive([@event])
  216. }.not_to change { Event.count }
  217. @checker.options['rules'].first['value'] = "hi"
  218. expect {
  219. @checker.receive([@event])
  220. }.not_to change { Event.count }
  221. end
  222. it "handles multiple events" do
  223. event2 = Event.new
  224. event2.agent = agents(:bob_weather_agent)
  225. event2.payload = { 'foo' => { 'bar' => { 'baz' => "a2b" }}}
  226. event3 = Event.new
  227. event3.agent = agents(:bob_weather_agent)
  228. event3.payload = { 'foo' => { 'bar' => { 'baz' => "a222b" }}}
  229. expect {
  230. @checker.receive([@event, event2, event3])
  231. }.to change { Event.count }.by(2)
  232. end
  233. it "handles ANDing rules together" do
  234. @checker.options['rules'] << {
  235. 'type' => "field>=value",
  236. 'value' => "4",
  237. 'path' => "foo.bing"
  238. }
  239. @event.payload['foo']["bing"] = "5"
  240. expect {
  241. @checker.receive([@event])
  242. }.to change { Event.count }.by(1)
  243. @checker.options['rules'].last['value'] = 6
  244. expect {
  245. @checker.receive([@event])
  246. }.not_to change { Event.count }
  247. end
  248. describe "when 'keep_event' is true" do
  249. before do
  250. @checker.options['keep_event'] = 'true'
  251. @event.payload['foo']['bar']['baz'] = "5"
  252. @checker.options['rules'].first['type'] = "field<value"
  253. end
  254. it "can re-emit the origin event" do
  255. @checker.options['rules'].first['value'] = 3
  256. @checker.options['message'] = ''
  257. @event.payload['message'] = 'hi there'
  258. expect {
  259. @checker.receive([@event])
  260. }.not_to change { Event.count }
  261. @checker.options['rules'].first['value'] = 6
  262. expect {
  263. @checker.receive([@event])
  264. }.to change { Event.count }.by(1)
  265. expect(@checker.most_recent_event.payload).to eq(@event.payload)
  266. end
  267. it "merges 'message' into the original event when present" do
  268. @checker.options['rules'].first['value'] = 6
  269. @checker.receive([@event])
  270. expect(@checker.most_recent_event.payload).to eq(@event.payload.merge(:message => "I saw '5' from Joe"))
  271. end
  272. end
  273. end
  274. end