Răsfoiți Sursa

Migrate from RR to RSpec Mocks

This closes #3062.
Akinori MUSHA 3 ani în urmă
părinte
comite
4a532395b7
76 a modificat fișierele cu 555 adăugiri și 550 ștergeri
  1. 1 1
      Gemfile
  2. 1 2
      Gemfile.lock
  3. 1 1
      app/models/agents/human_task_agent.rb
  4. 2 2
      spec/concerns/dry_runnable_spec.rb
  5. 25 25
      spec/concerns/long_runnable_spec.rb
  6. 2 2
      spec/controllers/admin/users_controller_spec.rb
  7. 8 14
      spec/controllers/agents_controller_spec.rb
  8. 2 2
      spec/controllers/users/registrations_controller_spec.rb
  9. 1 1
      spec/controllers/web_requests_controller_spec.rb
  10. 3 3
      spec/db/seeds/admin_and_default_scenario_spec.rb
  11. 18 18
      spec/helpers/application_helper_spec.rb
  12. 3 3
      spec/helpers/dot_helper_spec.rb
  13. 13 13
      spec/importers/default_scenario_importer_spec.rb
  14. 1 1
      spec/jobs/agent_propagate_job_spec.rb
  15. 19 19
      spec/lib/agent_runner_spec.rb
  16. 4 4
      spec/lib/delayed_job_worker_spec.rb
  17. 1 1
      spec/lib/google_calendar_spec.rb
  18. 9 9
      spec/lib/huginn_scheduler_spec.rb
  19. 3 3
      spec/lib/utils_spec.rb
  20. 1 1
      spec/models/agent_log_spec.rb
  21. 66 51
      spec/models/agent_spec.rb
  22. 1 1
      spec/models/agents/adioso_agent_spec.rb
  23. 4 4
      spec/models/agents/boxcar_agent_spec.rb
  24. 2 2
      spec/models/agents/commander_agent_spec.rb
  25. 13 13
      spec/models/agents/data_output_agent_spec.rb
  26. 1 1
      spec/models/agents/delay_agent_spec.rb
  27. 1 1
      spec/models/agents/digest_agent_spec.rb
  28. 12 8
      spec/models/agents/dropbox_file_url_agent_spec.rb
  29. 17 9
      spec/models/agents/dropbox_watch_agent_spec.rb
  30. 1 2
      spec/models/agents/email_agent_spec.rb
  31. 1 2
      spec/models/agents/email_digest_agent_spec.rb
  32. 11 11
      spec/models/agents/evernote_agent_spec.rb
  33. 29 28
      spec/models/agents/ftpsite_agent_spec.rb
  34. 6 6
      spec/models/agents/google_calendar_publish_agent_spec.rb
  35. 1 1
      spec/models/agents/google_translation_agent_spec.rb
  36. 14 20
      spec/models/agents/growl_agent_spec.rb
  37. 4 12
      spec/models/agents/hipchat_agent_spec.rb
  38. 33 33
      spec/models/agents/human_task_agent_spec.rb
  39. 10 10
      spec/models/agents/imap_folder_agent_spec.rb
  40. 16 15
      spec/models/agents/jabber_agent_spec.rb
  41. 2 2
      spec/models/agents/java_script_agent_spec.rb
  42. 4 8
      spec/models/agents/jira_agent_spec.rb
  43. 3 3
      spec/models/agents/jq_agent_spec.rb
  44. 1 1
      spec/models/agents/liquid_output_agent_spec.rb
  45. 16 16
      spec/models/agents/local_file_agent_spec.rb
  46. 1 1
      spec/models/agents/mqtt_agent_spec.rb
  47. 2 2
      spec/models/agents/pdf_agent_spec.rb
  48. 3 3
      spec/models/agents/post_agent_spec.rb
  49. 6 6
      spec/models/agents/pushbullet_agent_spec.rb
  50. 2 2
      spec/models/agents/pushover_agent_spec.rb
  51. 2 2
      spec/models/agents/read_file_agent_spec.rb
  52. 1 1
      spec/models/agents/rss_agent_spec.rb
  53. 27 27
      spec/models/agents/s3_agent_spec.rb
  54. 2 2
      spec/models/agents/scheduler_agent_spec.rb
  55. 1 1
      spec/models/agents/sentiment_agent_spec.rb
  56. 11 14
      spec/models/agents/shell_command_agent_spec.rb
  57. 2 4
      spec/models/agents/slack_agent_spec.rb
  58. 1 1
      spec/models/agents/stubhub_agent_spec.rb
  59. 1 1
      spec/models/agents/telegram_agent_spec.rb
  60. 1 1
      spec/models/agents/trigger_agent_spec.rb
  61. 6 5
      spec/models/agents/tumblr_likes_agent_spec.rb
  62. 8 7
      spec/models/agents/tumblr_publish_agent_spec.rb
  63. 16 18
      spec/models/agents/twilio_agent_spec.rb
  64. 1 1
      spec/models/agents/twilio_receive_text_agent_spec.rb
  65. 9 9
      spec/models/agents/twitter_action_agent_spec.rb
  66. 2 2
      spec/models/agents/twitter_publish_agent_spec.rb
  67. 47 38
      spec/models/agents/twitter_stream_agent_spec.rb
  68. 1 1
      spec/models/agents/website_agent_spec.rb
  69. 4 4
      spec/models/agents/weibo_publish_agent_spec.rb
  70. 1 1
      spec/models/agents/witai_agent_spec.rb
  71. 2 2
      spec/models/event_spec.rb
  72. 1 1
      spec/models/service_spec.rb
  73. 2 2
      spec/models/user_spec.rb
  74. 1 2
      spec/rails_helper.rb
  75. 2 2
      spec/support/shared_examples/agent_controller_concern.rb
  76. 2 2
      spec/support/shared_examples/file_handling_consumer.rb

+ 1 - 1
Gemfile

@@ -158,8 +158,8 @@ group :development do
     gem 'poltergeist'
     gem 'pry-rails'
     gem 'pry-byebug'
-    gem 'rr', '< 3', require: false
     gem 'rspec', '~> 3.8'
+    gem 'rspec-mocks'
     gem 'rspec-rails'
     gem 'rspec-collection_matchers', '~> 1.1.0'
     gem 'rspec-html-matchers', '~> 0.8'

+ 1 - 2
Gemfile.lock

@@ -576,7 +576,6 @@ GEM
     retriable (3.1.2)
     rexml (3.2.5)
     rly (0.2.3)
-    rr (1.1.2)
     rspec (3.8.0)
       rspec-core (~> 3.8.0)
       rspec-expectations (~> 3.8.0)
@@ -798,10 +797,10 @@ DEPENDENCIES
   rails-controller-testing
   rails-html-sanitizer (~> 1.2)
   rb-kqueue (>= 0.2)
-  rr (< 3)
   rspec (~> 3.8)
   rspec-collection_matchers (~> 1.1.0)
   rspec-html-matchers (~> 0.8)
+  rspec-mocks
   rspec-rails
   rturk (~> 2.12.1)
   ruby-growl (~> 4.1.0)

+ 1 - 1
app/models/agents/human_task_agent.rb

@@ -406,7 +406,7 @@ module Agents
         title = interpolate_string(opts['title'], payload).strip
         description = interpolate_string(opts['description'], payload).strip
         questions = interpolate_options(opts['questions'], payload)
-        hit = RTurk::Hit.create(:title => title) do |hit|
+        hit = RTurk::Hit.create(title: title) do |hit|
           hit.max_assignments = (opts['assignments'] || 1).to_i
           hit.description = description
           hit.lifetime = (opts['lifetime_in_seconds'] || 24 * 60 * 60).to_i

+ 2 - 2
spec/concerns/dry_runnable_spec.rb

@@ -29,7 +29,7 @@ describe DryRunnable do
   end
 
   before do
