agent_spec.rb 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. require 'spec_helper'
  2. describe Agent do
  3. describe ".run_schedule" do
  4. before do
  5. Agents::WeatherAgent.count.should > 0
  6. Agents::WebsiteAgent.count.should > 0
  7. end
  8. it "runs agents with the given schedule" do
  9. weather_agent_ids = [agents(:bob_weather_agent), agents(:jane_weather_agent)].map(&:id)
  10. stub(Agents::WeatherAgent).async_check(anything) {|agent_id| weather_agent_ids.delete(agent_id) }
  11. stub(Agents::WebsiteAgent).async_check(agents(:bob_website_agent).id)
  12. Agent.run_schedule("midnight")
  13. weather_agent_ids.should be_empty
  14. end
  15. it "groups agents by type" do
  16. mock(Agents::WeatherAgent).bulk_check("midnight").once
  17. mock(Agents::WebsiteAgent).bulk_check("midnight").once
  18. Agent.run_schedule("midnight")
  19. end
  20. it "only runs agents with the given schedule" do
  21. do_not_allow(Agents::WebsiteAgent).async_check
  22. Agent.run_schedule("blah")
  23. end
  24. end
  25. describe "changes to type" do
  26. it "validates types" do
  27. source = Agent.new
  28. source.type = "Agents::WeatherAgent"
  29. source.should have(0).errors_on(:type)
  30. source.type = "Agents::WebsiteAgent"
  31. source.should have(0).errors_on(:type)
  32. source.type = "Agents::Fake"
  33. source.should have(1).error_on(:type)
  34. end
  35. it "disallows changes to type once a record has been saved" do
  36. source = agents(:bob_website_agent)
  37. source.type = "Agents::WeatherAgent"
  38. source.should have(1).error_on(:type)
  39. end
  40. it "should know about available types" do
  41. Agent.types.should include(Agents::WeatherAgent, Agents::WebsiteAgent)
  42. end
  43. end
  44. describe "with a mock source" do
  45. class Agents::SomethingSource < Agent
  46. default_schedule "2pm"
  47. def check
  48. create_event :payload => {}
  49. end
  50. def validate_options
  51. errors.add(:base, "bad is bad") if options[:bad]
  52. end
  53. end
  54. class Agents::CannotBeScheduled < Agent
  55. cannot_be_scheduled!
  56. end
  57. before do
  58. stub(Agents::SomethingSource).valid_type?("Agents::SomethingSource") { true }
  59. stub(Agents::CannotBeScheduled).valid_type?("Agents::CannotBeScheduled") { true }
  60. end
  61. describe ".default_schedule" do
  62. it "stores the default on the class" do
  63. Agents::SomethingSource.default_schedule.should == "2pm"
  64. Agents::SomethingSource.new.default_schedule.should == "2pm"
  65. end
  66. it "sets the default on new instances, allows setting new schedules, and prevents invalid schedules" do
  67. @checker = Agents::SomethingSource.new(:name => "something")
  68. @checker.user = users(:bob)
  69. @checker.schedule.should == "2pm"
  70. @checker.save!
  71. @checker.reload.schedule.should == "2pm"
  72. @checker.update_attribute :schedule, "5pm"
  73. @checker.reload.schedule.should == "5pm"
  74. @checker.reload.schedule.should == "5pm"
  75. @checker.schedule = "this_is_not_real"
  76. @checker.should have(1).errors_on(:schedule)
  77. end
  78. it "should have an empty schedule if it cannot_be_scheduled" do
  79. @checker = Agents::CannotBeScheduled.new(:name => "something")
  80. @checker.user = users(:bob)
  81. @checker.schedule.should be_nil
  82. @checker.should be_valid
  83. @checker.schedule = "5pm"
  84. @checker.save!
  85. @checker.schedule.should be_nil
  86. @checker.schedule = "5pm"
  87. @checker.should have(0).errors_on(:schedule)
  88. @checker.schedule.should be_nil
  89. end
  90. end
  91. describe "#create_event" do
  92. it "should use the checker's user" do
  93. @checker = Agents::SomethingSource.new(:name => "something")
  94. @checker.user = users(:bob)
  95. @checker.save!
  96. @checker.check
  97. Event.last.user.should == @checker.user
  98. end
  99. end
  100. describe ".async_check" do
  101. it "records last_check_at and calls check on the given Agent" do
  102. @checker = Agents::SomethingSource.new(:name => "something")
  103. @checker.user = users(:bob)
  104. @checker.save!
  105. mock(@checker).check.once {
  106. @checker.options[:new] = true
  107. }
  108. mock(Agent).find(@checker.id) { @checker }
  109. @checker.last_check_at.should be_nil
  110. Agents::SomethingSource.async_check(@checker.id)
  111. @checker.reload.last_check_at.should be_within(2).of(Time.now)
  112. @checker.reload.options[:new].should be_true # Show that we save options
  113. end
  114. end
  115. describe ".receive!" do
  116. before do
  117. stub_request(:any, /wunderground/).to_return(:body => File.read(Rails.root.join("spec/data_fixtures/weather.json")), :status => 200)
  118. stub.any_instance_of(Agents::WeatherAgent).is_tomorrow?(anything) { true }
  119. end
  120. it "should use available events" do
  121. mock.any_instance_of(Agents::TriggerAgent).receive(anything).once
  122. Agent.async_check(agents(:bob_weather_agent).id)
  123. Agent.receive!
  124. end
  125. it "should track when events have been seen and not see them again" do
  126. mock.any_instance_of(Agents::TriggerAgent).receive(anything).once
  127. Agent.async_check(agents(:bob_weather_agent).id)
  128. Agent.receive!
  129. Agent.receive!
  130. end
  131. it "should not run consumers that have nothing to do" do
  132. do_not_allow.any_instance_of(Agents::TriggerAgent).receive(anything)
  133. Agent.receive!
  134. end
  135. it "should group events" do
  136. mock.any_instance_of(Agents::TriggerAgent).receive(anything).twice { |events|
  137. events.map(&:user).map(&:username).uniq.length.should == 1
  138. }
  139. Agent.async_check(agents(:bob_weather_agent).id)
  140. Agent.async_check(agents(:jane_weather_agent).id)
  141. Agent.receive!
  142. end
  143. end
  144. describe "validations" do
  145. it "calls validate_options" do
  146. agent = Agents::SomethingSource.new(:name => "something")
  147. agent.user = users(:bob)
  148. agent.options[:bad] = true
  149. agent.should have(1).error_on(:base)
  150. agent.options[:bad] = false
  151. agent.should have(0).errors_on(:base)
  152. end
  153. it "symbolizes options before validating" do
  154. agent = Agents::SomethingSource.new(:name => "something")
  155. agent.user = users(:bob)
  156. agent.options["bad"] = true
  157. agent.should have(1).error_on(:base)
  158. agent.options["bad"] = false
  159. agent.should have(0).errors_on(:base)
  160. end
  161. it "symbolizes memory before validating" do
  162. agent = Agents::SomethingSource.new(:name => "something")
  163. agent.user = users(:bob)
  164. agent.memory["bad"] = :hello
  165. agent.save
  166. agent.memory[:bad].should == :hello
  167. end
  168. it "should not allow agents owned by other people" do
  169. agent = Agents::SomethingSource.new(:name => "something")
  170. agent.user = users(:bob)
  171. agent.source_ids = [agents(:bob_weather_agent).id]
  172. agent.should have(0).errors_on(:sources)
  173. agent.source_ids = [agents(:jane_weather_agent).id]
  174. agent.should have(1).errors_on(:sources)
  175. agent.user = users(:jane)
  176. agent.should have(0).errors_on(:sources)
  177. end
  178. end
  179. end
  180. describe "scopes" do
  181. describe "of_type" do
  182. it "should accept classes" do
  183. agents = Agent.of_type(Agents::WebsiteAgent)
  184. agents.should include(agents(:bob_website_agent))
  185. agents.should include(agents(:jane_website_agent))
  186. agents.should_not include(agents(:bob_weather_agent))
  187. end
  188. it "should accept strings" do
  189. agents = Agent.of_type("Agents::WebsiteAgent")
  190. agents.should include(agents(:bob_website_agent))
  191. agents.should include(agents(:jane_website_agent))
  192. agents.should_not include(agents(:bob_weather_agent))
  193. end
  194. it "should accept instances of an Agent" do
  195. agents = Agent.of_type(agents(:bob_website_agent))
  196. agents.should include(agents(:bob_website_agent))
  197. agents.should include(agents(:jane_website_agent))
  198. agents.should_not include(agents(:bob_weather_agent))
  199. end
  200. end
  201. end
  202. end