Skip to content

Commit

Permalink
Faqueue, you know it makes sense.
Browse files Browse the repository at this point in the history
  • Loading branch information
Dylan Egan committed Mar 11, 2010
1 parent b9edab8 commit b7a0c31
Show file tree
Hide file tree
Showing 24 changed files with 95 additions and 110 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTORS.rdoc
@@ -1,3 +1,3 @@
= Contributors
* larrytheliquid (Larry Diehl) & Engine Yard http://github.com/larrytheliquid
* mattmatt (Mathias Meyer) & Peritor Consulting http://github.com/mattmatt
* mattmatt (Mathias Meyer) & Peritor Consulting http://github.com/mattmatt
28 changes: 14 additions & 14 deletions README.rdoc
@@ -1,22 +1,22 @@
= Moqueue
Moqueue is a library for mocking the various objects that make up the ruby AMQP[http://github.com/tmm1/amqp] library. It allows you to use the AMQP library naturally and test your code easily without running an AMQP broker. If you want a higher level of control, you can use your favorite mocking and stubbing library to modify individual calls to MQ.queue and the like so that they return Moqueue's mock up versions. If you want to go all-in, you can tell Moqueue to overload the MQ and AMQP. This allows you to use MQ and AMQP as normal, while Moqueue works behind the scenes to wire everything together.
= Faqueue
Faqueue is a library for mocking the various objects that make up the ruby AMQP[http://github.com/tmm1/amqp] library. It allows you to use the AMQP library naturally and test your code easily without running an AMQP broker. If you want a higher level of control, you can use your favorite mocking and stubbing library to modify individual calls to MQ.queue and the like so that they return Faqueue's mock up versions. If you want to go all-in, you can tell Faqueue to overload the MQ and AMQP. This allows you to use MQ and AMQP as normal, while Faqueue works behind the scenes to wire everything together.

= Getting started

require "moqueue"
require "faqueue"
overload_amqp

mq = MQ.new
=> #<MQ:0x1197ae8>

queue = mq.queue("mocktacular")
=> #<Moqueue::MockQueue:0x1194550 @name="mocktacular">
=> #<Faqueue::MockQueue:0x1194550 @name="mocktacular">

topic = mq.topic("lolz")
=> #<Moqueue::MockExchange:0x11913dc @topic="lolz">
=> #<Faqueue::MockExchange:0x11913dc @topic="lolz">

queue.bind(topic, :key=> "cats.*")
=> #<Moqueue::MockQueue:0x1194550 @name="mocktacular">
=> #<Faqueue::MockQueue:0x1194550 @name="mocktacular">

queue.subscribe {|header, msg| puts [header.routing_key, msg]}
=> nil
Expand All @@ -25,10 +25,10 @@ Moqueue is a library for mocking the various objects that make up the ruby AMQP[
# cats.inUrFridge
# eatin ur foodz

Note that in this example, we didn't have to deal with <tt>AMQP.start</tt> or <tt>EM.run</tt>. This should be ample evidence that you should run higher level tests without any mocks or stubs so you can be sure everything works with real MQ objects. With that said, <tt>#overload_amqp</tt> does overload the <tt>AMQP.start</tt> method, so you can use Moqueue for mid-level testing if desired. Have a look at the spec/examples directory to see Moqueue running some of AMQP's examples in overload mode for more demonstration of this.
Note that in this example, we didn't have to deal with <tt>AMQP.start</tt> or <tt>EM.run</tt>. This should be ample evidence that you should run higher level tests without any mocks or stubs so you can be sure everything works with real MQ objects. With that said, <tt>#overload_amqp</tt> does overload the <tt>AMQP.start</tt> method, so you can use Faqueue for mid-level testing if desired. Have a look at the spec/examples directory to see Faqueue running some of AMQP's examples in overload mode for more demonstration of this.

= Custom Rspec Matchers
For Test::Unit users, Moqueue's default syntax should be a good fit with <tt>assert()</tt>:
For Test::Unit users, Faqueue's default syntax should be a good fit with <tt>assert()</tt>:
assert(queue.received_message?("eatin ur foodz"))
Rspec users will probably want something a bit more natural language-y. You got it:
queue.should have_received("a message")
Expand All @@ -39,17 +39,17 @@ As you can tell from the example above, quite a bit is working. This includes di

What's not working:
* RPC exchanges.
* The routing key matching algorithm works for common cases, including "*" and "#" wildcards in the binding key. If you need anything more complicated than that, Moqueue is not guaranteed to do the right thing.
* The routing key matching algorithm works for common cases, including "*" and "#" wildcards in the binding key. If you need anything more complicated than that, Faqueue is not guaranteed to do the right thing.
* Receiving acks when using topic exchanges works only if you subscribe before publishing.

There are some things that Moqueue may never be able to do. As one prominent example, for queues that are configured to expect acknowledgements (the <tt>:ack=>true</tt> option), the behavior on shutdown is not emulated correctly.
There are some things that Faqueue may never be able to do. As one prominent example, for queues that are configured to expect acknowledgements (the <tt>:ack=>true</tt> option), the behavior on shutdown is not emulated correctly.

== Hacking
Moqueue is at a stage where it "works for me." That said, there may be methods or method signatures that aren't correct/ aren't supported. If this happens to you, fork me and send a pull request when you're done. Patches and feedback welcome.
Faqueue is at a stage where it "works for me." That said, there may be methods or method signatures that aren't correct/ aren't supported. If this happens to you, fork me and send a pull request when you're done. Patches and feedback welcome.

== Moar
I wrote an introductory post on my blog, it's probably the best source of high-level discussion right now. Visit: http://kallistec.com/2009/06/21/introducing-moqueue/
I wrote an introductory post on my blog, it's probably the best source of high-level discussion right now. Visit: http://kallistec.com/2009/06/21/introducing-faqueue/

If you prefer code over drivel, look at the specs under spec/examples. There you'll find some of the examples from the amqp library running completely Moqueue-ified; the basic_usage_spec.rb shows some lower-level use.
If you prefer code over drivel, look at the specs under spec/examples. There you'll find some of the examples from the amqp library running completely Faqueue-ified; the basic_usage_spec.rb shows some lower-level use.

As always, you're invited to git yer fork on if you want to work on any of these. If you find a bug that you can't source or want to send love or hate mail, you can contact me directly at dan@kallistec.com
As always, you're invited to git yer fork on if you want to work on any of these. If you find a bug that you can't source or want to send love or hate mail, you can contact me directly at dan@kallistec.com
10 changes: 5 additions & 5 deletions Rakefile
Expand Up @@ -12,14 +12,14 @@ end
begin
require 'jeweler'
Jeweler::Tasks.new do |s|
s.name = "moqueue"
s.name = "faqueue"
s.summary = "Mocktacular Companion to AMQP Library. Happy TATFTing!"
s.email = "dan@kallistec.com"
s.homepage = "http://github.com/danielsdeleo/moqueue"
s.homepage = "http://github.com/danielsdeleo/faqueue"
s.description = "Mocktacular Companion to AMQP Library. Happy TATFTing!"
s.authors = ["Daniel DeLeo"]
s.files = FileList["[A-Za-z]*", "{lib,spec}/**/*"]
s.rubyforge_project = "moqueue"
s.rubyforge_project = "faqueue"
s.add_dependency("amqp")
end
rescue LoadError
Expand All @@ -46,7 +46,7 @@ begin
)

host = "#{config['username']}@rubyforge.org"
remote_dir = "/var/www/gforge-projects/moqueue/"
remote_dir = "/var/www/gforge-projects/faqueue/"
local_dir = 'rdoc'

Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
Expand All @@ -61,4 +61,4 @@ Rake::RDocTask.new do |rd|
rd.main = "README.rdoc"
rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
rd.rdoc_dir = "rdoc"
end
end
File renamed without changes.
6 changes: 3 additions & 3 deletions lib/moqueue/matchers.rb → lib/faqueue/matchers.rb
@@ -1,4 +1,4 @@
module Moqueue
module Faqueue
module Matchers

class HasReceived
Expand Down Expand Up @@ -108,6 +108,6 @@ def have_received_exact_routing_key(expected_key)

if defined?(::Spec::Runner)
Spec::Runner.configure do |config|
config.include(::Moqueue::Matchers)
config.include(::Faqueue::Matchers)
end
end
end
4 changes: 2 additions & 2 deletions lib/moqueue/mock_broker.rb → lib/faqueue/mock_broker.rb
@@ -1,6 +1,6 @@
require "singleton"

module Moqueue
module Faqueue
class MockBroker
include Singleton

Expand Down Expand Up @@ -50,4 +50,4 @@ def find_fanout_exchange(fanout_name)
end

end
end
end
@@ -1,4 +1,4 @@
module Moqueue
module Faqueue

class MockExchange
attr_reader :topic, :fanout, :direct
Expand Down
4 changes: 2 additions & 2 deletions lib/moqueue/mock_headers.rb → lib/faqueue/mock_headers.rb
@@ -1,4 +1,4 @@
module Moqueue
module Faqueue

class MockHeaders
attr_accessor :size, :weight
Expand Down Expand Up @@ -28,4 +28,4 @@ def method_missing method, *args, &blk
end
end

end
end
2 changes: 1 addition & 1 deletion lib/moqueue/mock_queue.rb → lib/faqueue/mock_queue.rb
@@ -1,4 +1,4 @@
module Moqueue
module Faqueue

class DoubleSubscribeError < StandardError
end
Expand Down
@@ -1,4 +1,4 @@
module Moqueue
module Faqueue

module ObjectMethods
def mock_queue_and_exchange(name=nil)
Expand All @@ -25,7 +25,7 @@ def mock_exchange(opts={})
# Overloads the class-level method calls typically used by AMQP code
# such as MQ.direct, MQ.queue, MQ.topic, etc.
def overload_amqp
require MOQUEUE_ROOT + "moqueue/overloads"
require FAQUEUE_ROOT + "faqueue/overloads"
end

# Deletes all exchanges and queues from the mock broker. As a consequence of
Expand All @@ -38,4 +38,4 @@ def reset_broker

end

Object.send(:include, Moqueue::ObjectMethods)
Object.send(:include, Faqueue::ObjectMethods)
14 changes: 7 additions & 7 deletions lib/moqueue/overloads.rb → lib/faqueue/overloads.rb
Expand Up @@ -4,15 +4,15 @@ class MQ

class << self
def queue(name)
Moqueue::MockQueue.new(name)
Faqueue::MockQueue.new(name)
end

def direct(name, opts={})
Moqueue::MockExchange.new(opts.merge(:direct=>name))
Faqueue::MockExchange.new(opts.merge(:direct=>name))
end

def fanout(name, opts={})
Moqueue::MockExchange.new(opts.merge(:fanout=>name))
Faqueue::MockExchange.new(opts.merge(:fanout=>name))
end

end
Expand All @@ -21,19 +21,19 @@ def initialize(*args)
end

def direct(name, opts = {})
Moqueue::MockExchange.new(opts.merge(:direct => name))
Faqueue::MockExchange.new(opts.merge(:direct => name))
end

def fanout(name, opts = {})
Moqueue::MockExchange.new(opts.merge(:fanout => name))
Faqueue::MockExchange.new(opts.merge(:fanout => name))
end

def queue(name, opts = {})
Moqueue::MockQueue.new(name)
Faqueue::MockQueue.new(name)
end

def topic(topic_name)
Moqueue::MockExchange.new(:topic=>topic_name)
Faqueue::MockExchange.new(:topic=>topic_name)
end

end
Expand Down
15 changes: 0 additions & 15 deletions lib/moqueue.rb

This file was deleted.

4 changes: 2 additions & 2 deletions spec/examples/ack_spec.rb
@@ -1,7 +1,7 @@
require File.dirname(__FILE__) + '/../spec_helper'
require File.dirname(__FILE__) + '/example_helper'

# NOTE: moqueue currently does not mimic AMQP's behavior of:
# NOTE: faqueue currently does not mimic AMQP's behavior of:
# 1) requiring graceful shutdown for acks to be delivered
# 2) returning messages to the queue if not acked
# 3) not processing messages when AMQP isn't "running"
Expand All @@ -10,7 +10,7 @@
# with a real broker. The true behavior should be that the 3rd message
# published should be unacknowledged and returned to the queue. In this test,
# all messages get acknowleged
describe Moqueue, "when running the ack example" do
describe Faqueue, "when running the ack example" do
include ExampleHelper

def run_ack_example(&perform_ack)
Expand Down
8 changes: 4 additions & 4 deletions spec/examples/basic_usage_spec.rb
@@ -1,6 +1,6 @@
require File.dirname(__FILE__) + '/../spec_helper'

describe "AMQP", "when mocked out by Moqueue" do
describe "AMQP", "when mocked out by Faqueue" do

before(:each) do
reset_broker
Expand Down Expand Up @@ -54,7 +54,7 @@

end

describe Moqueue, "with syntax sugar" do
describe Faqueue, "with syntax sugar" do

before(:each) do
reset_broker
Expand Down Expand Up @@ -82,7 +82,7 @@

end

describe Moqueue, "when using custom rspec matchers" do
describe Faqueue, "when using custom rspec matchers" do

it "should accept syntax like queue.should have_received('a message')" do
queue = mock_queue("sugary")
Expand All @@ -98,4 +98,4 @@
queue.should have_ack_for("another message")
end

end
end
2 changes: 1 addition & 1 deletion spec/examples/logger_spec.rb
@@ -1,6 +1,6 @@
require File.dirname(__FILE__) + '/../spec_helper'

describe Moqueue, "when running the logger example" do
describe Faqueue, "when running the logger example" do

class MyLoggerRulez
def initialize *args, &block
Expand Down
4 changes: 2 additions & 2 deletions spec/examples/ping_pong_spec.rb
@@ -1,7 +1,7 @@
require File.dirname(__FILE__) + '/../spec_helper'
require File.dirname(__FILE__) + '/example_helper'

describe Moqueue, "when testing the ping pong example" do
describe Faqueue, "when testing the ping pong example" do
include ExampleHelper

def ping_pong
Expand Down Expand Up @@ -47,4 +47,4 @@ def ping_pong
[2, :sending, "ping"], [2, "one", :received, "ping", :sending, "pong"], [2, "two", :received, "pong"]]
@captured_output.should == expected
end
end
end
4 changes: 2 additions & 2 deletions spec/examples/stocks_spec.rb
@@ -1,7 +1,7 @@
require File.dirname(__FILE__) + '/../spec_helper'
require File.dirname(__FILE__) + '/example_helper'

describe Moqueue, "when running the stocks example" do
describe Faqueue, "when running the stocks example" do
include ExampleHelper

def run_stocks
Expand Down Expand Up @@ -61,4 +61,4 @@ def watch_us_stocks
@apple_queue.should have(6).received_messages
end

end
end
4 changes: 2 additions & 2 deletions spec/spec_helper.rb
Expand Up @@ -5,7 +5,7 @@
config.mock_with :mocha
end

require File.dirname(__FILE__) + "/../lib/moqueue"
require File.dirname(__FILE__) + "/../lib/faqueue"

# Make sure tests fail if deferred blocks (for susbscribe and pop) don't get called
def ensure_deferred_block_called(opts={:times=>1})
Expand All @@ -23,4 +23,4 @@ def ensure_deferred_block_skipped
@skip_me.expects(:deferred_block_called).times(0)
end

include Moqueue
include Faqueue

0 comments on commit b7a0c31

Please sign in to comment.