pivotal-moqueue 0.1.0.200907241602

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require File.dirname(__FILE__) + '/example_helper'
3
+
4
+ describe Moqueue, "when testing the ping pong example" do
5
+ include ExampleHelper
6
+
7
+ def ping_pong
8
+ AMQP.start(:host => 'localhost') do
9
+
10
+ # AMQP.logging = true
11
+
12
+ amq = MQ.new
13
+ EM.add_periodic_timer(0.1){
14
+ @counter_val = counter
15
+ capture_output @counter_val, :sending, 'ping'
16
+ amq.queue('one').publish('ping')
17
+ }
18
+
19
+ amq = MQ.new
20
+ amq.queue('one').subscribe{ |msg|
21
+ capture_output @counter_val, 'one', :received, msg, :sending, 'pong'
22
+ amq.queue('two').publish('pong')
23
+ }
24
+
25
+ amq = MQ.new
26
+ amq.queue('two').subscribe{ |msg|
27
+ capture_output @counter_val, 'two', :received, msg
28
+ }
29
+
30
+ end
31
+
32
+ end
33
+
34
+ before(:all) do
35
+ overload_amqp
36
+ end
37
+
38
+ before(:each) do
39
+ reset!
40
+ end
41
+
42
+ it "should get the correct result without error" do
43
+ Timeout::timeout(5) do
44
+ ping_pong
45
+ end
46
+ expected = [[1, :sending, "ping"], [1, "one", :received, "ping", :sending, "pong"], [1, "two", :received, "pong"],
47
+ [2, :sending, "ping"], [2, "one", :received, "ping", :sending, "pong"], [2, "two", :received, "pong"]]
48
+ @captured_output.should == expected
49
+ end
50
+ end
@@ -0,0 +1,64 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require File.dirname(__FILE__) + '/example_helper'
3
+
4
+ describe Moqueue, "when running the stocks example" do
5
+ include ExampleHelper
6
+
7
+ def run_stocks
8
+ AMQP.start(:host => 'localhost') do
9
+
10
+ def log *args
11
+ #p [ Time.now, *args ]
12
+ end
13
+
14
+ def publish_stock_prices
15
+ mq = MQ.new
16
+ counter = 0
17
+ EM.add_periodic_timer(0.1){
18
+ counter += 1
19
+ EM.stop if counter > 5
20
+
21
+ {:appl => 170+rand(1000)/100.0, :msft => 22+rand(500)/100.0}.each do |stock, price|
22
+ stock = "usd.#{stock}"
23
+
24
+ log :publishing, stock, price
25
+ mq.topic('stocks').publish(price, :key => stock)
26
+ end
27
+ }
28
+ end
29
+
30
+ def watch_appl_stock
31
+ mq = MQ.new
32
+ @apple_queue = mq.queue('apple stock')
33
+ @apple_queue.bind(mq.topic('stocks'), :key => 'usd.appl').subscribe{ |price|
34
+ log 'apple stock', price
35
+ }
36
+ end
37
+
38
+ def watch_us_stocks
39
+ mq = MQ.new
40
+ @us_stocks = mq.queue('us stocks')
41
+ @us_stocks.bind(mq.topic('stocks'), :key => 'usd.*').subscribe{ |info, price|
42
+ log 'us stock', info.routing_key, price
43
+ }
44
+ end
45
+
46
+ publish_stock_prices
47
+ watch_appl_stock
48
+ watch_us_stocks
49
+
50
+ end
51
+ end
52
+
53
+ before(:each) do
54
+ overload_amqp
55
+ reset_broker
56
+ end
57
+
58
+ it "should get the correct results" do
59
+ run_stocks
60
+ @us_stocks.should have(12).received_messages
61
+ @apple_queue.should have(6).received_messages
62
+ end
63
+
64
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ -c -f specdoc
@@ -0,0 +1,21 @@
1
+ require "rubygems"
2
+ require "spec"
3
+
4
+ Spec::Runner.configure do |config|
5
+ config.mock_with :mocha
6
+ end
7
+
8
+ require File.dirname(__FILE__) + "/../lib/moqueue"
9
+
10
+ # Make sure tests fail if deferred blocks (for susbscribe and pop) don't get called
11
+ def ensure_deferred_block_called(opts={:times=>1})
12
+ @poke_me = mock("poke_me")
13
+ @poke_me.expects(:deferred_block_called).times(opts[:times])
14
+ end
15
+
16
+ def deferred_block_called
17
+ @poke_me.deferred_block_called
18
+ true
19
+ end
20
+
21
+ include Moqueue
@@ -0,0 +1,92 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Matchers do
4
+ class MatcherHarness
5
+ include Moqueue::Matchers
6
+ end
7
+
8
+ before(:each) do
9
+ @matchable = MatcherHarness.new
10
+ @mock_moqueue = mock("mock Moqueue::MockQueue")
11
+ @failure_exception = Spec::Expectations::ExpectationNotMetError
12
+ end
13
+
14
+ it "should include matchers in describe blocks automatically when using rspec" do
15
+ self.class.include?(Moqueue::Matchers).should be_true
16
+ end
17
+
18
+ it "should implement Object#should have_received_message" do
19
+ @mock_moqueue.expects(:received_message?).with("matchtacular").returns(true)
20
+ @mock_moqueue.should have_received_message("matchtacular")
21
+ end
22
+
23
+ it "should implement Object#should_not have_received_message" do
24
+ @mock_moqueue.expects(:received_message?).with("no match").returns(false)
25
+ @mock_moqueue.should_not have_received_message("no match")
26
+ end
27
+
28
+ it "should have a useful failure message" do
29
+ @mock_moqueue.expects(:received_message?).with("this fails").returns(false)
30
+ failing_example = lambda {@mock_moqueue.should have_received_message("this fails")}
31
+ error_message = "expected #{@mock_moqueue.inspect} to have received message ``this fails''"
32
+ failing_example.should raise_error(@failure_exception, error_message)
33
+ end
34
+
35
+ it "should have a useful negative failure message" do
36
+ @mock_moqueue.expects(:received_message?).with("FAIL").returns(true)
37
+ failing_example = lambda{@mock_moqueue.should_not have_received_message("FAIL")}
38
+ error_message = "expected #{@mock_moqueue.inspect} to not have received message ``FAIL''"
39
+ failing_example.should raise_error(@failure_exception, error_message)
40
+ end
41
+
42
+ it "should fail gracefully if object being tested for #have_received doesn't respond to #received_message?" do
43
+ begin
44
+ Object.new.should have_received_message("foo")
45
+ rescue => e
46
+ end
47
+ e.should be_a NoMethodError
48
+ e.message.should match /you can't use \`\`should have_received_message\'\' on #\<Object/
49
+ end
50
+
51
+ it "should alias #have_received_message as #have_received for less verbosity" do
52
+ @matchable.should respond_to(:have_received)
53
+ end
54
+
55
+ it "should alias #have_received_ack_for as #have_ack_for for less verbosity" do
56
+ @matchable.should respond_to(:have_ack_for)
57
+ end
58
+
59
+ it "should implement Object#should have_received_ack_for(msg_text)" do
60
+ @mock_moqueue.expects(:received_ack_for_message?).with("foo bar").returns(true)
61
+ @mock_moqueue.should have_received_ack_for("foo bar")
62
+ end
63
+
64
+ it "should implement Object#should_not have_received_ack_for(msg_text)" do
65
+ @mock_moqueue.expects(:received_ack_for_message?).with("bar baz").returns(false)
66
+ @mock_moqueue.should_not have_received_ack_for("bar baz")
67
+ end
68
+
69
+ it "should have a helpful failure message" do
70
+ @mock_moqueue.expects(:received_ack_for_message?).with("foo baz").returns(false)
71
+ failure = lambda {@mock_moqueue.should have_received_ack_for("foo baz")}
72
+ fail_msg = "expected #{@mock_moqueue.inspect} to have received an ack for the message ``foo baz''"
73
+ failure.should raise_error(@failure_exception, fail_msg)
74
+ end
75
+
76
+ it "should have a helpful negative failure message" do
77
+ @mock_moqueue.expects(:received_ack_for_message?).with("bar foo").returns(true)
78
+ failure = lambda {@mock_moqueue.should_not have_received_ack_for("bar foo")}
79
+ fail_msg = "expected #{@mock_moqueue.inspect} to not have received an ack for the message ``bar foo''"
80
+ failure.should raise_error(@failure_exception, fail_msg)
81
+ end
82
+
83
+ it "should fail gracefully if object being tested for #have_received_ack_for doesn't respond to #received_ack_for_message?" do
84
+ begin
85
+ Object.new.should have_received_message("foo")
86
+ rescue => e
87
+ end
88
+ e.should be_a NoMethodError
89
+ e.message.should match /you can't use \`\`should have_received_message\'\' on #\<Object/
90
+ end
91
+
92
+ end
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe MockBroker do
4
+
5
+ before(:each) do
6
+ @broker = MockBroker.instance
7
+ @broker.reset!
8
+ end
9
+
10
+ it "should keep a list of named queues" do
11
+ queue = MockQueue.new("one-mocked-queue")
12
+ @broker.register_queue(queue)
13
+ @broker.find_queue("one-mocked-queue").should == queue
14
+ end
15
+
16
+ it "should reset itself" do
17
+ @broker.register_queue(MockQueue.new("throwaway"))
18
+ @broker.reset!
19
+ @broker.registered_queues.count.should == 0
20
+ end
21
+
22
+ it "should keep a list of topic exchanges" do
23
+ exchange = MockExchange.new(:topic => "lolcats")
24
+ @broker.register_topic_exchange(exchange)
25
+ @broker.find_topic_exchange("lolcats").should equal(exchange)
26
+ end
27
+
28
+ it "should keep a list of fanout queues" do
29
+ exchange = MockExchange.new(:fanout => "joinTheNaniteBorg")
30
+ @broker.register_fanout_exchange(exchange)
31
+ @broker.find_fanout_exchange("joinTheNaniteBorg").should equal(exchange)
32
+ end
33
+
34
+ end
@@ -0,0 +1,102 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe MockExchange do
4
+
5
+ before(:each) do
6
+ reset_broker
7
+ @queue, @exchange = mock_queue_and_exchange
8
+ end
9
+
10
+ it "should manually attach queues" do
11
+ ensure_deferred_block_called(:times => 2)
12
+ exchange = mock_exchange
13
+ one_queue, another_queue = mock_queue("one"), mock_queue("two")
14
+ exchange.attach_queue(one_queue)
15
+ exchange.attach_queue(another_queue)
16
+ one_queue.subscribe do |msg|
17
+ deferred_block_called && msg.should == "mmm, smoothies"
18
+ end
19
+ another_queue.subscribe do |msg|
20
+ deferred_block_called && msg.should == "mmm, smoothies"
21
+ end
22
+ exchange.publish("mmm, smoothies")
23
+ end
24
+
25
+ it "should accept options for the publish method" do
26
+ lambda {@exchange.publish("whateva eva", :key=>"foo.bar")}.should_not raise_error(ArgumentError)
27
+ end
28
+
29
+ it "should emulate topic exchanges" do
30
+ #pending "support for storing and retrieving topic exchanges in MockBroker"
31
+ topic_exchange = MockExchange.new(:topic => "lolcats")
32
+ topic_exchange.topic.should == "lolcats"
33
+ end
34
+
35
+ it "should register new topic exchanges with the mock broker" do
36
+ MockBroker.instance.expects(:register_topic_exchange)
37
+ MockExchange.new(:topic => "lolz")
38
+ end
39
+
40
+ it "should return a previously created topic exchange when asked to create a new one with the same topic" do
41
+ exchange = MockExchange.new(:topic => "fails")
42
+ MockExchange.new(:topic => "fails").should equal exchange
43
+ end
44
+
45
+ it "should determine if routing keys match" do
46
+ exchange = MockExchange.new(:topic => "lolz")
47
+ key = MockExchange::BindingKey
48
+ key.new("cats").matches?("cats").should be_true
49
+ key.new("cats").matches?("cats").should be_true
50
+ key.new("cats").matches?("dogs").should be_false
51
+ key.new("cats.*").matches?("cats.fridge").should be_true
52
+ key.new("cats.evil").matches?("cats.fridge").should be_false
53
+ key.new("cats.*").matches?("cats.fridge.in_urs").should be_false
54
+ key.new("cats.#").matches?("cats.fridge.in_urs").should be_true
55
+ end
56
+
57
+ it "should forward messages to a queue only if the keys match when emulating a topic exchange" do
58
+ ensure_deferred_block_called
59
+ exchange = MockExchange.new(:topic => "lolz")
60
+ queue = MockQueue.new("lolz-lover")
61
+ queue.bind(exchange, :key=>"cats.*").subscribe do |msg|
62
+ msg.should == "ohai"
63
+ deferred_block_called
64
+ end
65
+ exchange.publish("ohai", :key => "cats.attack")
66
+ end
67
+
68
+ it "should add the routing key to the headers' properties when publishing as a topic exchange" do
69
+ ensure_deferred_block_called
70
+ exchange = MockExchange.new(:topic => "mehDogs")
71
+ queue = MockQueue.new("dogzLover").bind(exchange, :key=>"boxers.*")
72
+ queue.subscribe do |headers, msg|
73
+ deferred_block_called
74
+ headers.routing_key.should == "boxers.awesome"
75
+ msg.should == "Roxie"
76
+ end
77
+ exchange.publish("Roxie", :key=>"boxers.awesome")
78
+ end
79
+
80
+ it "should raise an error when publishing to a topic exchange without specifying a key" do
81
+ exchange = MockExchange.new(:topic=>"failz")
82
+ fail_msg = "you must provide a key when publishing to a topic exchange"
83
+ lambda {exchange.publish("failtacular")}.should raise_error(ArgumentError, fail_msg)
84
+ end
85
+
86
+ it "should allow the fanout exchange name to be queried" do
87
+ exchange = MockExchange.new(:fanout => "hiMyNameIs")
88
+ exchange.fanout.should == "hiMyNameIs"
89
+ end
90
+
91
+ it "should register new fanout exchanges with the MockBroker" do
92
+ MockBroker.instance.expects(:register_fanout_exchange)
93
+ MockExchange.new(:fanout => "nanite friendly")
94
+ end
95
+
96
+ it "should return the exact same fanout exchange if creating one with an identical name" do
97
+ the_first_fanout = MockExchange.new(:fanout => "pseudo singleton")
98
+ the_second_one = MockExchange.new(:fanout => "pseudo singleton")
99
+ the_first_fanout.should equal the_second_one
100
+ end
101
+
102
+ end
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe MockHeaders do
4
+
5
+ it "should respond to the same methods as real AMQP::Protocol::Header" do
6
+ headers = Moqueue::MockHeaders.new
7
+ headers.should respond_to(:size)
8
+ headers.should respond_to(:weight)
9
+ headers.should respond_to(:properties)
10
+ headers.should respond_to(:to_frame)
11
+ end
12
+
13
+ it "should add properties given to constructor" do
14
+ headers = MockHeaders.new({:routing_key=>"lolz.cats.inKitchen"})
15
+ end
16
+
17
+ it "should lookup unknown methods as keys in the hash" do
18
+ headers = MockHeaders.new(:wtf_ftw_lolz_yo => "did I really write that?")
19
+ headers.wtf_ftw_lolz_yo.should == "did I really write that?"
20
+ end
21
+
22
+ end
@@ -0,0 +1,141 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe MockQueue do
4
+
5
+ before(:each) do
6
+ reset_broker
7
+ @queue, @exchange = mock_queue_and_exchange
8
+ end
9
+
10
+ it "should accept options for :ack=>(true|false) :nowait=>(true|false)" do
11
+ lambda {@queue.subscribe(:ack=>true) { |message| p message}}.should_not raise_error(ArgumentError)
12
+ end
13
+
14
+ it "should pass mock headers to block when subscribe is given a block w/ 2 arity" do
15
+ ensure_deferred_block_called
16
+ @queue.subscribe do |headers, msg|
17
+ headers.should be_kind_of(Moqueue::MockHeaders)
18
+ msg.should == "the message"
19
+ deferred_block_called
20
+ end
21
+ @exchange.publish("the message")
22
+ end
23
+
24
+ it "should create mock headers if pop is given a block w/ 2 arity" do
25
+ pending
26
+ end
27
+
28
+ it "should process pending messages after a handler block is defined" do
29
+ ensure_deferred_block_called
30
+ @exchange.publish("found!")
31
+ @queue.subscribe { |msg| deferred_block_called && msg.should == "found!" }
32
+ end
33
+
34
+ it "should not process pending messages twice" do
35
+ ensure_deferred_block_called(:times=>2)
36
+ @exchange.publish("take out the garbage")
37
+ @queue.subscribe do |msg|
38
+ deferred_block_called
39
+ msg.should match(/take out (.*) garbage/)
40
+ end
41
+ @exchange.publish("take out more garbage")
42
+ end
43
+
44
+ it "should not ack messages when given or defaulting to :ack=>false" do
45
+ ensure_deferred_block_called
46
+ @queue.subscribe { |msg| deferred_block_called && msg.should == "hew-row" }
47
+ @exchange.publish("hew-row")
48
+ @exchange.received_ack_for_message?("hew-row").should_not be_true
49
+ end
50
+
51
+ it "should not ack messages when given :ack => true, but headers don't receive #ack" do
52
+ ensure_deferred_block_called
53
+ @queue.subscribe(:ack=>true) do |headers, msg|
54
+ deferred_block_called
55
+ msg.should == "10-4"
56
+ end
57
+ @exchange.publish("10-4")
58
+ @exchange.received_ack_for_message?("10-4").should be_false
59
+ end
60
+
61
+ it "should ack messages when subscribe is given :ack=>true and headers are acked" do
62
+ @queue.subscribe(:ack=>true) do |headers, msg|
63
+ msg.should == "10-4"
64
+ headers.ack
65
+ end
66
+ @exchange.publish("10-4")
67
+ @exchange.received_ack_for_message?("10-4").should be_true
68
+ end
69
+
70
+ it "should provide ability to check for acks when direct exchange is used" do
71
+ queue = MockQueue.new("direct-ack-check")
72
+ queue.subscribe(:ack => true) do |headers, msg|
73
+ msg.should == "ack me"
74
+ headers.ack
75
+ end
76
+ queue.publish("ack me")
77
+ queue.received_ack_for_message?("ack me").should be_true
78
+ end
79
+
80
+ it "should store received messages in the queues" do
81
+ @queue.subscribe { |msg| msg.should == "save me!" }
82
+ @exchange.publish("save me!")
83
+ @queue.received_message?("save me!").should be_true
84
+ end
85
+
86
+ it "should #unsubscribe" do
87
+ pending ("should really remove the association with exchange")
88
+ @queue.should respond_to(:unsubscribe)
89
+ end
90
+
91
+ it "should raise an error on double subscribe" do
92
+ @queue.subscribe { |msg| "once" }
93
+ second_subscribe = lambda { @queue.subscribe {|msg| "twice"} }
94
+ second_subscribe.should raise_error DoubleSubscribeError
95
+ end
96
+
97
+ it "should emulate direct exchange publishing" do
98
+ ensure_deferred_block_called
99
+ @queue.subscribe { |msg|deferred_block_called && msg.should == "Dyrekt" }
100
+ @queue.publish("Dyrekt")
101
+ end
102
+
103
+ it "should take an optional name argument" do
104
+ lambda { MockQueue.new("say-my-name") }.should_not raise_error
105
+ end
106
+
107
+ it "should register itself with the mock broker if given a name" do
108
+ MockBroker.instance.expects(:register_queue)
109
+ queue = MockQueue.new("with-a-name")
110
+ end
111
+
112
+ it "should return the previously created queue when trying to create a queue with the same name" do
113
+ queue = MockQueue.new("firsties")
114
+ MockQueue.new("firsties").should equal(queue)
115
+ end
116
+
117
+ it "should support binding to a topic exchange" do
118
+ queue = MockQueue.new("lolz lover")
119
+ topic_exchange = MockExchange.new(:topic => "lolcats")
120
+ topic_exchange.expects(:attach_queue).with(queue, :key=>"lolcats.fridges")
121
+ queue.bind(topic_exchange, :key => "lolcats.fridges") #http://lolcatz.net/784/im-in-ur-fridge-eatin-ur-foodz/
122
+ end
123
+
124
+ it "should make the callback (#subscribe block) available for direct use" do
125
+ queue = MockQueue.new("inspect my guts, plz")
126
+ queue.subscribe { |msg| msg + "yo" }
127
+ queue.run_callback("hey-").should == "hey-yo"
128
+ end
129
+
130
+ it "should bind to a fanout exchange" do
131
+ queue = MockQueue.new("fanouts are cool, too")
132
+ lambda {queue.bind(MockExchange.new)}.should_not raise_error
133
+ end
134
+
135
+ it "should provide a null subscribe that does nothing but allows messages to be received" do
136
+ queue = MockQueue.new("nilly").null_subscribe
137
+ queue.publish("I'm feelin this")
138
+ queue.received_message?("I'm feelin this").should be_true
139
+ end
140
+
141
+ end