moqueue 0.1.4

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.
@@ -0,0 +1,101 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "AMQP", "when mocked out by Moqueue" do
4
+
5
+ before(:each) do
6
+ reset_broker
7
+ end
8
+
9
+ it "should have direct exchanges" do
10
+ queue = mock_queue("direct-exchanges")
11
+ queue.publish("you are correct, sir!")
12
+ queue.subscribe { |message| "do something with message" }
13
+ queue.received_message?("you are correct, sir!").should be_true
14
+ end
15
+
16
+ it "should have direct exchanges with acks" do
17
+ queue = mock_queue("direct-with-acks")
18
+ queue.publish("yessir!")
19
+ queue.subscribe(:ack => true) { |headers, message| headers.ack }
20
+ queue.received_ack_for_message?("yessir!").should be_true
21
+ end
22
+
23
+ it "should have topic exchanges" do
24
+ topic = mock_exchange(:topic => "TATFT")
25
+ queue = mock_queue("rspec-fiend")
26
+ queue.bind(topic, :key => "bdd.*").subscribe { |msg| "do something" }
27
+ topic.publish("TATFT FTW", :key=> "bdd.4life")
28
+ queue.received_message?("TATFT FTW").should be_true
29
+ end
30
+
31
+ it "should have topic exchanges with acks" do
32
+ topic = mock_exchange(:topic => "animals")
33
+ queue = mock_queue("cat-lover")
34
+ queue.bind(topic, :key => "cats.#").subscribe(:ack => true) do |header, msg|
35
+ header.ack
36
+ "do something with message"
37
+ end
38
+ topic.publish("OMG kittehs!", :key => "cats.lolz.kittehs")
39
+ topic.received_ack_for_message?("OMG kittehs!").should be_true
40
+ end
41
+
42
+ it "should have fanout exchanges with acks" do
43
+ film = mock_exchange(:fanout => "Godfather")
44
+ one_actor = mock_queue("Jack Woltz")
45
+ other_actor = mock_queue("Captain McCluskey")
46
+ one_actor.bind(film).subscribe(:ack =>true) { |h,msg| h.ack && "horse head" }
47
+ other_actor.bind(film).subscribe(:ack => true) { |h,msg| h.ack && "dirty cops" }
48
+ offer = "you can't refuse"
49
+ film.publish(offer)
50
+ one_actor.received_message?(offer).should be_true
51
+ other_actor.received_message?(offer).should be_true
52
+ film.should have(2).acked_messages
53
+ end
54
+
55
+ end
56
+
57
+ describe Moqueue, "with syntax sugar" do
58
+
59
+ before(:each) do
60
+ reset_broker
61
+ end
62
+
63
+ it "counts received messages" do
64
+ queue = mock_queue
65
+ queue.subscribe { |msg| msg.should_not be_nil }
66
+ 5.times {queue.publish("no moar beers kthxbye")}
67
+ queue.should have(5).received_messages
68
+ end
69
+
70
+ it "counts acked messages" do
71
+ queue = mock_queue
72
+ queue.subscribe(:ack=>true) { |headers,msg| headers.ack }
73
+ 5.times { queue.publish("time becomes a loop") }
74
+ queue.should have(5).acked_messages
75
+ end
76
+
77
+ it "makes the callback (#subscribe) block testable" do
78
+ emphasis = mock_queue
79
+ emphasis.subscribe { |msg| @emphasized = "**" + msg + "**" }
80
+ emphasis.run_callback("show emphasis").should == "**show emphasis**"
81
+ end
82
+
83
+ end
84
+
85
+ describe Moqueue, "when using custom rspec matchers" do
86
+
87
+ it "should accept syntax like queue.should have_received('a message')" do
88
+ queue = mock_queue("sugary")
89
+ queue.subscribe { |msg| "eat the message" }
90
+ queue.publish("a message")
91
+ queue.should have_received("a message")
92
+ end
93
+
94
+ it "should accept syntax like queue_or_exchange.should have_ack_for('a message')" do
95
+ queue = mock_queue("more sugar")
96
+ queue.subscribe(:ack => true) { |headers, msg| headers.ack }
97
+ queue.publish("another message")
98
+ queue.should have_ack_for("another message")
99
+ end
100
+
101
+ end
@@ -0,0 +1,16 @@
1
+ module ExampleHelper
2
+ def capture_output(*args)
3
+ @captured_output << args
4
+ end
5
+
6
+ def counter
7
+ @counter += 1
8
+ EM.stop {AMQP.stop} if @counter >= 2
9
+ @counter
10
+ end
11
+
12
+ def reset!
13
+ @counter, @captured_output = 0, []
14
+ end
15
+
16
+ end
@@ -0,0 +1,159 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Moqueue, "when running the logger example" do
4
+
5
+ class MyLoggerRulez
6
+ def initialize *args, &block
7
+ opts = args.pop if args.last.is_a? Hash
8
+ opts ||= {}
9
+
10
+ printer(block) if block
11
+
12
+ @prop = opts
13
+ @tags = ([:timestamp] + args).uniq
14
+ end
15
+
16
+ attr_reader :prop
17
+ alias :base :prop
18
+
19
+ def log severity, *args
20
+ opts = args.pop if args.last.is_a? Hash and args.size != 1
21
+ opts ||= {}
22
+ opts = @prop.clone.update(opts)
23
+
24
+ data = args.shift
25
+
26
+ data = {:type => :exception,
27
+ :name => data.class.to_s.intern,
28
+ :backtrace => data.backtrace,
29
+ :message => data.message} if data.is_a? Exception
30
+
31
+ (@tags + args).each do |tag|
32
+ tag = tag.to_sym
33
+ case tag
34
+ when :timestamp
35
+ opts.update :timestamp => Time.now
36
+ when :hostname
37
+ @hostname ||= { :hostname => `hostname`.strip }
38
+ opts.update @hostname
39
+ when :process
40
+ @process_id ||= { :process_id => Process.pid,
41
+ :process_name => $0,
42
+ :process_parent_id => Process.ppid,
43
+ :thread_id => Thread.current.object_id }
44
+ opts.update :process => @process_id
45
+ else
46
+ (opts[:tags] ||= []) << tag
47
+ end
48
+ end
49
+
50
+ opts.update(:severity => severity,
51
+ :msg => data)
52
+
53
+ print(opts)
54
+ unless MyLoggerRulez.disabled?
55
+ MQ.fanout('logging', :durable => true).publish Marshal.dump(opts)
56
+ end
57
+
58
+ opts
59
+ end
60
+ alias :method_missing :log
61
+
62
+ def print data = nil, &block
63
+ if block
64
+ @printer = block
65
+ elsif data.is_a? Proc
66
+ @printer = data
67
+ elsif data
68
+ (pr = @printer || self.class.printer) and pr.call(data)
69
+ else
70
+ @printer
71
+ end
72
+ end
73
+ alias :printer :print
74
+
75
+ def self.printer &block
76
+ @printer = block if block
77
+ @printer
78
+ end
79
+
80
+ def self.disabled?
81
+ !!@disabled
82
+ end
83
+
84
+ def self.enable
85
+ @disabled = false
86
+ end
87
+
88
+ def self.disable
89
+ @disabled = true
90
+ end
91
+ end
92
+
93
+
94
+ before(:all) do
95
+ overload_amqp
96
+ end
97
+
98
+
99
+ def run_client
100
+ AMQP.start do
101
+ log = MyLoggerRulez.new
102
+ log.debug 'its working!'
103
+
104
+ log = MyLoggerRulez.new do |msg|
105
+ #require 'pp'
106
+ #pp msg
107
+ #puts
108
+ end
109
+
110
+ log.info '123'
111
+ log.debug [1,2,3]
112
+ log.debug :one => 1, :two => 2
113
+ log.error Exception.new('123')
114
+
115
+ log.info '123', :process_id => Process.pid
116
+ log.info '123', :process
117
+ log.debug 'login', :session => 'abc', :user => 123
118
+
119
+ log = MyLoggerRulez.new(:webserver, :timestamp, :hostname, &log.printer)
120
+ log.info 'Request for /', :GET, :session => 'abc'
121
+
122
+ #AMQP.stop{ EM.stop }
123
+ end
124
+ end
125
+
126
+ def run_server
127
+ AMQP.start(:host => 'localhost') do
128
+
129
+ @server_queue = MQ.queue('logger')
130
+ @server_queue.bind(MQ.fanout('logging', :durable => true)).subscribe do |msg|
131
+ msg = Marshal.load(msg)
132
+ end
133
+ end
134
+ end
135
+
136
+ it "should get the expected results" do
137
+ EM.run do
138
+ threads = []
139
+ threads << Thread.new do
140
+ run_server
141
+ end
142
+ threads << Thread.new do
143
+ run_client
144
+ end
145
+
146
+ EM.add_timer(0.1) do
147
+ @server_queue.should have(9).received_messages
148
+ webserver_log = Marshal.load(@server_queue.received_messages.last)
149
+ webserver_log[:tags].should == [:webserver, :GET]
150
+ webserver_log[:msg].should == "Request for /"
151
+
152
+ EM.stop
153
+ threads.each { |t| t.join }
154
+ end
155
+
156
+ end
157
+ end
158
+
159
+ end
@@ -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
@@ -0,0 +1 @@
1
+ -c -f specdoc
@@ -0,0 +1,26 @@
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
+ def ensure_deferred_block_skipped
22
+ @skip_me = mock("poke_me")
23
+ @skip_me.expects(:deferred_block_called).times(0)
24
+ end
25
+
26
+ include Moqueue
@@ -0,0 +1,102 @@
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 implement Object#should have_exact_routing_key(key)" do
29
+ @mock_moqueue.expects(:received_routing_key?).with("routing.key").returns(true)
30
+ @mock_moqueue.should have_received_exact_routing_key("routing.key")
31
+ end
32
+
33
+ it "should implement Object#should_not have_exact_routing_key(key)" do
34
+ @mock_moqueue.expects(:received_routing_key?).with("routing.key").returns(false)
35
+ @mock_moqueue.should_not have_received_exact_routing_key("routing.key")
36
+ end
37
+
38
+ it "should have a useful failure message" do
39
+ @mock_moqueue.expects(:received_message?).with("this fails").returns(false)
40
+ failing_example = lambda {@mock_moqueue.should have_received_message("this fails")}
41
+ error_message = "expected #{@mock_moqueue.inspect} to have received message ``this fails''"
42
+ failing_example.should raise_error(@failure_exception, error_message)
43
+ end
44
+
45
+ it "should have a useful negative failure message" do
46
+ @mock_moqueue.expects(:received_message?).with("FAIL").returns(true)
47
+ failing_example = lambda{@mock_moqueue.should_not have_received_message("FAIL")}
48
+ error_message = "expected #{@mock_moqueue.inspect} to not have received message ``FAIL''"
49
+ failing_example.should raise_error(@failure_exception, error_message)
50
+ end
51
+
52
+ it "should fail gracefully if object being tested for #have_received doesn't respond to #received_message?" do
53
+ begin
54
+ Object.new.should have_received_message("foo")
55
+ rescue => e
56
+ end
57
+ e.should be_a(NoMethodError)
58
+ e.message.should match(/you can't use \`\`should have_received_message\'\' on #\<Object/)
59
+ end
60
+
61
+ it "should alias #have_received_message as #have_received for less verbosity" do
62
+ @matchable.should respond_to(:have_received)
63
+ end
64
+
65
+ it "should alias #have_received_ack_for as #have_ack_for for less verbosity" do
66
+ @matchable.should respond_to(:have_ack_for)
67
+ end
68
+
69
+ it "should implement Object#should have_received_ack_for(msg_text)" do
70
+ @mock_moqueue.expects(:received_ack_for_message?).with("foo bar").returns(true)
71
+ @mock_moqueue.should have_received_ack_for("foo bar")
72
+ end
73
+
74
+ it "should implement Object#should_not have_received_ack_for(msg_text)" do
75
+ @mock_moqueue.expects(:received_ack_for_message?).with("bar baz").returns(false)
76
+ @mock_moqueue.should_not have_received_ack_for("bar baz")
77
+ end
78
+
79
+ it "should have a helpful failure message" do
80
+ @mock_moqueue.expects(:received_ack_for_message?).with("foo baz").returns(false)
81
+ failure = lambda {@mock_moqueue.should have_received_ack_for("foo baz")}
82
+ fail_msg = "expected #{@mock_moqueue.inspect} to have received an ack for the message ``foo baz''"
83
+ failure.should raise_error(@failure_exception, fail_msg)
84
+ end
85
+
86
+ it "should have a helpful negative failure message" do
87
+ @mock_moqueue.expects(:received_ack_for_message?).with("bar foo").returns(true)
88
+ failure = lambda {@mock_moqueue.should_not have_received_ack_for("bar foo")}
89
+ fail_msg = "expected #{@mock_moqueue.inspect} to not have received an ack for the message ``bar foo''"
90
+ failure.should raise_error(@failure_exception, fail_msg)
91
+ end
92
+
93
+ it "should fail gracefully if object being tested for #have_received_ack_for doesn't respond to #received_ack_for_message?" do
94
+ begin
95
+ Object.new.should have_received_message("foo")
96
+ rescue => e
97
+ end
98
+ e.should be_a(NoMethodError)
99
+ e.message.should match(/you can't use \`\`should have_received_message\'\' on #\<Object/)
100
+ end
101
+
102
+ end