kafka-rb 0.0.11 → 0.0.12

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/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