queue-bus 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.gitignore +5 -0
  2. data/.rbenv-version +1 -0
  3. data/.rspec +1 -0
  4. data/.rvmrc +2 -0
  5. data/Gemfile +6 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.mdown +264 -0
  8. data/Rakefile +1 -0
  9. data/lib/queue-bus.rb +62 -0
  10. data/lib/queue_bus/adapters/base.rb +41 -0
  11. data/lib/queue_bus/adapters/data.rb +65 -0
  12. data/lib/queue_bus/application.rb +121 -0
  13. data/lib/queue_bus/config.rb +98 -0
  14. data/lib/queue_bus/dispatch.rb +61 -0
  15. data/lib/queue_bus/dispatchers.rb +26 -0
  16. data/lib/queue_bus/driver.rb +31 -0
  17. data/lib/queue_bus/heartbeat.rb +109 -0
  18. data/lib/queue_bus/local.rb +38 -0
  19. data/lib/queue_bus/matcher.rb +81 -0
  20. data/lib/queue_bus/publisher.rb +23 -0
  21. data/lib/queue_bus/publishing.rb +80 -0
  22. data/lib/queue_bus/rider.rb +28 -0
  23. data/lib/queue_bus/subscriber.rb +65 -0
  24. data/lib/queue_bus/subscription.rb +55 -0
  25. data/lib/queue_bus/subscription_list.rb +53 -0
  26. data/lib/queue_bus/task_manager.rb +52 -0
  27. data/lib/queue_bus/util.rb +87 -0
  28. data/lib/queue_bus/version.rb +3 -0
  29. data/lib/queue_bus/worker.rb +14 -0
  30. data/lib/tasks/resquebus.rake +2 -0
  31. data/queue-bus.gemspec +32 -0
  32. data/spec/adapter/publish_at_spec.rb +48 -0
  33. data/spec/adapter/support.rb +15 -0
  34. data/spec/adapter_spec.rb +14 -0
  35. data/spec/application_spec.rb +152 -0
  36. data/spec/config_spec.rb +83 -0
  37. data/spec/dispatch_spec.rb +76 -0
  38. data/spec/driver_spec.rb +100 -0
  39. data/spec/heartbeat_spec.rb +44 -0
  40. data/spec/integration_spec.rb +53 -0
  41. data/spec/matcher_spec.rb +143 -0
  42. data/spec/publish_spec.rb +95 -0
  43. data/spec/publisher_spec.rb +7 -0
  44. data/spec/rider_spec.rb +39 -0
  45. data/spec/spec_helper.rb +69 -0
  46. data/spec/subscriber_spec.rb +268 -0
  47. data/spec/subscription_list_spec.rb +43 -0
  48. data/spec/subscription_spec.rb +53 -0
  49. 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,3 @@
1
+ module QueueBus
2
+ VERSION = "0.5.0"
3
+ 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
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
2
+ require 'queue_bus/tasks'
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
@@ -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
+