klomp 1.0.4 → 1.0.5

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/.simplecov CHANGED
@@ -3,6 +3,6 @@
3
3
  SimpleCov.start do
4
4
  add_filter '/vendor/'
5
5
 
6
- add_group "Loldance", "lib"
6
+ add_group "Klomp", "lib"
7
7
  add_group "Specs", "spec"
8
8
  end
@@ -1,6 +1,16 @@
1
1
  Klomp Changes
2
2
  --------------------------------------------------------------------------------
3
3
 
4
+ 1.0.5 (2012/10/17)
5
+ ================================================================================
6
+
7
+ - Ensure subscriptions don't get lost if re-subscribe calls fail
8
+ - Add a test of the reconnect logic using em-proxy
9
+ - Rescue all errors while parsing server frames and treat them like foreign
10
+ (server/IO/socket) errors
11
+ - Bump up default select timeout to avoid niggling read errors on connect
12
+ - Don't log exceptions if we're already offline or closing
13
+
4
14
  1.0.4 (2012/10/10)
5
15
  ================================================================================
6
16
 
data/Gemfile CHANGED
@@ -13,6 +13,8 @@ gem "rspec", "~>2.11.0", :group => [:development, :test]
13
13
  gem "ZenTest", "~>4.8.0", :group => [:development, :test]
14
14
  gem "rspec-given", "~>1.0", :group => [:development, :test]
15
15
  gem "simplecov", "~>0.6.0", :group => [:development, :test]
16
+ gem "em-proxy", "~>0.1.0", :group => [:development, :test]
17
+ gem "ci_reporter", "~>1.7.0", :group => [:development, :test]
16
18
  gem "hoe", "~>3.0", :group => [:development, :test]
17
19
 
18
20
  # vim: syntax=ruby
@@ -2,7 +2,13 @@ GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
4
  ZenTest (4.8.0)
5
+ builder (3.1.4)
6
+ ci_reporter (1.7.3)
7
+ builder (>= 2.1.2)
5
8
  diff-lcs (1.1.3)
9
+ em-proxy (0.1.7)
10
+ eventmachine
11
+ eventmachine (1.0.0)
6
12
  hoe (3.0.3)
7
13
  rake (~> 0.8)
8
14
  hoe-bundler (1.1.0)
@@ -36,6 +42,8 @@ PLATFORMS
36
42
 
37
43
  DEPENDENCIES
38
44
  ZenTest (~> 4.8.0)
45
+ ci_reporter (~> 1.7.0)
46
+ em-proxy (~> 0.1.0)
39
47
  hoe (~> 3.0)
40
48
  hoe-bundler (~> 1.1.0)
41
49
  hoe-gemspec (~> 1.0.0)
@@ -12,6 +12,7 @@ lib/klomp/connection.rb
12
12
  lib/klomp/frames.rb
13
13
  lib/klomp/sentinel.rb
14
14
  spec/acceptance/acceptance_spec.rb
15
+ spec/acceptance/reconnect_spec.rb
15
16
  spec/frames/auth_error.txt
16
17
  spec/frames/connect.txt
17
18
  spec/frames/connect_vhost.txt
@@ -29,3 +30,4 @@ spec/klomp/sentinel_spec.rb
29
30
  spec/klomp_spec.rb
30
31
  spec/spec_helper.rb
31
32
  spec/support/have_received.rb
33
+ spec/support/shared_contexts.rb
data/Rakefile CHANGED
@@ -10,6 +10,8 @@ Hoe.spec 'klomp' do
10
10
  self.history_file = 'CHANGELOG.md'
11
11
  self.readme_file = 'README.md'
12
12
 
13
+ self.clean_globs << 'spec/reports'
14
+
13
15
  ### dependencies!
14
16
  self.extra_dev_deps << [ 'hoe-bundler', '~> 1.1.0' ]
15
17
  self.extra_dev_deps << [ 'hoe-gemspec', '~> 1.0.0' ]
@@ -18,4 +20,8 @@ Hoe.spec 'klomp' do
18
20
  self.extra_dev_deps << [ 'ZenTest', '~> 4.8.0' ]
19
21
  self.extra_dev_deps << [ 'rspec-given', '~> 1.0' ]
20
22
  self.extra_dev_deps << [ 'simplecov', '~> 0.6.0' ]
