klomp 0.0.6 → 0.0.7

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.
data/ChangeLog.md CHANGED
@@ -1,6 +1,11 @@
1
1
  Changes
2
2
  --------------------------------------------------------------------------------
3
3
 
4
+ 0.0.7 (2012/8/15)
5
+ ================================================================================
6
+
7
+ - back out the stomp/onstomp adapter code. we'll revisit this later
8
+
4
9
  0.0.6 (2012/8/10)
5
10
  ================================================================================
6
11
 
data/Gemfile CHANGED
@@ -2,7 +2,6 @@ source "http://rubygems.org"
2
2
 
3
3
  gem "onstomp", "~> 1.0.7"
4
4
  # gem 'onstomp', :path => '../onstomp'
5
- gem "stomp", "~> 1.2.4"
6
5
  gem "json"
7
6
  gem "uuid", "~> 2.3.5"
8
7
 
data/Gemfile.lock CHANGED
@@ -9,7 +9,6 @@ GEM
9
9
  systemu (~> 2.5.0)
10
10
  onstomp (1.0.7)
11
11
  rake (0.9.2.2)
12
- stomp (1.2.4)
13
12
  systemu (2.5.1)
14
13
  thor (0.15.2)
15
14
  uuid (2.3.5)
@@ -24,5 +23,4 @@ DEPENDENCIES
24
23
  json
25
24
  onstomp (~> 1.0.7)
26
25
  rake
27
- stomp (~> 1.2.4)
28
26
  uuid (~> 2.3.5)
data/README.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # Klomp
2
2
 
