kafka-rb 0.0.11 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -7,6 +7,11 @@ and is used in production at wooga.
7
7
  You need to have access to your Kafka instance and be able to connect through TCP.
8
8
  You can obtain a copy and instructions on how to setup kafka at http://incubator.apache.org/kafka/
9
9
 
10
+ To make Snappy compression available, add
11
+
12
+ gem "snappy", "0.0.4", :git => "git://github.com/watersofoblivion/snappy.git", :branch => "snappy-streaming"
13
+
14
+ to your Gemfile.
10
15
 
11
16
  ## Installation
12
17
 
data/Rakefile CHANGED
@@ -19,35 +19,7 @@ require 'rubygems/specification'
19
19
  require 'date'
20
20
  require 'rspec/core/rake_task'
21
21
 
22
- spec = Gem::Specification.new do |s|
23
- s.name = %q{kafka-rb}
24
- s.version = "0.0.11"
25
-
26
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
27
- s.authors = ["Alejandro Crosa", "Stefan Mees", "Tim Lossen", "Liam Stewart"]
28
- s.autorequire = %q{kafka-rb}
29
- s.date = Time.now.strftime("%Y-%m-%d")
30
- s.description = %q{kafka-rb allows you to produce and consume messages using the Kafka distributed publish/subscribe messaging service.}
31
- s.extra_rdoc_files = ["LICENSE"]
32
- s.files = ["LICENSE", "README.md", "Rakefile"] + Dir.glob("lib/**/*.rb")
33
- s.test_files = Dir.glob("spec/**/*.rb")
34
- s.homepage = %q{http://github.com/acrosa/kafka-rb}
35
- s.require_paths = ["lib"]
36
- s.summary = %q{A Ruby client for the Kafka distributed publish/subscribe messaging service}
37
-
38
- if s.respond_to? :specification_version then
39
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
40
- s.specification_version = 3
41
-
42
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
43
- s.add_development_dependency(%q<rspec>, [">= 0"])
44
- else
45
- s.add_dependency(%q<rspec>, [">= 0"])
46
- end
47
- else
48
- s.add_dependency(%q<rspec>, [">= 0"])
49
- end
50
- end
22
+ spec = eval(File.open("kafka-rb.gemspec", "r").read)
51
23
 
52
24
  Gem::PackageTask.new(spec) do |pkg|
53
25
  pkg.gem_spec = spec
@@ -58,12 +30,6 @@ task :install => [:package] do
58
30
  sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
59
31
  end
60
32
 
61
- desc "Run all examples with RCov"
62
- RSpec::Core::RakeTask.new(:rcov) do |t|
63
- t.pattern = FileList['spec/**/*_spec.rb']
64
- t.rcov = true
65
- end
66
-
67
33
  desc "Run specs"
68
34
  RSpec::Core::RakeTask.new do |t|
69
35
  t.pattern = FileList['spec/**/*_spec.rb']
@@ -14,8 +14,12 @@
14
14
  # limitations under the License.
15
15
  require 'socket'
16
16
  require 'zlib'
17
- if RUBY_VERSION[0,3] == "1.8"
18
- require 'iconv'
17
+ require "stringio"
18
+
19
+ begin
20
+ require 'snappy'
21
+ rescue LoadError
22
+ nil
19
23
  end
20
24
 
21
25
  require File.join(File.dirname(__FILE__), "kafka", "io")
@@ -15,22 +15,12 @@
15
15
 
16
16
  module Kafka
17
17
  module Encoder
18
- def self.message(message)
19
- payload = \
20
- if RUBY_VERSION[0,3] == "1.8" # Use old iconv on Ruby 1.8 for encoding
21
- Iconv.new('UTF-8//IGNORE', 'UTF-8').iconv(message.payload.to_s)
22
- else
23
- message.payload.to_s.force_encoding(Encoding::ASCII_8BIT)
24
- end
25
- data = [message.magic].pack("C") + [message.calculate_checksum].pack("N") + payload
26
-
27
- [data.length].pack("N") + data
18
+ def self.message(message, compression = Message::NO_COMPRESSION)
19
+ message.encode(compression)
28
20
  end
29
21
 
30
- def self.message_block(topic, partition, messages)
31
- message_set = Array(messages).collect { |message|
32
- self.message(message)
33
- }.join("")
22
+ def self.message_block(topic, partition, messages, compression)
23
+ message_set = message_set(messages, compression)
34
24
 
35
25
  topic = [topic.length].pack("n") + topic
36
26
  partition = [partition].pack("N")
@@ -39,16 +29,24 @@ module Kafka
39
29
  return topic + partition + messages
40
30
  end
41
31
 
42
- def self.produce(topic, partition, messages)
32
+ def self.message_set(messages, compression)
33
+ message_set = Array(messages).collect { |message|
34
+ self.message(message)
35
+ }.join("")
36
+ message_set = self.message(Message.new(message_set), compression) unless compression == Message::NO_COMPRESSION
37
+ message_set
38
+ end
39
+
40
+ def self.produce(topic, partition, messages, compression = Message::NO_COMPRESSION)
43
41
  request = [RequestType::PRODUCE].pack("n")
44
- data = request + self.message_block(topic, partition, messages)
42
+ data = request + self.message_block(topic, partition, messages, compression)
45
43
 
46
44
  return [data.length].pack("N") + data
47
45
  end
48
46
 
49
- def self.multiproduce(producer_requests)
47
+ def self.multiproduce(producer_requests, compression = Message::NO_COMPRESSION)
50
48
  part_set = Array(producer_requests).map { |req|
51
- self.message_block(req.topic, req.partition, req.messages)
49
+ self.message_block(req.topic, req.partition, req.messages, compression)
52
50
  }
53
51
 
54
52
  request = [RequestType::MULTIPRODUCE].pack("n")
@@ -14,7 +14,7 @@
14
14
  # limitations under the License.
15
15
  module Kafka
16
16
  module IO
17
- attr_accessor :socket, :host, :port
17
+ attr_accessor :socket, :host, :port, :compression
18
18
 
19
19
  HOST = "localhost"
20
20
  PORT = 9092
@@ -33,6 +33,10 @@ module Kafka
33
33
  class Message
34
34
 
35
35
  MAGIC_IDENTIFIER_DEFAULT = 0
36
+ MAGIC_IDENTIFIER_COMPRESSION = 1
37
+ NO_COMPRESSION = 0
38
+ GZIP_COMPRESSION = 1
39
+ SNAPPY_COMPRESSION = 2
36
40
  BASIC_MESSAGE_HEADER = 'NC'.freeze
37
41
  VERSION_0_HEADER = 'N'.freeze
38
42
  VERSION_1_HEADER = 'CN'.freeze
@@ -41,9 +45,10 @@ module Kafka
41
45
  attr_accessor :magic, :checksum, :payload
42
46
 
43
47
  def initialize(payload = nil, magic = MAGIC_IDENTIFIER_DEFAULT, checksum = nil)
44
- self.magic = magic
45
- self.payload = payload || ""
46
- self.checksum = checksum || self.calculate_checksum
48
+ self.magic = magic
49
+ self.payload = payload || ""
50
+ self.checksum = checksum || self.calculate_checksum
51
+ @compression = NO_COMPRESSION
47
52
  end
48
53
 
49
54
  def calculate_checksum
@@ -66,7 +71,7 @@ module Kafka
66
71
  break if bytes_processed + message_size + 4 > data.length # message is truncated
67
72
 
68
73
  case magic
69
- when 0
74
+ when MAGIC_IDENTIFIER_DEFAULT
70
75
  # | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 ...
71
76
  # | | | |
72
77
  # | message_size |magic| checksum | payload ...
@@ -75,7 +80,7 @@ module Kafka
75
80
  payload = data[bytes_processed + 9, payload_size]
76
81
  messages << Kafka::Message.new(payload, magic, checksum)
77
82
 
78
- when 1
83
+ when MAGIC_IDENTIFIER_COMPRESSION
79
84
  # | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 ...
80
85
  # | | | | |
81
86
  # | size |magic|attrs| checksum | payload ...
@@ -84,18 +89,22 @@ module Kafka
84
89
  payload = data[bytes_processed + 10, payload_size]
85
90
 
86
91
  case attributes & COMPRESSION_CODEC_MASK
87
- when 0 # a single uncompressed message
92
+ when NO_COMPRESSION # a single uncompressed message
88
93
  messages << Kafka::Message.new(payload, magic, checksum)
89
- when 1 # a gzip-compressed message set -- parse recursively
94
+ when GZIP_COMPRESSION # a gzip-compressed message set -- parse recursively
90
95
  uncompressed = Zlib::GzipReader.new(StringIO.new(payload)).read
91
96
  message_set = parse_from(uncompressed)
92
97
  raise 'malformed compressed message' if message_set.size != uncompressed.size
93
98
  messages.concat(message_set.messages)
99
+ when SNAPPY_COMPRESSION # a snappy-compresses message set -- parse recursively
100
+ ensure_snappy! do
101
+ uncompressed = Snappy::Reader.new(StringIO.new(payload)).read
102
+ message_set = parse_from(uncompressed)
103
+ raise 'malformed compressed message' if message_set.size != uncompressed.size
104
+ messages.concat(message_set.messages)
105
+ end
94
106
  else
95
107
  # https://cwiki.apache.org/confluence/display/KAFKA/Compression
96
- # claims that 2 is for Snappy compression, but Kafka's Scala client
97
- # implementation doesn't seem to support it yet, so I don't have
98
- # a reference implementation to test against.
99
108
  raise "Unsupported Kafka compression codec: #{attributes & COMPRESSION_CODEC_MASK}"
100
109
  end
101
110
 
@@ -108,10 +117,93 @@ module Kafka
108
117
 
109
118
  MessageSet.new(bytes_processed, messages)
110
119
  end
111
- end
112
120
 
113
- # Encapsulates a list of Kafka messages (as Kafka::Message objects in the
114
- # +messages+ attribute) and their total serialized size in bytes (the +size+
115
- # attribute).
116
- class MessageSet < Struct.new(:size, :messages); end
121
+ def encode(compression = NO_COMPRESSION)
122
+ @compression = compression
123
+
124
+ self.payload = asciify_payload
125
+ self.payload = compress_payload if compression?
126
+
127
+ data = magic_and_compression + [calculate_checksum].pack("N") + payload
128
+ [data.length].pack("N") + data
129
+ end
130
+
131
+
132
+ # Encapsulates a list of Kafka messages (as Kafka::Message objects in the
133
+ # +messages+ attribute) and their total serialized size in bytes (the +size+
134
+ # attribute).
135
+ class MessageSet < Struct.new(:size, :messages); end
136
+
137
+ def self.ensure_snappy!
138
+ if Object.const_defined? "Snappy"
139
+ yield
140
+ else
141
+ fail "Snappy not available!"
142
+ end
143
+ end
144
+
145
+ def ensure_snappy! &block
146
+ self.class.ensure_snappy! &block
147
+ end
148
+
149
+ private
150
+
151
+ attr_reader :compression
152
+
153
+ def compression?
154
+ compression != NO_COMPRESSION
155
+ end
156
+
157
+ def magic_and_compression
158
+ if compression?
159
+ [MAGIC_IDENTIFIER_COMPRESSION, compression].pack("CC")
160
+ else
161
+ [MAGIC_IDENTIFIER_DEFAULT].pack("C")
162
+ end
163
+ end
164
+
165
+ def asciify_payload
166
+ if RUBY_VERSION[0, 3] == "1.8"
167
+ payload
168
+ else
169
+ payload.to_s.force_encoding(Encoding::ASCII_8BIT)
170
+ end
171
+ end
172
+
173
+ def compress_payload
174
+ case compression
175
+ when GZIP_COMPRESSION
176
+ gzip
177
+ when SNAPPY_COMPRESSION
178
+ snappy
179
+ end
180
+ end
181
+
182
+ def gzip
183
+ with_buffer do |buffer|
184
+ gz = Zlib::GzipWriter.new buffer, nil, nil
185
+ gz.write payload
186
+ gz.close
187
+ end
188
+ end
189
+
190
+ def snappy
191
+ ensure_snappy! do
192
+ with_buffer do |buffer|
193
+ Snappy::Writer.new buffer do |w|
194
+ w << payload
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ def with_buffer
201
+ buffer = StringIO.new
202
+ buffer.set_encoding Encoding::ASCII_8BIT unless RUBY_VERSION =~ /^1\.8/
203
+ yield buffer if block_given?
204
+ buffer.rewind
205
+ buffer.string
206
+ end
207
+ end
117
208
  end
209
+
@@ -19,16 +19,17 @@ module Kafka
19
19
  def initialize(options={})
20
20
  self.host = options[:host] || HOST
21
21
  self.port = options[:port] || PORT
22
+ self.compression = options[:compression] || Message::NO_COMPRESSION
22
23
  self.connect(self.host, self.port)
23
24
  end
24
25
 
25
26
  def send(topic, messages, options={})
26
27
  partition = options[:partition] || 0
27
- self.write(Encoder.produce(topic, partition, messages))
28
+ self.write(Encoder.produce(topic, partition, messages, compression))
28
29
  end
29
30
 
30
31
  def multi_send(producer_requests)
31
- self.write(Encoder.multiproduce(producer_requests))
32
+ self.write(Encoder.multiproduce(producer_requests, compression))
32
33
  end
33
34
  end
34
35
  end
@@ -20,15 +20,16 @@ module Kafka
20
20
  attr_accessor :topic, :partition
21
21
 
22
22
  def initialize(options = {})
23
- self.topic = options[:topic] || "test"
24
- self.partition = options[:partition] || 0
25
- self.host = options[:host] || HOST
26
- self.port = options[:port] || PORT
23
+ self.topic = options[:topic] || "test"
24
+ self.partition = options[:partition] || 0
25
+ self.host = options[:host] || HOST
26
+ self.port = options[:port] || PORT
27
+ self.compression = options[:compression] || Message::NO_COMPRESSION
27
28
  self.connect(self.host, self.port)
28
29
  end
29
30
 
30
31
  def send(messages)
31
- self.write(Encoder.produce(self.topic, self.partition, messages))
32
+ self.write(Encoder.produce(self.topic, self.partition, messages, compression))
32
33
  end
33
34
 
34
35
  def batch(&block)
@@ -39,12 +39,73 @@ describe Encoder do
39
39
  encoded = described_class.message(message)
40
40
  message = Kafka::Message.parse_from(encoded).messages.first
41
41
  if RUBY_VERSION[0,3] == "1.8" # Use old iconv on Ruby 1.8 for encoding
42
- ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
43
- ic.iconv(message.payload).should eql("ümlaut")
42
+ #ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
43
+ #ic.iconv(message.payload).should eql("ümlaut")
44
+ message.payload.should eql("ümlaut")
44
45
  else
45
46
  message.payload.force_encoding(Encoding::UTF_8).should eql("ümlaut")
46
47
  end
47
48
  end
49
+
50
+ it "should encode strings containing non-ASCII characters" do
51
+ message = Kafka::Message.new("\214")
52
+ encoded = described_class.message(message)
53
+ message = Kafka::Message.parse_from(encoded).messages.first
54
+ if RUBY_VERSION[0,3] == "1.8"
55
+ message.payload.should eql("\214")
56
+ else
57
+ message.payload.force_encoding(Encoding::UTF_8).should eql("\214")
58
+ end
59
+ end
60
+ end
61
+
62
+ describe :compression do
63
+ before do
64
+ @message = Kafka::Message.new "foo"
65
+ end
66
+
67
+ it "should default to no compression" do
68
+ msg = "foo"
69
+ checksum = Zlib.crc32 msg
70
+ magic = 0
71
+ msg_size = 5 + msg.size
72
+ raw = [msg_size, magic, checksum, msg].pack "NCNa#{msg.size}"
73
+
74
+ Encoder.message(@message).should == raw
75
+ end
76
+
77
+ it "should support GZip compression" do
78
+ buffer = StringIO.new
79
+ gz = Zlib::GzipWriter.new buffer, nil, nil
80
+ gz.write "foo"
81
+ gz.close
82
+ buffer.rewind
83
+ msg = buffer.string
84
+ checksum = Zlib.crc32 msg
85
+ magic = 1
86
+ attrs = 1
87
+ msg_size = 6 + msg.size
88
+ raw = [msg_size, magic, attrs, checksum, msg].pack "NCCNa#{msg.size}"
89
+ Encoder.message(@message, 1).should == raw
90
+ end
91
+
92
+ if Object.const_defined? "Snappy"
93
+ it "should support Snappy compression" do
94
+ buffer = StringIO.new
95
+ Snappy::Writer.new buffer do |w|
96
+ w << "foo"
97
+ end
98
+ buffer.rewind
99
+ msg = buffer.string
100
+ checksum = Zlib.crc32 msg
101
+ magic = 1
102
+ attrs = 2
103
+ msg_size = 6 + msg.size
104
+ raw = [msg_size, magic, attrs, checksum, msg].pack "NCCNa#{msg.size}"
105
+
106
+ Encoder.message(@message, 2).should == raw
107
+ end
108
+ end
48
109
  end
49
110
 
50
111
  describe "produce" do
@@ -75,6 +136,23 @@ describe Encoder do
75
136
  end
76
137
  end
77
138
 
139
+ describe "message_set" do
140
+ it "should compress messages into a message set" do
141
+ message_one = Kafka::Message.new "foo"
142
+ message_two = Kafka::Message.new "bar"
143
+ bytes = described_class.message_set [message_one, message_two], Kafka::Message::GZIP_COMPRESSION
144
+
145
+ messages = Kafka::Message.parse_from bytes
146
+ messages.should be_a Kafka::Message::MessageSet
147
+ messages.messages.size.should == 2
148
+
149
+ messages.messages[0].should be_a Kafka::Message
150
+ messages.messages[0].payload.should == "foo"
151
+ messages.messages[1].should be_a Kafka::Message
152
+ messages.messages[1].payload.should == "bar"
153
+ end
154
+ end
155
+
78
156
  describe "multiproduce" do
79
157
  it "encodes an empty request" do
80
158
  bytes = described_class.multiproduce([])
@@ -135,7 +213,7 @@ describe Encoder do
135
213
  messages = [Kafka::Message.new("ale"), Kafka::Message.new("beer")]
136
214
  bytes = described_class.multiproduce([
137
215
  Kafka::ProducerRequest.new("test", messages[0]),
138
- Kafka::ProducerRequest.new("topic", messages[1], partition: 1),
216
+ Kafka::ProducerRequest.new("topic", messages[1], :partition => 1),
139
217
  ])
140
218
 
141
219
  req_length = bytes[0, 4].unpack("N").shift
@@ -15,7 +15,6 @@
15
15
  require File.dirname(__FILE__) + '/spec_helper'
16
16
 
17
17
  describe Kafka do
18
-
19
18
  before(:each) do
20
19
  end
21
20
  end
@@ -16,6 +16,10 @@ require File.dirname(__FILE__) + '/spec_helper'
16
16
 
17
17
  describe Message do
18
18
 
19
+ def pack_v1_message bytes, attributes
20
+ [6 + bytes.length, 1, attributes, Zlib.crc32(bytes), bytes].pack "NCCNa*"
21
+ end
22
+
19
23
  before(:each) do
20
24
  @message = Message.new
21
25
  end
@@ -120,7 +124,36 @@ describe Message do
120
124
  message.payload.should == 'abracadabra'
121
125
  end
122
126
 
123
- it "should recursively parse nested compressed messages" do
127
+ if Object.const_defined? "Snappy"
128
+ it "should parse a snappy-compressed message" do
129
+ cleartext = "abracadabra"
130
+ bytes = pack_v1_message cleartext, 0
131
+ compressed = Snappy.deflate(bytes)
132
+ bytes = pack_v1_message compressed, 2
133
+ message = Message.parse_from(bytes).messages.first
134
+ message.should be_valid
135
+ message.payload.should == cleartext
136
+ end
137
+
138
+ it "should recursively parse nested snappy compressed messages" do
139
+ uncompressed = pack_v1_message('abracadabra', 0)
140
+ uncompressed << pack_v1_message('foobar', 0)
141
+ compressed = pack_v1_message(Snappy.deflate(uncompressed), 2)
142
+ messages = Message.parse_from(compressed).messages
143
+ messages.map(&:payload).should == ['abracadabra', 'foobar']
144
+ messages.map(&:valid?).should == [true, true]
145
+ end
146
+
147
+ it "should support a mixture of snappy compressed and uncompressed messages" do
148
+ bytes = pack_v1_message(Snappy.deflate(pack_v1_message("compressed", 0)), 2)
149
+ bytes << pack_v1_message('uncompressed', 0)
150
+ messages = Message.parse_from(bytes).messages
151
+ messages.map(&:payload).should == ["compressed", "uncompressed"]
152
+ messages.map(&:valid?).should == [true, true]
153
+ end
154
+ end
155
+
156
+ it "should recursively parse nested gzip compressed messages" do
124
157
  uncompressed = [17, 1, 0, 401275319, 'abracadabra'].pack('NCCNa*')
125
158
  uncompressed << [12, 1, 0, 2666930069, 'foobar'].pack('NCCNa*')
126
159
  compressed_io = StringIO.new('')
@@ -132,7 +165,7 @@ describe Message do
132
165
  messages.map(&:valid?).should == [true, true]
133
166
  end
134
167
 
135
- it "should support a mixture of compressed and uncompressed messages" do
168
+ it "should support a mixture of gzip compressed and uncompressed messages" do
136
169
  compressed = 'H4sIAG0LI1AAA2NgYBBkZBB/9XN7YlJRYnJiCogCAH9lueQVAAAA'.unpack('m*').shift
137
170
  bytes = [45, 1, 1, 1303540914, compressed].pack('NCCNa*')
138
171
  bytes << [11, 1, 0, 907060870, 'hello'].pack('NCCNa*')
@@ -142,10 +175,53 @@ describe Message do
142
175
  end
143
176
 
144
177
  it "should raise an error if the compression codec is not supported" do
145
- bytes = [6, 1, 2, 0, ''].pack('NCCNa*') # 2 = Snappy codec
178
+ bytes = [6, 1, 3, 0, ''].pack('NCCNa*') # 3 = some unknown future compression codec
146
179
  lambda {
147
180
  Kafka::Message.parse_from(bytes)
148
181
  }.should raise_error(RuntimeError, /Unsupported Kafka compression codec/)
149
182
  end
150
183
  end
184
+
185
+ describe "#ensure_snappy!" do
186
+ let(:message) { Kafka::Message.new }
187
+ before { Kafka::Message.instance_variable_set :@snappy, nil }
188
+
189
+ subject { message.ensure_snappy! { 42 } }
190
+
191
+ if Object.const_defined? "Snappy"
192
+ context "when snappy is available" do
193
+ before { Object.stub! :const_defined? => true }
194
+ it { should == 42 }
195
+ end
196
+ end
197
+
198
+ context "when snappy is not available" do
199
+ before { Object.stub! :const_defined? => false }
200
+
201
+ it "raises an error" do
202
+ expect { message.ensure_snappy! { 42 } }.to raise_error
203
+ end
204
+ end
205
+ end
206
+
207
+ describe ".ensure_snappy!" do
208
+ before { Kafka::Message.instance_variable_set :@snappy, nil }
209
+
210
+ subject { Kafka::Message.ensure_snappy! { 42 } }
211
+
212
+ if Object.const_defined? "Snappy"
213
+ context "when snappy is available" do
214
+ before { Object.stub! :const_defined? => true }
215
+ it { should == 42 }
216
+ end
217
+ end
218
+
219
+ context "when snappy is not available" do
220
+ before { Object.stub! :const_defined? => false }
221
+
222
+ it "raises an error" do
223
+ expect { Kafka::Message.ensure_snappy! { 42 } }.to raise_error
224
+ end
225
+ end
226
+ end
151
227
  end
@@ -27,12 +27,18 @@ describe MultiProducer do
27
27
  subject.port.should eql(9092)
28
28
  end
29
29
 
30
+ it "should have compression" do
31
+ subject.should respond_to :compression
32
+ described_class.new(:compression => Kafka::Message::SNAPPY_COMPRESSION).compression.should == Kafka::Message::SNAPPY_COMPRESSION
33
+ described_class.new.compression.should == Kafka::Message::NO_COMPRESSION
34
+ end
35
+
30
36
  it "sends single messages" do
31
37
  message = Kafka::Message.new("ale")
32
38
  encoded = Kafka::Encoder.produce("test", 0, message)
33
39
 
34
40
  subject.should_receive(:write).with(encoded).and_return(encoded.length)
35
- subject.send("test", message, partition: 0).should == encoded.length
41
+ subject.send("test", message, :partition => 0).should == encoded.length
36
42
  end
37
43
 
38
44
  it "sends multiple messages" do
@@ -46,5 +52,23 @@ describe MultiProducer do
46
52
  subject.should_receive(:write).with(encoded).and_return(encoded.length)
47
53
  subject.multi_send(reqs).should == encoded.length
48
54
  end
55
+
56
+ it "should compress messages" do
57
+ subject.compression = Kafka::Message::SNAPPY_COMPRESSION
58
+ @mocked_socket.stub! :write => 0
59
+ messages = [Kafka::Message.new("ale"), Kafka::Message.new("beer")]
60
+
61
+ encoded = Encoder.produce("test", 0, messages[0])
62
+ Encoder.should_receive(:produce).with("test", 0, messages[0], subject.compression).and_return encoded
63
+ subject.send("test", messages[0], :partition => 0)
64
+
65
+ reqs = [
66
+ Kafka::ProducerRequest.new("topic", messages[0]),
67
+ Kafka::ProducerRequest.new("topic", messages[1]),
68
+ ]
69
+ encoded = Encoder.multiproduce(reqs)
70
+ Encoder.should_receive(:multiproduce).with(reqs, subject.compression)
71
+ subject.multi_send(reqs)
72
+ end
49
73
  end
50
74
  end
@@ -32,7 +32,7 @@ describe ProducerRequest do
32
32
  end
33
33
 
34
34
  it "can use a user-specified partition" do
35
- req = described_class.new("topic", message, partition: 42)
35
+ req = described_class.new("topic", message, :partition => 42)
36
36
  req.partition.should == 42
37
37
  end
38
38
  end
@@ -30,6 +30,12 @@ describe Producer do
30
30
  @producer.should respond_to(:partition)
31
31
  end
32
32
 
33
+ it "should have compression" do
34
+ @producer.should respond_to :compression
35
+ Producer.new(:compression => 1).compression.should == 1
36
+ Producer.new.compression.should == 0
37
+ end
38
+
33
39
  it "should set a topic and partition on initialize" do
34
40
  @producer = Producer.new({ :host => "localhost", :port => 9092, :topic => "testing" })
35
41
  @producer.topic.should eql("testing")
metadata CHANGED
@@ -1,10 +1,14 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: kafka-rb
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.11
5
- prerelease:
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 12
9
+ version: 0.0.12
6
10
  platform: ruby
7
- authors:
11
+ authors:
8
12
  - Alejandro Crosa
9
13
  - Stefan Mees
10
14
  - Tim Lossen
@@ -12,32 +16,31 @@ authors:
12
16
  autorequire: kafka-rb
13
17
  bindir: bin
14
18
  cert_chain: []
15
- date: 2012-09-12 00:00:00.000000000 Z
16
- dependencies:
17
- - !ruby/object:Gem::Dependency
19
+
20
+ date: 2012-12-19 00:00:00 -08:00
21
+ default_executable:
22
+ dependencies:
23
+ - !ruby/object:Gem::Dependency
18
24
  name: rspec
19
- requirement: !ruby/object:Gem::Requirement
20
- none: false
21
- requirements:
22
- - - ! '>='
23
- - !ruby/object:Gem::Version
24
- version: '0'
25
- type: :development
26
25
  prerelease: false
27
- version_requirements: !ruby/object:Gem::Requirement
28
- none: false
29
- requirements:
30
- - - ! '>='
31
- - !ruby/object:Gem::Version
32
- version: '0'
33
- description: kafka-rb allows you to produce and consume messages using the Kafka distributed
34
- publish/subscribe messaging service.
26
+ requirement: &id001 !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ description: kafka-rb allows you to produce and consume messages using the Kafka distributed publish/subscribe messaging service.
35
36
  email:
36
37
  executables: []
38
+
37
39
  extensions: []
38
- extra_rdoc_files:
40
+
41
+ extra_rdoc_files:
39
42
  - LICENSE
40
- files:
43
+ files:
41
44
  - LICENSE
42
45
  - README.md
43
46
  - Rakefile
@@ -52,41 +55,37 @@ files:
52
55
  - lib/kafka/producer_request.rb
53
56
  - lib/kafka/request_type.rb
54
57
  - lib/kafka.rb
55
- - spec/batch_spec.rb
56
- - spec/consumer_spec.rb
57
- - spec/encoder_spec.rb
58
- - spec/io_spec.rb
59
- - spec/kafka_spec.rb
60
- - spec/message_spec.rb
61
- - spec/multi_producer_spec.rb
62
- - spec/producer_request_spec.rb
63
- - spec/producer_spec.rb
64
- - spec/spec_helper.rb
58
+ has_rdoc: true
65
59
  homepage: http://github.com/acrosa/kafka-rb
66
60
  licenses: []
61
+
67
62
  post_install_message:
68
63
  rdoc_options: []
69
- require_paths:
64
+
65
+ require_paths:
70
66
  - lib
71
- required_ruby_version: !ruby/object:Gem::Requirement
72
- none: false
73
- requirements:
74
- - - ! '>='
75
- - !ruby/object:Gem::Version
76
- version: '0'
77
- required_rubygems_version: !ruby/object:Gem::Requirement
78
- none: false
79
- requirements:
80
- - - ! '>='
81
- - !ruby/object:Gem::Version
82
- version: '0'
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ segments:
79
+ - 0
80
+ version: "0"
83
81
  requirements: []
82
+
84
83
  rubyforge_project:
85
- rubygems_version: 1.8.24
84
+ rubygems_version: 1.3.6
86
85
  signing_key:
87
86
  specification_version: 3
88
87
  summary: A Ruby client for the Kafka distributed publish/subscribe messaging service
89
- test_files:
88
+ test_files:
90
89
  - spec/batch_spec.rb
91
90
  - spec/consumer_spec.rb
92
91
  - spec/encoder_spec.rb