freddy-jruby 0.5.1 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 304a469e602a811401b7e58433f7adc482b35798
4
- data.tar.gz: 959e5d55ea51de9e6f42bc4a85abe767125ee5eb
3
+ metadata.gz: 0b6494076ba5683b88c6381cd4fe89140d4cb877
4
+ data.tar.gz: 8dcea8a4f75bba5192ec372998a822f9fbc4ab70
5
5
  SHA512:
6
- metadata.gz: 49d8f58e7ecb635cd784486ecdf78a1316745b3de5d17aa5f60f9f6fb478aacf0be5191511f40429438de0d5a53ea188c617e26f5be0345834d87c43b63a3c82
7
- data.tar.gz: 1f61a010e7a14caf92e7ce3990f888e7d0383786a8bc30a1e4a697c411b1a43b0f53743dec3564ab028a0ff13b5c13f5b7639f5da4c8fc50eb7f6c046a60e1c1
6
+ metadata.gz: 4d05477dbd8e2aec9e0e4044edef0720dfaad0c96f9c2ece269c32388fb412332c0573ff44fc7926885bcafa4fa0e4c9895f7f17abadc9768b81cda3579de4fd
7
+ data.tar.gz: e49f5287155ad988a10474366f13e9b371712abedd9f6c3f46082d5ae57a73f2f1b78cfe04b42131e96e2a30b2a67af933be83322642d7325ebde0ffcf40e4a1
data/.gitignore CHANGED
@@ -3,3 +3,4 @@ Gemfile.lock
3
3
  pkg
4
4
  .tags
5
5
  .tags1
6
+ coverage
data/.travis.yml CHANGED
@@ -1,7 +1,10 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 2.1.0
4
- - jruby-9.0.0.0
4
+ - jruby-9.0.4.0
5
+ addons:
6
+ code_climate:
7
+ repo_token: 1f3842b985fdeff6a36168165d491ca5f444667e9381a85c899a61706a9dd285
5
8
  services:
6
9
  - rabbitmq
7
10
  before_script:
data/Gemfile CHANGED
@@ -1,8 +1,7 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
- group :test, :development do
4
- gem 'rspec'
5
- gem 'pry'
6
- end
3
+ gem 'rspec'
4
+ gem 'pry'
5
+ gem 'codeclimate-test-reporter'
7
6
 
