logstash-filter-useragent 3.2.4-java → 3.3.1-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
22
22
 
23
23
  # Gem dependencies
24
24
  s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
25
+ s.add_runtime_dependency 'logstash-mixin-ecs_compatibility_support', '~> 1.1'
25
26
  s.add_development_dependency 'logstash-devutils'
26
27
  end
27
28
 
@@ -1,116 +1,448 @@
1
1
  # encoding: utf-8
2
-
3
2
  require "logstash/devutils/rspec/spec_helper"
3
+ require 'logstash/plugin_mixins/ecs_compatibility_support/spec_helper'
4
4
  require "logstash/filters/useragent"
5
5
 
6
6
  describe LogStash::Filters::UserAgent do
7
7
 
8
- describe "defaults" do
9
- config <<-CONFIG
10
- filter {
11
- useragent {
12
- source => "message"
13
- target => "ua"
8
+ subject { LogStash::Filters::UserAgent.new(options) }
9
+
10
+ let(:options) { { 'source' => 'message' } }
11
+ let(:message) { "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36" }
12
+
13
+ let(:event) { LogStash::Event.new('message' => message) }
14
+
15
+ context 'with target', :ecs_compatibility_support do
16
+ ecs_compatibility_matrix(:disabled, :v1) do |ecs_select|
17
+
18
+ let(:ecs_compatibility?) { ecs_select.active_mode != :disabled }
19
+
20
+ before(:each) do
21
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
22
+ end
23
+
24
+ config <<-CONFIG
25
+ filter {
26
+ useragent {
27
+ source => "message"
28
+ target => "ua"
29
+ }
14
30
  }
15
- }
16
- CONFIG
31
+ CONFIG
32
+
33
+ sample "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.63 Safari/537.31" do
34
+ expect( subject.to_hash ).to include("ua")
35
+ expect( subject.get("[ua][name]") ).to eql "Chrome"
36
+ if ecs_compatibility?
37
+ expect( subject.get("[ua][os][name]") ).to eql "Linux"
38
+ expect( subject.get("[ua][os][full]") ).to eql "Linux"
39
+ expect( subject.get("[ua][device][name]") ).to eql "Other"
40
+ ua_metadata = subject.get("[@metadata][filter][user_agent]")
41
+ expect( ua_metadata ).to include 'version' => { 'major' => '26', 'minor' => '0', 'patch' => '1410' }
42
+ expect( subject.get("[ua][version]") ).to eql "26.0.1410.63"
43
+ expect( subject.get("[ua]").keys ).to_not include 'major'
44
+ expect( subject.get("[ua]").keys ).to_not include 'minor'
45
+ else
46
+ expect( subject.get("[ua][os_name]") ).to eql "Linux"
47
+ expect( subject.get("[ua][os_full]") ).to eql "Linux"
48
+ expect( subject.get("[ua][os]") ).to eql "Linux"
49
+ expect( subject.get("[ua][device]") ).to eql "Other"
50
+ expect( subject.get("[ua][major]") ).to eql "26"
51
+ expect( subject.get("[ua][minor]") ).to eql "0"
52
+ end
53
+
54
+ expect( subject.get("[ua][name]").encoding ).to eql Encoding::UTF_8
55
+ end
56
+
57
+ sample "MacOutlook/16.24.0.190414 (Intelx64 Mac OS X Version 10.14.4 (Build 18E226))" do
58
+ expect( subject.to_hash ).to include("ua")
59
+ expect( subject.get("[ua][name]") ).to eql "MacOutlook"
60
+ if ecs_compatibility?
61
+ expect( subject.get("[ua][version]") ).to eql "16.24.0.190414"
62
+ expect( subject.get("[ua][os][full]") ).to eql "Mac OS X 10.14.4"
63
+ expect( subject.get("[ua][os][name]") ).to eql "Mac OS X"
64
+ expect( subject.get("[ua][os][version]") ).to eql '10.14.4'
65
+ expect( subject.get("[ua][device][name]") ).to eql 'Mac'
66
+
67
+ expect( subject.get("[ua][os][name]").encoding ).to eql Encoding::UTF_8
68
+ else
69
+ expect( subject.get("[ua][major]") ).to eql "16"
70
+ expect( subject.get("[ua][minor]") ).to eql "24"
71
+ expect( subject.get("[ua][patch]") ).to eql "0"
72
+ expect( subject.get("[ua][os_full]") ).to eql "Mac OS X 10.14.4"
73
+ expect( subject.get("[ua][os_name]") ).to eql "Mac OS X"
74
+ expect( subject.get("[ua][os_major]") ).to eql '10'
75
+ expect( subject.get("[ua][os_minor]") ).to eql '14'
76
+ expect( subject.get("[ua][device]") ).to eql 'Mac'
77
+
78
+ expect( subject.get("[ua][os]") ).to eql "Mac OS X"
79
+ expect( subject.get("[ua][os]").encoding ).to eql Encoding::UTF_8
80
+ end
81
+ end
82
+
83
+ # Safari 12 on Mojave
84
+ sample "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Safari/605.1.15" do
85
+ expect( subject.to_hash ).to include("ua")
86
+ expect( subject.get("[ua][name]") ).to eql "Safari"
87
+ if ecs_compatibility?
88
+ expect( subject.get("[ua][version]") ).to eql "12.0"
89
+ expect( subject.get("[ua][os][full]") ).to eql "Mac OS X 10.14"
90
+ expect( subject.get("[ua][os][name]") ).to eql "Mac OS X"
91
+ expect( subject.get("[ua][os][version]") ).to eql '10.14'
92
+ ua_metadata = subject.get("[@metadata][filter][user_agent][os]")
93
+ expect( ua_metadata ).to include 'version' => { 'major' => '10', 'minor' => '14' }
94
+
95
+ expect( subject.get("[@metadata][filter][user_agent][os][version][major]").encoding ).to eql Encoding::UTF_8
96
+ else
97
+ expect( subject.get("[ua][major]") ).to eql "12"
98
+ expect( subject.get("[ua][minor]") ).to eql "0"
99
+ expect( subject.get("[ua][patch]") ).to be nil
100
+ expect( subject.get("[ua][os_full]") ).to eql "Mac OS X 10.14"
101
+ expect( subject.get("[ua][os_name]") ).to eql "Mac OS X"
102
+ expect( subject.get("[ua][os_major]") ).to eql '10'
103
+ expect( subject.get("[ua][os_minor]") ).to eql '14'
104
+
105
+ expect( subject.get("[ua][os_major]").encoding ).to eql Encoding::UTF_8
106
+ end
107
+ end
108
+
109
+ # Safari 7 on Mac OS X (Mavericks)
110
+ sample "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/7046A194A" do
111
+ expect( subject.to_hash ).to include("ua")
112
+ expect( subject.get("[ua][name]") ).to eql "Safari"
113
+ if ecs_compatibility?
114
+ expect( subject.get("[ua][version]") ).to eql "7.0.3"
115
+ expect( subject.get("[ua][os][full]") ).to eql "Mac OS X 10.9.3"
116
+ expect( subject.get("[ua][os][name]") ).to eql "Mac OS X"
117
+ expect( subject.get("[ua][device][name]") ).to eql 'Mac'
118
+ else
119
+ expect( subject.get("[ua][major]") ).to eql "7"
120
+ expect( subject.get("[ua][minor]") ).to eql "0"
121
+ expect( subject.get("[ua][patch]") ).to eql "3"
122
+ expect( subject.get("[ua][os_full]") ).to eql "Mac OS X 10.9.3"
123
+ expect( subject.get("[ua][os_name]") ).to eql "Mac OS X"
124
+ expect( subject.get("[ua][os_major]") ).to eql '10'
125
+ expect( subject.get("[ua][os_minor]") ).to eql '9'
126
+ expect( subject.get("[ua][device]") ).to eql 'Mac'
127
+ end
128
+ end
129
+
130
+ sample "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:45.0) Gecko/20100101 Firefox/45.0" do
131
+ expect( subject.to_hash ).to include("ua")
132
+ expect( subject.get("[ua][name]") ).to eql "Firefox"
133
+ if ecs_compatibility?
134
+ expect( subject.get("[ua][version]") ).to eql "45.0"
135
+ expect( subject.get("[ua][os][full]") ).to eql "Mac OS X 10.11"
136
+ expect( subject.get("[ua][os][name]") ).to eql "Mac OS X"
137
+ expect( subject.get("[ua][os][version]") ).to eql '10.11'
138
+ expect( subject.get("[ua][device][name]") ).to eql 'Mac'
139
+ else
140
+ expect( subject.get("[ua][major]") ).to eql "45"
141
+ expect( subject.get("[ua][minor]") ).to eql "0"
142
+ expect( subject.get("[ua][patch]") ).to be nil
143
+ expect( subject.get("[ua][os_full]") ).to eql "Mac OS X 10.11"
144
+ expect( subject.get("[ua][os_name]") ).to eql "Mac OS X"
145
+ expect( subject.get("[ua][os_major]") ).to eql '10'
146
+ expect( subject.get("[ua][os_minor]") ).to eql '11'
147
+ expect( subject.get("[ua][device]") ).to eql 'Mac'
148
+ end
149
+ end
150
+
151
+ # IE7 Vista
152
+ sample "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)" do
153
+ expect( subject.to_hash ).to include("ua")
154
+ if ecs_compatibility?
155
+ expect( subject.get("[ua][os][name]") ).to eql "Windows"
156
+ expect( subject.get("[ua][os][version]") ).to eql 'Vista'
157
+ expect( subject.get("[ua][device][name]") ).to eql 'Other'
158
+
159
+ expect( subject.get("[ua][device][name]").encoding ).to eql Encoding::UTF_8
160
+ else
161
+ expect( subject.get("[ua][os_name]") ).to eql "Windows"
162
+ expect( subject.get("[ua][os_major]") ).to eql 'Vista'
163
+ expect( subject.get("[ua][os_minor]") ).to be nil
164
+ expect( subject.get("[ua][device]") ).to eql 'Other'
165
+
166
+ expect( subject.get("[ua][device]").encoding ).to eql Encoding::UTF_8
167
+ end
168
+ end
169
+
170
+ # IE8 XP
171
+ sample "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.5.30729)" do
172
+ expect( subject.to_hash ).to include("ua")
173
+ expect( subject.get("[ua][name]") ).to eql 'IE'
174
+ if ecs_compatibility?
175
+ expect( subject.get("[ua][os][name]") ).to eql 'Windows'
176
+ expect( subject.get("[ua][os][version]") ).to eql 'XP'
177
+ expect( subject.get("[ua][device][name]") ).to eql 'Other'
178
+ else
179
+ expect( subject.get("[ua][os_name]") ).to eql 'Windows'
180
+ expect( subject.get("[ua][os_major]") ).to eql 'XP'
181
+ expect( subject.get("[ua][os_minor]") ).to be nil
182
+ expect( subject.get("[ua][device]") ).to eql 'Other'
183
+ end
184
+ end
185
+
186
+ # # Windows 8.1
187
+ sample "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246" do
188
+ expect( subject.to_hash ).to include("ua")
189
+ expect( subject.get("[ua][name]") ).to eql 'Edge'
190
+ if ecs_compatibility?
191
+ expect( subject.get("[ua][os][name]") ).to eql 'Windows'
192
+ expect( subject.get("[ua][os][version]") ).to eql '8.1'
193
+ else
194
+ expect( subject.get("[ua][os_name]") ).to eql 'Windows'
195
+ expect( subject.get("[ua][os_major]") ).to eql '8'
196
+ expect( subject.get("[ua][os_minor]") ).to eql '1'
197
+ end
198
+ end
199
+
200
+ # Windows 10
201
+ sample "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.50" do
202
+ expect( subject.to_hash ).to include("ua")
203
+ expect( subject.get("[ua][name]") ).to eql "Edge"
204
+ if ecs_compatibility?
205
+ expect( subject.get("[ua][version]") ).to eql "89.0.774.50"
206
+ expect( subject.get("[ua][os][full]") ).to eql "Windows 10"
207
+ expect( subject.get("[ua][os][name]") ).to eql "Windows"
208
+ expect( subject.get("[ua][os][version]") ).to eql '10'
209
+ ua_metadata = subject.get("[@metadata][filter][user_agent][os]")
210
+ expect( ua_metadata ).to include 'version' => { 'major' => '10' }
211
+ expect( subject.get("[ua][device][name]") ).to eql 'Other'
212
+ else
213
+ expect( subject.get("[ua][os_name]") ).to eql "Windows"
214
+ expect( subject.get("[ua][os_major]") ).to eql '10'
215
+ expect( subject.get("[ua][os_minor]") ).to be nil
216
+ expect( subject.get("[ua][device]") ).to eql 'Other'
217
+ end
218
+ end
219
+
220
+ # Chrome on Linux
221
+ sample "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36" do
222
+ expect( subject.to_hash ).to include("ua")
223
+ expect( subject.get("[ua][name]") ).to eql 'Chrome'
224
+ if ecs_compatibility?
225
+ expect( subject.get("[ua][os][name]") ).to eql "Linux"
226
+ expect( subject.get("[ua][os][version]") ).to be nil
227
+ expect( subject.get("[ua][device][name]") ).to eql 'Other'
228
+ else
229
+ expect( subject.get("[ua][os_name]") ).to eql "Linux"
230
+ expect( subject.get("[ua][os_major]") ).to be nil
231
+ expect( subject.get("[ua][os_minor]") ).to be nil
232
+ expect( subject.get("[ua][device]") ).to eql 'Other'
233
+ end
234
+ end
17
235
 
18
- sample "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.63 Safari/537.31" do
19
- insist { subject }.include?("ua")
20
- insist { subject.get("[ua][name]") } == "Chrome"
21
- insist { subject.get("[ua][os]") } == "Linux"
22
- insist { subject.get("[ua][major]") } == "26"
23
- insist { subject.get("[ua][minor]") } == "0"
24
236
  end
237
+ end
238
+
239
+ context "manually specified regexes file", :ecs_compatibility_support do
240
+ ecs_compatibility_matrix(:disabled, :v1) do |ecs_select|
241
+
242
+ let(:ecs_compatibility?) { ecs_select.active_mode != :disabled }
243
+
244
+ before(:each) do
245
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
246
+ end
247
+
248
+ config <<-CONFIG
249
+ filter {
250
+ useragent {
251
+ source => "message"
252
+ target => "[ua]"
253
+ regexes => "build/resources/main/regexes.yaml"
254
+ }
255
+ }
256
+ CONFIG
257
+
258
+ sample "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.63 Safari/537.31" do
259
+ expect( subject.to_hash ).to include("ua")
260
+ if ecs_compatibility?
261
+ expect( subject.get("[ua][name]") ).to eql "Chrome"
262
+ expect( subject.get("[ua][os][name]") ).to eql "Linux"
263
+ expect( subject.get("[ua][version]") ).to eql "26.0.1410.63"
264
+ expect( subject.get("[@metadata][filter][user_agent][version][major]") ).to eql "26"
265
+ expect( subject.get("[@metadata][filter][user_agent][version][minor]") ).to eql "0"
266
+ else
267
+ expect( subject.get("[ua][name]") ).to eql "Chrome"
268
+ expect( subject.get("[ua][os]") ).to eql "Linux"
269
+ expect( subject.get("[ua][major]") ).to eql "26"
270
+ expect( subject.get("[ua][minor]") ).to eql "0"
271
+ end
272
+ end
25
273
 
26
- sample "MacOutlook/16.24.0.190414 (Intelx64 Mac OS X Version 10.14.4 (Build 18E226))" do
27
- insist { subject }.include?("ua")
28
- insist { subject.get("[ua][name]") } == "MacOutlook"
29
- insist { subject.get("[ua][major]") } == "16"
30
- insist { subject.get("[ua][minor]") } == "24"
31
- insist { subject.get("[ua][os]") } == "Mac OS X"
32
- insist { subject.get("[ua][os_name]") } == "Mac OS X"
33
- insist { subject.get("[ua][os_major]") } == "10"
34
- insist { subject.get("[ua][os_minor]") } == "14"
35
274
  end
36
275
  end
37
276
 
38
- describe "manually specified regexes file" do
39
- config <<-CONFIG
40
- filter {
41
- useragent {
42
- source => "message"
43
- target => "ua"
44
- regexes => "build/resources/main/regexes.yaml"
277
+ context "without target field", :ecs_compatibility_support do
278
+ ecs_compatibility_matrix(:disabled, :v1) do |ecs_select|
279
+
280
+ let(:ecs_compatibility?) { ecs_select.active_mode != :disabled }
281
+
282
+ before(:each) do
283
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
284
+ end
285
+
286
+ config <<-CONFIG
287
+ filter {
288
+ useragent {
289
+ source => "message"
290
+ }
45
291
  }
46
- }
47
- CONFIG
292
+ CONFIG
48
293
 
49
- sample "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.63 Safari/537.31" do
50
- insist { subject }.include?("ua")
51
- insist { subject.get("[ua][name]") } == "Chrome"
52
- insist { subject.get("[ua][os]") } == "Linux"
53
- insist { subject.get("[ua][major]") } == "26"
54
- insist { subject.get("[ua][minor]") } == "0"
294
+ sample "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.63 Safari/537.31" do
295
+ if ecs_compatibility? # [user_agent] default target in ECS
296
+ expect( subject.get("user_agent") ).to include 'name' => 'Chrome'
297
+ expect( subject.get("user_agent") ).to include 'os' => hash_including('name' => 'Linux')
298
+ expect( subject.get("user_agent") ).to include 'version' => '26.0.1410.63'
299
+ else
300
+ expect( subject.get("name") ).to eql "Chrome"
301
+ expect( subject.get("os_name") ).to eql "Linux"
302
+ expect( subject.get("os") ).to eql "Linux"
303
+ expect( subject.get("major") ).to eql "26"
304
+ expect( subject.get("minor") ).to eql "0"
305
+ expect( subject.get("patch") ).to eql "1410"
306
+ expect( subject.get("version") ).to eql "26.0.1410.63"
307
+ end
308
+ end
55
309
  end
56
310
  end
57
-
58
- describe "Without target field" do
59
- config <<-CONFIG
60
- filter {
61
- useragent {
62
- source => "message"
311
+
312
+ context "nested target field", :ecs_compatibility_support do
313
+ ecs_compatibility_matrix(:disabled, :v1) do
314
+
315
+ before(:each) do
316
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
317
+ end
318
+
319
+ config <<-CONFIG
320
+ filter {
321
+ useragent {
322
+ source => "message"
323
+ target => "[foo][bar]"
324
+ }
63
325
  }
64
- }
65
- CONFIG
326
+ CONFIG
327
+
328
+ # Facebook App User Agent
329
+ sample "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) " +
330
+ "Mobile/15E148 [FBAN/FBIOS;FBDV/iPhone11,8;FBMD/iPhone;FBSN/iOS;FBSV/13.3.1;FBSS/2;FBID/phone;FBLC/en_US;FBOP/5;FBCR/]" do
331
+ expect( subject ).to include 'foo'
332
+ expect( subject.get('foo') ).to include 'bar'
333
+ expect( subject.get('foo')['bar'] ).to include "name" => "Facebook"
334
+ end
335
+
336
+ end
337
+ end
338
+
339
+ context "without user agent", :ecs_compatibility_support do
340
+ ecs_compatibility_matrix(:disabled, :v1) do |ecs_select|
341
+
342
+ let(:ecs_compatibility?) { ecs_select.active_mode != :disabled }
343
+
344
+ before(:each) do
345
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
346
+ end
347
+
348
+ config <<-CONFIG
349
+ filter {
350
+ useragent {
351
+ source => "message"
352
+ target => "ua"
353
+ }
354
+ }
355
+ CONFIG
356
+
357
+ sample "foo" => "bar" do
358
+ expect( subject.to_hash ).to_not include("ua")
359
+ end
360
+
361
+ sample "" do
362
+ expect( subject.to_hash ).to_not include("ua")
363
+ end
66
364
 
67
- sample "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.63 Safari/537.31" do
68
- insist { subject.get("name") } == "Chrome"
69
- insist { subject.get("os") } == "Linux"
70
- insist { subject.get("major") } == "26"
71
- insist { subject.get("minor") } == "0"
72
365
  end
73
366
  end
74
367
 
75
- describe "Without user agent" do
368
+ describe "non-exact UA data" do
76
369
  config <<-CONFIG
77
370
  filter {
78
371
  useragent {
79
372
  source => "message"
80
- target => "ua"
373
+ target => "user_agent"
81
374
  }
82
375
  }
83
376
  CONFIG
84
377
 
85
- sample "foo" => "bar" do
86
- reject { subject }.include?("ua")
378
+ sample 'Prefix DATA! Mozilla/5.0 (Android 11; Mobile; rv:68.0) Gecko/68.0 Firefox/86.0' do
379
+ expect( subject.to_hash ).to include("user_agent")
380
+ expect( subject.get('user_agent') ).to include "name" => "Firefox Mobile", "version" => '86.0', "os_name" => "Android"
87
381
  end
88
382
 
89
- sample "" do
90
- reject { subject }.include?("ua")
383
+ end
384
+
385
+ context "with prefix", :ecs_compatibility_support do
386
+ ecs_compatibility_matrix(:disabled, :v1) do |ecs_select|
387
+
388
+ let(:message) { 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0' }
389
+ let(:options) { super().merge('prefix' => 'pre_') }
390
+
391
+ before(:each) do
392
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
393
+ end
394
+
395
+ it 'works in legacy mode with prefix (without a warning)' do
396
+ expect( subject.logger ).to_not receive(:warn)
397
+ subject.register
398
+
399
+ subject.filter(event)
400
+
401
+ expect( event.to_hash ).to include('pre_name' => 'Firefox', 'pre_version' => '78.0')
402
+ end if ecs_select.active_mode == :disabled
403
+
404
+ it 'warns in ECS mode (and ignores prefix)' do
405
+ expect( subject.logger ).to receive(:warn).with /Field prefix isn't supported in ECS compatibility mode/
406
+ subject.register
407
+
408
+ subject.filter(event)
409
+
410
+ expect( event.to_hash.keys.find { |key| key.index('pre_') } ).to be nil
411
+ expect( event.get('user_agent').keys.find { |key| key.index('pre_') } ).to be nil
412
+ expect( event.get('user_agent') ).to include('name' => 'Firefox', 'version' => '78.0')
413
+ end if ecs_select.active_mode != :disabled
414
+
91
415
  end
92
416
  end
93
417
 
94
- describe "LRU object identity" do
95
- let(:ua_string) { "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36" }
96
- let(:uafilter) { LogStash::Filters::UserAgent.new("source" => "foo") }
97
- let(:ua_data) { uafilter.lookup_useragent(ua_string) }
418
+ context "no prefix", :ecs_compatibility_support do
419
+ ecs_compatibility_matrix(:disabled, :v1) do
98
420
 
99
- subject(:target) { LogStash::Event.new("foo" => ua_string) }
421
+ let(:message) { 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0' }
100
422
 
101
- before do
102
- uafilter.register
423
+ before(:each) do
424
+ allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
425
+ end
103
426
 
104
- # Stub this out because this UA doesn't have this field
105
- allow(ua_data.userAgent).to receive(:patchMinor).and_return("foo")
427
+ it 'does not warn' do
428
+ expect( subject.logger ).to_not receive(:warn)
429
+ subject.register
430
+ end
106
431
 
107
- # expect(event).receive(:lookup_useragent)
108
- uafilter.filter(target)
432
+ end
433
+ end
434
+
435
+ describe "LRU object identity" do
436
+
437
+ let(:ua_data) { subject.send :lookup_useragent, message }
438
+
439
+ before do
440
+ subject.register
441
+ subject.filter(event)
109
442
  end
110
443
 
111
444
  {
112
445
  "name" => lambda {|uad| uad.userAgent.family},
113
- "os" => lambda {|uad| uad.os.family},
114
446
  "os_name" => lambda {|uad| uad.os.family},
115
447
  "os_major" => lambda {|uad| uad.os.major},
116
448
  "os_minor" => lambda {|uad| uad.os.minor},
@@ -118,11 +450,10 @@ describe LogStash::Filters::UserAgent do
118
450
  "major" => lambda {|uad| uad.userAgent.major},
119
451
  "minor" => lambda {|uad| uad.userAgent.minor},
120
452
  "patch" => lambda {|uad| uad.userAgent.patch},
121
- "build" => lambda {|uad| uad.userAgent.patchMinor}
122
453
  }.each do |field, uad_getter|
123
454
  context "for the #{field} field" do
124
- let(:value) {uad_getter.call(ua_data)}
125
- let(:target_field) { target.get(field)}
455
+ let(:value) { uad_getter.call(ua_data) }
456
+ let(:target_field) { event.get(field) }
126
457
 
127
458
  it "should not have a nil value" do
128
459
  expect(target_field).to be_truthy
@@ -135,6 +466,10 @@ describe LogStash::Filters::UserAgent do
135
466
  it "should dup/clone the field to prevent cache corruption" do
136
467
  expect(target_field.object_id).not_to eql(value.object_id)
137
468
  end
469
+
470
+ it "should be an utf-8 string" do
471
+ expect(target_field.encoding.name).to eql 'UTF-8'
472
+ end
138
473
  end
139
474
  end
140
475
  end
@@ -150,11 +485,25 @@ describe LogStash::Filters::UserAgent do
150
485
  CONFIG
151
486
 
152
487
  sample "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.63 Safari/537.31" do
153
- insist { subject.to_hash }.include?("message")
154
- insist { subject.get("[message][name]") } == "Chrome"
155
- insist { subject.get("[message][os]") } == "Linux"
156
- insist { subject.get("[message][major]") } == "26"
157
- insist { subject.get("[message][minor]") } == "0"
488
+ expect( subject.to_hash ).to include("message")
489
+ expect( subject.get("[message][name]") ).to eql "Chrome"
490
+ expect( subject.get("[message][os]") ).to eql "Linux"
491
+ expect( subject.get("[message][major]") ).to eql "26"
492
+ expect( subject.get("[message][minor]") ).to eql "0"
158
493
  end
159
494
  end
495
+
496
+ context 'exception handling' do
497
+
498
+ before do
499
+ subject.register
500
+ expect(subject).to receive(:lookup_useragent).and_raise RuntimeError.new('this is a test')
501
+ end
502
+
503
+ it 'errors do not propagate' do
504
+ expect(subject.logger).to receive(:error).with(/Unknown error while parsing user agent data/, hash_including(exception: RuntimeError, message: 'this is a test'))
505
+ expect { subject.filter(event) }.not_to raise_error
506
+ end
507
+
508
+ end
160
509
  end