queue-bus 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/.rbenv-version +1 -0
- data/.rspec +1 -0
- data/.rvmrc +2 -0
- data/Gemfile +6 -0
- data/MIT-LICENSE +20 -0
- data/README.mdown +264 -0
- data/Rakefile +1 -0
- data/lib/queue-bus.rb +62 -0
- data/lib/queue_bus/adapters/base.rb +41 -0
- data/lib/queue_bus/adapters/data.rb +65 -0
- data/lib/queue_bus/application.rb +121 -0
- data/lib/queue_bus/config.rb +98 -0
- data/lib/queue_bus/dispatch.rb +61 -0
- data/lib/queue_bus/dispatchers.rb +26 -0
- data/lib/queue_bus/driver.rb +31 -0
- data/lib/queue_bus/heartbeat.rb +109 -0
- data/lib/queue_bus/local.rb +38 -0
- data/lib/queue_bus/matcher.rb +81 -0
- data/lib/queue_bus/publisher.rb +23 -0
- data/lib/queue_bus/publishing.rb +80 -0
- data/lib/queue_bus/rider.rb +28 -0
- data/lib/queue_bus/subscriber.rb +65 -0
- data/lib/queue_bus/subscription.rb +55 -0
- data/lib/queue_bus/subscription_list.rb +53 -0
- data/lib/queue_bus/task_manager.rb +52 -0
- data/lib/queue_bus/util.rb +87 -0
- data/lib/queue_bus/version.rb +3 -0
- data/lib/queue_bus/worker.rb +14 -0
- data/lib/tasks/resquebus.rake +2 -0
- data/queue-bus.gemspec +32 -0
- data/spec/adapter/publish_at_spec.rb +48 -0
- data/spec/adapter/support.rb +15 -0
- data/spec/adapter_spec.rb +14 -0
- data/spec/application_spec.rb +152 -0
- data/spec/config_spec.rb +83 -0
- data/spec/dispatch_spec.rb +76 -0
- data/spec/driver_spec.rb +100 -0
- data/spec/heartbeat_spec.rb +44 -0
- data/spec/integration_spec.rb +53 -0
- data/spec/matcher_spec.rb +143 -0
- data/spec/publish_spec.rb +95 -0
- data/spec/publisher_spec.rb +7 -0
- data/spec/rider_spec.rb +39 -0
- data/spec/spec_helper.rb +69 -0
- data/spec/subscriber_spec.rb +268 -0
- data/spec/subscription_list_spec.rb +43 -0
- data/spec/subscription_spec.rb +53 -0
- metadata +192 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
module QueueBus
|
2
|
+
class TaskManager
|
3
|
+
|
4
|
+
attr_reader :logging
|
5
|
+
|
6
|
+
def initialize(logging)
|
7
|
+
@logging = logging
|
8
|
+
end
|
9
|
+
|
10
|
+
def subscribe!
|
11
|
+
count = 0
|
12
|
+
::QueueBus.dispatchers.each do |dispatcher|
|
13
|
+
subscriptions = dispatcher.subscriptions
|
14
|
+
if subscriptions.size > 0
|
15
|
+
count += subscriptions.size
|
16
|
+
log "Subscribing #{dispatcher.app_key} to #{subscriptions.size} subscriptions"
|
17
|
+
app = ::QueueBus::Application.new(dispatcher.app_key)
|
18
|
+
app.subscribe(subscriptions, logging)
|
19
|
+
log " ...done"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
count
|
23
|
+
end
|
24
|
+
|
25
|
+
def unsubscribe!
|
26
|
+
count = 0
|
27
|
+
::QueueBus.dispatchers.each do |dispatcher|
|
28
|
+
log "Unsubcribing from #{dispatcher.app_key}"
|
29
|
+
app = ::QueueBus::Application.new(dispatcher.app_key)
|
30
|
+
app.unsubscribe
|
31
|
+
count += 1
|
32
|
+
log " ...done"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def queue_names
|
37
|
+
# let's not talk to redis in here. Seems to screw things up
|
38
|
+
queues = []
|
39
|
+
::QueueBus.dispatchers.each do |dispatcher|
|
40
|
+
dispatcher.subscriptions.all.each do |sub|
|
41
|
+
queues << sub.queue_name
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
queues.uniq
|
46
|
+
end
|
47
|
+
|
48
|
+
def log(message)
|
49
|
+
puts(message) if logging
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
|
3
|
+
module QueueBus
|
4
|
+
module Util
|
5
|
+
extend self
|
6
|
+
|
7
|
+
class DecodeException < StandardError; end
|
8
|
+
|
9
|
+
# Given a Ruby object, returns a string suitable for storage in a
|
10
|
+
# queue.
|
11
|
+
def encode(object)
|
12
|
+
if MultiJson.respond_to?(:dump) && MultiJson.respond_to?(:load)
|
13
|
+
MultiJson.dump object
|
14
|
+
else
|
15
|
+
MultiJson.encode object
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Given a string, returns a Ruby object.
|
20
|
+
def decode(object)
|
21
|
+
return unless object
|
22
|
+
|
23
|
+
begin
|
24
|
+
if MultiJson.respond_to?(:dump) && MultiJson.respond_to?(:load)
|
25
|
+
MultiJson.load object
|
26
|
+
else
|
27
|
+
MultiJson.decode object
|
28
|
+
end
|
29
|
+
rescue ::MultiJson::DecodeError => e
|
30
|
+
raise DecodeException, e.message, e.backtrace
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def underscore(camel_cased_word)
|
35
|
+
word = camel_cased_word.to_s.dup
|
36
|
+
word.gsub!('::', '/')
|
37
|
+
# word.gsub!(/(?:([A-Za-z\d])|^)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1}#{$1 && '_'}#{$2.downcase}" }
|
38
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
|
39
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
40
|
+
word.tr!("-", "_")
|
41
|
+
word.downcase!
|
42
|
+
word
|
43
|
+
end
|
44
|
+
|
45
|
+
def classify(table_name)
|
46
|
+
# strip out any leading schema name
|
47
|
+
# camelize(singularize(table_name.to_s.sub(/.*\./, '')))
|
48
|
+
camelize(table_name.to_s.sub(/.*\./, ''))
|
49
|
+
end
|
50
|
+
|
51
|
+
def camelize(term)
|
52
|
+
string = term.to_s
|
53
|
+
# string = string.sub(/^[a-z\d]*/) { inflections.acronyms[$&] || $&.capitalize }
|
54
|
+
string = string.sub(/^[a-z\d]*/) { $&.capitalize }
|
55
|
+
# string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
|
56
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
|
57
|
+
string.gsub!(/\//, '::')
|
58
|
+
string
|
59
|
+
end
|
60
|
+
|
61
|
+
def constantize(camel_cased_word)
|
62
|
+
names = camel_cased_word.split('::')
|
63
|
+
names.shift if names.empty? || names.first.empty?
|
64
|
+
|
65
|
+
names.inject(Object) do |constant, name|
|
66
|
+
if constant == Object
|
67
|
+
constant.const_get(name)
|
68
|
+
else
|
69
|
+
candidate = constant.const_get(name)
|
70
|
+
next candidate if constant.const_defined?(name, false)
|
71
|
+
next candidate unless Object.const_defined?(name)
|
72
|
+
|
73
|
+
# Go down the ancestors to check it it's owned
|
74
|
+
# directly before we reach Object or the end of ancestors.
|
75
|
+
constant = constant.ancestors.inject do |const, ancestor|
|
76
|
+
break const if ancestor == Object
|
77
|
+
break ancestor if ancestor.const_defined?(name, false)
|
78
|
+
const
|
79
|
+
end
|
80
|
+
|
81
|
+
# owner is in Object, so raise
|
82
|
+
constant.const_get(name, false)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module QueueBus
|
2
|
+
module Worker
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
::QueueBus.adapter.worker_included(base)
|
6
|
+
end
|
7
|
+
|
8
|
+
# all our workers include this one
|
9
|
+
def perform(*args)
|
10
|
+
# instance method level support for sidekiq
|
11
|
+
self.class.perform(*args)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/queue-bus.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "queue_bus/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "queue-bus"
|
7
|
+
s.version = QueueBus::VERSION
|
8
|
+
s.authors = ["Brian Leonard"]
|
9
|
+
s.email = ["brian@bleonard.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{A simple event bus on top of background queues}
|
12
|
+
s.description = %q{A simple event bus on top of common background queues. Publish and subscribe to events as they occur using what you already have.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "queue-bus"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency("multi_json")
|
22
|
+
s.add_dependency("redis")
|
23
|
+
|
24
|
+
# if using resque
|
25
|
+
# s.add_development_dependency('resque', ['>= 1.10.0', '< 2.0'])
|
26
|
+
# s.add_development_dependency('resque-scheduler', '>= 2.0.1')
|
27
|
+
# s.add_development_dependency('resque-retry')
|
28
|
+
|
29
|
+
s.add_development_dependency("rspec")
|
30
|
+
s.add_development_dependency("timecop")
|
31
|
+
s.add_development_dependency("json_pure")
|
32
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Publishing an event in the future" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
Timecop.freeze(now)
|
7
|
+
QueueBus.stub(:generate_uuid).and_return("idfhlkj")
|
8
|
+
end
|
9
|
+
after(:each) do
|
10
|
+
Timecop.return
|
11
|
+
end
|
12
|
+
let(:delayed_attrs) { {"bus_delayed_until" => future.to_i,
|
13
|
+
"bus_id" => "#{now.to_i}-idfhlkj",
|
14
|
+
"bus_app_hostname" => `hostname 2>&1`.strip.sub(/.local/,'')} }
|
15
|
+
|
16
|
+
let(:bus_attrs) { delayed_attrs.merge({"bus_published_at" => worktime.to_i})}
|
17
|
+
let(:now) { Time.parse("01/01/2013 5:00")}
|
18
|
+
let(:future) { Time.at(now.to_i + 60) }
|
19
|
+
let(:worktime) {Time.at(future.to_i + 1)}
|
20
|
+
|
21
|
+
it "should add it to Redis then to the real queue" do
|
22
|
+
hash = {:one => 1, "two" => "here", "id" => 12 }
|
23
|
+
event_name = "event_name"
|
24
|
+
QueueBus.publish_at(future, event_name, hash)
|
25
|
+
|
26
|
+
schedule = QueueBus.redis { |redis| redis.zrange("delayed_queue_schedule", 0, 1) }
|
27
|
+
schedule.should == [future.to_i.to_s]
|
28
|
+
|
29
|
+
val = QueueBus.redis { |redis| redis.lpop("delayed:#{future.to_i}") }
|
30
|
+
hash = JSON.parse(val)
|
31
|
+
|
32
|
+
hash["class"].should == "QueueBus::Publisher"
|
33
|
+
hash["args"].should == [ {"bus_event_type"=>"event_name", "two"=>"here", "one"=>1, "id" => 12}.merge(delayed_attrs) ]
|
34
|
+
hash["queue"].should == "bus_incoming"
|
35
|
+
|
36
|
+
val = QueueBus.redis { |redis| redis.lpop("queue:bus_incoming") }
|
37
|
+
val.should == nil # nothing really added
|
38
|
+
|
39
|
+
Timecop.freeze(worktime)
|
40
|
+
QueueBus::Publisher.perform(*hash["args"])
|
41
|
+
|
42
|
+
val = QueueBus.redis { |redis| redis.lpop("queue:bus_incoming") }
|
43
|
+
hash = JSON.parse(val)
|
44
|
+
hash["class"].should == "QueueBus::Driver"
|
45
|
+
hash["args"].should == [ {"bus_event_type"=>"event_name", "two"=>"here", "one"=>1, "id" => 12}.merge(bus_attrs) ]
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'redis'
|
2
|
+
|
3
|
+
def reset_test_adapter
|
4
|
+
QueueBus.send(:reset)
|
5
|
+
QueueBus.adapter = :data
|
6
|
+
QueueBus.adapter.redis = Redis.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def adapter_under_test_class
|
10
|
+
QueueBus::Adapters::Data
|
11
|
+
end
|
12
|
+
|
13
|
+
def adapter_under_test_symbol
|
14
|
+
:data
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "adapter is set" do
|
4
|
+
it "should call it's enabled! method on init" do
|
5
|
+
QueueBus.send(:reset)
|
6
|
+
adapter_under_test_class.any_instance.should_receive(:enabled!)
|
7
|
+
instance = adapter_under_test_class.new
|
8
|
+
QueueBus.send(:reset)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should be defaulting to Data from spec_helper" do
|
12
|
+
QueueBus.adapter.is_a?(adapter_under_test_class).should == true
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module QueueBus
|
4
|
+
describe Application do
|
5
|
+
describe ".all" do
|
6
|
+
it "should return empty array when none" do
|
7
|
+
Application.all.should == []
|
8
|
+
end
|
9
|
+
it "should return registered applications when there are some" do
|
10
|
+
Application.new("One").subscribe(test_list(test_sub("fdksjh")))
|
11
|
+
Application.new("Two").subscribe(test_list(test_sub("fdklhf")))
|
12
|
+
Application.new("Three").subscribe(test_list(test_sub("fkld")))
|
13
|
+
|
14
|
+
Application.all.collect(&:app_key).should =~ ["one", "two", "three"]
|
15
|
+
|
16
|
+
Application.new("two").unsubscribe
|
17
|
+
Application.all.collect(&:app_key).should =~ ["one", "three"]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe ".new" do
|
22
|
+
it "should have a key" do
|
23
|
+
Application.new("something").app_key.should == "something"
|
24
|
+
|
25
|
+
Application.new("some thing").app_key.should == "some_thing"
|
26
|
+
Application.new("some-thing").app_key.should == "some_thing"
|
27
|
+
Application.new("some_thing").app_key.should == "some_thing"
|
28
|
+
Application.new("Some Thing").app_key.should == "some_thing"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should raise an error if not valid" do
|
32
|
+
lambda {
|
33
|
+
Application.new("")
|
34
|
+
}.should raise_error
|
35
|
+
|
36
|
+
lambda {
|
37
|
+
Application.new(nil)
|
38
|
+
}.should raise_error
|
39
|
+
|
40
|
+
lambda {
|
41
|
+
Application.new("/")
|
42
|
+
}.should raise_error
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#read_redis_hash" do
|
47
|
+
it "should handle old and new values" do
|
48
|
+
|
49
|
+
QueueBus.redis { |redis| redis.hset("bus_app:myapp", "new_one", QueueBus::Util.encode("queue_name" => "x", "bus_event_type" => "event_name") ) }
|
50
|
+
QueueBus.redis { |redis| redis.hset("bus_app:myapp", "old_one", "oldqueue_name") }
|
51
|
+
app = Application.new("myapp")
|
52
|
+
val = app.send(:read_redis_hash)
|
53
|
+
val.should == {"new_one" => {"queue_name" => "x", "bus_event_type" => "event_name"}, "old_one" => "oldqueue_name"}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#subscribe" do
|
58
|
+
let(:sub1) { test_sub("event_one", "default") }
|
59
|
+
let(:sub2) { test_sub("event_two", "default") }
|
60
|
+
let(:sub3) { test_sub("event_three", "other") }
|
61
|
+
it "should add array to redis" do
|
62
|
+
QueueBus.redis { |redis| redis.get("bus_app:myapp") }.should be_nil
|
63
|
+
Application.new("myapp").subscribe(test_list(sub1, sub2))
|
64
|
+
|
65
|
+
QueueBus.redis { |redis| redis.hgetall("bus_app:myapp") }.should == {"event_two"=>"{\"queue_name\":\"default\",\"key\":\"event_two\",\"class\":\"::QueueBus::Rider\",\"matcher\":{\"bus_event_type\":\"event_two\"}}",
|
66
|
+
"event_one"=>"{\"queue_name\":\"default\",\"key\":\"event_one\",\"class\":\"::QueueBus::Rider\",\"matcher\":{\"bus_event_type\":\"event_one\"}}"}
|
67
|
+
QueueBus.redis { |redis| redis.hkeys("bus_app:myapp") }.should =~ ["event_one", "event_two"]
|
68
|
+
QueueBus.redis { |redis| redis.smembers("bus_apps") }.should =~ ["myapp"]
|
69
|
+
end
|
70
|
+
it "should add string to redis" do
|
71
|
+
QueueBus.redis { |redis| redis.get("bus_app:myapp") }.should be_nil
|
72
|
+
Application.new("myapp").subscribe(test_list(sub1))
|
73
|
+
|
74
|
+
QueueBus.redis { |redis| redis.hgetall("bus_app:myapp") }.should == {"event_one"=>"{\"queue_name\":\"default\",\"key\":\"event_one\",\"class\":\"::QueueBus::Rider\",\"matcher\":{\"bus_event_type\":\"event_one\"}}"}
|
75
|
+
QueueBus.redis { |redis| redis.hkeys("bus_app:myapp") }.should =~ ["event_one"]
|
76
|
+
QueueBus.redis { |redis| redis.smembers("bus_apps") }.should =~ ["myapp"]
|
77
|
+
end
|
78
|
+
it "should multiple queues to redis" do
|
79
|
+
QueueBus.redis { |redis| redis.get("bus_app:myapp") }.should be_nil
|
80
|
+
Application.new("myapp").subscribe(test_list(sub1, sub2, sub3))
|
81
|
+
QueueBus.redis { |redis| redis.hgetall("bus_app:myapp") }.should == {"event_two"=>"{\"queue_name\":\"default\",\"key\":\"event_two\",\"class\":\"::QueueBus::Rider\",\"matcher\":{\"bus_event_type\":\"event_two\"}}", "event_one"=>"{\"queue_name\":\"default\",\"key\":\"event_one\",\"class\":\"::QueueBus::Rider\",\"matcher\":{\"bus_event_type\":\"event_one\"}}",
|
82
|
+
"event_three"=>"{\"queue_name\":\"other\",\"key\":\"event_three\",\"class\":\"::QueueBus::Rider\",\"matcher\":{\"bus_event_type\":\"event_three\"}}"}
|
83
|
+
QueueBus.redis { |redis| redis.hkeys("bus_app:myapp") }.should =~ ["event_three", "event_two", "event_one"]
|
84
|
+
QueueBus.redis { |redis| redis.smembers("bus_apps") }.should =~ ["myapp"]
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should do nothing if nil or empty" do
|
88
|
+
|
89
|
+
QueueBus.redis { |redis| redis.get("bus_app:myapp") }.should be_nil
|
90
|
+
|
91
|
+
Application.new("myapp").subscribe(nil)
|
92
|
+
QueueBus.redis { |redis| redis.get("bus_app:myapp") }.should be_nil
|
93
|
+
|
94
|
+
Application.new("myapp").subscribe([])
|
95
|
+
QueueBus.redis { |redis| redis.get("bus_app:myapp") }.should be_nil
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should call unsubscribe" do
|
99
|
+
app = Application.new("myapp")
|
100
|
+
app.should_receive(:unsubscribe)
|
101
|
+
app.subscribe([])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#unsubscribe" do
|
106
|
+
it "should remove items" do
|
107
|
+
QueueBus.redis { |redis| redis.sadd("bus_apps", "myapp") }
|
108
|
+
QueueBus.redis { |redis| redis.sadd("bus_apps", "other") }
|
109
|
+
QueueBus.redis { |redis| redis.hset("bus_app:myapp", "event_one", "myapp_default") }
|
110
|
+
|
111
|
+
Application.new("myapp").unsubscribe
|
112
|
+
|
113
|
+
QueueBus.redis { |redis| redis.smembers("bus_apps") }.should == ["other"]
|
114
|
+
QueueBus.redis { |redis| redis.get("bus_app:myapp") }.should be_nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "#subscription_matches" do
|
119
|
+
it "should return if it is there" do
|
120
|
+
Application.new("myapp").subscription_matches("bus_event_type"=>"three").collect{|s| [s.app_key, s.key, s.queue_name, s.class_name]}.should == []
|
121
|
+
|
122
|
+
subs = test_list(test_sub("one_x"), test_sub("one_y"), test_sub("one"), test_sub("two"))
|
123
|
+
Application.new("myapp").subscribe(subs)
|
124
|
+
Application.new("myapp").subscription_matches("bus_event_type"=>"three").collect{|s| [s.app_key, s.key, s.queue_name, s.class_name]}.should == []
|
125
|
+
|
126
|
+
Application.new("myapp").subscription_matches("bus_event_type"=>"two").collect{|s| [s.app_key, s.key, s.queue_name, s.class_name]}.should =~ [["myapp", "two", "default", "::QueueBus::Rider"]]
|
127
|
+
Application.new("myapp").subscription_matches("bus_event_type"=>"one").collect{|s| [s.app_key, s.key, s.queue_name, s.class_name]}.should =~ [["myapp", "one", "default", "::QueueBus::Rider"]]
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should handle * wildcards" do
|
131
|
+
subs = test_list(test_sub("one.+"), test_sub("one"), test_sub("one_.*"), test_sub("two"))
|
132
|
+
Application.new("myapp").subscribe(subs)
|
133
|
+
Application.new("myapp").subscription_matches("bus_event_type"=>"three").collect{|s| [s.app_key, s.key, s.queue_name, s.class_name]}.should == []
|
134
|
+
|
135
|
+
Application.new("myapp").subscription_matches("bus_event_type"=>"onex").collect{|s| [s.app_key, s.key, s.queue_name, s.class_name]}.should =~ [["myapp", "one.+", "default", "::QueueBus::Rider"]]
|
136
|
+
Application.new("myapp").subscription_matches("bus_event_type"=>"one").collect{|s| [s.app_key, s.key, s.queue_name, s.class_name]}.should =~ [["myapp", "one", "default", "::QueueBus::Rider"]]
|
137
|
+
Application.new("myapp").subscription_matches("bus_event_type"=>"one_x").collect{|s| [s.app_key, s.key, s.queue_name, s.class_name]}.should =~ [["myapp", "one.+","default", "::QueueBus::Rider"], ["myapp", "one_.*", "default", "::QueueBus::Rider"]]
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should handle actual regular expressions" do
|
141
|
+
subs = test_list(test_sub(/one.+/), test_sub("one"), test_sub(/one_.*/), test_sub("two"))
|
142
|
+
Application.new("myapp").subscribe(subs)
|
143
|
+
Application.new("myapp").subscription_matches("bus_event_type"=>"three").collect{|s| [s.app_key, s.key, s.queue_name, s.class_name]}.should == []
|
144
|
+
|
145
|
+
Application.new("myapp").subscription_matches("bus_event_type"=>"onex").collect{|s| [s.app_key, s.key, s.queue_name, s.class_name]}.should =~ [["myapp", "(?-mix:one.+)", "default", "::QueueBus::Rider"]]
|
146
|
+
Application.new("myapp").subscription_matches("bus_event_type"=>"donex").collect{|s| [s.app_key, s.key, s.queue_name, s.class_name]}.should =~ [["myapp", "(?-mix:one.+)", "default", "::QueueBus::Rider"]]
|
147
|
+
Application.new("myapp").subscription_matches("bus_event_type"=>"one").collect{|s| [s.app_key, s.key, s.queue_name, s.class_name]}.should =~ [["myapp", "one" ,"default", "::QueueBus::Rider"]]
|
148
|
+
Application.new("myapp").subscription_matches("bus_event_type"=>"one_x").collect{|s| [s.app_key, s.key, s.queue_name, s.class_name]}.should =~ [["myapp", "(?-mix:one.+)", "default", "::QueueBus::Rider"], ["myapp", "(?-mix:one_.*)", "default", "::QueueBus::Rider"]]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module QueueBus
|
4
|
+
module Adapters
|
5
|
+
class TestOne
|
6
|
+
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "QueueBus config" do
|
12
|
+
it "should set the default app key" do
|
13
|
+
QueueBus.default_app_key.should == nil
|
14
|
+
|
15
|
+
QueueBus.default_app_key = "my_app"
|
16
|
+
QueueBus.default_app_key.should == "my_app"
|
17
|
+
|
18
|
+
QueueBus.default_app_key = "something here"
|
19
|
+
QueueBus.default_app_key.should == "something_here"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should set the default queue" do
|
23
|
+
QueueBus.default_queue.should == nil
|
24
|
+
|
25
|
+
QueueBus.default_queue = "my_queue"
|
26
|
+
QueueBus.default_queue.should == "my_queue"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should set the local mode" do
|
30
|
+
QueueBus.local_mode.should == nil
|
31
|
+
QueueBus.local_mode = :standalone
|
32
|
+
QueueBus.local_mode.should == :standalone
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should set the hostname" do
|
36
|
+
QueueBus.hostname.should_not == nil
|
37
|
+
QueueBus.hostname = "whatever"
|
38
|
+
QueueBus.hostname.should == "whatever"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should set before_publish callback" do
|
42
|
+
QueueBus.before_publish = lambda {|attributes| 42 }
|
43
|
+
QueueBus.before_publish_callback({}).should == 42
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
it "should use the default Redis connection" do
|
48
|
+
QueueBus.redis { |redis| redis }.should_not eq(nil)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should default to given adapter" do
|
52
|
+
QueueBus.adapter.is_a?(adapter_under_test_class).should == true
|
53
|
+
|
54
|
+
# and should raise if already set
|
55
|
+
lambda {
|
56
|
+
QueueBus.adapter = :data
|
57
|
+
}.should raise_error
|
58
|
+
end
|
59
|
+
|
60
|
+
context "with a fresh load" do
|
61
|
+
before(:each) do
|
62
|
+
QueueBus.send(:reset)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should be able to be set to resque" do
|
66
|
+
QueueBus.adapter = adapter_under_test_symbol
|
67
|
+
QueueBus.adapter.is_a?(adapter_under_test_class).should == true
|
68
|
+
|
69
|
+
# and should raise if already set
|
70
|
+
lambda {
|
71
|
+
QueueBus.adapter = :data
|
72
|
+
}.should raise_error
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should be able to be set to something else" do
|
76
|
+
|
77
|
+
QueueBus.adapter = :test_one
|
78
|
+
QueueBus.adapter.is_a?(QueueBus::Adapters::TestOne).should == true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module QueueBus
|
4
|
+
describe Dispatch do
|
5
|
+
it "should not start with any applications" do
|
6
|
+
Dispatch.new("d").subscriptions.size.should == 0
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should register code to run and execute it" do
|
10
|
+
dispatch = Dispatch.new("d")
|
11
|
+
dispatch.subscribe("my_event") do |attrs|
|
12
|
+
Runner1.run(attrs)
|
13
|
+
end
|
14
|
+
sub = dispatch.subscriptions.key("my_event")
|
15
|
+
sub.send(:executor).is_a?(Proc).should == true
|
16
|
+
|
17
|
+
Runner.value.should == 0
|
18
|
+
dispatch.execute("my_event", {"bus_event_type" => "my_event", "ok" => true})
|
19
|
+
Runner1.value.should == 1
|
20
|
+
Runner1.attributes.should == {"bus_event_type" => "my_event", "ok" => true}
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not crash if not there" do
|
25
|
+
lambda {
|
26
|
+
Dispatch.new("d").execute("fdkjh", "bus_event_type" => "fdkjh")
|
27
|
+
}.should_not raise_error
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "Top Level" do
|
31
|
+
before(:each) do
|
32
|
+
QueueBus.dispatch("testit") do
|
33
|
+
subscribe "event1" do |attributes|
|
34
|
+
Runner2.run(attributes)
|
35
|
+
end
|
36
|
+
|
37
|
+
subscribe "event2" do
|
38
|
+
Runner2.run({})
|
39
|
+
end
|
40
|
+
|
41
|
+
high "event3" do
|
42
|
+
Runner2.run({})
|
43
|
+
end
|
44
|
+
|
45
|
+
low /^patt.+ern/ do
|
46
|
+
Runner.run({})
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should register and run" do
|
52
|
+
Runner2.value.should == 0
|
53
|
+
QueueBus.dispatcher_execute("testit", "event2", "bus_event_type" => "event2")
|
54
|
+
Runner2.value.should == 1
|
55
|
+
QueueBus.dispatcher_execute("testit", "event1", "bus_event_type" => "event1")
|
56
|
+
Runner2.value.should == 2
|
57
|
+
QueueBus.dispatcher_execute("testit", "event1", "bus_event_type" => "event1")
|
58
|
+
Runner2.value.should == 3
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should return the subscriptions" do
|
62
|
+
dispatcher = QueueBus.dispatcher_by_key("testit")
|
63
|
+
subs = dispatcher.subscriptions.all
|
64
|
+
tuples = subs.collect{ |sub| [sub.key, sub.queue_name]}
|
65
|
+
tuples.should =~ [ ["event1", "testit_default"],
|
66
|
+
["event2", "testit_default"],
|
67
|
+
["event3", "testit_high"],
|
68
|
+
[ "(?-mix:^patt.+ern)", "testit_low"]
|
69
|
+
]
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|