forked from danp/resque-mock
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit f25ef64
Showing
6 changed files
with
267 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
source :rubygems | ||
|
||
gemspec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
PATH | ||
remote: . | ||
specs: | ||
resque-mock (1.0.0) | ||
resque | ||
|
||
GEM | ||
remote: http://rubygems.org/ | ||
specs: | ||
diff-lcs (1.1.2) | ||
json (1.5.1) | ||
rack (1.3.0) | ||
rake (0.9.2) | ||
redis (2.2.1) | ||
redis-namespace (1.0.3) | ||
redis (< 3.0.0) | ||
resque (1.17.1) | ||
json (< 1.6, >= 1.4.6) | ||
redis-namespace (~> 1.0.2) | ||
sinatra (>= 0.9.2) | ||
vegas (~> 0.1.2) | ||
rspec (2.6.0) | ||
rspec-core (~> 2.6.0) | ||
rspec-expectations (~> 2.6.0) | ||
rspec-mocks (~> 2.6.0) | ||
rspec-core (2.6.3) | ||
rspec-expectations (2.6.0) | ||
diff-lcs (~> 1.1.2) | ||
rspec-mocks (2.6.0) | ||
sinatra (1.2.6) | ||
rack (~> 1.1) | ||
tilt (< 2.0, >= 1.2.2) | ||
tilt (1.3.2) | ||
vegas (0.1.8) | ||
rack (>= 1.0.0) | ||
|
||
PLATFORMS | ||
ruby | ||
|
||
DEPENDENCIES | ||
rake | ||
resque-mock! | ||
rspec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
begin | ||
require 'rspec/core/rake_task' | ||
RSpec::Core::RakeTask.new do |t| | ||
t.rspec_opts = %w[ -c ] | ||
t.pattern = 'spec/**/*_spec.rb' | ||
end | ||
|
||
task :default => :spec | ||
rescue LoadError | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
require 'resque' | ||
|
||
module Resque | ||
def self.mock! | ||
extend MockExt | ||
end | ||
|
||
module MockExt | ||
def async | ||
@async = true | ||
create_worker_manager | ||
yield | ||
ensure | ||
wait_for_worker_manager | ||
@async = false | ||
end | ||
|
||
def enqueue(klass, *args) | ||
puts "Mock enqueue: async=#{!!@async}, stack_depth=#{caller.size}, #{klass}, #{args.inspect}" if ENV['VERBOSE'] | ||
defer(klass, args) | ||
end | ||
|
||
def enqueue_in(delay, klass, *args) | ||
puts "Mock enqueue in #{delay}: async=#{!!@async}, stack_depth=#{caller.size}, #{klass}, #{args.inspect}" if ENV['VERBOSE'] | ||
defer(klass, args, delay) | ||
end | ||
|
||
def defer(klass, args, delay = nil) | ||
if @async | ||
add_job('payload' => { 'class' => klass, 'args' => args }, 'delay' => delay) | ||
else | ||
sleep delay if delay | ||
klass.perform(*roundtrip(args)) | ||
end | ||
end | ||
|
||
def create_worker_manager | ||
@worker_manager = Thread.new do | ||
Thread.current.abort_on_exception = true | ||
worker_threads = [] | ||
|
||
while true | ||
break if Thread.current[:exit] && worker_threads.empty? && Thread.current[:jobs].empty? | ||
|
||
worker_threads.reject! {|t| !t.alive? } | ||
|
||
while Thread.current[:jobs] && job_data = Thread.current[:jobs].shift | ||
worker_threads << create_worker_thread_for(job_data) | ||
end | ||
|
||
sleep 0.5 | ||
end | ||
end.tap {|t| t[:jobs] = [] } | ||
end | ||
|
||
def wait_for_worker_manager | ||
@worker_manager[:exit] = true | ||
@worker_manager.join | ||
@worker_manager = nil | ||
end | ||
|
||
def create_worker_thread_for(data) | ||
Thread.new(data) do |data| | ||
Thread.current.abort_on_exception = true | ||
if delay = data['delay'] | ||
sleep delay | ||
end | ||
|
||
klass = data['payload']['class'] | ||
puts "Mock perform: #{klass}.perform(*#{data['payload']['args'].inspect})" if ENV['VERBOSE'] | ||
klass.perform(*roundtrip(data['payload']['args'])) | ||
puts "Mock exit: #{klass}.perform(*#{data['payload']['args'].inspect})" if ENV['VERBOSE'] | ||
end | ||
end | ||
|
||
def roundtrip(args) | ||
decode(encode(args)) | ||
end | ||
|
||
def add_job(data) | ||
@worker_manager[:jobs] << data | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
Gem::Specification.new do |gem| | ||
gem.authors = ["Dan Peterson"] | ||
gem.email = ["dpiddy@gmail.com"] | ||
gem.description = gem.summary = %q{Mock resque with threads} | ||
gem.homepage = 'https://github.com/dpiddy/resque-mock' | ||
|
||
gem.files = ['lib/resque/mock.rb'] | ||
gem.test_files = ['Rakefile'] + Dir['spec/**.rb'] | ||
gem.name = "resque-mock" | ||
gem.require_paths = ['lib'] | ||
gem.version = '0.1.0.pre' | ||
|
||
gem.add_runtime_dependency 'resque' | ||
gem.add_development_dependency 'rake' | ||
gem.add_development_dependency 'rspec' | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
#require 'spec_helper' | ||
require 'resque/mock' | ||
|
||
Resque.mock! | ||
|
||
class Performer | ||
def self.run? | ||
!!@args | ||
end | ||
|
||
def self.args | ||
@args | ||
end | ||
|
||
def self.runs | ||
@runs || 0 | ||
end | ||
|
||
def self.perform(*args) | ||
@runs += 1 | ||
if Hash === (options = args.first) | ||
if runs_left = options['runs'] | ||
runs_left -= 1 | ||
if runs_left > 0 | ||
Resque.enqueue(self, 'runs' => runs_left) | ||
end | ||
end | ||
end | ||
@args = args | ||
end | ||
|
||
def self.reset! | ||
@args = nil | ||
@runs = 0 | ||
end | ||
end | ||
|
||
class BadPerformer < Performer | ||
def self.perform(*args) | ||
raise 'hello' | ||
end | ||
end | ||
|
||
describe Resque do | ||
before { Performer.reset! } | ||
|
||
describe "synchronously" do | ||
it "performs jobs without delay" do | ||
Resque.enqueue(Performer, 'hello', 'there') | ||
Performer.should be_run | ||
Performer.args.should == ['hello', 'there'] | ||
end | ||
|
||
it "performs jobs with a delay" do | ||
Resque.should_receive(:sleep).with(5) | ||
Resque.enqueue_in(5, Performer, 'hello', 'there') | ||
Performer.should be_run | ||
Performer.args.should == ['hello', 'there'] | ||
end | ||
|
||
it "can perform more jobs that are queued" do | ||
Resque.enqueue(Performer, 'runs' => 3) | ||
Performer.runs.should == 3 | ||
end | ||
|
||
it "roundtrips arguments" do | ||
Resque.enqueue(Performer, :hello => :there) | ||
Performer.args.should == [{ 'hello' => 'there' }] | ||
end | ||
end | ||
|
||
describe "asynchronously" do | ||
it "performs jobs without delay" do | ||
Resque.async do | ||
Resque.enqueue(Performer, 'hello', 'there') | ||
end | ||
|
||
Performer.should be_run | ||
Performer.args.should == ['hello', 'there'] | ||
end | ||
|
||
it "performs jobs with delay" do | ||
# not immediately sure how to mock this | ||
|
||
Resque.async do | ||
Resque.enqueue_in(5, Performer, 'hello', 'there') | ||
end | ||
|
||
Performer.should be_run | ||
Performer.args.should == ['hello', 'there'] | ||
end | ||
|
||
it "can perform more jobs that are queued" do | ||
Resque.async { Resque.enqueue(Performer, 'runs' => 3) } | ||
Performer.runs.should == 3 | ||
end | ||
|
||
it "roundtrips arguments" do | ||
Resque.async { Resque.enqueue(Performer, :hello => :there) } | ||
Performer.args.should == [{ 'hello' => 'there' }] | ||
end | ||
|
||
it "raises errors encountered inside the block" do | ||
expect { Resque.async { raise 'hello' } }.to raise_error | ||
end | ||
|
||
it "raises errors encountered by jobs" do | ||
expect { Resque.async { Resque.enqueue(BadPerformer, 5) } }.to raise_error | ||
end | ||
end | ||
end |