logstash-codec-protobuf 1.0.5 → 1.2.5
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 +5 -5
- data/CHANGELOG.md +20 -1
- data/Gemfile +1 -1
- data/LICENSE +2 -3
- data/README.md +147 -40
- data/docs/index.asciidoc +173 -41
- data/lib/logstash/codecs/protobuf.rb +598 -238
- data/logstash-codec-protobuf.gemspec +3 -3
- data/spec/codecs/{protobuf_spec.rb → pb2_spec.rb} +81 -54
- data/spec/codecs/pb3_decode_spec.rb +445 -0
- data/spec/codecs/pb3_encode_spec.rb +243 -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/pb3/FantasyHorse_pb.rb +44 -0
- data/spec/helpers/pb3/ProbeResult_pb.rb +26 -0
- data/spec/helpers/pb3/dnsmessage_pb.rb +82 -0
- data/spec/helpers/pb3/events.proto3 +10 -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 +20 -0
- data/spec/helpers/pb3/messageA.proto3 +12 -0
- data/spec/helpers/pb3/messageA_pb.rb +16 -0
- data/spec/helpers/pb3/messageB.proto3 +12 -0
- data/spec/helpers/pb3/messageB_pb.rb +16 -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
- metadata +62 -34
- data/lib/net/jpountz/lz4/lz4/1.3.0/lz4-1.3.0.jar +0 -0
- data/lib/org/apache/kafka/kafka-clients/0.11.0.0/kafka-clients-0.11.0.0.jar +0 -0
- data/lib/org/apache/logging/log4j/log4j-api/2.8.2/log4j-api-2.8.2.jar +0 -0
- data/lib/org/apache/logging/log4j/log4j-slf4j-impl/2.8.2/log4j-slf4j-impl-2.8.2.jar +0 -0
- data/lib/org/slf4j/slf4j-api/1.7.24/slf4j-api-1.7.24.jar +0 -0
- data/lib/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar +0 -0
- data/lib/org/xerial/snappy/snappy-java/1.1.2.6/snappy-java-1.1.2.6.jar +0 -0
- data/spec/codecs/protobuf3_spec.rb +0 -147
- data/vendor/jar-dependencies/runtime-jars/kafka-clients-0.11.0.0.jar +0 -0
- data/vendor/jar-dependencies/runtime-jars/log4j-api-2.8.2.jar +0 -0
- data/vendor/jar-dependencies/runtime-jars/log4j-slf4j-impl-2.8.2.jar +0 -0
- data/vendor/jar-dependencies/runtime-jars/lz4-1.3.0.jar +0 -0
- data/vendor/jar-dependencies/runtime-jars/slf4j-api-1.7.24.jar +0 -0
- data/vendor/jar-dependencies/runtime-jars/slf4j-api-1.7.25.jar +0 -0
- data/vendor/jar-dependencies/runtime-jars/snappy-java-1.1.2.6.jar +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
|
3
3
|
s.name = 'logstash-codec-protobuf'
|
4
|
-
s.version = '1.
|
4
|
+
s.version = '1.2.5'
|
5
5
|
s.licenses = ['Apache License (2.0)']
|
6
6
|
s.summary = "Reads protobuf messages and converts to Logstash Events"
|
7
7
|
s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
|
@@ -20,8 +20,8 @@ Gem::Specification.new do |s|
|
|
20
20
|
|
21
21
|
# Gem dependencies
|
22
22
|
s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
|
23
|
-
s.add_runtime_dependency 'google-protobuf', '3.
|
23
|
+
s.add_runtime_dependency 'google-protobuf', '3.5.0.pre'
|
24
24
|
s.add_runtime_dependency 'ruby-protocol-buffers' # for protobuf 2
|
25
25
|
s.add_development_dependency 'logstash-devutils'
|
26
|
-
end
|
27
26
|
|
27
|
+
end
|
@@ -2,30 +2,32 @@
|
|
2
2
|
require "logstash/devutils/rspec/spec_helper"
|
3
3
|
require "logstash/codecs/protobuf"
|
4
4
|
require "logstash/event"
|
5
|
-
require "insist"
|
6
|
-
|
7
5
|
|
8
6
|
require 'protocol_buffers' # https://github.com/codekitchen/ruby-protocol-buffers, for protobuf2
|
9
7
|
|
8
|
+
require_relative '../helpers/pb2/header/header.pb.rb'
|
9
|
+
require_relative '../helpers/pb2/event.pb.rb'
|
10
|
+
|
10
11
|
|
11
12
|
describe LogStash::Codecs::Protobuf do
|
12
13
|
|
14
|
+
pb_include_path = File.expand_path(".") + "/spec/helpers"
|
13
15
|
|
16
|
+
context "#test1" do
|
14
17
|
|
15
|
-
context "#decodePB2" do
|
16
18
|
|
17
19
|
|
18
20
|
#### Test case 1: Decode simple protobuf bytes for unicorn ####################################################################################################################
|
19
|
-
let(:plugin_unicorn) { LogStash::Codecs::Protobuf.new("class_name" => "Animal::Unicorn", "include_path" => ['
|
21
|
+
let(:plugin_unicorn) { LogStash::Codecs::Protobuf.new("class_name" => "Animal::Unicorn", "include_path" => [pb_include_path + '/pb2/unicorn.pb.rb']) }
|
20
22
|
before do
|
21
|
-
plugin_unicorn.register
|
23
|
+
plugin_unicorn.register
|
22
24
|
end
|
23
25
|
|
24
26
|
it "should return an event from protobuf encoded data" do
|
25
|
-
|
27
|
+
|
26
28
|
data = {:colour => 'rainbow', :horn_length => 18, :last_seen => 1420081471, :has_wings => true}
|
27
29
|
unicorn = Animal::Unicorn.new(data)
|
28
|
-
|
30
|
+
|
29
31
|
plugin_unicorn.decode(unicorn.serialize_to_string) do |event|
|
30
32
|
expect(event.get("colour") ).to eq(data[:colour] )
|
31
33
|
expect(event.get("horn_length") ).to eq(data[:horn_length] )
|
@@ -34,34 +36,34 @@ describe LogStash::Codecs::Protobuf do
|
|
34
36
|
end
|
35
37
|
end # it
|
36
38
|
|
37
|
-
|
39
|
+
end
|
38
40
|
|
39
41
|
#### Test case 2: Decode complex protobuf bytes for human #####################################################################################################################
|
40
42
|
|
43
|
+
context "#test2" do
|
41
44
|
|
42
|
-
|
43
|
-
|
44
|
-
let(:plugin_human) { LogStash::Codecs::Protobuf.new("class_name" => "Animal::Human", "include_path" => ['spec/helpers/pb2/human.pb.rb']) }
|
45
|
+
|
46
|
+
let(:plugin_human) { LogStash::Codecs::Protobuf.new("class_name" => "Animal::Human", "include_path" => [pb_include_path + '/pb2/human.pb.rb']) }
|
45
47
|
before do
|
46
|
-
plugin_human.register
|
48
|
+
plugin_human.register
|
47
49
|
end
|
48
50
|
|
49
51
|
it "should return an event from complex nested protobuf encoded data" do
|
50
|
-
|
52
|
+
|
51
53
|
data_gm = {:first_name => 'Elisabeth', :last_name => "Oliveoil", :middle_names => ["Maria","Johanna"], :vegetarian=>true}
|
52
54
|
grandmother = Animal::Human.new(data_gm)
|
53
55
|
data_m = {:first_name => 'Annemarie', :last_name => "Smørebrød", :mother => grandmother}
|
54
56
|
mother = Animal::Human.new(data_m)
|
55
57
|
data_f = {:first_name => 'Karl', :middle_names => ["Theodor-Augustin"], :last_name => "Falkenstein"}
|
56
58
|
father = Animal::Human.new(data_f)
|
57
|
-
data = {:first_name => 'Hugo', :middle_names => ["Heinz", "Peter"], :last_name => "Smørebrød",:father => father, :mother => mother}
|
59
|
+
data = {:first_name => 'Hugo', :middle_names => ["Heinz", "Peter"], :last_name => "Smørebrød",:father => father, :mother => mother}
|
58
60
|
hugo = Animal::Human.new(data)
|
59
|
-
|
61
|
+
|
60
62
|
plugin_human.decode(hugo.serialize_to_string) do |event|
|
61
63
|
expect(event.get("first_name") ).to eq(data[:first_name] )
|
62
64
|
expect(event.get("middle_names") ).to eq(data[:middle_names] )
|
63
65
|
expect(event.get("last_name") ).to eq(data[:last_name] )
|
64
|
-
expect(event.get("[mother][first_name]") ).to eq(data_m[:first_name] )
|
66
|
+
expect(event.get("[mother][first_name]") ).to eq(data_m[:first_name] )
|
65
67
|
expect(event.get("[father][first_name]") ).to eq(data_f[:first_name] )
|
66
68
|
expect(event.get("[mother][last_name]") ).to eq(data_m[:last_name] )
|
67
69
|
expect(event.get("[mother][mother][last_name]") ).to eq(data_gm[:last_name] )
|
@@ -72,28 +74,25 @@ describe LogStash::Codecs::Protobuf do
|
|
72
74
|
expect(event.get("[father][middle_names]") ).to eq(data_f[:middle_names] )
|
73
75
|
end
|
74
76
|
end # it
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
77
|
+
end # context
|
79
78
|
|
80
79
|
|
81
80
|
#### Test case 3: Decoder test for enums #####################################################################################################################
|
82
81
|
|
82
|
+
context "#test3" do
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
let(:plugin_col) { LogStash::Codecs::Protobuf.new("class_name" => "ColourProtoTest", "include_path" => ['spec/helpers/pb2/ColourTestcase.pb.rb']) }
|
84
|
+
|
85
|
+
let(:plugin_col) { LogStash::Codecs::Protobuf.new("class_name" => "ColourProtoTest", "include_path" => [pb_include_path + '/pb2/ColourTestcase.pb.rb']) }
|
87
86
|
before do
|
88
|
-
plugin_col.register
|
87
|
+
plugin_col.register
|
89
88
|
end
|
90
89
|
|
91
90
|
it "should return an event from protobuf encoded data with enums" do
|
92
|
-
|
91
|
+
|
93
92
|
data = {:least_liked => ColourProtoTest::Colour::YELLOW, :favourite_colours => \
|
94
|
-
[ColourProtoTest::Colour::BLACK, ColourProtoTest::Colour::BLUE], :booleantest => [true, false, true]}
|
93
|
+
[ColourProtoTest::Colour::BLACK, ColourProtoTest::Colour::BLUE], :booleantest => [true, false, true]}
|
95
94
|
pb = ColourProtoTest.new(data)
|
96
|
-
|
95
|
+
|
97
96
|
plugin_col.decode(pb.serialize_to_string) do |event|
|
98
97
|
expect(event.get("least_liked") ).to eq(data[:least_liked] )
|
99
98
|
expect(event.get("favourite_colours") ).to eq(data[:favourite_colours] )
|
@@ -102,31 +101,28 @@ describe LogStash::Codecs::Protobuf do
|
|
102
101
|
end # it
|
103
102
|
|
104
103
|
|
105
|
-
end # context
|
106
|
-
|
107
|
-
|
108
|
-
|
104
|
+
end # context test3
|
109
105
|
|
110
106
|
|
111
107
|
#### Test case 4: Encode simple protobuf bytes for unicorn ####################################################################################################################
|
112
108
|
|
113
109
|
context "#encodePB2-a" do
|
114
110
|
subject do
|
115
|
-
next LogStash::Codecs::Protobuf.new("class_name" => "Animal::UnicornEvent", "include_path" => ['
|
111
|
+
next LogStash::Codecs::Protobuf.new("class_name" => "Animal::UnicornEvent", "include_path" => [pb_include_path + '/pb2/unicorn_event.pb.rb'])
|
116
112
|
end
|
117
113
|
|
118
|
-
event = LogStash::Event.new("colour" => "pink", "horn_length" => 12, "last_seen" => 1410081999, "has_wings" => true)
|
114
|
+
event = LogStash::Event.new("colour" => "pink", "horn_length" => 12, "last_seen" => 1410081999, "has_wings" => true)
|
119
115
|
|
120
116
|
it "should return protobuf encoded data from a simple event" do
|
121
117
|
subject.on_event do |event, data|
|
122
|
-
|
123
|
-
unicorn = Animal::UnicornEvent.parse(data)
|
124
|
-
|
118
|
+
expect(data).to be_a(String)
|
119
|
+
unicorn = Animal::UnicornEvent.parse(data)
|
120
|
+
|
125
121
|
expect(unicorn.colour ).to eq(event.get("colour") )
|
126
122
|
expect(unicorn.horn_length ).to eq(event.get("horn_length") )
|
127
123
|
expect(unicorn.last_seen ).to eq(event.get("last_seen") )
|
128
124
|
expect(unicorn.has_wings ).to eq(event.get("has_wings") )
|
129
|
-
|
125
|
+
|
130
126
|
end # subject.on_event
|
131
127
|
subject.encode(event)
|
132
128
|
end # it
|
@@ -136,23 +132,23 @@ describe LogStash::Codecs::Protobuf do
|
|
136
132
|
|
137
133
|
|
138
134
|
#### Test case 5: encode complex protobuf bytes for human #####################################################################################################################
|
139
|
-
|
140
|
-
|
135
|
+
|
136
|
+
|
141
137
|
context "#encodePB2-b" do
|
142
138
|
subject do
|
143
|
-
next LogStash::Codecs::Protobuf.new("class_name" => "Animal::Human", "include_path" => ['
|
139
|
+
next LogStash::Codecs::Protobuf.new("class_name" => "Animal::Human", "include_path" => [pb_include_path + '/pb2/human.pb.rb'])
|
144
140
|
end
|
145
141
|
|
146
142
|
event = LogStash::Event.new("first_name" => "Jimmy", "middle_names" => ["Bob", "James"], "last_name" => "Doe" \
|
147
143
|
, "mother" => {"first_name" => "Jane", "middle_names" => ["Elizabeth"], "last_name" => "Doe" , "age" => 83, "vegetarian"=> false} \
|
148
|
-
, "father" => {"first_name" => "John", "last_name" => "Doe", "@email" => "character_replacement_test@nothing" })
|
144
|
+
, "father" => {"first_name" => "John", "last_name" => "Doe", "@email" => "character_replacement_test@nothing" })
|
149
145
|
|
150
146
|
it "should return protobuf encoded data from a complex event" do
|
151
147
|
|
152
148
|
subject.on_event do |event, data|
|
153
|
-
|
154
|
-
jimmy = Animal::Human.parse(data)
|
155
|
-
|
149
|
+
expect(data).to be_a(String)
|
150
|
+
jimmy = Animal::Human.parse(data)
|
151
|
+
|
156
152
|
expect(jimmy.first_name ).to eq(event.get("first_name") )
|
157
153
|
expect(jimmy.middle_names ).to eq(event.get("middle_names") )
|
158
154
|
expect(jimmy.last_name ).to eq(event.get("last_name") )
|
@@ -164,7 +160,7 @@ describe LogStash::Codecs::Protobuf do
|
|
164
160
|
expect(jimmy.father.last_name ).to eq(event.get("[father][last_name]") )
|
165
161
|
expect(jimmy.father.email ).to eq(event.get("[father][@email]") ) # recursion test for keys
|
166
162
|
expect(jimmy.mother.last_name ).to eq(event.get("[mother][last_name]") )
|
167
|
-
|
163
|
+
|
168
164
|
end # subject.on_event
|
169
165
|
subject.encode(event)
|
170
166
|
end # it
|
@@ -175,35 +171,66 @@ describe LogStash::Codecs::Protobuf do
|
|
175
171
|
|
176
172
|
|
177
173
|
#### Test case 6: encode enums #########################################################################################################################
|
178
|
-
|
179
174
|
|
180
|
-
|
175
|
+
|
176
|
+
|
181
177
|
context "#encodePB2-c" do
|
182
178
|
subject do
|
183
|
-
next LogStash::Codecs::Protobuf.new("class_name" => "ColourProtoTest", "include_path" => ['
|
179
|
+
next LogStash::Codecs::Protobuf.new("class_name" => "ColourProtoTest", "include_path" => [pb_include_path + '/pb2/ColourTestcase.pb.rb'])
|
184
180
|
end
|
185
181
|
|
186
|
-
|
182
|
+
require_relative '../helpers/pb2/ColourTestcase.pb.rb' # otherwise we cant use the colour enums in the next line
|
183
|
+
# ^ this import is run from the spec directory, $LOGSTASH_DIR/spec/codecs/
|
184
|
+
|
187
185
|
event = LogStash::Event.new("booleantest" => [false, false, true], "least_liked" => ColourProtoTest::Colour::YELLOW, "favourite_colours" => \
|
188
|
-
[ColourProtoTest::Colour::BLACK, ColourProtoTest::Colour::BLUE] )
|
186
|
+
[ColourProtoTest::Colour::BLACK, ColourProtoTest::Colour::BLUE] )
|
189
187
|
|
190
188
|
it "should return protobuf encoded data from a complex event with enums" do
|
191
189
|
|
192
190
|
subject.on_event do |event, data|
|
193
|
-
|
191
|
+
expect(data).to be_a(String)
|
192
|
+
|
193
|
+
colpref = ColourProtoTest.parse(data)
|
194
194
|
|
195
|
-
colpref = ColourProtoTest.parse(data)
|
196
|
-
|
197
195
|
expect(colpref.booleantest ).to eq(event.get("booleantest") )
|
198
196
|
expect(colpref.least_liked ).to eq(event.get("least_liked") )
|
199
197
|
expect(colpref.favourite_colours ).to eq(event.get("favourite_colours") )
|
200
198
|
|
201
|
-
|
199
|
+
|
202
200
|
end # subject.on_event
|
203
201
|
subject.encode(event)
|
204
202
|
end # it
|
205
203
|
end # context
|
206
204
|
|
205
|
+
#### Test case 7: decode a message automatically loading the dependencies ######################################################################################
|
206
|
+
|
207
|
+
context "#test4" do
|
208
|
+
let(:plugin) { LogStash::Codecs::Protobuf.new(
|
209
|
+
"class_name" => "Logging::Event",
|
210
|
+
"class_file" => [ 'event.pb.rb' ],
|
211
|
+
"protobuf_root_directory" => pb_include_path + '/pb2/')
|
212
|
+
}
|
213
|
+
|
214
|
+
before do
|
215
|
+
plugin.register
|
216
|
+
end
|
217
|
+
|
218
|
+
it "should return an event from protobuf encoded data loading the dependencies" do
|
219
|
+
header = Grpc::Header.new(:protocol => 'https')
|
220
|
+
|
221
|
+
data = {
|
222
|
+
:name => "Test",
|
223
|
+
:header => header,
|
224
|
+
}
|
225
|
+
|
226
|
+
pb = Logging::Event.new(data)
|
227
|
+
|
228
|
+
plugin.decode(pb.serialize_to_string) do |event|
|
229
|
+
expect(event.get("name") ).to eq(data[:name])
|
230
|
+
expect(event.get("header") ).to eq({"protocol"=>"https"})
|
231
|
+
end
|
232
|
+
end # it
|
233
|
+
end # context test4
|
207
234
|
|
208
235
|
|
209
236
|
end # describe
|
@@ -0,0 +1,445 @@
|
|
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
|
+
|
11
|
+
require pb_include_path + '/pb3/unicorn_pb.rb'
|
12
|
+
unicorn_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("Unicorn").msgclass
|
13
|
+
|
14
|
+
describe LogStash::Codecs::Protobuf do
|
15
|
+
|
16
|
+
context ".reloadable?" do
|
17
|
+
subject do
|
18
|
+
next LogStash::Codecs::Protobuf.new(
|
19
|
+
"class_name" => "Unicorn",
|
20
|
+
"include_path" => [pb_include_path + '/pb3/unicorn_pb.rb'],
|
21
|
+
"protobuf_version" => 3
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns false" do
|
26
|
+
expect(subject.reloadable?).to be_falsey
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "config" do
|
31
|
+
context "using class_file and include_path" do
|
32
|
+
let(:plugin) {
|
33
|
+
LogStash::Codecs::Protobuf.new(
|
34
|
+
"class_name" => "Unicorn",
|
35
|
+
"include_path" => [pb_include_path + '/pb3/unicorn_pb.rb'],
|
36
|
+
"class_file" => pb_include_path + '/pb3/unicorn_pb.rb',
|
37
|
+
"protobuf_version" => 3
|
38
|
+
)
|
39
|
+
}
|
40
|
+
|
41
|
+
it "should fail to register the plugin with ConfigurationError" do
|
42
|
+
expect {plugin.register}.to raise_error(LogStash::ConfigurationError, /`include_path` and `class_file`/)
|
43
|
+
end # it
|
44
|
+
end
|
45
|
+
|
46
|
+
context "not using class_file or include_path" do
|
47
|
+
let(:plugin) {
|
48
|
+
LogStash::Codecs::Protobuf.new("class_name" => "Unicorn")
|
49
|
+
}
|
50
|
+
|
51
|
+
it "should fail to register the plugin with ConfigurationError" do
|
52
|
+
expect {plugin.register}.to raise_error(LogStash::ConfigurationError, /`include_path` or `class_file`/)
|
53
|
+
end # it
|
54
|
+
end
|
55
|
+
|
56
|
+
RSpec::Expectations.configuration.on_potential_false_positives = :nothing
|
57
|
+
|
58
|
+
context "re-registering the plugin with a valid configuration" do
|
59
|
+
let(:plugin) { LogStash::Codecs::Protobuf.new(
|
60
|
+
"class_name" => "A.MessageA",
|
61
|
+
"class_file" => [ pb_include_path + '/pb3/messageA_pb.rb' ],
|
62
|
+
"protobuf_version" => 3,
|
63
|
+
"protobuf_root_directory" => File.expand_path(File.dirname(__FILE__) + pb_include_path + '/pb3/'))
|
64
|
+
}
|
65
|
+
|
66
|
+
it "should not fail" do
|
67
|
+
expect {
|
68
|
+
# this triggers the `register()` method of the plugin multiple times
|
69
|
+
plugin.register
|
70
|
+
plugin.register
|
71
|
+
}.not_to raise_error(RuntimeError)
|
72
|
+
end # it
|
73
|
+
end
|
74
|
+
end # context
|
75
|
+
|
76
|
+
context "#pb3decoder_test1" do
|
77
|
+
|
78
|
+
|
79
|
+
#### Test case 1: Decode simple protobuf ####################################################################################################################
|
80
|
+
let(:plugin_unicorn) { LogStash::Codecs::Protobuf.new(
|
81
|
+
"class_name" => "Unicorn", "include_path" => [pb_include_path + '/pb3/unicorn_pb.rb'], "protobuf_version" => 3)
|
82
|
+
}
|
83
|
+
|
84
|
+
it "should return an event from protobuf data" do
|
85
|
+
|
86
|
+
unicorn_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("Unicorn").msgclass
|
87
|
+
data = {:name => 'Pinkie', :age => 18, :is_pegasus => false, :favourite_numbers => [4711,23], :fur_colour => Colour::PINK,
|
88
|
+
:favourite_colours => [Colour::GREEN, Colour::BLUE]
|
89
|
+
}
|
90
|
+
|
91
|
+
unicorn_object = unicorn_class.new(data)
|
92
|
+
bin = unicorn_class.encode(unicorn_object)
|
93
|
+
plugin_unicorn.decode(bin) do |event|
|
94
|
+
expect(event.get("name") ).to eq(data[:name] )
|
95
|
+
expect(event.get("age") ).to eq(data[:age])
|
96
|
+
expect(event.get("fur_colour") ).to eq("PINK")
|
97
|
+
expect(event.get("favourite_numbers") ).to eq(data[:favourite_numbers])
|
98
|
+
expect(event.get("favourite_colours") ).to eq(["GREEN","BLUE"])
|
99
|
+
expect(event.get("is_pegasus") ).to eq(data[:is_pegasus] )
|
100
|
+
end
|
101
|
+
end # it
|
102
|
+
end # context
|
103
|
+
|
104
|
+
context "#pb3decoder_test2" do
|
105
|
+
|
106
|
+
#### Test case 2: decode nested protobuf ####################################################################################################################
|
107
|
+
let(:plugin_unicorn) { LogStash::Codecs::Protobuf.new("class_name" => "Unicorn", "include_path" => [pb_include_path + '/pb3/unicorn_pb.rb'], "protobuf_version" => 3) }
|
108
|
+
|
109
|
+
it "should return an event from protobuf data with nested classes" do
|
110
|
+
father = unicorn_class.new({:name=> "Sparkle", :age => 50, :fur_colour => 3 })
|
111
|
+
data = {:name => 'Glitter', :fur_colour => Colour::GLITTER, :father => father}
|
112
|
+
|
113
|
+
unicorn_object = unicorn_class.new(data)
|
114
|
+
bin = unicorn_class.encode(unicorn_object)
|
115
|
+
plugin_unicorn.decode(bin) do |event|
|
116
|
+
expect(event.get("name") ).to eq(data[:name] )
|
117
|
+
expect(event.get("fur_colour") ).to eq("GLITTER" )
|
118
|
+
expect(event.get("father")["name"] ).to eq(data[:father][:name] )
|
119
|
+
expect(event.get("father")["age"] ).to eq(data[:father][:age] )
|
120
|
+
expect(event.get("father")["fur_colour"] ).to eq("SILVER")
|
121
|
+
|
122
|
+
end
|
123
|
+
end # it
|
124
|
+
|
125
|
+
end # context
|
126
|
+
|
127
|
+
context "#pb3decoder_test3" do
|
128
|
+
|
129
|
+
#### Test case 3: decode ProbeResult ####################################################################################################################
|
130
|
+
let(:plugin_3) { LogStash::Codecs::Protobuf.new("class_name" => "ProbeResult", "include_path" => [pb_include_path + '/pb3/ProbeResult_pb.rb'], "protobuf_version" => 3) }
|
131
|
+
|
132
|
+
before do
|
133
|
+
plugin_3.register
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should return an event from protobuf data with nested classes" do
|
137
|
+
|
138
|
+
probe_result_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("ProbeResult").msgclass
|
139
|
+
ping_result_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("PingIPv4Result").msgclass
|
140
|
+
|
141
|
+
ping_result_data = {:status=> PingIPv4Result::Status::ERROR,
|
142
|
+
:latency => 50, :ip => "8.8.8.8", :probe_ip => "127.0.0.1", :geolocation => "New York City" }
|
143
|
+
ping_result_object = ping_result_class.new(ping_result_data)
|
144
|
+
|
145
|
+
probe_result_data = {:UUID => '12345678901233456789', :TaskPingIPv4Result => ping_result_object}
|
146
|
+
probe_result_object = probe_result_class.new(probe_result_data)
|
147
|
+
bin = probe_result_class.encode(probe_result_object)
|
148
|
+
plugin_3.decode(bin) do |event|
|
149
|
+
expect(event.get("UUID") ).to eq(probe_result_data[:UUID] )
|
150
|
+
expect(event.get("TaskPingIPv4Result")["status"] ).to eq("ERROR")
|
151
|
+
expect(event.get("TaskPingIPv4Result")["latency"] ).to eq(ping_result_data[:latency] )
|
152
|
+
expect(event.get("TaskPingIPv4Result")["ip"] ).to eq(ping_result_data[:ip] )
|
153
|
+
expect(event.get("TaskPingIPv4Result")["probe_ip"] ).to eq(ping_result_data[:probe_ip] )
|
154
|
+
expect(event.get("TaskPingIPv4Result")["geolocation"] ).to eq(ping_result_data[:geolocation] )
|
155
|
+
end
|
156
|
+
end # it
|
157
|
+
end # context
|
158
|
+
|
159
|
+
context "#pb3decoder_test4" do
|
160
|
+
|
161
|
+
#### Test case 4: decode PBDNSMessage ####################################################################################################################
|
162
|
+
let(:plugin_4) { LogStash::Codecs::Protobuf.new("class_name" => "PBDNSMessage", "include_path" => [pb_include_path + '/pb3/dnsmessage_pb.rb'], "protobuf_version" => 3) }
|
163
|
+
|
164
|
+
before do
|
165
|
+
plugin_4.register
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should return an event from protobuf data with nested classes" do
|
169
|
+
|
170
|
+
|
171
|
+
pbdns_message_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("PBDNSMessage").msgclass
|
172
|
+
dns_question_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("PBDNSMessage.DNSQuestion").msgclass
|
173
|
+
dns_response_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("PBDNSMessage.DNSResponse").msgclass
|
174
|
+
dns_rr_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("PBDNSMessage.DNSResponse.DNSRR").msgclass
|
175
|
+
|
176
|
+
dns_question_data = {:qName => "Foo", :qType => 12345, :qClass => 67890 }
|
177
|
+
dns_question_object = dns_question_class.new(dns_question_data)
|
178
|
+
|
179
|
+
dns_response_data = {:rcode => 12345, :appliedPolicy => "baz", :tags => ["a","b","c"],
|
180
|
+
:queryTimeSec => 123, :queryTimeUsec => 456,
|
181
|
+
:appliedPolicyType => PBDNSMessage::PolicyType::NSIP}
|
182
|
+
|
183
|
+
dns_rr_data = [
|
184
|
+
{:name => "abc", :type => 9000, :class => 8000, :ttl => 20, :rdata => "300"},
|
185
|
+
{:name => "def", :type => 19000, :class => 18000, :ttl => 120, :rdata => "1300"}
|
186
|
+
]
|
187
|
+
|
188
|
+
dns_response_data[:rrs] = dns_rr_data.map { | d | d = dns_rr_class.new(d) }
|
189
|
+
dns_response_object = dns_response_class.new(dns_response_data)
|
190
|
+
|
191
|
+
pbdns_message_data = {
|
192
|
+
# :UUID => '12345678901233456789', :TaskPingIPv4Result => ping_result_object
|
193
|
+
:type => PBDNSMessage::Type::DNSIncomingResponseType,
|
194
|
+
:messageId => "15",
|
195
|
+
:serverIdentity => "16",
|
196
|
+
:socketFamily => PBDNSMessage::SocketFamily::INET6,
|
197
|
+
:socketProtocol => PBDNSMessage::SocketProtocol::TCP,
|
198
|
+
:from => "17",
|
199
|
+
:to => "18",
|
200
|
+
:inBytes => 70000,
|
201
|
+
:timeSec => 80000,
|
202
|
+
:timeUsec => 90000,
|
203
|
+
:id => 20000,
|
204
|
+
:question => dns_question_object,
|
205
|
+
:response => dns_response_object,
|
206
|
+
:originalRequestorSubnet => "19",
|
207
|
+
:requestorId => "Bar",
|
208
|
+
:initialRequestId => "20",
|
209
|
+
:deviceId => "21",
|
210
|
+
}
|
211
|
+
pbdns_message_object = pbdns_message_class.new(pbdns_message_data)
|
212
|
+
bin = pbdns_message_class.encode(pbdns_message_object)
|
213
|
+
plugin_4.decode(bin) do |event|
|
214
|
+
|
215
|
+
['messageId', 'serverIdentity','from','to','inBytes','timeUsec','timeSec','id', 'originalRequestorSubnet', 'requestorId' ,'initialRequestId','deviceIdf'].each { |n|
|
216
|
+
expect(event.get(n)).to eq(pbdns_message_data[n.to_sym] ) }
|
217
|
+
|
218
|
+
# enum test:
|
219
|
+
expect(event.get("type") ).to eq("DNSIncomingResponseType" )
|
220
|
+
expect(event.get("socketFamily") ).to eq("INET6" )
|
221
|
+
expect(event.get("socketProtocol") ).to eq("TCP" )
|
222
|
+
|
223
|
+
expect(event.get("question")["qName"] ).to eq(dns_question_data[:qName] )
|
224
|
+
expect(event.get("question")["qType"] ).to eq(dns_question_data[:qType] )
|
225
|
+
expect(event.get("question")["qClass"] ).to eq(dns_question_data[:qClass] )
|
226
|
+
|
227
|
+
['rcode', 'appliedPolicy','tags','queryTimeSec','queryTimeUsec'].each { |n| expect(event.get('response')[n]).to eq(dns_response_data[n.to_sym] ) }
|
228
|
+
expect(event.get("response")['appliedPolicyType'] ).to eq("NSIP" )
|
229
|
+
|
230
|
+
dns_rr_data.each_with_index { | data, index |
|
231
|
+
found = event.get("response")['rrs'][index]
|
232
|
+
['name', 'type','class','ttl','rdata'].each { |n| expect(found[n]).to eq(data[n.to_sym]) }
|
233
|
+
}
|
234
|
+
|
235
|
+
end
|
236
|
+
end # it
|
237
|
+
|
238
|
+
end # context
|
239
|
+
|
240
|
+
context "#pb3decoder_test5" do
|
241
|
+
|
242
|
+
#### Test case 5: decode test case for github issue 17 ####################################################################################################################
|
243
|
+
let(:plugin_5) { LogStash::Codecs::Protobuf.new("class_name" => "com.foo.bar.IntegerTestMessage", "include_path" => [pb_include_path + '/pb3/integertest_pb.rb'], "protobuf_version" => 3) }
|
244
|
+
|
245
|
+
before do
|
246
|
+
plugin_5.register
|
247
|
+
end
|
248
|
+
|
249
|
+
it "should return an event from protobuf data with nested classes" do
|
250
|
+
integertest_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("com.foo.bar.IntegerTestMessage").msgclass
|
251
|
+
integertest_object = integertest_class.new({:response_time => 500})
|
252
|
+
bin = integertest_class.encode(integertest_object)
|
253
|
+
plugin_5.decode(bin) do |event|
|
254
|
+
expect(event.get("response_time") ).to eq(500)
|
255
|
+
end
|
256
|
+
end # it
|
257
|
+
|
258
|
+
|
259
|
+
end # context
|
260
|
+
|
261
|
+
context "#pb3decoder_test6" do
|
262
|
+
|
263
|
+
|
264
|
+
let(:execution_context) { double("execution_context")}
|
265
|
+
let(:pipeline_id) {rand(36**8).to_s(36)}
|
266
|
+
|
267
|
+
# Test case 6: decode a message automatically loading the dependencies ##############################################################################
|
268
|
+
let(:plugin) { LogStash::Codecs::Protobuf.new(
|
269
|
+
"class_name" => "A.MessageA",
|
270
|
+
"class_file" => [ 'messageA_pb.rb' ],
|
271
|
+
"protobuf_version" => 3,
|
272
|
+
"protobuf_root_directory" => pb_include_path + '/pb3/')
|
273
|
+
}
|
274
|
+
|
275
|
+
before do
|
276
|
+
allow(plugin).to receive(:execution_context).and_return(execution_context)
|
277
|
+
allow(execution_context).to receive(:pipeline_id).and_return(pipeline_id)
|
278
|
+
|
279
|
+
# this is normally done on the input plugins we "mock" it here to avoid
|
280
|
+
# instantiating a dummy input plugin. See
|
281
|
+
# https://github.com/ph/logstash/blob/37551a89b8137c1dc6fa4fbd992584c363a36065/logstash-core/lib/logstash/inputs/base.rb#L108
|
282
|
+
plugin.execution_context = execution_context
|
283
|
+
end
|
284
|
+
|
285
|
+
it "should return an event from protobuf data" do
|
286
|
+
|
287
|
+
header_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("Header").msgclass
|
288
|
+
header_data = {:name => {'a' => 'b'}}
|
289
|
+
header_object = header_class.new(header_data)
|
290
|
+
|
291
|
+
message_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("A.MessageA").msgclass
|
292
|
+
data = {:name => "Test name", :header => header_object}
|
293
|
+
|
294
|
+
message_object = message_class.new(data)
|
295
|
+
bin = message_class.encode(message_object)
|
296
|
+
|
297
|
+
plugin.decode(bin) do |event|
|
298
|
+
expect(event.get("name") ).to eq(data[:name] )
|
299
|
+
expect(event.get("header")['name'] ).to eq(header_data[:name])
|
300
|
+
end
|
301
|
+
end # it
|
302
|
+
end # context
|
303
|
+
|
304
|
+
|
305
|
+
|
306
|
+
|
307
|
+
|
308
|
+
|
309
|
+
context "#pb3decoder_test7" do
|
310
|
+
|
311
|
+
#### Test case 6: decode test case for github issue 17 ####################################################################################################################
|
312
|
+
let(:plugin_7) { LogStash::Codecs::Protobuf.new("class_name" => "RepeatedEvents", "include_path" => [pb_include_path + '/pb3/events_pb.rb'], "protobuf_version" => 3) }
|
313
|
+
before do
|
314
|
+
plugin_7.register
|
315
|
+
end
|
316
|
+
|
317
|
+
it "should return an event from protobuf data with repeated top level objects" do
|
318
|
+
event_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("RepeatedEvent").msgclass # TODO this shouldnt be necessary because the classes are already
|
319
|
+
# specified at the end of the _pb.rb files
|
320
|
+
events_class = Google::Protobuf::DescriptorPool.generated_pool.lookup("RepeatedEvents").msgclass
|
321
|
+
test_a = event_class.new({:id => "1", :msg => "a"})
|
322
|
+
test_b = event_class.new({:id => "2", :msg => "b"})
|
323
|
+
test_c = event_class.new({:id => "3", :msg => "c"})
|
324
|
+
event_obj = events_class.new({:repeated_events=>[test_a, test_b, test_c]})
|
325
|
+
bin = events_class.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
|
+
|
336
|
+
end # context pb3decoder_test7
|
337
|
+
|
338
|
+
|
339
|
+
context "#pb3decoder_test8a" do
|
340
|
+
|
341
|
+
########################################################################################################################
|
342
|
+
let(:plugin_8a) { LogStash::Codecs::Protobuf.new("class_name" => "FantasyHorse", "class_file" => 'pb3/FantasyHorse_pb.rb',
|
343
|
+
"protobuf_root_directory" => pb_include_path, "protobuf_version" => 3, "pb3_set_oneof_metainfo" => true) }
|
344
|
+
before do
|
345
|
+
plugin_8a.register
|
346
|
+
end
|
347
|
+
|
348
|
+
it "should add meta information on oneof fields" do
|
349
|
+
pegasus_data = {:wings_length => 100}
|
350
|
+
horsey = FantasyPegasus.new(pegasus_data)
|
351
|
+
|
352
|
+
braid_data = {:braid_thickness => 10, :braiding_style => "french"}
|
353
|
+
tail_data = {:tail_length => 80, :braided => BraidedHorseTail.new(braid_data) }
|
354
|
+
tail = FantasyHorseTail.new(tail_data)
|
355
|
+
|
356
|
+
data = {:name=>"Reinhold", :pegasus => horsey, :tail => tail}
|
357
|
+
pb_obj = FantasyHorse.new(data)
|
358
|
+
bin = FantasyHorse.encode(pb_obj)
|
359
|
+
plugin_8a.decode(bin) do |event|
|
360
|
+
|
361
|
+
expect(event.get("name") ).to eq(data[:name])
|
362
|
+
expect(event.get("pegasus")["wings_length"] ).to eq(pegasus_data[:wings_length])
|
363
|
+
expect(event.get("tail")['tail_length'] ).to eq(tail_data[:tail_length])
|
364
|
+
expect(event.get("tail")['braided']['braiding_style'] ).to eq(braid_data[:braiding_style])
|
365
|
+
expect(event.get("@metadata")["pb_oneof"]["horse_type"] ).to eq("pegasus")
|
366
|
+
expect(event.get("@metadata")["pb_oneof"]["tail"]["hair_type"] ).to eq("braided")
|
367
|
+
|
368
|
+
end
|
369
|
+
end # it
|
370
|
+
|
371
|
+
|
372
|
+
end # context pb3decoder_test8a
|
373
|
+
|
374
|
+
|
375
|
+
|
376
|
+
|
377
|
+
context "#pb3decoder_test8b" do
|
378
|
+
|
379
|
+
########################################################################################################################
|
380
|
+
let(:plugin_8b) { LogStash::Codecs::Protobuf.new("class_name" => "FantasyHorse", "class_file" => 'pb3/FantasyHorse_pb.rb',
|
381
|
+
"protobuf_root_directory" => pb_include_path, "protobuf_version" => 3, "pb3_set_oneof_metainfo" => false) }
|
382
|
+
before do
|
383
|
+
plugin_8b.register
|
384
|
+
end
|
385
|
+
|
386
|
+
it "should not add meta information on oneof fields" do
|
387
|
+
pegasus_data = {:wings_length => 100}
|
388
|
+
horsey = FantasyPegasus.new(pegasus_data)
|
389
|
+
|
390
|
+
braid_data = {:braid_thickness => 10, :braiding_style => "french"}
|
391
|
+
tail_data = {:tail_length => 80, :braided => BraidedHorseTail.new(braid_data) }
|
392
|
+
tail = FantasyHorseTail.new(tail_data)
|
393
|
+
|
394
|
+
data = {:name=>"Winfried", :pegasus => horsey, :tail => tail}
|
395
|
+
pb_obj = FantasyHorse.new(data)
|
396
|
+
bin = FantasyHorse.encode(pb_obj)
|
397
|
+
plugin_8b.decode(bin) do |event|
|
398
|
+
expect(event.get("name") ).to eq(data[:name])
|
399
|
+
expect(event.get("pegasus")["wings_length"] ).to eq(pegasus_data[:wings_length])
|
400
|
+
expect(event.get("tail")['tail_length'] ).to eq(tail_data[:tail_length])
|
401
|
+
expect(event.get("tail")['braided']['braiding_style'] ).to eq(braid_data[:braiding_style])
|
402
|
+
expect(event.get("@metadata")["pb_oneof"]).to be_nil
|
403
|
+
|
404
|
+
end
|
405
|
+
end # it
|
406
|
+
|
407
|
+
|
408
|
+
end # context pb3decoder_test8b
|
409
|
+
|
410
|
+
|
411
|
+
context "#pb3decoder_test8c" do # same test as 8a just with different one_of options selected
|
412
|
+
|
413
|
+
########################################################################################################################
|
414
|
+
let(:plugin_8c) { LogStash::Codecs::Protobuf.new("class_name" => "FantasyHorse", "class_file" => 'pb3/FantasyHorse_pb.rb',
|
415
|
+
"protobuf_root_directory" => pb_include_path, "protobuf_version" => 3, "pb3_set_oneof_metainfo" => true) }
|
416
|
+
before do
|
417
|
+
plugin_8c.register
|
418
|
+
end
|
419
|
+
|
420
|
+
it "should add meta information on oneof fields" do
|
421
|
+
unicorn_data = {:horn_length => 30}
|
422
|
+
horsey = FantasyUnicorn.new(unicorn_data)
|
423
|
+
|
424
|
+
natural_data = {:wavyness => "B"}
|
425
|
+
tail_data = {:tail_length => 80, :natural => NaturalHorseTail.new(natural_data) }
|
426
|
+
tail = FantasyHorseTail.new(tail_data)
|
427
|
+
|
428
|
+
data = {:name=>"Hubert", :unicorn => horsey, :tail => tail}
|
429
|
+
pb_obj = FantasyHorse.new(data)
|
430
|
+
bin = FantasyHorse.encode(pb_obj)
|
431
|
+
plugin_8c.decode(bin) do |event|
|
432
|
+
expect(event.get("name") ).to eq(data[:name])
|
433
|
+
expect(event.get("unicorn")["horn_length"] ).to eq(unicorn_data[:horn_length])
|
434
|
+
expect(event.get("tail")['tail_length'] ).to eq(tail_data[:tail_length])
|
435
|
+
expect(event.get("tail")['natural']['wavyness'] ).to eq(natural_data[:wavyness])
|
436
|
+
expect(event.get("@metadata")["pb_oneof"]["horse_type"] ).to eq("unicorn")
|
437
|
+
expect(event.get("@metadata")["pb_oneof"]["tail"]["hair_type"] ).to eq("natural")
|
438
|
+
|
439
|
+
end
|
440
|
+
end # it
|
441
|
+
|
442
|
+
|
443
|
+
end # context pb3decoder_test8c
|
444
|
+
|
445
|
+
end # describe
|