Няма описание http://j1x-huginn.herokuapp.com

post_agent_spec.rb 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. require 'rails_helper'
  2. require 'ostruct'
  3. describe Agents::PostAgent do
  4. before do
  5. @valid_options = {
  6. 'post_url' => "http://www.example.com",
  7. 'expected_receive_period_in_days' => 1,
  8. 'payload' => {
  9. 'default' => 'value'
  10. }
  11. }
  12. @valid_params = {
  13. name: "somename",
  14. options: @valid_options
  15. }
  16. @checker = Agents::PostAgent.new(@valid_params)
  17. @checker.user = users(:jane)
  18. @checker.save!
  19. @event = Event.new
  20. @event.agent = agents(:jane_weather_agent)
  21. @event.payload = {
  22. 'somekey' => 'somevalue',
  23. 'someotherkey' => {
  24. 'somekey' => 'value'
  25. }
  26. }
  27. @requests = 0
  28. @sent_requests = Hash.new { |hash, method| hash[method] = [] }
  29. stub_request(:any, /:/).to_return { |request|
  30. method = request.method
  31. @requests += 1
  32. @sent_requests[method] << req = OpenStruct.new(uri: request.uri, headers: request.headers)
  33. case method
  34. when :get, :delete
  35. req.data = request.uri.query
  36. else
  37. content_type = request.headers['Content-Type'][/\A[^;\s]+/]
  38. case content_type
  39. when 'application/x-www-form-urlencoded'
  40. req.data = request.body
  41. when 'application/json'
  42. req.data = ActiveSupport::JSON.decode(request.body)
  43. when 'text/xml'
  44. req.data = Hash.from_xml(request.body)
  45. when Agents::PostAgent::MIME_RE
  46. req.data = request.body
  47. else
  48. raise "unexpected Content-Type: #{content_type}"
  49. end
  50. end
  51. { status: 200, body: "<html>a webpage!</html>", headers: { 'Content-type' => 'text/html' } }
  52. }
  53. end
  54. it_behaves_like WebRequestConcern
  55. describe "making requests" do
  56. it "can make requests of each type" do
  57. %w[get put post patch delete].each.with_index(1) do |verb, index|
  58. @checker.options['method'] = verb
  59. expect(@checker).to be_valid
  60. @checker.check
  61. expect(@requests).to eq(index)
  62. expect(@sent_requests[verb.to_sym].length).to eq(1)
  63. end
  64. end
  65. end
  66. describe "#receive" do
  67. it "can handle multiple events and merge the payloads with options['payload']" do
  68. event1 = Event.new
  69. event1.agent = agents(:bob_weather_agent)
  70. event1.payload = {
  71. 'xyz' => 'value1',
  72. 'message' => 'value2',
  73. 'default' => 'value2'
  74. }
  75. expect {
  76. expect {
  77. @checker.receive([@event, event1])
  78. }.to change { @sent_requests[:post].length }.by(2)
  79. }.not_to change { @sent_requests[:get].length }
  80. expect(@sent_requests[:post][0].data).to eq(@event.payload.merge('default' => 'value').to_query)
  81. expect(@sent_requests[:post][1].data).to eq(event1.payload.to_query)
  82. end
  83. it "can make GET requests" do
  84. @checker.options['method'] = 'get'
  85. expect {
  86. expect {
  87. @checker.receive([@event])
  88. }.to change { @sent_requests[:get].length }.by(1)
  89. }.not_to change { @sent_requests[:post].length }
  90. expect(@sent_requests[:get][0].data).to eq(@event.payload.merge('default' => 'value').to_query)
  91. end
  92. it "can make a GET request merging params in post_url, payload and event" do
  93. @checker.options['method'] = 'get'
  94. @checker.options['post_url'] = "http://example.com/a/path?existing_param=existing_value"
  95. @event.payload = {
  96. "some_param" => "some_value",
  97. "another_param" => "another_value"
  98. }
  99. @checker.receive([@event])
  100. uri = @sent_requests[:get].first.uri
  101. # parameters are alphabetically sorted by Faraday
  102. expect(uri.request_uri).to eq("/a/path?another_param=another_value&default=value&existing_param=existing_value&some_param=some_value")
  103. end
  104. it "can skip merging the incoming event when no_merge is set, but it still interpolates" do
  105. @checker.options['no_merge'] = 'true'
  106. @checker.options['payload'] = {
  107. 'key' => 'it said: {{ someotherkey.somekey }}'
  108. }
  109. @checker.receive([@event])
  110. expect(@sent_requests[:post].first.data).to eq({ 'key' => 'it said: value' }.to_query)
  111. end
  112. it "interpolates when receiving a payload" do
  113. @checker.options['post_url'] = "https://{{ domain }}/{{ variable }}?existing_param=existing_value"
  114. @event.payload = {
  115. 'domain' => 'google.com',
  116. 'variable' => 'a_variable'
  117. }
  118. @checker.receive([@event])
  119. uri = @sent_requests[:post].first.uri
  120. expect(uri.scheme).to eq('https')
  121. expect(uri.host).to eq('google.com')
  122. expect(uri.path).to eq('/a_variable')
  123. expect(uri.query).to eq("existing_param=existing_value")
  124. end
  125. it "interpolates outgoing headers with the event payload" do
  126. @checker.options['headers'] = {
  127. "Foo" => "{{ variable }}"
  128. }
  129. @event.payload = {
  130. 'variable' => 'a_variable'
  131. }
  132. @checker.receive([@event])
  133. headers = @sent_requests[:post].first.headers
  134. expect(headers["Foo"]).to eq("a_variable")
  135. end
  136. end
  137. describe "#check" do
  138. it "sends options['payload'] as a POST request" do
  139. expect {
  140. @checker.check
  141. }.to change { @sent_requests[:post].length }.by(1)
  142. expect(@sent_requests[:post][0].data).to eq(@checker.options['payload'].to_query)
  143. end
  144. it "sends options['payload'] as JSON as a POST request" do
  145. @checker.options['content_type'] = 'json'
  146. expect {
  147. @checker.check
  148. }.to change { @sent_requests[:post].length }.by(1)
  149. expect(@sent_requests[:post][0].data).to eq(@checker.options['payload'])
  150. end
  151. it "sends options['payload'] as XML as a POST request" do
  152. @checker.options['content_type'] = 'xml'
  153. expect {
  154. @checker.check
  155. }.to change { @sent_requests[:post].length }.by(1)
  156. expect(@sent_requests[:post][0].data.keys).to eq([ 'post' ])
  157. expect(@sent_requests[:post][0].data['post']).to eq(@checker.options['payload'])
  158. end
  159. it "sends options['payload'] as XML with custom root element name, as a POST request" do
  160. @checker.options['content_type'] = 'xml'
  161. @checker.options['xml_root'] = 'foobar'
  162. expect {
  163. @checker.check
  164. }.to change { @sent_requests[:post].length }.by(1)
  165. expect(@sent_requests[:post][0].data.keys).to eq([ 'foobar' ])
  166. expect(@sent_requests[:post][0].data['foobar']).to eq(@checker.options['payload'])
  167. end
  168. it "sends options['payload'] as a GET request" do
  169. @checker.options['method'] = 'get'
  170. expect {
  171. expect {
  172. @checker.check
  173. }.to change { @sent_requests[:get].length }.by(1)
  174. }.not_to change { @sent_requests[:post].length }
  175. expect(@sent_requests[:get][0].data).to eq(@checker.options['payload'].to_query)
  176. end
  177. it "sends options['payload'] as a string POST request when content-type continas a MIME type" do
  178. @checker.options['payload'] = '<test>hello</test>'
  179. @checker.options['content_type'] = 'application/xml'
  180. expect {
  181. @checker.check
  182. }.to change { @sent_requests[:post].length }.by(1)
  183. expect(@sent_requests[:post][0].data).to eq('<test>hello</test>')
  184. end
  185. it "interpolates outgoing headers" do
  186. @checker.options['headers'] = {
  187. "Foo" => "{% credential aws_key %}"
  188. }
  189. @checker.check
  190. headers = @sent_requests[:post].first.headers
  191. expect(headers["Foo"]).to eq("2222222222-jane")
  192. end
  193. describe "emitting events" do
  194. context "when emit_events is not set to true" do
  195. it "does not emit events" do
  196. expect {
  197. @checker.check
  198. }.not_to change { @checker.events.count }
  199. end
  200. end
  201. context "when emit_events is set to true" do
  202. before do
  203. @checker.options['emit_events'] = 'true'
  204. @checker.save!
  205. end
  206. it "emits the response status" do
  207. expect {
  208. @checker.check
  209. }.to change { @checker.events.count }.by(1)
  210. expect(@checker.events.last.payload['status']).to eq 200
  211. end
  212. it "emits the body" do
  213. @checker.check
  214. expect(@checker.events.last.payload['body']).to eq '<html>a webpage!</html>'
  215. end
  216. it "emits the response headers capitalized by default" do
  217. @checker.check
  218. expect(@checker.events.last.payload['headers']).to eq({ 'Content-Type' => 'text/html' })
  219. end
  220. it "emits the response headers capitalized" do
  221. @checker.options['event_headers_style'] = 'capitalized'
  222. @checker.check
  223. expect(@checker.events.last.payload['headers']).to eq({ 'Content-Type' => 'text/html' })
  224. end
  225. it "emits the response headers downcased" do
  226. @checker.options['event_headers_style'] = 'downcased'
  227. @checker.check
  228. expect(@checker.events.last.payload['headers']).to eq({ 'content-type' => 'text/html' })
  229. end
  230. it "emits the response headers snakecased" do
  231. @checker.options['event_headers_style'] = 'snakecased'
  232. @checker.check
  233. expect(@checker.events.last.payload['headers']).to eq({ 'content_type' => 'text/html' })
  234. end
  235. end
  236. end
  237. end
  238. describe "#working?" do
  239. it "checks if events have been received within expected receive period" do
  240. expect(@checker).not_to be_working
  241. Agents::PostAgent.async_receive @checker.id, [@event.id]
  242. expect(@checker.reload).to be_working
  243. two_days_from_now = 2.days.from_now
  244. stub(Time).now { two_days_from_now }
  245. expect(@checker.reload).not_to be_working
  246. end
  247. end
  248. describe "validation" do
  249. before do
  250. expect(@checker).to be_valid
  251. end
  252. it "should validate presence of post_url" do
  253. @checker.options['post_url'] = ""
  254. expect(@checker).not_to be_valid
  255. end
  256. it "should validate presence of expected_receive_period_in_days" do
  257. @checker.options['expected_receive_period_in_days'] = ""
  258. expect(@checker).not_to be_valid
  259. end
  260. it "should validate method as post, get, put, patch, or delete, defaulting to post" do
  261. @checker.options['method'] = ""
  262. expect(@checker.method).to eq("post")
  263. expect(@checker).to be_valid
  264. @checker.options['method'] = "POST"
  265. expect(@checker.method).to eq("post")
  266. expect(@checker).to be_valid
  267. @checker.options['method'] = "get"
  268. expect(@checker.method).to eq("get")
  269. expect(@checker).to be_valid
  270. @checker.options['method'] = "patch"
  271. expect(@checker.method).to eq("patch")
  272. expect(@checker).to be_valid
  273. @checker.options['method'] = "wut"
  274. expect(@checker.method).to eq("wut")
  275. expect(@checker).not_to be_valid
  276. end
  277. it "should validate that no_merge is 'true' or 'false', if present" do
  278. @checker.options['no_merge'] = ""
  279. expect(@checker).to be_valid
  280. @checker.options['no_merge'] = "true"
  281. expect(@checker).to be_valid
  282. @checker.options['no_merge'] = "false"
  283. expect(@checker).to be_valid
  284. @checker.options['no_merge'] = false
  285. expect(@checker).to be_valid
  286. @checker.options['no_merge'] = true
  287. expect(@checker).to be_valid
  288. @checker.options['no_merge'] = 'blarg'
  289. expect(@checker).not_to be_valid
  290. end
  291. it "should validate payload as a hash, if present" do
  292. @checker.options['payload'] = ""
  293. expect(@checker).to be_valid
  294. @checker.options['payload'] = "hello"
  295. expect(@checker).not_to be_valid
  296. @checker.options['payload'] = ["foo", "bar"]
  297. expect(@checker).not_to be_valid
  298. @checker.options['payload'] = { 'this' => 'that' }
  299. expect(@checker).to be_valid
  300. end
  301. it "should not validate payload as a hash if content_type includes a MIME type and method is not get or delete" do
  302. @checker.options['no_merge'] = 'true'
  303. @checker.options['content_type'] = 'text/xml'
  304. @checker.options['payload'] = "test"
  305. expect(@checker).to be_valid
  306. @checker.options['method'] = 'get'
  307. expect(@checker).not_to be_valid
  308. @checker.options['method'] = 'delete'
  309. expect(@checker).not_to be_valid
  310. end
  311. it "requires `no_merge` to be set to true when content_type contains a MIME type" do
  312. @checker.options['content_type'] = 'text/xml'
  313. @checker.options['payload'] = "test"
  314. expect(@checker).not_to be_valid
  315. end
  316. it "requires headers to be a hash, if present" do
  317. @checker.options['headers'] = [1,2,3]
  318. expect(@checker).not_to be_valid
  319. @checker.options['headers'] = "hello world"
  320. expect(@checker).not_to be_valid
  321. @checker.options['headers'] = ""
  322. expect(@checker).to be_valid
  323. @checker.options['headers'] = {}
  324. expect(@checker).to be_valid
  325. @checker.options['headers'] = { "Authorization" => "foo bar" }
  326. expect(@checker).to be_valid
  327. end
  328. it "requires emit_events to be true or false" do
  329. @checker.options['emit_events'] = 'what?'
  330. expect(@checker).not_to be_valid
  331. @checker.options.delete('emit_events')
  332. expect(@checker).to be_valid
  333. @checker.options['emit_events'] = 'true'
  334. expect(@checker).to be_valid
  335. @checker.options['emit_events'] = 'false'
  336. expect(@checker).to be_valid
  337. @checker.options['emit_events'] = true
  338. expect(@checker).to be_valid
  339. end
  340. end
  341. end