tochtli 0.5.0 → 0.5.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 56acd327a8d04ef8de6ca2ab8a2b677e27e276e4
4
- data.tar.gz: c0f076e6906b0ef7a401585be0946ec1b8b0d1f3
3
+ metadata.gz: d7a4aeafb78f7399f7f0f7444bcae42b8a025fa6
4
+ data.tar.gz: 5d387cebbd67b3323ee3ef60e7f2eac1d6cc7087
5
5
  SHA512:
6
- metadata.gz: 4653fc71fcd32d2a9a21bb9929d9994564b2b3b5e1a680e04faf414705ad7bf9b9bcc8e12e274d653183f2fec2780adb3d872a93c004123c611820479d95cd97
7
- data.tar.gz: 4e799d6d4888f1182772ca63dfdcd534fa2255f50926a98bb2a3df8ba1fd0b5b8b897361227e785dfdb5287269400ecac5cae7be9925f6cd2babf2350889fdb9
6
+ metadata.gz: 556377482683580c625cbf00a34f100bbf03fd8a0c3338b7f6a10efba216283d27be4389dca208168a47923ea08dd72f68710bddafd2271c60c32a3f83100bd0
7
+ data.tar.gz: c7b5e7dee6939180abe8981e110c87d02e62fefa223971f32aa46bd27ce72ddb7fa605bf944ca7107f1f3cf52ba9f8638195ec687327461243768a0302c4f572
data/History.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.5.1 / 2015-08-19
2
+
3
+ * [Integration Tests] Fix controller manager restart - some controllers are fixed to the test connection after functional tests
4
+
1
5
  ## 0.5.0 / 2015-08-19
2
6
 