-    stub(Agents::SandboxedAgent).valid_type?("Agents::SandboxedAgent") { true }
+    allow(Agents::SandboxedAgent).to receive(:valid_type?).with("Agents::SandboxedAgent") { true }
 
     @agent = Agents::SandboxedAgent.create(name: "some agent") { |agent|
       agent.user = users(:bob)
@@ -59,7 +59,7 @@ describe DryRunnable do
   end
 
   it "does not perform dry-run if Agent does not support dry-run" do
-    stub(@agent).can_dry_run? { false }
+    allow(@agent).to receive(:can_dry_run?) { false }
 
     results = nil
 

+ 25 - 25
spec/concerns/long_runnable_spec.rb

@@ -23,7 +23,7 @@ describe LongRunnable do
 
   context "#setup_worker" do
     it "returns active agent workers" do
-      mock(LongRunnableAgent).active { [@agent] }
+      expect(LongRunnableAgent).to receive(:active) { [@agent] }
       workers = LongRunnableAgent.setup_worker
       expect(workers.length).to eq(1)
       expect(workers.first).to be_a(LongRunnableAgent::Worker)
@@ -31,7 +31,7 @@ describe LongRunnable do
     end
 
     it "returns an empty array when no agent is active" do
-      mock(LongRunnableAgent).active { [] }
+      expect(LongRunnableAgent).to receive(:active) { [] }
       workers = LongRunnableAgent.setup_worker
       expect(workers.length).to eq(0)
     end
@@ -51,7 +51,7 @@ describe LongRunnable do
     end
 
     it "calls boolify of the agent" do
-      mock(@agent).boolify('true') { true }
+      expect(@agent).to receive(:boolify).with('true') { true }
       expect(@worker.boolify('true')).to be_truthy
     end
 
@@ -61,32 +61,32 @@ describe LongRunnable do
 
     context "#run!" do
       it "runs the agent worker" do
-        mock(@worker).run
+        expect(@worker).to receive(:run)
         @worker.run!.join
       end
 
       it "stops when rescueing a SystemExit" do
-        mock(@worker).run { raise SystemExit }
-        mock(@worker).stop!
+        expect(@worker).to receive(:run) { raise SystemExit }
+        expect(@worker).to receive(:stop!)
         @worker.run!.join
       end
 
       it "creates an agent log entry for a generic exception" do
-        stub(STDERR).puts
-        mock(@worker).run { raise "woups" }
-        mock(@agent).error(/woups/)
+        allow(STDERR).to receive(:puts)
+        expect(@worker).to receive(:run) { raise "woups" }
+        expect(@agent).to receive(:error).with(/woups/)
         @worker.run!.join
       end
     end
 
     context "#stop!" do
       it "terminates the thread" do
-        mock.proxy(@worker).terminate_thread!
+        expect(@worker).to receive(:terminate_thread!)
         @worker.stop!
       end
 
       it "gracefully stops the worker" do
-        mock(@worker).stop
+        expect(@worker).to receive(:stop)
         @worker.stop!
       end
     end
@@ -95,47 +95,47 @@ describe LongRunnable do
       before do
         @skip_thread_terminate = true
         mock_thread = Object.new
-        stub(@worker).thread { mock_thread }
+        allow(@worker).to receive(:thread) { mock_thread }
       end
 
       it "terminates the thread" do
-        mock(@worker.thread).terminate
-        do_not_allow(@worker.thread).wakeup
-        mock(@worker.thread).status { 'run' }
+        expect(@worker.thread).to receive(:terminate)
+        expect(@worker.thread).not_to receive(:wakeup)
+        expect(@worker.thread).to receive(:status) { 'run' }
         @worker.terminate_thread!
       end
 
       it "wakes up sleeping threads after termination" do
-        mock(@worker.thread).terminate
-        mock(@worker.thread).wakeup
-        mock(@worker.thread).status { 'sleep' }
+        expect(@worker.thread).to receive(:terminate)
+        expect(@worker.thread).to receive(:wakeup)
+        expect(@worker.thread).to receive(:status) { 'sleep' }
         @worker.terminate_thread!
       end
     end
 
     context "#restart!" do
       it "stops, setups and starts the worker" do
-        mock(@worker).stop!
-        mock(@worker).setup!(@worker.scheduler, @worker.mutex)
-        mock(@worker).run!
-        mock(@worker).puts(anything) { |text| expect(text).to match(/Restarting/) }
+        expect(@worker).to receive(:stop!)
+        expect(@worker).to receive(:setup!).with(@worker.scheduler, @worker.mutex)
+        expect(@worker).to receive(:run!)
+        expect(@worker).to receive(:puts).with(anything) { |text| expect(text).to match(/Restarting/) }
         @worker.restart!
       end
     end
 
     context "scheduling" do
       it "schedules tasks once" do
-        mock(@worker.scheduler).send(:schedule_in, 1.hour, tag: 'test1234')
+        expect(@worker.scheduler).to receive(:send).with(:schedule_in, 1.hour, tag: 'test1234')
         @worker.schedule_in 1.hour do noop; end
       end
 
       it "schedules repeating tasks" do
-        mock(@worker.scheduler).send(:every, 1.hour, tag: 'test1234')
+        expect(@worker.scheduler).to receive(:send).with(:every, 1.hour, tag: 'test1234')
         @worker.every 1.hour do noop; end
       end
 
       it "allows the cron syntax" do
-        mock(@worker.scheduler).send(:cron, '0 * * * *', tag: 'test1234')
+        expect(@worker.scheduler).to receive(:send).with(:cron, '0 * * * *', tag: 'test1234')
         @worker.cron '0 * * * *' do noop; end
       end
     end

+ 2 - 2
spec/controllers/admin/users_controller_spec.rb

@@ -4,7 +4,7 @@ describe Admin::UsersController do
   describe 'POST #create' do
     context 'with valid user params' do
       it 'imports the default scenario for the new user' do
-        mock(DefaultScenarioImporter).import(is_a(User))
+        expect(DefaultScenarioImporter).to receive(:import).with(kind_of(User))
         sign_in users(:jane)
         post :create, params: {:user => {username: 'jdoe', email: 'jdoe@example.com',
                                          password: 's3cr3t55', password_confirmation: 's3cr3t55', admin: false }}
@@ -13,7 +13,7 @@ describe Admin::UsersController do
     
     context 'with invalid user params' do
       it 'does not import the default scenario' do
-        stub(DefaultScenarioImporter).import(is_a(User)) { fail "Should not attempt import" }
+        allow(DefaultScenarioImporter).to receive(:import).with(kind_of(User)) { fail "Should not attempt import" }
         sign_in users(:jane)
         post :create, params: {:user => {username: 'user'}}
       end

+ 8 - 14
spec/controllers/agents_controller_spec.rb

@@ -45,7 +45,7 @@ describe AgentsController do
   describe "POST run" do
     it "triggers Agent.async_check with the Agent's ID" do
       sign_in users(:bob)
-      mock(Agent).async_check(agents(:bob_manual_event_agent).id)
+      expect(Agent).to receive(:async_check).with(agents(:bob_manual_event_agent).id)
       post :run, params: {:id => agents(:bob_manual_event_agent).to_param}
     end
 
@@ -62,14 +62,14 @@ describe AgentsController do
     let(:params) { { :id => agent.to_param } }
 
     it "enqueues an AgentReemitJob" do
-      mock(AgentReemitJob).perform_later(agent, agent.most_recent_event.id, false)
+      expect(AgentReemitJob).to receive(:perform_later).with(agent, agent.most_recent_event.id, false)
       sign_in users(:bob)
       post :reemit_events, params: params
     end
 
     context "when delete_old_events passed" do
       it "enqueues an AgentReemitJob with delete_old_events set to true" do
-        mock(AgentReemitJob).perform_later(agent, agent.most_recent_event.id, true)
+        expect(AgentReemitJob).to receive(:perform_later).with(agent, agent.most_recent_event.id, true)
         sign_in users(:bob)
         post :reemit_events, params: params.merge('delete_old_events' => '1')
       end
@@ -122,12 +122,12 @@ describe AgentsController do
     end
 
     it "runs event propagation for all Agents" do
-      mock.proxy(Agent).receive!
+      expect(Agent).to receive(:receive!).and_call_original
       post :propagate
     end
 
     it "does not run the propagation when a job is already enqueued" do
-      mock(AgentPropagateJob).can_enqueue? { false }
+      expect(AgentPropagateJob).to receive(:can_enqueue?) { false }
       post :propagate
       expect(flash[:notice]).to eq('Event propagation is already scheduled to run.')
     end
@@ -409,18 +409,14 @@ describe AgentsController do
     describe "POST validate" do
 
       it "returns with status 200 when called with a valid option" do
-        any_instance_of(Agents::HipchatAgent) do |klass|
-          stub(klass).validate_option { true }
-        end
+        allow_any_instance_of(Agents::HipchatAgent).to receive(:validate_option) { true }
 
         post :validate, params: @params
         expect(response.status).to eq 200
       end
 
       it "returns with status 403 when called with an invalid option" do
-        any_instance_of(Agents::HipchatAgent) do |klass|
-          stub(klass).validate_option { false }
-        end
+        allow_any_instance_of(Agents::HipchatAgent).to receive(:validate_option) { false }
 
         post :validate, params: @params
         expect(response.status).to eq 403
@@ -429,9 +425,7 @@ describe AgentsController do
 
     describe "POST complete" do
       it "callsAgent#complete_option and renders json" do
-        any_instance_of(Agents::HipchatAgent) do |klass|
-          stub(klass).complete_option { [{name: 'test', value: 1}] }
-        end
+        allow_any_instance_of(Agents::HipchatAgent).to receive(:complete_option) { [{name: 'test', value: 1}] }
 
         post :complete, params: @params
         expect(response.status).to eq 200

+ 2 - 2
spec/controllers/users/registrations_controller_spec.rb

@@ -9,7 +9,7 @@ module Users
 
       context 'with valid params' do
         it "imports the default scenario for the new user" do
-          mock(DefaultScenarioImporter).import(is_a(User))
+          expect(DefaultScenarioImporter).to receive(:import).with(kind_of(User))
 
           post :create, params: {
             :user => {username: 'jdoe', email: 'jdoe@example.com',
@@ -20,7 +20,7 @@ module Users
 
       context 'with invalid params' do
         it "does not import the default scenario" do
-          stub(DefaultScenarioImporter).import(is_a(User)) { fail "Should not attempt import" }
+          allow(DefaultScenarioImporter).to receive(:import).with(kind_of(User)) { fail "Should not attempt import" }
 
           setup_controller_for_warden
           post :create, params: {:user => {}}

+ 1 - 1
spec/controllers/web_requests_controller_spec.rb

@@ -18,7 +18,7 @@ describe WebRequestsController do
   end
 
   before do
-    stub(Agents::WebRequestReceiverAgent).valid_type?("Agents::WebRequestReceiverAgent") { true }
+    allow(Agents::WebRequestReceiverAgent).to receive(:valid_type?).with("Agents::WebRequestReceiverAgent") { true }
     @agent = Agents::WebRequestReceiverAgent.new(:name => "something", :options => { :secret => "my_secret" })
     @agent.user = users(:bob)
     @agent.save!

+ 3 - 3
spec/db/seeds/admin_and_default_scenario_spec.rb

@@ -23,13 +23,13 @@ describe Seeder do
 
     it 'can be run multiple times and exit normally' do
       Seeder.seed
-      mock(Seeder).exit
+      expect(Seeder).to receive(:exit)
       Seeder.seed
     end
   end
 
   def stub_puts_to_prevent_spew_in_spec_output
-    stub(Seeder).puts(anything)
-    stub(Seeder).puts
+    allow(Seeder).to receive(:puts).with(anything)
+    allow(Seeder).to receive(:puts)
   end
 end

+ 18 - 18
spec/helpers/application_helper_spec.rb

@@ -29,14 +29,14 @@ describe ApplicationHelper do
 
   describe '#nav_link' do
     it 'returns a nav link' do
-      stub(self).current_page?('/things') { false }
+      allow(self).to receive(:current_page?).with('/things') { false }
       nav = nav_link('Things', '/things')
       a = Nokogiri(nav).at('li:not(.active) > a[href="/things"]')
       expect(a.text.strip).to eq('Things')
     end
 
     it 'returns an active nav link' do
-      stub(self).current_page?('/things') { true }
+      allow(self).to receive(:current_page?).with('/things') { true }
       nav = nav_link('Things', '/things')
       expect(nav).to be_html_safe
       a = Nokogiri(nav).at('li.active > a[href="/things"]')
@@ -46,8 +46,8 @@ describe ApplicationHelper do
 
     describe 'with block' do
       it 'returns a nav link with menu' do
-        stub(self).current_page?('/things') { false }
-        stub(self).current_page?('/things/stuff') { false }
+        allow(self).to receive(:current_page?).with('/things') { false }
+        allow(self).to receive(:current_page?).with('/things/stuff') { false }
         nav = nav_link('Things', '/things') { nav_link('Stuff', '/things/stuff') }
         expect(nav).to be_html_safe
         a0 = Nokogiri(nav).at('li.dropdown.dropdown-hover:not(.active) > a[href="/things"]')
@@ -59,8 +59,8 @@ describe ApplicationHelper do
       end
 
       it 'returns an active nav link with menu' do
-        stub(self).current_page?('/things') { true }
-        stub(self).current_page?('/things/stuff') { false }
+        allow(self).to receive(:current_page?).with('/things') { true }
+        allow(self).to receive(:current_page?).with('/things/stuff') { false }
         nav = nav_link('Things', '/things') { nav_link('Stuff', '/things/stuff') }
         expect(nav).to be_html_safe
         a0 = Nokogiri(nav).at('li.dropdown.dropdown-hover.active > a[href="/things"]')
@@ -72,8 +72,8 @@ describe ApplicationHelper do
       end
 
       it 'returns an active nav link with menu when on a child page' do
-        stub(self).current_page?('/things') { false }
-        stub(self).current_page?('/things/stuff') { true }
+        allow(self).to receive(:current_page?).with('/things') { false }
+        allow(self).to receive(:current_page?).with('/things/stuff') { true }
         nav = nav_link('Things', '/things') { nav_link('Stuff', '/things/stuff') }
         expect(nav).to be_html_safe
         a0 = Nokogiri(nav).at('li.dropdown.dropdown-hover.active > a[href="/things"]')
@@ -110,28 +110,28 @@ describe ApplicationHelper do
     end
 
     it 'returns a label "Disabled" if a given agent is disabled' do
-      stub(@agent).disabled? { true }
+      allow(@agent).to receive(:disabled?) { true }
       label = working(@agent)
       expect(label).to be_html_safe
       expect(Nokogiri(label).text).to eq 'Disabled'
     end
 
     it 'returns a label "Missing Gems" if a given agent has dependencies missing' do
-      stub(@agent).dependencies_missing? { true }
+      allow(@agent).to receive(:dependencies_missing?) { true }
       label = working(@agent)
       expect(label).to be_html_safe
       expect(Nokogiri(label).text).to eq 'Missing Gems'
     end
 
     it 'returns a label "Yes" if a given agent is working' do
-      stub(@agent).working? { true }
+      allow(@agent).to receive(:working?) { true }
       label = working(@agent)
       expect(label).to be_html_safe
       expect(Nokogiri(label).text).to eq 'Yes'
     end
 
     it 'returns a label "No" if a given agent is not working' do
-      stub(@agent).working? { false }
+      allow(@agent).to receive(:working?) { false }
       label = working(@agent)
       expect(label).to be_html_safe
       expect(Nokogiri(label).text).to eq 'No'
@@ -163,32 +163,32 @@ describe ApplicationHelper do
 
   describe '#highlighted?' do
     it 'understands hl=6-8' do
-      stub(params).[](:hl) { '6-8' }
+      allow(params).to receive(:[]).with(:hl) { '6-8' }
       expect((1..10).select { |i| highlighted?(i) }).to eq [6, 7, 8]
     end
 
     it 'understands hl=1,3-4,9' do
-      stub(params).[](:hl) { '1,3-4,9' }
+      allow(params).to receive(:[]).with(:hl) { '1,3-4,9' }
       expect((1..10).select { |i| highlighted?(i) }).to eq [1, 3, 4, 9]
     end
 
     it 'understands hl=8-' do
-      stub(params).[](:hl) { '8-' }
+      allow(params).to receive(:[]).with(:hl) { '8-' }
       expect((1..10).select { |i| highlighted?(i) }).to eq [8, 9, 10]
     end
 
     it 'understands hl=-2' do
-      stub(params).[](:hl) { '-2' }
+      allow(params).to receive(:[]).with(:hl) { '-2' }
       expect((1..10).select { |i| highlighted?(i) }).to eq [1, 2]
     end
 
     it 'understands hl=-' do
-      stub(params).[](:hl) { '-' }
+      allow(params).to receive(:[]).with(:hl) { '-' }
       expect((1..10).select { |i| highlighted?(i) }).to eq [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
     end
 
     it 'is OK with no hl' do
-      stub(params).[](:hl) { nil }
+      allow(params).to receive(:[]).with(:hl) { nil }
       expect((1..10).select { |i| highlighted?(i) }).to be_empty
     end
   end

+ 3 - 3
spec/helpers/dot_helper_spec.rb

@@ -19,8 +19,8 @@ describe DotHelper do
     end
 
     before do
-      stub(Agents::DotFoo).valid_type?("Agents::DotFoo") { true }
-      stub(Agents::DotBar).valid_type?("Agents::DotBar") { true }
+      allow(Agents::DotFoo).to receive(:valid_type?).with("Agents::DotFoo") { true }
+      allow(Agents::DotBar).to receive(:valid_type?).with("Agents::DotBar") { true }
     end
 
     describe "#agents_dot" do
@@ -56,7 +56,7 @@ describe DotHelper do
 
         # Fix the order of receivers
         @agents.each do |agent|
-          stub.proxy(agent).receivers { |orig| orig.order(:id) }
+          expect(agent).to receive(:receivers).and_wrap_original { |orig| orig.call.order(:id) }
         end
       end
 

+ 13 - 13
spec/importers/default_scenario_importer_spec.rb

@@ -4,23 +4,23 @@ describe DefaultScenarioImporter do
   let(:user) { users(:bob) }
   describe '.import' do
     it 'imports a set of agents to get the user going when they are first created' do
-      mock(DefaultScenarioImporter).seed(is_a(User))
-      stub.proxy(ENV).[](anything)
-      stub(ENV).[]('IMPORT_DEFAULT_SCENARIO_FOR_ALL_USERS') { 'true' }
+      expect(DefaultScenarioImporter).to receive(:seed).with(kind_of(User))
+      allow(ENV).to receive(:[]) { nil }
+      allow(ENV).to receive(:[]).with('IMPORT_DEFAULT_SCENARIO_FOR_ALL_USERS') { 'true' }
       DefaultScenarioImporter.import(user)
     end
 
     it 'can be turned off' do
-      stub(DefaultScenarioImporter).seed { fail "seed should not have been called"}
-      stub.proxy(ENV).[](anything)
-      stub(ENV).[]('IMPORT_DEFAULT_SCENARIO_FOR_ALL_USERS') { 'false' }
+      allow(DefaultScenarioImporter).to receive(:seed) { fail "seed should not have been called"}
+      allow(ENV).to receive(:[]) { nil }
+      allow(ENV).to receive(:[]).with('IMPORT_DEFAULT_SCENARIO_FOR_ALL_USERS') { 'false' }
       DefaultScenarioImporter.import(user)
     end
 
     it 'is turned off for existing instances of Huginn' do
-      stub(DefaultScenarioImporter).seed { fail "seed should not have been called"}
-      stub.proxy(ENV).[](anything)
-      stub(ENV).[]('IMPORT_DEFAULT_SCENARIO_FOR_ALL_USERS') { nil }
+      allow(DefaultScenarioImporter).to receive(:seed) { fail "seed should not have been called"}
+      allow(ENV).to receive(:[]) { nil }
+      allow(ENV).to receive(:[]).with('IMPORT_DEFAULT_SCENARIO_FOR_ALL_USERS') { nil }
       DefaultScenarioImporter.import(user)
     end
 
@@ -32,14 +32,14 @@ describe DefaultScenarioImporter do
     end
 
     it 'respects an environment variable that specifies a path or URL to a different scenario' do
-      stub.proxy(ENV).[](anything)
-      stub(ENV).[]('DEFAULT_SCENARIO_FILE') { File.join(Rails.root, "spec", "fixtures", "test_default_scenario.json") }
+      allow(ENV).to receive(:[]) { nil }
+      allow(ENV).to receive(:[]).with('DEFAULT_SCENARIO_FILE') { File.join(Rails.root, "spec", "fixtures", "test_default_scenario.json") }
       expect { DefaultScenarioImporter.seed(user) }.to change(user.agents, :count).by(3)
     end
 
     it 'can not be turned off' do
-      stub.proxy(ENV).[](anything)
-      stub(ENV).[]('IMPORT_DEFAULT_SCENARIO_FOR_ALL_USERS') { 'true' }
+      allow(ENV).to receive(:[]) { nil }
+      allow(ENV).to receive(:[]).with('IMPORT_DEFAULT_SCENARIO_FOR_ALL_USERS') { 'true' }
       expect { DefaultScenarioImporter.seed(user) }.to change(user.agents, :count).by(7)
     end
   end

+ 1 - 1
spec/jobs/agent_propagate_job_spec.rb

@@ -2,7 +2,7 @@ require 'rails_helper'
 
 describe AgentPropagateJob do
   it "calls Agent.receive! when run" do
-    mock(Agent).receive!
+    expect(Agent).to receive(:receive!)
     AgentPropagateJob.new.perform
   end
 

+ 19 - 19
spec/lib/agent_runner_spec.rb

@@ -3,8 +3,8 @@ require 'rails_helper'
 describe AgentRunner do
   context "without traps" do
     before do
-      stub.instance_of(Rufus::Scheduler).every
-      stub.instance_of(AgentRunner).set_traps
+      allow_any_instance_of(Rufus::Scheduler).to receive(:every)
+      allow_any_instance_of(AgentRunner).to receive(:set_traps)
       @agent_runner = AgentRunner.new
     end
 
@@ -15,11 +15,11 @@ describe AgentRunner do
 
     context "#run" do
       before do
-        mock(@agent_runner).run_workers
+        allow(@agent_runner).to receive(:run_workers)
       end
 
       it "runs until stop is called" do
-        mock.instance_of(Rufus::Scheduler).join
+        expect_any_instance_of(Rufus::Scheduler).to receive(:join)
         Thread.new { while @agent_runner.instance_variable_get(:@running) != false do sleep 0.1; @agent_runner.stop end }
         @agent_runner.run
       end
@@ -60,37 +60,37 @@ describe AgentRunner do
     context "running workers" do
       before do
         AgentRunner.class_variable_set(:@@agents, [HuginnScheduler, DelayedJobWorker])
-        stub.instance_of(HuginnScheduler).setup
-        stub.instance_of(DelayedJobWorker).setup
+        allow_any_instance_of(HuginnScheduler).to receive(:setup)
+        allow_any_instance_of(DelayedJobWorker).to receive(:setup)
       end
 
       context "#run_workers" do
         it "runs all the workers" do
-          mock.instance_of(HuginnScheduler).run!
-          mock.instance_of(DelayedJobWorker).run!
+          expect_any_instance_of(HuginnScheduler).to receive(:run!)
+          expect_any_instance_of(DelayedJobWorker).to receive(:run!)
           @agent_runner.send(:run_workers)
         end
 
         it "kills no long active workers" do
-          mock.instance_of(HuginnScheduler).run!
-          mock.instance_of(DelayedJobWorker).run!
+          expect_any_instance_of(HuginnScheduler).to receive(:run!)
+          expect_any_instance_of(DelayedJobWorker).to receive(:run!)
           @agent_runner.send(:run_workers)
           AgentRunner.class_variable_set(:@@agents, [DelayedJobWorker])
-          mock.instance_of(HuginnScheduler).stop!
+          expect_any_instance_of(HuginnScheduler).to receive(:stop!)
           @agent_runner.send(:run_workers)
         end
       end
 
       context "#restart_dead_workers" do
         before do
-          mock.instance_of(HuginnScheduler).run!
-          mock.instance_of(DelayedJobWorker).run!
+          allow_any_instance_of(HuginnScheduler).to receive(:setup)
+          allow_any_instance_of(DelayedJobWorker).to receive(:setup)
           @agent_runner.send(:run_workers)
 
         end
         it "restarts dead workers" do
-          stub.instance_of(HuginnScheduler).thread { OpenStruct.new(alive?: false) }
-          mock.instance_of(HuginnScheduler).run!
+          expect_any_instance_of(HuginnScheduler).to receive(:thread) { OpenStruct.new(alive?: false) }
+          expect_any_instance_of(HuginnScheduler).to receive(:run!)
           @agent_runner.send(:restart_dead_workers)
         end
       end
@@ -100,12 +100,12 @@ describe AgentRunner do
   context "#set_traps" do
     it "sets traps for INT TERM and QUIT" do
       agent_runner = AgentRunner.new
-      mock(Signal).trap('INT')
-      mock(Signal).trap('TERM')
-      mock(Signal).trap('QUIT')
+      expect(Signal).to receive(:trap).with('INT')
+      expect(Signal).to receive(:trap).with('TERM')
+      expect(Signal).to receive(:trap).with('QUIT')
       agent_runner.set_traps
 
       agent_runner.stop
     end
   end
-end
+end

+ 4 - 4
spec/lib/delayed_job_worker_spec.rb

@@ -6,14 +6,14 @@ describe DelayedJobWorker do
   end
 
   it "should run" do
-    mock.instance_of(Delayed::Worker).start
+    expect_any_instance_of(Delayed::Worker).to receive(:start)
     @djw.run
   end
 
   it "should stop" do
-    mock.instance_of(Delayed::Worker).start
-    mock.instance_of(Delayed::Worker).stop
+    expect_any_instance_of(Delayed::Worker).to receive(:start)
     @djw.run
+    expect_any_instance_of(Delayed::Worker).to receive(:stop)
     @djw.stop
   end
 
@@ -25,4 +25,4 @@ describe DelayedJobWorker do
       expect(workers.first.id).to eq('DelayedJobWorker')
     end
   end
-end
+end

+ 1 - 1
spec/lib/google_calendar_spec.rb

@@ -2,7 +2,7 @@ require 'rails_helper'
 
 describe GoogleCalendar do
   it '#open does not mask exception in initlize' do
-    stub(Google::Apis::CalendarV3::CalendarService).new do
+    allow(Google::Apis::CalendarV3::CalendarService).to receive(:new) do
       raise "test exception"
     end
     expect {

+ 9 - 9
spec/lib/huginn_scheduler_spec.rb

@@ -5,7 +5,7 @@ describe HuginnScheduler do
   before(:each) do
     @rufus_scheduler = Rufus::Scheduler.new
     @scheduler = HuginnScheduler.new
-    stub(@scheduler).setup {}
+    allow(@scheduler).to receive(:setup)
     @scheduler.setup!(@rufus_scheduler, Mutex.new)
   end
 
@@ -14,27 +14,27 @@ describe HuginnScheduler do
   end
 
   it "schould register the schedules with the rufus scheduler and run" do
-    mock(@rufus_scheduler).join
+    expect(@rufus_scheduler).to receive(:join)
     scheduler = HuginnScheduler.new
     scheduler.setup!(@rufus_scheduler, Mutex.new)
     scheduler.run
   end
 
   it "should run scheduled agents" do
-    mock(Agent).run_schedule('every_1h')
-    mock.instance_of(IO).puts('Queuing schedule for every_1h')
+    expect(Agent).to receive(:run_schedule).with('every_1h')
+    expect_any_instance_of(IO).to receive(:puts).with('Queuing schedule for every_1h')
     @scheduler.send(:run_schedule, 'every_1h')
   end
 
   it "should propagate events" do
-    mock(Agent).receive!
-    stub.instance_of(IO).puts
+    expect(Agent).to receive(:receive!)
+    expect_any_instance_of(IO).to receive(:puts)
     @scheduler.send(:propagate!)
   end
 
   it "schould clean up expired events" do
-    mock(Event).cleanup_expired!
-    stub.instance_of(IO).puts
+    expect(Event).to receive(:cleanup_expired!)
+    expect_any_instance_of(IO).to receive(:puts)
     @scheduler.send(:cleanup_expired_events!)
   end
 
@@ -98,7 +98,7 @@ describe Rufus::Scheduler do
 
     @scheduler = Rufus::Scheduler.new
 
-    stub.any_instance_of(Agents::SchedulerAgent).second_precision_enabled { true }
+    allow_any_instance_of(Agents::SchedulerAgent).to receive(:second_precision_enabled) { true }
 
     @agent1 = Agents::SchedulerAgent.new(name: 'Scheduler 1', options: { action: 'run', schedule: '*/1 * * * * *' }).tap { |a|
       a.user = users(:bob)

+ 3 - 3
spec/lib/utils_spec.rb

@@ -180,7 +180,7 @@ describe Utils do
     end
 
     it "warns and returns nil when not parseable" do
-      mock(STDERR).puts("WARNING: Invalid duration format: 'bogus'")
+      expect(STDERR).to receive(:puts).with("WARNING: Invalid duration format: 'bogus'")
       expect(Utils.parse_duration('bogus')).to be_nil
     end
   end
@@ -191,8 +191,8 @@ describe Utils do
     end
 
     it "calls the specified method when the argument is present" do
-      argument = mock()
-      mock(argument).to_i { 1 }
+      argument = double()
+      expect(argument).to receive(:to_i) { 1 }
       expect(Utils.if_present(argument, :to_i)).to eq(1)
     end
   end

+ 1 - 1
spec/models/agent_log_spec.rb

@@ -68,7 +68,7 @@ describe AgentLog do
     end
 
     it "cleans up old logs when there are more than log_length" do
-      stub(AgentLog).log_length { 4 }
+      allow(AgentLog).to receive(:log_length) { 4 }
       AgentLog.log_for_agent(agents(:jane_website_agent), "message 1")
       AgentLog.log_for_agent(agents(:jane_website_agent), "message 2")
       AgentLog.log_for_agent(agents(:jane_website_agent), "message 3")

+ 66 - 51
spec/models/agent_spec.rb

@@ -37,19 +37,19 @@ describe Agent do
     end
 
     it "should run all Agents with the given schedule" do
-      mock(Agents::WeatherAgent).async_check(anything).times(@weather_agent_count)
+      expect(Agents::WeatherAgent).to receive(:async_check).with(anything).exactly(@weather_agent_count).times
       Agents::WeatherAgent.bulk_check("midnight")
     end
 
     it "should skip disabled Agents" do
       agents(:bob_weather_agent).update_attribute :disabled, true
-      mock(Agents::WeatherAgent).async_check(anything).times(@weather_agent_count - 1)
+      expect(Agents::WeatherAgent).to receive(:async_check).with(anything).exactly(@weather_agent_count - 1).times
       Agents::WeatherAgent.bulk_check("midnight")
     end
 
     it "should skip agents of deactivated accounts" do
       agents(:bob_weather_agent).user.deactivate!
-      mock(Agents::WeatherAgent).async_check(anything).times(@weather_agent_count - 1)
+      expect(Agents::WeatherAgent).to receive(:async_check).with(anything).exactly(@weather_agent_count - 1).times
       Agents::WeatherAgent.bulk_check("midnight")
     end
   end
@@ -62,53 +62,56 @@ describe Agent do
 
     it "runs agents with the given schedule" do
       weather_agent_ids = [agents(:bob_weather_agent), agents(:jane_weather_agent)].map(&:id)
-      stub(Agents::WeatherAgent).async_check(anything) {|agent_id| weather_agent_ids.delete(agent_id) }
-      stub(Agents::WebsiteAgent).async_check(agents(:bob_website_agent).id)
+      expect(Agents::WeatherAgent).to receive(:async_check) { |agent_id| weather_agent_ids.delete(agent_id) }.twice
+      expect(Agents::WebsiteAgent).to receive(:async_check).with(agents(:bob_website_agent).id)
       Agent.run_schedule("midnight")
       expect(weather_agent_ids).to be_empty
     end
 
     it "groups agents by type" do
-      mock(Agents::WeatherAgent).bulk_check("midnight").once
-      mock(Agents::WebsiteAgent).bulk_check("midnight").once
+      expect(Agents::WeatherAgent).to receive(:bulk_check).with("midnight").once
+      expect(Agents::WebsiteAgent).to receive(:bulk_check).with("midnight").once
       Agent.run_schedule("midnight")
     end
 
     it "ignores unknown types" do
       Agent.where(id: agents(:bob_weather_agent).id).update_all type: 'UnknownTypeAgent'
-      mock(Agents::WeatherAgent).bulk_check("midnight").once
-      mock(Agents::WebsiteAgent).bulk_check("midnight").once
+      expect(Agents::WeatherAgent).to receive(:bulk_check).with("midnight").once
+      expect(Agents::WebsiteAgent).to receive(:bulk_check).with("midnight").once
       Agent.run_schedule("midnight")
     end
 
     it "only runs agents with the given schedule" do
-      do_not_allow(Agents::WebsiteAgent).async_check
+      expect(Agents::WebsiteAgent).not_to receive(:async_check)
       Agent.run_schedule("blah")
     end
 
     it "will not run the 'never' schedule" do
       agents(:bob_weather_agent).update_attribute 'schedule', 'never'
-      do_not_allow(Agents::WebsiteAgent).async_check
+      expect(Agents::WebsiteAgent).not_to receive(:async_check)
       Agent.run_schedule("never")
     end
   end
 
   describe "credential" do
+    let(:agent) { agents(:bob_weather_agent) }
+
     it "should return the value of the credential when credential is present" do
-      expect(agents(:bob_weather_agent).credential("aws_secret")).to eq(user_credentials(:bob_aws_secret).credential_value)
+      expect(agent.credential("aws_secret")).to eq(user_credentials(:bob_aws_secret).credential_value)
     end
 
     it "should return nil when credential is not present" do
-      expect(agents(:bob_weather_agent).credential("non_existing_credential")).to eq(nil)
+      expect(agent.credential("non_existing_credential")).to eq(nil)
     end
 
     it "should memoize the load" do
-      mock.any_instance_of(UserCredential).credential_value.twice { "foo" }
-      expect(agents(:bob_weather_agent).credential("aws_secret")).to eq("foo")
-      expect(agents(:bob_weather_agent).credential("aws_secret")).to eq("foo")
-      agents(:bob_weather_agent).reload
-      expect(agents(:bob_weather_agent).credential("aws_secret")).to eq("foo")
-      expect(agents(:bob_weather_agent).credential("aws_secret")).to eq("foo")
+      count = 0
+      allow_any_instance_of(UserCredential).to receive(:credential_value) { count += 1 }.and_return("foo")
+      expect { expect(agent.credential("aws_secret")).to eq("foo") }.to change { count }.by(1)
+      expect { expect(agent.credential("aws_secret")).to eq("foo") }.not_to change { count }
+      agent.reload
+      expect { expect(agent.credential("aws_secret")).to eq("foo") }.to change { count }.by(1)
+      expect { expect(agent.credential("aws_secret")).to eq("foo") }.not_to change { count }
     end
   end
 
@@ -158,8 +161,8 @@ describe Agent do
     end
 
     before do
-      stub(Agents::SomethingSource).valid_type?("Agents::SomethingSource") { true }
-      stub(Agents::CannotBeScheduled).valid_type?("Agents::CannotBeScheduled") { true }
+      allow(Agents::SomethingSource).to receive(:valid_type?).with("Agents::SomethingSource") { true }
+      allow(Agents::CannotBeScheduled).to receive(:valid_type?).with("Agents::CannotBeScheduled") { true }
     end
 
     describe Agents::SomethingSource do
@@ -229,7 +232,7 @@ describe Agent do
       end
 
       it "should log an error if the Agent has been marked with 'cannot_create_events!'" do
-        mock(@checker).can_create_events? { false }
+        expect(@checker).to receive(:can_create_events?) { false }
         expect {
           @checker.check
         }.not_to change { Event.count }
@@ -245,11 +248,11 @@ describe Agent do
       end
 
       it "records last_check_at and calls check on the given Agent" do
-        mock(@checker).check.once {
+        expect(@checker).to receive(:check).once {
           @checker.options[:new] = true
         }
 
-        mock(Agent).find(@checker.id) { @checker }
+        allow(Agent).to receive(:find).with(@checker.id) { @checker }
 
         expect(@checker.last_check_at).to be_nil
         Agents::SomethingSource.async_check(@checker.id)
@@ -258,10 +261,10 @@ describe Agent do
       end
 
       it "should log exceptions" do
-        mock(@checker).check.once {
+        expect(@checker).to receive(:check).once {
           raise "foo"
         }
-        mock(Agent).find(@checker.id) { @checker }
+        expect(Agent).to receive(:find).with(@checker.id) { @checker }
         expect {
           Agents::SomethingSource.async_check(@checker.id)
         }.to raise_error(RuntimeError)
@@ -271,8 +274,8 @@ describe Agent do
       end
 
       it "should not run disabled Agents" do
-        mock(Agent).find(agents(:bob_weather_agent).id) { agents(:bob_weather_agent) }
-        do_not_allow(agents(:bob_weather_agent)).check
+        expect(Agent).to receive(:find).with(agents(:bob_weather_agent).id) { agents(:bob_weather_agent) }
+        expect(agents(:bob_weather_agent)).not_to receive(:check)
         agents(:bob_weather_agent).update_attribute :disabled, true
         Agent.async_check(agents(:bob_weather_agent).id)
       end
@@ -281,19 +284,18 @@ describe Agent do
     describe ".receive!" do
       before do
         stub_request(:any, /darksky/).to_return(:body => File.read(Rails.root.join("spec/data_fixtures/weather.json")), :status => 200)
-        stub.any_instance_of(Agents::WeatherAgent).is_tomorrow?(anything) { true }
       end
 
       it "should use available events" do
         Agent.async_check(agents(:bob_weather_agent).id)
-        mock(Agent).async_receive(agents(:bob_rain_notifier_agent).id, anything).times(1)
+        expect(Agent).to receive(:async_receive).with(agents(:bob_rain_notifier_agent).id, anything).once
         Agent.receive!
       end
 
       it "should not propagate to disabled Agents" do
         Agent.async_check(agents(:bob_weather_agent).id)
         agents(:bob_rain_notifier_agent).update_attribute :disabled, true
-        mock(Agent).async_receive(agents(:bob_rain_notifier_agent).id, anything).times(0)
+        expect(Agent).not_to receive(:async_receive).with(agents(:bob_rain_notifier_agent).id, anything)
         Agent.receive!
       end
 
@@ -303,8 +305,8 @@ describe Agent do
 
         Agent.where(id: agents(:bob_rain_notifier_agent).id).update_all type: 'UnknownTypeAgent'
 
-        mock(Agent).async_receive(agents(:bob_rain_notifier_agent).id, anything).times(0)
-        mock(Agent).async_receive(agents(:jane_rain_notifier_agent).id, anything).times(1)
+        expect(Agent).not_to receive(:async_receive).with(agents(:bob_rain_notifier_agent).id, anything)
+        expect(Agent).to receive(:async_receive).with(agents(:jane_rain_notifier_agent).id, anything).once
 
         Agent.receive!
       end
@@ -315,14 +317,16 @@ describe Agent do
 
         Agent.where(id: agents(:bob_weather_agent).id).update_all type: 'UnknownTypeAgent'
 
-        mock(Agent).async_receive(agents(:bob_rain_notifier_agent).id, anything).times(0)
-        mock(Agent).async_receive(agents(:jane_rain_notifier_agent).id, anything).times(1)
+        expect(Agent).not_to receive(:async_receive).with(agents(:bob_rain_notifier_agent).id, anything)
+        expect(Agent).to receive(:async_receive).with(agents(:jane_rain_notifier_agent).id, anything).once
 
         Agent.receive!
       end
 
       it "should log exceptions" do
-        mock.any_instance_of(Agents::TriggerAgent).receive(anything).once {
+        count = 0
+        allow_any_instance_of(Agents::TriggerAgent).to receive(:receive) {
+          count += 1
           raise "foo"
         }
         Agent.async_check(agents(:bob_weather_agent).id)
@@ -332,10 +336,12 @@ describe Agent do
         log = agents(:bob_rain_notifier_agent).logs.first
         expect(log.message).to match(/Exception/)
         expect(log.level).to eq(4)
+        expect(count).to eq 1
       end
 
       it "should track when events have been seen and not received them again" do
-        mock.any_instance_of(Agents::TriggerAgent).receive(anything).once
+        count = 0
+        allow_any_instance_of(Agents::TriggerAgent).to receive(:receive) { count += 1 }
         Agent.async_check(agents(:bob_weather_agent).id)
         expect {
           Agent.receive!
@@ -344,28 +350,34 @@ describe Agent do
         expect {
           Agent.receive!
         }.not_to change { agents(:bob_rain_notifier_agent).reload.last_checked_event_id }
+        expect(count).to eq 1
       end
 
       it "should not run consumers that have nothing to do" do
-        do_not_allow.any_instance_of(Agents::TriggerAgent).receive(anything)
+        anything
         Agent.receive!
       end
 
       it "should group events" do
-        mock.any_instance_of(Agents::TriggerAgent).receive(anything).twice { |events|
+        count = 0
+        allow_any_instance_of(Agents::TriggerAgent).to receive(:receive) { |agent, events|
+          count += 1
           expect(events.map(&:user).map(&:username).uniq.length).to eq(1)
         }
         Agent.async_check(agents(:bob_weather_agent).id)
         Agent.async_check(agents(:jane_weather_agent).id)
         Agent.receive!
+        expect(count).to eq 2
       end
 
       it "should call receive for each event when no_bulk_receive! is used" do
-        mock.any_instance_of(Agents::TriggerAgent).receive(anything).twice
-        stub(Agents::TriggerAgent).no_bulk_receive? { true }
+        count = 0
+        allow_any_instance_of(Agents::TriggerAgent).to receive(:receive).with(anything) { count += 1 }
+        allow(Agents::TriggerAgent).to receive(:no_bulk_receive?) { true }
         Agent.async_check(agents(:bob_weather_agent).id)
         Agent.async_check(agents(:bob_weather_agent).id)
         Agent.receive!
+        expect(count).to eq 2
       end
 
       it "should ignore events that were created before a particular Link" do
@@ -374,7 +386,8 @@ describe Agent do
         agent2.save!
         agent2.check
 
-        mock.any_instance_of(Agents::TriggerAgent).receive(anything).twice
+        count = 0
+        allow_any_instance_of(Agents::TriggerAgent).to receive(:receive) { count += 1 }
         agents(:bob_weather_agent).check # bob_weather_agent makes an event
 
         expect {
@@ -399,20 +412,22 @@ describe Agent do
         expect {
           Agent.receive! # and we receive it
         }.to change { agents(:bob_rain_notifier_agent).reload.last_checked_event_id }
+
+        expect(count).to eq 2
       end
 
       it "should not run agents of deactivated accounts" do
         agents(:bob_weather_agent).user.deactivate!
         Agent.async_check(agents(:bob_weather_agent).id)
-        mock(Agent).async_receive(agents(:bob_rain_notifier_agent).id, anything).times(0)
+        expect(Agent).not_to receive(:async_receive).with(agents(:bob_rain_notifier_agent).id, anything)
         Agent.receive!
       end
     end
 
     describe ".async_receive" do
       it "should not run disabled Agents" do
-        mock(Agent).find(agents(:bob_rain_notifier_agent).id) { agents(:bob_rain_notifier_agent) }
-        do_not_allow(agents(:bob_rain_notifier_agent)).receive
+        expect(Agent).to receive(:find).with(agents(:bob_rain_notifier_agent).id) { agents(:bob_rain_notifier_agent) }
+        expect(agents(:bob_rain_notifier_agent)).not_to receive(:receive)
         agents(:bob_rain_notifier_agent).update_attribute :disabled, true
         Agent.async_receive(agents(:bob_rain_notifier_agent).id, [1, 2, 3])
       end
@@ -665,7 +680,7 @@ describe Agent do
 
       describe "when keep_events_for has not changed" do
         it "does nothing" do
-          mock(@agent).update_event_expirations!.times(0)
+          expect(@agent).not_to receive(:update_event_expirations!)
 
           @agent.options[:foo] = "bar1"
           @agent.save!
@@ -762,7 +777,7 @@ describe Agent do
     end
 
     before do
-      stub(Agents::WebRequestReceiver).valid_type?("Agents::WebRequestReceiver") { true }
+      allow(Agents::WebRequestReceiver).to receive(:valid_type?).with("Agents::WebRequestReceiver") { true }
     end
 
     context "when .receive_web_request is defined" do
@@ -835,7 +850,7 @@ describe Agent do
           'HTTP_ACCEPT' => 'text/html'
         })
 
-        mock(Rails.logger).warn("DEPRECATED: The .receive_webhook method is deprecated, please switch your Agent to use .receive_web_request.")
+        expect(Rails.logger).to receive(:warn).with("DEPRECATED: The .receive_webhook method is deprecated, please switch your Agent to use .receive_web_request.")
         @agent.trigger_web_request(request)
         expect(@agent.reload.memory['last_webhook_request']).to eq({ "some_param" => "some_value" })
         expect(@agent.last_web_request_at.to_i).to be_within(1).of(Time.now.to_i)
@@ -1050,9 +1065,9 @@ describe AgentDrop do
   end
 
   it 'should have .working' do
-    stub(@wsa1).working? { false }
-    stub(@wsa2).working? { true }
-    stub(@efa).working? { false }
+    allow(@wsa1).to receive(:working?) { false }
+    allow(@wsa2).to receive(:working?) { true }
+    allow(@efa).to receive(:working?) { false }
 
     t = '{% if agent.working %}healthy{% else %}unhealthy{% endif %}'
     expect(interpolate(t, @wsa1)).to eq('unhealthy')

+ 1 - 1
spec/models/agents/adioso_agent_spec.rb

@@ -31,7 +31,7 @@ describe Agents::AdiosoAgent do
 			@checker.check
 			expect(@checker.reload).to be_working
 			three_days_from_now = 3.days.from_now
-			stub(Time).now { three_days_from_now }
+			allow(Time).to receive(:now) { three_days_from_now }
 			expect(@checker).not_to be_working
 		end
 	end

+ 4 - 4
spec/models/agents/boxcar_agent_spec.rb

@@ -38,22 +38,22 @@ describe Agents::BoxcarAgent do
 
   describe "#receive" do
     it "sends a message" do
-      stub(HTTParty).post { {"id" => 1, "message" => "blah", "title" => "blah","source_name" => "Custom Notification"} }
+      allow(HTTParty).to receive(:post) { {"id" => 1, "message" => "blah", "title" => "blah","source_name" => "Custom Notification"} }
       @checker.receive([@event])
     end
 
     it "should raise error when invalid response arrives" do
-      stub(HTTParty).post { {"blah" => "blah"} }
+      allow(HTTParty).to receive(:post) { {"blah" => "blah"} }
       expect { @checker.send_notification({}) }.to raise_error(StandardError, /Invalid response from Boxcar:/)
     end
 
     it "should raise error when response says unauthorized" do
-      stub(HTTParty).post { {"Response" => "Not authorized"} }
+      allow(HTTParty).to receive(:post) { {"Response" => "Not authorized"} }
       expect { @checker.send_notification({}) }.to raise_error(StandardError, /Not authorized/)
     end
 
     it "should raise error when response has an error" do
-      stub(HTTParty).post { {"error" => {"message" => "Sample error"}} }
+      allow(HTTParty).to receive(:post) { {"error" => {"message" => "Sample error"}} }
       expect { @checker.send_notification({}) }.to raise_error(StandardError, /Sample error/)
     end
   end

+ 2 - 2
spec/models/agents/commander_agent_spec.rb

@@ -25,14 +25,14 @@ describe Agents::CommanderAgent do
 
   describe "check" do
     it "should command targets" do
-      stub(Agent).async_check(target.id).once { nil }
+      allow(Agent).to receive(:async_check).with(target.id).once { nil }
       agent.check
     end
   end
 
   describe "receive_events" do
     it "should command targets" do
-      stub(Agent).async_check(target.id).once { nil }
+      allow(Agent).to receive(:async_check).with(target.id).once { nil }
 
       event = Event.new
       event.agent = agents(:bob_rain_notifier_agent)

+ 13 - 13
spec/models/agents/data_output_agent_spec.rb

@@ -20,7 +20,7 @@ describe Agents::DataOutputAgent do
       Agents::DataOutputAgent.async_receive agent.id, [events(:bob_website_agent_event).id]
       expect(agent.reload).to be_working
       two_days_from_now = 2.days.from_now
-      stub(Time).now { two_days_from_now }
+      allow(Time).to receive(:now) { two_days_from_now }
       expect(agent.reload).not_to be_working
     end
   end
@@ -100,7 +100,7 @@ describe Agents::DataOutputAgent do
   describe "#receive_web_request" do
     before do
       current_time = Time.now
-      stub(Time).now { current_time }
+      allow(Time).to receive(:now) { current_time }
       agents(:bob_website_agent).events.destroy_all
     end
 
@@ -151,7 +151,7 @@ describe Agents::DataOutputAgent do
       end
 
       it "can output RSS" do
-        stub(agent).feed_link { "https://yoursite.com" }
+        allow(agent).to receive(:feed_link) { "https://yoursite.com" }
         content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml')
         expect(status).to eq(200)
         expect(content_type).to eq('application/rss+xml')
@@ -214,7 +214,7 @@ describe Agents::DataOutputAgent do
       end
 
       it "can output RSS with hub links when push_hubs is specified" do
-        stub(agent).feed_link { "https://yoursite.com" }
+        allow(agent).to receive(:feed_link) { "https://yoursite.com" }
         agent.options[:push_hubs] = %w[https://pubsubhubbub.superfeedr.com/ https://pubsubhubbub.appspot.com/]
         content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml')
         expect(status).to eq(200)
@@ -347,7 +347,7 @@ describe Agents::DataOutputAgent do
         end
 
         it "can output RSS" do
-          stub(agent).feed_link { "https://yoursite.com" }
+          allow(agent).to receive(:feed_link) { "https://yoursite.com" }
           content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml')
           expect(status).to eq(200)
           expect(content_type).to eq('application/rss+xml')
@@ -391,7 +391,7 @@ describe Agents::DataOutputAgent do
         end
 
         it "can output RSS" do
-          stub(agent).feed_link { "https://yoursite.com" }
+          allow(agent).to receive(:feed_link) { "https://yoursite.com" }
           content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml')
           expect(status).to eq(200)
           expect(content_type).to eq('application/rss+xml')
@@ -406,7 +406,7 @@ describe Agents::DataOutputAgent do
         end
 
         it "can output RSS" do
-          stub(agent).feed_link { "https://yoursite.com" }
+          allow(agent).to receive(:feed_link) { "https://yoursite.com" }
           content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml')
           expect(status).to eq(200)
           expect(content_type).to eq('application/rss+xml')
@@ -424,7 +424,7 @@ describe Agents::DataOutputAgent do
         end
 
         it "can output RSS" do
-          stub(agent).feed_link { "https://yoursite.com" }
+          allow(agent).to receive(:feed_link) { "https://yoursite.com" }
           content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml')
           expect(status).to eq(200)
           expect(content_type).to eq('application/rss+xml')
@@ -444,7 +444,7 @@ describe Agents::DataOutputAgent do
         end
 
         it "can output RSS" do
-          stub(agent).feed_link { "https://yoursite.com" }
+          allow(agent).to receive(:feed_link) { "https://yoursite.com" }
           content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml')
           expect(status).to eq(200)
           expect(content_type).to eq('application/rss+xml')
@@ -462,7 +462,7 @@ describe Agents::DataOutputAgent do
         end
 
         it "can output RSS" do
-          stub(agent).feed_link { "https://yoursite.com" }
+          allow(agent).to receive(:feed_link) { "https://yoursite.com" }
           content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml')
           expect(status).to eq(200)
           expect(content_type).to eq('application/rss+xml')
@@ -481,7 +481,7 @@ describe Agents::DataOutputAgent do
         end
 
         it "can output RSS" do
-          stub(agent).feed_link { "https://yoursite.com" }
+          allow(agent).to receive(:feed_link) { "https://yoursite.com" }
           content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml')
           expect(status).to eq(200)
           expect(content_type).to eq('application/rss+xml')
@@ -502,7 +502,7 @@ describe Agents::DataOutputAgent do
         end
 
         it "can output RSS" do
-          stub(agent).feed_link { "https://yoursite.com" }
+          allow(agent).to receive(:feed_link) { "https://yoursite.com" }
           content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml')
           expect(status).to eq(200)
           expect(content_type).to eq('application/rss+xml')
@@ -606,7 +606,7 @@ describe Agents::DataOutputAgent do
       end
 
       it "can output RSS" do
-        stub(agent).feed_link { "https://yoursite.com" }
+        allow(agent).to receive(:feed_link) { "https://yoursite.com" }
         content, status, content_type = agent.receive_web_request({ 'secret' => 'secret1' }, 'get', 'text/xml')
         expect(status).to eq(200)
         expect(content_type).to eq('application/rss+xml')

+ 1 - 1
spec/models/agents/delay_agent_spec.rb

@@ -27,7 +27,7 @@ describe Agents::DelayAgent do
       Agents::DelayAgent.async_receive agent.id, [events(:bob_website_agent_event).id]
       expect(agent.reload).to be_working
       the_future = (agent.options[:expected_receive_period_in_days].to_i + 1).days.from_now
-      stub(Time).now { the_future }
+      allow(Time).to receive(:now) { the_future }
       expect(agent.reload).not_to be_working
     end
   end

+ 1 - 1
spec/models/agents/digest_agent_spec.rb

@@ -20,7 +20,7 @@ describe Agents::DigestAgent do
       Agents::DigestAgent.async_receive @checker.id, [event.id]
       expect(@checker.reload).to be_working # Events received
       three_days_from_now = 3.days.from_now
-      stub(Time).now { three_days_from_now }
+      allow(Time).to receive(:now) { three_days_from_now }
       expect(@checker).not_to be_working # too much time has passed
     end
   end

+ 12 - 8
spec/models/agents/dropbox_file_url_agent_spec.rb

@@ -41,10 +41,12 @@ describe Agents::DropboxFileUrlAgent do
       let(:third_dropbox_url_payload)  { Dropbox::API::Object.new({ 'link' => 'http://dropbox.com/third/path/url' }, nil) }
 
       before(:each) do
-        stub.proxy(Dropbox::API::Client).new do |api|
-          stub(api).find('/first/path')  { stub(Dropbox::API::File.new({}, nil)).direct_url { first_dropbox_url_payload } }
-          stub(api).find('/second/path') { stub(Dropbox::API::File.new({}, nil)).direct_url { second_dropbox_url_payload } }
-          stub(api).find('/third/path')  { stub(Dropbox::API::File.new({}, nil)).direct_url { third_dropbox_url_payload } }
+        allow(Dropbox::API::Client).to receive(:new) do
+          instance_double(Dropbox::API::Client).tap { |api|
+            allow(api).to receive(:find).with('/first/path')  { Dropbox::API::File.new({}, nil).tap { |file| allow(file).to receive(:direct_url) { first_dropbox_url_payload } } }
+            allow(api).to receive(:find).with('/second/path') { Dropbox::API::File.new({}, nil).tap { |file| allow(file).to receive(:direct_url) { second_dropbox_url_payload } } }
+            allow(api).to receive(:find).with('/third/path')  { Dropbox::API::File.new({}, nil).tap { |file| allow(file).to receive(:direct_url) { third_dropbox_url_payload } } }
+          }
         end
       end
 
@@ -80,10 +82,12 @@ describe Agents::DropboxFileUrlAgent do
       let(:third_dropbox_url_payload)  { response_for('/third/path') }
 
       before(:each) do
-        stub.proxy(Dropbox::API::Client).new do |api|
-          stub(api).find('/first/path')  { stub(Dropbox::API::File.new({}, nil)).share_url { first_dropbox_url_payload } }
-          stub(api).find('/second/path') { stub(Dropbox::API::File.new({}, nil)).share_url { second_dropbox_url_payload } }
-          stub(api).find('/third/path')  { stub(Dropbox::API::File.new({}, nil)).share_url { third_dropbox_url_payload } }
+        allow(Dropbox::API::Client).to receive(:new) do
+          instance_double(Dropbox::API::Client).tap { |api|
+            allow(api).to receive(:find).with('/first/path')  { Dropbox::API::File.new({}, nil).tap { |file| allow(file).to receive(:share_url) { first_dropbox_url_payload } } }
+            allow(api).to receive(:find).with('/second/path') { Dropbox::API::File.new({}, nil).tap { |file| allow(file).to receive(:share_url) { second_dropbox_url_payload } } }
+            allow(api).to receive(:find).with('/third/path')  { Dropbox::API::File.new({}, nil).tap { |file| allow(file).to receive(:share_url) { third_dropbox_url_payload } } }
+          }
         end
         @agent.options['link_type'] = 'permanent'
       end

+ 17 - 9
spec/models/agents/dropbox_watch_agent_spec.rb

@@ -53,8 +53,10 @@ describe Agents::DropboxWatchAgent do
     let(:first_result) { Dropbox::API::Object.convert([{ 'path_display' => '1.json', 'rev' => '1', 'server_modified' => '01-01-01' }], nil) }
 
     before(:each) do
-      stub.proxy(Dropbox::API::Client).new do |api|
-        stub(api).ls('/my/dropbox/dir') { first_result }
+      allow(Dropbox::API::Client).to receive(:new) do
+        instance_double(Dropbox::API::Client).tap { |api|
+          allow(api).to receive(:ls).with('/my/dropbox/dir') { first_result }
+        }
       end
     end
 
@@ -80,24 +82,30 @@ describe Agents::DropboxWatchAgent do
       before(:each) do
         @agent.memory = { 'contents' => 'not_empty' }
 
-        stub.proxy(Dropbox::API::Client).new do |api|
-          stub(api).ls('/my/dropbox/dir') { second_result }
+        allow(Dropbox::API::Client).to receive(:new) do
+          instance_double(Dropbox::API::Client).tap { |api|
+            allow(api).to receive(:ls).with('/my/dropbox/dir') { second_result }
+          }
         end
       end
 
       it 'sends an event upon a different directory listing' do
         payload = { 'diff' => 'object as hash' }
-        stub.proxy(Agents::DropboxWatchAgent::DropboxDirDiff).new(@agent.memory['contents'], [{"path"=>"2.json", "rev"=>"1", "modified"=>"02-02-02"}]) do |diff|
-          stub(diff).empty? { false }
-          stub(diff).to_hash { payload }
+        allow(Agents::DropboxWatchAgent::DropboxDirDiff).to receive(:new).with(@agent.memory['contents'], [{"path"=>"2.json", "rev"=>"1", "modified"=>"02-02-02"}]) do
+          instance_double(Agents::DropboxWatchAgent::DropboxDirDiff).tap { |diff|
+            allow(diff).to receive(:empty?) { false }
+            allow(diff).to receive(:to_hash) { payload }
+          }
         end
         expect { @agent.check }.to change(Event, :count).by(1)
         expect(Event.last.payload).to eq(payload)
       end
 
       it 'does not sent any events when there is no difference on the directory listing' do
-        stub.proxy(Agents::DropboxWatchAgent::DropboxDirDiff).new(@agent.memory['contents'], [{"path"=>"2.json", "rev"=>"1", "modified"=>"02-02-02"}]) do |diff|
-          stub(diff).empty? { true }
+        allow(Agents::DropboxWatchAgent::DropboxDirDiff).to receive(:new).with(@agent.memory['contents'], [{"path"=>"2.json", "rev"=>"1", "modified"=>"02-02-02"}]) do
+          instance_double(Agents::DropboxWatchAgent::DropboxDirDiff).tap { |diff|
+            allow(diff).to receive(:empty?) { true }
+          }
         end
 
         expect { @agent.check }.to_not change(Event, :count)

+ 1 - 2
spec/models/agents/email_agent_spec.rb

@@ -46,7 +46,7 @@ describe Agents::EmailAgent do
       event1.payload = { :message => "hi!", :data => "Something you should know about" }
       event1.save!
 
-      mock(SystemMailer).send_message(anything) { raise Net::SMTPAuthenticationError.new("Wrong password") }
+      expect(SystemMailer).to receive(:send_message).with(anything) { raise Net::SMTPAuthenticationError.new("Wrong password") }
 
       expect {
         Agents::EmailAgent.async_receive(@checker.id, [event1.id])
@@ -57,7 +57,6 @@ describe Agents::EmailAgent do
 
     it "can receive complex events and send them on" do
       stub_request(:any, /darksky/).to_return(:body => File.read(Rails.root.join("spec/data_fixtures/weather.json")), :status => 200)
-      stub.any_instance_of(Agents::WeatherAgent).is_tomorrow?(anything) { true }
       @checker.sources << agents(:bob_weather_agent)
 
       Agent.async_check(agents(:bob_weather_agent).id)

+ 1 - 2
spec/models/agents/email_digest_agent_spec.rb

@@ -70,7 +70,7 @@ describe Agents::EmailDigestAgent do
     end
 
     it "logs and re-raises mailer errors" do
-      mock(SystemMailer).send_message(anything) { raise Net::SMTPAuthenticationError.new("Wrong password") }
+      expect(SystemMailer).to receive(:send_message).with(anything) { raise Net::SMTPAuthenticationError.new("Wrong password") }
 
       @checker.memory[:events] = [1]
       @checker.save!
@@ -85,7 +85,6 @@ describe Agents::EmailDigestAgent do
 
     it "can receive complex events and send them on" do
       stub_request(:any, /darksky/).to_return(:body => File.read(Rails.root.join("spec/data_fixtures/weather.json")), :status => 200)
-      stub.any_instance_of(Agents::WeatherAgent).is_tomorrow?(anything) { true }
       @checker.sources << agents(:bob_weather_agent)
 
       Agent.async_check(agents(:bob_weather_agent).id)

+ 11 - 11
spec/models/agents/evernote_agent_spec.rb

@@ -53,7 +53,7 @@ describe Agents::EvernoteAgent do
   end
 
   before do
-    stub.any_instance_of(Agents::EvernoteAgent).evernote_note_store { en_note_store }
+    allow_any_instance_of(Agents::EvernoteAgent).to receive(:evernote_note_store) { en_note_store }
   end
 
   describe "#receive" do
@@ -90,7 +90,7 @@ describe Agents::EvernoteAgent do
       end
 
       it "adds a note for any payload it receives" do
-        stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: []) }
+        allow(en_note_store).to receive(:findNotesMetadata) { OpenStruct.new(notes: []) }
         Agents::EvernoteAgent.async_receive(@agent.id, [@event.id])
 
         expect(en_note_store.notes.size).to eq(1)
@@ -115,7 +115,7 @@ describe Agents::EvernoteAgent do
           [note1, note2].each { |note| en_note_store.createNote(note) }
           en_note_store.createNotebook(OpenStruct.new(name: "xkcd"))
 
-          stub(en_note_store).findNotesMetadata {
+          allow(en_note_store).to receive(:findNotesMetadata) {
             OpenStruct.new(notes: [note1]) }
         end
 
@@ -135,7 +135,7 @@ describe Agents::EvernoteAgent do
         end
 
         it "creates an event with note content wrapped in ENML" do
-          stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: []) }
+          allow(en_note_store).to receive(:findNotesMetadata) { OpenStruct.new(notes: []) }
           Agents::EvernoteAgent.async_receive(@agent.id, [@event.id])
 
           payload = @agent.events.first.payload
@@ -184,7 +184,7 @@ describe Agents::EvernoteAgent do
         tag2 = OpenStruct.new(name: "comic")
         [tag1, tag2].each { |tag| en_note_store.createTag(tag) }
 
-        stub(en_note_store).findNotesMetadata {
+        allow(en_note_store).to receive(:findNotesMetadata) {
           notes = en_note_store.notes.select do |note|
             note.notebookGuid == 1 &&
             %w(funny comic).all? { |tag_name| note.tagNames.include?(tag_name) }
@@ -385,7 +385,7 @@ describe Agents::EvernoteAgent do
 
       context "a note with given title and notebook does not exist" do
         before do
-          stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: []) }
+          allow(en_note_store).to receive(:findNotesMetadata) { OpenStruct.new(notes: []) }
         end
 
         it "creates a note" do
@@ -407,7 +407,7 @@ describe Agents::EvernoteAgent do
 
         before do
           en_note_store.createNote(note)
-          stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: [note]) }
+          allow(en_note_store).to receive(:findNotesMetadata) { OpenStruct.new(notes: [note]) }
         end
 
         it "updates the note" do
@@ -459,7 +459,7 @@ describe Agents::EvernoteAgent do
 
     describe "#note_guids" do
       it "returns the guids of notes satisfying search options" do
-        stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: [note1]) }
+        allow(en_note_store).to receive(:findNotesMetadata) { OpenStruct.new(notes: [note1]) }
         result = search.note_guids
 
         expect(result.size).to eq(1)
@@ -470,7 +470,7 @@ describe Agents::EvernoteAgent do
     describe "#notes" do
       context "last_checked_at is not set" do
         it "returns notes satisfying the search options" do
-          stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: [note1]) }
+          allow(en_note_store).to receive(:findNotesMetadata) { OpenStruct.new(notes: [note1]) }
           result = search.notes
 
           expect(result.size).to eq(1)
@@ -482,7 +482,7 @@ describe Agents::EvernoteAgent do
       context "last_checked_at is set" do
         context "notes_with_tags is not set" do
           it "only returns notes updated since then" do
-            stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: [note1, note3]) }
+            allow(en_note_store).to receive(:findNotesMetadata) { OpenStruct.new(notes: [note1, note3]) }
             result = search_with_time.notes
 
             expect(result.size).to eq(1)
@@ -493,7 +493,7 @@ describe Agents::EvernoteAgent do
         context "notes_with_tags is set" do
           it "returns notes updated since then or notes with recently added tags" do
             note3.tagNames = ["funny", "comic"]
-            stub(en_note_store).findNotesMetadata { OpenStruct.new(notes: [note1, note3]) }
+            allow(en_note_store).to receive(:findNotesMetadata) { OpenStruct.new(notes: [note1, note3]) }
 
             result = search_with_time_and_tags.notes
             expect(result.size).to eq(2)

+ 29 - 28
spec/models/agents/ftpsite_agent_spec.rb

@@ -79,7 +79,7 @@ describe Agents::FtpsiteAgent do
     describe "#check" do
 
       before do
-        stub(@checker).each_entry.returns { |block|
+        allow(@checker).to receive(:each_entry) { |&block|
           block.call("example latest.tar.gz", Time.parse("2014-04-01T10:00:01Z"))
           block.call("example-1.0.tar.gz",    Time.parse("2013-10-01T10:00:00Z"))
           block.call("example-1.1.tar.gz",    Time.parse("2014-04-01T10:00:00Z"))
@@ -112,7 +112,7 @@ describe Agents::FtpsiteAgent do
 
         expect { @checker.check }.not_to change { Event.count }
 
-        stub(@checker).each_entry.returns { |block|
+        allow(@checker).to receive(:each_entry) { |&block|
           block.call("example latest.tar.gz", Time.parse("2014-04-02T10:00:01Z"))
 
           # In the long list format the timestamp may look going
@@ -153,11 +153,11 @@ describe Agents::FtpsiteAgent do
 
     describe "#each_entry" do
       before do
-        stub.any_instance_of(Net::FTP).list.returns [ # Windows format
+        allow_any_instance_of(Net::FTP).to receive(:list).and_return [ # Windows format
           "04-02-14  10:01AM            288720748 example latest.tar.gz",
           "04-01-14  10:05AM            288720710 no-match-example.tar.gz"
         ]
-        stub(@checker).open_ftp.yields Net::FTP.new
+        allow(@checker).to receive(:open_ftp).and_yield(Net::FTP.new)
       end
 
       it "filters out files that don't match the given format" do
@@ -180,53 +180,54 @@ describe Agents::FtpsiteAgent do
 
     context "#open_ftp" do
       before(:each) do
-        @ftp_mock = mock()
-        mock(@ftp_mock).close
-        mock(@ftp_mock).connect('ftp.example.org', 21)
-        mock(@ftp_mock).passive=(true)
-        mock(Net::FTP).new { @ftp_mock }
+        @ftp_mock = double()
+        allow(@ftp_mock).to receive(:close)
+        allow(@ftp_mock).to receive(:connect).with('ftp.example.org', 21)
+        allow(@ftp_mock).to receive(:passive=).with(true)
+        allow(Net::FTP).to receive(:new) { @ftp_mock }
       end
+
       context 'with_path' do
-        before(:each) { mock(@ftp_mock).chdir('pub/releases') }
+        before(:each) { expect(@ftp_mock).to receive(:chdir).with('pub/releases') }
 
         it "logs in as anonymous when no user and password are given" do
-          mock(@ftp_mock).login('anonymous', 'anonymous@')
+          expect(@ftp_mock).to receive(:login).with('anonymous', 'anonymous@')
           expect { |b| @checker.open_ftp(@checker.base_uri, &b) }.to yield_with_args(@ftp_mock)
         end
 
         it "passes the provided user and password" do
           @checker.options['url'] = "ftp://user:password@ftp.example.org/pub/releases/"
-          mock(@ftp_mock).login('user', 'password')
+          expect(@ftp_mock).to receive(:login).with('user', 'password')
           expect { |b| @checker.open_ftp(@checker.base_uri, &b) }.to yield_with_args(@ftp_mock)
         end
       end
 
       it "does not call chdir when no path is given" do
         @checker.options['url'] = "ftp://ftp.example.org/"
-        mock(@ftp_mock).login('anonymous', 'anonymous@')
+        expect(@ftp_mock).to receive(:login).with('anonymous', 'anonymous@')
         expect { |b| @checker.open_ftp(@checker.base_uri, &b) }.to yield_with_args(@ftp_mock)
       end
     end
 
     context "#get_io" do
       it "returns the contents of the file" do
-        ftp_mock= mock()
-        mock(ftp_mock).getbinaryfile('file', nil).yields('data')
-        mock(@checker).open_ftp(@checker.base_uri).yields(ftp_mock)
+        ftp_mock = double()
+        expect(ftp_mock).to receive(:getbinaryfile).with('file', nil).and_yield('data')
+        expect(@checker).to receive(:open_ftp).with(@checker.base_uri).and_yield(ftp_mock)
         expect(@checker.get_io('file').read).to eq('data')
       end
 
       it "uses the encoding specified in force_encoding to convert the data to UTF-8" do
-        ftp_mock= mock()
-        mock(ftp_mock).getbinaryfile('file', nil).yields('ümlaut'.force_encoding('ISO-8859-15'))
-        mock(@checker).open_ftp(@checker.base_uri).yields(ftp_mock)
+        ftp_mock = double()
+        expect(ftp_mock).to receive(:getbinaryfile).with('file', nil).and_yield('ümlaut'.force_encoding('ISO-8859-15'))
+        expect(@checker).to receive(:open_ftp).with(@checker.base_uri).and_yield(ftp_mock)
         expect(@checker.get_io('file').read).to eq('ümlaut')
       end
 
       it "returns an empty StringIO instance when no data was read" do
-        ftp_mock= mock()
-        mock(ftp_mock).getbinaryfile('file', nil)
-        mock(@checker).open_ftp(@checker.base_uri).yields(ftp_mock)
+        ftp_mock = double()
+        expect(ftp_mock).to receive(:getbinaryfile).with('file', nil)
+        expect(@checker).to receive(:open_ftp).with(@checker.base_uri).and_yield(ftp_mock)
         expect(@checker.get_io('file').length).to eq(0)
       end
     end
@@ -236,22 +237,22 @@ describe Agents::FtpsiteAgent do
         @checker.options['mode'] = 'write'
         @checker.options['filename'] = 'file.txt'
         @checker.options['data'] = '{{ data }}'
-        @ftp_mock= mock()
+        @ftp_mock = double()
         @stringio = StringIO.new()
-        mock(@checker).open_ftp(@checker.base_uri).yields(@ftp_mock)
+        allow(@checker).to receive(:open_ftp).with(@checker.base_uri).and_yield(@ftp_mock)
       end
 
       it "writes the data at data into a file" do
-        mock(StringIO).new('hello world🔥') { @stringio }
-        mock(@ftp_mock).storbinary('STOR file.txt', @stringio, Net::FTP::DEFAULT_BLOCKSIZE)
+        expect(StringIO).to receive(:new).with('hello world🔥') { @stringio }
+        expect(@ftp_mock).to receive(:storbinary).with('STOR file.txt', @stringio, Net::FTP::DEFAULT_BLOCKSIZE)
         event = Event.new(payload: {'data' => 'hello world🔥'})
         @checker.receive([event])
       end
 
       it "converts the string encoding when force_encoding is specified" do
         @checker.options['force_encoding'] = 'ISO-8859-1'
-        mock(StringIO).new('hello world?') { @stringio }
-        mock(@ftp_mock).storbinary('STOR file.txt', @stringio, Net::FTP::DEFAULT_BLOCKSIZE)
+        expect(StringIO).to receive(:new).with('hello world?') { @stringio }
+        expect(@ftp_mock).to receive(:storbinary).with('STOR file.txt', @stringio, Net::FTP::DEFAULT_BLOCKSIZE)
         event = Event.new(payload: {'data' => 'hello world🔥'})
         @checker.receive([event])
       end

+ 6 - 6
spec/models/agents/google_calendar_publish_agent_spec.rb

@@ -74,9 +74,9 @@ describe Agents::GoogleCalendarPublishAgent do
 
     def setup_mock!
       fake_interface = Object.new
-      mock(GoogleCalendar).new(agent.interpolate_options(agent.options), Rails.logger) { fake_interface }
-      mock(fake_interface).publish_as(calendar_id, message) { response_hash }
-      mock(fake_interface).cleanup!
+      expect(GoogleCalendar).to receive(:new).with(agent.interpolate_options(agent.options), Rails.logger) { fake_interface }
+      expect(fake_interface).to receive(:publish_as).with(calendar_id, message) { response_hash }
+      expect(fake_interface).to receive(:cleanup!)
     end
 
     describe 'when the calendar_id is in the options' do
@@ -188,9 +188,9 @@ describe Agents::GoogleCalendarPublishAgent do
 
     def setup_mock!
       fake_interface = Object.new
-      mock(GoogleCalendar).new(agent.interpolate_options(agent.options), Rails.logger) { fake_interface }
-      mock(fake_interface).publish_as(calendar_id, message) { response_hash }
-      mock(fake_interface).cleanup!
+      expect(GoogleCalendar).to receive(:new).with(agent.interpolate_options(agent.options), Rails.logger) { fake_interface }
+      expect(fake_interface).to receive(:publish_as).with(calendar_id, message) { response_hash }
+      expect(fake_interface).to receive(:cleanup!)
     end
 
     describe 'when the calendar_id is in the options' do

+ 1 - 1
spec/models/agents/google_translation_agent_spec.rb

@@ -50,7 +50,7 @@ describe Agents::GoogleTranslationAgent, :vcr do
       Agents::GoogleTranslationAgent.async_receive @checker.id, [@event.id]
       expect(@checker.reload).to be_working
       two_days_from_now = 2.days.from_now
-      stub(Time).now { two_days_from_now }
+      allow(Time).to receive(:now) { two_days_from_now }
       expect(@checker.reload).not_to be_working
     end
   end

+ 14 - 20
spec/models/agents/growl_agent_spec.rb

@@ -13,7 +13,7 @@ describe Agents::GrowlAgent do
     @checker.user = users(:bob)
     @checker.save!
 
-    stub.any_instance_of(Growl::GNTP).notify
+    allow_any_instance_of(Growl::GNTP).to receive(:notify)
 
     @event = Event.new
     @event.agent = agents(:bob_weather_agent)
@@ -27,7 +27,7 @@ describe Agents::GrowlAgent do
       Agents::GrowlAgent.async_receive @checker.id, [@event.id]
       expect(@checker.reload).to be_working # Just received events
       two_days_from_now = 2.days.from_now
-      stub(Time).now { two_days_from_now }
+      allow(Time).to receive(:now) { two_days_from_now }
       expect(@checker.reload).not_to be_working # More time has passed than the expected receive period without any new events
     end
   end
@@ -55,32 +55,26 @@ describe Agents::GrowlAgent do
     end
 
     it "should add a notification to the Growl connection" do
-      called = false
-      any_instance_of(Growl::GNTP) do |obj|
-        called = true
-        mock(obj).add_notification(@checker.options[:growl_notification_name])
+      expect(Growl::GNTP).to receive(:new).and_wrap_original do |orig, *args|
+        orig.call(*args).tap { |obj|
+          expect(obj).to receive(:add_notification).with(@checker.options[:growl_notification_name])
+        }
       end
-
       @checker.register_growl
-      expect(called).to be_truthy
     end
   end
 
   describe "notify_growl" do
-    before do
-      @checker.register_growl
-    end
-
     it "should call Growl.notify with the correct notification name, subject, and message" do
       message = "message"
       subject = "subject"
-      called = false
-      any_instance_of(Growl::GNTP) do |obj|
-        called = true
-        mock(obj).notify(@checker.options[:growl_notification_name], subject, message, 0, false, nil, '')
+      expect(Growl::GNTP).to receive(:new).and_wrap_original do |orig, *args|
+        orig.call(*args).tap { |obj|
+          expect(obj).to receive(:notify).with(@checker.options[:growl_notification_name], subject, message, 0, false, nil, '')
+        }
       end
+      @checker.register_growl
       @checker.notify_growl(subject: subject, message: message, sticky: false, priority: 0, callback_url: '')
-      expect(called).to be_truthy
     end
   end
 
@@ -95,14 +89,14 @@ describe Agents::GrowlAgent do
 
     it "should call register_growl once per received event" do
       events = generate_events_array
-      mock.proxy(@checker).register_growl.times(events.length)
+      expect(@checker).to receive(:register_growl).exactly(events.length).times.and_call_original
       @checker.receive(events)
     end
 
     it "should call notify_growl one time for each event received" do
       events = generate_events_array
       events.each do |event|
-        mock.proxy(@checker).notify_growl(subject: event.payload['subject'], message: event.payload['message'], priority: 0, sticky: false, callback_url: nil)
+        expect(@checker).to receive(:notify_growl).with(subject: event.payload['subject'], message: event.payload['message'], priority: 0, sticky: false, callback_url: nil)
       end
       @checker.receive(events)
     end
@@ -118,7 +112,7 @@ describe Agents::GrowlAgent do
       event_without_a_message.payload = { :subject => 'Weather Alert YO!' }
       event_without_a_message.save!
 
-      mock.proxy(@checker).notify_growl.never
+      expect(@checker).not_to receive(:notify_growl)
       @checker.receive([event_without_a_subject,event_without_a_message])
     end
   end

+ 4 - 12
spec/models/agents/hipchat_agent_spec.rb

@@ -52,34 +52,26 @@ describe Agents::HipchatAgent do
 
   describe "#validate_auth_token" do
     it "should return true when valid" do
-      any_instance_of(HipChat::Client) do |klass|
-        stub(klass).rooms { true }
-      end
+      allow_any_instance_of(HipChat::Client).to receive(:rooms) { true }
       expect(@checker.validate_auth_token).to be true
     end
 
     it "should return false when invalid" do
-      any_instance_of(HipChat::Client) do |klass|
-        stub(klass).rooms { raise HipChat::UnknownResponseCode.new }
-      end
+      allow_any_instance_of(HipChat::Client).to receive(:rooms) { raise HipChat::UnknownResponseCode.new }
       expect(@checker.validate_auth_token).to be false
     end
   end
 
   describe "#complete_room_name" do
     it "should return a array of hashes" do
-      any_instance_of(HipChat::Client) do |klass|
-        stub(klass).rooms { [OpenStruct.new(name: 'test'), OpenStruct.new(name: 'test1')] }
-      end
+      allow_any_instance_of(HipChat::Client).to receive(:rooms) { [OpenStruct.new(name: 'test'), OpenStruct.new(name: 'test1')] }
       expect(@checker.complete_room_name).to eq [{text: 'test', id: 'test'},{text: 'test1', id: 'test1'}]
     end
   end
 
   describe "#receive" do
     it "send a message to the hipchat" do
-      any_instance_of(HipChat::Room) do |obj|
-        mock(obj).send(@event.payload[:username][0..14], @event.payload[:message], {:notify => false, :color => 'yellow'})
-      end
+      expect_any_instance_of(HipChat::Room).to receive(:send).with(@event.payload[:username][0..14], @event.payload[:message], { notify: false, color: 'yellow', message_format: 'html' })
       @checker.receive([@event])
     end
   end

+ 33 - 33
spec/models/agents/human_task_agent_spec.rb

@@ -161,17 +161,17 @@ describe Agents::HumanTaskAgent do
     end
 
     it "should check for reviewable HITs frequently" do
-      mock(@checker).review_hits.twice
-      mock(@checker).create_basic_hit.once
+      expect(@checker).to receive(:review_hits).twice
+      expect(@checker).to receive(:create_basic_hit).once
       @checker.check
       @checker.check
     end
 
     it "should create HITs every 'submission_period' hours" do
       now = Time.now
-      stub(Time).now { now }
-      mock(@checker).review_hits.times(3)
-      mock(@checker).create_basic_hit.twice
+      allow(Time).to receive(:now) { now }
+      expect(@checker).to receive(:review_hits).exactly(3).times
+      expect(@checker).to receive(:create_basic_hit).twice
       @checker.check
       now += 1 * 60 * 60
       @checker.check
@@ -180,7 +180,7 @@ describe Agents::HumanTaskAgent do
     end
 
     it "should ignore events" do
-      mock(@checker).create_basic_hit(anything).times(0)
+      expect(@checker).not_to receive(:create_basic_hit).with(anything)
       @checker.receive([events(:bob_website_agent_event)])
     end
   end
@@ -189,9 +189,9 @@ describe Agents::HumanTaskAgent do
     it "should not create HITs during check but should check for reviewable HITs" do
       @checker.options['submission_period'] = "2"
       now = Time.now
-      stub(Time).now { now }
-      mock(@checker).review_hits.times(3)
-      mock(@checker).create_basic_hit.times(0)
+      allow(Time).to receive(:now) { now }
+      expect(@checker).to receive(:review_hits).exactly(3).times
+      expect(@checker).not_to receive(:create_basic_hit)
       @checker.check
       now += 1 * 60 * 60
       @checker.check
@@ -200,7 +200,7 @@ describe Agents::HumanTaskAgent do
     end
 
     it "should create HITs based on events" do
-      mock(@checker).create_basic_hit(events(:bob_website_agent_event)).times(1)
+      expect(@checker).to receive(:create_basic_hit).with(events(:bob_website_agent_event)).once
       @checker.receive([events(:bob_website_agent_event)])
     end
   end
@@ -214,8 +214,8 @@ describe Agents::HumanTaskAgent do
       question_form = nil
       hitInterface = OpenStruct.new
       hitInterface.id = 123
-      mock(hitInterface).question_form(instance_of Agents::HumanTaskAgent::AgentQuestionForm) { |agent_question_form_instance| question_form = agent_question_form_instance }
-      mock(RTurk::Hit).create(:title => "Hi Joe").yields(hitInterface) { hitInterface }
+      expect(hitInterface).to receive(:question_form).with(instance_of Agents::HumanTaskAgent::AgentQuestionForm) { |agent_question_form_instance| question_form = agent_question_form_instance }
+      expect(RTurk::Hit).to receive(:create).with(title: "Hi Joe").and_yield(hitInterface).and_return(hitInterface)
 
       @checker.send :create_basic_hit, @event
 
@@ -235,8 +235,8 @@ describe Agents::HumanTaskAgent do
       @checker.options['hit']['title'] = "Hi {{name}}"
       hitInterface = OpenStruct.new
       hitInterface.id = 123
-      mock(hitInterface).question_form(instance_of Agents::HumanTaskAgent::AgentQuestionForm)
-      mock(RTurk::Hit).create(:title => "Hi").yields(hitInterface) { hitInterface }
+      expect(hitInterface).to receive(:question_form).with(instance_of Agents::HumanTaskAgent::AgentQuestionForm)
+      expect(RTurk::Hit).to receive(:create).with(title: "Hi").and_yield(hitInterface).and_return(hitInterface)
       @checker.send :create_basic_hit
       expect(hitInterface.max_assignments).to eq(@checker.options['hit']['assignments'])
       expect(hitInterface.reward).to eq(@checker.options['hit']['reward'])
@@ -299,27 +299,27 @@ describe Agents::HumanTaskAgent do
       @checker.memory['hits']["JH39AA63836DHG"] = { 'event_id' => event2.id }
 
       hit_ids = %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345]
-      mock(RTurk::GetReviewableHITs).create { mock!.hit_ids { hit_ids } } # It sees 3 HITs.
+      expect(RTurk::GetReviewableHITs).to receive(:create) { double(hit_ids: hit_ids) } # It sees 3 HITs.
 
       # It looksup the two HITs that it owns.  Neither are ready yet.
-      mock(RTurk::Hit).new("JH3132836336DHG") { FakeHit.new }
-      mock(RTurk::Hit).new("JH39AA63836DHG") { FakeHit.new }
+      expect(RTurk::Hit).to receive(:new).with("JH3132836336DHG") { FakeHit.new }
+      expect(RTurk::Hit).to receive(:new).with("JH39AA63836DHG") { FakeHit.new }
 
       @checker.send :review_hits
     end
 
     it "shouldn't do anything if an assignment isn't ready" do
       @checker.memory['hits'] = { "JH3132836336DHG" => { 'event_id' => @event.id } }
-      mock(RTurk::GetReviewableHITs).create { mock!.hit_ids { %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345] } }
+      expect(RTurk::GetReviewableHITs).to receive(:create) { double(hit_ids: %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345]) }
       assignments = [
         FakeAssignment.new(:status => "Accepted", :answers => {}),
         FakeAssignment.new(:status => "Submitted", :answers => {"sentiment"=>"happy", "feedback"=>"Take 2"})
       ]
       hit = FakeHit.new(:max_assignments => 2, :assignments => assignments)
-      mock(RTurk::Hit).new("JH3132836336DHG") { hit }
+      expect(RTurk::Hit).to receive(:new).with("JH3132836336DHG") { hit }
 
       # One of the assignments isn't set to "Submitted", so this should get skipped for now.
-      mock.any_instance_of(FakeAssignment).answers.times(0)
+      expect_any_instance_of(FakeAssignment).not_to receive(:answers)
 
       @checker.send :review_hits
 
@@ -329,15 +329,15 @@ describe Agents::HumanTaskAgent do
 
     it "shouldn't do anything if an assignment is missing" do
       @checker.memory['hits'] = { "JH3132836336DHG" => { 'event_id' => @event.id } }
-      mock(RTurk::GetReviewableHITs).create { mock!.hit_ids { %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345] } }
+      expect(RTurk::GetReviewableHITs).to receive(:create) { double(hit_ids: %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345]) }
       assignments = [
         FakeAssignment.new(:status => "Submitted", :answers => {"sentiment"=>"happy", "feedback"=>"Take 2"})
       ]
       hit = FakeHit.new(:max_assignments => 2, :assignments => assignments)
-      mock(RTurk::Hit).new("JH3132836336DHG") { hit }
+      expect(RTurk::Hit).to receive(:new).with("JH3132836336DHG") { hit }
 
       # One of the assignments hasn't shown up yet, so this should get skipped for now.
-      mock.any_instance_of(FakeAssignment).answers.times(0)
+      expect_any_instance_of(FakeAssignment).not_to receive(:answers)
 
       @checker.send :review_hits
 
@@ -348,14 +348,14 @@ describe Agents::HumanTaskAgent do
     context "emitting events" do
       before do
         @checker.memory['hits'] = { "JH3132836336DHG" => { 'event_id' => @event.id } }
-        mock(RTurk::GetReviewableHITs).create { mock!.hit_ids { %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345] } }
+        expect(RTurk::GetReviewableHITs).to receive(:create) { double(hit_ids: %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345]) }
         @assignments = [
           FakeAssignment.new(:status => "Submitted", :answers => {"sentiment"=>"neutral", "feedback"=>""}),
           FakeAssignment.new(:status => "Submitted", :answers => {"sentiment"=>"happy", "feedback"=>"Take 2"})
         ]
         @hit = FakeHit.new(:max_assignments => 2, :assignments => @assignments)
         expect(@hit).not_to be_disposed
