brightbox-warren 0.5

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,2 @@
1
+ v0.5. Added filters
2
+ v0.3. Initial release
data/LICENCE ADDED
@@ -0,0 +1,11 @@
1
+ Released under the MIT Licence
2
+
3
+ Copyright (c) 2008 Brightbox Systems Ltd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10
+
11
+ See http://www.brightbox.co.uk/ for contact details.
data/Manifest ADDED
@@ -0,0 +1,25 @@
1
+ CHANGELOG
2
+ examples/authed/receiver.rb
3
+ examples/authed/secret.rb
4
+ examples/authed/sender.rb
5
+ examples/simple/mass_sender.rb
6
+ examples/simple/receiver.rb
7
+ examples/simple/sender.rb
8
+ lib/warren/connection.rb
9
+ lib/warren/message_filter.rb
10
+ lib/warren/message_filters/shared_secret.rb
11
+ lib/warren/message_filters/yaml.rb
12
+ lib/warren/queue.rb
13
+ lib/warren.rb
14
+ LICENCE
15
+ Manifest
16
+ Rakefile
17
+ readme.rdoc
18
+ spec/hash_extend.rb
19
+ spec/spec.opts
20
+ spec/spec_helper.rb
21
+ spec/warren/connection_spec.rb
22
+ spec/warren/message_filter_spec.rb
23
+ spec/warren/queue_spec.rb
24
+ tasks/rdoc.rake
25
+ tasks/rspec.rake
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ # Load in external rakefiles
5
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each do | rake_file |
6
+ load rake_file
7
+ end
8
+
9
+ # Gem stuff
10
+ require 'echoe'
11
+ Echoe.new('warren') do | gem |
12
+ gem.author = ["Caius Durling", "David Smalley"]
13
+ gem.email = 'support@brightbox.co.uk'
14
+ gem.summary = 'Library for pushing messages onto and off RabbitMQ queues'
15
+ gem.url = 'http://github.com/brightbox/warren'
16
+ gem.dependencies = [["amqp", '>= 0.6.0']]
17
+ end
18
+
19
+ desc "Generates the manifest and the gemspec"
20
+ task :build => [:manifest, :build_gemspec] do
21
+ puts "Built!"
22
+ end
23
+
@@ -0,0 +1,23 @@
1
+ require "rubygems"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../../lib/warren")
3
+
4
+ Signal.trap("INT") { AMQP.stop { EM.stop } }
5
+ Signal.trap("TERM") { AMQP.stop { EM.stop } }
6
+
7
+ # Listen to the main queue
8
+ q = "main"
9
+ puts "Listening to the #{q} queue."
10
+
11
+ # Setup the connection directly this time
12
+ Warren::Queue.connection = {:user => "caius", :pass => "caius", :vhost => "/"}
13
+
14
+ # Set the secret key
15
+ require File.expand_path(File.dirname(__FILE__) + "/secret")
16
+ Warren::MessageFilter::SharedSecret.key = SUPER_SECRET_KEY
17
+ # And add the filter
18
+ Warren::MessageFilter << Warren::MessageFilter::SharedSecret
19
+
20
+ # And attach a block for new messages to fire
21
+ Warren::Queue.subscribe(q) do |msg|
22
+ p [Time.now, msg]
23
+ end
@@ -0,0 +1 @@
1
+ SUPER_SECRET_KEY = "This is my super secret string"
@@ -0,0 +1,38 @@
1
+ require "rubygems"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../../lib/warren")
3
+
4
+ Signal.trap("INT") { exit! }
5
+ Signal.trap("TERM") { exit! }
6
+
7
+ # Setup our own connection before generating the queue object
8
+ conn = Warren::Connection.new(
9
+ :user => "caius",
10
+ :pass => "caius",
11
+ :vhost => "/",
12
+ :default_queue => "main"
13
+ )
14
+ # Set the connection for the queue
15
+ Warren::Queue.connection = conn
16
+ # Generate some data to send
17
+ data = {
18
+ :people => [
19
+ :fred => {
20
+ :age => 25,
21
+ :location => "Leeds"
22
+ },
23
+ :george => {
24
+ :age => 32,
25
+ :location => "London"
26
+ }
27
+ ]
28
+ }
29
+
30
+ # Set the secret key
31
+ require File.expand_path(File.dirname(__FILE__) + "/secret")
32
+ Warren::MessageFilter::SharedSecret.key = SUPER_SECRET_KEY
33
+
34
+ # And add the filter
35
+ Warren::MessageFilter << Warren::MessageFilter::SharedSecret
36
+
37
+ # Push a message onto the queue
38
+ p Warren::Queue.publish(:default, data )
@@ -0,0 +1,21 @@
1
+ require "rubygems"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/warren")
3
+
4
+ Signal.trap("INT") { exit! }
5
+ Signal.trap("TERM") { exit! }
6
+
7
+ # Setup our own connection before generating the queue object
8
+ conn = Warren::Connection.new({
9
+ :user => "caius",
10
+ :pass => "caius",
11
+ :vhost => "/",
12
+ :default_queue => "main"
13
+ })
14
+ # Set the connection for the queue
15
+ Warren::Queue.connection = conn
16
+
17
+ 1000.times do | i |
18
+ puts i
19
+ sleep 0.1
20
+ Warren::Queue.publish(:default, "Message no #{i}") { puts "sent ##{i}" }
21
+ end
@@ -0,0 +1,17 @@
1
+ require "rubygems"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/warren")
3
+
4
+ Signal.trap("INT") { AMQP.stop { EM.stop } }
5
+ Signal.trap("TERM") { AMQP.stop { EM.stop } }
6
+
7
+ # Listen to the main queue
8
+ q = "main"
9
+ puts "Listening to the #{q} queue."
10
+
11
+ # Setup the connection directly this time
12
+ Warren::Queue.connection = {:user => "caius", :pass => "caius", :vhost => "/"}
13
+
14
+ # And attach a block for new messages to fire
15
+ Warren::Queue.subscribe(q) do |msg|
16
+ p [Time.now, msg]
17
+ end
@@ -0,0 +1,33 @@
1
+ require "rubygems"
2
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/warren")
3
+
4
+ Signal.trap("INT") { exit! }
5
+ Signal.trap("TERM") { exit! }
6
+
7
+ # Setup our own connection before generating the queue object
8
+ conn = Warren::Connection.new(
9
+ :user => "caius",
10
+ :pass => "caius",
11
+ :vhost => "/",
12
+ :default_queue => "main"
13
+ )
14
+ # Set the connection for the queue
15
+ Warren::Queue.connection = conn
16
+ # Generate some data to send
17
+ data = {
18
+ :people => [
19
+ :fred => {
20
+ :age => 25,
21
+ :location => "Leeds"
22
+ },
23
+ :george => {
24
+ :age => 32,
25
+ :location => "London"
26
+ }
27
+ ]
28
+ }
29
+ # Push a message onto the queue
30
+ p Warren::Queue.publish(:default, data )
31
+
32
+ # And then push a message onto the queue, returning "foo"
33
+ p Warren::Queue.publish(:default, data) { "foo" }
@@ -0,0 +1,37 @@
1
+ class Warren::Connection
2
+
3
+ # Creates a new connection with the options passed in.
4
+ # Requires at least a :user, :pass and :vhost else will raise
5
+ # InvalidConnectionDetails.
6
+ def initialize opts = {}
7
+ # Check they've passed in the stuff without a default on it
8
+ unless opts.has_key?(:user) && opts.has_key?(:pass) && opts.has_key?(:vhost)
9
+ raise InvalidConnectionDetails, "Missing a username, password or vhost."
10
+ end
11
+ @opts = opts
12
+ end
13
+
14
+ # Returns the default queue name or returns InvalidConnectionDetails
15
+ # if no default queue is defined
16
+ def queue_name
17
+ raise InvalidConnectionDetails, "Missing a default queue name." unless @opts.has_key?(:default_queue)
18
+ @opts[:default_queue]
19
+ end
20
+
21
+ # Returns a hash of the connection options
22
+ def options
23
+ {
24
+ :user => @opts[:user],
25
+ :pass => @opts[:pass],
26
+ :vhost => @opts[:vhost],
27
+ :host => (@opts[:host] || "localhost"),
28
+ :port => (@opts[:port] || ::AMQP::PORT.to_i),
29
+ :logging => (@opts[:logging] || false)
30
+ }
31
+ end
32
+
33
+ # Raised if connection details are missing or invalid
34
+ # Check the error message for more details
35
+ class InvalidConnectionDetails < Exception
36
+ end
37
+ end
@@ -0,0 +1,70 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/message_filters/yaml")
2
+
3
+ module Warren
4
+ # Handles filtering messages going onto/coming off the queue
5
+ class MessageFilter
6
+ # Array of filters to be run on the message before its
7
+ # pushed to rabbit.
8
+ #
9
+ # NB: These get called in reverse order from the array -
10
+ # the last filter to be added gets called first.
11
+ @@filters = [Warren::MessageFilter::Yaml]
12
+
13
+ class << self
14
+ # Adds a filter to the list
15
+ #
16
+ # A valid filter is just a class that defines
17
+ # <tt>self.pack</tt> and <tt>self.unpack</tt>
18
+ # methods, which both accept a single argument,
19
+ # act upon it, and return the output.
20
+ #
21
+ # Example filter class (See also message_filters/*.rb)
22
+ #
23
+ # class Foo
24
+ # def self.pack msg
25
+ # msg.reverse # Assumes msg responds to reverse
26
+ # end
27
+ #
28
+ # def self.unpack msg
29
+ # msg.reverse # Does the opposite of Foo#pack
30
+ # end
31
+ # end
32
+ #
33
+ def << filter
34
+ @@filters << filter
35
+ end
36
+ alias :add_filter :<<
37
+ end
38
+
39
+ # Returns current array of filters
40
+ def self.filters
41
+ @@filters
42
+ end
43
+
44
+ # Resets the filters to default
45
+ def self.reset_filters
46
+ @@filters = [Warren::MessageFilter::Yaml]
47
+ end
48
+
49
+ # Runs the raw message through all the filters
50
+ # and returns the filtered version
51
+ def self.pack msg
52
+ @@filters.reverse.each do |f|
53
+ # puts "Packing with #{f}"
54
+ msg = f.send(:pack, msg)
55
+ end
56
+ msg
57
+ end
58
+
59
+ # Runs the filtered message through all the
60
+ # filters and returns the raw version
61
+ def self.unpack msg
62
+ @@filters.each do |f|
63
+ # puts "Unpacking with #{f}"
64
+ msg = f.unpack(msg)
65
+ end
66
+ msg
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,70 @@
1
+ begin
2
+ require "hmac-sha2"
3
+ rescue LoadError => e
4
+ puts "Error loading the `ruby-hmac` gem."
5
+ exit!
6
+ end
7
+
8
+ module Warren
9
+ class MessageFilter
10
+ # Hashes the message using a secret salt, stores the hash
11
+ # in the message and then checks its the same when pulled
12
+ # off the other end.
13
+ #
14
+ # Basic trust implementation to make sure the message
15
+ # hasn't been tampered with in transit and came from
16
+ # an "authorised" app.
17
+ #
18
+ # Make sure both the publisher and subscriber use the same
19
+ # key else you'll get KeyValidationError error raised.
20
+ #
21
+ class SharedSecret
22
+ # Raised when no key (salt) is provided
23
+ class NoKeyError < Exception; end
24
+ # Raised when there is a key mismatch error
25
+ class KeyValidationError < Exception; end
26
+
27
+ # Sets the key to use
28
+ def self.key= key
29
+ @@key = key
30
+ end
31
+
32
+ # Returns the current key
33
+ # Raises NoKeyError if no key has been assigned yet
34
+ def self.key
35
+ raise NoKeyError if @@key.nil?
36
+ @@key
37
+ end
38
+
39
+ # Returns the hashed message
40
+ #
41
+ # Expects that msg#to_s returns a string
42
+ # to hash against.
43
+ #
44
+ def self.secret msg
45
+ HMAC::SHA256.hexdigest(self.key, msg.to_s)
46
+ end
47
+
48
+ # Called when the message is being packed for
49
+ # transit. Returns a hash.
50
+ def self.pack msg
51
+ # Make sure its a hash
52
+ msg = {:secret_msg => msg} unless msg.is_a? Hash
53
+ # And add our secret into the hash
54
+ msg[:secret] = self.secret(msg.to_s)
55
+ msg
56
+ end
57
+
58
+ # Called when unpacking the message from transit.
59
+ # Returns the original object.
60
+ def self.unpack msg
61
+ # Check the secret exists in the msg and matches the secret_string
62
+ raise KeyValidationError unless msg.delete(:secret) == self.secret(msg)
63
+ # see if its a hash we created, it'll only contain the key "secret_msg" if it is
64
+ msg = msg[:secret_msg] if msg.keys == [:secret_msg]
65
+ msg
66
+ end
67
+
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,20 @@
1
+ require "yaml"
2
+
3
+ module Warren
4
+ class MessageFilter
5
+ # Packs the message into a YAML string
6
+ # for transferring safely across the wire
7
+ class Yaml
8
+
9
+ # Returns a YAML string
10
+ def self.pack msg
11
+ YAML.dump(msg)
12
+ end
13
+
14
+ # Returns original message
15
+ def self.unpack msg
16
+ YAML.load(msg)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,85 @@
1
+ class Warren::Queue
2
+ @@connection = nil
3
+
4
+ # Raised if no connection has been defined yet.
5
+ class NoConnectionDetails < Exception
6
+ end
7
+
8
+ # Raised if a block is expected by the method but none is given.
9
+ class NoBlockGiven < Exception
10
+ end
11
+
12
+ # Sets the connection details
13
+ def self.connection= params
14
+ @@connection = params.is_a?(Warren::Connection) ? params : Warren::Connection.new(params)
15
+ end
16
+
17
+ # Returns the current connection details
18
+ # Raises NoConnectionDetails if no connection details have been
19
+ # assigned yet.
20
+ def self.connection
21
+ if @@connection.nil?
22
+ raise NoConnectionDetails, "You need to set the connection details."
23
+ end
24
+ @@connection
25
+ end
26
+
27
+ #
28
+ # Sends a message to a queue. If successfully sent it returns
29
+ # true, unless callback block is passed (see below)
30
+ #
31
+ # Warren::Queue.publish(:queue_name, {:foo => "name"})
32
+ #
33
+ # Can also pass a block which is fired after the message
34
+ # is sent. If a block is passed, then the return value of the block
35
+ # is returned from this method.
36
+ #
37
+ # Warren::Queue.publish(:queue_name, {:foo => "name"}) { puts "foo" }
38
+ #
39
+ def self.publish queue_name, payload, &blk
40
+ queue_name = self.connection.queue_name if queue_name == :default
41
+ # Create a message object if it isn't one already
42
+ msg = Warren::MessageFilter.pack(payload)
43
+
44
+ do_connect(true, blk) do
45
+ queue = MQ::Queue.new(MQ.new, queue_name)
46
+ queue.publish msg.to_s
47
+ end
48
+
49
+ end
50
+
51
+ #
52
+ # Subscribes to a queue and runs the block
53
+ # for each message received
54
+ #
55
+ # Warren::Queue.subscribe("example") {|msg| puts msg }
56
+ #
57
+ # Expects a block and raises NoBlockGiven if no block is given.
58
+ #
59
+ def self.subscribe queue_name, &block
60
+ raise NoBlockGiven unless block_given?
61
+ queue_name = self.connection.queue_name if queue_name == :default
62
+ # todo: check if its a valid queue?
63
+ do_connect(false) do
64
+ queue = MQ::Queue.new(MQ.new, queue_name)
65
+ queue.subscribe do |msg|
66
+ msg = Warren::MessageFilter.unpack(msg)
67
+ block.call(msg)
68
+ end
69
+ end
70
+ end
71
+
72
+
73
+ private
74
+
75
+ # Connects and does the stuff its told to!
76
+ def self.do_connect should_stop = true, callback = nil, &block
77
+ AMQP.start(self.connection.options) do
78
+ block.call
79
+ AMQP.stop { EM.stop_event_loop } if should_stop
80
+ end
81
+ # Returns the block return value or true
82
+ callback.nil? ? true : callback.call
83
+ end
84
+
85
+ end
data/lib/warren.rb ADDED
@@ -0,0 +1,24 @@
1
+ require "yaml"
2
+ require "rubygems"
3
+ require "mq"
4
+
5
+ #
6
+ # Library for pushing messages onto RabbitMQ queues,
7
+ # and receiving them at the other end.
8
+ #
9
+ # It handles authentication + filtering messages with custom
10
+ # classes if needed.
11
+ #
12
+ # Start with Warren::Queue for details and see also
13
+ # examples/
14
+ #
15
+ module Warren
16
+ @@foo = ""
17
+ end
18
+
19
+ WARREN_ROOT = File.expand_path(File.join(File.dirname(__FILE__), ".."))
20
+
21
+ # Require everything in the lib folder
22
+ Dir["#{WARREN_ROOT}/lib/warren/**/*.rb"].each do |file|
23
+ require file
24
+ end
data/readme.rdoc ADDED
@@ -0,0 +1,19 @@
1
+ = Warren
2
+
3
+ Library for pushing messages onto RabbitMQ queues, and receiving them at the other end.
4
+
5
+ It handles authentication + filtering messages with custom classes if needed.
6
+
7
+ Start with Warren::Queue for details and see also examples/
8
+
9
+ == Released under the MIT Licence
10
+
11
+ Copyright (c) 2008 Brightbox Systems Ltd
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
14
+
15
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18
+
19
+ See http://www.brightbox.co.uk/ for contact details.
@@ -0,0 +1,9 @@
1
+ class Hash
2
+ def except(*blacklist)
3
+ self.reject {|key, value| blacklist.include?(key) }
4
+ end
5
+
6
+ def only(*whitelist)
7
+ self.reject {|key, value| !whitelist.include?(key) }
8
+ end
9
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
@@ -0,0 +1,4 @@
1
+ require File.join(File.dirname(__FILE__) + "/../lib/warren")
2
+
3
+ # Hash#only and Hash#except
4
+ require File.join(File.dirname(__FILE__) + "/hash_extend")
@@ -0,0 +1,70 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Warren::Connection do
4
+
5
+ before(:each) do
6
+ @c = Warren::Connection.new(details)
7
+ end
8
+
9
+ it "should require a username" do
10
+ lambda {
11
+ Warren::Connection.new(details.except(:user))
12
+ }.should raise_error(Warren::Connection::InvalidConnectionDetails)
13
+ end
14
+
15
+ it "should require a password" do
16
+ lambda {
17
+ Warren::Connection.new(details.except(:pass))
18
+ }.should raise_error(Warren::Connection::InvalidConnectionDetails)
19
+ end
20
+
21
+ it "should require a queue name if none specified" do
22
+ lambda {
23
+ conn = Warren::Connection.new(details)
24
+ conn.queue_name
25
+ }.should raise_error(Warren::Connection::InvalidConnectionDetails)
26
+ end
27
+
28
+ it "should return a default host" do
29
+ @c.options[:host].should == "localhost"
30
+ end
31
+
32
+ it "should return a given host" do
33
+ c = Warren::Connection.new(details.merge({:host => "caius"}))
34
+ c.options[:host].should == "caius"
35
+ end
36
+
37
+ it "should return a default port" do
38
+ @c.options[:port].should == 5672
39
+ end
40
+
41
+ it "should return a given port" do
42
+ c = Warren::Connection.new(details.merge({:port => 1}))
43
+ c.options[:port].should == 1
44
+ end
45
+
46
+ it "should return a default logging param" do
47
+ @c.options[:logging].should == false
48
+ end
49
+
50
+ it "should return a given logging param" do
51
+ c = Warren::Connection.new(details.merge({:logging => true}))
52
+ c.options[:logging].should == true
53
+ end
54
+
55
+ it "should return the given queue name" do
56
+ conn = Warren::Connection.new(details.merge({:default_queue => "queue"}))
57
+ conn.queue_name.should == "queue"
58
+ end
59
+
60
+ private
61
+
62
+ def details
63
+ {
64
+ :user => "user",
65
+ :pass => "pass",
66
+ :vhost => "main",
67
+ }
68
+ end
69
+
70
+ end
@@ -0,0 +1,84 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ # Needed for some tests later on
4
+ class Foo
5
+ def self.pack msg
6
+ msg
7
+ end
8
+
9
+ def self.unpack msg
10
+ msg
11
+ end
12
+ end
13
+
14
+ describe Warren::MessageFilter do
15
+
16
+ before(:each) do
17
+ Warren::MessageFilter.reset_filters
18
+ end
19
+
20
+ describe "Managing Filters" do
21
+ it "should have YAML as a filter by default" do
22
+ fs = Warren::MessageFilter.filters
23
+
24
+ fs.should have(1).element
25
+ fs.first.should == Warren::MessageFilter::Yaml
26
+ end
27
+
28
+ it "should add additional filters to the stack" do
29
+ Warren::MessageFilter.should respond_to(:<<)
30
+ Warren::MessageFilter << Foo
31
+ fs = Warren::MessageFilter.filters
32
+
33
+ fs.should have(2).elements
34
+ fs.first.should == Warren::MessageFilter::Yaml
35
+ fs.last.should == Foo
36
+ end
37
+ end
38
+
39
+ describe "calling filters to send message" do
40
+
41
+ it "should YAML by default" do
42
+ @msg = "message"
43
+ Warren::MessageFilter::Yaml.should_receive(:pack).with(@msg).and_return("yamled")
44
+
45
+ Warren::MessageFilter.pack(@msg)
46
+ end
47
+
48
+ it "should call each filter in turn when packing" do
49
+ @msg = "message"
50
+
51
+ Foo.should_receive(:pack).with(@msg).and_return("fooed")
52
+ Warren::MessageFilter::Yaml.should_receive(:pack).with("fooed").and_return("yamled")
53
+
54
+ Warren::MessageFilter << Foo
55
+
56
+ Warren::MessageFilter.pack(@msg).should == "yamled"
57
+ end
58
+
59
+ end
60
+
61
+ describe "calling filters to unpack message" do
62
+ it "should un-YAML by default" do
63
+ @msg = "yamled"
64
+
65
+ Warren::MessageFilter::Yaml.should_receive(:unpack).with("yamled").and_return("message")
66
+
67
+ Warren::MessageFilter.unpack(@msg).should == "message"
68
+ end
69
+
70
+ it "should run all unpack filters" do
71
+ @msg = "yamled message"
72
+
73
+ Warren::MessageFilter::Yaml.should_receive(:unpack).with("yamled message").and_return("fooed")
74
+ Foo.should_receive(:unpack).with("fooed").and_return("message")
75
+
76
+ Warren::MessageFilter << Foo
77
+ Warren::MessageFilter.filters.should == [Warren::MessageFilter::Yaml, Foo]
78
+
79
+ Warren::MessageFilter.unpack(@msg).should == "message"
80
+ end
81
+ end
82
+
83
+ end
84
+
@@ -0,0 +1,93 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Warren::Queue do
4
+
5
+ it "should require raise exception with no connection details" do
6
+ lambda {
7
+ Warren::Queue.connection
8
+ }.should raise_error(Warren::Queue::NoConnectionDetails)
9
+ end
10
+
11
+ it "should require connection details to publish" do
12
+ lambda {
13
+ Warren::Queue.publish("", "")
14
+ }.should raise_error(Warren::Queue::NoConnectionDetails)
15
+ end
16
+
17
+ it "should require connection details to subscribe" do
18
+ lambda {
19
+ Warren::Queue.subscribe("") { true }
20
+ }.should raise_error(Warren::Queue::NoConnectionDetails)
21
+ end
22
+
23
+ it "should set connection details" do
24
+ conn = new_connection
25
+
26
+ Warren::Queue.connection = conn
27
+ Warren::Queue.connection.should == conn
28
+ end
29
+
30
+ it "should publish to a queue" do
31
+ Warren::Queue.connection = new_connection
32
+
33
+ Warren::Queue.should_receive(:do_connect).with(true, nil).and_return(true)
34
+ Warren::Queue.publish("queue", "payload")
35
+ end
36
+
37
+ it "should publish to a default queue" do
38
+ Warren::Queue.connection = new_connection(:default_queue => "queue")
39
+
40
+ Warren::Queue.should_receive(:do_connect).with(true, nil).and_return(true)
41
+ Warren::Queue.publish(:default, "payload")
42
+ end
43
+
44
+ it "should publish to a queue with a block" do
45
+ Warren::Queue.connection = new_connection
46
+
47
+ blk = Proc.new { true }
48
+
49
+ Warren::Queue.should_receive(:do_connect).with(true, blk).and_return(true)
50
+ Warren::Queue.publish("queue", "payload", &blk)
51
+ end
52
+
53
+ describe "subscribing" do
54
+
55
+ it "should require a block to be passed" do
56
+ Warren::Queue.connection = new_connection
57
+
58
+ lambda {
59
+ Warren::Queue.subscribe("queue")
60
+ }.should raise_error(Warren::Queue::NoBlockGiven)
61
+ end
62
+
63
+ it "should subscribe to a queue" do
64
+ Warren::Queue.connection = new_connection
65
+
66
+ Warren::Queue.should_receive(:do_connect).with(false).and_return(true)
67
+ Warren::Queue.subscribe("queue") { true }
68
+ end
69
+
70
+ it "should subscribe to the default queue" do
71
+ Warren::Queue.connection = new_connection(:default_queue => "queue")
72
+
73
+ Warren::Queue.should_receive(:do_connect).with(false).and_return(true)
74
+ Warren::Queue.subscribe(:default) { true }
75
+ end
76
+
77
+ end
78
+
79
+ private
80
+
81
+ def new_connection opts = {}
82
+ Warren::Connection.new(details.merge(opts))
83
+ end
84
+
85
+ def details
86
+ {
87
+ :user => "user",
88
+ :pass => "pass",
89
+ :vhost => "main",
90
+ }
91
+ end
92
+
93
+ end
data/tasks/rdoc.rake ADDED
@@ -0,0 +1,7 @@
1
+ require "rake/rdoctask"
2
+
3
+ Rake::RDocTask.new do |rd|
4
+ rd.main = "lib/warren.rb"
5
+ rd.rdoc_files.include("lib/**/*.rb")
6
+ rd.rdoc_dir = "doc"
7
+ end
data/tasks/rspec.rake ADDED
@@ -0,0 +1,24 @@
1
+ # Borrowed from http://github.com/rsim/ruby-plsql/tree/master/tasks/rspec.rake
2
+ # Github++
3
+ begin
4
+ require "spec"
5
+ rescue LoadError
6
+ require "rubygems"
7
+ require "spec"
8
+ end
9
+
10
+ begin
11
+ require "spec/rake/spectask"
12
+ rescue LoadError
13
+ puts <<-EOS
14
+ To use rspec for testing you must install rspec gem:
15
+ [sudo] gem install rspec
16
+ EOS
17
+ exit(0)
18
+ end
19
+
20
+ desc "Run the specs under spec/*"
21
+ Spec::Rake::SpecTask.new do |t|
22
+ t.spec_opts = ["--options", "spec/spec.opts"]
23
+ t.spec_files = FileList["spec/**/*_spec.rb"]
24
+ end
data/warren.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{warren}
5
+ s.version = "0.5"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Caius Durling, David Smalley"]
9
+ s.date = %q{2009-03-13}
10
+ s.description = %q{Library for pushing messages onto and off RabbitMQ queues}
11
+ s.email = %q{support@brightbox.co.uk}
12
+ s.extra_rdoc_files = ["CHANGELOG", "lib/warren/connection.rb", "lib/warren/message_filter.rb", "lib/warren/message_filters/shared_secret.rb", "lib/warren/message_filters/yaml.rb", "lib/warren/queue.rb", "lib/warren.rb", "tasks/rdoc.rake", "tasks/rspec.rake"]
13
+ s.files = ["CHANGELOG", "examples/authed/receiver.rb", "examples/authed/secret.rb", "examples/authed/sender.rb", "examples/simple/mass_sender.rb", "examples/simple/receiver.rb", "examples/simple/sender.rb", "lib/warren/connection.rb", "lib/warren/message_filter.rb", "lib/warren/message_filters/shared_secret.rb", "lib/warren/message_filters/yaml.rb", "lib/warren/queue.rb", "lib/warren.rb", "LICENCE", "Manifest", "Rakefile", "readme.rdoc", "spec/hash_extend.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/warren/connection_spec.rb", "spec/warren/message_filter_spec.rb", "spec/warren/queue_spec.rb", "tasks/rdoc.rake", "tasks/rspec.rake", "warren.gemspec"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://github.com/brightbox/warren}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Warren", "--main", "readme.rdoc"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{warren}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{Library for pushing messages onto and off RabbitMQ queues}
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 2
25
+
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
+ s.add_runtime_dependency(%q<amqp>, [">= 0.6.0"])
28
+ else
29
+ s.add_dependency(%q<amqp>, [">= 0.6.0"])
30
+ end
31
+ else
32
+ s.add_dependency(%q<amqp>, [">= 0.6.0"])
33
+ end
34
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: brightbox-warren
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.5"
5
+ platform: ruby
6
+ authors:
7
+ - Caius Durling, David Smalley
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-13 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: amqp
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.6.0
24
+ version:
25
+ description: Library for pushing messages onto and off RabbitMQ queues
26
+ email: support@brightbox.co.uk
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - CHANGELOG
33
+ - lib/warren/connection.rb
34
+ - lib/warren/message_filter.rb
35
+ - lib/warren/message_filters/shared_secret.rb
36
+ - lib/warren/message_filters/yaml.rb
37
+ - lib/warren/queue.rb
38
+ - lib/warren.rb
39
+ - tasks/rdoc.rake
40
+ - tasks/rspec.rake
41
+ files:
42
+ - CHANGELOG
43
+ - examples/authed/receiver.rb
44
+ - examples/authed/secret.rb
45
+ - examples/authed/sender.rb
46
+ - examples/simple/mass_sender.rb
47
+ - examples/simple/receiver.rb
48
+ - examples/simple/sender.rb
49
+ - lib/warren/connection.rb
50
+ - lib/warren/message_filter.rb
51
+ - lib/warren/message_filters/shared_secret.rb
52
+ - lib/warren/message_filters/yaml.rb
53
+ - lib/warren/queue.rb
54
+ - lib/warren.rb
55
+ - LICENCE
56
+ - Manifest
57
+ - Rakefile
58
+ - readme.rdoc
59
+ - spec/hash_extend.rb
60
+ - spec/spec.opts
61
+ - spec/spec_helper.rb
62
+ - spec/warren/connection_spec.rb
63
+ - spec/warren/message_filter_spec.rb
64
+ - spec/warren/queue_spec.rb
65
+ - tasks/rdoc.rake
66
+ - tasks/rspec.rake
67
+ - warren.gemspec
68
+ has_rdoc: true
69
+ homepage: http://github.com/brightbox/warren
70
+ post_install_message:
71
+ rdoc_options:
72
+ - --line-numbers
73
+ - --inline-source
74
+ - --title
75
+ - Warren
76
+ - --main
77
+ - readme.rdoc
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "0"
85
+ version:
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: "1.2"
91
+ version:
92
+ requirements: []
93
+
94
+ rubyforge_project: warren
95
+ rubygems_version: 1.2.0
96
+ signing_key:
97
+ specification_version: 2
98
+ summary: Library for pushing messages onto and off RabbitMQ queues
99
+ test_files: []
100
+