3
- Klomp is a simple wrapper around the [Stomp](https://github.com/stompgem/stomp)
4
- and [OnStomp](https://github.com/meadvillerb/onstomp/) libraries with some
5
- additional HA and usability features:
3
+ Klomp is a simple wrapper around the [OnStomp](https://github.com/meadvillerb/onstomp/)
4
+ library with some additional HA and usability features:
6
5
 
7
6
  * When initialized with multiple broker URIs, Klomp will publish messages to
8
7
  one broker at a time, but will consume from all brokers simultaneously. This is
9
- a slight improvement over traditional failover clients that work by publishing
10
- and subscribing through a single "active" broker. This one-broker-at-a-time
11
- technique can lead to a split-brain scenario in which messages are only
12
- received by a subset of your STOMP clients. By consuming from all brokers
13
- simultaneously, Klomp ensures that no message is left behind.
8
+ a slight improvement over the regular [OnStomp::Failover::Client](http://mdvlrb.com/onstomp/OnStomp/Failover/Client.html)
9
+ which handles all publishing and subscribing through a single "active" broker.
10
+ This traditional one-broker-at-a-time technique can lead to a split-brain
11
+ scenario in which messages are only received by a subset of your STOMP clients.
12
+ By consuming from all brokers simultaneously, Klomp ensures that no message is
13
+ left behind.
14
14
 
15
15
  * Where applicable, message bodies are automatically translated between native
16
16
  Ruby and JSON objects.
@@ -26,13 +26,14 @@ subscribe block.
26
26
  ## Example usage
27
27
 
28
28
  The goal is that you should be able to use most (if not all) of the standard
29
- Stomp/OnStomp APIs via a `Klomp::Client`:
29
+ OnStomp API (see [OnStomp's UserNarrative](https://github.com/meadvillerb/onstomp/blob/master/extra_doc/UserNarrative.md))
30
+ via a `Klomp::Client`:
30
31
 
31
32
  client = Klomp::Client.new([ ... ])
32
33
 
33
34
  However, there will be some differences in the API due to how `Klomp::Client`
34
- manages connections. For example, while OnStomp's `connected?` method normally
35
- returns a single boolean value, Klomp's `connected?` will return many booleans
35
+ manages connections. For example, while the `connected?` method normally
36
+ returns a boolean value, Klomp's `connected?` will return an array of booleans
36
37
  (i.e. one result for each broker).
37
38
 
38
39
  ### Fibonacci back-off retry behavior
@@ -58,11 +59,6 @@ pass implements a `#generate` method that returns a string ID.
58
59
  <th>Default value</th>
59
60
  <th>Description</th>
60
61
  </tr>
61
- <tr>
62
- <td>:adapter</td>
63
- <td>:onstomp</td>
64
- <td>Stomp library to use. Currently, only :stomp and :onstomp are supported.</td>
65
- </tr>
66
62
  <tr>
67
63
  <td>:translate_json</td>
68
64
  <td>true</td>
@@ -79,9 +75,9 @@ pass implements a `#generate` method that returns a string ID.
79
75
  <td>Logger object</td>
80
76
  </tr>
81
77
  <tr>
82
- <td>:uuid</td>
83
- <td>UUID.new</td>
84
- <td>UUID generator object, responds to :generate and returns an ID</td>
78
+ <td>:uuid</td>
79
+ <td>UUID.new</td>
80
+ <td>UUID generator object, responds to :generate and returns an ID</td>
85
81
  </tr>
86
82
  </table>
87
83
 
data/lib/klomp.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'klomp/client'
2
2
 
3
3
  module Klomp
4
- VERSION = '0.0.6'
4
+ VERSION = '0.0.7'
5
5
  end
data/lib/klomp/client.rb CHANGED
@@ -3,47 +3,19 @@ require 'onstomp/failover'
3
3
  require 'json'
4
4
  require 'uuid'
5
5
  require 'logger'
6
- require 'pp'
7
6
 
8
7
  class OnStomp::Failover::Client
9
8
  # Save previous N, N-1 delays for fibonacci backoff
10
9
  attr_accessor :prev_retry_delay
11
10
  end
12
11
 
13
- class Hash
14
- def to_query_string
15
- self.inject([]) { |memo,(k,v)| memo + ["#{k}=#{v}"] }.join('&')
16
- end
17
- end
18
-
19
12
  module Klomp
20
13
 
21
14
  class Client
22
- attr_reader :read_conn, :write_conn, :all_conn
15
+ attr_reader :read_conn, :write_conn
23
16
  attr_accessor :last_connect_exception
24
17
 
25
- WRITE_ONLY_METHODS = [
26
- :abort,
27
- :begin,
28
- :commit,
29
- ]
30
-
31
- READ_ONLY_METHODS = [
32
- :ack,
33
- :nack,
34
- ]
35
-
36
- TRANSLATE_METHODS = {
37
- :connected? => {
38
- :stomp => :open?
39
- },
40
- :ack => {
41
- :stomp => :acknowledge
42
- }
43
- }
44
-
45
18
  def initialize(uri, options={})
46
- @adapter = options.fetch(:adapter, :onstomp)
47
19
  @translate_json = options.fetch(:translate_json, true)
48
20
  @auto_reply_to = options.fetch(:auto_reply_to, true)
49
21
  @logger = options.fetch(:logger, nil)
@@ -55,93 +27,44 @@ module Klomp
55
27
  options[:retry_delay] ||= 1
56
28
  options[:retry_attempts] ||= -1
57
29
 
58
- case @adapter
59
- when :onstomp
60
- if uri.is_a?(Array)
61
- @write_conn = OnStomp::Failover::Client.new(uri, options)
62
- @read_conn = uri.map {|obj| OnStomp::Failover::Client.new([obj], options) }
63
- else
64
- @write_conn = OnStomp::Failover::Client.new([uri], options)
65
- @read_conn = [@write_conn]
66
- end
67
- when :stomp
68
- require 'stomp'
69
-
70
- # Failover in the Stomp library is kind of flaky. If the client
71
- # temporarily loses its connection, it is eventually able to reconnect
72
- # and resume sending messages. However, the subscribe thread never
73
- # seems to recover. One workaround I discovered is to always create new
74
- # clients with the following URL scheme:
75
- #
76
- # failover:(stomp://localhost,stomp://localhost)
77
- #
78
- # Notice that we're using a failover URL in which the same host is
79
- # specified twice. It's a pretty silly hack, but it's the only way I've
80
- # been able to get failover to work reliably.
81
- #
82
- # - Mike Conigliaro
83
- #
84
- if uri.is_a?(Array)
85
- @write_conn = Stomp::Client.new("failover:(#{uri.join(',')})?#{options.to_query_string}")
86
- @read_conn = uri.map {|obj| Stomp::Client.new("failover:(#{obj},#{obj})?#{options.to_query_string}") }
87
- else
88
- @write_conn = Stomp::Client.new("failover:(#{uri},#{uri})?#{options.to_query_string}")
89
- @read_conn = [@write_conn]
90
- end
30
+ if uri.is_a?(Array)
31
+ @write_conn = OnStomp::Failover::Client.new(uri, options)
32
+ @read_conn = uri.map {|obj| OnStomp::Failover::Client.new([obj], options) }
91
33
  else
92
- raise ArgumentError, "Klomp does not support the #{@adapter} library"
34
+ @write_conn = OnStomp::Failover::Client.new([uri], options)
35
+ @read_conn = [@write_conn]
93
36
  end
94
37
  @all_conn = ([@write_conn] + @read_conn).uniq
95
38
  configure_connections
96
39
  end
97
40
 
98
41
  def connect
99
- case @adapter
100
- when :onstomp
101
- @all_conn.each do |conn|
102
- begin
103
- attempts = conn.retry_attempts
104
- conn.retry_attempts = 1
105
- conn.connect
106
- rescue OnStomp::Failover::MaximumRetriesExceededError
107
- location = conn.active_client.uri.dup.tap {|u| u.password = 'REDACTED' }.to_s
108
- msg = ": #{last_connect_exception.message}" if last_connect_exception
109
- raise OnStomp::ConnectFailedError, "initial connection failed for #{location}#{msg}"
110
- ensure
111
- conn.retry_attempts = attempts
112
- end
42
+ @all_conn.each do |conn|
43
+ begin
44
+ attempts = conn.retry_attempts
45
+ conn.retry_attempts = 1
46
+ conn.connect
47
+ rescue OnStomp::Failover::MaximumRetriesExceededError
48
+ location = conn.active_client.uri.dup.tap {|u| u.password = 'REDACTED' }.to_s
49
+ msg = ": #{last_connect_exception.message}" if last_connect_exception
50
+ raise OnStomp::ConnectFailedError, "initial connection failed for #{location}#{msg}"
51
+ ensure
52
+ conn.retry_attempts = attempts
113
53
  end
114
54
  end
115
55
  self
116
56
  end
117
57
 
118
- def disconnect
119
- method = case @adapter
120
- when :onstomp
121
- :disconnect
122
- when :stomp
123
- :close
124
- end
125
- @all_conn.inject({}) { |memo,obj| memo.update({ obj => obj.__send__(method) }) }
126
- end
127
-
128
- def send(dest, body, headers={}, &block)
58
+ def send(dest, body, headers={}, &cb)
129
59
  if @translate_json && body.respond_to?(:to_json)
130
60
  body = body.to_json
131
- headers['content-type'] = 'application/json'
61
+ headers[:'content-type'] = 'application/json'
132
62
  else
133
63
  body = body.to_s
134
64
  end
135
- uuid = headers['id'] = @uuid.generate if @uuid
65
+ uuid = headers[:id] = @uuid.generate if @uuid
136
66
  log.debug("[Sending] ID=#{uuid} Destination=#{dest} Body=#{body.inspect} Headers=#{headers.inspect}") if log
137
-
138
- method = case @adapter
139
- when :onstomp
140
- :send
141
- when :stomp
142
- :publish
143
- end
144
- @write_conn.__send__(method, dest, body, headers, &block)
67
+ @write_conn.send(dest, body, headers, &cb)
145
68
  end
146
69
  alias publish send
147
70
 
@@ -149,7 +72,7 @@ module Klomp
149
72
  frames = []
150
73
  @read_conn.each do |c|
151
74
  frames << c.subscribe(*args) do |msg|
152
- log.debug("[Received] ID=#{msg.headers['id']} Body=#{msg.body.inspect} Headers=#{msg.headers.to_hash.inspect}") if log
75
+ log.debug("[Received] ID=#{msg[:id]} Body=#{msg.body.inspect} Headers=#{msg.headers.to_hash.inspect}") if log
153
76
  if @translate_json
154
77
  msg.body = begin
155
78
  JSON.parse(msg.body)
@@ -158,11 +81,11 @@ module Klomp
158
81
  end
159
82
  end
160
83
  reply_args = yield msg
161
- if @auto_reply_to && !msg.headers['reply-to'].nil?
84
+ if @auto_reply_to && !msg.headers[:'reply-to'].nil?
162
85
  if reply_args.is_a?(Array)
163
- send(msg.headers['reply-to'], *reply_args)
86
+ send(msg.headers[:'reply-to'], *reply_args)
164
87
  else
165
- send(msg.headers['reply-to'], reply_args)
88
+ send(msg.headers[:'reply-to'], reply_args)
166
89
  end
167
90
  end
168
91
  end
@@ -171,16 +94,11 @@ module Klomp
171
94
  end
172
95
 
173
96
  def unsubscribe(frames, headers={})
174
- case @adapter
175
- when :onstomp
176
- if !frames.respond_to?(:length) || frames.length != @read_conn.length
177
- raise ArgumentError,
178
- "frames is not an array or its length does not match number of connections"
179
- end
180
- frames.each_with_index.map {|f,i| @read_conn[i].unsubscribe f, headers }
181
- else
182
- @read_conn.each { |obj| obj.unsubscribe(frames, headers) }
97
+ if !frames.respond_to?(:length) || frames.length != @read_conn.length
98
+ raise ArgumentError,
99
+ "frames is not an array or its length does not match number of connections"
183
100
  end
101
+ frames.each_with_index.map {|f,i| @read_conn[i].unsubscribe f, headers }
184
102
  end
185
103
 
186
104
  def subscriptions
@@ -191,45 +109,47 @@ module Klomp
191
109
  @logger
192
110
  end
193
111
 
194
- def method_missing(method, *args, &block)
195
- if TRANSLATE_METHODS.has_key?(method) && TRANSLATE_METHODS[method].has_key?(@adapter)
196
- method = TRANSLATE_METHODS[method][@adapter]
197
- end
112
+ WRITE_ONLY_METHODS = [
113
+ :abort,
114
+ :begin,
115
+ :commit,
116
+ ]
198
117
 
118
+ READ_ONLY_METHODS = [
119
+ :ack,
120
+ :nack,
121
+ ]
122
+
123
+ def method_missing(method, *args, &block)
199
124
  case method
200
125
  when *WRITE_ONLY_METHODS
201
126
  @write_conn.__send__(method, *args, &block)
202
127
  when *READ_ONLY_METHODS
203
- @read_conn.inject({}) { |memo,obj| memo.update({ obj => obj.__send__(method, *args, &block) }) }
128
+ @read_conn.map {|c| c.__send__(method, *args, &block) }
204
129
  else
205
- @all_conn.inject({}) { |memo,obj| memo.update({ obj => obj.__send__(method, *args, &block) }) }
130
+ @all_conn.map {|c| c.__send__(method, *args) }
206
131
  end
207
132
  end
208
133
 
209
134
  private
210
-
211
135
  def configure_connections
212
- case @adapter
213
- when :onstomp
214
- klomp_client = self
215
- @all_conn.each do |c|
216
- if @fib_retry_backoff
217
- c.before_failover_retry do |conn, attempt|
218
- if attempt == 1
219
- conn.prev_retry_delay, conn.retry_delay = 0, 1
220
- else
221
- conn.prev_retry_delay, conn.retry_delay = conn.retry_delay, conn.prev_retry_delay + conn.retry_delay
222
- end
136
+ klomp_client = self
137
+ @all_conn.each do |c|
138
+ if @fib_retry_backoff
139
+ c.before_failover_retry do |conn, attempt|
140
+ if attempt == 1
141
+ conn.prev_retry_delay, conn.retry_delay = 0, 1
142
+ else
143
+ conn.prev_retry_delay, conn.retry_delay = conn.retry_delay, conn.prev_retry_delay + conn.retry_delay
223
144
  end
224
145
  end
146
+ end
225
147
 
226
- c.on_failover_connect_failure do
227
- klomp_client.last_connect_exception = $!
228
- end
148
+ c.on_failover_connect_failure do
149
+ klomp_client.last_connect_exception = $!
229
150
  end
230
151
  end
231
152
  end
232
-
233
153
  end
234
154
 
235
155
  end
@@ -10,12 +10,12 @@ task :test_failover do
10
10
  client = Klomp::Client.new([
11
11
  'stomp://admin:password@localhost:61613',
12
12
  'stomp://admin:password@127.0.0.1:62613'
13
- ], :adapter => :onstomp).connect
13
+ ]).connect
14
14
 
15
15
  last_i = nil
16
16
  client.subscribe("/queue/test") do |msg|
17
17
  print "-"
18
- last_i = msg.body.gsub('"', '').to_i
18
+ last_i = msg.body.to_i
19
19
  end
20
20
 
21
21
  begin
@@ -0,0 +1,232 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/pride'
3
+
4
+ require 'klomp'
5
+ require File.expand_path('../test_helper', __FILE__)
6
+
7
+ describe Klomp::Client do
8
+
9
+ include KlompTestHelpers
10
+
11
+ before do
12
+ @uris = [
13
+ 'stomp://admin:password@localhost:61613',
14
+ 'stomp://admin:password@127.0.0.1:62613'
15
+ ]
16
+ @destination = '/queue/test_component.test_event'
17
+ end
18
+
19
+ it 'accepts a single uri and establishes separate failover connections for writes and reads' do
20
+ client = Klomp::Client.new(@uris.first).connect
21
+
22
+ assert_equal [client.write_conn], client.read_conn
23
+ assert client.write_conn.connected?
24
+
25
+ client.disconnect
26
+ end
27
+
28
+ it 'accepts an array of uris and establishes separate failover connections for writes and reads' do
29
+ client = Klomp::Client.new(@uris).connect
30
+
31
+ assert client.write_conn.connected?
32
+ refute_empty client.read_conn
33
+ client.read_conn.each do |obj|
34
+ assert obj.connected?
35
+ end
36
+
37
+ client.disconnect
38
+ end
39
+
40
+ it 'raises an error if authentication fails' do
41
+ assert_raises OnStomp::ConnectFailedError do
42
+ Klomp::Client.new(@uris.first.sub('password', 'psswrd')).connect
43
+ end
44
+ end
45
+
46
+ it 'disconnnects' do
47
+ client = Klomp::Client.new(@uris.first).connect
48
+ assert client.write_conn.connected?
49
+ client.disconnect
50
+ refute client.write_conn.connected?
51
+ end
52
+
53
+ it 'has a logger' do
54
+ logger = Logger.new(STDOUT)
55
+ client = Klomp::Client.new(@uris, :logger=>logger)
56
+ assert_equal client.log, logger
57
+ end
58
+
59
+ it 'sends heartbeat' do
60
+ client = Klomp::Client.new(@uris).connect
61
+ client.beat
62
+ client.disconnect
63
+ end
64
+
65
+ it 'sends requests and gets responses' do
66
+ client = Klomp::Client.new(@uris).connect
67
+ body = { 'body' => rand(36**128).to_s(36) }
68
+
69
+ client.send(@destination, body, :ack=>'client')
70
+
71
+ got_message = false
72
+ client.subscribe(@destination) do |msg|
73
+ got_message = true if msg.body == body
74
+ client.ack(msg)
75
+ end
76
+ let_background_processor_run
77
+ assert got_message
78
+
79
+ client.disconnect
80
+ end
81
+
82
+ it 'automatically publishes responses to the reply-to destination' do
83
+ client = Klomp::Client.new(@uris).connect
84
+ reply_to_body = { 'reply_to_body' => rand(36**128).to_s(36) }
85
+
86
+ client.send(@destination, nil, { 'reply-to' => @destination })
87
+
88
+ got_message = false
89
+ client.subscribe(@destination) do |msg|
90
+ got_message = true if msg.body == reply_to_body
91
+ reply_to_body
92
+ end
93
+ let_background_processor_run
94
+ assert got_message
95
+
96
+ client.disconnect
97
+ end
98
+
99
+ it 'unsubscribes' do
100
+ client = Klomp::Client.new(@uris).connect
101
+
102
+ subscribe_frames = client.subscribe(@destination) { |msg| }
103
+ unsub_frames = client.unsubscribe(subscribe_frames)
104
+ assert_equal subscribe_frames.length, unsub_frames.length
105
+ let_background_processor_run
106
+
107
+ assert client.subscriptions.flatten.empty?, "expected connection to have no subscriptions"
108
+
109
+ client.disconnect
110
+ end
111
+
112
+ it 'sends all unknown options through to OnStomp' do
113
+ client = Klomp::Client.new(@uris.first, :haz_cheezburgers => true, :retry_attempts => 42).connect
114
+ assert client.write_conn.connected?
115
+ assert_equal 42, client.write_conn.retry_attempts
116
+ client.disconnect
117
+ end
118
+
119
+ it 'uses a fibonacci back-off approach to reconnect' do
120
+ good_client = Object.new
121
+ def good_client.connect; true; end
122
+ def good_client.connected?; true; end
123
+ def good_client.connection; true; end
124
+
125
+ bad_client = Object.new
126
+ def bad_client.connect; raise "could not connect"; end
127
+ def bad_client.connected?; false; end
128
+
129
+ test_context = self
130
+ attempts = 0
131
+ conn = nil
132
+ fib = lambda {|n| (1..n).inject([0, 1]) {|fib,_| [fib[1], fib[0]+fib[1]]}.first}
133
+
134
+ pool_class = Class.new do
135
+ def initialize(*) end
136
+ def each(&blk) end
137
+ define_method :next_client do
138
+ attempts += 1
139
+ test_context.assert_equal fib[attempts], conn.retry_delay
140
+ if attempts == 6
141
+ good_client
142
+ else
143
+ bad_client
144
+ end
145
+ end
146
+ end
147
+
148
+ client = Klomp::Client.new(@uris.first, :pool => pool_class)
149
+ conn = client.write_conn
150
+ def conn.sleep_for_retry(*) end # skip sleep between retries for test
151
+
152
+ client.reconnect
153
+ assert_equal 6, attempts
154
+ end
155
+
156
+ it 'sends messages with uuids in the :id header' do
157
+ client = Klomp::Client.new(@uris, :translate_json => false).connect
158
+ client.send(@destination, '')
159
+
160
+ received_message = false
161
+ client.subscribe(@destination) do |msg|
162
+ received_message = msg
163
+ end
164
+ let_background_processor_run
165
+ assert received_message
166
+ assert received_message[:id], "message did not have an id"
167
+ assert received_message[:id] =~ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
168
+ "message id did not look like a uuid"
169
+
170
+ client.disconnect
171
+ end
172
+
173
+ it 'allows customization of the uuid generator' do
174
+ generator = Object.new
175
+ def generator.generate; "42"; end
176
+
177
+ client = Klomp::Client.new(@uris, :translate_json => false, :uuid => generator).connect
178
+ client.send(@destination, '')
179
+
180
+ received_message = false
181
+ client.subscribe(@destination) do |msg|
182
+ received_message = msg
183
+ end
184
+ let_background_processor_run
185
+ assert received_message
186
+ assert received_message[:id], "message did not have an id"
187
+ assert_equal "42", received_message[:id]
188
+
189
+ client.disconnect
190
+ end
191
+
192
+ it 'allows disabling generated message ids' do
193
+ client = Klomp::Client.new(@uris, :translate_json => false, :uuid => false).connect
194
+ client.send(@destination, '')
195
+
196
+ received_message = false
197
+ client.subscribe(@destination) do |msg|
198
+ received_message = msg
199
+ end
200
+ let_background_processor_run
201
+ assert received_message
202
+ refute received_message[:id], "message had an id"
203
+
204
+ client.disconnect
205
+ end
206
+
207
+ it 'logs message ids' do
208
+ logger = Object.new
209
+ def logger.msgs; @msgs; end
210
+ def logger.debug(msg) (@msgs ||= []) << msg end
211
+
212
+ client = Klomp::Client.new(@uris, :translate_json => false, :logger => logger).connect
213
+ client.send(@destination, '')
214
+
215
+ received_message = false
216
+ client.subscribe(@destination) do |msg|
217
+ received_message = msg
218
+ end
219
+ let_background_processor_run
220
+ assert received_message
221
+ assert received_message[:id], "message did not have an id"
222
+
223
+ assert_equal 2, logger.msgs.length
224
+ assert logger.msgs[0] =~ /\[Sending\] ID=([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/
225
+ sent_id = $1
226
+ assert logger.msgs[1] =~ /\[Received\] ID=([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/
227
+ received_id = $1
228
+ assert_equal sent_id, received_id
229
+
230
+ client.disconnect
231
+ end
232
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: klomp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-10 00:00:00.000000000 Z
12
+ date: 2012-08-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: onstomp
@@ -78,9 +78,7 @@ files:
78
78
  - lib/klomp.rb
79
79
  - lib/klomp/client.rb
80
80
  - tasks/test_failover.rake
81
- - test/test_client_all.rb
82
- - test/test_client_onstomp.rb
83
- - test/test_client_stomp.rb
81
+ - test/test_client.rb
84
82
  - test/test_helper.rb
85
83
  homepage: https://github.com/livingsocial/klomp
86
84
  licenses: []
@@ -96,7 +94,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
96
94
  version: '0'
97
95
  segments:
98
96
  - 0
99
- hash: -1910889246392223441
97
+ hash: 1929971310502642728
100
98
  required_rubygems_version: !ruby/object:Gem::Requirement
101
99
  none: false
102
100
  requirements:
@@ -110,7 +108,5 @@ signing_key:
110
108
  specification_version: 3
111
109
  summary: A simple wrapper around the OnStomp library with additional features
112
110
  test_files:
113
- - test/test_client_all.rb
114
- - test/test_client_onstomp.rb
115
- - test/test_client_stomp.rb
111
+ - test/test_client.rb
116
112
  - test/test_helper.rb
@@ -1,167 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'minitest/pride'
3
-
4
- require 'klomp'
5
- require File.expand_path('../test_helper', __FILE__)
6
-
7
- describe Klomp::Client do
8
-
9
- include KlompTestHelpers
10
-
11
- before do
12
- @uris = [
13
- 'stomp://admin:password@localhost:61613',
14
- 'stomp://admin:password@127.0.0.1:62613'
15
- ]
16
- @destination = '/queue/test_component.test_event'
17
- end
18
-
19
- [ :onstomp, :stomp ].each do |adapter|
20
-
21
- it "(#{adapter}) has a logger" do
22
- logger = Logger.new(STDOUT)
23
- client = Klomp::Client.new(@uris, :adapter => adapter, :logger => logger)
24
- assert_equal client.log, logger
25
- end
26
-
27
- it "(#{adapter}) sends all unknown options through to the underlying library" do
28
- client = Klomp::Client.new(@uris.first, :adapter => adapter, :haz_cheezburgers => true, :retry_attempts => 42).connect
29
- assert client.connected?.values.all?
30
- assert_equal 42, client.write_conn.retry_attempts if adapter == :onstomp
31
- client.disconnect
32
- end
33
-
34
- it "(#{adapter}) accepts a single uri and establishes separate failover connections for writes and reads" do
35
- client = Klomp::Client.new(@uris.first, :adapter => adapter).connect
36
- assert_equal [client.write_conn], client.read_conn
37
- assert client.connected?.values.all?
38
- client.disconnect
39
- end
40
-
41
- it "(#{adapter}) accepts an array of uris and establishes separate failover connections for writes and reads" do
42
- client = Klomp::Client.new(@uris, :adapter => adapter).connect
43
- assert client.all_conn.length == @uris.length + 1
44
- assert client.connected?.values.all?
45
- client.disconnect
46
- end
47
-
48
- it "(#{adapter}) disconnnects" do
49
- client = Klomp::Client.new(@uris.first, :adapter => adapter).connect
50
- assert client.connected?.values.all?
51
- client.disconnect
52
- refute client.connected?.values.any?
53
- end
54
-
55
- it "(#{adapter}) sends requests and gets responses" do
56
- client = Klomp::Client.new(@uris, :adapter => adapter).connect
57
- body = { 'body' => rand(36**128).to_s(36) }
58
-
59
- client.send(@destination, body, :ack=>'client')
60
- got_message = false
61
- client.subscribe(@destination) do |msg|
62
- got_message = true if msg.body == body
63
- client.ack(msg)
64
- end
65
- let_background_processor_run
66
- client.disconnect
67
-
68
- assert got_message
69
- end
70
-
71
- it "(#{adapter}) automatically publishes responses to the reply-to destination" do
72
- client = Klomp::Client.new(@uris, :adapter => adapter).connect
73
- reply_to_body = { 'reply_to_body' => rand(36**128).to_s(36) }
74
-
75
- client.send(@destination, nil, { 'reply-to' => @destination })
76
-
77
- got_message = false
78
- client.subscribe(@destination) do |msg|
79
- got_message = true if msg.body == reply_to_body
80
- reply_to_body
81
- end
82
- let_background_processor_run
83
- client.disconnect
84
-
85
- assert got_message
86
- end
87
-
88
- it "(#{adapter}) sends messages with uuids in the 'id' header" do
89
- client = Klomp::Client.new(@uris, :adapter => adapter, :translate_json => false).connect
90
- client.send(@destination, '')
91
-
92
- received_message = false
93
- client.subscribe(@destination) do |msg|
94
- received_message = msg
95
- end
96
- let_background_processor_run
97
- client.disconnect
98
-
99
- assert received_message
100
- assert received_message.headers['id'], "message did not have an id"
101
- assert received_message.headers['id'] =~ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
102
- "message id did not look like a uuid"
103
- end
104
-
105
- it "(#{adapter}) allows customization of the uuid generator" do
106
- generator = Object.new
107
- def generator.generate; "42"; end
108
-
109
- client = Klomp::Client.new(@uris, :adapter => adapter, :translate_json => false, :uuid => generator).connect
110
- client.send(@destination, '')
111
-
112
- received_message = false
113
- client.subscribe(@destination) do |msg|
114
- received_message = msg
115
- end
116
- let_background_processor_run
117
- client.disconnect
118
-
119
- assert received_message
120
- assert received_message.headers['id'], "message did not have an id"
121
- assert_equal "42", received_message.headers['id']
122
- end
123
-
124
- it "(#{adapter}) allows disabling generated message ids" do
125
- client = Klomp::Client.new(@uris, :adapter => adapter, :translate_json => false, :uuid => false).connect
126
- client.send(@destination, '')
127
-
128
- received_message = false
129
- client.subscribe(@destination) do |msg|
130
- received_message = msg
131
- end
132
- let_background_processor_run
133
- client.disconnect
134
-
135
- assert received_message
136
- refute received_message.headers['id'], "message had an id"
137
- end
138
-
139
- it "(#{adapter}) logs message ids" do
140
- logger = Object.new
141
- def logger.msgs; @msgs; end
142
- def logger.debug(msg) (@msgs ||= []) << msg end
143
-
144
- client = Klomp::Client.new(@uris, :adapter => adapter, :translate_json => false, :logger => logger).connect
145
- client.send(@destination, '')
146
-
147
- received_message = false
148
- client.subscribe(@destination) do |msg|
149
- received_message = msg
150
- end
151
- let_background_processor_run
152
- client.disconnect
153
-
154
- assert received_message
155
- assert received_message.headers['id'], "message did not have an id"
156
-
157
- assert_equal 2, logger.msgs.length
158
- assert logger.msgs[0] =~ /\[Sending\] ID=([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/
159
- sent_id = $1
160
- assert logger.msgs[1] =~ /\[Received\] ID=([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/
161
- received_id = $1
162
- assert_equal sent_id, received_id
163
- end
164
-
165
- end
166
-
167
- end
@@ -1,81 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'minitest/pride'
3
-
4
- require 'klomp'
5
- require File.expand_path('../test_helper', __FILE__)
6
-
7
- describe Klomp::Client do
8
-
9
- include KlompTestHelpers
10
-
11
- before do
12
- @adapter = :onstomp
13
- @uris = [
14
- 'stomp://admin:password@localhost:61613',
15
- 'stomp://admin:password@127.0.0.1:62613'
16
- ]
17
- @destination = '/queue/test_component.test_event'
18
- end
19
-
20
- it "raises an error if authentication fails" do
21
- assert_raises OnStomp::ConnectFailedError do
22
- Klomp::Client.new(@uris.first.sub('password', 'psswrd'), :adapter => @adapter).connect
23
- end
24
- end
25
-
26
- it "sends heartbeat" do
27
- client = Klomp::Client.new(@uris, :adapter => @adapter).connect
28
- client.beat
29
- client.disconnect
30
- end
31
-
32
- it "unsubscribes" do
33
- client = Klomp::Client.new(@uris, :adapter => @adapter).connect
34
-
35
- subscribe_frames = client.subscribe(@destination) { |msg| }
36
- unsub_frames = client.unsubscribe(subscribe_frames)
37
- let_background_processor_run
38
- client.disconnect
39
-
40
- assert_equal subscribe_frames.length, unsub_frames.length
41
- assert client.subscriptions.flatten.empty?, "expected connection to have no subscriptions"
42
- end
43
-
44
- it 'uses a fibonacci back-off approach to reconnect' do
45
- good_client = Object.new
46
- def good_client.connect; true; end
47
- def good_client.connected?; true; end
48
- def good_client.connection; true; end
49
-
50
- bad_client = Object.new
51
- def bad_client.connect; raise "could not connect"; end
52
- def bad_client.connected?; false; end
53
-
54
- test_context = self
55
- attempts = 0
56
- conn = nil
57
- fib = lambda {|n| (1..n).inject([0, 1]) {|fib,_| [fib[1], fib[0]+fib[1]]}.first}
58
-
59
- pool_class = Class.new do
60
- def initialize(*) end
61
- def each(&blk) end
62
- define_method :next_client do
63
- attempts += 1
64
- test_context.assert_equal fib[attempts], conn.retry_delay
65
- if attempts == 6
66
- good_client
67
- else
68
- bad_client
69
- end
70
- end
71
- end
72
-
73
- client = Klomp::Client.new(@uris.first, :adapter => @adapter, :pool => pool_class)
74
- conn = client.write_conn
75
- def conn.sleep_for_retry(*) end # skip sleep between retries for test
76
-
77
- client.reconnect
78
- assert_equal 6, attempts
79
- end
80
-
81
- end
@@ -1,27 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'minitest/pride'
3
-
4
- require 'klomp'
5
- require File.expand_path('../test_helper', __FILE__)
6
-
7
- describe Klomp::Client do
8
-
9
- include KlompTestHelpers
10
-
11
- before do
12
- @adapter = :stomp
13
- @uris = [
14
- 'stomp://admin:password@localhost:61613',
15
- 'stomp://admin:password@127.0.0.1:62613'
16
- ]
17
- @destination = '/queue/test_component.test_event'
18
- end
19
-
20
- it "unsubscribes" do
21
- client = Klomp::Client.new(@uris, :adapter => @adapter).connect
22
- client.subscribe(@destination) { |msg| }
23
- client.unsubscribe(@destination)
24
- client.disconnect
25
- end
26
-
27
- end