poseidon 0.0.3 → 0.0.4

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: 3d5bb4f86848c948a0395678c366213e43a69129
4
- data.tar.gz: f9ef623ef716cfe2197c55cb50031c41eb45f785
3
+ metadata.gz: 4c4852d5b615cd1fe50528b0136602756087d0db
4
+ data.tar.gz: 2172c5cd70c8047cb0b0bdd171d5f9ed5cb82b73
5
5
  SHA512:
6
- metadata.gz: ff293ca0f11064c40e3411a57ab8df729013524cf2afb9c2dd018153457f34e200bd8fdfd6ee32aaf4a7af3fa2ce6e19447f9a70275c8bda8332285180e2b509
7
- data.tar.gz: 4c4ab22ed0aa8d84cdfce68051788c0cdfb5fb60d468c64740285af4bda8b217473c11e1974aaa4c4220f4fe6ca7542e8c9a71de5e081a8d2e33aa83323bb91f
6
+ metadata.gz: 3949ab96ce033255e31bc588db0f0895c6a72a91d9bfb56137995f0d5f52bc467dfa660359d440fddca89fe64fd3f6af7a2b28f2476698ba35319f999358a721
7
+ data.tar.gz: 2348e329e244a3b4a777e8635143d33ec591c10ee411f40aa69a629487643585e8b303c13f120d51e85a2dde13f5dea5b0cb3290b152e619d3fa07dc6f4769d4
data/CHANGES.md CHANGED
@@ -1,3 +1,8 @@
1
+ # 0.0.4
2
+
3
+ * Don't truncate UTF8 Messages [GH-18]
4
+ * Gracefully handle truncated fetch reponses [GH-19]
5
+
1
6
  # 0.0.3
2
7
 
3
8
  * Better distribute messages across partitions.
@@ -115,7 +115,7 @@ module Poseidon
115
115
  def send_request(request)
116
116
  buffer = Protocol::RequestBuffer.new
117
117
  request.write(buffer)
118
- @socket.write([buffer.to_s.size].pack("N") + buffer.to_s)
118
+ @socket.write([buffer.to_s.bytesize].pack("N") + buffer.to_s)
119
119
  rescue Errno::EPIPE, Errno::ECONNRESET
120
120
  @socket = nil
121
121
  raise ConnectionFailedError
@@ -82,9 +82,13 @@ module Poseidon
82
82
  #
83
83
  # @api public
84
84
  def fetch(options = {})
85
- fetch_max_wait = options[:max_wait] || max_wait_ms
86
- fetch_max_bytes = options[:max_bytes] || max_bytes
87
- fetch_min_bytes = options[:min_bytes] || min_bytes
85
+ fetch_max_wait = options.delete(:max_wait) || max_wait_ms
86
+ fetch_max_bytes = options.delete(:max_bytes) || max_bytes
87
+ fetch_min_bytes = options.delete(:min_bytes) || min_bytes
88
+
89
+ if options.keys.any?
90
+ raise ArgumentError, "Unknown options: #{options.keys.inspect}"
91
+ end
88
92
 
89
93
  topic_fetches = build_topic_fetch_request(fetch_max_bytes)
90
94
  fetch_response = @connection.fetch(fetch_max_wait, fetch_min_bytes, topic_fetches)
@@ -158,6 +158,11 @@ module Poseidon
158
158
 
159
159
  def read(buffer)
160
160
  if self.class.prepend_size?
161
+ if !have_header?(buffer)
162
+ @truncated = true
163
+ return
164
+ end
165
+
161
166
  @size = buffer.int32
162
167
 
163
168
  if self.class.prepend_crc32?
@@ -171,7 +176,6 @@ module Poseidon
171
176
  expected_bytes_remaining = @size
172
177
  end
173
178
 
174
-
175
179
  if self.class.truncatable? && expected_bytes_remaining > buffer.bytes_remaining
176
180
  @truncated = true
177
181
  return
@@ -190,6 +194,20 @@ module Poseidon
190
194
  end
191
195
  end
192
196
 
197
+ def have_header?(buffer)
198
+ if self.class.truncatable?
199
+ if self.class.prepend_crc32?
200
+ header_bytes = 8
201
+ else
202
+ header_bytes = 4
203
+ end
204
+
205
+ return buffer.bytes_remaining >= header_bytes
206
+ else
207
+ return true
208
+ end
209
+ end
210
+
193
211
  def read_member(buffer, member)
194
212
  case type = type_map[member]
195
213
  when Array
@@ -40,7 +40,7 @@ module Poseidon
40
40
  if string.nil?
41
41
  int16(-1)
42
42
  else
43
- int16(string.size)
43
+ int16(string.bytesize)
44
44
  append(string)
45
45
  end
46
46
  end
@@ -49,13 +49,13 @@ module Poseidon
49
49
  if string.nil?
50
50
  int32(-1)
51
51
  else
52
- int32(string.size)
52
+ int32(string.bytesize)
53
53
  append(string)
54
54
  end
55
55
  end
56
56
 
57
57
  def prepend_crc32
58
- checksum_pos = @s.size
58
+ checksum_pos = @s.bytesize
59
59
  @s += " "
60
60
  yield
61
61
  @s[checksum_pos] = [Zlib::crc32(@s[(checksum_pos+1)..-1])].pack("N")
@@ -63,10 +63,10 @@ module Poseidon
63
63
  end
64
64
 
65
65
  def prepend_size
66
- size_pos = @s.size
66
+ size_pos = @s.bytesize
67
67
  @s += " "