-        mock(RTurk::Hit).new("JH3132836336DHG") { @hit }
+        expect(RTurk::Hit).to receive(:new).with("JH3132836336DHG") { @hit }
       end
 
       it "should create events when all assignments are ready" do
@@ -398,7 +398,7 @@ describe Agents::HumanTaskAgent do
       before do
         @checker.options['combination_mode'] = "take_majority"
         @checker.memory['hits'] = { "JH3132836336DHG" => { 'event_id' => @event.id } }
-        mock(RTurk::GetReviewableHITs).create { mock!.hit_ids { %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345] } }
+        expect(RTurk::GetReviewableHITs).to receive(:create) { double(hit_ids: %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345]) }
       end
 
       it "should take the majority votes of all questions" do
@@ -422,7 +422,7 @@ describe Agents::HumanTaskAgent do
           FakeAssignment.new(:status => "Submitted", :answers => {"sentiment"=>"happy", "age_range"=>">50"})
         ]
         hit = FakeHit.new(:max_assignments => 4, :assignments => assignments)
-        mock(RTurk::Hit).new("JH3132836336DHG") { hit }
+        expect(RTurk::Hit).to receive(:new).with("JH3132836336DHG") { hit }
 
         expect {
           @checker.send :review_hits
@@ -475,7 +475,7 @@ describe Agents::HumanTaskAgent do
           FakeAssignment.new(:status => "Submitted", :answers => { "rating"=>"2" })
         ]
         hit = FakeHit.new(:max_assignments => 5, :assignments => assignments)
