lapine 0.1.1 → 0.2.0
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.
- checksums.yaml +4 -4
- data/Gemfile +4 -0
- data/bin/lapine +5 -0
- data/example/consumer_config.yml +24 -0
- data/example/consumer_handler.rb +5 -0
- data/example/producer.rb +20 -0
- data/lapine.gemspec +5 -2
- data/lib/lapine/cli.rb +30 -0
- data/lib/lapine/consumer.rb +1 -0
- data/lib/lapine/consumer/config.rb +127 -0
- data/lib/lapine/consumer/connection.rb +16 -0
- data/lib/lapine/consumer/dispatcher.rb +65 -0
- data/lib/lapine/consumer/environment.rb +47 -0
- data/lib/lapine/consumer/runner.rb +69 -0
- data/lib/lapine/consumer/topology.rb +45 -0
- data/lib/lapine/dtrace.rb +30 -0
- data/lib/lapine/test/exchange.rb +10 -4
- data/lib/lapine/test/rspec_helper.rb +4 -4
- data/lib/lapine/version.rb +1 -1
- data/spec/lib/lapine/consumer/config_spec.rb +164 -0
- data/spec/lib/lapine/consumer/connection_spec.rb +23 -0
- data/spec/lib/lapine/consumer/dispatcher_spec.rb +66 -0
- data/spec/lib/lapine/consumer/runner_spec.rb +76 -0
- data/spec/lib/lapine/consumer/topology_spec.rb +82 -0
- data/spec/lib/lapine/test/exchange_spec.rb +41 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/support/rspec_test_helper.rb +14 -0
- metadata +88 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ccc8f9935974ce4c4981bc4d43da3f08cdf2c8b2
|
4
|
+
data.tar.gz: a296e0395e2c43aaf6369a47c921176c2862442e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f2992302c858ec6589bc6b5147cd85b332bb6eb83a4ba9ee7df10be251711fbb7bc9e9d4e6d292b33b3a97bc6c7123054553ee3866adbc33de6c17d71f602c39
|
7
|
+
data.tar.gz: 61271187c14a82e828f3031c0063d8f0ecd237ac1d7dff4cb1ed5ba223dff3d9713fe3cc0c4b66ec1c8e421b6c3aba434af3afd255d5bbac3d54d3a61002f163
|
data/Gemfile
CHANGED
data/bin/lapine
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
connection:
|
2
|
+
host: '127.0.0.1'
|
3
|
+
port: 5672
|
4
|
+
ssl: false
|
5
|
+
vhost: '/'
|
6
|
+
username: 'guest'
|
7
|
+
password: 'guest'
|
8
|
+
|
9
|
+
require:
|
10
|
+
- example/consumer_handler
|
11
|
+
|
12
|
+
topics:
|
13
|
+
- lapine.topic
|
14
|
+
|
15
|
+
queues:
|
16
|
+
- q: handler
|
17
|
+
topic: lapine.topic
|
18
|
+
routing_key: stuff
|
19
|
+
handlers:
|
20
|
+
- ConsumerHandler
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
|
data/example/producer.rb
ADDED
data/lapine.gemspec
CHANGED
@@ -6,7 +6,7 @@ require 'lapine/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'lapine'
|
8
8
|
spec.version = Lapine::VERSION
|
9
|
-
spec.authors = ['Eric Saxby','Matt Camuto']
|
9
|
+
spec.authors = ['Eric Saxby', 'Matt Camuto']
|
10
10
|
spec.email = ['dev@wanelo.com']
|
11
11
|
spec.summary = %q{Talk to rabbits}
|
12
12
|
spec.description = %q{Talk to rabbits}
|
@@ -18,12 +18,15 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
|
+
spec.add_dependency 'amqp'
|
21
22
|
spec.add_dependency 'bunny'
|
23
|
+
spec.add_dependency 'mixlib-cli'
|
22
24
|
spec.add_dependency 'oj'
|
25
|
+
spec.add_dependency 'ruby-usdt', '>= 0.2.2'
|
23
26
|
|
24
27
|
spec.add_development_dependency 'bundler', '~> 1.7'
|
25
28
|
spec.add_development_dependency 'guard-rspec', '~> 4.3.1'
|
26
29
|
spec.add_development_dependency 'rake', '~> 10.0'
|
27
30
|
spec.add_development_dependency 'rspec', '~> 3.1.0'
|
28
|
-
|
31
|
+
spec.add_development_dependency 'em-spec'
|
29
32
|
end
|
data/lib/lapine/cli.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module Lapine
|
2
|
+
class CLI
|
3
|
+
attr_reader :argv, :command
|
4
|
+
|
5
|
+
def initialize(argv)
|
6
|
+
@argv = argv
|
7
|
+
@command = argv.shift
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
case command
|
12
|
+
when 'consume'
|
13
|
+
require 'lapine/consumer'
|
14
|
+
::Lapine::Consumer::Runner.new(argv).run
|
15
|
+
else
|
16
|
+
usage
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def usage
|
21
|
+
puts <<-EOF.gsub(/^ {8}/, '')
|
22
|
+
Usage: lapine [command] [options]
|
23
|
+
|
24
|
+
commands: consume
|
25
|
+
EOF
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'lapine/consumer/runner'
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'mixlib/cli'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Lapine
|
5
|
+
module Consumer
|
6
|
+
class Config
|
7
|
+
include Mixlib::CLI
|
8
|
+
|
9
|
+
banner 'Usage: lapine consume (options)'
|
10
|
+
|
11
|
+
option :config_file,
|
12
|
+
short: '-c CONFIG_FILE',
|
13
|
+
long: '--config CONFIG_FILE',
|
14
|
+
description: 'YML file with configuration of subscribers',
|
15
|
+
required: true
|
16
|
+
|
17
|
+
option :logfile,
|
18
|
+
short: '-l LOGFILE',
|
19
|
+
long: '--logfile LOGFILE',
|
20
|
+
description: 'where to log consumer info',
|
21
|
+
required: false
|
22
|
+
|
23
|
+
option :host,
|
24
|
+
short: '-H RABBIT_HOST',
|
25
|
+
long: '--host RABBIT_HOST',
|
26
|
+
description: 'IP or FQDN of RabbitMQ host (default 127.0.0.1)'
|
27
|
+
|
28
|
+
option :port,
|
29
|
+
short: '-p RABBIT_PORT',
|
30
|
+
long: '--port RABBIT_PORT',
|
31
|
+
description: 'port to use with RabbitMQ (default 5672)'
|
32
|
+
|
33
|
+
option :ssl,
|
34
|
+
short: '-S',
|
35
|
+
long: '--ssl',
|
36
|
+
description: 'use ssl to connect (default false)'
|
37
|
+
|
38
|
+
option :vhost,
|
39
|
+
short: '-V VHOST',
|
40
|
+
long: '--vhost VHOST',
|
41
|
+
description: 'RabbitMQ vhost to use (default "/")'
|
42
|
+
|
43
|
+
option :username,
|
44
|
+
short: '-U USERNAME',
|
45
|
+
long: '--username USERNAME',
|
46
|
+
description: 'RabbitMQ user (default guest)'
|
47
|
+
|
48
|
+
option :password,
|
49
|
+
short: '-P PASSWORD',
|
50
|
+
long: '--password PASSWORD',
|
51
|
+
description: 'RabbitMQ password (default guest)'
|
52
|
+
|
53
|
+
option :debug,
|
54
|
+
long: '--debug',
|
55
|
+
description: 'More verbose (and possibly non-threadsafe) log statements',
|
56
|
+
default: false
|
57
|
+
|
58
|
+
option :help,
|
59
|
+
short: '-?',
|
60
|
+
long: '--help',
|
61
|
+
description: 'Show this message',
|
62
|
+
on: :tail,
|
63
|
+
boolean: true,
|
64
|
+
show_options: true,
|
65
|
+
exit: 0
|
66
|
+
|
67
|
+
def load(argv)
|
68
|
+
parse_options argv
|
69
|
+
self
|
70
|
+
end
|
71
|
+
|
72
|
+
def debug?
|
73
|
+
config[:debug]
|
74
|
+
end
|
75
|
+
|
76
|
+
def logfile
|
77
|
+
config[:logfile]
|
78
|
+
end
|
79
|
+
|
80
|
+
def queues
|
81
|
+
yaml_config['queues']
|
82
|
+
end
|
83
|
+
|
84
|
+
def require
|
85
|
+
yaml_config['require'] || []
|
86
|
+
end
|
87
|
+
|
88
|
+
def topics
|
89
|
+
yaml_config['topics']
|
90
|
+
end
|
91
|
+
|
92
|
+
def connection_properties
|
93
|
+
{
|
94
|
+
host: '127.0.0.1',
|
95
|
+
port: 5672,
|
96
|
+
ssl: false,
|
97
|
+
vhost: '/',
|
98
|
+
username: 'guest',
|
99
|
+
password: 'guest'
|
100
|
+
}.merge(file_connection_props)
|
101
|
+
.merge(cli_connection_props)
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def file_connection_props
|
107
|
+
return {} unless yaml_config['connection']
|
108
|
+
yaml_config['connection'].inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
109
|
+
end
|
110
|
+
|
111
|
+
def cli_connection_props
|
112
|
+
{
|
113
|
+
host: config[:host],
|
114
|
+
port: config[:port] ? config[:port].to_i : nil,
|
115
|
+
ssl: config[:ssl],
|
116
|
+
vhost: config[:vhost],
|
117
|
+
username: config[:username],
|
118
|
+
password: config[:password]
|
119
|
+
}.delete_if { |k, v| v.nil? }
|
120
|
+
end
|
121
|
+
|
122
|
+
def yaml_config
|
123
|
+
@yaml ||= YAML.load_file(config[:config_file])
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'amqp'
|
2
|
+
require 'eventmachine'
|
3
|
+
|
4
|
+
module Lapine
|
5
|
+
module Consumer
|
6
|
+
class Connection
|
7
|
+
attr_reader :connection, :channel, :exchange
|
8
|
+
|
9
|
+
def initialize(config, topic)
|
10
|
+
@connection = AMQP.connect(config.connection_properties)
|
11
|
+
@channel = AMQP::Channel.new(connection)
|
12
|
+
@exchange = AMQP::Exchange.new(channel, :topic, topic, durable: true)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'oj'
|
2
|
+
require 'lapine/dtrace'
|
3
|
+
|
4
|
+
module Lapine
|
5
|
+
module Consumer
|
6
|
+
class Dispatcher
|
7
|
+
class DefaultErrorHandler
|
8
|
+
def call(e, data)
|
9
|
+
logger.info "Lapine::Dispatcher unable to dispatch, #{e.message}, data: #{data}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :delegate_class, :raw_payload, :metadata, :logger
|
14
|
+
|
15
|
+
def self.error_handler=(handler)
|
16
|
+
@error_handler = handler
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.error_handler
|
20
|
+
@error_handler || DefaultErrorHandler.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(delegate_class, raw_payload, metadata, logger)
|
24
|
+
@delegate_class = delegate_class
|
25
|
+
@raw_payload = raw_payload
|
26
|
+
@metadata = metadata
|
27
|
+
@logger = logger
|
28
|
+
end
|
29
|
+
|
30
|
+
def dispatch
|
31
|
+
Lapine::DTrace.fire!(:dispatch_enter, delegate_class.name, raw_payload)
|
32
|
+
begin
|
33
|
+
json = Oj.load(raw_payload)
|
34
|
+
with_timed_logging(json) { do_dispatch(json) }
|
35
|
+
rescue Oj::Error => e
|
36
|
+
self.class.error_handler.call(e, raw_payload)
|
37
|
+
rescue StandardError => e
|
38
|
+
self.class.error_handler.call(e, json)
|
39
|
+
end
|
40
|
+
Lapine::DTrace.fire!(:dispatch_return, delegate_class.name, raw_payload)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def with_timed_logging(json)
|
46
|
+
time = Time.now
|
47
|
+
ret = yield
|
48
|
+
time_end = Time.now
|
49
|
+
duration = (time_end - time) * 1000
|
50
|
+
logger.info "Processing rabbit message handler:#{delegate_class.name} duration(ms):#{duration} payload:#{json.inspect}"
|
51
|
+
ret
|
52
|
+
end
|
53
|
+
|
54
|
+
def delegate_method_names
|
55
|
+
[:handle_lapine_payload, :perform_async]
|
56
|
+
end
|
57
|
+
|
58
|
+
def do_dispatch(payload)
|
59
|
+
delegate_method_names.each do |meth|
|
60
|
+
return delegate_class.send(meth, payload, metadata) if delegate_class.respond_to?(meth)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Lapine
|
2
|
+
module Consumer
|
3
|
+
class Environment
|
4
|
+
attr_reader :config
|
5
|
+
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def load!
|
11
|
+
set_environment
|
12
|
+
load_rails
|
13
|
+
require_from_config
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_environment
|
17
|
+
ENV['RAILS_ENV'] ||= 'development'
|
18
|
+
ENV['RACK_ENV'] = ENV['RAILS_ENV']
|
19
|
+
end
|
20
|
+
|
21
|
+
def load_rails
|
22
|
+
begin
|
23
|
+
require 'rails'
|
24
|
+
if ::Rails.application.respond_to?(:eager_load)
|
25
|
+
require File.expand_path('config/environment.rb')
|
26
|
+
::Rails.application.eager_load!
|
27
|
+
else
|
28
|
+
require File.expand_path('config/application.rb')
|
29
|
+
::Rails::Application.initializer "lapine.load_rails" do
|
30
|
+
::Rails.application.config.eager_load = true
|
31
|
+
end
|
32
|
+
require File.expand_path('config/environment.rb')
|
33
|
+
end
|
34
|
+
rescue LoadError
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def require_from_config
|
39
|
+
if config.require
|
40
|
+
config.require.each do |file|
|
41
|
+
require File.expand_path(file)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'amqp'
|
2
|
+
require 'digest'
|
3
|
+
require 'eventmachine'
|
4
|
+
require 'logger'
|
5
|
+
require 'lapine/consumer/config'
|
6
|
+
require 'lapine/consumer/connection'
|
7
|
+
require 'lapine/consumer/environment'
|
8
|
+
require 'lapine/consumer/topology'
|
9
|
+
require 'lapine/consumer/dispatcher'
|
10
|
+
|
11
|
+
module Lapine
|
12
|
+
module Consumer
|
13
|
+
class Runner
|
14
|
+
attr_reader :argv
|
15
|
+
|
16
|
+
def initialize(argv)
|
17
|
+
@argv = argv
|
18
|
+
@message_count = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
handle_signals!
|
23
|
+
Consumer::Environment.new(config).load!
|
24
|
+
logger.info 'starting Lapine::Consumer'
|
25
|
+
|
26
|
+
EventMachine.run do
|
27
|
+
topology.each_binding do |q, conn, routing_key, classes|
|
28
|
+
queue = conn.channel.queue(q).bind(conn.exchange, routing_key: routing_key)
|
29
|
+
queue.subscribe(ack: true) do |metadata, payload|
|
30
|
+
classes.each do |clazz|
|
31
|
+
Lapine::Consumer::Dispatcher.new(clazz, payload, metadata, logger).dispatch
|
32
|
+
end
|
33
|
+
|
34
|
+
@message_count += 1 if config.debug?
|
35
|
+
|
36
|
+
metadata.ack
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
if config.debug?
|
41
|
+
EventMachine.add_periodic_timer(10) do
|
42
|
+
logger.info "Lapine::Consumer messages processed=#{@message_count}"
|
43
|
+
@message_count = 0
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
logger.warn 'exiting Lapine::Consumer'
|
49
|
+
end
|
50
|
+
|
51
|
+
def config
|
52
|
+
@config ||= Lapine::Consumer::Config.new.load(argv)
|
53
|
+
end
|
54
|
+
|
55
|
+
def topology
|
56
|
+
@topology ||= ::Lapine::Consumer::Topology.new(config, logger)
|
57
|
+
end
|
58
|
+
|
59
|
+
def logger
|
60
|
+
@logger ||= config.logfile ? Logger.new(config.logfile) : Logger.new(STDOUT)
|
61
|
+
end
|
62
|
+
|
63
|
+
def handle_signals!
|
64
|
+
Signal.trap('INT') { EventMachine.stop }
|
65
|
+
Signal.trap('TERM') { EventMachine.stop }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'lapine/consumer/connection'
|
2
|
+
|
3
|
+
module Lapine
|
4
|
+
module Consumer
|
5
|
+
class Topology < Struct.new(:config, :logger)
|
6
|
+
|
7
|
+
def each_binding
|
8
|
+
config.queues.each do |node|
|
9
|
+
classes = node['handlers'].map do |handler|
|
10
|
+
handler.split('::').inject(Object) do |const, name|
|
11
|
+
const.const_get(name)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
yield node['q'], get_conn(node['topic']), node['routing_key'], classes
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def each_topic
|
21
|
+
config.topics.each do |topic|
|
22
|
+
yield topic
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def get_conn(name)
|
29
|
+
@cons ||= {}.tap do |cons|
|
30
|
+
each_topic do |topic|
|
31
|
+
debug "Connecting to RabbiMQ: topic: #{topic}, #{config.connection_properties}"
|
32
|
+
cons[topic] = Lapine::Consumer::Connection.new(config, topic)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
@cons[name]
|
36
|
+
end
|
37
|
+
|
38
|
+
def debug(msg)
|
39
|
+
return unless config.debug?
|
40
|
+
return unless logger
|
41
|
+
logger.info msg
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'usdt'
|
2
|
+
|
3
|
+
module Lapine
|
4
|
+
class DTrace
|
5
|
+
attr_reader :provider, :probes
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@provider = USDT::Provider.create(:ruby, :lapine)
|
9
|
+
|
10
|
+
@probes = {
|
11
|
+
# args: Class name, payload
|
12
|
+
dispatch_enter: provider.probe(:dispatch, :enter, :string, :string),
|
13
|
+
# args: Class name, payload
|
14
|
+
dispatch_return: provider.probe(:dispatch, :return, :string, :string),
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.provider
|
19
|
+
@provider ||= new.tap do |p|
|
20
|
+
p.provider.enable
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.fire!(probe_name, *args)
|
25
|
+
raise "Unknown probe: #{probe_name}" unless self.provider.probes[probe_name]
|
26
|
+
probe = self.provider.probes[probe_name]
|
27
|
+
probe.fire(*args) if probe.enabled?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/lapine/test/exchange.rb
CHANGED
@@ -35,16 +35,21 @@ module Lapine
|
|
35
35
|
end
|
36
36
|
|
37
37
|
class FakeQueue
|
38
|
-
attr_reader :
|
38
|
+
attr_reader :exchange, :message_history
|
39
39
|
|
40
40
|
def bind(exchange)
|
41
|
-
@
|
42
|
-
|
41
|
+
@exchange = exchange
|
42
|
+
@message_history = MessageHistory.new
|
43
|
+
exchange.bind message_history
|
43
44
|
self
|
44
45
|
end
|
45
46
|
|
46
47
|
def message_count
|
47
|
-
|
48
|
+
message_history.message_count
|
49
|
+
end
|
50
|
+
|
51
|
+
def messages
|
52
|
+
message_history.messages
|
48
53
|
end
|
49
54
|
end
|
50
55
|
|
@@ -76,6 +81,7 @@ module Lapine
|
|
76
81
|
end
|
77
82
|
|
78
83
|
def close!
|
84
|
+
@exchange = nil
|
79
85
|
true
|
80
86
|
end
|
81
87
|
end
|
@@ -3,11 +3,11 @@ require 'lapine/test/exchange'
|
|
3
3
|
module Lapine
|
4
4
|
module Test
|
5
5
|
module RSpecHelper
|
6
|
-
def self.setup(
|
7
|
-
|
8
|
-
|
6
|
+
def self.setup(_example = nil)
|
7
|
+
RSpec::Mocks::AllowanceTarget.new(Lapine::Exchange).to(
|
8
|
+
RSpec::Mocks::Matchers::Receive.new(:new, ->(name, properties) {
|
9
9
|
Lapine::Test::Exchange.new(name, properties)
|
10
|
-
}
|
10
|
+
})
|
11
11
|
)
|
12
12
|
end
|
13
13
|
|
data/lib/lapine/version.rb
CHANGED
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'lapine/consumer/config'
|
3
|
+
|
4
|
+
RSpec.describe Lapine::Consumer::Config do
|
5
|
+
let(:argv) { %w(-c /path/to/config.yml) }
|
6
|
+
|
7
|
+
subject(:config) { Lapine::Consumer::Config.new }
|
8
|
+
let(:config_from_file) { {} }
|
9
|
+
|
10
|
+
before do
|
11
|
+
config.load argv
|
12
|
+
allow(YAML).to receive(:load_file).with('/path/to/config.yml').and_return(config_from_file)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#load' do
|
16
|
+
it 'returns self' do
|
17
|
+
expect(config.load(argv)).to eq(config)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#connection_properties' do
|
22
|
+
before { config.load(argv) }
|
23
|
+
|
24
|
+
let(:connection_properties) { config.connection_properties }
|
25
|
+
|
26
|
+
describe 'host' do
|
27
|
+
it 'defaults to 127.0.0.1' do
|
28
|
+
expect(connection_properties[:host]).to eq('127.0.0.1')
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with connection info in file' do
|
32
|
+
let(:config_from_file) { { 'connection' => { 'host' => '1.1.1.1' } } }
|
33
|
+
|
34
|
+
it 'uses the config file info' do
|
35
|
+
expect(connection_properties[:host]).to eq('1.1.1.1')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'with command line arg' do
|
40
|
+
let(:argv) { %w(--host 2.2.2.2 -c /path/to/config.yml) }
|
41
|
+
let(:config_from_file) { { 'connection' => { 'host' => '1.1.1.1' } } }
|
42
|
+
|
43
|
+
it 'prefers the cli' do
|
44
|
+
expect(connection_properties[:host]).to eq('2.2.2.2')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'port' do
|
50
|
+
it 'defaults to 5672' do
|
51
|
+
expect(connection_properties[:port]).to eq(5672)
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'with connection info in file' do
|
55
|
+
let(:config_from_file) { { 'connection' => { 'port' => 5673 } } }
|
56
|
+
|
57
|
+
it 'uses the config file info' do
|
58
|
+
expect(connection_properties[:port]).to eq(5673)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'with command line arg' do
|
63
|
+
let(:argv) { %w(--port 5674 -c /path/to/config.yml) }
|
64
|
+
let(:config_from_file) { { 'connection' => { 'port' => 5673 } } }
|
65
|
+
|
66
|
+
it 'prefers the cli' do
|
67
|
+
expect(connection_properties[:port]).to eq(5674)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe 'ssl' do
|
73
|
+
it 'defaults to false' do
|
74
|
+
expect(connection_properties[:ssl]).to be(false)
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'with connection info in file' do
|
78
|
+
let(:config_from_file) { { 'connection' => { 'ssl' => true } } }
|
79
|
+
|
80
|
+
it 'uses the config file info' do
|
81
|
+
expect(connection_properties[:ssl]).to be(true)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'with command line arg' do
|
86
|
+
let(:argv) { %w(--ssl -c /path/to/config.yml) }
|
87
|
+
let(:config_from_file) { { 'connection' => { 'ssl' => false } } }
|
88
|
+
|
89
|
+
it 'prefers the cli' do
|
90
|
+
expect(connection_properties[:ssl]).to be(true)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe 'vhost' do
|
96
|
+
it 'defaults to /' do
|
97
|
+
expect(connection_properties[:vhost]).to eq('/')
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'with connection info in file' do
|
101
|
+
let(:config_from_file) { { 'connection' => { 'vhost' => '/blah' } } }
|
102
|
+
|
103
|
+
it 'uses the config file info' do
|
104
|
+
expect(connection_properties[:vhost]).to eq('/blah')
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'with command line arg' do
|
109
|
+
let(:argv) { %w(--vhost /argh -c /path/to/config.yml) }
|
110
|
+
let(:config_from_file) { { 'connection' => { 'vhost' => '/blah' } } }
|
111
|
+
|
112
|
+
it 'prefers the cli' do
|
113
|
+
expect(connection_properties[:vhost]).to eq('/argh')
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe 'username' do
|
119
|
+
it 'defaults to guest' do
|
120
|
+
expect(connection_properties[:username]).to eq('guest')
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'with connection info in file' do
|
124
|
+
let(:config_from_file) { { 'connection' => { 'username' => 'Hrairoo' } } }
|
125
|
+
|
126
|
+
it 'uses the config file info' do
|
127
|
+
expect(connection_properties[:username]).to eq('Hrairoo')
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'with command line arg' do
|
132
|
+
let(:argv) { %w(--username Thlayli -c /path/to/config.yml) }
|
133
|
+
let(:config_from_file) { { 'connection' => { 'username' => 'Hrairoo' } } }
|
134
|
+
|
135
|
+
it 'prefers the cli' do
|
136
|
+
expect(connection_properties[:username]).to eq('Thlayli')
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe 'password' do
|
142
|
+
it 'defaults to guest' do
|
143
|
+
expect(connection_properties[:password]).to eq('guest')
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'with connection info in file' do
|
147
|
+
let(:config_from_file) { { 'connection' => { 'password' => 'flayrah' } } }
|
148
|
+
|
149
|
+
it 'uses the config file info' do
|
150
|
+
expect(connection_properties[:password]).to eq('flayrah')
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'with command line arg' do
|
155
|
+
let(:argv) { %w(--password pfeffa -c /path/to/config.yml) }
|
156
|
+
let(:config_from_file) { { 'connection' => { 'password' => 'flayrah' } } }
|
157
|
+
|
158
|
+
it 'prefers the cli' do
|
159
|
+
expect(connection_properties[:password]).to eq('pfeffa')
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'lapine/consumer/connection'
|
3
|
+
|
4
|
+
RSpec.describe Lapine::Consumer::Connection do
|
5
|
+
|
6
|
+
describe "initialize" do
|
7
|
+
let(:properties) { {host: '127.0.0.1', port: 5672, ssl: false, vhost: '/', username: 'guest', password: 'guest'} }
|
8
|
+
let(:connection) { double('AMQP::Session') }
|
9
|
+
let(:channel) { double('AMQP::Channel') }
|
10
|
+
let(:config) { double('config', connection_properties: properties) }
|
11
|
+
|
12
|
+
before do
|
13
|
+
expect(AMQP).to receive(:connect).with(properties) { connection }
|
14
|
+
expect(AMQP::Channel).to receive(:new).with(connection) { channel }
|
15
|
+
end
|
16
|
+
|
17
|
+
it "Builds amqp objects" do
|
18
|
+
expect(AMQP::Exchange).to receive(:new).with(channel, :topic, 'thing.topic', durable: true)
|
19
|
+
described_class.new(config, 'thing.topic')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'lapine/consumer/dispatcher'
|
3
|
+
|
4
|
+
RSpec.describe Lapine::Consumer::Dispatcher do
|
5
|
+
|
6
|
+
subject(:dispatcher) { Lapine::Consumer::Dispatcher.new(delegate, json, metadata, logger) }
|
7
|
+
let(:logger) { double('logger') }
|
8
|
+
let(:hash) { {'foo' => 'bar'} }
|
9
|
+
let(:json) { Oj.dump(hash) }
|
10
|
+
let(:metadata) { double("metadata") }
|
11
|
+
let(:delegate) { double("delegate", name: "ClassName") }
|
12
|
+
|
13
|
+
let(:caught_errors) { [] }
|
14
|
+
|
15
|
+
before do
|
16
|
+
Lapine::Consumer::Dispatcher.error_handler = ->(error, data) {
|
17
|
+
caught_errors << [error, data]
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#delegation" do
|
22
|
+
context "success cases" do
|
23
|
+
before do
|
24
|
+
expect(logger).to receive(:info).once.with(/Processing(.*)ClassName/)
|
25
|
+
end
|
26
|
+
|
27
|
+
context ".handle_lapine_payload method" do
|
28
|
+
it "receives handle_lapine_payload" do
|
29
|
+
expect(delegate).to receive(:respond_to?).with(:handle_lapine_payload).and_return(true)
|
30
|
+
expect(delegate).to receive(:handle_lapine_payload).once
|
31
|
+
dispatcher.dispatch
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context ".perform_async method" do
|
36
|
+
it "receives perform_async" do
|
37
|
+
expect(delegate).to receive(:respond_to?).with(:handle_lapine_payload).and_return(false)
|
38
|
+
expect(delegate).to receive(:respond_to?).with(:perform_async).and_return(true)
|
39
|
+
expect(delegate).to receive(:perform_async).once
|
40
|
+
dispatcher.dispatch
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'error cases' do
|
46
|
+
context 'with invalid json' do
|
47
|
+
let(:json) { 'oh boy I am not actually JSON' }
|
48
|
+
|
49
|
+
it 'notifies new relic with the raw payload' do
|
50
|
+
dispatcher.dispatch
|
51
|
+
expect(caught_errors).to include([an_instance_of(Oj::ParseError), json])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'with any other error' do
|
56
|
+
before { allow(dispatcher).to receive(:do_dispatch).and_raise(ArgumentError) }
|
57
|
+
|
58
|
+
it 'notifies new relic with the parsed json' do
|
59
|
+
dispatcher.dispatch
|
60
|
+
expect(caught_errors).to include([an_instance_of(ArgumentError), hash])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'lapine/consumer/runner'
|
3
|
+
require 'amqp'
|
4
|
+
require 'em-spec/rspec'
|
5
|
+
|
6
|
+
RSpec.describe Lapine::Consumer::Runner do
|
7
|
+
include EM::SpecHelper
|
8
|
+
|
9
|
+
class FakerHandler
|
10
|
+
def self.handle_lapine_payload(payload, metadata)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
subject(:runner) { Lapine::Consumer::Runner.new(argv) }
|
15
|
+
let(:argv) { [] }
|
16
|
+
let(:queues) do
|
17
|
+
[
|
18
|
+
{
|
19
|
+
'q' => 'testing.test',
|
20
|
+
'topic' => 'testing.topic',
|
21
|
+
'routing_key' => 'testing.update',
|
22
|
+
'handlers' =>
|
23
|
+
[
|
24
|
+
'FakerHandler'
|
25
|
+
]
|
26
|
+
}
|
27
|
+
]
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:config) { double('config',
|
31
|
+
logfile: '/dev/null',
|
32
|
+
yaml_config: 'fakefil',
|
33
|
+
connection_properties: connection_properties,
|
34
|
+
require: [],
|
35
|
+
queues: queues,
|
36
|
+
topics: ['testing.topic'],
|
37
|
+
debug?: true) }
|
38
|
+
let(:connection_properties) { {host: '127.0.0.1', port: 5672, ssl: false, vhost: '/', username: 'guest', password: 'guest'} }
|
39
|
+
let(:message) { Oj.dump({'pay' => 'load'}) }
|
40
|
+
|
41
|
+
describe '#run' do
|
42
|
+
before do
|
43
|
+
allow(runner).to receive(:config).and_return(config)
|
44
|
+
allow(runner).to receive(:topology).and_return(::Lapine::Consumer::Topology.new(config, runner.logger))
|
45
|
+
allow(runner).to receive(:handle_signals!)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'sends a message to handler' do
|
49
|
+
expect(FakerHandler).to receive(:handle_lapine_payload).twice
|
50
|
+
em do
|
51
|
+
subject.run
|
52
|
+
conn = Lapine::Consumer::Connection.new(config, 'testing.topic')
|
53
|
+
conn.exchange.publish(message, routing_key: 'testing.update')
|
54
|
+
conn.exchange.publish(message, routing_key: 'testing.update')
|
55
|
+
EventMachine.add_timer(2.0) { done }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#config' do
|
61
|
+
it 'passes argv to a new config object' do
|
62
|
+
allow(Lapine::Consumer::Config).to receive(:new).and_return(config)
|
63
|
+
expect(config).to receive(:load).with(argv).and_return(config)
|
64
|
+
expect(runner.config).to eq(config)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#handle_signals!' do
|
69
|
+
it 'traps INT and TERM signals' do
|
70
|
+
expect(Signal).to receive(:trap).with('INT')
|
71
|
+
expect(Signal).to receive(:trap).with('TERM')
|
72
|
+
subject.handle_signals!
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'lapine/consumer/topology'
|
3
|
+
|
4
|
+
RSpec.describe Lapine::Consumer::Topology do
|
5
|
+
module MessageBusTest
|
6
|
+
class Clazz
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:topics) {
|
11
|
+
[
|
12
|
+
"a.topic",
|
13
|
+
"b.topic"
|
14
|
+
]
|
15
|
+
}
|
16
|
+
let(:queues) {
|
17
|
+
[{
|
18
|
+
"q" => "store.buyable",
|
19
|
+
"topic" => "a.topic",
|
20
|
+
"routing_key" =>
|
21
|
+
"store.buyable.update",
|
22
|
+
"handlers" => ["MessageBusTest::Clazz"]
|
23
|
+
}]
|
24
|
+
}
|
25
|
+
let(:connection_properties) {
|
26
|
+
{}
|
27
|
+
}
|
28
|
+
let(:config) do
|
29
|
+
double('config',
|
30
|
+
topics: topics,
|
31
|
+
queues: queues,
|
32
|
+
connection_properties: connection_properties,
|
33
|
+
debug?: debug)
|
34
|
+
end
|
35
|
+
|
36
|
+
subject(:topology) { Lapine::Consumer::Topology.new(config, logger) }
|
37
|
+
let(:debug) { false }
|
38
|
+
let(:logger) { nil }
|
39
|
+
|
40
|
+
describe "#each_topic" do
|
41
|
+
it "yields correct dount" do
|
42
|
+
expect { |b| topology.each_topic(&b) }.to yield_control.twice
|
43
|
+
end
|
44
|
+
|
45
|
+
it "yields all topics in order" do
|
46
|
+
expect { |b| topology.each_topic(&b) }.to yield_successive_args("a.topic", "b.topic")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#each_binding" do
|
51
|
+
let(:conn) { double('connection') }
|
52
|
+
|
53
|
+
before do
|
54
|
+
allow(Lapine::Consumer::Connection).to receive(:new) { conn }
|
55
|
+
end
|
56
|
+
|
57
|
+
it "yields correct count" do
|
58
|
+
expect { |b| topology.each_binding(&b) }.to yield_control.once
|
59
|
+
end
|
60
|
+
|
61
|
+
it "yields expected arguments" do
|
62
|
+
expect { |b|
|
63
|
+
topology.each_binding(&b)
|
64
|
+
}.to yield_with_args("store.buyable",
|
65
|
+
conn,
|
66
|
+
"store.buyable.update",
|
67
|
+
[MessageBusTest::Clazz])
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'with a logger and debug mode' do
|
71
|
+
let(:debug) { true }
|
72
|
+
let(:logger) { double('logger', info: true) }
|
73
|
+
|
74
|
+
it 'logs each connection' do
|
75
|
+
topology.each_binding {}
|
76
|
+
expect(logger).to have_received(:info).with("Connecting to RabbiMQ: topic: a.topic, #{config.connection_properties}")
|
77
|
+
expect(logger).to have_received(:info).with("Connecting to RabbiMQ: topic: b.topic, #{config.connection_properties}")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'lapine/test/rspec_helper'
|
3
|
+
|
4
|
+
RSpec.describe Lapine::Test::Exchange, with_rspec_helper: true do
|
5
|
+
class Publisher
|
6
|
+
include Lapine::Publisher
|
7
|
+
|
8
|
+
exchange 'my.topic'
|
9
|
+
|
10
|
+
def to_hash
|
11
|
+
{
|
12
|
+
omg: 'lol'
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:exchange) { Lapine.find_exchange('my.topic') }
|
18
|
+
let(:queue) { exchange.channel.queue.bind(exchange) }
|
19
|
+
|
20
|
+
before do
|
21
|
+
Lapine.add_connection 'conn', {}
|
22
|
+
Lapine.add_exchange 'my.topic', connection: 'conn'
|
23
|
+
queue
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'publish' do
|
27
|
+
it 'changes the queue message count' do
|
28
|
+
expect {
|
29
|
+
Publisher.new.publish
|
30
|
+
}.to change {
|
31
|
+
queue.message_count
|
32
|
+
}.to(1)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'saves message for later introspection' do
|
36
|
+
Publisher.new.publish('my.things')
|
37
|
+
message = ['{"omg":"lol"}', {routing_key: 'my.things'}]
|
38
|
+
expect(queue.messages).to include(message)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'lapine/test/rspec_helper'
|
2
|
+
|
3
|
+
RSpec.configure do |config|
|
4
|
+
config.include Lapine::Test::RSpecHelper, with_rspec_helper: true
|
5
|
+
|
6
|
+
config.before :each, :with_rspec_helper do |example|
|
7
|
+
Lapine::Test::RSpecHelper.setup(example)
|
8
|
+
end
|
9
|
+
|
10
|
+
config.after :each, :with_rspec_helper do
|
11
|
+
Lapine::Test::RSpecHelper.teardown
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lapine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Saxby
|
@@ -9,8 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-12-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: amqp
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
14
28
|
- !ruby/object:Gem::Dependency
|
15
29
|
name: bunny
|
16
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -25,6 +39,20 @@ dependencies:
|
|
25
39
|
- - ">="
|
26
40
|
- !ruby/object:Gem::Version
|
27
41
|
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: mixlib-cli
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :runtime
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
28
56
|
- !ruby/object:Gem::Dependency
|
29
57
|
name: oj
|
30
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -39,6 +67,20 @@ dependencies:
|
|
39
67
|
- - ">="
|
40
68
|
- !ruby/object:Gem::Version
|
41
69
|
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: ruby-usdt
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 0.2.2
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 0.2.2
|
42
84
|
- !ruby/object:Gem::Dependency
|
43
85
|
name: bundler
|
44
86
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,10 +137,25 @@ dependencies:
|
|
95
137
|
- - "~>"
|
96
138
|
- !ruby/object:Gem::Version
|
97
139
|
version: 3.1.0
|
140
|
+
- !ruby/object:Gem::Dependency
|
141
|
+
name: em-spec
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
type: :development
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ">="
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
98
154
|
description: Talk to rabbits
|
99
155
|
email:
|
100
156
|
- dev@wanelo.com
|
101
|
-
executables:
|
157
|
+
executables:
|
158
|
+
- lapine
|
102
159
|
extensions: []
|
103
160
|
extra_rdoc_files: []
|
104
161
|
files:
|
@@ -109,17 +166,37 @@ files:
|
|
109
166
|
- LICENSE.txt
|
110
167
|
- README.md
|
111
168
|
- Rakefile
|
169
|
+
- bin/lapine
|
170
|
+
- example/consumer_config.yml
|
171
|
+
- example/consumer_handler.rb
|
172
|
+
- example/producer.rb
|
112
173
|
- lapine.gemspec
|
113
174
|
- lib/lapine.rb
|
175
|
+
- lib/lapine/cli.rb
|
114
176
|
- lib/lapine/configuration.rb
|
177
|
+
- lib/lapine/consumer.rb
|
178
|
+
- lib/lapine/consumer/config.rb
|
179
|
+
- lib/lapine/consumer/connection.rb
|
180
|
+
- lib/lapine/consumer/dispatcher.rb
|
181
|
+
- lib/lapine/consumer/environment.rb
|
182
|
+
- lib/lapine/consumer/runner.rb
|
183
|
+
- lib/lapine/consumer/topology.rb
|
184
|
+
- lib/lapine/dtrace.rb
|
115
185
|
- lib/lapine/exchange.rb
|
116
186
|
- lib/lapine/publisher.rb
|
117
187
|
- lib/lapine/test/exchange.rb
|
118
188
|
- lib/lapine/test/rspec_helper.rb
|
119
189
|
- lib/lapine/version.rb
|
190
|
+
- spec/lib/lapine/consumer/config_spec.rb
|
191
|
+
- spec/lib/lapine/consumer/connection_spec.rb
|
192
|
+
- spec/lib/lapine/consumer/dispatcher_spec.rb
|
193
|
+
- spec/lib/lapine/consumer/runner_spec.rb
|
194
|
+
- spec/lib/lapine/consumer/topology_spec.rb
|
120
195
|
- spec/lib/lapine/publisher_spec.rb
|
196
|
+
- spec/lib/lapine/test/exchange_spec.rb
|
121
197
|
- spec/lib/lapine_spec.rb
|
122
198
|
- spec/spec_helper.rb
|
199
|
+
- spec/support/rspec_test_helper.rb
|
123
200
|
homepage: https://github.com/wanelo/lapine
|
124
201
|
licenses:
|
125
202
|
- MIT
|
@@ -140,12 +217,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
217
|
version: '0'
|
141
218
|
requirements: []
|
142
219
|
rubyforge_project:
|
143
|
-
rubygems_version: 2.
|
220
|
+
rubygems_version: 2.2.2
|
144
221
|
signing_key:
|
145
222
|
specification_version: 4
|
146
223
|
summary: Talk to rabbits
|
147
224
|
test_files:
|
225
|
+
- spec/lib/lapine/consumer/config_spec.rb
|
226
|
+
- spec/lib/lapine/consumer/connection_spec.rb
|
227
|
+
- spec/lib/lapine/consumer/dispatcher_spec.rb
|
228
|
+
- spec/lib/lapine/consumer/runner_spec.rb
|
229
|
+
- spec/lib/lapine/consumer/topology_spec.rb
|
148
230
|
- spec/lib/lapine/publisher_spec.rb
|
231
|
+
- spec/lib/lapine/test/exchange_spec.rb
|
149
232
|
- spec/lib/lapine_spec.rb
|
150
233
|
- spec/spec_helper.rb
|
234
|
+
- spec/support/rspec_test_helper.rb
|
151
235
|
has_rdoc:
|