logstash-codec-protobuf 1.0.5 → 1.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +20 -1
  3. data/Gemfile +1 -1
  4. data/LICENSE +2 -3
  5. data/README.md +147 -40
  6. data/docs/index.asciidoc +173 -41
  7. data/lib/logstash/codecs/protobuf.rb +598 -238
  8. data/logstash-codec-protobuf.gemspec +3 -3
  9. data/spec/codecs/{protobuf_spec.rb → pb2_spec.rb} +81 -54
  10. data/spec/codecs/pb3_decode_spec.rb +445 -0
  11. data/spec/codecs/pb3_encode_spec.rb +243 -0
  12. data/spec/helpers/pb2/event.pb.rb +19 -0
  13. data/spec/helpers/pb2/event.proto +12 -0
  14. data/spec/helpers/pb2/header/header.pb.rb +16 -0
  15. data/spec/helpers/pb2/header/header.proto +8 -0
  16. data/spec/helpers/pb3/FantasyHorse_pb.rb +44 -0
  17. data/spec/helpers/pb3/ProbeResult_pb.rb +26 -0
  18. data/spec/helpers/pb3/dnsmessage_pb.rb +82 -0
  19. data/spec/helpers/pb3/events.proto3 +10 -0
  20. data/spec/helpers/pb3/events_pb.rb +17 -0
  21. data/spec/helpers/pb3/header/header.proto3 +7 -0
  22. data/spec/helpers/pb3/header/header_pb.rb +12 -0
  23. data/spec/helpers/pb3/integertest_pb.rb +20 -0
  24. data/spec/helpers/pb3/messageA.proto3 +12 -0
  25. data/spec/helpers/pb3/messageA_pb.rb +16 -0
  26. data/spec/helpers/pb3/messageB.proto3 +12 -0
  27. data/spec/helpers/pb3/messageB_pb.rb +16 -0
  28. data/spec/helpers/pb3/rum2_pb.rb +87 -0
  29. data/spec/helpers/pb3/rum3_pb.rb +87 -0
  30. data/spec/helpers/pb3/rum_pb.rb +87 -0
  31. metadata +62 -34
  32. data/lib/net/jpountz/lz4/lz4/1.3.0/lz4-1.3.0.jar +0 -0
  33. data/lib/org/apache/kafka/kafka-clients/0.11.0.0/kafka-clients-0.11.0.0.jar +0 -0
  34. data/lib/org/apache/logging/log4j/log4j-api/2.8.2/log4j-api-2.8.2.jar +0 -0
  35. data/lib/org/apache/logging/log4j/log4j-slf4j-impl/2.8.2/log4j-slf4j-impl-2.8.2.jar +0 -0
  36. data/lib/org/slf4j/slf4j-api/1.7.24/slf4j-api-1.7.24.jar +0 -0
  37. data/lib/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar +0 -0
  38. data/lib/org/xerial/snappy/snappy-java/1.1.2.6/snappy-java-1.1.2.6.jar +0 -0
  39. data/spec/codecs/protobuf3_spec.rb +0 -147
  40. data/vendor/jar-dependencies/runtime-jars/kafka-clients-0.11.0.0.jar +0 -0
  41. data/vendor/jar-dependencies/runtime-jars/log4j-api-2.8.2.jar +0 -0
  42. data/vendor/jar-dependencies/runtime-jars/log4j-slf4j-impl-2.8.2.jar +0 -0
  43. data/vendor/jar-dependencies/runtime-jars/lz4-1.3.0.jar +0 -0
  44. data/vendor/jar-dependencies/runtime-jars/slf4j-api-1.7.24.jar +0 -0
  45. data/vendor/jar-dependencies/runtime-jars/slf4j-api-1.7.25.jar +0 -0
  46. 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.0.5'
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.1'
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" => ['spec/helpers/pb2/unicorn.pb.rb']) }
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 decodePB2
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" => ['spec/helpers/pb2/unicorn_event.pb.rb'])
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
- insist { data.is_a? String }
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" => ['spec/helpers/pb2/human.pb.rb'])
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
- insist { data.is_a? String }
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" => ['spec/helpers/pb2/ColourTestcase.pb.rb'])
179
+ next LogStash::Codecs::Protobuf.new("class_name" => "ColourProtoTest", "include_path" => [pb_include_path + '/pb2/ColourTestcase.pb.rb'])
184
180
  end
185
181
 
186
- require 'spec/helpers/pb2/ColourTestcase.pb.rb' # otherwise we cant use the colour enums in the next line
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
- insist { data.is_a? String }
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