-        mock(RTurk::Hit).new("JH3132836336DHG") { hit }
+        expect(RTurk::Hit).to receive(:new).with("JH3132836336DHG") { hit }
 
         expect {
           @checker.send :review_hits
@@ -509,7 +509,7 @@ describe Agents::HumanTaskAgent do
           'row_template' => "This is {{sentiment}}"
         }
         @event.save!
-        mock(RTurk::GetReviewableHITs).create { mock!.hit_ids { %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345] } }
+        expect(RTurk::GetReviewableHITs).to receive(:create) { double(hit_ids: %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345]) }
       end
 
       it "creates a poll using the row_template, message, and correct number of assignments" do
@@ -523,7 +523,7 @@ describe Agents::HumanTaskAgent do
           FakeAssignment.new(:status => "Submitted", :answers => {"sentiment"=>"happy",   "feedback"=>"This is my feedback 4"})
         ]
         hit = FakeHit.new(:max_assignments => 4, :assignments => assignments)
-        mock(RTurk::Hit).new("JH3132836336DHG") { hit }
+        expect(RTurk::Hit).to receive(:new).with("JH3132836336DHG") { hit }
 
         expect(@checker.memory['hits']["JH3132836336DHG"]).to be_present
 
@@ -532,8 +532,8 @@ describe Agents::HumanTaskAgent do
         question_form = nil
         hitInterface = OpenStruct.new
         hitInterface.id = "JH39AA63836DH12345"