3
7
  * Usage examples
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  [![Build Status](https://travis-ci.org/PuzzleFlow/tochtli.svg?branch=master)](https://travis-ci.org/PuzzleFlow/tochtli)
2
+ [![Gem Version](https://badge.fury.io/rb/tochtli.svg)](http://badge.fury.io/rb/tochtli)
2
3
 
3
4
  # What's Tochtli?
4
5
 
@@ -43,4 +44,4 @@ Read more about Tochtli and go through the tutorial on [Tochtli homepage](http:/
43
44
 
44
45
  # License
45
46
 
46
- Released under the MIT license.
47
+ Released under the MIT license.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.5.1
@@ -3,13 +3,13 @@ require_relative 'common'
3
3
  Tochtli.logger.progname = 'CLIENT'
4
4
 
5
5
  class ScreenerClient < Tochtli::BaseClient
6
- def create_screen(url, file_name)
7
- handler = SyncMessageHandler.new
8
- message = CreateScreenMessage.new(url: url, file: file_name)
9
- rabbit_client.publish message, handler: handler
10
- handler.wait!(20)
11
- puts "Done in #{handler.reply.time} seconds"
12
- end
6
+ def create_screen(url, file_name)
7
+ handler = SyncMessageHandler.new
8
+ message = CreateScreenMessage.new(url: url, file: file_name)
9
+ rabbit_client.publish message, handler: handler
10
+ handler.wait!(20)
11
+ puts "Done in #{handler.reply.time} seconds"
12
+ end
13
13
  end
14
14
 
15
15
  ScreenerClient.new.create_screen(ARGV[0], ARGV[1])
@@ -4,12 +4,12 @@ Bundler.require
4
4
  Tochtli.logger = Logger.new('tochtli.log')
5
5
 
6
6
  class CreateScreenMessage < Tochtli::Message
7
- route_to 'screener.create'
7
+ route_to 'screener.create'
8
8
 
9
- attribute :url, String
10
- attribute :file, String
9
+ attribute :url, String
10
+ attribute :file, String
11
11
  end
12
12
 
13
13
  class CreateScreenReplyMessage < Tochtli::Message
14
- attribute :time, Float
14
+ attribute :time, Float
15
15
  end
@@ -3,17 +3,17 @@ require_relative 'common'
3
3
  Tochtli.logger.progname = 'SERVER'
4
4
 
5
5
  class ScreenerController < Tochtli::BaseController
6
- bind 'screener.*'
6
+ bind 'screener.*'
7
7
 
8
- on CreateScreenMessage, :create
8
+ on CreateScreenMessage, :create
9
9
 
10
- def create
11
- start_time = Time.now
12
- f = Screencap::Fetcher.new(message.url)
13
- f.fetch output: File.join(__dir__, 'images', message.file)
14
- total_time = Time.now - start_time
15
- reply CreateScreenReplyMessage.new(time: total_time)
16
- end
10
+ def create
11
+ start_time = Time.now
12
+ f = Screencap::Fetcher.new(message.url)
13
+ f.fetch output: File.join(__dir__, 'images', message.file)
14
+ total_time = Time.now - start_time
15
+ reply CreateScreenReplyMessage.new(time: total_time)
16
+ end
17
17
  end
18
18
 
19
19
  Tochtli::ControllerManager.setup
@@ -9,9 +9,9 @@ module LogAnalyzer
9
9
  end
10
10
 
11
11
  def react_on_events(client_id, severities, handler=nil, &block)
12
- handler = block unless handler
12
+ handler = block unless handler
13
13
  severities = Array(severities)
14
- routing_keys = severities.map {|severity| "log.events.#{severity}" }
14
+ routing_keys = severities.map {|severity| "log.events.#{severity}" }
15
15
  Tochtli::ControllerManager.start EventsController,
16
16
  queue_name: "log_analyzer/events/#{client_id}", # custom queue name
17
17
  routing_keys: routing_keys, # make custom binding (only selected severities)
@@ -19,7 +19,7 @@ module LogAnalyzer
19
19
  end
20
20
 
21
21
  def monitor_status(monitor=nil, &block)
22
- monitor = block unless monitor
22
+ monitor = block unless monitor
23
23
  Tochtli::ControllerManager.start MonitorController, env: { monitor: monitor }
24
24
  end
25
25
  end
@@ -27,18 +27,18 @@ module LogAnalyzer
27
27
  protected
28
28
 
29
29
  class EventsController < Tochtli::BaseController
30
- on EventOccurred, :handle, routing_key: 'log.events.*'
30
+ on EventOccurred, :handle, routing_key: 'log.events.*'
31
31
 
32
32
  def handle
33
- handler.call(message.severity, message.timestamp, message.message)
33
+ handler.call(message.severity, message.timestamp, message.message)
34
34
  end
35
35
 
36
- protected
36
+ protected
37
37
 
38
- def handler
39
- raise "Internal Error: handler not set for EventsController" unless env.has_key?(:handler)
40
- env[:handler]
41
- end
38
+ def handler
39
+ raise "Internal Error: handler not set for EventsController" unless env.has_key?(:handler)
40
+ env[:handler]
41
+ end
42
42
  end
43
43
 
44
44
  class MonitorController < Tochtli::BaseController
@@ -50,14 +50,14 @@ module LogAnalyzer
50
50
  self.queue_auto_delete = true
51
51
 
52
52
  on CurrentStatus do
53
- monitor.call(message.to_hash)
53
+ monitor.call(message.to_hash)
54
54
  end
55
55
 
56
56
  protected
57
57
 
58
58
  def monitor
59
- raise "Internal Error: monitor not set for MonitorController" unless env.has_key?(:monitor)
60
- env[:monitor]
59
+ raise "Internal Error: monitor not set for MonitorController" unless env.has_key?(:monitor)
60
+ env[:monitor]
61
61
  end
62
62
  end
63
63
  end
@@ -66,30 +66,30 @@ client = LogAnalyzer::Client.new
66
66
  command = ARGV[0]
67
67
 
68
68
  def hold
69
- puts 'Press Ctrl-C to stop...'
70
- sleep
69
+ puts 'Press Ctrl-C to stop...'
70
+ sleep
71
71
  end
72
72
 
73
73
 
74
74
  case command
75
- when 's'
76
- client.send_new_log ARGV[1]
77
- when 'm'
78
- client.monitor_status {|status| p status }
79
- hold
80
- when 'c'
81
- client.react_on_events ARGV[1], [:fatal, :error], lambda {|severity, timestamp, message|
82
- puts "[#{timestamp}] Got #{severity}: #{message}"
83
- }
84
- hold
85
- else
86
- puts "Unknown command: #{command.inspect}"
87
- puts
88
- puts "Usage: bundle exec ruby client [command] [params]"
89
- puts
90
- puts "Commands:"
91
- puts " s [path] - send log from file to server"
92
- puts " m - start status monitor"
93
- puts " c [client ID] - catch fatal and error events"
75
+ when 's'
76
+ client.send_new_log ARGV[1]
77
+ when 'm'
78
+ client.monitor_status {|status| p status }
79
+ hold
80
+ when 'c'
81
+ client.react_on_events ARGV[1], [:fatal, :error], lambda {|severity, timestamp, message|
82
+ puts "[#{timestamp}] Got #{severity}: #{message}"
83
+ }
84
+ hold
85
+ else
86
+ puts "Unknown command: #{command.inspect}"
87
+ puts
88
+ puts "Usage: bundle exec ruby client [command] [params]"
89
+ puts
90
+ puts "Commands:"
91
+ puts " s [path] - send log from file to server"
92
+ puts " m - start status monitor"
93
+ puts " c [client ID] - catch fatal and error events"
94
94
  end
95
95
 
@@ -14,8 +14,8 @@ module LogAnalyzer
14
14
  cattr_accessor :monitor
15
15
 
16
16
  after_setup do |rabbit_connection|
17
- self.monitor = StatusMonitor.new(rabbit_connection)
18
- self.monitor.start
17
+ self.monitor = StatusMonitor.new(rabbit_connection)
18
+ self.monitor.start
19
19
  end
20
20
 
21
21
  def create
@@ -68,11 +68,11 @@ module LogAnalyzer
68
68
  end
69
69
 
70
70
  class EventNotifier < Tochtli::BaseClient
71
- SIGNIFICANT_SEVERITIES = [:fatal, :error, :warn]
71
+ SIGNIFICANT_SEVERITIES = [:fatal, :error, :warn]
72
72
 
73
- def self.significant?(severity)
74
- SIGNIFICANT_SEVERITIES.include?(severity)
75
- end
73
+ def self.significant?(severity)
74
+ SIGNIFICANT_SEVERITIES.include?(severity)
75
+ end
76
76
 
77
77
  def notify(event)
78
78
  publish EventOccurred.new(event), mandatory: false
@@ -105,18 +105,18 @@ module LogAnalyzer
105
105
  protected
106
106
 
107
107
  def reset_status
108
- synchronize do
109
- status = @status
110
- @status = Hash.new(0)
111
- status
112
- end
108
+ synchronize do
109
+ status = @status
110
+ @status = Hash.new(0)
111
+ status
112
+ end
113
113
  end
114
114
 
115
115
  def monitor
116
116
  loop do
117
117
  current_status = reset_status
118
118
  current_status[:timestamp] = Time.now
119
- @notifier.update_status current_status
119
+ @notifier.update_status current_status
120
120
  sleep 10
121
121
  end
122
122
  end
@@ -69,9 +69,9 @@ module Tochtli
69
69
  @logger = Logger.new(File.join(Rails.root, 'log/service.log'))
70
70
  @logger.level = Rails.env.production? ? Logger::WARN : Logger::DEBUG
71
71
  else
72
- @logger = Logger.new(STDERR)
73
- @logger.level = Logger::WARN
74
- end
72
+ @logger = Logger.new(STDERR)
73
+ @logger.level = Logger::WARN
74
+ end
75
75
  end
76
76
  @logger
77
77
  end
@@ -83,9 +83,9 @@ module Tochtli
83
83
  end
84
84
 
85
85
  def start(queue_name=nil, routing_keys=nil, initial_env={})
86
- run_hook :before_start, queue_name, initial_env
86
+ run_hook :before_start, queue_name, initial_env
87
87
  self.dispatcher.start(queue_name || self.queue_name, routing_keys || self.routing_keys, initial_env)
88
- run_hook :after_start, queue_name, initial_env
88
+ run_hook :after_start, queue_name, initial_env
89
89
  end
90
90
 
91
91
  def set_up?
@@ -97,24 +97,30 @@ module Tochtli
97
97
  end
98
98
 
99
99
  def stop(options={})
100
- if started?
101
- queues = self.dispatcher.queues
102
- run_hook :before_stop, queues
100
+ if started?
101
+ queues = self.dispatcher.queues
102
+ run_hook :before_stop, queues
103
+ end
104
+
105
+ if self.dispatcher
106
+ self.dispatcher.shutdown(options)
107
+ self.dispatcher = nil
103
108
 
104
- self.dispatcher.shutdown(options)
105
- self.dispatcher = nil
109
+ run_hook :after_stop, queues
106
110
 
107
- run_hook :after_stop, queues
108
- end
111
+ true
112
+ else
113
+ false
114
+ end
109
115
  end
110
116
 
111
117
  def restart(options={})
112
- if started?
113
- queues = self.dispatcher.queues
114
- run_hook :before_restart, queues
115
- self.dispatcher.restart options
116
- run_hook :after_restart, queues
117
- end
118
+ if started?
119
+ queues = self.dispatcher.queues
120
+ run_hook :before_restart, queues
121
+ self.dispatcher.restart options
122
+ run_hook :after_restart, queues
123
+ end
118
124
  end
119
125
 
120
126
  def find_message_route(routing_key)
@@ -181,13 +187,13 @@ module Tochtli
181
187
  end
182
188
 
183
189
  def rabbit_connection
184
- self.class.dispatcher.rabbit_connection if self.class.set_up?
190
+ self.class.dispatcher.rabbit_connection if self.class.set_up?
185
191
  end
186
192
 
187
193
  class MessageRoute < Struct.new(:message_class, :action, :routing_key, :pattern)
188
- def initialize(message_class, action, routing_key)
189
- super message_class, action, routing_key, KeyPattern.new(routing_key)
190
- end
194
+ def initialize(message_class, action, routing_key)
195
+ super message_class, action, routing_key, KeyPattern.new(routing_key)
196
+ end
191
197
  end
192
198
 
193
199
  class Dispatcher
@@ -209,13 +215,13 @@ module Tochtli
209
215
  end
210
216
 
211
217
  def restart(options={})
212
- queues = @queues.dup
218
+ queues = @queues.dup
213
219
 
214
- shutdown options
220
+ shutdown options
215
221
 
216
- queues.each do |queue_name, queue_opts|
217
- start queue_name, queue_opts[:initial_env]
218
- end
222
+ queues.each do |queue_name, queue_opts|
223
+ start queue_name, queue_opts[:initial_env]
224
+ end
219
225
  end
220
226
 
221
227
  def process_message(delivery_info, properties, payload, initial_env)
@@ -266,15 +272,15 @@ module Tochtli
266
272
  rescue Bunny::ConnectionClosedError
267
273
  # ignore closed connection error
268
274
  ensure
269
- @queues = {}
275
+ @queues = {}
270
276
  end
271
277
 
272
278
  def started?(queue_name=nil)
273
- if queue_name
274
- @queues.has_key?(queue_name)
275
- else
276
- !@queues.empty?
277
- end
279
+ if queue_name
280
+ @queues.has_key?(queue_name)
281
+ else
282
+ !@queues.empty?
283
+ end
278
284
  end
279
285
 
280
286
  def queues
@@ -326,35 +332,35 @@ module Tochtli
326
332
  end
327
333
 
328
334
  class KeyPattern
329
- ASTERIX_EXP = '[a-zA-Z0-9]+'
330
- HASH_EXP = '[a-zA-Z0-9\.]*'
331
-
332
- def initialize(pattern)
333
- @str = pattern
334
- @simple = !pattern.include?('*') && !pattern.include?('#')
335
- if @simple
336
- @pattern = pattern
337
- else
338
- @pattern = Regexp.new('^' + pattern.gsub('.', '\\.').
339
- gsub('*', ASTERIX_EXP).gsub(/(\\\.)?#(\\\.)?/, HASH_EXP) + '$')
340
- end
341
- end
342
-
343
- def =~(key)
344
- if @simple
345
- @pattern == key
346
- else
347
- @pattern =~ key
348
- end
349
- end
350
-
351
- def !~(key)
352
- !(self =~ key)
353
- end
354
-
355
- def to_s
356
- @str
357
- end
358
- end
335
+ ASTERIX_EXP = '[a-zA-Z0-9]+'
336
+ HASH_EXP = '[a-zA-Z0-9\.]*'
337
+
338
+ def initialize(pattern)
339
+ @str = pattern
340
+ @simple = !pattern.include?('*') && !pattern.include?('#')
341
+ if @simple
342
+ @pattern = pattern
343
+ else
344
+ @pattern = Regexp.new('^' + pattern.gsub('.', '\\.').
345
+ gsub('*', ASTERIX_EXP).gsub(/(\\\.)?#(\\\.)?/, HASH_EXP) + '$')
346
+ end
347
+ end
348
+
349
+ def =~(key)
350
+ if @simple
351
+ @pattern == key
352
+ else
353
+ @pattern =~ key
354
+ end
355
+ end
356
+
357
+ def !~(key)
358
+ !(self =~ key)
359
+ end
360
+
361
+ def to_s
362
+ @str
363
+ end
364
+ end
359
365
  end
360
366
  end
@@ -26,13 +26,13 @@ module Tochtli
26
26
  end
27
27
 
28
28
  def start(*controllers)
29
- options = controllers.extract_options!
30
- setup_options = options.except!(:logger, :cache, :connection)
31
- queue_name = options.delete(:queue_name)
32
- routing_keys = options.delete(:routing_keys)
33
- initial_env = options.delete(:env) || {}
29
+ options = controllers.extract_options!
30
+ setup_options = options.except!(:logger, :cache, :connection)
31
+ queue_name = options.delete(:queue_name)
32
+ routing_keys = options.delete(:routing_keys)
33
+ initial_env = options.delete(:env) || {}
34
34
 
35
- setup(setup_options) unless set_up?
35
+ setup(setup_options) unless set_up?
36
36
 
37
37
  if controllers.empty? || controllers.include?(:all)
38
38
  controllers = @controller_classes
@@ -41,34 +41,33 @@ module Tochtli
41
41
  controllers.each do |controller_class|
42
42
  raise ArgumentError, "Controller expected, got: #{controller_class.inspect}" unless controller_class.is_a?(Class) && controller_class < Tochtli::BaseController
43
43
  unless controller_class.started?(queue_name)
44
- @logger.info "Starting #{controller_class}..." if @logger
45
44
  controller_class.setup(@rabbit_connection, @cache, @logger) unless controller_class.set_up?
46
45
  controller_class.start queue_name, routing_keys, initial_env
46
+ @logger.info "[#{Time.now} AMQP] Started #{controller_class}" if @logger
47
47
  end
48
48
  end
49
49
  end
50
50
 
51
51
  def stop
52
52
  @controller_classes.each do |controller_class|
53
- if controller_class.started?
54
- @logger.info "Stopping #{controller_class}..." if @logger
55
- controller_class.stop
53
+ if controller_class.stop
54
+ @logger.info "[#{Time.now} AMQP] Stopped #{controller_class}" if @logger
56
55
  end
57
56
  end
58
57
  @rabbit_connection = nil
59
58
  end
60
59
 
61
60
  def restart(options={})
62
- options[:rabbit_connection] ||= @rabbit_connection
63
- options[:logger] ||= @logger
64
- options[:cache] ||= @cache
61
+ options[:rabbit_connection] ||= @rabbit_connection
62
+ options[:logger] ||= @logger
63
+ options[:cache] ||= @cache
65
64
 
66
- setup options
67
- restart_active_controllers
65
+ setup options
66
+ restart_active_controllers
68
67
  end
69
68
 
70
69
  def set_up?
71
- !@rabbit_connection.nil?
70
+ !@rabbit_connection.nil?
72
71
  end
73
72
 
74
73
  def running?
@@ -78,17 +77,17 @@ module Tochtli
78
77
  protected
79
78
 
80
79
  def restart_active_controllers
81
- @controller_classes.each do |controller_class|
82
- if controller_class.started?
83
- @logger.info "Restarting #{controller_class}..." if @logger
84
- controller_class.restart
85
- end
86
- end
80
+ @controller_classes.each do |controller_class|
81
+ if controller_class.started?
82
+ @logger.info "Restarting #{controller_class}..." if @logger
83
+ controller_class.restart
84
+ end
85
+ end
87
86
  end
88
87
 
89
88
  class << self
90
89
  def method_missing(method, *args)
91
- if instance.respond_to?(method)
90
+ if instance.respond_to?(method)
92
91
  instance.send(method, *args)
93
92
  else
94
93
  super
@@ -88,11 +88,11 @@ module Tochtli
88
88
  end
89
89
 
90
90
  def routing_key
91
- if self.class.routing_key.is_a?(Proc)
92
- self.instance_eval(&self.class.routing_key)
93
- else
91
+ if self.class.routing_key.is_a?(Proc)
92
+ self.instance_eval(&self.class.routing_key)
93
+ else
94
94
  self.class.routing_key
95
- end
95
+ end
96
96
  end
97
97
 
98
98
  def to_hash
@@ -16,6 +16,7 @@ module Tochtli
16
16
  @client = Tochtli::RabbitClient.new(nil, @logger)
17
17
  @connection = @client.rabbit_connection
18
18
  @controller_manager = Tochtli::ControllerManager.instance
19
+ @controller_manager.stop # restart all controllers - some can be started with functional tests on test connections
19
20
  @controller_manager.setup(connection: @connection, logger: @logger)
20
21
  @controller_manager.start(:all)
21
22
 
@@ -5,7 +5,7 @@ SEVERITIES = [:fatal] + [:error]*3 + [:warn]*5 + [:info]*12 + [:debug]*20
5
5
  log = Logger.new('sample.log')
6
6
 
7
7
  10000.times do
8
- severity = SEVERITIES.sample
9
- log.send severity, "Sample #{severity}"
8
+ severity = SEVERITIES.sample
9
+ log.send severity, "Sample #{severity}"
10
10
  end
11
11
 
@@ -11,7 +11,7 @@ class ControllerFunctionalTest < Minitest::Test
11
11
  end
12
12
 
13
13
  class CustomTopicMessage < Tochtli::Message
14
- route_to { "fn.test.#{key}.#{action}" }
14
+ route_to { "fn.test.#{key}.#{action}" }
15
15
 
16
16
  attribute :resource, String
17
17
 
@@ -40,7 +40,7 @@ class ControllerFunctionalTest < Minitest::Test
40
40
  off 'fn.test.off.accept'
41
41
 
42
42
  on CustomTopicMessage, routing_key: 'fn.test.*.reject' do
43
- reply TestCustomReply.new(:message => "#{message.resource} rejected")
43
+ reply TestCustomReply.new(:message => "#{message.resource} rejected")
44
44
  end
45
45
 
46
46
  def echo
@@ -56,20 +56,20 @@ class ControllerManagerTest < Minitest::Test
56
56
  Tochtli::ControllerManager.start(FirstController, connection: @connection, logger: @logger)
57
57
  end
58
58
 
59
- def test_multiple_queues
60
- Tochtli::ControllerManager.setup(connection: @connection, logger: @logger)
61
- Tochtli::ControllerManager.start(FirstController, queue_name: 'first_queue')
62
- Tochtli::ControllerManager.start(FirstController, queue_name: 'second_queue')
59
+ def test_multiple_queues
60
+ Tochtli::ControllerManager.setup(connection: @connection, logger: @logger)
61
+ Tochtli::ControllerManager.start(FirstController, queue_name: 'first_queue')
62
+ Tochtli::ControllerManager.start(FirstController, queue_name: 'second_queue')
63
63
 
64
- assert_equal ["first_queue", "second_queue"], FirstController.dispatcher.queues.map(&:name).sort
65
- end
64
+ assert_equal ["first_queue", "second_queue"], FirstController.dispatcher.queues.map(&:name).sort
65
+ end
66
66
 
67
- def test_restart_multiple_queues
68
- Tochtli::ControllerManager.setup(connection: @connection, logger: @logger)
69
- Tochtli::ControllerManager.start(FirstController, queue_name: 'first_queue')
70
- Tochtli::ControllerManager.start(FirstController, queue_name: 'second_queue')
71
- Tochtli::ControllerManager.restart
67
+ def test_restart_multiple_queues
68
+ Tochtli::ControllerManager.setup(connection: @connection, logger: @logger)
69
+ Tochtli::ControllerManager.start(FirstController, queue_name: 'first_queue')
70
+ Tochtli::ControllerManager.start(FirstController, queue_name: 'second_queue')
71
+ Tochtli::ControllerManager.restart
72
72
 
73
- assert_equal ["first_queue", "second_queue"], FirstController.dispatcher.queues.map(&:name).sort
74
- end
73
+ assert_equal ["first_queue", "second_queue"], FirstController.dispatcher.queues.map(&:name).sort
74
+ end
75
75
  end
@@ -2,99 +2,99 @@ require_relative 'test_helper'
2
2
  require 'benchmark'
3
3
 
4
4
  class MessageTest < Minitest::Test
5
- KeyPattern = Tochtli::BaseController::KeyPattern
5
+ KeyPattern = Tochtli::BaseController::KeyPattern
6
6
 
7
- def test_simple_pattern
8
- pattern = KeyPattern.new('a.b.c')
7
+ def test_simple_pattern
8
+ pattern = KeyPattern.new('a.b.c')
9
9
 
10
- assert_matches pattern, 'a.b.c'
11
- refute_matches pattern, 'a.b.c.d'
12
- refute_matches pattern, 'b.c.d'
13
- end
10
+ assert_matches pattern, 'a.b.c'
11
+ refute_matches pattern, 'a.b.c.d'
12
+ refute_matches pattern, 'b.c.d'
13
+ end
14
14
 
15
- def test_asterix_at_start
16
- pattern = KeyPattern.new('*.b.c')
15
+ def test_asterix_at_start
16
+ pattern = KeyPattern.new('*.b.c')
17
17
 
18
- assert_matches pattern, 'a.b.c'
19
- assert_matches pattern, 'b.b.c'
20
- refute_matches pattern, 'a.b.c.d'
21
- end
18
+ assert_matches pattern, 'a.b.c'
19
+ assert_matches pattern, 'b.b.c'
20
+ refute_matches pattern, 'a.b.c.d'
21
+ end
22
22
 
23
- def test_asterix_in_the_middle
24
- pattern = KeyPattern.new('a.*.b.c')
23
+ def test_asterix_in_the_middle
24
+ pattern = KeyPattern.new('a.*.b.c')
25
25
 
26
- assert_matches pattern, 'a.a.b.c'
27
- assert_matches pattern, 'a.d.b.c'
28
- refute_matches pattern, 'a.b.c.d'
29
- end
26
+ assert_matches pattern, 'a.a.b.c'
27
+ assert_matches pattern, 'a.d.b.c'
28
+ refute_matches pattern, 'a.b.c.d'
29
+ end
30
30
 
31
- def test_asterix_at_the_end
32
- pattern = KeyPattern.new('a.b.c.*')
31
+ def test_asterix_at_the_end
32
+ pattern = KeyPattern.new('a.b.c.*')
33
33
 
34
- assert_matches pattern, 'a.b.c.d'
35
- assert_matches pattern, 'a.b.c.a'
36
- refute_matches pattern, 'a.b.c'
37
- refute_matches pattern, 'a.b.c.d.e'
38
- end
34
+ assert_matches pattern, 'a.b.c.d'
35
+ assert_matches pattern, 'a.b.c.a'
36
+ refute_matches pattern, 'a.b.c'
37
+ refute_matches pattern, 'a.b.c.d.e'
38
+ end
39
39
 
40
- def test_hash
41
- pattern = KeyPattern.new('#')
40
+ def test_hash
41
+ pattern = KeyPattern.new('#')
42
42
 
43
- assert_matches pattern, ''
44
- assert_matches pattern, 'a.b.c'
45
- assert_matches pattern, 'a.b.b.c'
46
- end
43
+ assert_matches pattern, ''
44
+ assert_matches pattern, 'a.b.c'
45
+ assert_matches pattern, 'a.b.b.c'
46
+ end
47
47
 
48
- def test_hash_at_start
49
- pattern = KeyPattern.new('#.b.c')
48
+ def test_hash_at_start
49
+ pattern = KeyPattern.new('#.b.c')
50
50
 
51
- assert_matches pattern, 'b.c'
52
- assert_matches pattern, 'a.b.c'
53
- assert_matches pattern, 'a.b.b.c'
54
- refute_matches pattern, 'a.b.c.d'
55
- end
51
+ assert_matches pattern, 'b.c'
52
+ assert_matches pattern, 'a.b.c'
53
+ assert_matches pattern, 'a.b.b.c'
54
+ refute_matches pattern, 'a.b.c.d'
55
+ end
56
56
 
57
- def test_hash_in_the_middle
58
- pattern = KeyPattern.new('a.#.c')
57
+ def test_hash_in_the_middle
58
+ pattern = KeyPattern.new('a.#.c')
59
59
 
60
- assert_matches pattern, 'a.a.b.c'
61
- assert_matches pattern, 'a.d.b.c'
62
- refute_matches pattern, 'a.b.c.d'
63
- end
60
+ assert_matches pattern, 'a.a.b.c'
61
+ assert_matches pattern, 'a.d.b.c'
62
+ refute_matches pattern, 'a.b.c.d'
63
+ end
64
64
 
65
- def test_hash_at_the_end
66
- pattern = KeyPattern.new('a.b.#')
65
+ def test_hash_at_the_end
66
+ pattern = KeyPattern.new('a.b.#')
67
67
 
68
- assert_matches pattern, 'a.b.c.d'
69
- assert_matches pattern, 'a.b.c'
70
- assert_matches pattern, 'a.b.c.d.e'
71
- end
68
+ assert_matches pattern, 'a.b.c.d'
69
+ assert_matches pattern, 'a.b.c'
70
+ assert_matches pattern, 'a.b.c.d.e'
71
+ end
72
72
 
73
- def test_complex
74
- pattern = KeyPattern.new('*.*.a.b.#.c.#')
73
+ def test_complex
74
+ pattern = KeyPattern.new('*.*.a.b.#.c.#')
75
75
 
76
- assert_matches pattern, '1.2.a.b.c.d'
77
- assert_matches pattern, '1.2.a.b.3.4.c.d'
78
- assert_matches pattern, '1.2.a.b.c'
79
- refute_matches pattern, 'a.b.c.d.e'
80
- end
76
+ assert_matches pattern, '1.2.a.b.c.d'
77
+ assert_matches pattern, '1.2.a.b.3.4.c.d'
78
+ assert_matches pattern, '1.2.a.b.c'
79
+ refute_matches pattern, 'a.b.c.d.e'
80
+ end
81
81
 
82
- def test_performance
83
- pattern = KeyPattern.new('*.*.a.b.#.c.#')
82
+ def test_performance
83
+ pattern = KeyPattern.new('*.*.a.b.#.c.#')
84
84
 
85
- n = 10_000
86
- time = Benchmark.realtime { n.times { pattern =~ '1.2.a.b.3.4.c.d' } }
85
+ n = 10_000
86
+ time = Benchmark.realtime { n.times { pattern =~ '1.2.a.b.3.4.c.d' } }
87
87
 
88
- assert time < 0.1
89
- end
88
+ assert time < 0.1
89
+ end
90
90
 
91
- protected
91
+ protected
92
92
 
93
- def assert_matches(pattern, key)
94
- assert pattern =~ key, "#{key} SHOULD match #{pattern}"
95
- end
93
+ def assert_matches(pattern, key)
94
+ assert pattern =~ key, "#{key} SHOULD match #{pattern}"
95
+ end
96
96
 
97
- def refute_matches(pattern, key)
98
- assert pattern !~ key, "#{key} MUST NOT match #{pattern}"
99
- end
97
+ def refute_matches(pattern, key)
98
+ assert pattern !~ key, "#{key} MUST NOT match #{pattern}"
99
+ end
100
100
  end
@@ -1,151 +1,151 @@
1
- require_relative 'test_helper'
2
- require 'tochtli/test/test_case'
3
-
4
- class RabbitConnectionTest < Minitest::Test
5
- def setup
6
- Tochtli::RabbitConnection.close('test')
7
- end
8
-
9
- def teardown
10
- Tochtli::RabbitConnection.close('test')
11
- end
12
-
13
- class TestMessage < Tochtli::Message
14
- attributes :text
15
- end
16
-
17
- def test_connection_with_default_options
18
- Tochtli::RabbitConnection.open('test') do |connection|
19
- assert_equal "puzzleflow.services", connection.exchange.name
20
- end
21
- end
22
-
23
- def test_connection_with_custom_options
24
- Tochtli::RabbitConnection.open('test', exchange_name: "puzzleflow.tests") do |connection|
25
- assert_equal "puzzleflow.tests", connection.exchange.name
26
- end
27
- end
28
-
29
- def test_multiple_channels_and_exchanges
30
- Tochtli::RabbitConnection.open('test', exchange_name: "puzzleflow.tests") do |connection|
31
- another_thread = Thread.new {}
32
-
33
- current_channel = connection.channel
34
- another_channel = connection.channel(another_thread)
35
-
36
- current_exchange = connection.exchange
37
- another_exchange = connection.exchange(another_thread)
38
-
39
- refute_equal current_channel, another_channel
40
- refute_equal current_exchange, another_exchange
41
- assert_equal "puzzleflow.tests", current_exchange.name
42
- assert_equal "puzzleflow.tests", another_exchange.name
43
- end
44
- end
45
-
46
- def test_queue_creation_and_existance
47
- Tochtli::RabbitConnection.open('test') do |connection|
48
- queue = connection.queue('test-queue', [], auto_delete: true)
49
- refute_nil queue
50
- assert_equal 'test-queue', queue.name
51
- assert connection.queue_exists?('test-queue')
52
- end
53
- end
54
-
55
- def test_reply_queue_recovery
56
- Tochtli::RabbitConnection.open('test',
57
- network_recovery_interval: 0.1,
58
- recover_from_connection_close: true) do |rabbit_connection|
59
- reply_queue = rabbit_connection.reply_queue
60
- original_name = reply_queue.name
61
- timeout = 0.3
62
-
63
- message = TestMessage.new(text: "Response")
64
- reply = TestMessage.new(text: "Reply")
65
- handler = Tochtli::Test::TestMessageHandler.new
66
- reply_queue.register_message_handler message, handler, timeout
67
-
68
- rabbit_connection.publish reply_queue.name, reply, correlation_id: message.id, timeout: timeout
69
- sleep timeout
70
-
71
- refute_nil handler.reply
72
-
73
- # simulate network failure
74
- rabbit_connection.connection.handle_network_failure(RuntimeError.new('fake connection error'))
75
- sleep 0.1 until rabbit_connection.open? # wait for recovery
76
- refute_equal original_name, reply_queue.name, "Recovered queue should have re-generated name"
77
-
78
- message = TestMessage.new(text: "Response")
79
- reply = TestMessage.new(text: "Reply")
80
- handler = Tochtli::Test::TestMessageHandler.new
81
- reply_queue.register_message_handler message, handler, timeout
82
-
83
- rabbit_connection.publish reply_queue.name, reply, correlation_id: message.id, timeout: timeout
84
- sleep timeout
85
-
86
- refute_nil handler.reply
87
- end
88
- end
89
-
90
- def test_multithreaded_consumer_performance
91
- work_pool_size = 10
92
- Tochtli::RabbitConnection.open('test',
93
- exchange_name: "puzzleflow.tests",
94
- work_pool_size: work_pool_size) do |connection|
95
- mutex = Mutex.new
96
- cv = ConditionVariable.new
97
- thread_count = 5
98
- message_count = 100
99
- expected_message_count = message_count*thread_count
100
-
101
- consumed = 0
102
- consumed_mutex = Mutex.new
103
- consumer_threads = Set.new
104
- consumer = Proc.new do |delivery_info, metadata, payload|
105
- consumed_mutex.synchronize { consumed += 1 }
106
- consumer_threads << Thread.current
107
- connection.publish metadata.reply_to, TestMessage.new(text: "Response to #{payload}")
108
- end
109
-
110
- queue = connection.channel.queue('', auto_delete: true)
111
- queue.bind(connection.exchange, routing_key: queue.name)
112
- queue.subscribe(block: false, &consumer)
113
-
114
- replies = 0
115
- reply_consumer = Proc.new do |delivery_info, metadata, payload|
116
- replies += 1
117
- mutex.synchronize { cv.signal } if replies == expected_message_count
118
- end
119
-
120
- reply_queue = connection.channel.queue('', auto_delete: true)
121
- reply_queue.bind(connection.exchange, routing_key: reply_queue.name)
122
- reply_queue.subscribe(block: false, &reply_consumer)
123
-
124
- start_t = Time.now
125
-
126
- threads = (1..thread_count).collect do
127
- t = Thread.new do
128
- message_count.times do |i|
129
- connection.publish queue.name, TestMessage.new(text: "Message #{i}"),
130
- reply_to: reply_queue.name
131
- end
132
- end
133
- t.abort_on_exception = true
134
- t
135
- end
136
-
137
- threads.each(&:join)
138
-
139
- mutex.synchronize { cv.wait(mutex, 5.0) }
140
-
141
- end_t = Time.now
142
- time = end_t - start_t
143
-
144
- assert_equal expected_message_count, consumed
145
- assert_equal expected_message_count, replies
146
- assert_equal work_pool_size, consumer_threads.size
147
-
148
- puts "Published: #{expected_message_count} in #{time} (#{expected_message_count/time}req/s)"
149
- end
150
- end
151
- end
1
+ require_relative 'test_helper'
2
+ require 'tochtli/test/test_case'
3
+
4
+ class RabbitConnectionTest < Minitest::Test
5
+ def setup
6
+ Tochtli::RabbitConnection.close('test')
7
+ end
8
+
9
+ def teardown
10
+ Tochtli::RabbitConnection.close('test')
11
+ end
12
+
13
+ class TestMessage < Tochtli::Message
14
+ attributes :text
15
+ end
16
+
17
+ def test_connection_with_default_options
18
+ Tochtli::RabbitConnection.open('test') do |connection|
19
+ assert_equal "puzzleflow.services", connection.exchange.name
20
+ end
21
+ end
22
+
23
+ def test_connection_with_custom_options
24
+ Tochtli::RabbitConnection.open('test', exchange_name: "puzzleflow.tests") do |connection|
25
+ assert_equal "puzzleflow.tests", connection.exchange.name
26
+ end
27
+ end
28
+
29
+ def test_multiple_channels_and_exchanges
30
+ Tochtli::RabbitConnection.open('test', exchange_name: "puzzleflow.tests") do |connection|
31
+ another_thread = Thread.new {}
32
+
33
+ current_channel = connection.channel
34
+ another_channel = connection.channel(another_thread)
35
+
36
+ current_exchange = connection.exchange
37
+ another_exchange = connection.exchange(another_thread)
38
+
39
+ refute_equal current_channel, another_channel
40
+ refute_equal current_exchange, another_exchange
41
+ assert_equal "puzzleflow.tests", current_exchange.name
42
+ assert_equal "puzzleflow.tests", another_exchange.name
43
+ end
44
+ end
45
+
46
+ def test_queue_creation_and_existance
47
+ Tochtli::RabbitConnection.open('test') do |connection|
48
+ queue = connection.queue('test-queue', [], auto_delete: true)
49
+ refute_nil queue
50
+ assert_equal 'test-queue', queue.name
51
+ assert connection.queue_exists?('test-queue')
52
+ end
53
+ end
54
+
55
+ def test_reply_queue_recovery
56
+ Tochtli::RabbitConnection.open('test',
57
+ network_recovery_interval: 0.1,
58
+ recover_from_connection_close: true) do |rabbit_connection|
59
+ reply_queue = rabbit_connection.reply_queue
60
+ original_name = reply_queue.name
61
+ timeout = 0.3
62
+
63
+ message = TestMessage.new(text: "Response")
64
+ reply = TestMessage.new(text: "Reply")
65
+ handler = Tochtli::Test::TestMessageHandler.new
66
+ reply_queue.register_message_handler message, handler, timeout
67
+
68
+ rabbit_connection.publish reply_queue.name, reply, correlation_id: message.id, timeout: timeout
69
+ sleep timeout
70
+
71
+ refute_nil handler.reply
72
+
73
+ # simulate network failure
74
+ rabbit_connection.connection.handle_network_failure(RuntimeError.new('fake connection error'))
75
+ sleep 0.1 until rabbit_connection.open? # wait for recovery
76
+ refute_equal original_name, reply_queue.name, "Recovered queue should have re-generated name"
77
+
78
+ message = TestMessage.new(text: "Response")
79
+ reply = TestMessage.new(text: "Reply")
80
+ handler = Tochtli::Test::TestMessageHandler.new
81
+ reply_queue.register_message_handler message, handler, timeout
82
+
83
+ rabbit_connection.publish reply_queue.name, reply, correlation_id: message.id, timeout: timeout
84
+ sleep timeout
85
+
86
+ refute_nil handler.reply
87
+ end
88
+ end
89
+
90
+ def test_multithreaded_consumer_performance
91
+ work_pool_size = 10
92
+ Tochtli::RabbitConnection.open('test',
93
+ exchange_name: "puzzleflow.tests",
94
+ work_pool_size: work_pool_size) do |connection|
95
+ mutex = Mutex.new
96
+ cv = ConditionVariable.new
97
+ thread_count = 5
98
+ message_count = 100
99
+ expected_message_count = message_count*thread_count
100
+
101
+ consumed = 0
102
+ consumed_mutex = Mutex.new
103
+ consumer_threads = Set.new
104
+ consumer = Proc.new do |delivery_info, metadata, payload|
105
+ consumed_mutex.synchronize { consumed += 1 }
106
+ consumer_threads << Thread.current
107
+ connection.publish metadata.reply_to, TestMessage.new(text: "Response to #{payload}")
108
+ end
109
+
110
+ queue = connection.channel.queue('', auto_delete: true)
111
+ queue.bind(connection.exchange, routing_key: queue.name)
112
+ queue.subscribe(block: false, &consumer)
113
+
114
+ replies = 0
115
+ reply_consumer = Proc.new do |delivery_info, metadata, payload|
116
+ replies += 1
117
+ mutex.synchronize { cv.signal } if replies == expected_message_count
118
+ end
119
+
120
+ reply_queue = connection.channel.queue('', auto_delete: true)
121
+ reply_queue.bind(connection.exchange, routing_key: reply_queue.name)
122
+ reply_queue.subscribe(block: false, &reply_consumer)
123
+
124
+ start_t = Time.now
125
+
126
+ threads = (1..thread_count).collect do
127
+ t = Thread.new do
128
+ message_count.times do |i|
129
+ connection.publish queue.name, TestMessage.new(text: "Message #{i}"),
130
+ reply_to: reply_queue.name
131
+ end
132
+ end
133
+ t.abort_on_exception = true
134
+ t
135
+ end
136
+
137
+ threads.each(&:join)
138
+
139
+ mutex.synchronize { cv.wait(mutex, 5.0) }
140
+
141
+ end_t = Time.now
142
+ time = end_t - start_t
143
+
144
+ assert_equal expected_message_count, consumed
145
+ assert_equal expected_message_count, replies
146
+ assert_equal work_pool_size, consumer_threads.size
147
+
148
+ puts "Published: #{expected_message_count} in #{time} (#{expected_message_count/time}req/s)"
149
+ end
150
+ end
151
+ end
@@ -1,8 +1,8 @@
1
1
  require_relative 'test_helper'
2
2
 
3
3
  class VersionTest < Minitest::Test
4
- def test_version_match
5
- spec = Gem::Specification::load(File.expand_path('../../tochtli.gemspec', __FILE__))
6
- assert_equal Tochtli::VERSION, spec.version.to_s, "Gem version mismatch. Run: 'rake gemspec'"
7
- end
4
+ def test_version_match
5
+ spec = Gem::Specification::load(File.expand_path('../../tochtli.gemspec', __FILE__))
6
+ assert_equal Tochtli::VERSION, spec.version.to_s, "Gem version mismatch. Run: 'rake gemspec'"
7
+ end
8
8
  end
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: tochtli 0.5.0 ruby lib
5
+ # stub: tochtli 0.5.1 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "tochtli"
9
- s.version = "0.5.0"
9
+ s.version = "0.5.1"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Rafal Bigaj"]
14
- s.date = "2015-08-19"
14
+ s.date = "2015-08-20"
15
15
  s.description = "Lightweight framework for service oriented applications based on bunny (RabbitMQ)"
16
16
  s.email = "rafal.bigaj@puzzleflow.com"
17
17
  s.extra_rdoc_files = [
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tochtli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rafal Bigaj
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-19 00:00:00.000000000 Z
11
+ date: 2015-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bunny