68
68
  yield
69
- @s[size_pos] = [(@s.size-1) - size_pos].pack("N")
69
+ @s[size_pos] = [(@s.bytesize-1) - size_pos].pack("N")
70
70
  nil
71
71
  end
72
72
 
@@ -57,11 +57,11 @@ module Poseidon
57
57
  end
58
58
 
59
59
  def bytes_remaining
60
- @s.size - @pos
60
+ @s.bytesize - @pos
61
61
  end
62
62
 
63
63
  def eof?
64
- @pos == @s.size
64
+ @pos == @s.bytesize
65
65
  end
66
66
 
67
67
  def to_s
@@ -1,4 +1,4 @@
1
1
  module Poseidon
2
2
  # Unstable! API May Change!
3
- VERSION = "0.0.3"
3
+ VERSION = "0.0.4"
4
4
  end
@@ -0,0 +1,44 @@
1
+ require 'integration/simple/spec_helper'
2
+
3
+ describe "truncated messages" do
4
+ before(:all) do
5
+ @s1 = "a" * 335
6
+ @s2 = "b" * 338
7
+
8
+ @producer = Producer.new(["localhost:9092"],
9
+ "test_client",
10
+ :type => :sync)
11
+
12
+ @producer.send_messages([Message.new(:topic => 'test_max_bytes', :value => @s1), Message.new(:topic => 'test_max_bytes', :value => @s2)])
13
+ end
14
+
15
+ it "correctly handles max_byte lengths smallert than a message" do
16
+ 0.upto(360) do |n|
17
+ consumer = PartitionConsumer.new("test_consumer", "localhost", 9092,
18
+ "test_max_bytes", 0, :earliest_offset)
19
+ expect(consumer.fetch(:max_bytes => n)).to eq([])
20
+ end
21
+ end
22
+
23
+ it "correctly handles max_byte lengths that should return a single message" do
24
+ 361.upto(724) do |n|
25
+ consumer = PartitionConsumer.new("test_consumer", "localhost", 9092,
26
+ "test_max_bytes", 0, :earliest_offset)
27
+
28
+ messages = consumer.fetch(:max_bytes => n)
29
+ expect(messages.size).to eq(1)
30
+ expect(messages.first.value).to eq(@s1)
31
+ end
32
+ end
33
+
34
+ it "correctly handles max_byte lengths that should return two messages" do
35
+ 725.upto(1000) do |n|
36
+ consumer = PartitionConsumer.new("test_consumer", "localhost", 9092,
37
+ "test_max_bytes", 0, :earliest_offset)
38
+
39
+ messages = consumer.fetch(:max_bytes => n)
40
+ expect(messages.size).to eq(2)
41
+ expect(messages.map(&:value)).to eq([@s1, @s2])
42
+ end
43
+ end
44
+ end
@@ -24,9 +24,13 @@ describe MessageConductor do
24
24
 
25
25
  context "for unkeyed messages" do
26
26
  it "round robins which partition the message should go to" do
27
- [0,1,0,1].each do |destination|
28
- expect(@mc.destination("test").first).to eq(destination)
27
+ destinations = 4.times.map do
28
+ @mc.destination("test").first
29
29
  end
30
+
31
+ first = [destinations[0], destinations[2]]
32
+ second = [destinations[1], destinations[3]]
33
+ expect([first.uniq, second.uniq].sort).to eq([[0],[1]])
30
34
  end
31
35
 
32
36
  context "unknown topic" do
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  require 'spec_helper'
2
3
 
3
4
  describe Message do
@@ -87,6 +88,22 @@ describe Message do
87
88
  end
88
89
  end
89
90
 
91
+ context "utf8 string with multibyte characters" do
92
+ it "roundtrips correctly" do
93
+ s = "the µ is two bytes"
94
+ m = Message.new(:value => s,
95
+ :key => "key",
96
+ :topic => "topic")
97
+
98
+ req_buf = Protocol::RequestBuffer.new
99
+ m.write(req_buf)
100
+
101
+ resp_buf = Protocol::ResponseBuffer.new(req_buf.to_s)
102
+
103
+ expect(Message.read(resp_buf).value).to eq(s.force_encoding("ASCII-8BIT"))
104
+ end
105
+ end
106
+
90
107
  context "frozen string for value" do
91
108
  it "builds the payload without error" do
92
109
  s = "asdffasdf".freeze
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: poseidon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bob Potter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-25 00:00:00.000000000 Z
11
+ date: 2013-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -121,6 +121,7 @@ files:
121
121
  - spec/integration/simple/multiple_brokers_spec.rb
122
122
  - spec/integration/simple/simple_producer_and_consumer_spec.rb
123
123
  - spec/integration/simple/spec_helper.rb
124
+ - spec/integration/simple/truncated_messages_spec.rb
124
125
  - spec/integration/simple/unavailable_broker_spec.rb
125
126
  - spec/spec_helper.rb
126
127
  - spec/test_cluster.rb
@@ -176,6 +177,7 @@ test_files:
176
177
  - spec/integration/simple/multiple_brokers_spec.rb
177
178
  - spec/integration/simple/simple_producer_and_consumer_spec.rb
178
179
  - spec/integration/simple/spec_helper.rb
180
+ - spec/integration/simple/truncated_messages_spec.rb
179
181
  - spec/integration/simple/unavailable_broker_spec.rb
180
182
  - spec/spec_helper.rb
181
183
  - spec/test_cluster.rb