-        mock(hitInterface).question_form(instance_of Agents::HumanTaskAgent::AgentQuestionForm) { |agent_question_form_instance| question_form = agent_question_form_instance }
-        mock(RTurk::Hit).create(:title => "Hi!").yields(hitInterface) { hitInterface }
+        expect(hitInterface).to receive(:question_form).with(instance_of Agents::HumanTaskAgent::AgentQuestionForm) { |agent_question_form_instance| question_form = agent_question_form_instance }
+        expect(RTurk::Hit).to receive(:create).with(title: "Hi!").and_yield(hitInterface).and_return(hitInterface)
 
         # And finally, the test.
 
@@ -589,7 +589,7 @@ describe Agents::HumanTaskAgent do
           FakeAssignment.new(:status => "Submitted", :answers => {"1" => "3", "2" => "4", "3" => "1", "4" => "4"})
         ]
         hit = FakeHit.new(:max_assignments => 2, :assignments => assignments)
-        mock(RTurk::Hit).new("JH39AA63836DH12345") { hit }
+        expect(RTurk::Hit).to receive(:new).with("JH39AA63836DH12345") { hit }
 
         expect(@checker.memory['hits']["JH39AA63836DH12345"]).to be_present
 

+ 10 - 10
spec/models/agents/imap_folder_agent_spec.rb