23
+ self.extra_dev_deps << [ 'em-proxy', '~> 0.1.0' ]
24
+ self.extra_dev_deps << [ 'ci_reporter', '~> 1.7.0' ]
21
25
  end
26
+
27
+ require 'ci/reporter/rake/rspec'
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "klomp"
5
- s.version = "1.0.4"
5
+ s.version = "1.0.5"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Nick Sieger"]
9
- s.date = "2012-10-10"
9
+ s.date = "2012-10-17"
10
10
  s.description = "Klomp is a simple [Stomp] messaging client that keeps your sanity intact.\n\nThe purpose of Klomp is to be the simplest possible Stomp client. No in-memory\nbuffering of outgoing messages, no fanout subscriptions in-process, no\ntransactions, no complicated messaging patterns. Code simple enough so that when\nsomething goes wrong, the problem is obvious.\n\n[Stomp]: http://stomp.github.com/"
11
11
  s.email = ["nick.sieger@livingsocial.com"]
12
12
  s.extra_rdoc_files = ["Manifest.txt"]
@@ -30,6 +30,8 @@ Gem::Specification.new do |s|
30
30
  s.add_development_dependency(%q<ZenTest>, ["~> 4.8.0"])
31
31
  s.add_development_dependency(%q<rspec-given>, ["~> 1.0"])
32
32
  s.add_development_dependency(%q<simplecov>, ["~> 0.6.0"])
33
+ s.add_development_dependency(%q<em-proxy>, ["~> 0.1.0"])
34
+ s.add_development_dependency(%q<ci_reporter>, ["~> 1.7.0"])
33
35
  s.add_development_dependency(%q<hoe>, ["~> 3.0"])
34
36
  else
35
37
  s.add_dependency(%q<rdoc>, ["~> 3.10"])
@@ -40,6 +42,8 @@ Gem::Specification.new do |s|
40
42
  s.add_dependency(%q<ZenTest>, ["~> 4.8.0"])
41
43
  s.add_dependency(%q<rspec-given>, ["~> 1.0"])
42
44
  s.add_dependency(%q<simplecov>, ["~> 0.6.0"])
45
+ s.add_dependency(%q<em-proxy>, ["~> 0.1.0"])
46
+ s.add_dependency(%q<ci_reporter>, ["~> 1.7.0"])
43
47
  s.add_dependency(%q<hoe>, ["~> 3.0"])
44
48
  end
45
49
  else
@@ -51,6 +55,8 @@ Gem::Specification.new do |s|
51
55
  s.add_dependency(%q<ZenTest>, ["~> 4.8.0"])
52
56
  s.add_dependency(%q<rspec-given>, ["~> 1.0"])
53
57
  s.add_dependency(%q<simplecov>, ["~> 0.6.0"])
58
+ s.add_dependency(%q<em-proxy>, ["~> 0.1.0"])
59
+ s.add_dependency(%q<ci_reporter>, ["~> 1.7.0"])
54
60
  s.add_dependency(%q<hoe>, ["~> 3.0"])
55
61
  end
56
62
  end
@@ -1,5 +1,5 @@
1
1
  class Klomp
2
- VERSION = '1.0.4'
2
+ VERSION = '1.0.5'
3
3
 
4
4
  class Error < StandardError; end
5
5
 
@@ -28,7 +28,7 @@ class Klomp
28
28
  @options['host'] ||= host
29
29
  @subscriptions = {}
30
30
  @logger = options['logger']
31
- @select_timeout = options['select_timeout'] || 0.1
31
+ @select_timeout = options['select_timeout'] || 0.5
32
32
  connect
33
33
  end
34
34
 
@@ -77,6 +77,8 @@ class Klomp
77
77
  subscriptions.clear
78
78
  subs.each {|queue, subscriber| subscribe(queue, subscriber) }
79
79
  @sentinel = nil
80
+ ensure
81
+ @subscriptions = subs if subs && subs.size != @subscriptions.size
80
82
  end
81
83
 
82
84
  private
@@ -134,8 +136,8 @@ class Klomp
134
136
  end
135
137
 
136
138
  def go_offline(ex)
139
+ return if @closing || (@sentinel && @sentinel.alive?)
137
140
  log_exception(ex, :warn, "offline server=#{options['server'].join(':')} ") if logger
138
- return if @sentinel && @sentinel.alive?
139
141
  @socket.close rescue nil
