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.
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
+