logstash-codec-protobuf 1.3.0-java
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 +7 -0
- data/CHANGELOG.md +56 -0
- data/CONTRIBUTORS +12 -0
- data/DEVELOPER.md +2 -0
- data/Gemfile +11 -0
- data/LICENSE +202 -0
- data/NOTICE.TXT +4 -0
- data/README.md +184 -0
- data/docs/index.asciidoc +241 -0
- data/google-protobuf-lib-update.md +57 -0
- data/lib/logstash/codecs/protobuf.rb +804 -0
- data/logstash-codec-protobuf.gemspec +33 -0
- data/spec/codecs/pb2_spec.rb +236 -0
- data/spec/codecs/pb3_decode_spec.rb +665 -0
- data/spec/codecs/pb3_encode_spec.rb +243 -0
- data/spec/helpers/pb2/ColourTestcase.pb.rb +35 -0
- data/spec/helpers/pb2/ColourTestcase.proto +24 -0
- data/spec/helpers/pb2/event.pb.rb +19 -0
- data/spec/helpers/pb2/event.proto +12 -0
- data/spec/helpers/pb2/header/header.pb.rb +16 -0
- data/spec/helpers/pb2/header/header.proto +8 -0
- data/spec/helpers/pb2/human.pb.rb +26 -0
- data/spec/helpers/pb2/unicorn.pb.rb +19 -0
- data/spec/helpers/pb2/unicorn_event.pb.rb +24 -0
- data/spec/helpers/pb3/FantasyHorse_pb.rb +48 -0
- data/spec/helpers/pb3/PhoneDirectory_pb.rb +37 -0
- data/spec/helpers/pb3/ProbeResult_pb.rb +26 -0
- data/spec/helpers/pb3/ResultListComposerRequest_pb.rb +25 -0
- data/spec/helpers/pb3/dnsmessage_pb.rb +82 -0
- data/spec/helpers/pb3/events_pb.rb +17 -0
- data/spec/helpers/pb3/header/header.proto3 +7 -0
- data/spec/helpers/pb3/header/header_pb.rb +12 -0
- data/spec/helpers/pb3/integertest_pb.rb +18 -0
- data/spec/helpers/pb3/messageA_pb.rb +16 -0
- data/spec/helpers/pb3/messageB_pb.rb +15 -0
- data/spec/helpers/pb3/rum2_pb.rb +87 -0
- data/spec/helpers/pb3/rum3_pb.rb +87 -0
- data/spec/helpers/pb3/rum_pb.rb +87 -0
- data/spec/helpers/pb3/struct_test_pb.rb +21 -0
- data/spec/helpers/pb3/unicorn_pb.rb +31 -0
- metadata +175 -0
@@ -0,0 +1,665 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "logstash/devutils/rspec/spec_helper"
|
3
|
+
require "logstash/codecs/protobuf"
|
4
|
+
require "logstash/event"
|
5
|
+
|
6
|
+
require 'google/protobuf' # for protobuf3
|
7
|
+
|
8
|
+
# absolute path to the protobuf helpers directory
|
9
|
+
pb_include_path = File.expand_path(".") + "/spec/helpers"
|
10
|
+
pb_include_path.freeze
|
11
|
+
|
12
|
+
# Include the protobuf definitions so that we can reference the classes
|
13
|
+
# directly instead of looking them up in the pb decriptor pool
|
14
|
+
['./pb3/header/*.rb', './pb3/*.rb'].each do | d |
|
15
|
+
Dir.glob(pb_include_path + d).each do |file|
|
16
|
+
require file
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe LogStash::Codecs::Protobuf do
|
21
|
+
|
22
|
+
context ".reloadable?" do
|
23
|
+
subject do
|
24
|
+
next LogStash::Codecs::Protobuf.new(
|
25
|
+
"class_name" => "Unicorn",
|
26
|
+
"include_path" => [pb_include_path + '/pb3/unicorn_pb.rb'],
|
27
|
+
"protobuf_version" => 3
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "returns false" do
|
32
|
+
expect(subject.reloadable?).to be_falsey
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
##################################################
|
37
|
+
|
38
|
+
context "config" do
|
39
|
+
context "using class_file and include_path" do
|
40
|
+
let(:plugin) {
|
41
|
+
LogStash::Codecs::Protobuf.new(
|
42
|
+
"class_name" => "Unicorn",
|
43
|
+
"include_path" => [pb_include_path + '/pb3/unicorn_pb.rb'],
|
44
|
+
"class_file" => pb_include_path + '/pb3/unicorn_pb.rb',
|
45
|
+
"protobuf_version" => 3
|
46
|
+
)
|
47
|
+
}
|
48
|
+
|
49
|
+
it "should fail to register the plugin with ConfigurationError" do
|
50
|
+
expect {plugin.register}.to raise_error(LogStash::ConfigurationError, /`include_path` and `class_file`/)
|
51
|
+
end # it
|
52
|
+
end
|
53
|
+
|
54
|
+
context "not using class_file or include_path" do
|
55
|
+
let(:plugin) {
|
56
|
+
LogStash::Codecs::Protobuf.new("class_name" => "Unicorn")
|
57
|
+
}
|
58
|
+
|
59
|
+
it "should fail to register the plugin with ConfigurationError" do
|
60
|
+
expect {plugin.register}.to raise_error(LogStash::ConfigurationError, /`include_path` or `class_file`/)
|
61
|
+
end # it
|
62
|
+
end
|
63
|
+
|
64
|
+
RSpec::Expectations.configuration.on_potential_false_positives = :nothing
|
65
|
+
|
66
|
+
context "re-registering the plugin with a valid configuration" do
|
67
|
+
let(:plugin) { LogStash::Codecs::Protobuf.new(
|
68
|
+
"class_name" => "A.MessageA",
|
69
|
+
"class_file" => [ pb_include_path + '/pb3/messageA_pb.rb' ],
|
70
|
+
"protobuf_version" => 3,
|
71
|
+
"protobuf_root_directory" => File.expand_path(File.dirname(__FILE__) + pb_include_path + '/pb3/'))
|
72
|
+
}
|
73
|
+
|
74
|
+
it "should not fail" do
|
75
|
+
expect {
|
76
|
+
# this triggers the `register()` method of the plugin multiple times
|
77
|
+
plugin.register
|
78
|
+
plugin.register
|
79
|
+
}.not_to raise_error(RuntimeError)
|
80
|
+
end # it
|
81
|
+
end
|
82
|
+
|
83
|
+
end # context config
|
84
|
+
|
85
|
+
##################################################
|
86
|
+
|
87
|
+
context "#pb3decoder_test1" do
|
88
|
+
|
89
|
+
# Test case 1: Decode simple protobuf
|
90
|
+
let(:plugin_unicorn) { LogStash::Codecs::Protobuf.new(
|
91
|
+
"class_name" => "Unicorn", "include_path" => [pb_include_path + '/pb3/unicorn_pb.rb'], "protobuf_version" => 3)
|
92
|
+
}
|
93
|
+
|
94
|
+
it "should return an event from protobuf data" do
|
95
|
+
|
96
|
+
data = {:name => 'Pinkie', :age => 18, :is_pegasus => false, :favourite_numbers => [4711,23],
|
97
|
+
:fur_colour => Colour::PINK, :favourite_colours => [Colour::GREEN, Colour::BLUE]
|
98
|
+
}
|
99
|
+
|
100
|
+
unicorn_object = Unicorn.new(data)
|
101
|
+
bin = Unicorn.encode(unicorn_object)
|
102
|
+
plugin_unicorn.decode(bin) do |event|
|
103
|
+
expect(event.get("name")).to eq(data[:name] )
|
104
|
+
expect(event.get("age")).to eq(data[:age])
|
105
|
+
expect(event.get("fur_colour")).to eq("PINK")
|
106
|
+
expect(event.get("favourite_numbers")).to eq(data[:favourite_numbers])
|
107
|
+
expect(event.get("favourite_colours")).to eq(["GREEN","BLUE"])
|
108
|
+
expect(event.get("is_pegasus")).to eq(data[:is_pegasus] )
|
109
|
+
end
|
110
|
+
end # it
|
111
|
+
end # context
|
112
|
+
|
113
|
+
##################################################
|
114
|
+
|
115
|
+
context "#pb3decoder_test2" do
|
116
|
+
|
117
|
+
# Test case 2: decode nested protobuf
|
118
|
+
let(:plugin_unicorn) { LogStash::Codecs::Protobuf.new("class_name" => "Unicorn",
|
119
|
+
"include_path" => [pb_include_path + '/pb3/unicorn_pb.rb'], "protobuf_version" => 3) }
|
120
|
+
|
121
|
+
it "should return an event from protobuf data with nested classes" do
|
122
|
+
father = Unicorn.new({:name=> "Sparkle", :age => 50, :fur_colour => 3 })
|
123
|
+
data = {:name => 'Glitter', :fur_colour => Colour::GLITTER, :father => father}
|
124
|
+
|
125
|
+
unicorn_object = Unicorn.new(data)
|
126
|
+
bin = Unicorn.encode(unicorn_object)
|
127
|
+
plugin_unicorn.decode(bin) do |event|
|
128
|
+
expect(event.get("name")).to eq(data[:name] )
|
129
|
+
expect(event.get("fur_colour")).to eq("GLITTER" )
|
130
|
+
expect(event.get("father")["name"]).to eq(data[:father][:name] )
|
131
|
+
expect(event.get("father")["age"]).to eq(data[:father][:age] )
|
132
|
+
expect(event.get("father")["fur_colour"]).to eq("SILVER")
|
133
|
+
|
134
|
+
end
|
135
|
+
end # it
|
136
|
+
|
137
|
+
end # context
|
138
|
+
|
139
|
+
##################################################
|
140
|
+
|
141
|
+
context "#pb3decoder_test3" do
|
142
|
+
|
143
|
+
# Test case 3: decode ProbeResult
|
144
|
+
let(:plugin_3) { LogStash::Codecs::Protobuf.new("class_name" => "ProbeResult",
|
145
|
+
"include_path" => [pb_include_path + '/pb3/ProbeResult_pb.rb'], "protobuf_version" => 3) }
|
146
|
+
|
147
|
+
before do
|
148
|
+
plugin_3.register
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should return an event from protobuf data with nested classes" do
|
152
|
+
ping_result_data = {:status=> PingIPv4Result::Status::ERROR,
|
153
|
+
:latency => 50, :ip => "8.8.8.8", :probe_ip => "127.0.0.1", :geolocation => "New York City" }
|
154
|
+
ping_result_object = PingIPv4Result.new(ping_result_data)
|
155
|
+
|
156
|
+
probe_result_data = {:UUID => '12345678901233456789', :TaskPingIPv4Result => ping_result_object}
|
157
|
+
probe_result_object = ProbeResult.new(probe_result_data)
|
158
|
+
bin = ProbeResult.encode(probe_result_object)
|
159
|
+
plugin_3.decode(bin) do |event|
|
160
|
+
expect(event.get("UUID")).to eq(probe_result_data[:UUID] )
|
161
|
+
expect(event.get("TaskPingIPv4Result")["status"]).to eq("ERROR")
|
162
|
+
expect(event.get("TaskPingIPv4Result")["latency"]).to eq(ping_result_data[:latency] )
|
163
|
+
expect(event.get("TaskPingIPv4Result")["ip"]).to eq(ping_result_data[:ip] )
|
164
|
+
expect(event.get("TaskPingIPv4Result")["probe_ip"]).to eq(ping_result_data[:probe_ip] )
|
165
|
+
expect(event.get("TaskPingIPv4Result")["geolocation"]).to eq(ping_result_data[:geolocation] )
|
166
|
+
end
|
167
|
+
end # it
|
168
|
+
end # context #pb3decoder_test3
|
169
|
+
|
170
|
+
##################################################
|
171
|
+
|
172
|
+
context "#pb3decoder_test4" do
|
173
|
+
|
174
|
+
# Test case 4: decode PBDNSMessage
|
175
|
+
let(:plugin_4) { LogStash::Codecs::Protobuf.new("class_name" => "PBDNSMessage",
|
176
|
+
"include_path" => [pb_include_path + '/pb3/dnsmessage_pb.rb'], "protobuf_version" => 3) }
|
177
|
+
|
178
|
+
before do
|
179
|
+
plugin_4.register
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should return an event from protobuf data with nested classes" do
|
183
|
+
dns_question_data = {:qName => "Foo", :qType => 12345, :qClass => 67890 }
|
184
|
+
|
185
|
+
dns_response_data = {:rcode => 12345, :appliedPolicy => "baz", :tags => ["a","b","c"],
|
186
|
+
:queryTimeSec => 123, :queryTimeUsec => 456,
|
187
|
+
:appliedPolicyType => PBDNSMessage::PolicyType::NSIP}
|
188
|
+
|
189
|
+
dns_rr_data = [
|
190
|
+
{:name => "abc", :type => 9000, :class => 8000, :ttl => 20, :rdata => "300"},
|
191
|
+
{:name => "def", :type => 19000, :class => 18000, :ttl => 120, :rdata => "1300"}
|
192
|
+
]
|
193
|
+
dns_response_data[:rrs] = dns_rr_data.map { | d | d = PBDNSMessage::DNSResponse::DNSRR.new(d) }
|
194
|
+
|
195
|
+
pbdns_message_data = {
|
196
|
+
# :UUID => '12345678901233456789', :TaskPingIPv4Result => ping_result_object
|
197
|
+
:type => PBDNSMessage::Type::DNSIncomingResponseType,
|
198
|
+
:messageId => "15",
|
199
|
+
:serverIdentity => "16",
|
200
|
+
:socketFamily => PBDNSMessage::SocketFamily::INET6,
|
201
|
+
:socketProtocol => PBDNSMessage::SocketProtocol::TCP,
|
202
|
+
:from => "17",
|
203
|
+
:to => "18",
|
204
|
+
:inBytes => 70000,
|
205
|
+
:timeSec => 80000,
|
206
|
+
:timeUsec => 90000,
|
207
|
+
:id => 20000,
|
208
|
+
:question => PBDNSMessage::DNSQuestion.new(dns_question_data),
|
209
|
+
:response => PBDNSMessage::DNSResponse.new(dns_response_data),
|
210
|
+
:originalRequestorSubnet => "19",
|
211
|
+
:requestorId => "Bar",
|
212
|
+
:initialRequestId => "20",
|
213
|
+
:deviceId => "21",
|
214
|
+
}
|
215
|
+
pbdns_message_object = PBDNSMessage.new(pbdns_message_data)
|
216
|
+
bin = PBDNSMessage.encode(pbdns_message_object)
|
217
|
+
plugin_4.decode(bin) do |event|
|
218
|
+
['messageId', 'serverIdentity','from','to','inBytes','timeUsec','timeSec','id', 'originalRequestorSubnet', 'requestorId' ,'initialRequestId','deviceIdf'].each { |n|
|
219
|
+
expect(event.get(n)).to eq(pbdns_message_data[n.to_sym] ) }
|
220
|
+
|
221
|
+
# enum test:
|
222
|
+
expect(event.get("type")).to eq("DNSIncomingResponseType" )
|
223
|
+
expect(event.get("socketFamily")).to eq("INET6" )
|
224
|
+
expect(event.get("socketProtocol")).to eq("TCP" )
|
225
|
+
|
226
|
+
expect(event.get("question")["qName"]).to eq(dns_question_data[:qName] )
|
227
|
+
expect(event.get("question")["qType"]).to eq(dns_question_data[:qType] )
|
228
|
+
expect(event.get("question")["qClass"]).to eq(dns_question_data[:qClass] )
|
229
|
+
|
230
|
+
['rcode', 'appliedPolicy','tags','queryTimeSec','queryTimeUsec'].each { |n| expect(event.get('response')[n]).to eq(dns_response_data[n.to_sym] ) }
|
231
|
+
expect(event.get("response")['appliedPolicyType']).to eq("NSIP" )
|
232
|
+
|
233
|
+
dns_rr_data.each_with_index { | data, index |
|
234
|
+
found = event.get("response")['rrs'][index]
|
235
|
+
['name', 'type','class','ttl','rdata'].each { |n| expect(found[n]).to eq(data[n.to_sym]) }
|
236
|
+
}
|
237
|
+
|
238
|
+
end
|
239
|
+
end # it
|
240
|
+
|
241
|
+
end # context pb3decoder_test4
|
242
|
+
|
243
|
+
##################################################
|
244
|
+
|
245
|
+
context "#pb3decoder_test5" do
|
246
|
+
|
247
|
+
# Test case 5: decode test case for github issue 17
|
248
|
+
let(:plugin_5) {
|
249
|
+
LogStash::Codecs::Protobuf.new("class_name" => "com.foo.bar.IntegerTestMessage",
|
250
|
+
"include_path" => [pb_include_path + '/pb3/integertest_pb.rb'], "protobuf_version" => 3)
|
251
|
+
}
|
252
|
+
|
253
|
+
before do
|
254
|
+
plugin_5.register
|
255
|
+
end
|
256
|
+
|
257
|
+
it "should return an event from protobuf data with nested classes" do
|
258
|
+
integertest_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("com.foo.bar.IntegerTestMessage").msgclass
|
259
|
+
integertest_object = integertest_class.new({:response_time => 500})
|
260
|
+
bin = integertest_class.encode(integertest_object)
|
261
|
+
plugin_5.decode(bin) do |event|
|
262
|
+
expect(event.get("response_time")).to eq(500)
|
263
|
+
end
|
264
|
+
end # it
|
265
|
+
|
266
|
+
end # context pb3decoder_test5
|
267
|
+
|
268
|
+
##################################################
|
269
|
+
|
270
|
+
context "#pb3decoder_test6" do
|
271
|
+
|
272
|
+
let(:execution_context) { double("execution_context")}
|
273
|
+
let(:pipeline_id) {rand(36**8).to_s(36)}
|
274
|
+
|
275
|
+
# Test case 6: decode a message automatically loading the dependencies
|
276
|
+
let(:plugin) { LogStash::Codecs::Protobuf.new(
|
277
|
+
"class_name" => "A.MessageA",
|
278
|
+
"class_file" => [ 'messageA_pb.rb' ],
|
279
|
+
"protobuf_version" => 3,
|
280
|
+
"protobuf_root_directory" => pb_include_path + '/pb3/')
|
281
|
+
}
|
282
|
+
|
283
|
+
before do
|
284
|
+
allow(plugin).to receive(:execution_context).and_return(execution_context)
|
285
|
+
allow(execution_context).to receive(:pipeline_id).and_return(pipeline_id)
|
286
|
+
|
287
|
+
# this is normally done on the input plugins. we "mock" it here to avoid
|
288
|
+
# instantiating a dummy input plugin. See
|
289
|
+
# https://github.com/ph/logstash/blob/37551a89b8137c1dc6fa4fbd992584c363a36065/logstash-core/lib/logstash/inputs/base.rb#L108
|
290
|
+
plugin.execution_context = execution_context
|
291
|
+
end
|
292
|
+
|
293
|
+
it "should return an event from protobuf data" do
|
294
|
+
header_data = {:name => {'a' => 'b'}}
|
295
|
+
header_object = Header.new(header_data)
|
296
|
+
|
297
|
+
message_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.MessageA").msgclass
|
298
|
+
data = {:name => "Test name", :header => header_object}
|
299
|
+
|
300
|
+
message_object = message_class.new(data)
|
301
|
+
bin = message_class.encode(message_object)
|
302
|
+
plugin.decode(bin) do |event|
|
303
|
+
expect(event.get("name")).to eq(data[:name] )
|
304
|
+
expect(event.get("header")['name']).to eq(header_data[:name])
|
305
|
+
end
|
306
|
+
end # it
|
307
|
+
end # context
|
308
|
+
|
309
|
+
##################################################
|
310
|
+
|
311
|
+
context "#pb3decoder_test7" do
|
312
|
+
|
313
|
+
# Test case 6: decode test case for github issue 17
|
314
|
+
let(:plugin_7) { LogStash::Codecs::Protobuf.new("class_name" => "RepeatedEvents",
|
315
|
+
"include_path" => [pb_include_path + '/pb3/events_pb.rb'], "protobuf_version" => 3) }
|
316
|
+
before do
|
317
|
+
plugin_7.register
|
318
|
+
end
|
319
|
+
|
320
|
+
it "should return an event from protobuf data with repeated top level objects" do
|
321
|
+
test_a = RepeatedEvent.new({:id => "1", :msg => "a"})
|
322
|
+
test_b = RepeatedEvent.new({:id => "2", :msg => "b"})
|
323
|
+
test_c = RepeatedEvent.new({:id => "3", :msg => "c"})
|
324
|
+
event_obj = RepeatedEvents.new({:repeated_events=>[test_a, test_b, test_c]})
|
325
|
+
bin = RepeatedEvents.encode(event_obj)
|
326
|
+
plugin_7.decode(bin) do |event|
|
327
|
+
expect(event.get("repeated_events").size ).to eq(3)
|
328
|
+
expect(event.get("repeated_events")[0]["id"]).to eq("1")
|
329
|
+
expect(event.get("repeated_events")[2]["id"]).to eq("3")
|
330
|
+
expect(event.get("repeated_events")[0]["msg"]).to eq("a")
|
331
|
+
expect(event.get("repeated_events")[2]["msg"]).to eq("c")
|
332
|
+
end
|
333
|
+
end # it
|
334
|
+
|
335
|
+
end # context pb3decoder_test7
|
336
|
+
|
337
|
+
##################################################
|
338
|
+
|
339
|
+
context "#pb3decoder_test8a" do
|
340
|
+
|
341
|
+
let(:plugin_8a) { LogStash::Codecs::Protobuf.new("class_name" => "FantasyHorse", "class_file" => 'pb3/FantasyHorse_pb.rb',
|
342
|
+
"protobuf_root_directory" => pb_include_path, "protobuf_version" => 3, "pb3_set_oneof_metainfo" => true) }
|
343
|
+
before do
|
344
|
+
plugin_8a.register
|
345
|
+
end
|
346
|
+
|
347
|
+
it "should add meta information on oneof fields" do
|
348
|
+
pegasus_data = {:wings_length => 100}
|
349
|
+
horsey = FantasyPegasus.new(pegasus_data)
|
350
|
+
|
351
|
+
braid_data = {:braid_thickness => 10, :braiding_style => "french"}
|
352
|
+
tail_data = {:tail_length => 80, :braided => BraidedHorseTail.new(braid_data) }
|
353
|
+
tail = FantasyHorseTail.new(tail_data)
|
354
|
+
|
355
|
+
data = {:name=>"Reinhold", :pegasus => horsey, :tail => tail}
|
356
|
+
pb_obj = FantasyHorse.new(data)
|
357
|
+
bin = FantasyHorse.encode(pb_obj)
|
358
|
+
plugin_8a.decode(bin) do |event|
|
359
|
+
|
360
|
+
expect(event.get("name")).to eq(data[:name])
|
361
|
+
expect(event.get("pegasus")["wings_length"]).to eq(pegasus_data[:wings_length])
|
362
|
+
expect(event.get("tail")['tail_length']).to eq(tail_data[:tail_length])
|
363
|
+
expect(event.get("tail")['braided']['braiding_style']).to eq(braid_data[:braiding_style])
|
364
|
+
expect(event.get("@metadata")["pb_oneof"]["horse_type"]).to eq("pegasus")
|
365
|
+
expect(event.get("@metadata")["pb_oneof"]["tail"]["hair_type"]).to eq("braided")
|
366
|
+
|
367
|
+
end
|
368
|
+
end # it
|
369
|
+
|
370
|
+
end # context pb3decoder_test8a
|
371
|
+
|
372
|
+
##################################################
|
373
|
+
|
374
|
+
context "#pb3decoder_test8b" do
|
375
|
+
|
376
|
+
# same test as 8a just with different one_of options selected
|
377
|
+
|
378
|
+
let(:plugin_8b) { LogStash::Codecs::Protobuf.new("class_name" => "FantasyHorse", "class_file" => 'pb3/FantasyHorse_pb.rb',
|
379
|
+
"protobuf_root_directory" => pb_include_path, "protobuf_version" => 3, "pb3_set_oneof_metainfo" => false) }
|
380
|
+
before do
|
381
|
+
plugin_8b.register
|
382
|
+
end
|
383
|
+
|
384
|
+
it "should not add meta information on oneof fields" do
|
385
|
+
pegasus_data = {:wings_length => 100}
|
386
|
+
horsey = FantasyPegasus.new(pegasus_data)
|
387
|
+
|
388
|
+
braid_data = {:braid_thickness => 10, :braiding_style => "french"}
|
389
|
+
tail_data = {:tail_length => 80, :braided => BraidedHorseTail.new(braid_data) }
|
390
|
+
tail = FantasyHorseTail.new(tail_data)
|
391
|
+
|
392
|
+
data = {:name=>"Winfried", :pegasus => horsey, :tail => tail}
|
393
|
+
pb_obj = FantasyHorse.new(data)
|
394
|
+
bin = FantasyHorse.encode(pb_obj)
|
395
|
+
plugin_8b.decode(bin) do |event|
|
396
|
+
expect(event.get("name")).to eq(data[:name])
|
397
|
+
expect(event.get("pegasus")["wings_length"]).to eq(pegasus_data[:wings_length])
|
398
|
+
expect(event.get("tail")['tail_length']).to eq(tail_data[:tail_length])
|
399
|
+
expect(event.get("tail")['braided']['braiding_style']).to eq(braid_data[:braiding_style])
|
400
|
+
expect(event.get("@metadata")["pb_oneof"]).to be_nil
|
401
|
+
|
402
|
+
end
|
403
|
+
end # it
|
404
|
+
|
405
|
+
end # context pb3decoder_test8b
|
406
|
+
|
407
|
+
##################################################
|
408
|
+
|
409
|
+
context "#pb3decoder_test8c" do
|
410
|
+
|
411
|
+
# activate the meta info for the one-ofs
|
412
|
+
|
413
|
+
let(:plugin_8c) { LogStash::Codecs::Protobuf.new("class_name" => "FantasyHorse", "class_file" => 'pb3/FantasyHorse_pb.rb',
|
414
|
+
"protobuf_root_directory" => pb_include_path, "protobuf_version" => 3, "pb3_set_oneof_metainfo" => true) }
|
415
|
+
before do
|
416
|
+
plugin_8c.register
|
417
|
+
end
|
418
|
+
|
419
|
+
it "should add meta information on oneof fields" do
|
420
|
+
unicorn_data = {:horn_length => 30}
|
421
|
+
horsey = FantasyUnicorn.new(unicorn_data)
|
422
|
+
|
423
|
+
natural_data = {:wavyness => "B"}
|
424
|
+
tail_data = {:natural => NaturalHorseTail.new(natural_data) }
|
425
|
+
tail = FantasyHorseTail.new(tail_data)
|
426
|
+
|
427
|
+
data = {:name=>"Hubert", :unicorn => horsey, :tail => tail}
|
428
|
+
pb_obj = FantasyHorse.new(data)
|
429
|
+
bin = FantasyHorse.encode(pb_obj)
|
430
|
+
plugin_8c.decode(bin) do |event|
|
431
|
+
expect(event.get("name")).to eq(data[:name])
|
432
|
+
expect(event.get("unicorn")["horn_length"]).to eq(unicorn_data[:horn_length])
|
433
|
+
# TODO fix: the codec should not set default values for fields which were not set by the producer
|
434
|
+
# TODO activate after fix: expect(event.get("unicorn")["horn_colour"]).to be_nil
|
435
|
+
# TODO activate after fix: expect(event.get("tail")['tail_length']).to be_nil
|
436
|
+
expect(event.get("tail")['natural']['wavyness']).to eq(natural_data[:wavyness])
|
437
|
+
expect(event.get("@metadata")["pb_oneof"]["horse_type"]).to eq("unicorn")
|
438
|
+
expect(event.get("@metadata")["pb_oneof"]["tail"]["hair_type"]).to eq("natural")
|
439
|
+
end
|
440
|
+
end # it
|
441
|
+
|
442
|
+
end # context pb3decoder_test8c
|
443
|
+
|
444
|
+
##################################################
|
445
|
+
|
446
|
+
context "#pb3decoder_test9a" do
|
447
|
+
|
448
|
+
let(:plugin_9) { LogStash::Codecs::Protobuf.new("class_name" => "messages.SendJsonRequest", "class_file" => 'pb3/struct_test_pb.rb',
|
449
|
+
"protobuf_root_directory" => pb_include_path, "protobuf_version" => 3, "pb3_set_oneof_metainfo" => false) }
|
450
|
+
before do
|
451
|
+
plugin_9.register
|
452
|
+
end
|
453
|
+
|
454
|
+
it "should decode a message with an embedded struct" do
|
455
|
+
# nested struct field
|
456
|
+
struct = Google::Protobuf::Struct.new(fields: {"field_a" => {:string_value => "value_a"}},)
|
457
|
+
data = {:UserID=>"123-456", :Details => struct}
|
458
|
+
pb_obj = Messages::SendJsonRequest.new(data)
|
459
|
+
bin = Messages::SendJsonRequest.encode(pb_obj)
|
460
|
+
|
461
|
+
plugin_9.decode(bin) do |event|
|
462
|
+
expect(event.get("@metadata")["pb_oneof"]).to be_nil
|
463
|
+
expect(event.get("UserID")).to eq(data[:UserID])
|
464
|
+
expect(event.get("Details")).to eq({"field_a"=>"value_a"})
|
465
|
+
end
|
466
|
+
end # it
|
467
|
+
end # context pb3decoder_test9a
|
468
|
+
|
469
|
+
context "#pb3decoder_test9b" do # same as 9a but with one-of metainfo activated
|
470
|
+
|
471
|
+
let(:plugin_9) { LogStash::Codecs::Protobuf.new("class_name" => "messages.SendJsonRequest", "class_file" => 'pb3/struct_test_pb.rb',
|
472
|
+
"protobuf_root_directory" => pb_include_path, "protobuf_version" => 3, "pb3_set_oneof_metainfo" => true)}
|
473
|
+
before do
|
474
|
+
plugin_9.register
|
475
|
+
end
|
476
|
+
|
477
|
+
it "should decode a message with an embedded struct" do
|
478
|
+
# nested struct field
|
479
|
+
details = Google::Protobuf::Struct.new(
|
480
|
+
fields: {"field_a" => {:string_value => "value_a"}},
|
481
|
+
)
|
482
|
+
data = {:UserID=>"123-456", :Details => details}
|
483
|
+
pb_obj = Messages::SendJsonRequest.new(data)
|
484
|
+
bin = Messages::SendJsonRequest.encode(pb_obj)
|
485
|
+
|
486
|
+
plugin_9.decode(bin) do |event|
|
487
|
+
expect(event.get("@metadata")["pb_oneof"]).to eq({})
|
488
|
+
expect(event.get("UserID")).to eq(data[:UserID])
|
489
|
+
expect(event.get("Details")).to eq({"field_a"=>"value_a"})
|
490
|
+
end
|
491
|
+
end # it
|
492
|
+
end # context pb3decoder_test9b
|
493
|
+
|
494
|
+
##################################################
|
495
|
+
|
496
|
+
context "#pb3decoder_test10a" do
|
497
|
+
|
498
|
+
let(:plugin_10) { LogStash::Codecs::Protobuf.new("class_name" => "ProtoResultListCompositionCriteria", "class_file" => 'pb3/ResultListComposerRequest_pb.rb',
|
499
|
+
"protobuf_root_directory" => pb_include_path, "protobuf_version" => 3, "pb3_set_oneof_metainfo" => true) }
|
500
|
+
before do
|
501
|
+
plugin_10.register
|
502
|
+
end
|
503
|
+
|
504
|
+
it "should have only one option set for a double-choice oneOf" do
|
505
|
+
input_criterion = {:sort_criterion => "descending", :top_accommodation_id => 4711}
|
506
|
+
pb_obj = ProtoResultListCompositionCriteria.new(input_criterion)
|
507
|
+
|
508
|
+
bin = ProtoResultListCompositionCriteria.encode(pb_obj)
|
509
|
+
plugin_10.decode(bin) do |event|
|
510
|
+
expect(event.get("sort_criterion")).to eq(input_criterion[:sort_criterion])
|
511
|
+
expect(event.get("top_accommodation_id")).to eq(input_criterion[:top_accommodation_id])
|
512
|
+
expect(event.get("recommend_similar_accommodation_id")).to be_nil
|
513
|
+
expect(event.get("@metadata")["pb_oneof"]['accommodation_id']).to eq("top_accommodation_id")
|
514
|
+
end
|
515
|
+
end # it
|
516
|
+
end # context pb3decoder_test10a
|
517
|
+
|
518
|
+
|
519
|
+
context "#pb3decoder_test10b" do
|
520
|
+
|
521
|
+
# same as 10a but now as a nested field and with a value that equals the default
|
522
|
+
|
523
|
+
let(:plugin_10) { LogStash::Codecs::Protobuf.new("class_name" => "ProtoResultListComposerRequest", "class_file" => 'pb3/ResultListComposerRequest_pb.rb',
|
524
|
+
"protobuf_root_directory" => pb_include_path, "protobuf_version" => 3, "pb3_set_oneof_metainfo" => true) }
|
525
|
+
before do
|
526
|
+
plugin_10.register
|
527
|
+
end
|
528
|
+
|
529
|
+
it "should have only one option set for a nested double-choice oneOf" do
|
530
|
+
input_criterion = {:sort_criterion => "descending", :top_accommodation_id => 0}
|
531
|
+
input_resultlist = {:metadata => [], :page_number => 3, :results_per_page => 100,
|
532
|
+
:result_list_composition_criteria => ProtoResultListCompositionCriteria.new(input_criterion)}
|
533
|
+
pb_obj = ProtoResultListComposerRequest.new(input_resultlist)
|
534
|
+
|
535
|
+
bin = ProtoResultListComposerRequest.encode(pb_obj)
|
536
|
+
plugin_10.decode(bin) do |event|
|
537
|
+
expect(event.get("@metadata")["pb_oneof"]['result_list_composition_criteria']['accommodation_id']).to eq('top_accommodation_id')
|
538
|
+
expect(event.get("page_number")).to eq(input_resultlist[:page_number])
|
539
|
+
expect(event.get("results_per_page")).to eq(input_resultlist[:results_per_page])
|
540
|
+
expect(event.get("metadata")).to eq(input_resultlist[:metadata])
|
541
|
+
expect(event.get("result_list_composition_criteria")["sort_criterion"]).to eq(input_criterion[:sort_criterion])
|
542
|
+
expect(event.get("result_list_composition_criteria")["top_accommodation_id"]).to eq(input_criterion[:top_accommodation_id])
|
543
|
+
expect(event.get("result_list_composition_criteria")["recommend_similar_accommodation_id"]).to be_nil
|
544
|
+
end
|
545
|
+
end # it
|
546
|
+
end # context pb3decoder_test10b
|
547
|
+
|
548
|
+
##################################################
|
549
|
+
|
550
|
+
context "#pb3decoder_test11" do
|
551
|
+
|
552
|
+
# XOR test for one-of but this time with objects instead of scalars, also triple-option of which only 1 must be set.
|
553
|
+
|
554
|
+
let(:plugin_11) { LogStash::Codecs::Protobuf.new("class_name" => "FantasyHorse", "class_file" => 'pb3/FantasyHorse_pb.rb',
|
555
|
+
"protobuf_root_directory" => pb_include_path, "protobuf_version" => 3, "pb3_set_oneof_metainfo" => false) }
|
556
|
+
before do
|
557
|
+
plugin_11.register
|
558
|
+
end
|
559
|
+
|
560
|
+
it "should have only one option set for a triple-choice oneOf" do
|
561
|
+
pegasus_data = {:wings_length => 200}
|
562
|
+
horsey = FantasyPegasus.new(pegasus_data)
|
563
|
+
|
564
|
+
braid_data = {:braid_thickness => 3, :braiding_style => "french"}
|
565
|
+
tail_data = {:tail_length => 80, :braided => BraidedHorseTail.new(braid_data) }
|
566
|
+
tail = FantasyHorseTail.new(tail_data)
|
567
|
+
|
568
|
+
data = {:name=>"Reinhold", :pegasus => horsey, :tail => tail}
|
569
|
+
pb_obj = FantasyHorse.new(data)
|
570
|
+
bin = FantasyHorse.encode(pb_obj)
|
571
|
+
plugin_11.decode(bin) do |event|
|
572
|
+
expect(event.get("name")).to eq(data[:name])
|
573
|
+
expect(event.get("pegasus")["wings_length"]).to eq(pegasus_data[:wings_length])
|
574
|
+
expect(event.get("tail")['tail_length']).to eq(tail_data[:tail_length])
|
575
|
+
expect(event.get("tail")['braided']['braiding_style']).to eq(braid_data[:braiding_style])
|
576
|
+
expect(event.get("tail")['natural']).to be_nil
|
577
|
+
expect(event.get("tail")['short']).to be_nil
|
578
|
+
expect(event.get("tail")['hair_type']).to be_nil
|
579
|
+
expect(event.get("@metadata")["pb_oneof"]).to be_nil
|
580
|
+
end
|
581
|
+
end # it
|
582
|
+
end # context pb3decoder_test11
|
583
|
+
|
584
|
+
##################################################
|
585
|
+
|
586
|
+
context "#pb3decoder_test12" do
|
587
|
+
# One-of metadata with nested class names. Class lookup in the pb descriptor pool has previously been an issue.
|
588
|
+
let(:plugin_12) { LogStash::Codecs::Protobuf.new("class_name" => "company.communication.directories.PhoneDirectory", "class_file" => 'pb3/PhoneDirectory_pb.rb',
|
589
|
+
"protobuf_root_directory" => pb_include_path, "protobuf_version" => 3, "pb3_set_oneof_metainfo" => true) }
|
590
|
+
before do
|
591
|
+
plugin_12.register
|
592
|
+
end
|
593
|
+
|
594
|
+
it "should do one-of meta info lookup for nested classes" do
|
595
|
+
contacts = []
|
596
|
+
hans = {:name => "Horst Test", :address => "Test street 12, 90210 Test hills", :prefered_email => "horst@test.com"}
|
597
|
+
contacts << Company::Communication::Directories::Contact.new(hans)
|
598
|
+
jane = {:name => "Jane Trial", :address => "Test street 13, 90210 Test hills", :prefered_phone => 1234567}
|
599
|
+
contacts << Company::Communication::Directories::Contact.new(jane)
|
600
|
+
kimmy = {:name => "Kimmy Experiment", :address => "Test street 14, 90210 Test hills", :prefered_fax => 666777888}
|
601
|
+
contacts << Company::Communication::Directories::Contact.new(kimmy)
|
602
|
+
|
603
|
+
data = {:last_updated_timestamp=>1900000000, :internal => true, :contacts => contacts}
|
604
|
+
pb_obj = Company::Communication::Directories::PhoneDirectory.new(data)
|
605
|
+
bin = Company::Communication::Directories::PhoneDirectory.encode(pb_obj)
|
606
|
+
|
607
|
+
plugin_12.decode(bin) do |event|
|
608
|
+
|
609
|
+
expect(event.get("internal")).to eq(data[:internal])
|
610
|
+
expect(event.get("external")).to be_nil
|
611
|
+
expect(event.get("@metadata")['pb_oneof']["scope"]).to eq('internal')
|
612
|
+
|
613
|
+
expect(event.get("contacts")[0]["name"]).to eq(hans[:name])
|
614
|
+
expect(event.get("contacts")[0]["address"]).to eq(hans[:address])
|
615
|
+
expect(event.get("contacts")[0]["prefered_email"]).to eq(hans[:prefered_email])
|
616
|
+
expect(event.get("contacts")[0]["prefered_fax"]).to be_nil
|
617
|
+
expect(event.get("contacts")[0]["prefered_phone"]).to be_nil
|
618
|
+
expect(event.get("@metadata")['pb_oneof']["contacts"]).not_to be_nil
|
619
|
+
expect(event.get("@metadata")['pb_oneof']["contacts"]).to be_a(Array)
|
620
|
+
expect(event.get("@metadata")['pb_oneof']["contacts"].length()).to eq(3)
|
621
|
+
expect(event.get("@metadata")['pb_oneof']["contacts"][0]['prefered_contact']).to eq('prefered_email')
|
622
|
+
|
623
|
+
expect(event.get("contacts")[1]["name"]).to eq(jane[:name])
|
624
|
+
expect(event.get("contacts")[1]["address"]).to eq(jane[:address])
|
625
|
+
expect(event.get("contacts")[1]["prefered_phone"]).to eq(jane[:prefered_phone])
|
626
|
+
expect(event.get("contacts")[1]["prefered_fax"]).to be_nil
|
627
|
+
expect(event.get("contacts")[1]["prefered_email"]).to be_nil
|
628
|
+
expect(event.get("@metadata")['pb_oneof']["contacts"][1]['prefered_contact']).to eq('prefered_phone')
|
629
|
+
|
630
|
+
expect(event.get("contacts")[2]["name"]).to eq(kimmy[:name])
|
631
|
+
expect(event.get("contacts")[2]["address"]).to eq(kimmy[:address])
|
632
|
+
expect(event.get("contacts")[2]["prefered_fax"]).to eq(kimmy[:prefered_fax])
|
633
|
+
expect(event.get("contacts")[2]["prefered_email"]).to be_nil
|
634
|
+
expect(event.get("contacts")[2]["prefered_phone"]).to be_nil
|
635
|
+
expect(event.get("@metadata")['pb_oneof']["contacts"][2]['prefered_contact']).to eq('prefered_fax')
|
636
|
+
|
637
|
+
end
|
638
|
+
end # it
|
639
|
+
end # context pb3decoder_test12
|
640
|
+
|
641
|
+
##################################################
|
642
|
+
|
643
|
+
context "#pb3decoder_test13" do
|
644
|
+
let(:plugin_13) { LogStash::Codecs::Protobuf.new(
|
645
|
+
"class_name" => "B.MessageB",
|
646
|
+
"class_file" => [ pb_include_path + '/pb3/messageB_pb.rb' ],
|
647
|
+
"protobuf_version" => 3, "pb3_set_oneof_metainfo" => true,
|
648
|
+
"protobuf_root_directory" => pb_include_path)
|
649
|
+
}
|
650
|
+
before do
|
651
|
+
plugin_13.register
|
652
|
+
end
|
653
|
+
|
654
|
+
it "should find the class name in the protobuf descriptor pool" do
|
655
|
+
data = {:name => "test"}
|
656
|
+
pb_obj = B::MessageB.new(data)
|
657
|
+
result = plugin_13.pb3_class_for_name(pb_obj)
|
658
|
+
expect {result.not_to be_nil}
|
659
|
+
end # it
|
660
|
+
|
661
|
+
end # context pb3decoder_test13
|
662
|
+
|
663
|
+
##################################################
|
664
|
+
|
665
|
+
end # describe
|