140
142
  @socket = nil
141
143
  @sentinel = Sentinel.new(self)
@@ -156,7 +158,7 @@ class Klomp
156
158
  rescue INTERRUPT
157
159
  break
158
160
  rescue => e
159
- log_exception(e, :warn) if logger
161
+ log_exception(e, :warn) if logger && !@closing
160
162
  end
161
163
  break if @closing
162
164
  end
@@ -1,5 +1,5 @@
1
1
  class Klomp
2
- class FrameError < Error; end
2
+ class FrameError < ::StandardError; end
3
3
 
4
4
  module Frames
5
5
  class Frame
@@ -36,6 +36,10 @@ class Klomp
36
36
  def parse(data)
37
37
  headers, body = data.split("\n\n")
38
38
  [parse_headers(headers), body.chomp(FRAME_SEP)]
39
+ rescue FrameError
40
+ raise
41
+ rescue
42
+ raise FrameError, "malformed frame from server"
39
43
  end
40
44
 
41
45
  def parse_headers(data)
@@ -47,7 +51,7 @@ class Klomp
47
51
  frame = line.chomp
48
52
  @error = frame == "ERROR"
49
53
  if !@error && frame != name
50
- raise Klomp::FrameError,
54
+ raise FrameError,
51
55
  "unexpected frame #{frame} (expected #{name}):\n#{data}"
52
56
  end
53
57
  next
@@ -4,11 +4,7 @@ require 'open-uri'
4
4
 
5
5
  describe "Klomp acceptance", :acceptance => true do
6
6
 
7
- Given(:server) { "127.0.0.1:61613" }
8
- Given(:credentials) { %w(admin password) }
9
- Given(:options) { Hash[*%w(login passcode).zip(credentials).flatten] }
10
- Given(:clients) { [] }
11
- Given(:klomp) { Klomp.new(server, options).tap {|l| clients << l } }
7
+ include_context :acceptance_client
12
8
 
13
9
  context "connect" do
14
10
 
@@ -51,7 +47,6 @@ describe "Klomp acceptance", :acceptance => true do
51
47
  subscriber.message.body.should == "hello subscriber!"
52
48
  end
53
49
 
54
-
55
50
  context "and unsubscribe" do
56
51
 
57
52
  When do
@@ -135,8 +130,6 @@ describe "Klomp acceptance", :acceptance => true do
135
130
  end
136
131
  end
137
132
 
138
- after { clients.each(&:disconnect) }
139
-
140
133
  def apollo_mgmt_url(path)
141
134
  "http://localhost:61680#{path}"
142
135
  end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+ require 'em-proxy'
3
+ require 'logger'
4
+
5
+ describe "Klomp reconnect logic", :acceptance => true do
6
+
7
+ include_context :acceptance_client
8
+ Given(:origin_server) { "127.0.0.1:61613" }
9
+ Given(:server) { "127.0.0.1:62623" }
10
+ Given(:options) { Hash[*%w(login passcode).zip(credentials).flatten] }
11
+
12
+ it "reconnects after a server goes down" do
13
+ # Publish and receive a message
14
+ klomp.publish "/queue/greeting", "hello"
15
+ incoming = []
16
+ klomp.subscribe "/queue/greeting" do |msg|
17
+ incoming << msg
18
+ end
19
+ sleep 2
20
+ incoming.should_not be_empty
21
+
22
+ # Server disappears
23
+ stop_proxy
24
+ expect { klomp.publish "/queue/greeting", "hello" }.to raise_error
25
+ klomp.should_not be_connected
26
+
27
+ # Server reappears
28
+ start_proxy
29
+ klomp.should be_connected
30
+
31
+ # Subscription is re-established
32
+ incoming = []
33
+ klomp.publish "/queue/greeting", "hello"
34
+ sleep 2
35
+ incoming.should_not be_empty
36
+
37
+ klomp.unsubscribe "/queue/greeting"
38
+ end
39
+
40
+ before { start_proxy }
41
+ after { stop_proxy }
42
+
43
+ def server_to_hash(s)
44
+ Hash[*[:host, :port].zip(s.split(':')).flatten]
45
+ end
46
+
47
+ def start_proxy
48
+ listen, forward = server_to_hash(server), server_to_hash(origin_server)
49
+ @pid = fork do
50
+ [STDIN, STDOUT, STDERR].each {|s| s.reopen "/dev/null" }
51
+ Proxy.start listen do |conn|
52
+ conn.server :origin, forward.merge(:relay_client => true, :relay_server => true)
53
+ end
54
+ end
55
+ sleep 2
56
+ end
57
+
58
+ def stop_proxy
59
+ if @pid
60
+ Process.kill "TERM", @pid
61
+ Process.waitpid @pid
62
+ @pid = nil
63
+ end
64
+ end
65
+
66
+ end
@@ -161,8 +161,6 @@ describe Klomp::Connection do
161
161
 
