moqueue 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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