8
7
  gemspec
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.org/salemove/freddy.svg?branch=master)](https://travis-ci.org/salemove/freddy)
4
4
  [![Code Climate](https://codeclimate.com/github/salemove/freddy/badges/gpa.svg)](https://codeclimate.com/github/salemove/freddy)
5
+ [![Test Coverage](https://codeclimate.com/github/salemove/freddy/badges/coverage.svg)](https://codeclimate.com/github/salemove/freddy/coverage)
5
6
 
6
7
  ## Setup
7
8
 
data/freddy.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  else
9
9
  spec.name = "freddy"
10
10
  end
11
- spec.version = '0.5.1'
11
+ spec.version = '0.5.6'
12
12
  spec.authors = ["Urmas Talimaa"]
13
13
  spec.email = ["urmas.talimaa@gmail.com"]
14
14
  spec.description = %q{Messaging API}
data/lib/freddy.rb CHANGED
@@ -34,7 +34,7 @@ class Freddy
34
34
  @connection = connection
35
35
  @logger = logger
36
36
 
37
- @tap_into_consumer = Consumers::TapIntoConsumer.new(consume_thread_pool)
37
+ @tap_into_consumer = Consumers::TapIntoConsumer.new(consume_thread_pool, @logger)
38
38
  @respond_to_consumer = Consumers::RespondToConsumer.new(consume_thread_pool, @logger)
39
39
 
40
40
  @send_and_forget_producer = Producers::SendAndForgetProducer.new(
@@ -75,9 +75,11 @@ class Freddy
75
75
 
76
76
  channel = @connection.create_channel
77
77
  producer = Producers::ReplyProducer.new(channel, @logger)
78
- handler_factory = MessageHandlers::Factory.new(producer, @logger)
78
+ handler_adapter_factory = MessageHandlerAdapters::Factory.new(producer)
79
79
 
80
- @respond_to_consumer.consume(destination, channel, handler_factory, &callback)
80
+ @respond_to_consumer.consume(
81
+ destination, channel, handler_adapter_factory, &callback
82
+ )
81
83
  end
82
84
 
83
85
  # Listens for messages without consuming them
@@ -9,5 +9,22 @@ class Freddy
9
9
  BunnyAdapter
10
10
  end
11
11
  end
12
+
13
+ module Shared
14
+ class Queue
15
+ def initialize(queue)
16
+ @queue = queue
17
+ end
18
+
19
+ def bind(*args)
20
+ @queue.bind(*args)
21
+ self
22
+ end
23
+
24
+ def name
25
+ @queue.name
26
+ end
27
+ end
28
+ end
12
29
  end
13
30
  end
@@ -45,26 +45,13 @@ class Freddy
45
45
  end
46
46
  end
47
47
 
48
- class Queue
49
- def initialize(queue)
50
- @queue = queue
51
- end
52
-
48
+ class Queue < Shared::Queue
53
49
  def subscribe(&block)
54
50
  @queue.subscribe do |info, properties, payload|
55
51
  parsed_payload = Payload.parse(payload)
56
52
  block.call(Delivery.new(parsed_payload, properties, info.routing_key))
57
53
  end
58
54
  end
59
-
60
- def bind(*args)
61
- @queue.bind(*args)
62
- self
63
- end
64
-
65
- def name
66
- @queue.name
67
- end
68
55
  end
69
56
  end
70
57
  end
@@ -44,26 +44,13 @@ class Freddy
44
44
  end
45
45
  end
46
46
 
47
- class Queue
48
- def initialize(queue)
49
- @queue = queue
50
- end
51
-
47
+ class Queue < Shared::Queue
52
48
  def subscribe(&block)
53
49
  @queue.subscribe do |meta, payload|
54
50
  parsed_payload = Payload.parse(payload)
55
51
  block.call(Delivery.new(parsed_payload, meta, meta.routing_key))
56
52
  end
57
53
  end
58
-
59
- def bind(*args)
60
- @queue.bind(*args)
61
- self
62
- end
63
-
64
- def name
65
- @queue.name
66
- end
67
54
  end
68
55
  end
69
56
  end
@@ -1 +1,13 @@
1
+ class Freddy
2
+ module Consumers
3
+ def self.log_receive_event(logger, queue_name, delivery)
4
+ if defined?(Logasm) && logger.is_a?(Logasm)
5
+ logger.debug "Received message", queue: queue_name, payload: delivery.payload, correlation_id: delivery.correlation_id
6
+ else
7
+ logger.debug "Received message on #{queue_name} with payload #{delivery.payload} with correlation_id #{delivery.correlation_id}"
8
+ end
9
+ end
10
+ end
11
+ end
12
+
1
13
  Dir[File.dirname(__FILE__) + '/consumers/*.rb'].each(&method(:require))
@@ -6,14 +6,14 @@ class Freddy
6
6
  @logger = logger
7
7
  end
8
8
 
9
- def consume(destination, channel, handler_factory, &block)
9
+ def consume(destination, channel, handler_adapter_factory, &block)
10
10
  consumer = consume_from_destination(destination, channel) do |delivery|
11
- log_receive_event(destination, delivery)
11
+ Consumers.log_receive_event(@logger, destination, delivery)
12
12
 
13
- handler = handler_factory.build(delivery.type, destination)
13
+ adapter = handler_adapter_factory.for(delivery)
14
14
 
15
- msg_handler = MessageHandler.new(handler, delivery)
16
- handler.handle_message delivery.payload, msg_handler, &block
15
+ msg_handler = MessageHandler.new(adapter, delivery)
16
+ block.call(delivery.payload, msg_handler)
17
17
  end
18
18
 
19
19
  ResponderHandler.new(consumer, @consume_thread_pool)
@@ -32,14 +32,6 @@ class Freddy
32
32
  block.call(delivery)
33
33
  end
34
34
  end
35
-
36
- def log_receive_event(destination, delivery)
37
- if defined?(Logasm) && @logger.is_a?(Logasm)
38
- @logger.debug "Received message", queue: destination, payload: delivery.payload, correlation_id: delivery.correlation_id
39
- else
40
- @logger.debug "Received message on #{destination} with payload #{delivery.payload} with correlation_id #{delivery.correlation_id}"
41
- end
42
- end
43
35
  end
44
36
  end
45
37
  end
@@ -18,18 +18,10 @@ class Freddy
18
18
 
19
19
  def process_message(queue, delivery, &block)
20
20
  @dedicated_thread_pool.process do
21
- log_receive_event(queue.name, delivery)
21
+ Consumers.log_receive_event(@logger, queue.name, delivery)
22
22
  block.call(delivery)
23
23
  end
24
24
  end
25
-
26
- def log_receive_event(queue_name, delivery)
27
- if defined?(Logasm) && @logger.is_a?(Logasm)
28
- @logger.debug "Received message", queue: queue_name, payload: delivery.payload, correlation_id: delivery.correlation_id
29
- else
30
- @logger.debug "Received message on #{queue_name} with payload #{delivery.payload} with correlation_id #{delivery.correlation_id}"
31
- end
32
- end
33
25
  end
34
26
  end
35
27
  end
@@ -1,7 +1,8 @@
1
1
  class Freddy
2
2
  module Consumers
3
3
  class TapIntoConsumer
4
- def initialize(consume_thread_pool)
4
+ def initialize(consume_thread_pool, logger)
5
+ @logger = logger
5
6
  @consume_thread_pool = consume_thread_pool
6
7
  end
7
8
 
@@ -9,7 +10,7 @@ class Freddy
9
10
  queue = create_queue(pattern, channel)
10
11
 
11
12
  consumer = queue.subscribe do |delivery|
12
- process_message(delivery, &block)
13
+ process_message(queue, delivery, &block)
13
14
  end
14
15
 
15
16
  ResponderHandler.new(consumer, @consume_thread_pool)
@@ -25,8 +26,9 @@ class Freddy
25
26
  .bind(topic_exchange, routing_key: pattern)
26
27
  end
27
28
 
28
- def process_message(delivery, &block)
29
+ def process_message(queue, delivery, &block)
29
30
  @consume_thread_pool.process do
31
+ Consumers.log_receive_event(@logger, queue.name, delivery)
30
32
  block.call delivery.payload, delivery.routing_key
31
33
  end
32
34
  end
@@ -1,19 +1,16 @@
1
1
  class Freddy
2
2
  class MessageHandler
3
- attr_reader :correlation_id
4
-
5
3
  def initialize(adapter, delivery)
6
4
  @adapter = adapter
7
5
  @delivery = delivery
8
- @correlation_id = @delivery.correlation_id
9
6
  end
10
7
 
11
8
  def success(response = nil)
12
- @adapter.success(@delivery.reply_to, response)
9
+ @adapter.success(@delivery, response)
13
10
  end
14
11
 
15
- def error(error = {error: "Couldn't process message"})
16
- @adapter.error(@delivery.reply_to, error)
12
+ def error(response = {error: "Couldn't process message"})
13
+ @adapter.error(@delivery, response)
17
14
  end
18
15
  end
19
16
  end
@@ -0,0 +1,50 @@
1
+ class Freddy
2
+ module MessageHandlerAdapters
3
+ class Factory
4
+ def initialize(producer)
5
+ @no_op_handler = NoOpHandler.new
6
+ @request_handler = RequestHandler.new(producer)
7
+ end
8
+
9
+ def for(delivery)
10
+ if delivery.type == 'request'
11
+ @request_handler
12
+ else
13
+ @no_op_handler
14
+ end
15
+ end
16
+ end
17
+
18
+ class NoOpHandler
19
+ def success(*)
20
+ # NOP
21
+ end
22
+
23
+ def error(*)
24
+ # NOP
25
+ end
26
+ end
27
+
28
+ class RequestHandler
29
+ def initialize(producer)
30
+ @producer = producer
31
+ end
32
+
33
+ def success(delivery, response)
34
+ send_response(delivery, response, type: 'success')
35
+ end
36
+
37
+ def error(delivery, response)
38
+ send_response(delivery, response, type: 'error')
39
+ end
40
+
41
+ private
42
+
43
+ def send_response(delivery, response, opts = {})
44
+ @producer.produce delivery.reply_to.force_encoding('utf-8'), response, {
45
+ correlation_id: delivery.correlation_id
46
+ }.merge(opts)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -17,27 +17,21 @@ class Freddy
17
17
  end
18
18
 
19
19
  @response_queue = @channel.queue("", exclusive: true)
20
- @request_manager.start
21
20
 
22
21
  @response_consumer = Consumers::ResponseConsumer.new(@logger)
23
22
  @response_consumer.consume(@response_queue, &method(:handle_response))
24
23
  end
25
24
 
26
- def produce(destination, payload, properties)
27
- timeout_in_seconds = properties.fetch(:timeout_in_seconds)
28
- container = SyncResponseContainer.new
29
- async_request destination, payload, properties, &container
30
- container.wait_for_response(timeout_in_seconds + 0.1)
31
- end
25
+ def produce(destination, payload, timeout_in_seconds:, delete_on_timeout:, **properties)
26
+ correlation_id = SecureRandom.uuid
32
27
 
33
- private
28
+ container = SyncResponseContainer.new(
29
+ on_timeout(correlation_id, destination, timeout_in_seconds)
30
+ )
34
31
 
35
- def async_request(destination, payload, timeout_in_seconds:, delete_on_timeout:, **properties, &block)
36
- correlation_id = SecureRandom.uuid
37
32
  @request_manager.store(correlation_id,
38
- callback: block,
39
- destination: destination,
40
- expires_at: Time.now + timeout_in_seconds
33
+ callback: container,
34
+ destination: destination
41
35
  )
42
36
 
43
37
  if delete_on_timeout
@@ -59,6 +53,8 @@ class Freddy
59
53
  # need to lock these.
60
54
  @topic_exchange.publish json_payload, properties.dup
61
55
  @exchange.publish json_payload, properties.dup
56
+
57
+ container.wait_for_response(timeout_in_seconds)
62
58
  end
63
59
 
64
60
  def handle_response(delivery)
@@ -78,11 +74,23 @@ class Freddy
78
74
  @logger.debug "Got response for request to #{request[:destination]} "\
79
75
  "with correlation_id #{delivery.correlation_id}"
80
76
  request[:callback].call(delivery.payload, delivery)
81
- rescue => e
82
- @logger.error "Exception occured while handling the response of "\
83
- "request made to #{request[:destination]} with "\
84
- "correlation_id #{correlation_id}: #{Utils.format_exception(e)}"
85
- Utils.notify_exception(e, destination: request[:destination], correlation_id: correlation_id)
77
+ end
78
+
79
+ def on_timeout(correlation_id, destination, timeout_in_seconds)
80
+ Proc.new do
81
+ @logger.warn "Request timed out waiting response from #{destination}"\
82
+ ", correlation id #{correlation_id}"
83
+
84
+ Utils.notify 'RequestTimeout',
85
+ "Request timed out waiting for response from #{destination}",
86
+ {
87
+ correlation_id: correlation_id,
88
+ destination: destination,
89
+ timeout_in_seconds: timeout_in_seconds
90
+ }
91
+
92
+ @request_manager.delete(correlation_id)
93
+ end
86
94
  end
87
95
  end
88
96
  end
@@ -1,20 +1,10 @@
1
1
  class Freddy
2
2
  class RequestManager
3
-
4
3
  def initialize(logger)
5
4
  @requests = Hamster.mutable_hash
6
5
  @logger = logger
7
6
  end
8
7
 
9
- def start
10
- @timeout_thread = Thread.new do
11
- while true do
12
- clear_timeouts Time.now
13
- sleep 0.05
14
- end
15
- end
16
- end
17
-
18
8
  def no_route(correlation_id)
19
9
  if request = @requests[correlation_id]
20
10
  @requests.delete correlation_id
@@ -29,26 +19,5 @@ class Freddy
29
19
  def delete(correlation_id)
30
20
  @requests.delete(correlation_id)
31
21
  end
32
-
33
- private
34
-
35
- def clear_timeouts(now)
36
- @requests.each do |key, value|
37
- timeout(key, value) if now > value[:expires_at]
38
- end
39
- end
40
-
41
- def timeout(correlation_id, request)
42
- @requests.delete correlation_id
43
-
44
- @logger.warn "Request timed out waiting response from #{request[:destination]}, correlation id #{correlation_id}"
45
- Utils.notify 'RequestTimeout', "Request timed out waiting for response from #{request[:destination]}", {
46
- correlation_id: correlation_id,
47
- destination: request[:destination],
48
- expires_at: request[:expires_at]
49
- }
50
-
51
- request[:callback].call({error: 'RequestTimeout', message: 'Timed out waiting for response'}, nil)
52
- end
53
22
  end
54
23
  end
@@ -3,41 +3,36 @@ require 'timeout'
3
3
 
4
4
  class Freddy
5
5
  class SyncResponseContainer
6
- def initialize
6
+ def initialize(on_timeout)
7
7
  @mutex = Mutex.new
8
+ @resource = ConditionVariable.new
9
+ @on_timeout = on_timeout
8
10
  end
9
11
 
10
12
  def call(response, delivery)
13
+ if response.nil?
14
+ raise StandardError, 'unexpected nil value for response'
15
+ end
16
+
11
17
  @response = response
12
18
  @delivery = delivery
13
- @mutex.synchronize { @waiting.wakeup }
19
+ @mutex.synchronize { @resource.signal }
14
20
  end
15
21
 
16
22
  def wait_for_response(timeout)
17
- @mutex.synchronize do
18
- @waiting = Thread.current
19
- @mutex.sleep(timeout)
20
- end
23
+ @mutex.synchronize { @response || @resource.wait(@mutex, timeout) }
21
24
 
22
- if @response.nil?
23
- raise Timeout::Error, 'execution expired'
24
- elsif @response[:error] == 'RequestTimeout'
25
- raise TimeoutError.new(@response)
25
+ if !@response
26
+ @on_timeout.call
27
+ raise TimeoutError.new(
28
+ error: 'RequestTimeout',
29
+ message: 'Timed out waiting for response'
30
+ )
26
31
  elsif !@delivery || @delivery.type == 'error'
27
32
  raise InvalidRequestError.new(@response)
28
33
  else
29
34
  @response
30
35
  end
31
36
  end
32
-
33
- private
34
-
35
- def to_proc
36
- Proc.new {|*args| self.call(*args)}
37
- end
38
-
39
- def filled?
40
- !@response.nil?
41
- end
42
37
  end
43
38
  end
data/lib/freddy/utils.rb CHANGED
@@ -1,12 +1,10 @@
1
1
  class Freddy
2
2
  class Utils
3
3
  def self.format_exception(exception)
4
- backtrace = exception.backtrace.map do |x|
5
- x.match(/^(.+?):(\d+)(|:in `(.+)')$/);
6
- [$1, $2, $4]
7
- end.join("\n")
4
+ message = exception.message
5
+ backtrace = exception.backtrace.join("\n")
8
6
 
9
- "#{exception.exception}\n#{backtrace}"
7
+ "#{message}\n#{backtrace}"
10
8
  end
11
9
 
12
10
  def self.notify(name, message, parameters={})
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Freddy::Consumers do
4
+ describe '.log_receive_event' do
5
+ subject { described_class.log_receive_event(logger, queue_name, delivery) }
6
+
7
+ let(:queue_name) { 'salemove' }
8
+ let(:delivery) do
9
+ instance_double(Freddy::Delivery,
10
+ payload: {key: 'value'},
11
+ correlation_id: 'a1b2'
12
+ )
13
+ end
14
+
15
+ context 'when configured with logasm logger' do
16
+ let(:logger) { logasm_class.new }
17
+ let(:logasm_class) { Class.new }
18
+
19
+ before do
20
+ stub_const('::Logasm', logasm_class)
21
+ end
22
+
23
+ it 'logs the received event' do
24
+ expect(logger).to receive(:debug).with('Received message',
25
+ queue: 'salemove', payload: {key: 'value'}, correlation_id: 'a1b2'
26
+ )
27
+
28
+ subject
29
+ end
30
+ end
31
+
32
+ context 'when configured with regular logger' do
33
+ let(:logger) { Logger.new('/dev/null') }
34
+
35
+ it 'logs the received event' do
36
+ expect(logger).to receive(:debug)
37
+ .with('Received message on salemove with payload {:key=>"value"} with correlation_id a1b2')
38
+
39
+ subject
40
+ end
41
+ end
42
+ end
43
+ end
@@ -4,12 +4,11 @@ describe Freddy::MessageHandler do
4
4
  subject(:handler) { described_class.new(adapter, delivery) }
5
5
 
6
6
  let(:adapter) { double }
7
- let(:delivery) { double(reply_to: reply_to, correlation_id: 'abc') }
8
- let(:reply_to) { double }
7
+ let(:delivery) { double }
9
8
 
10
9
  describe '#success' do
11
10
  it 'delegates to the adapter' do
12
- expect(adapter).to receive(:success).with(reply_to, x: 'y')
11
+ expect(adapter).to receive(:success).with(delivery, x: 'y')
13
12
 
14
13
  subject.success(x: 'y')
15
14
  end
@@ -17,7 +16,7 @@ describe Freddy::MessageHandler do
17
16
 
18
17
  describe '#error' do
19
18
  it 'delegates to the adapter' do
20
- expect(adapter).to receive(:error).with(reply_to, error: 'text')
19
+ expect(adapter).to receive(:error).with(delivery, error: 'text')
21
20
 
22
21
  subject.error(error: 'text')
23
22
  end
@@ -1,13 +1,54 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Freddy::SyncResponseContainer do
4
- let(:container) { described_class.new }
4
+ let(:container) { described_class.new(on_timeout) }
5
+ let(:on_timeout) { Proc.new {} }
5
6
 
6
7
  context 'when timeout' do
7
8
  subject { container.wait_for_response(0.01) }
8
9
 
9
10
  it 'raises timeout error' do
10
- expect { subject }.to raise_error(Timeout::Error, 'execution expired')
11
+ expect { subject }.to raise_error do |error|
12
+ expect(error).to be_a(Freddy::TimeoutError)
13
+ expect(error.response).to eq(
14
+ error: 'RequestTimeout',
15
+ message: 'Timed out waiting for response'
16
+ )
17
+ end
18
+ end
19
+ end
20
+
21
+ context 'when nil response' do
22
+ let(:delivery) { {} }
23
+
24
+ it 'raises timeout error' do
25
+ expect {
26
+ container.call(nil, delivery)
27
+ }.to raise_error(StandardError, 'unexpected nil value for response')
28
+ end
29
+ end
30
+
31
+ describe '#wait_for_response' do
32
+ let(:timeout) { 2 }
33
+ let(:response) { {msg: 'response'} }
34
+ let(:delivery) { OpenStruct.new(type: 'success') }
35
+
36
+ context 'when called after #call' do
37
+ let(:max_wait_time_in_seconds) { 0.5 }
38
+
39
+ before do
40
+ container.call(response, delivery)
41
+ end
42
+
43
+ it 'returns response' do
44
+ expect(container.wait_for_response(timeout)).to eq(response)
45
+ end
46
+
47
+ it 'does not wait for timeout' do
48
+ expect {
49
+ container.wait_for_response(timeout)
50
+ }.to change(Time, :now).by_at_most(max_wait_time_in_seconds)
51
+ end
11
52
  end
12
53
  end
13
54
  end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+
3
+ describe Freddy::Utils do
4
+ describe '.format_exception' do
5
+ subject { described_class.format_exception(exception) }
6
+
7
+ let(:exception) { double(backtrace: backtrace, message: message) }
8
+ let(:message) { 'format exception test' }
9
+ let(:backtrace) { ['line1', 'line2', 'line3'] }
10
+
11
+ it 'format the exception' do
12
+ should eq "format exception test\n" \
13
+ "line1\n" \
14
+ "line2\n" \
15
+ 'line3'
16
+ end
17
+ end
18
+
19
+ describe '.notify' do
20
+ subject { described_class.notify(error_class, error_message, parameters) }
21
+
22
+ let(:env_attributes) { double }
23
+ let(:error_class) { double }
24
+ let(:error_message) { double }
25
+ let(:parameters) { double }
26
+
27
+ context 'when Airbrake is defined' do
28
+ let(:airbrake) { double }
29
+
30
+ before do
31
+ allow(ENV).to receive(:to_hash) { env_attributes }
32
+ stub_const('::Airbrake', airbrake)
33
+ end
34
+
35
+ it 'notifies airbrake' do
36
+ expect(airbrake).to receive(:notify_or_ignore).with(
37
+ error_class: error_class,
38
+ error_message: error_message,
39
+ cgi_data: env_attributes,
40
+ parameters: parameters
41
+ )
42
+
43
+ subject
44
+ end
45
+ end
46
+
47
+ context 'when Airbrake is not defined' do
48
+ it 'does nothing' do
49
+ should eq(nil)
50
+ end
51
+ end
52
+ end
53
+
54
+ describe '.notify_exception' do
55
+ subject { described_class.notify_exception(exception, {a: 'b'}) }
56
+
57
+ let(:exception) { double }
58
+
59
+ context 'when Airbrake is defined' do
60
+ let(:airbrake) { double }
61
+
62
+ before do
63
+ stub_const('::Airbrake', airbrake)
64
+ end
65
+
66
+ it 'notifies airbrake' do
67
+ expect(airbrake).to receive(:notify_or_ignore) do |ex, content|
68
+ expect(ex).to eq(exception)
69
+ expect(content[:cgi_data]).to be_instance_of(Hash)
70
+ expect(content[:parameters]).to eq(a: 'b')
71
+ end
72
+
73
+ subject
74
+ end
75
+ end
76
+
77
+ context 'when Airbrake is not defined' do
78
+ it 'does nothing' do
79
+ should eq(nil)
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Reply' do
4
+ let(:freddy) { Freddy.build(logger, config) }
5
+
6
+ let(:destination) { random_destination }
7
+ let(:request_payload) { {req: 'load'} }
8
+ let(:response_payload) { {res: 'load'} }
9
+
10
+ after { freddy.close }
11
+
12
+ context 'when a synchronized request' do
13
+ before do
14
+ freddy.respond_to(destination) do |payload, msg_handler|
15
+ msg_handler.success(response_payload)
16
+ end
17
+ end
18
+
19
+ it 'sends reply' do
20
+ response = freddy.deliver_with_response(destination, request_payload)
21
+ expect(response).to eq(response_payload)
22
+ end
23
+
24
+ it 'does not send the reply to the topic queue' do
25
+ freddy.tap_into 'amq.*' do |payload|
26
+ @message_received = true
27
+ end
28
+
29
+ freddy.deliver_with_response(destination, request_payload)
30
+ default_sleep
31
+
32
+ expect(@message_received).to be_falsy
33
+ end
34
+ end
35
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,16 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup
4
+
5
+ require 'codeclimate-test-reporter'
6
+ SimpleCov.start do
7
+ formatter SimpleCov::Formatter::MultiFormatter.new([
8
+ SimpleCov::Formatter::HTMLFormatter,
9
+ CodeClimate::TestReporter::Formatter
10
+ ])
11
+ add_filter '/spec/'
12
+ end
13
+
1
14
  require 'pry'
2
15
  require 'securerandom'
3
16
  require 'freddy'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: freddy-jruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Urmas Talimaa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-08 00:00:00.000000000 Z
11
+ date: 2016-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -124,7 +124,7 @@ files:
124
124
  - lib/freddy/error_response.rb
125
125
  - lib/freddy/invalid_request_error.rb
126
126
  - lib/freddy/message_handler.rb
127
- - lib/freddy/message_handlers.rb
127
+ - lib/freddy/message_handler_adapaters.rb
128
128
  - lib/freddy/payload.rb
129
129
  - lib/freddy/producers.rb
130
130
  - lib/freddy/producers/reply_producer.rb
@@ -136,13 +136,16 @@ files:
136
136
  - lib/freddy/timeout_error.rb
137
137
  - lib/freddy/utils.rb
138
138
  - spec/freddy/consumers/respond_to_consumer_spec.rb
139
+ - spec/freddy/consumers_spec.rb
139
140
  - spec/freddy/error_response_spec.rb
140
141
  - spec/freddy/freddy_spec.rb
141
142
  - spec/freddy/message_handler_spec.rb
142
143
  - spec/freddy/responder_handler_spec.rb
143
144
  - spec/freddy/sync_response_container_spec.rb
145
+ - spec/freddy/utils_spec.rb
144
146
  - spec/integration/concurrency_spec.rb
145
147
  - spec/integration/logging_spec.rb
148
+ - spec/integration/reply_spec.rb
146
149
  - spec/spec_helper.rb
147
150
  homepage:
148
151
  licenses:
@@ -170,11 +173,14 @@ specification_version: 4
170
173
  summary: API for inter-application messaging supporting acknowledgements and request-response
171
174
  test_files:
172
175
  - spec/freddy/consumers/respond_to_consumer_spec.rb
176
+ - spec/freddy/consumers_spec.rb
173
177
  - spec/freddy/error_response_spec.rb
174
178
  - spec/freddy/freddy_spec.rb
175
179
  - spec/freddy/message_handler_spec.rb
176
180
  - spec/freddy/responder_handler_spec.rb
177
181
  - spec/freddy/sync_response_container_spec.rb
182
+ - spec/freddy/utils_spec.rb
178
183
  - spec/integration/concurrency_spec.rb
179
184
  - spec/integration/logging_spec.rb
185
+ - spec/integration/reply_spec.rb
180
186
  - spec/spec_helper.rb
@@ -1,77 +0,0 @@
1
- class Freddy
2
- module MessageHandlers
3
- class Factory
4
- def initialize(producer, logger)
5
- @producer = producer
6
- @logger = logger
7
- end
8
-
9
- def build(type, destination)
10
- if type == 'request'
11
- RequestHandler.new(@producer, destination, @logger)
12
- else
13
- StandardMessageHandler.new(destination, @logger)
14
- end
15
- end
16
- end
17
-
18
- class StandardMessageHandler
19
- def initialize(destination, logger)
20
- @destination = destination
21
- @logger = logger
22
- end
23
-
24
- def handle_message(payload, msg_handler, &block)
25
- block.call payload, msg_handler
26
- rescue Exception => e
27
- @logger.error "Exception occured while processing message from #{Utils.format_exception(e)}"
28
- Utils.notify_exception(e, destination: @destination)
29
- end
30
-
31
- def success(*)
32
- # NOP
33
- end
34
-
35
- def error(*)
36
- # NOP
37
- end
38
- end
39
-
40
- class RequestHandler
41
- def initialize(producer, destination, logger)
42
- @producer = producer
43
- @logger = logger
44
- @destination = destination
45
- end
46
-
47
- def handle_message(payload, msg_handler, &block)
48
- @correlation_id = msg_handler.correlation_id
49
-
50
- if !@correlation_id
51
- @logger.error "Received request without correlation_id"
52
- else
53
- block.call payload, msg_handler
54
- end
55
- rescue Exception => e
56
- @logger.error "Exception occured while handling the request with correlation_id #{@correlation_id}: #{Utils.format_exception(e)}"
57
- Utils.notify_exception(e, correlation_id: @correlation_id, destination: @destination)
58
- end
59
-
60
- def success(reply_to, response)
61
- send_response(reply_to, response, type: 'success')
62
- end
63
-
64
- def error(reply_to, response)
65
- send_response(reply_to, response, type: 'error')
66
- end
67
-
68
- private
69
-
70
- def send_response(reply_to, response, opts = {})
71
- @producer.produce reply_to.force_encoding('utf-8'), response, {
72
- correlation_id: @correlation_id
73
- }.merge(opts)
74
- end
75
- end
76
- end
77
- end