klomp 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
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: