PageRenderTime 60ms CodeModel.GetById 28ms RepoModel.GetById 2ms app.codeStats 0ms

/test/beetle/subscriber_test.rb

https://github.com/cpocommerce/beetle
Ruby | 263 lines | 259 code | 4 blank | 0 comment | 1 complexity | 2ac07cbd319531f40e6347510e585ac1 MD5 | raw file
  1. require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
  2. module Beetle
  3. class SubscriberTest < Test::Unit::TestCase
  4. def setup
  5. client = Client.new
  6. @sub = client.send(:subscriber)
  7. end
  8. test "initially there should be no amqp connections" do
  9. assert_equal({}, @sub.instance_variable_get("@amqp_connections"))
  10. end
  11. test "initially there should be no instances of MQ" do
  12. assert_equal({}, @sub.instance_variable_get("@mqs"))
  13. end
  14. test "acccessing an amq_connection for a server which doesn't have one should create it and associate it with the server" do
  15. @sub.expects(:new_amqp_connection).returns(42)
  16. # TODO: smarter way to test? what triggers the amqp_connection private method call?
  17. assert_equal 42, @sub.send(:amqp_connection)
  18. connections = @sub.instance_variable_get("@amqp_connections")
  19. assert_equal 42, connections[@sub.server]
  20. end
  21. test "new amqp connections should be created using current host and port" do
  22. m = mock("dummy")
  23. expected_amqp_options = {
  24. :host => @sub.send(:current_host), :port => @sub.send(:current_port),
  25. :user => "guest", :pass => "guest", :vhost => "/"
  26. }
  27. AMQP.expects(:connect).with(expected_amqp_options).returns(m)
  28. # TODO: smarter way to test? what triggers the amqp_connection private method call?
  29. assert_equal m, @sub.send(:new_amqp_connection)
  30. end
  31. test "mq instances should be created for the current server if accessed" do
  32. @sub.expects(:amqp_connection).returns(11)
  33. mq_mock = mock('mq')
  34. mq_mock.expects(:prefetch).with(1).returns(42)
  35. MQ.expects(:new).with(11).returns(mq_mock)
  36. assert_equal 42, @sub.send(:mq)
  37. mqs = @sub.instance_variable_get("@mqs")
  38. assert_equal 42, mqs[@sub.server]
  39. end
  40. test "stop! should stop the event loop" do
  41. EM.expects(:stop_event_loop)
  42. @sub.send(:stop!)
  43. end
  44. end
  45. class SubscriberQueueManagementTest < Test::Unit::TestCase
  46. def setup
  47. @client = Client.new
  48. @sub = @client.send(:subscriber)
  49. end
  50. test "initially there should be no queues for the current server" do
  51. assert_equal({}, @sub.send(:queues))
  52. assert !@sub.send(:queues)["some_queue"]
  53. end
  54. test "binding a queue should create it using the config and bind it to the exchange with the name specified" do
  55. @client.register_queue("some_queue", "durable" => true, "exchange" => "some_exchange", "key" => "haha.#")
  56. @sub.expects(:exchange).with("some_exchange").returns(:the_exchange)
  57. q = mock("queue")
  58. q.expects(:bind).with(:the_exchange, {:key => "haha.#"})
  59. m = mock("MQ")
  60. m.expects(:queue).with("some_queue", :durable => true, :passive => false, :auto_delete => false, :exclusive => false).returns(q)
  61. @sub.expects(:mq).returns(m)
  62. @sub.send(:queue, "some_queue")
  63. assert_equal q, @sub.send(:queues)["some_queue"]
  64. end
  65. test "binding queues should iterate over all servers" do
  66. s = sequence("binding")
  67. @client.register_queue(:x)
  68. @client.register_queue(:y)
  69. @client.register_handler(%w(x y)){}
  70. @sub.servers = %w(a b)
  71. @sub.expects(:set_current_server).with("a").in_sequence(s)
  72. @sub.expects(:queue).with("x").in_sequence(s)
  73. @sub.expects(:queue).with("y").in_sequence(s)
  74. @sub.expects(:set_current_server).with("b").in_sequence(s)
  75. @sub.expects(:queue).with("x").in_sequence(s)
  76. @sub.expects(:queue).with("y").in_sequence(s)
  77. @sub.send(:bind_queues, %W(x y))
  78. end
  79. end
  80. class SubscriberExchangeManagementTest < Test::Unit::TestCase
  81. def setup
  82. @client = Client.new
  83. @sub = @client.send(:subscriber)
  84. end
  85. test "initially there should be no exchanges for the current server" do
  86. assert_equal({}, @sub.send(:exchanges))
  87. end
  88. test "accessing a given exchange should create it using the config. further access should return the created exchange" do
  89. @client.register_exchange("some_exchange", "type" => "topic", "durable" => true)
  90. m = mock("AMQP")
  91. m.expects(:topic).with("some_exchange", :durable => true).returns(42)
  92. @sub.expects(:mq).returns(m)
  93. ex = @sub.send(:exchange, "some_exchange")
  94. assert @sub.send(:exchanges).include?("some_exchange")
  95. ex2 = @sub.send(:exchange, "some_exchange")
  96. assert_equal ex2, ex
  97. end
  98. test "should create exchanges for all exchanges passed to create_exchanges, for all servers" do
  99. @sub.servers = %w(x y)
  100. @client.register_queue(:donald, :exchange => 'duck')
  101. @client.register_queue(:mickey)
  102. @client.register_queue(:mouse, :exchange => 'mickey')
  103. exchange_creation = sequence("exchange creation")
  104. @sub.expects(:set_current_server).with('x').in_sequence(exchange_creation)
  105. @sub.expects(:create_exchange!).with("duck", anything).in_sequence(exchange_creation)
  106. @sub.expects(:create_exchange!).with("mickey", anything).in_sequence(exchange_creation)
  107. @sub.expects(:set_current_server).with('y', anything).in_sequence(exchange_creation)
  108. @sub.expects(:create_exchange!).with("duck", anything).in_sequence(exchange_creation)
  109. @sub.expects(:create_exchange!).with("mickey", anything).in_sequence(exchange_creation)
  110. @sub.send(:create_exchanges, %w(duck mickey))
  111. end
  112. end
  113. class CallBackExecutionTest < Test::Unit::TestCase
  114. def setup
  115. client = Client.new
  116. @queue = "somequeue"
  117. client.register_queue(@queue)
  118. @sub = client.send(:subscriber)
  119. @exception = Exception.new "murks"
  120. @handler = Handler.create(lambda{|*args| raise @exception})
  121. @callback = @sub.send(:create_subscription_callback, "my myessage", @queue, @handler, :exceptions => 1)
  122. end
  123. test "exceptions raised from message processing should be ignored" do
  124. header = header_with_params({})
  125. Message.any_instance.expects(:process).raises(Exception.new)
  126. assert_nothing_raised { @callback.call(header, 'foo') }
  127. end
  128. test "should call recover on the server when processing the handler returns true on recover?" do
  129. header = header_with_params({})
  130. result = mock("result")
  131. result.expects(:recover?).returns(true)
  132. Message.any_instance.expects(:process).returns(result)
  133. @sub.expects(:sleep).with(1)
  134. mq = mock("MQ")
  135. mq.expects(:recover)
  136. @sub.expects(:mq).with(@sub.server).returns(mq)
  137. @callback.call(header, 'foo')
  138. end
  139. test "should sent a reply with status OK if the message reply_to header is set and processing the handler succeeds" do
  140. header = header_with_params(:reply_to => "tmp-queue")
  141. result = RC::OK
  142. Message.any_instance.expects(:process).returns(result)
  143. Message.any_instance.expects(:handler_result).returns("response-data")
  144. mq = mock("MQ")
  145. @sub.expects(:mq).with(@sub.server).returns(mq)
  146. exchange = mock("exchange")
  147. exchange.expects(:publish).with("response-data", :headers => {:status => "OK"})
  148. MQ::Exchange.expects(:new).with(mq, :direct, "", :key => "tmp-queue").returns(exchange)
  149. @callback.call(header, 'foo')
  150. end
  151. test "should sent a reply with status FAILED if the message reply_to header is set and processing the handler fails" do
  152. header = header_with_params(:reply_to => "tmp-queue")
  153. result = RC::AttemptsLimitReached
  154. Message.any_instance.expects(:process).returns(result)
  155. Message.any_instance.expects(:handler_result).returns(nil)
  156. mq = mock("MQ")
  157. @sub.expects(:mq).with(@sub.server).returns(mq)
  158. exchange = mock("exchange")
  159. exchange.expects(:publish).with("", :headers => {:status => "FAILED"})
  160. MQ::Exchange.expects(:new).with(mq, :direct, "", :key => "tmp-queue").returns(exchange)
  161. @callback.call(header, 'foo')
  162. end
  163. end
  164. class SubscriptionTest < Test::Unit::TestCase
  165. def setup
  166. @client = Client.new
  167. @sub = @client.send(:subscriber)
  168. end
  169. test "subscribe should create subscriptions on all queues for all servers" do
  170. @sub.servers << "localhost:7777"
  171. @client.register_message(:a)
  172. @client.register_message(:b)
  173. @client.register_queue(:a)
  174. @client.register_queue(:b)
  175. @client.register_handler(%W(a b)){}
  176. @sub.expects(:subscribe).with("a").times(2)
  177. @sub.expects(:subscribe).with("b").times(2)
  178. @sub.send(:subscribe_queues, %W(a b))
  179. end
  180. test "subscribe should subscribe with a subscription callback created from the registered block" do
  181. @client.register_queue(:some_queue, :exchange => "some_exchange", :key => "some_key")
  182. server = @sub.server
  183. header = header_with_params({})
  184. header.expects(:ack)
  185. block_called = false
  186. proc = lambda do |m|
  187. block_called = true
  188. assert_equal header, m.header
  189. assert_equal "data", m.data
  190. assert_equal server, m.server
  191. end
  192. @sub.register_handler("some_queue", &proc)
  193. q = mock("QUEUE")
  194. q.expects(:subscribe).with({:ack => true, :key => "#"}).yields(header, 'foo')
  195. @sub.expects(:queues).returns({"some_queue" => q})
  196. @sub.send(:subscribe, "some_queue")
  197. assert block_called
  198. end
  199. test "subscribe should fail if no handler exists for given message" do
  200. assert_raises(Error){ @sub.send(:subscribe, "some_queue") }
  201. end
  202. test "listening should use eventmachine. create exchanges. bind queues. install subscribers. and yield." do
  203. @client.register_queue(:a)
  204. @client.register_message(:a)
  205. EM.expects(:run).yields
  206. @sub.expects(:create_exchanges).with(["a"])
  207. @sub.expects(:bind_queues).with(["a"])
  208. @sub.expects(:subscribe_queues).with(["a"])
  209. @sub.listen(["a"]) {}
  210. end
  211. end
  212. class HandlersTest < Test::Unit::TestCase
  213. def setup
  214. @client = Client.new
  215. @sub = @client.send(:subscriber)
  216. end
  217. test "initially we should have no handlers" do
  218. assert_equal({}, @sub.instance_variable_get("@handlers"))
  219. end
  220. test "registering a handler for a queue should store it in the configuration with symbolized option keys" do
  221. opts = {"ack" => true}
  222. @sub.register_handler("some_queue", opts){ |*args| 42 }
  223. opts, block = @sub.instance_variable_get("@handlers")["some_queue"]
  224. assert_equal({:ack => true}, opts)
  225. assert_equal 42, block.call(1)
  226. end
  227. end
  228. end