@@ -46,14 +46,14 @@ describe Agents::ImapFolderAgent do
       [
         Mail.read(Rails.root.join('spec/data_fixtures/imap1.eml')).tap { |mail|
           mail.extend(MessageMixin)
-          stub(mail).uid.returns(1)
-          stub(mail).raw_mail.returns(mail.encoded)
+          allow(mail).to receive(:uid).and_return(1)
+          allow(mail).to receive(:raw_mail).and_return(mail.encoded)
         },
         Mail.read(Rails.root.join('spec/data_fixtures/imap2.eml')).tap { |mail|
           mail.extend(MessageMixin)
-          stub(mail).uid.returns(2)
-          stub(mail).has_attachment?.returns(true)
-          stub(mail).raw_mail.returns(mail.encoded)
+          allow(mail).to receive(:uid).and_return(2)
+          allow(mail).to receive(:has_attachment?).and_return(true)
+          allow(mail).to receive(:raw_mail).and_return(mail.encoded)
         },
       ]
     }
@@ -94,7 +94,7 @@ describe Agents::ImapFolderAgent do
       @checker.user = users(:bob)
       @checker.save!
 
-      stub(@checker).each_unread_mail.returns { |yielder|
+      allow(@checker).to receive(:each_unread_mail) { |&yielder|
         seen = @checker.lastseen
         notified = @checker.notified
         mails.each_with_object(notified) { |mail|
@@ -255,7 +255,7 @@ describe Agents::ImapFolderAgent do
 
       it 'should never mark mails as read unless mark_as_read is true' do
         mails.each { |mail|
-          stub(mail).mark_as_read.never
+          allow(mail).to receive(:mark_as_read).never
         }
         expect { @checker.check }.to change { Event.count }.by(2)
       end
@@ -263,7 +263,7 @@ describe Agents::ImapFolderAgent do
       it 'should mark mails as read if mark_as_read is true' do
         @checker.options['mark_as_read'] = true
         mails.each { |mail|
-          stub(mail).mark_as_read.once
+          allow(mail).to receive(:mark_as_read).once
         }
         expect { @checker.check }.to change { Event.count }.by(2)
       end
@@ -272,7 +272,7 @@ describe Agents::ImapFolderAgent do
         mails.first.message_id = mails.last.message_id
         @checker.options['mark_as_read'] = true
         mails.each { |mail|
-          stub(mail).mark_as_read.once
+          allow(mail).to receive(:mark_as_read).once
         }
         expect { @checker.check }.to change { Event.count }.by(1)
       end
@@ -280,7 +280,7 @@ describe Agents::ImapFolderAgent do
       it 'should delete mails if delete is true' do
         @checker.options['delete'] = true
         mails.each { |mail|
-          stub(mail).delete.once
+          allow(mail).to receive(:delete).once
         }
         expect { @checker.check }.to change { Event.count }.by(2)
       end

+ 16 - 15
spec/models/agents/jabber_agent_spec.rb

@@ -30,7 +30,7 @@ describe Agents::JabberAgent do
   end
 
   before do
-    stub.any_instance_of(Agents::JabberAgent).deliver { |message| sent << message }
+    allow_any_instance_of(Agents::JabberAgent).to receive(:deliver) { |agent, message| sent << message }
   end
 
   describe "#working?" do
@@ -39,7 +39,7 @@ describe Agents::JabberAgent do
       Agents::JabberAgent.async_receive agent.id, [event.id]
       expect(agent.reload).to be_working # Just received events
       two_days_from_now = 2.days.from_now
-      stub(Time).now { two_days_from_now }
+      allow(Time).to receive(:now) { two_days_from_now }
       expect(agent.reload).not_to be_working # More time has passed than the expected receive period without any new events
     end
   end
@@ -78,15 +78,16 @@ describe Agents::JabberAgent do
 
   describe "receive" do
     it "should send an IM for each event" do
-      event2 = Event.new.tap do |e|
-        e.agent = agents(:bob_weather_agent)
-        e.payload = { :title => 'Another Weather Alert!', :url => 'http://www.weather.com/we-are-screwed' }
-        e.save!
-      end
+      event2 = Event.create!(
+        agent: agents(:bob_weather_agent),
+        payload: { title: 'Another Weather Alert!', url: 'http://www.weather.com/we-are-screwed' },
+      )
 
       agent.receive([event, event2])
-      expect(sent).to eq([ 'Warning! Weather Alert! - http://www.weather.com/',
-                       'Warning! Another Weather Alert! - http://www.weather.com/we-are-screwed'])
+      expect(sent).to eq([
+        'Warning! Weather Alert! - http://www.weather.com/',
+        'Warning! Another Weather Alert! - http://www.weather.com/we-are-screwed'
+      ])
     end
   end
 
@@ -94,21 +95,21 @@ describe Agents::JabberAgent do
     before(:each) do
       @worker = Agents::JabberAgent::Worker.new(agent: agent)
       @worker.setup
-      stub.any_instance_of(Jabber::Client).connect
-      stub.any_instance_of(Jabber::Client).auth
+      allow_any_instance_of(Jabber::Client).to receive(:connect)
+      allow_any_instance_of(Jabber::Client).to receive(:auth)
     end
 
     it "runs" do
       agent.options[:jabber_receiver] = 'someJID'
-      mock.any_instance_of(Jabber::MUC::SimpleMUCClient).join('someJID')
+      expect_any_instance_of(Jabber::MUC::SimpleMUCClient).to receive(:join).with('someJID')
       @worker.run
     end
 
     it "stops" do
       @worker.instance_variable_set(:@client, @worker.client)
-      mock.any_instance_of(Jabber::Client).close
-      mock.any_instance_of(Jabber::Client).stop
-      mock(@worker).thread { mock!.terminate }
+      expect_any_instance_of(Jabber::Client).to receive(:close)
+      expect_any_instance_of(Jabber::Client).to receive(:stop)
+      expect(@worker).to receive(:thread) { double(terminate: nil) }
       @worker.stop
     end
 

+ 2 - 2
spec/models/agents/java_script_agent_spec.rb

@@ -56,7 +56,7 @@ describe Agents::JavaScriptAgent do
         @agent.check
         expect(@agent.reload).to be_working
         three_days_from_now = 3.days.from_now
-        stub(Time).now { three_days_from_now }
+        allow(Time).to receive(:now) { three_days_from_now }
         expect(@agent).not_to be_working
       end
     end
@@ -69,7 +69,7 @@ describe Agents::JavaScriptAgent do
         Agents::JavaScriptAgent.async_receive @agent.id, [events(:bob_website_agent_event).id]
         expect(@agent.reload).to be_working
         two_days_from_now = 2.days.from_now
-        stub(Time).now { two_days_from_now }
+        allow(Time).to receive(:now) { two_days_from_now }
         expect(@agent.reload).not_to be_working
       end
     end

+ 4 - 8
spec/models/agents/jira_agent_spec.rb

@@ -69,7 +69,7 @@ describe Agents::JiraAgent do
       expected_url = "https://jira.atlassian.com/rest/api/2/search?jql=resolution+%3D+unresolved&fields=*all&startAt=0"
       expected_headers = {headers: {"User-Agent"=>"Huginn - https://github.com/huginn/huginn"}, basic_auth: {username: "user", password: "pass"}}
       reply = JSON.parse(File.read(Rails.root.join("spec/data_fixtures/jira.json")))
-      mock(@checker).get(expected_url, expected_headers).returns(reply)
+      expect(@checker).to receive(:get).with(expected_url, expected_headers).and_return(reply)
 
       @checker.check
     end
@@ -81,20 +81,16 @@ describe Agents::JiraAgent do
       expected_headers = {headers: {"User-Agent"=>"Huginn - https://github.com/huginn/huginn"}, basic_auth: {username: "user", password: "pass"}}
       reply = JSON.parse(File.read(Rails.root.join("spec/data_fixtures/jira.json")))
 
-      mock(@checker) do 
-        get(expected_url_1, expected_headers).returns(reply)
-        # time specification
-        get(/\d+-\d+-\d+\+\d+%3A\d+/, expected_headers).returns(reply)
-      end
-
+      expect(@checker).to receive(:get).with(expected_url_1, expected_headers).and_return(reply)
       @checker.check
+      expect(@checker).to receive(:get).with(/\d+-\d+-\d+\+\d+%3A\d+/, expected_headers).and_return(reply)
       @checker.check
     end
   end
   describe "#check" do
     it "should be able to retrieve issues" do
       reply = JSON.parse(File.read(Rails.root.join("spec/data_fixtures/jira.json")))
-      mock(@checker).get(anything,anything).returns(reply)
+      expect(@checker).to receive(:get).and_return(reply)
 
       expect { @checker.check }.to change { Event.count }.by(50)
     end

+ 3 - 3
spec/models/agents/jq_agent_spec.rb

@@ -22,8 +22,8 @@ describe Agents::JqAgent do
 
     context 'when not enabled' do
       before do
-        stub.proxy(ENV).[](anything)
-        stub(ENV).[]('USE_JQ') { nil }
+        allow(ENV).to receive(:[]) { nil }
+        allow(ENV).to receive(:[]).with('USE_JQ') { nil }
       end
 
       it 'should be false' do
@@ -33,7 +33,7 @@ describe Agents::JqAgent do
 
     context 'when jq command is not available' do
       before do
-        stub(Agents::JqAgent).jq_version { nil }
+        allow(Agents::JqAgent).to receive(:jq_version) { nil }
       end
 
       it 'should be false' do

+ 1 - 1
spec/models/agents/liquid_output_agent_spec.rb

@@ -19,7 +19,7 @@ describe Agents::LiquidOutputAgent do
       Agents::LiquidOutputAgent.async_receive agent.id, [events(:bob_website_agent_event).id]
       expect(agent.reload).to be_working
       two_days_from_now = 2.days.from_now
-      stub(Time).now { two_days_from_now }
+      allow(Time).to receive(:now) { two_days_from_now }
       expect(agent.reload).not_to be_working
     end
   end

+ 16 - 16
spec/models/agents/local_file_agent_spec.rb

@@ -144,7 +144,7 @@ describe Agents::LocalFileAgent do
   end
 
   it "get_io opens the file" do
-    mock(File).open('test', 'r')
+    expect(File).to receive(:open).with('test', 'r')
     @checker.get_io('test')
   end
 
@@ -164,21 +164,21 @@ describe Agents::LocalFileAgent do
     before(:each) do
       @checker.options['mode'] = 'write'
       @checker.options['data'] = '{{ data }}'
-      @file_mock = mock()
+      @file_mock = double()
     end
 
     it "writes the data at data into a file" do
-      mock(@file_mock).write('hello world')
+      expect(@file_mock).to receive(:write).with('hello world')
       event = Event.new(payload: {'data' => 'hello world'})
-      mock(File).open(File.join(Rails.root, 'tmp', 'spec'), 'w').yields @file_mock
+      expect(File).to receive(:open).with(File.join(Rails.root, 'tmp', 'spec'), 'w').and_yield(@file_mock)
       @checker.receive([event])
     end
 
     it "appends the data at data onto a file" do
-      mock(@file_mock).write('hello world')
+      expect(@file_mock).to receive(:write).with('hello world')
       @checker.options['append'] = 'true'
       event = Event.new(payload: {'data' => 'hello world'})
-      mock(File).open(File.join(Rails.root, 'tmp', 'spec'), 'a').yields @file_mock
+      expect(File).to receive(:open).with(File.join(Rails.root, 'tmp', 'spec'), 'a').and_yield(@file_mock)
       @checker.receive([event])
     end
 
@@ -196,41 +196,41 @@ describe Agents::LocalFileAgent do
       @checker.options['watch'] = true
       @checker.save
       @worker = Agents::LocalFileAgent::Worker.new(agent: @checker)
-      @listen_mock = mock()
+      @listen_mock = double()
     end
 
     context "#setup" do
       it "initializes the listen gem" do
-        mock(Listen).to(@checker.options['path'], ignore!: [])
+        expect(Listen).to receive(:to).with(@checker.options['path'], ignore!: [])
         @worker.setup
       end
     end
 
     context "#run" do
       before(:each) do
-        stub(Listen).to { @listen_mock }
+        allow(Listen).to receive(:to) { @listen_mock }
         @worker.setup
       end
 
       it "starts to listen to changes in the directory when the path is present" do
-        mock(@worker).sleep
-        mock(@listen_mock).start
+        expect(@worker).to receive(:sleep)
+        expect(@listen_mock).to receive(:start)
         @worker.run
       end
 
       it "does nothing when the path does not exist" do
-        mock(@worker.agent).check_path_existance(true) { false }
-        dont_allow(@listen_mock).start
-        mock(@worker).sleep { raise "Sleeping" }
+        expect(@worker.agent).to receive(:check_path_existance).with(true) { false }
+        expect(@listen_mock).not_to receive(:start)
+        expect(@worker).to receive(:sleep) { raise "Sleeping" }
         expect { @worker.run }.to raise_exception(RuntimeError, 'Sleeping')
       end
     end
 
     context "#stop" do
       it "stops the listen gem" do
-        stub(Listen).to { @listen_mock }
+        allow(Listen).to receive(:to) { @listen_mock }
         @worker.setup
-        mock(@listen_mock).stop
+        expect(@listen_mock).to receive(:stop)
         @worker.stop
       end
     end

+ 1 - 1
spec/models/agents/mqtt_agent_spec.rb

@@ -51,7 +51,7 @@ describe Agents::MqttAgent do
       @checker.check
       expect(@checker.reload).to be_working
       three_days_from_now = 3.days.from_now
-      stub(Time).now { three_days_from_now }
+      allow(Time).to receive(:now) { three_days_from_now }
       expect(@checker).not_to be_working
     end
   end

+ 2 - 2
spec/models/agents/pdf_agent_spec.rb

@@ -16,8 +16,8 @@ describe Agents::PdfInfoAgent do
 
     it "should call HyPDF" do
       expect {
-        mock(agent).open('http://mypdf.com') { "data" }
-        mock(HyPDF).pdfinfo('data') { {title: "Huginn"} }
+        expect(agent).to receive(:open).with('http://mypdf.com') { "data" }
+        expect(HyPDF).to receive(:pdfinfo).with('data') { {title: "Huginn"} }
         agent.receive([@event])
       }.to change { Event.count }.by(1)
       event = Event.last

+ 3 - 3
spec/models/agents/post_agent_spec.rb

@@ -167,8 +167,8 @@ describe Agents::PostAgent do
         /\A--#{qboundary}\r\nContent-Disposition: form-data; name="default"\r\n\r\nvalue\r\n--#{qboundary}\r\nContent-Disposition: form-data; name="file"; filename="local.path"\r\nContent-Length: 8\r\nContent-Type: \r\nContent-Transfer-Encoding: binary\r\n\r\ntestdata\r\n--#{qboundary}--\r\n\z/ === request.body
       }.to_return(status: 200, body: "", headers: {})
       event = Event.new(payload: {file_pointer: {agent_id: 111, file: 'test'}})
-      io_mock = mock()
-      mock(@checker).get_io(event) { StringIO.new("testdata") }
+      io_mock = double()
+      expect(@checker).to receive(:get_io).with(event) { StringIO.new("testdata") }
       @checker.options['no_merge'] = true
       @checker.receive([event])
     end
@@ -341,7 +341,7 @@ describe Agents::PostAgent do
       Agents::PostAgent.async_receive @checker.id, [@event.id]
       expect(@checker.reload).to be_working
       two_days_from_now = 2.days.from_now
-      stub(Time).now { two_days_from_now }
+      allow(Time).to receive(:now) { two_days_from_now }
       expect(@checker.reload).not_to be_working
     end
   end

+ 6 - 6
spec/models/agents/pushbullet_agent_spec.rb

@@ -80,19 +80,19 @@ describe Agents::PushbulletAgent do
 
   describe '#validate_api_key' do
     it "should return true when working" do
-      mock(@checker).devices
+      expect(@checker).to receive(:devices)
       expect(@checker.validate_api_key).to be_truthy
     end
 
     it "should return true when working" do
-      mock(@checker).devices { raise Agents::PushbulletAgent::Unauthorized }
+      expect(@checker).to receive(:devices) { raise Agents::PushbulletAgent::Unauthorized }
       expect(@checker.validate_api_key).to be_falsy
     end
   end
 
   describe '#complete_device_id' do
     it "should return an array" do
-      mock(@checker).devices { [{'iden' => '12345', 'nickname' => 'huginn'}] }
+      expect(@checker).to receive(:devices) { [{'iden' => '12345', 'nickname' => 'huginn'}] }
       expect(@checker.complete_device_id).to eq([{:text=>"All Devices", :id=>"__ALL__"}, {:text=>"huginn", :id=>"12345"}])
     end
   end
@@ -103,7 +103,7 @@ describe Agents::PushbulletAgent do
         with(basic_auth: [@checker.options[:api_key], ''],
              body: "device_iden=124&type=note&title=hello%20from%20huginn&body=One%20two%20test").
         to_return(status: 200, body: "{}", headers: {})
-      dont_allow(@checker).error
+      expect(@checker).not_to receive(:error)
       @checker.receive([@event])
     end
 
@@ -112,7 +112,7 @@ describe Agents::PushbulletAgent do
         with(basic_auth: [@checker.options[:api_key], ''],
              body: "device_iden=124&type=note&title=hello%20from%20huginn&body=One%20two%20test").
         to_return(status: 200, body: '{"error": {"message": "error"}}', headers: {})
-      mock(@checker).error("error")
+      expect(@checker).to receive(:error).with("error")
       @checker.receive([@event])
     end
   end
@@ -136,7 +136,7 @@ describe Agents::PushbulletAgent do
     end
 
     it "should return an empty array on error" do
-      stub(@checker).request { raise Agents::PushbulletAgent::Unauthorized }
+      allow(@checker).to receive(:request) { raise Agents::PushbulletAgent::Unauthorized }
       expect(@checker.send(:devices)).to eq([])
     end
   end

+ 2 - 2
spec/models/agents/pushover_agent_spec.rb

@@ -28,7 +28,7 @@ describe Agents::PushoverAgent do
     @event.save!
 
     @sent_notifications = []
-    stub.any_instance_of(Agents::PushoverAgent).send_notification  { |notification| @sent_notifications << notification}
+    allow_any_instance_of(Agents::PushoverAgent).to receive(:send_notification) { |agent, notification| @sent_notifications << notification }
   end
 
   describe '#receive' do
@@ -159,7 +159,7 @@ describe Agents::PushoverAgent do
       # Just received events
       expect(@checker.reload).to be_working
       two_days_from_now = 2.days.from_now
-      stub(Time).now { two_days_from_now }
+      allow(Time).to receive(:now) { two_days_from_now }
 
       # More time has passed than the expected receive period without any new events
       expect(@checker.reload).not_to be_working

+ 2 - 2
spec/models/agents/read_file_agent_spec.rb

@@ -38,8 +38,8 @@ describe Agents::ReadFileAgent do
   context '#receive' do
     it "emits an event with the contents of the receives files" do
       event = Event.new(payload: {file_pointer: {agent_id: 111, file: 'test'}})
-      io_mock = mock()
-      mock(@checker).get_io(event) { StringIO.new("testdata") }
+      io_mock = double()
+      expect(@checker).to receive(:get_io).with(event) { StringIO.new("testdata") }
       expect { @checker.receive([event]) }.to change(Event, :count).by(1)
       expect(Event.last.payload).to eq('data' => 'testdata')
     end

+ 1 - 1
spec/models/agents/rss_agent_spec.rb

@@ -538,7 +538,7 @@ describe Agents::RssAgent do
 
   describe 'logging errors with the feed url' do
     it 'includes the feed URL when an exception is raised' do
-      mock(Feedjira).parse(anything) { raise StandardError.new("Some error!") }
+      expect(Feedjira).to receive(:parse).with(anything) { raise StandardError.new("Some error!") }
       expect {
         agent.check
       }.not_to raise_error

+ 27 - 27
spec/models/agents/s3_agent_spec.rb

@@ -65,18 +65,18 @@ describe Agents::S3Agent do
 
   describe "#validating" do
     it "validates the key" do
-      mock(@checker).client { raise Aws::S3::Errors::SignatureDoesNotMatch.new('', '') }
+      expect(@checker).to receive(:client) { raise Aws::S3::Errors::SignatureDoesNotMatch.new('', '') }
       expect(@checker.validate_access_key_id).to be_falsy
     end
 
     it "validates the secret" do
-      mock(@checker).buckets { true }
+      expect(@checker).to receive(:buckets) { true }
       expect(@checker.validate_access_key_secret).to be_truthy
     end
   end
 
   it "completes the buckets" do
-    mock(@checker).buckets { [OpenStruct.new(name: 'test'), OpenStruct.new(name: 'test2')]}
+    expect(@checker).to receive(:buckets) { [OpenStruct.new(name: 'test'), OpenStruct.new(name: 'test2')]}
     expect(@checker.complete_bucket).to eq([{text: 'test', id: 'test'}, {text: 'test2', id: 'test2'}])
   end
 
@@ -90,7 +90,7 @@ describe Agents::S3Agent do
   context "#check" do
     context "not watching" do
       it "emits an event for every file" do
-        mock(@checker).get_bucket_contents { {"test"=>"231232", "test2"=>"4564545"} }
+        expect(@checker).to receive(:get_bucket_contents) { {"test"=>"231232", "test2"=>"4564545"} }
         expect { @checker.check }.to change(Event, :count).by(2)
         expect(Event.last.payload).to eq({"file_pointer" => {"file"=>"test2", "agent_id"=> @checker.id}})
       end
@@ -103,7 +103,7 @@ describe Agents::S3Agent do
 
       it "does not emit any events on the first run" do
         contents = {"test"=>"231232", "test2"=>"4564545"}
-        mock(@checker).get_bucket_contents { contents }
+        expect(@checker).to receive(:get_bucket_contents) { contents }
         expect { @checker.check }.not_to change(Event, :count)
         expect(@checker.memory).to eq('seen_contents' => contents)
       end
@@ -111,27 +111,27 @@ describe Agents::S3Agent do
       context "detecting changes" do
         before(:each) do
           contents = {"test"=>"231232", "test2"=>"4564545"}
-          mock(@checker).get_bucket_contents { contents }
+          expect(@checker).to receive(:get_bucket_contents) { contents }
           expect { @checker.check }.not_to change(Event, :count)
           @checker.last_check_at = Time.now
         end
 
         it "emits events for removed files" do
           contents = {"test"=>"231232"}
-          mock(@checker).get_bucket_contents { contents }
+          expect(@checker).to receive(:get_bucket_contents) { contents }
           expect { @checker.check }.to change(Event, :count).by(1)
           expect(Event.last.payload).to eq({"file_pointer" => {"file" => "test2", "agent_id"=> @checker.id}, "event_type" => "removed"})
         end
 
         it "emits events for modified files" do
           contents = {"test"=>"231232", "test2"=>"changed"}
-          mock(@checker).get_bucket_contents { contents }
+          expect(@checker).to receive(:get_bucket_contents) { contents }
           expect { @checker.check }.to change(Event, :count).by(1)
           expect(Event.last.payload).to eq({"file_pointer" => {"file" => "test2", "agent_id"=> @checker.id}, "event_type" => "modified"})
         end
         it "emits events for added files" do
           contents = {"test"=>"231232", "test2"=>"4564545", "test3" => "31231231"}
-          mock(@checker).get_bucket_contents { contents }
+          expect(@checker).to receive(:get_bucket_contents) { contents }
           expect { @checker.check }.to change(Event, :count).by(1)
           expect(Event.last.payload).to eq({"file_pointer" => {"file" => "test3", "agent_id"=> @checker.id}, "event_type" => "added"})
         end
@@ -139,13 +139,13 @@ describe Agents::S3Agent do
 
       context "error handling" do
         it "handles AccessDenied exceptions" do
-          mock(@checker).get_bucket_contents { raise Aws::S3::Errors::AccessDenied.new('', '') }
+          expect(@checker).to receive(:get_bucket_contents) { raise Aws::S3::Errors::AccessDenied.new('', '') }
           expect { @checker.check }.to change(AgentLog, :count).by(1)
           expect(AgentLog.last.message).to eq("Could not access 'testbucket' Aws::S3::Errors::AccessDenied ")
         end
 
         it "handles generic S3 exceptions" do
-          mock(@checker).get_bucket_contents { raise Aws::S3::Errors::PermanentRedirect.new('', 'error') }
+          expect(@checker).to receive(:get_bucket_contents) { raise Aws::S3::Errors::PermanentRedirect.new('', 'error') }
           expect { @checker.check }.to change(AgentLog, :count).by(1)
           expect(AgentLog.last.message).to eq("Aws::S3::Errors::PermanentRedirect: error")
         end
@@ -155,30 +155,30 @@ describe Agents::S3Agent do
 
   it "get_io returns a StringIO object" do
     stringio =StringIO.new
-    mock_response = mock()
-    mock(mock_response).body { stringio }
-    mock_client = mock()
-    mock(mock_client).get_object(bucket: 'testbucket', key: 'testfile') { mock_response }
-    mock(@checker).client { mock_client }
+    mock_response = double()
+    expect(mock_response).to receive(:body) { stringio }
+    mock_client = double()
+    expect(mock_client).to receive(:get_object).with(bucket: 'testbucket', key: 'testfile') { mock_response }
+    expect(@checker).to receive(:client) { mock_client }
     @checker.get_io('testfile')
   end
 
   context "#get_bucket_contents" do
     it "returns a hash with the contents of the bucket" do
-      mock_response = mock()
-      mock(mock_response).contents { [OpenStruct.new(key: 'test', etag: '231232'), OpenStruct.new(key: 'test2', etag: '4564545')] }
-      mock_client = mock()
-      mock(mock_client).list_objects(bucket: 'testbucket') { [mock_response] }
-      mock(@checker).client { mock_client }
+      mock_response = double()
+      expect(mock_response).to receive(:contents) { [OpenStruct.new(key: 'test', etag: '231232'), OpenStruct.new(key: 'test2', etag: '4564545')] }
+      mock_client = double()
+      expect(mock_client).to receive(:list_objects).with(bucket: 'testbucket') { [mock_response] }
+      expect(@checker).to receive(:client) { mock_client }
       expect(@checker.send(:get_bucket_contents)).to eq({"test"=>"231232", "test2"=>"4564545"})
     end
   end
 
   context "#client" do
     it "initializes the S3 client correctly" do
-      mock_credential = mock()
-      mock(Aws::Credentials).new('32343242', '1231312') { mock_credential }
-      mock(Aws::S3::Client).new(credentials: mock_credential,
+      mock_credential = double()
+      expect(Aws::Credentials).to receive(:new).with('32343242', '1231312') { mock_credential }
+      expect(Aws::S3::Client).to receive(:new).with(credentials: mock_credential,
                                       region: 'us-east-1')
       @checker.send(:client)
     end
@@ -204,9 +204,9 @@ describe Agents::S3Agent do
     end
 
     it "writes the data at data into a file" do
-      client_mock = mock()
-      mock(client_mock).put_object(bucket: @checker.options['bucket'], key: @checker.options['filename'], body: 'hello world!')
-      mock(@checker).client { client_mock }
+      client_mock = double()
+      expect(client_mock).to receive(:put_object).with(bucket: @checker.options['bucket'], key: @checker.options['filename'], body: 'hello world!')
+      expect(@checker).to receive(:client) { client_mock }
       event = Event.new(payload: {'data' => 'hello world!'})
       @checker.receive([event])
     end

+ 2 - 2
spec/models/agents/scheduler_agent_spec.rb

@@ -44,11 +44,11 @@ describe Agents::SchedulerAgent do
       agent.options['schedule'] = '*/1 * * *'
       expect(agent).not_to be_valid
 
-      stub(agent).second_precision_enabled { true }
+      allow(agent).to receive(:second_precision_enabled) { true }
       agent.options['schedule'] = '*/15 * * * * *'
       expect(agent).to be_valid
 
-      stub(agent).second_precision_enabled { false }
+      allow(agent).to receive(:second_precision_enabled) { false }
       agent.options['schedule'] = '*/10 * * * * *'
       expect(agent).not_to be_valid
 

+ 1 - 1
spec/models/agents/sentiment_agent_spec.rb

@@ -28,7 +28,7 @@ describe Agents::SentimentAgent do
             Agents::SentimentAgent.async_receive @checker.id, [@event.id]
             expect(@checker.reload).to be_working
             two_days_from_now = 2.days.from_now
-            stub(Time).now { two_days_from_now }  
+            allow(Time).to receive(:now) { two_days_from_now }  
             expect(@checker.reload).not_to be_working
         end
     end

+ 11 - 14
spec/models/agents/shell_command_agent_spec.rb

@@ -33,7 +33,7 @@ describe Agents::ShellCommandAgent do
     }
     @event.save!
 
-    stub(Agents::ShellCommandAgent).should_run? { true }
+    allow(Agents::ShellCommandAgent).to receive(:should_run?) { true }
   end
 
   describe "validation" do
@@ -60,13 +60,13 @@ describe Agents::ShellCommandAgent do
 
   describe "#working?" do
     it "generating events as scheduled" do
-      stub(@checker).run_command(@valid_path, 'pwd', nil, {}) { ["fake pwd output", "", 0] }
+      allow(@checker).to receive(:run_command).with(@valid_path, 'pwd', nil, {}) { ["fake pwd output", "", 0] }
 
       expect(@checker).not_to be_working
       @checker.check
       expect(@checker.reload).to be_working
       three_days_from_now = 3.days.from_now
-      stub(Time).now { three_days_from_now }
+      allow(Time).to receive(:now) { three_days_from_now }
       expect(@checker).not_to be_working
     end
   end
@@ -74,12 +74,12 @@ describe Agents::ShellCommandAgent do
   describe "#check" do
     before do
       orig_run_command = @checker.method(:run_command)
-      stub(@checker).run_command(@valid_path, 'pwd', nil, {}) { ["fake pwd output", "", 0] }
-      stub(@checker).run_command(@valid_path, 'empty_output', nil, {}) { ["", "", 0] }
-      stub(@checker).run_command(@valid_path, 'failure', nil, {}) { ["failed", "error message", 1] }
-      stub(@checker).run_command(@valid_path, 'echo $BUNDLE_GEMFILE', nil, unbundle: true) { orig_run_command.(@valid_path, 'echo $BUNDLE_GEMFILE', nil, unbundle: true) }
+      allow(@checker).to receive(:run_command).with(@valid_path, 'pwd', nil, {}) { ["fake pwd output", "", 0] }
+      allow(@checker).to receive(:run_command).with(@valid_path, 'empty_output', nil, {}) { ["", "", 0] }
+      allow(@checker).to receive(:run_command).with(@valid_path, 'failure', nil, {}) { ["failed", "error message", 1] }
+      allow(@checker).to receive(:run_command).with(@valid_path, 'echo $BUNDLE_GEMFILE', nil, unbundle: true) { orig_run_command.(@valid_path, 'echo $BUNDLE_GEMFILE', nil, unbundle: true) }
       [[], [{}], [{ unbundle: false }]].each do |rest|
-        stub(@checker).run_command(@valid_path, 'echo $BUNDLE_GEMFILE', nil, *rest) { [ENV['BUNDLE_GEMFILE'].to_s, "", 0] }
+        allow(@checker).to receive(:run_command).with(@valid_path, 'echo $BUNDLE_GEMFILE', nil, *rest) { [ENV['BUNDLE_GEMFILE'].to_s, "", 0] }
       end
     end
 
@@ -127,16 +127,13 @@ describe Agents::ShellCommandAgent do
     end
 
     it "does not run when should_run? is false" do
-      stub(Agents::ShellCommandAgent).should_run? { false }
+      allow(Agents::ShellCommandAgent).to receive(:should_run?) { false }
       expect { @checker.check }.not_to change { Event.count }
     end
 
     describe "with unbundle" do
       before do
         @checker.options[:command] = 'echo $BUNDLE_GEMFILE'
-        if ENV['TRAVIS'] == 'true'
-          stub.proxy(Bundler).original_env { |env| env.except('BUNDLE_GEMFILE') }
-        end
       end
 
       context "unspecified" do
@@ -172,7 +169,7 @@ describe Agents::ShellCommandAgent do
 
   describe "#receive" do
     before do
-      stub(@checker).run_command(@valid_path, @event.payload[:cmd], nil, {}) { ["fake ls output", "", 0] }
+      allow(@checker).to receive(:run_command).with(@valid_path, @event.payload[:cmd], nil, {}) { ["fake ls output", "", 0] }
     end
 
     it "creates events" do
@@ -191,7 +188,7 @@ describe Agents::ShellCommandAgent do
     end
 
     it "does not run when should_run? is false" do
-      stub(Agents::ShellCommandAgent).should_run? { false }
+      allow(Agents::ShellCommandAgent).to receive(:should_run?) { false }
 
       expect {
         @checker.receive([@event])

+ 2 - 4
spec/models/agents/slack_agent_spec.rb

@@ -60,13 +60,11 @@ describe Agents::SlackAgent do
 
   describe "#receive" do
     it "receive an event without errors" do
-      any_instance_of(Slack::Notifier) do |obj|
-        mock(obj).ping(@event.payload[:message],
+      expect_any_instance_of(Slack::Notifier).to receive(:ping).with(@event.payload[:message],
                        attachments: [{'fallback' => @fallback}],
                        channel: @event.payload[:channel],
                        username: @event.payload[:username]
                       )
-      end
 
       expect { @checker.receive([@event]) }.not_to raise_error
     end
@@ -74,7 +72,7 @@ describe Agents::SlackAgent do
 
   describe "#working?" do
     it "should call received_event_without_error?" do
-      mock(@checker).received_event_without_error?
+      expect(@checker).to receive(:received_event_without_error?)
       @checker.working?
     end
   end

+ 1 - 1
spec/models/agents/stubhub_agent_spec.rb

@@ -60,7 +60,7 @@ describe Agents::StubhubAgent do
       Agents::StubhubAgent.async_check @stubhub_agent.id
       expect(@stubhub_agent.reload).to be_working
       two_days_from_now = 2.days.from_now
-      stub(Time).now { two_days_from_now }
+      allow(Time).to receive(:now) { two_days_from_now }
       expect(@stubhub_agent.reload).not_to be_working
     end
   end

+ 1 - 1
spec/models/agents/telegram_agent_spec.rb

@@ -26,7 +26,7 @@ describe Agents::TelegramAgent do
   end
 
   def stub_methods
-    stub.any_instance_of(Agents::TelegramAgent).send_message do |method, params|
+    allow_any_instance_of(Agents::TelegramAgent).to receive(:send_message) do |agent, method, params|
       @sent_messages << { method => params }
     end
   end

+ 1 - 1
spec/models/agents/trigger_agent_spec.rb

@@ -105,7 +105,7 @@ describe Agents::TriggerAgent do
       Agents::TriggerAgent.async_receive(@checker.id, [@event.id])
       expect(@checker.reload).to be_working # Events received
       three_days_from_now = 3.days.from_now
-      stub(Time).now { three_days_from_now }
+      allow(Time).to receive(:now) { three_days_from_now }
       expect(@checker.reload).not_to be_working # too much time has passed
     end
   end

+ 6 - 5
spec/models/agents/tumblr_likes_agent_spec.rb

@@ -2,12 +2,13 @@ require 'rails_helper'
 
 describe Agents::TumblrLikesAgent do
   before do
-    stub.any_instance_of(Agents::TumblrLikesAgent).tumblr {
-      obj = Object.new
-      stub(obj).blog_likes('wendys.tumblr.com', after: 0) {
-        JSON.parse File.read(Rails.root.join('spec/data_fixtures/tumblr_likes.json'))
+    allow_any_instance_of(Agents::TumblrLikesAgent).to receive(:tumblr) {
+      double.tap { |obj|
+        allow(obj).to receive(:blog_likes).with('wendys.tumblr.com', after: 0) {
+          JSON.parse File.read(Rails.root.join('spec/data_fixtures/tumblr_likes.json'))
+        }
+        allow(obj).to receive(:blog_likes).with('notfound.tumblr.com', after: 0) { { 'status' => 404, 'msg' => 'Not Found' } }
       }
-      stub(obj).blog_likes('notfound.tumblr.com', after: 0) { { 'status' => 404, 'msg' => 'Not Found' } }
     }
   end
 

+ 8 - 7
spec/models/agents/tumblr_publish_agent_spec.rb

@@ -28,11 +28,10 @@ describe Agents::TumblrPublishAgent do
         "title" => "Gonna rain...",
         "link" => "http://huginnbot.tumblr.com/gonna-rain..."
       }
-      stub.any_instance_of(Agents::TumblrPublishAgent).tumblr {
-        obj = Object.new
-        stub(obj).text(anything, anything) { { "id" => "5" } }
-        stub(obj).posts("huginnbot.tumblr.com", {:id => "5"}) {
-          {"posts" => [@post_body]}
+      allow_any_instance_of(Agents::TumblrPublishAgent).to receive(:tumblr) {
+        double.tap { |obj|
+          allow(obj).to receive(:text).with(anything, anything) { { "id" => "5" } }
+          allow(obj).to receive(:posts).with("huginnbot.tumblr.com", { id: "5" }) { {"posts" => [@post_body]} }
         }
       }
 
@@ -71,8 +70,10 @@ describe Agents::TumblrPublishAgent do
       @event.payload = { :title => "Gonna rain...", :body => 'San Francisco is gonna get wet' }
       @event.save!
 
-      stub.any_instance_of(Agents::TumblrPublishAgent).tumblr {
-        stub!.text(anything, anything) { {"status" => 401,"msg" => "Not Authorized"} }
+      allow_any_instance_of(Agents::TumblrPublishAgent).to receive(:tumblr) {
+        double.tap { |obj|
+          allow(obj).to receive(:text).with(anything, anything) { {"status" => 401,"msg" => "Not Authorized"} }
+        }
       }
     end
 

+ 16 - 18
spec/models/agents/twilio_agent_spec.rb

@@ -22,26 +22,24 @@ describe Agents::TwilioAgent do
     @messages = []
     @calls = []
 
-    stub(Twilio::REST::Client).new do
-      c = Object.new
-      stub(c).calls do
-        l = Object.new
-        stub(l).create do |message|
-          @calls << message
+    allow(Twilio::REST::Client).to receive(:new) do
+      instance_double(Twilio::REST::Client).tap { |c|
+        allow(c).to receive(:calls) do
+          double.tap { |l|
+            allow(l).to receive(:create) do |message|
+              @calls << message
+            end
+          }
         end
-        l
-      end
-      stub(c).messages do
-        l = Object.new
-        stub(l).create do |message|
-          @messages << message
+        allow(c).to receive(:messages) do
+          double.tap { |l|
+            allow(l).to receive(:create) do |message|
+              @messages << message
+            end
+          }
         end
-        l
-      end
-      c
+      }
     end
-
-    stub.any_instance_of(Twilio::TwiML::VoiceResponse)
   end
 
   describe '#receive' do
@@ -83,7 +81,7 @@ describe Agents::TwilioAgent do
       Agents::TwilioAgent.async_receive @checker.id, [@event.id]
       expect(@checker.reload).to be_working # Just received events
       two_days_from_now = 2.days.from_now
-      stub(Time).now { two_days_from_now }
+      allow(Time).to receive(:now) { two_days_from_now }
       expect(@checker.reload).not_to be_working # More time has passed than the expected receive period without any new events
     end
   end

+ 1 - 1
spec/models/agents/twilio_receive_text_agent_spec.rb

@@ -8,7 +8,7 @@ require 'rails_helper'
 
 describe Agents::TwilioReceiveTextAgent do
   before do
-    stub.any_instance_of(Twilio::Security::RequestValidator).validate { true }
+    allow_any_instance_of(Twilio::Security::RequestValidator).to receive(:validate) { true }
   end
 
   let(:payload) { 

+ 9 - 9
spec/models/agents/twitter_action_agent_spec.rb

@@ -34,14 +34,14 @@ describe Agents::TwitterActionAgent do
 
       context 'when the twitter client succeeds retweeting' do
         it 'should retweet the tweets from the payload' do
-          mock(@agent.twitter).retweet([@tweet1, @tweet2])
+          expect(@agent.twitter).to receive(:retweet).with([@tweet1, @tweet2])
           @agent.receive([@event1, @event2])
         end
       end
 
       context 'when the twitter client fails retweeting' do
         it 'creates an event with tweet info and the error message' do
-          stub(@agent.twitter).retweet(anything) {
+          allow(@agent.twitter).to receive(:retweet).with(anything) {
             raise Twitter::Error.new('uh oh')
           }
 
@@ -77,14 +77,14 @@ describe Agents::TwitterActionAgent do
 
       context 'when the twitter client succeeds favoriting' do
         it 'should favorite the tweets from the payload' do
-          mock(@agent.twitter).favorite([@tweet1, @tweet2])
+          expect(@agent.twitter).to receive(:favorite).with([@tweet1, @tweet2])
           @agent.receive([@event1, @event2])
         end
       end
 
       context 'when the twitter client fails retweeting' do
         it 'creates an event with tweet info and the error message' do
-          stub(@agent.twitter).favorite(anything) {
+          allow(@agent.twitter).to receive(:favorite).with(anything) {
             raise Twitter::Error.new('uh oh')
           }
 
@@ -112,7 +112,7 @@ describe Agents::TwitterActionAgent do
       let(:agent) { build_agent.tap(&:save!) }
 
       it 're-raises the exception on failure' do
-        stub(agent.twitter).retweet(anything) {
+        allow(agent.twitter).to receive(:retweet).with(anything) {
           raise Twitter::Error.new('uh oh')
         }
 
@@ -120,7 +120,7 @@ describe Agents::TwitterActionAgent do
       end
 
       it 'does not re-raise the exception on "already retweeted" error' do
-        stub(agent.twitter).retweet(anything) {
+        allow(agent.twitter).to receive(:retweet).with(anything) {
           raise Twitter::Error::AlreadyRetweeted.new('You have already retweeted this tweet.')
         }
 
@@ -128,7 +128,7 @@ describe Agents::TwitterActionAgent do
       end
 
       it 'does not re-raise the exception on "already favorited" error' do
-        stub(agent.twitter).retweet(anything) {
+        allow(agent.twitter).to receive(:retweet).with(anything) {
           raise Twitter::Error::AlreadyFavorited.new('You have already favorited this status.')
         }
 
@@ -175,7 +175,7 @@ describe Agents::TwitterActionAgent do
 
   describe '#working?' do
     before do
-      stub.any_instance_of(Twitter::REST::Client).retweet(anything)
+      allow_any_instance_of(Twitter::REST::Client).to receive(:retweet)
     end
 
     it 'checks if events have been received within the expected time period' do
@@ -188,7 +188,7 @@ describe Agents::TwitterActionAgent do
       expect(agent.reload).to be_working # Just received events
 
       two_days_from_now = 2.days.from_now
-      stub(Time).now { two_days_from_now }
+      allow(Time).to receive(:now) { two_days_from_now }
       expect(agent.reload).not_to be_working # Too much time has passed
     end
   end

+ 2 - 2
spec/models/agents/twitter_publish_agent_spec.rb

@@ -23,7 +23,7 @@ describe Agents::TwitterPublishAgent do
     @event.save!
 
     @sent_messages = []
-    stub.any_instance_of(Agents::TwitterPublishAgent).publish_tweet { |message|
+    allow_any_instance_of(Agents::TwitterPublishAgent).to receive(:publish_tweet) { |message|
       @sent_messages << message
       OpenStruct.new(:id => 454209588376502272)
     }
@@ -53,7 +53,7 @@ describe Agents::TwitterPublishAgent do
       Agents::TwitterPublishAgent.async_receive(@checker.id, [@event.id])
       expect(@checker.reload).to be_working # Just received events
       two_days_from_now = 2.days.from_now
-      stub(Time).now { two_days_from_now }
+      allow(Time).to receive(:now) { two_days_from_now }
       expect(@checker.reload).not_to be_working # More time has passed than the expected receive period without any new events
     end
   end

+ 47 - 38
spec/models/agents/twitter_stream_agent_spec.rb

@@ -129,8 +129,8 @@ describe Agents::TwitterStreamAgent do
 
   context "#setup_worker" do
     it "ensures the dependencies are available" do
-      mock(STDERR).puts(Agents::TwitterStreamAgent.twitter_dependencies_missing)
-      mock(Agents::TwitterStreamAgent).dependencies_missing? { true }
+      expect(STDERR).to receive(:puts).with(Agents::TwitterStreamAgent.twitter_dependencies_missing)
+      expect(Agents::TwitterStreamAgent).to receive(:dependencies_missing?) { true }
       expect(Agents::TwitterStreamAgent.setup_worker).to eq(false)
     end
 
@@ -167,7 +167,7 @@ describe Agents::TwitterStreamAgent do
 
   describe Agents::TwitterStreamAgent::Worker do
     before(:each) do
-      @mock_agent = mock!
+      @mock_agent = double
       @config = {agent: @agent, config: {filter_to_agent_map: {'agent' => [@mock_agent]}}}
       @worker = Agents::TwitterStreamAgent::Worker.new(@config)
       @worker.instance_variable_set(:@recent_tweets, [])
@@ -177,79 +177,88 @@ describe Agents::TwitterStreamAgent do
 
     context "#run" do
       before(:each) do
-        mock(EventMachine).run.yields
-        mock(EventMachine).add_periodic_timer(3600)
+        allow(EventMachine).to receive(:run).and_yield
+        allow(EventMachine).to receive(:add_periodic_timer).with(3600)
       end
 
       it "starts the stream" do
-        mock(@worker).stream!(['agent'], @agent)
-        mock(Thread).stop
+        expect(@worker).to receive(:stream!).with(['agent'], @agent)
+        expect(Thread).to receive(:stop)
         @worker.run
       end
 
       it "yields received tweets" do
-        mock(@worker).stream!(['agent'], @agent).yields('status' => 'hello')
-        mock(@worker).handle_status('status' => 'hello')
-        mock(Thread).stop
+        expect(@worker).to receive(:stream!).with(['agent'], @agent).and_yield('status' => 'hello')
+        expect(@worker).to receive(:handle_status).with('status' => 'hello')
+        expect(Thread).to receive(:stop)
         @worker.run
       end
     end
 
     context "#stop" do
       it "stops the thread" do
-        mock(@worker).terminate_thread!
+        expect(@worker).to receive(:terminate_thread!)
         @worker.stop
       end
     end
 
     context "stream!" do
-      def stub_without(method = nil)
-        stream_stub = stub!
-        stream_stub.each_item if method != :each_item
-        stream_stub.on_error if method != :on_error
-        stream_stub.on_no_data if method != :on_no_data
-        stream_stub.on_max_reconnects if method != :on_max_reconnects
-        stub(Twitter::JSONStream).connect { stream_stub }
-        stream_stub
+      def stream_stub
+        stream = double(
+          each_item: nil,
+          on_error: nil,
+          on_no_data: nil,
+          on_max_reconnects: nil,
+        )
+        allow(Twitter::JSONStream).to receive(:connect) { stream }
+        stream
+      end
+
+      def stream_stub_yielding(**pairs)
+        stream = stream_stub
+        pairs.each do |method, args|
+          expect(stream).to receive(method).and_yield(*args)
+        end
+        stream
       end
 
       it "initializes Twitter::JSONStream" do
-        mock(Twitter::JSONStream).connect({:path=>"/1.1/statuses/filter.json?track=agent",
+        expect(Twitter::JSONStream).to receive(:connect).with({:path=>"/1.1/statuses/filter.json?track=agent",
                                            :ssl=>true, :oauth=>{:consumer_key=>"twitteroauthkey",
                                            :consumer_secret=>"twitteroauthsecret",
                                            :access_key=>"1234token",
                                            :access_secret=>"56789secret"}
-                                          }) { stub_without }
+                                          }) { stream_stub }
         @worker.send(:stream!, ['agent'], @agent)
       end
 
       context "callback handling" do
         it "logs error messages" do
-          stub_without(:on_error).on_error.yields('woups')
-          mock(STDERR).puts(anything) { |text| expect(text).to match(/woups/) }
-          mock(STDERR).puts(anything) { |text| expect(text).to match(/Sleeping/) }
-          mock(@worker).sleep(15)
-          mock(@worker).restart!
+          stream_stub_yielding(on_error: ['woups'])
+          expect(STDERR).to receive(:puts).with(anything) { |text| expect(text).to match(/woups/) }
+          expect(STDERR).to receive(:puts).with(anything) { |text| expect(text).to match(/Sleeping/) }
+          expect(@worker).to receive(:sleep).with(15)
+          expect(@worker).to receive(:restart!)
           @worker.send(:stream!, ['agent'], @agent)
         end
 
         it "stop when no data was received"do
-          stub_without(:on_no_data).on_no_data.yields
-          mock(@worker).restart!
-          mock(STDERR).puts(anything)
+          stream_stub_yielding(on_no_data: ['woups'])
+          expect(@worker).to receive(:restart!)
+          expect(STDERR).to receive(:puts).with(anything)
           @worker.send(:stream!, ['agent'], @agent)
         end
 
         it "sleeps for 60 seconds on_max_reconnects" do
-          stub_without(:on_max_reconnects).on_max_reconnects.yields
-          mock(STDERR).puts(anything)
-          mock(@worker).sleep(60)
-          mock(@worker).restart!
+          stream_stub_yielding(on_max_reconnects: [1, 1])
+          expect(STDERR).to receive(:puts).with(anything)
+          expect(@worker).to receive(:sleep).with(60)
+          expect(@worker).to receive(:restart!)
           @worker.send(:stream!, ['agent'], @agent)
         end
 
         it "yields every status received" do
-          stub_without(:each_item).each_item.yields({'text' => 'hello'})
+          stream_stub_yielding(each_item: [{'text' => 'hello'}])
           @worker.send(:stream!, ['agent'], @agent) do |status|
             expect(status).to eq({'text' => 'hello'})
           end
@@ -272,15 +281,15 @@ describe Agents::TwitterStreamAgent do
 
       it "deduplicates tweets" do
         @worker.send(:handle_status, {'text' => 'dup', 'id_str' => '1'})
-        mock(@worker).puts(anything) { |text| expect(text).to match(/Skipping/) }
+        expect(@worker).to receive(:puts).with(anything) { |text| expect(text).to match(/Skipping/) }
         @worker.send(:handle_status, {'text' => 'dup', 'id_str' => '1'})
         expect(@worker.instance_variable_get(:'@recent_tweets').select { |str| str == '1' }.length).to eq 1
       end
 
       it "calls the agent to process the tweet" do
-        mock(@mock_agent).name { 'mock' }
-        mock(@mock_agent).process_tweet('agent', {'text' => 'agent'})
-        mock(@worker).puts(anything) { |text| expect(text).to match(/received/) }
+        expect(@mock_agent).to receive(:name) { 'mock' }
+        expect(@mock_agent).to receive(:process_tweet).with('agent', {'text' => 'agent', 'id_str' => '123'})
+        expect(@worker).to receive(:puts).with(a_string_matching(/received/))
         @worker.send(:handle_status, {'text' => 'agent', 'id_str' => '123'})
         expect(@worker.instance_variable_get(:'@recent_tweets')).to include('123')
       end

+ 1 - 1
spec/models/agents/website_agent_spec.rb

@@ -616,7 +616,7 @@ describe Agents::WebsiteAgent do
     describe '#working?' do
       it 'checks if events have been received within the expected receive period' do
         stubbed_time = Time.now
-        stub(Time).now { stubbed_time }
+        allow(Time).to receive(:now) { stubbed_time }
 
         expect(@checker).not_to be_working # No events created
         @checker.check

+ 4 - 4
spec/models/agents/weibo_publish_agent_spec.rb

@@ -24,9 +24,9 @@ describe Agents::WeiboPublishAgent do
 
     @sent_messages = []
     @sent_pictures = []
-    stub.any_instance_of(Agents::WeiboPublishAgent).publish_tweet { |message| @sent_messages << message}
-    stub.any_instance_of(Agents::WeiboPublishAgent).publish_tweet_with_pic { |message, picture| @sent_pictures << picture}
-    stub.any_instance_of(Agents::WeiboPublishAgent).sleep
+    allow_any_instance_of(Agents::WeiboPublishAgent).to receive(:publish_tweet) { |agent, message| @sent_messages << message}
+    allow_any_instance_of(Agents::WeiboPublishAgent).to receive(:publish_tweet_with_pic) { |agent, message, picture| @sent_pictures << picture}
+    allow_any_instance_of(Agents::WeiboPublishAgent).to receive(:sleep)
   end
 
   describe '#receive' do
@@ -99,7 +99,7 @@ describe Agents::WeiboPublishAgent do
       Agents::WeiboPublishAgent.async_receive(@checker.id, [@event.id])
       expect(@checker.reload).to be_working # Just received events
       two_days_from_now = 2.days.from_now
-      stub(Time).now { two_days_from_now }
+      allow(Time).to receive(:now) { two_days_from_now }
       expect(@checker.reload).not_to be_working # More time has passed than the expected receive period without any new events
     end
   end

+ 1 - 1
spec/models/agents/witai_agent_spec.rb

@@ -51,7 +51,7 @@ describe Agents::WitaiAgent do
       Agents::WitaiAgent.async_receive @checker.id, [@event.id]
       expect(@checker.reload).to be_working
       two_days_from_now = 2.days.from_now
-      stub(Time).now { two_days_from_now }
+      allow(Time).to receive(:now) { two_days_from_now }
       expect(@checker.reload).not_to be_working
     end
   end

+ 2 - 2
spec/models/event_spec.rb

@@ -73,7 +73,7 @@ describe Event do
       initial_jane_count = agents(:jane_weather_agent).reload.events_count
 
       current_time = Time.now
-      stub(Time).now { current_time }
+      allow(Time).to receive(:now) { current_time }
 
       Event.cleanup_expired!
       expect(Event.find_by_id(half_hour_event.id)).not_to be_nil
@@ -110,7 +110,7 @@ describe Event do
       event.save!
 
       current_time = Time.now
-      stub(Time).now { current_time }
+      allow(Time).to receive(:now) { current_time }
 
       Event.cleanup_expired!
       expect(Event.find_by_id(event.id)).not_to be_nil

+ 1 - 1
spec/models/service_spec.rb

@@ -58,7 +58,7 @@ describe Service do
     end
 
     it "should call refresh_token! if the token expired" do
-      stub(@service).refresh_token! { @service }
+      allow(@service).to receive(:refresh_token!) { @service }
       @service.expires_at = Time.now - 1.hour
       expect(@service.prepare_request).to eq(@service)
     end

+ 2 - 2
spec/models/user_spec.rb

@@ -7,7 +7,7 @@ describe User do
     describe "invitation_code" do
       context "when configured to use invitation codes" do
         before do
-          stub(User).using_invitation_code? {true}
+          allow(User).to receive(:using_invitation_code?) {true}
         end
         
         it "only accepts valid invitation codes" do
@@ -31,7 +31,7 @@ describe User do
       
       context "when configured not to use invitation codes" do
         before do
-          stub(User).using_invitation_code? {false}
+          allow(User).to receive(:using_invitation_code?) {false}
         end
         
         it "skips this validation" do

+ 1 - 2
spec/rails_helper.rb

@@ -10,7 +10,6 @@ end
 
 require File.expand_path("../../config/environment", __FILE__)
 require 'rspec/rails'
-require 'rr'
 require 'webmock/rspec'
 
 WebMock.disable_net_connect!(allow_localhost: true)
@@ -30,7 +29,7 @@ Shoulda::Matchers.configure do |config|
 end
 
 RSpec.configure do |config|
-  config.mock_with :rr
+  config.mock_with :rspec
 
   # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
   config.fixture_path = "#{::Rails.root}/spec/fixtures"

+ 2 - 2
spec/support/shared_examples/agent_controller_concern.rb

@@ -79,7 +79,7 @@ shared_examples_for AgentControllerConcern do
 
     it "should run targets" do
       control_target_ids = agent.control_targets.map(&:id)
-      stub(Agent).async_check(anything) { |id|
+      allow(Agent).to receive(:async_check).with(anything) { |id|
         control_target_ids.delete(id)
       }
 
@@ -89,7 +89,7 @@ shared_examples_for AgentControllerConcern do
 
     it "should not run disabled targets" do
       control_target_ids = agent.control_targets.map(&:id)
-      stub(Agent).async_check(anything) { |id|
+      allow(Agent).to receive(:async_check).with(anything) { |id|
         control_target_ids.delete(id)
       }
 

+ 2 - 2
spec/support/shared_examples/file_handling_consumer.rb

@@ -26,8 +26,8 @@ shared_examples_for 'FileHandlingConsumer' do
   end
 
   it '#get_upload_io returns a Faraday::UploadIO instance' do
-    io_mock = mock()
-    mock(@checker).get_io(event) { StringIO.new("testdata") }
+    io_mock = double()
+    expect(@checker).to receive(:get_io).with(event) { StringIO.new("testdata") }
 
     upload_io = @checker.get_upload_io(event)
     expect(upload_io).to be_a(Faraday::UploadIO)