162
162
  Then { subscriber.should_not have_received(:call) }
163
163
 
164
- Then { logger.should have_received(:warn) }
165
-
166
164
  end
167
165
 
168
166
  context "fails if neither a subscriber nor a block is given" do
@@ -351,6 +349,28 @@ describe Klomp::Connection do
351
349
 
352
350
  end
353
351
 
352
+ context "ensures subscriptions don't get lost if re-subscribe calls fail" do
353
+
354
+ Given do
355
+ connection.subscribe "/queue/greeting", subscriber
356
+ connection.subscribe "/queue/hello", subscriber
357
+ thread.stub!(:raise)
358
+ connection.disconnect
359
+ socket.messages_received.clear
360
+ socket.stub!(:write).and_return do |data|
361
+ raise "some error" if data =~ /SUBSCRIBE/
362
+ end
363
+ end
364
+
365
+ When(:expect_reconnect) { expect { connection.reconnect } }
366
+
367
+ Then do
368
+ expect_reconnect.to raise_error
369
+ connection.subscriptions.size.should == 2
370
+ end
371
+
372
+ end
373
+
354
374
  end
355
375
 
356
376
  end
@@ -0,0 +1,9 @@
1
+ shared_context :acceptance_client do
2
+ Given(:server) { "127.0.0.1:61613" }
3
+ Given(:credentials) { %w(admin password) }
4
+ Given(:options) { Hash[*%w(login passcode).zip(credentials).flatten] }
5
+ Given(:clients) { [] }
6
+ Given(:klomp) { Klomp.new(server, options).tap {|l| clients << l } }
7
+
8
+ after { clients.each(&:disconnect) }
9
+ 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: 1.0.4
4
+ version: 1.0.5
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-10-10 00:00:00.000000000 Z
12
+ date: 2012-10-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rdoc
@@ -139,6 +139,38 @@ dependencies:
139
139
  - - ~>
140
140
  - !ruby/object:Gem::Version
141
141
  version: 0.6.0
142
+ - !ruby/object:Gem::Dependency
143
+ name: em-proxy
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ~>
148
+ - !ruby/object:Gem::Version
149
+ version: 0.1.0
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ~>
156
+ - !ruby/object:Gem::Version
157
+ version: 0.1.0
158
+ - !ruby/object:Gem::Dependency
159
+ name: ci_reporter
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ~>
164
+ - !ruby/object:Gem::Version
165
+ version: 1.7.0
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ~>
172
+ - !ruby/object:Gem::Version
173
+ version: 1.7.0
142
174
  - !ruby/object:Gem::Dependency
143
175
  name: hoe
144
176
  requirement: !ruby/object:Gem::Requirement
@@ -190,6 +222,7 @@ files:
190
222
  - lib/klomp/frames.rb
191
223
  - lib/klomp/sentinel.rb
192
224
  - spec/acceptance/acceptance_spec.rb
225
+ - spec/acceptance/reconnect_spec.rb
193
226
  - spec/frames/auth_error.txt
194
227
  - spec/frames/connect.txt
195
228
  - spec/frames/connect_vhost.txt
@@ -207,6 +240,7 @@ files:
207
240
  - spec/klomp_spec.rb
208
241
  - spec/spec_helper.rb
209
242
  - spec/support/have_received.rb
243
+ - spec/support/shared_contexts.rb
210
244
  - .gemtest
211
245
  homepage: http://github.com/livingsocial/klomp
212
246
  licenses: []
@@ -224,7 +258,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
224
258
  version: '0'
225
259
  segments:
226
260
  - 0
227
- hash: 1370034990818288756
261
+ hash: -3900239592679067652
228
262
  required_rubygems_version: !ruby/object:Gem::Requirement
229
263
  none: false
230
264
  requirements: