fluent-plugin-windows-eventlog 0.8.1 → 0.8.2

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.
@@ -1,600 +1,619 @@
1
- require 'helper'
2
- require 'fileutils'
3
- require 'generate-windows-event'
4
-
5
- # Monkey patch for testing
6
- class Winevt::EventLog::Session
7
- def ==(obj)
8
- self.server == obj.server &&
9
- self.domain == obj.domain &&
10
- self.username == obj.username &&
11
- self.password == obj.password &&
12
- self.flags == obj.flags
13
- end
14
- end
15
-
16
- class WindowsEventLog2InputTest < Test::Unit::TestCase
17
-
18
- def setup
19
- Fluent::Test.setup
20
- end
21
-
22
- CONFIG = config_element("ROOT", "", {"tag" => "fluent.eventlog"}, [
23
- config_element("storage", "", {
24
- '@type' => 'local',
25
- 'persistent' => false
26
- })
27
- ])
28
-
29
- XML_RENDERING_CONFIG = config_element("ROOT", "", {"tag" => "fluent.eventlog",
30
- "render_as_xml" => true}, [
31
- config_element("storage", "", {
32
- '@type' => 'local',
33
- 'persistent' => false
34
- })
35
- ])
36
-
37
- def create_driver(conf = CONFIG)
38
- Fluent::Test::Driver::Input.new(Fluent::Plugin::WindowsEventLog2Input).configure(conf)
39
- end
40
-
41
- def test_configure
42
- d = create_driver CONFIG
43
- assert_equal 'fluent.eventlog', d.instance.tag
44
- assert_equal 2, d.instance.read_interval
45
- assert_equal [], d.instance.channels
46
- assert_false d.instance.read_existing_events
47
- assert_false d.instance.render_as_xml
48
- assert_nil d.instance.refresh_subscription_interval
49
- end
50
-
51
- sub_test_case "configure" do
52
- test "refresh subscription interval" do
53
- d = create_driver config_element("ROOT", "", {"tag" => "fluent.eventlog",
54
- "refresh_subscription_interval" => "2m"}, [
55
- config_element("storage", "", {
56
- '@type' => 'local',
57
- 'persistent' => false
58
- })
59
- ])
60
- assert_equal 120, d.instance.refresh_subscription_interval
61
- end
62
-
63
- test "subscribe directive" do
64
- d = create_driver config_element("ROOT", "", {"tag" => "fluent.eventlog"}, [
65
- config_element("storage", "", {
66
- '@type' => 'local',
67
- 'persistent' => false
68
- }),
69
- config_element("subscribe", "", {
70
- 'channels' => ['System', 'Windows PowerShell'],
71
- }),
72
- config_element("subscribe", "", {
73
- 'channels' => ['Security'],
74
- 'read_existing_events' => true
75
- }),
76
- ])
77
- expected = [["system", false, nil], ["windows powershell", false, nil], ["security", true, nil]]
78
- assert_equal expected, d.instance.instance_variable_get(:@chs)
79
- end
80
-
81
- test "subscribe directive with remote server session" do
82
- d = create_driver config_element("ROOT", "", {"tag" => "fluent.eventlog"}, [
83
- config_element("storage", "", {
84
- '@type' => 'local',
85
- 'persistent' => false
86
- }),
87
- config_element("subscribe", "", {
88
- 'channels' => ['System', 'Windows PowerShell'],
89
- 'remote_server' => '127.0.0.1',
90
- }),
91
- config_element("subscribe", "", {
92
- 'channels' => ['Security'],
93
- 'read_existing_events' => true,
94
- 'remote_server' => '192.168.0.1',
95
- 'remote_username' => 'fluentd',
96
- 'remote_password' => 'changeme!'
97
- }),
98
- ])
99
- localhost_session = Winevt::EventLog::Session.new("127.0.0.1")
100
- remote_session = Winevt::EventLog::Session.new("192.168.0.1",
101
- nil,
102
- "fluentd",
103
- "changeme!")
104
- expected = [["system", false, localhost_session],
105
- ["windows powershell", false, localhost_session],
106
- ["security", true, remote_session]]
107
- assert_equal expected, d.instance.instance_variable_get(:@chs)
108
- end
109
-
110
- test "duplicated subscribe" do
111
- d = create_driver config_element("ROOT", "", {"tag" => "fluent.eventlog",
112
- "channels" => ["System", "Windows PowerShell"]
113
- }, [
114
- config_element("storage", "", {
115
- '@type' => 'local',
116
- 'persistent' => false
117
- }),
118
- config_element("subscribe", "", {
119
- 'channels' => ['System', 'Windows PowerShell'],
120
- }),
121
- config_element("subscribe", "", {
122
- 'channels' => ['Security'],
123
- 'read_existing_events' => true
124
- }),
125
- ])
126
- expected = [["system", false, nil], ["windows powershell", false, nil], ["security", true, nil]]
127
- assert_equal 1, d.instance.instance_variable_get(:@chs).select {|ch, flag| ch == "system"}.size
128
- assert_equal expected, d.instance.instance_variable_get(:@chs)
129
- end
130
-
131
- test "non duplicated subscribe" do
132
- d = create_driver config_element("ROOT", "", {"tag" => "fluent.eventlog",
133
- "channels" => ["System", "Windows PowerShell"]
134
- }, [
135
- config_element("storage", "", {
136
- '@type' => 'local',
137
- 'persistent' => false
138
- }),
139
- config_element("subscribe", "", {
140
- 'channels' => ['System', 'Windows PowerShell'],
141
- 'read_existing_events' => true
142
- }),
143
- config_element("subscribe", "", {
144
- 'channels' => ['Security'],
145
- 'read_existing_events' => true
146
- }),
147
- ])
148
- expected = [["system", false, nil], ["windows powershell", false, nil], ["system", true, nil], ["windows powershell", true, nil], ["security", true, nil]]
149
- assert_equal 2, d.instance.instance_variable_get(:@chs).select {|ch, flag| ch == "system"}.size
150
- assert_equal expected, d.instance.instance_variable_get(:@chs)
151
- end
152
-
153
- test "invalid combination for preserving qualifiers" do
154
- assert_raise(Fluent::ConfigError) do
155
- create_driver config_element("ROOT", "", {"tag" => "fluent.eventlog",
156
- "render_as_xml" => true,
157
- "preserve_qualifiers_on_hash" => true,
158
- }, [
159
- config_element("storage", "", {
160
- '@type' => 'local',
161
- 'persistent' => false
162
- }),
163
- ])
164
- end
165
- end
166
-
167
- test "invalid description locale" do
168
- assert_raise(Fluent::ConfigError) do
169
- create_driver config_element("ROOT", "", {"tag" => "fluent.eventlog",
170
- "description_locale" => "ex_EX"
171
- }, [
172
- config_element("storage", "", {
173
- '@type' => 'local',
174
- 'persistent' => false
175
- })
176
- ])
177
- end
178
- end
179
- end
180
-
181
- data("Japanese" => ["ja_JP", false],
182
- "English (United States)" => ["en_US", false],
183
- "English (UK)" => ["en_GB", false],
184
- "Dutch" => ["nl_NL", false],
185
- "French" => ["fr_FR", false],
186
- "German" => ["de_DE", false],
187
- "Russian" => ["ru_RU", false],
188
- "Spanish" => ["es_ES", false],
189
- "Invalid" => ["ex_EX", true],
190
- )
191
- def test_unsupported_locale_p(data)
192
- description_locale, expected = data
193
- d = create_driver CONFIG
194
- locale = Winevt::EventLog::Locale.new
195
- result = d.instance.unsupported_locale?(locale, description_locale)
196
- assert_equal expected, result
197
- end
198
-
199
- data("application" => ["Application", "Application"],
200
- "windows powershell" => ["Windows PowerShell", "Windows PowerShell"],
201
- "escaped" => ["Should_Be_Escaped_", "Should+Be;Escaped/"]
202
- )
203
- def test_escape_channel(data)
204
- expected, actual = data
205
- d = create_driver CONFIG
206
- assert_equal expected, d.instance.escape_channel(actual)
207
- end
208
-
209
- def test_parse_desc
210
- d = create_driver
211
- desc =<<-DESC
212
- A user's local group membership was enumerated.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-X-Y-XX-WWWWWW-VVVV\r\n\tAccount Name:\t\tAdministrator\r\n\tAccount Domain:\t\tDESKTOP-FLUENTTEST\r\n\tLogon ID:\t\t0x3185B1\r\n\r\nUser:\r\n\tSecurity ID:\t\tS-X-Y-XX-WWWWWW-VVVV\r\n\tAccount Name:\t\tAdministrator\r\n\tAccount Domain:\t\tDESKTOP-FLUENTTEST\r\n\r\nProcess Information:\r\n\tProcess ID:\t\t0x50b8\r\n\tProcess Name:\t\tC:\\msys64\\usr\\bin\\make.exe
213
- DESC
214
- h = {"Description" => desc}
215
- expected = {"DescriptionTitle" => "A user's local group membership was enumerated.",
216
- "subject.security_id" => "S-X-Y-XX-WWWWWW-VVVV",
217
- "subject.account_name" => "Administrator",
218
- "subject.account_domain" => "DESKTOP-FLUENTTEST",
219
- "subject.logon_id" => "0x3185B1",
220
- "user.security_id" => "S-X-Y-XX-WWWWWW-VVVV",
221
- "user.account_name" => "Administrator",
222
- "user.account_domain" => "DESKTOP-FLUENTTEST",
223
- "process_information.process_id" => "0x50b8",
224
- "process_information.process_name" => "C:\\msys64\\usr\\bin\\make.exe"}
225
- d.instance.parse_desc(h)
226
- assert_equal(expected, h)
227
- end
228
-
229
- def test_parse_privileges_description
230
- d = create_driver
231
- desc = ["Special privileges assigned to new logon.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-X-Y-ZZ\r\n\t",
232
- "AccountName:\t\tSYSTEM\r\n\tAccount Domain:\t\tNT AUTHORITY\r\n\tLogon ID:\t\t0x3E7\r\n\r\n",
233
- "Privileges:\t\tSeAssignPrimaryTokenPrivilege\r\n\t\t\tSeTcbPrivilege\r\n\t\t\t",
234
- "SeSecurityPrivilege\r\n\t\t\tSeTakeOwnershipPrivilege\r\n\t\t\tSeLoadDriverPrivilege\r\n\t\t\t",
235
- "SeBackupPrivilege\r\n\t\t\tSeRestorePrivilege\r\n\t\t\tSeDebugPrivilege\r\n\t\t\t",
236
- "SeAuditPrivilege\r\n\t\t\tSeSystemEnvironmentPrivilege\r\n\t\t\tSeImpersonatePrivilege\r\n\t\t\t",
237
- "SeDelegateSessionUserImpersonatePrivilege"].join("")
238
-
239
- h = {"Description" => desc}
240
- expected = {"DescriptionTitle" => "Special privileges assigned to new logon.",
241
- "subject.security_id" => "S-X-Y-ZZ",
242
- "subject.accountname" => "SYSTEM",
243
- "subject.account_domain" => "NT AUTHORITY",
244
- "subject.logon_id" => "0x3E7",
245
- "privileges" => ["SeAssignPrimaryTokenPrivilege",
246
- "SeTcbPrivilege",
247
- "SeSecurityPrivilege",
248
- "SeTakeOwnershipPrivilege",
249
- "SeLoadDriverPrivilege",
250
- "SeBackupPrivilege",
251
- "SeRestorePrivilege",
252
- "SeDebugPrivilege",
253
- "SeAuditPrivilege",
254
- "SeSystemEnvironmentPrivilege",
255
- "SeImpersonatePrivilege",
256
- "SeDelegateSessionUserImpersonatePrivilege"]}
257
- d.instance.parse_desc(h)
258
- assert_equal(expected, h)
259
- end
260
-
261
- test "A new external device was recognized by the system." do
262
- # using the event log example: eventopedia.cloudapp.net/EventDetails.aspx?id=17ef124e-eb89-4c01-9ba2-d761e06b2b68
263
- d = create_driver
264
- desc = nil
265
- File.open('./test/data/eventid_6416', 'r') do |f|
266
- desc = f.read.gsub(/\R/, "\r\n")
267
- end
268
- h = {"Description" => desc}
269
- expected = {"DescriptionTitle" => "A new external device was recognized by the system.",
270
- "class_id" => "{1ed2bbf9-11f0-4084-b21f-ad83a8e6dcdc}",
271
- "class_name" => "PrintQueue",
272
- "compatible_ids" => ["GenPrintQueue", "SWD\\GenericRaw", "SWD\\Generic"],
273
- "device_id" => "SWD\\PRINTENUM\\{60FA1C6A-1AB2-440A-AEE1-62ABFB9A4650}",
274
- "device_name" => "Microsoft Print to PDF",
275
- "subject.account_domain" => "ITSS",
276
- "subject.account_name" => "IIZHU2016$",
277
- "subject.logon_id" => "0x3E7",
278
- "subject.security_id" => "SYSTEM",
279
- "vendor_ids" => ["PRINTENUM\\{084f01fa-e634-4d77-83ee-074817c03581}",
280
- "PRINTENUM\\LocalPrintQueue",
281
- "{084f01fa-e634-4d77-83ee-074817c03581}"]}
282
- d.instance.parse_desc(h)
283
- assert_equal(expected, h)
284
- end
285
-
286
- def test_write
287
- d = create_driver
288
-
289
- service = Fluent::Plugin::EventService.new
290
-
291
- d.run(expect_emits: 1) do
292
- service.run
293
- end
294
-
295
- assert(d.events.length >= 1)
296
- event = d.events.select {|e| e.last["EventID"] == "65500" }.last
297
- record = event.last
298
-
299
- assert_equal("Application", record["Channel"])
300
- assert_equal("65500", record["EventID"])
301
- assert_equal("4", record["Level"])
302
- assert_equal("fluent-plugins", record["ProviderName"])
303
- end
304
-
305
- CONFIG_WITH_QUERY = config_element("ROOT", "", {"tag" => "fluent.eventlog",
306
- "event_query" => "Event/System[EventID=65500]"}, [
307
- config_element("storage", "", {
308
- '@type' => 'local',
309
- 'persistent' => false
310
- })
311
- ])
312
- def test_write_with_event_query
313
- d = create_driver(CONFIG_WITH_QUERY)
314
-
315
- service = Fluent::Plugin::EventService.new
316
-
317
- d.run(expect_emits: 1) do
318
- service.run
319
- end
320
-
321
- assert(d.events.length >= 1)
322
- event = d.events.last
323
- record = event.last
324
-
325
- assert_equal("Application", record["Channel"])
326
- assert_equal("65500", record["EventID"])
327
- assert_equal("4", record["Level"])
328
- assert_equal("fluent-plugins", record["ProviderName"])
329
- end
330
-
331
-
332
- CONFIG_KEYS = config_element("ROOT", "", {
333
- "tag" => "fluent.eventlog",
334
- "keys" => ["EventID", "Level", "Channel", "ProviderName"]
335
- }, [
336
- config_element("storage", "", {
337
- '@type' => 'local',
338
- 'persistent' => false
339
- })
340
- ])
341
- def test_write_with_keys
342
- d = create_driver(CONFIG_KEYS)
343
-
344
- service = Fluent::Plugin::EventService.new
345
-
346
- d.run(expect_emits: 1) do
347
- service.run
348
- end
349
-
350
- assert(d.events.length >= 1)
351
- event = d.events.select {|e| e.last["EventID"] == "65500" }.last
352
- record = event.last
353
-
354
- expected = {"EventID" => "65500",
355
- "Level" => "4",
356
- "Channel" => "Application",
357
- "ProviderName" => "fluent-plugins"}
358
-
359
- assert_equal(expected, record)
360
- end
361
-
362
- REMOTING_ACCESS_CONFIG = config_element("ROOT", "", {"tag" => "fluent.eventlog"}, [
363
- config_element("storage", "", {
364
- '@type' => 'local',
365
- 'persistent' => false
366
- }),
367
- config_element("subscribe", "", {
368
- 'channels' => ['Application'],
369
- 'remote_server' => '127.0.0.1',
370
- }),
371
- ])
372
-
373
- def test_write_with_remoting_access
374
- d = create_driver(REMOTING_ACCESS_CONFIG)
375
-
376
- service = Fluent::Plugin::EventService.new
377
-
378
- d.run(expect_emits: 1) do
379
- service.run
380
- end
381
-
382
- assert(d.events.length >= 1)
383
- event = d.events.select {|e| e.last["EventID"] == "65500" }.last
384
- record = event.last
385
-
386
- assert_equal("Application", record["Channel"])
387
- assert_equal("65500", record["EventID"])
388
- assert_equal("4", record["Level"])
389
- assert_equal("fluent-plugins", record["ProviderName"])
390
- end
391
-
392
- class HashRendered < self
393
- def test_write
394
- d = create_driver(config_element("ROOT", "", {"tag" => "fluent.eventlog",
395
- "render_as_xml" => false}, [
396
- config_element("storage", "", {
397
- '@type' => 'local',
398
- 'persistent' => false
399
- })
400
- ]))
401
-
402
- service = Fluent::Plugin::EventService.new
403
-
404
- d.run(expect_emits: 1) do
405
- service.run
406
- end
407
-
408
- assert(d.events.length >= 1)
409
- event = d.events.select {|e| e.last["EventID"] == "65500" }.last
410
- record = event.last
411
-
412
- assert_false(d.instance.render_as_xml)
413
- assert_equal("Application", record["Channel"])
414
- assert_equal("65500", record["EventID"])
415
- assert_equal("4", record["Level"])
416
- assert_equal("fluent-plugins", record["ProviderName"])
417
- end
418
-
419
- def test_write_with_preserving_qualifiers
420
- require 'winevt'
421
-
422
- d = create_driver(config_element("ROOT", "", {"tag" => "fluent.eventlog",
423
- "render_as_xml" => false,
424
- 'preserve_qualifiers_on_hash' => true
425
- }, [
426
- config_element("storage", "", {
427
- '@type' => 'local',
428
- 'persistent' => false
429
- }),
430
- ]))
431
-
432
- service = Fluent::Plugin::EventService.new
433
- subscribe = Winevt::EventLog::Subscribe.new
434
-
435
- omit "@parser.preserve_qualifiers does not respond" unless subscribe.respond_to?(:preserve_qualifiers?)
436
-
437
- d.run(expect_emits: 1) do
438
- service.run
439
- end
440
-
441
- assert(d.events.length >= 1)
442
- event = d.events.last
443
- record = event.last
444
-
445
- assert_true(record.has_key?("Description"))
446
- assert_true(record.has_key?("EventData"))
447
- assert_true(record.has_key?("Qualifiers"))
448
- end
449
- end
450
-
451
- class PersistBookMark < self
452
- TEST_PLUGIN_STORAGE_PATH = File.join( File.dirname(File.dirname(__FILE__)), 'tmp', 'in_windows_eventlog2', 'store' )
453
- CONFIG2 = config_element("ROOT", "", {"tag" => "fluent.eventlog"}, [
454
- config_element("storage", "", {
455
- '@type' => 'local',
456
- '@id' => 'test-02',
457
- '@log_level' => "info",
458
- 'path' => File.join(TEST_PLUGIN_STORAGE_PATH,
459
- 'json', 'test-02.json'),
460
- 'persistent' => true,
461
- })
462
- ])
463
-
464
- def setup
465
- FileUtils.rm_rf(TEST_PLUGIN_STORAGE_PATH)
466
- FileUtils.mkdir_p(File.join(TEST_PLUGIN_STORAGE_PATH, 'json'))
467
- FileUtils.chmod_R(0755, File.join(TEST_PLUGIN_STORAGE_PATH, 'json'))
468
- end
469
-
470
- def test_write
471
- d = create_driver(CONFIG2)
472
-
473
- assert !File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
474
-
475
- service = Fluent::Plugin::EventService.new
476
-
477
- d.run(expect_emits: 1) do
478
- service.run
479
- end
480
-
481
- assert(d.events.length >= 1)
482
- event = d.events.select {|e| e.last["EventID"] == "65500" }.last
483
- record = event.last
484
-
485
- prev_id = record["EventRecordID"].to_i
486
- assert_equal("Application", record["Channel"])
487
- assert_equal("65500", record["EventID"])
488
- assert_equal("4", record["Level"])
489
- assert_equal("fluent-plugins", record["ProviderName"])
490
-
491
- assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
492
-
493
- d2 = create_driver(CONFIG2)
494
- d2.run(expect_emits: 1) do
495
- service.run
496
- end
497
-
498
- events = d2.events.select {|e| e.last["EventID"] == "65500" }
499
- assert(events.length == 1) # should be tailing after previous context.
500
- event2 = events.last
501
- record2 = event2.last
502
-
503
- curr_id = record2["EventRecordID"].to_i
504
- assert(curr_id > prev_id)
505
-
506
- assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
507
- end
508
-
509
- def test_start_with_invalid_bookmark
510
- invalid_storage_contents = <<-EOS
511
- <BookmarkList>\r\n <Bookmark Channel='Application' RecordId='20063' IsCurrent='true'/>\r\n
512
- EOS
513
- d = create_driver(CONFIG2)
514
- storage = d.instance.instance_variable_get(:@bookmarks_storage)
515
- storage.put('application', invalid_storage_contents)
516
- assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
517
-
518
- d2 = create_driver(CONFIG2)
519
- assert_raise(Fluent::ConfigError) do
520
- d2.instance.start
521
- end
522
- assert_equal 0, d2.logs.grep(/This stored bookmark is incomplete for using. Referring `read_existing_events` parameter to subscribe:/).length
523
- end
524
-
525
- def test_start_with_empty_bookmark
526
- invalid_storage_contents = <<-EOS
527
- <BookmarkList>\r\n</BookmarkList>
528
- EOS
529
- d = create_driver(CONFIG2)
530
- storage = d.instance.instance_variable_get(:@bookmarks_storage)
531
- storage.put('application', invalid_storage_contents)
532
- assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
533
-
534
- d2 = create_driver(CONFIG2)
535
- d2.instance.start
536
- assert_equal 1, d2.logs.grep(/This stored bookmark is incomplete for using. Referring `read_existing_events` parameter to subscribe:/).length
537
- end
538
- end
539
-
540
- def test_write_with_none_parser
541
- d = create_driver(config_element("ROOT", "", {"tag" => "fluent.eventlog",
542
- "render_as_xml" => true}, [
543
- config_element("storage", "", {
544
- '@type' => 'local',
545
- 'persistent' => false
546
- }),
547
- config_element("parse", "", {
548
- '@type' => 'none',
549
- }),
550
- ]))
551
-
552
- service = Fluent::Plugin::EventService.new
553
-
554
- d.run(expect_emits: 1) do
555
- service.run
556
- end
557
-
558
- assert(d.events.length >= 1)
559
- event = d.events.last
560
- record = event.last
561
-
562
- assert do
563
- # record should be {message: <RAW XML EventLog>}.
564
- record["message"]
565
- end
566
-
567
- assert_true(record.has_key?("Description"))
568
- assert_true(record.has_key?("EventData"))
569
- end
570
-
571
- def test_write_with_winevt_xml_parser_without_qualifiers
572
- d = create_driver(config_element("ROOT", "", {"tag" => "fluent.eventlog",
573
- "render_as_xml" => true}, [
574
- config_element("storage", "", {
575
- '@type' => 'local',
576
- 'persistent' => false
577
- }),
578
- config_element("parse", "", {
579
- '@type' => 'winevt_xml',
580
- 'preserve_qualifiers' => false
581
- }),
582
- ]))
583
-
584
- service = Fluent::Plugin::EventService.new
585
-
586
- omit "@parser.preserve_qualifiers does not respond" unless d.instance.instance_variable_get(:@parser).respond_to?(:preserve_qualifiers?)
587
-
588
- d.run(expect_emits: 1) do
589
- service.run
590
- end
591
-
592
- assert(d.events.length >= 1)
593
- event = d.events.last
594
- record = event.last
595
-
596
- assert_true(record.has_key?("Description"))
597
- assert_true(record.has_key?("EventData"))
598
- assert_false(record.has_key?("Qualifiers"))
599
- end
600
- end
1
+ require 'helper'
2
+ require 'fileutils'
3
+ require 'generate-windows-event'
4
+
5
+ # Monkey patch for testing
6
+ class Winevt::EventLog::Session
7
+ def ==(obj)
8
+ self.server == obj.server &&
9
+ self.domain == obj.domain &&
10
+ self.username == obj.username &&
11
+ self.password == obj.password &&
12
+ self.flags == obj.flags
13
+ end
14
+ end
15
+
16
+ class WindowsEventLog2InputTest < Test::Unit::TestCase
17
+
18
+ def setup
19
+ Fluent::Test.setup
20
+ end
21
+
22
+ CONFIG = config_element("ROOT", "", {"tag" => "fluent.eventlog"}, [
23
+ config_element("storage", "", {
24
+ '@type' => 'local',
25
+ 'persistent' => false
26
+ })
27
+ ])
28
+
29
+ XML_RENDERING_CONFIG = config_element("ROOT", "", {"tag" => "fluent.eventlog",
30
+ "render_as_xml" => true}, [
31
+ config_element("storage", "", {
32
+ '@type' => 'local',
33
+ 'persistent' => false
34
+ })
35
+ ])
36
+
37
+ def create_driver(conf = CONFIG)
38
+ Fluent::Test::Driver::Input.new(Fluent::Plugin::WindowsEventLog2Input).configure(conf)
39
+ end
40
+
41
+ def test_configure
42
+ d = create_driver CONFIG
43
+ assert_equal 'fluent.eventlog', d.instance.tag
44
+ assert_equal 2, d.instance.read_interval
45
+ assert_equal [], d.instance.channels
46
+ assert_false d.instance.read_existing_events
47
+ assert_false d.instance.render_as_xml
48
+ assert_nil d.instance.refresh_subscription_interval
49
+ end
50
+
51
+ sub_test_case "configure" do
52
+ test "refresh subscription interval" do
53
+ d = create_driver config_element("ROOT", "", {"tag" => "fluent.eventlog",
54
+ "refresh_subscription_interval" => "2m"}, [
55
+ config_element("storage", "", {
56
+ '@type' => 'local',
57
+ 'persistent' => false
58
+ })
59
+ ])
60
+ assert_equal 120, d.instance.refresh_subscription_interval
61
+ end
62
+
63
+ test "subscribe directive" do
64
+ d = create_driver config_element("ROOT", "", {"tag" => "fluent.eventlog"}, [
65
+ config_element("storage", "", {
66
+ '@type' => 'local',
67
+ 'persistent' => false
68
+ }),
69
+ config_element("subscribe", "", {
70
+ 'channels' => ['System', 'Windows PowerShell'],
71
+ }),
72
+ config_element("subscribe", "", {
73
+ 'channels' => ['Security'],
74
+ 'read_existing_events' => true
75
+ }),
76
+ ])
77
+ expected = [["system", false, nil], ["windows powershell", false, nil], ["security", true, nil]]
78
+ assert_equal expected, d.instance.instance_variable_get(:@chs)
79
+ end
80
+
81
+ test "subscribe directive with remote server session" do
82
+ d = create_driver config_element("ROOT", "", {"tag" => "fluent.eventlog"}, [
83
+ config_element("storage", "", {
84
+ '@type' => 'local',
85
+ 'persistent' => false
86
+ }),
87
+ config_element("subscribe", "", {
88
+ 'channels' => ['System', 'Windows PowerShell'],
89
+ 'remote_server' => '127.0.0.1',
90
+ }),
91
+ config_element("subscribe", "", {
92
+ 'channels' => ['Security'],
93
+ 'read_existing_events' => true,
94
+ 'remote_server' => '192.168.0.1',
95
+ 'remote_username' => 'fluentd',
96
+ 'remote_password' => 'changeme!'
97
+ }),
98
+ ])
99
+ localhost_session = Winevt::EventLog::Session.new("127.0.0.1")
100
+ remote_session = Winevt::EventLog::Session.new("192.168.0.1",
101
+ nil,
102
+ "fluentd",
103
+ "changeme!")
104
+ expected = [["system", false, localhost_session],
105
+ ["windows powershell", false, localhost_session],
106
+ ["security", true, remote_session]]
107
+ assert_equal expected, d.instance.instance_variable_get(:@chs)
108
+ end
109
+
110
+ test "duplicated subscribe" do
111
+ d = create_driver config_element("ROOT", "", {"tag" => "fluent.eventlog",
112
+ "channels" => ["System", "Windows PowerShell"]
113
+ }, [
114
+ config_element("storage", "", {
115
+ '@type' => 'local',
116
+ 'persistent' => false
117
+ }),
118
+ config_element("subscribe", "", {
119
+ 'channels' => ['System', 'Windows PowerShell'],
120
+ }),
121
+ config_element("subscribe", "", {
122
+ 'channels' => ['Security'],
123
+ 'read_existing_events' => true
124
+ }),
125
+ ])
126
+ expected = [["system", false, nil], ["windows powershell", false, nil], ["security", true, nil]]
127
+ assert_equal 1, d.instance.instance_variable_get(:@chs).select {|ch, flag| ch == "system"}.size
128
+ assert_equal expected, d.instance.instance_variable_get(:@chs)
129
+ end
130
+
131
+ test "non duplicated subscribe" do
132
+ d = create_driver config_element("ROOT", "", {"tag" => "fluent.eventlog",
133
+ "channels" => ["System", "Windows PowerShell"]
134
+ }, [
135
+ config_element("storage", "", {
136
+ '@type' => 'local',
137
+ 'persistent' => false
138
+ }),
139
+ config_element("subscribe", "", {
140
+ 'channels' => ['System', 'Windows PowerShell'],
141
+ 'read_existing_events' => true
142
+ }),
143
+ config_element("subscribe", "", {
144
+ 'channels' => ['Security'],
145
+ 'read_existing_events' => true
146
+ }),
147
+ ])
148
+ expected = [["system", false, nil], ["windows powershell", false, nil], ["system", true, nil], ["windows powershell", true, nil], ["security", true, nil]]
149
+ assert_equal 2, d.instance.instance_variable_get(:@chs).select {|ch, flag| ch == "system"}.size
150
+ assert_equal expected, d.instance.instance_variable_get(:@chs)
151
+ end
152
+
153
+ test "invalid combination for preserving qualifiers" do
154
+ assert_raise(Fluent::ConfigError) do
155
+ create_driver config_element("ROOT", "", {"tag" => "fluent.eventlog",
156
+ "render_as_xml" => true,
157
+ "preserve_qualifiers_on_hash" => true,
158
+ }, [
159
+ config_element("storage", "", {
160
+ '@type' => 'local',
161
+ 'persistent' => false
162
+ }),
163
+ ])
164
+ end
165
+ end
166
+
167
+ test "invalid description locale" do
168
+ assert_raise(Fluent::ConfigError) do
169
+ create_driver config_element("ROOT", "", {"tag" => "fluent.eventlog",
170
+ "description_locale" => "ex_EX"
171
+ }, [
172
+ config_element("storage", "", {
173
+ '@type' => 'local',
174
+ 'persistent' => false
175
+ })
176
+ ])
177
+ end
178
+ end
179
+ end
180
+
181
+ data("Japanese" => ["ja_JP", false],
182
+ "English (United States)" => ["en_US", false],
183
+ "English (UK)" => ["en_GB", false],
184
+ "Dutch" => ["nl_NL", false],
185
+ "French" => ["fr_FR", false],
186
+ "German" => ["de_DE", false],
187
+ "Russian" => ["ru_RU", false],
188
+ "Spanish" => ["es_ES", false],
189
+ "Invalid" => ["ex_EX", true],
190
+ )
191
+ def test_unsupported_locale_p(data)
192
+ description_locale, expected = data
193
+ d = create_driver CONFIG
194
+ locale = Winevt::EventLog::Locale.new
195
+ result = d.instance.unsupported_locale?(locale, description_locale)
196
+ assert_equal expected, result
197
+ end
198
+
199
+ data("application" => ["Application", "Application"],
200
+ "windows powershell" => ["Windows PowerShell", "Windows PowerShell"],
201
+ "escaped" => ["Should_Be_Escaped_", "Should+Be;Escaped/"]
202
+ )
203
+ def test_escape_channel(data)
204
+ expected, actual = data
205
+ d = create_driver CONFIG
206
+ assert_equal expected, d.instance.escape_channel(actual)
207
+ end
208
+
209
+ def test_parse_desc
210
+ d = create_driver
211
+ desc =<<-DESC
212
+ A user's local group membership was enumerated.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-X-Y-XX-WWWWWW-VVVV\r\n\tAccount Name:\t\tAdministrator\r\n\tAccount Domain:\t\tDESKTOP-FLUENTTEST\r\n\tLogon ID:\t\t0x3185B1\r\n\r\nUser:\r\n\tSecurity ID:\t\tS-X-Y-XX-WWWWWW-VVVV\r\n\tAccount Name:\t\tAdministrator\r\n\tAccount Domain:\t\tDESKTOP-FLUENTTEST\r\n\r\nProcess Information:\r\n\tProcess ID:\t\t0x50b8\r\n\tProcess Name:\t\tC:\\msys64\\usr\\bin\\make.exe
213
+ DESC
214
+ h = {"Description" => desc}
215
+ expected = {"DescriptionTitle" => "A user's local group membership was enumerated.",
216
+ "subject.security_id" => "S-X-Y-XX-WWWWWW-VVVV",
217
+ "subject.account_name" => "Administrator",
218
+ "subject.account_domain" => "DESKTOP-FLUENTTEST",
219
+ "subject.logon_id" => "0x3185B1",
220
+ "user.security_id" => "S-X-Y-XX-WWWWWW-VVVV",
221
+ "user.account_name" => "Administrator",
222
+ "user.account_domain" => "DESKTOP-FLUENTTEST",
223
+ "process_information.process_id" => "0x50b8",
224
+ "process_information.process_name" => "C:\\msys64\\usr\\bin\\make.exe"}
225
+ d.instance.parse_desc(h)
226
+ assert_equal(expected, h)
227
+ end
228
+
229
+ def test_parse_privileges_description
230
+ d = create_driver
231
+ desc = ["Special privileges assigned to new logon.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-X-Y-ZZ\r\n\t",
232
+ "AccountName:\t\tSYSTEM\r\n\tAccount Domain:\t\tNT AUTHORITY\r\n\tLogon ID:\t\t0x3E7\r\n\r\n",
233
+ "Privileges:\t\tSeAssignPrimaryTokenPrivilege\r\n\t\t\tSeTcbPrivilege\r\n\t\t\t",
234
+ "SeSecurityPrivilege\r\n\t\t\tSeTakeOwnershipPrivilege\r\n\t\t\tSeLoadDriverPrivilege\r\n\t\t\t",
235
+ "SeBackupPrivilege\r\n\t\t\tSeRestorePrivilege\r\n\t\t\tSeDebugPrivilege\r\n\t\t\t",
236
+ "SeAuditPrivilege\r\n\t\t\tSeSystemEnvironmentPrivilege\r\n\t\t\tSeImpersonatePrivilege\r\n\t\t\t",
237
+ "SeDelegateSessionUserImpersonatePrivilege"].join("")
238
+
239
+ h = {"Description" => desc}
240
+ expected = {"DescriptionTitle" => "Special privileges assigned to new logon.",
241
+ "subject.security_id" => "S-X-Y-ZZ",
242
+ "subject.accountname" => "SYSTEM",
243
+ "subject.account_domain" => "NT AUTHORITY",
244
+ "subject.logon_id" => "0x3E7",
245
+ "privileges" => ["SeAssignPrimaryTokenPrivilege",
246
+ "SeTcbPrivilege",
247
+ "SeSecurityPrivilege",
248
+ "SeTakeOwnershipPrivilege",
249
+ "SeLoadDriverPrivilege",
250
+ "SeBackupPrivilege",
251
+ "SeRestorePrivilege",
252
+ "SeDebugPrivilege",
253
+ "SeAuditPrivilege",
254
+ "SeSystemEnvironmentPrivilege",
255
+ "SeImpersonatePrivilege",
256
+ "SeDelegateSessionUserImpersonatePrivilege"]}
257
+ d.instance.parse_desc(h)
258
+ assert_equal(expected, h)
259
+ end
260
+
261
+ test "A new external device was recognized by the system." do
262
+ # using the event log example: eventopedia.cloudapp.net/EventDetails.aspx?id=17ef124e-eb89-4c01-9ba2-d761e06b2b68
263
+ d = create_driver
264
+ desc = nil
265
+ File.open('./test/data/eventid_6416', 'r') do |f|
266
+ desc = f.read.gsub(/\R/, "\r\n")
267
+ end
268
+ h = {"Description" => desc}
269
+ expected = {"DescriptionTitle" => "A new external device was recognized by the system.",
270
+ "class_id" => "{1ed2bbf9-11f0-4084-b21f-ad83a8e6dcdc}",
271
+ "class_name" => "PrintQueue",
272
+ "compatible_ids" => ["GenPrintQueue", "SWD\\GenericRaw", "SWD\\Generic"],
273
+ "device_id" => "SWD\\PRINTENUM\\{60FA1C6A-1AB2-440A-AEE1-62ABFB9A4650}",
274
+ "device_name" => "Microsoft Print to PDF",
275
+ "subject.account_domain" => "ITSS",
276
+ "subject.account_name" => "IIZHU2016$",
277
+ "subject.logon_id" => "0x3E7",
278
+ "subject.security_id" => "SYSTEM",
279
+ "vendor_ids" => ["PRINTENUM\\{084f01fa-e634-4d77-83ee-074817c03581}",
280
+ "PRINTENUM\\LocalPrintQueue",
281
+ "{084f01fa-e634-4d77-83ee-074817c03581}"]}
282
+ d.instance.parse_desc(h)
283
+ assert_equal(expected, h)
284
+ end
285
+
286
+ def test_write
287
+ d = create_driver
288
+
289
+ service = Fluent::Plugin::EventService.new
290
+
291
+ d.run(expect_emits: 1) do
292
+ service.run
293
+ end
294
+
295
+ assert(d.events.length >= 1)
296
+ event = d.events.select {|e| e.last["EventID"] == "65500" }.last
297
+ record = event.last
298
+
299
+ assert_equal("Application", record["Channel"])
300
+ assert_equal("65500", record["EventID"])
301
+ assert_equal("4", record["Level"])
302
+ assert_equal("fluent-plugins", record["ProviderName"])
303
+ end
304
+
305
+ CONFIG_WITH_NON_EXISTENT_CHANNEL = config_element("ROOT", "", {
306
+ "channels" => ["application", "NonExistentChannel"]
307
+ })
308
+ def test_skip_non_existent_channel
309
+ d = create_driver(CONFIG + CONFIG_WITH_NON_EXISTENT_CHANNEL)
310
+
311
+ service = Fluent::Plugin::EventService.new
312
+
313
+ assert_nothing_raised do
314
+ d.run(expect_emits: 1) do
315
+ service.run
316
+ end
317
+ end
318
+
319
+ assert(d.events.length >= 1)
320
+ assert(d.logs.any?{|log| log.include?("[warn]: Channel Not Found: nonexistentchannel") },
321
+ d.logs.join("\n"))
322
+ end
323
+
324
+ CONFIG_WITH_QUERY = config_element("ROOT", "", {"tag" => "fluent.eventlog",
325
+ "event_query" => "Event/System[EventID=65500]"}, [
326
+ config_element("storage", "", {
327
+ '@type' => 'local',
328
+ 'persistent' => false
329
+ })
330
+ ])
331
+ def test_write_with_event_query
332
+ d = create_driver(CONFIG_WITH_QUERY)
333
+
334
+ service = Fluent::Plugin::EventService.new
335
+
336
+ d.run(expect_emits: 1) do
337
+ service.run
338
+ end
339
+
340
+ assert(d.events.length >= 1)
341
+ event = d.events.last
342
+ record = event.last
343
+
344
+ assert_equal("Application", record["Channel"])
345
+ assert_equal("65500", record["EventID"])
346
+ assert_equal("4", record["Level"])
347
+ assert_equal("fluent-plugins", record["ProviderName"])
348
+ end
349
+
350
+
351
+ CONFIG_KEYS = config_element("ROOT", "", {
352
+ "tag" => "fluent.eventlog",
353
+ "keys" => ["EventID", "Level", "Channel", "ProviderName"]
354
+ }, [
355
+ config_element("storage", "", {
356
+ '@type' => 'local',
357
+ 'persistent' => false
358
+ })
359
+ ])
360
+ def test_write_with_keys
361
+ d = create_driver(CONFIG_KEYS)
362
+
363
+ service = Fluent::Plugin::EventService.new
364
+
365
+ d.run(expect_emits: 1) do
366
+ service.run
367
+ end
368
+
369
+ assert(d.events.length >= 1)
370
+ event = d.events.select {|e| e.last["EventID"] == "65500" }.last
371
+ record = event.last
372
+
373
+ expected = {"EventID" => "65500",
374
+ "Level" => "4",
375
+ "Channel" => "Application",
376
+ "ProviderName" => "fluent-plugins"}
377
+
378
+ assert_equal(expected, record)
379
+ end
380
+
381
+ REMOTING_ACCESS_CONFIG = config_element("ROOT", "", {"tag" => "fluent.eventlog"}, [
382
+ config_element("storage", "", {
383
+ '@type' => 'local',
384
+ 'persistent' => false
385
+ }),
386
+ config_element("subscribe", "", {
387
+ 'channels' => ['Application'],
388
+ 'remote_server' => '127.0.0.1',
389
+ }),
390
+ ])
391
+
392
+ def test_write_with_remoting_access
393
+ d = create_driver(REMOTING_ACCESS_CONFIG)
394
+
395
+ service = Fluent::Plugin::EventService.new
396
+
397
+ d.run(expect_emits: 1) do
398
+ service.run
399
+ end
400
+
401
+ assert(d.events.length >= 1)
402
+ event = d.events.select {|e| e.last["EventID"] == "65500" }.last
403
+ record = event.last
404
+
405
+ assert_equal("Application", record["Channel"])
406
+ assert_equal("65500", record["EventID"])
407
+ assert_equal("4", record["Level"])
408
+ assert_equal("fluent-plugins", record["ProviderName"])
409
+ end
410
+
411
+ class HashRendered < self
412
+ def test_write
413
+ d = create_driver(config_element("ROOT", "", {"tag" => "fluent.eventlog",
414
+ "render_as_xml" => false}, [
415
+ config_element("storage", "", {
416
+ '@type' => 'local',
417
+ 'persistent' => false
418
+ })
419
+ ]))
420
+
421
+ service = Fluent::Plugin::EventService.new
422
+
423
+ d.run(expect_emits: 1) do
424
+ service.run
425
+ end
426
+
427
+ assert(d.events.length >= 1)
428
+ event = d.events.select {|e| e.last["EventID"] == "65500" }.last
429
+ record = event.last
430
+
431
+ assert_false(d.instance.render_as_xml)
432
+ assert_equal("Application", record["Channel"])
433
+ assert_equal("65500", record["EventID"])
434
+ assert_equal("4", record["Level"])
435
+ assert_equal("fluent-plugins", record["ProviderName"])
436
+ end
437
+
438
+ def test_write_with_preserving_qualifiers
439
+ require 'winevt'
440
+
441
+ d = create_driver(config_element("ROOT", "", {"tag" => "fluent.eventlog",
442
+ "render_as_xml" => false,
443
+ 'preserve_qualifiers_on_hash' => true
444
+ }, [
445
+ config_element("storage", "", {
446
+ '@type' => 'local',
447
+ 'persistent' => false
448
+ }),
449
+ ]))
450
+
451
+ service = Fluent::Plugin::EventService.new
452
+ subscribe = Winevt::EventLog::Subscribe.new
453
+
454
+ omit "@parser.preserve_qualifiers does not respond" unless subscribe.respond_to?(:preserve_qualifiers?)
455
+
456
+ d.run(expect_emits: 1) do
457
+ service.run
458
+ end
459
+
460
+ assert(d.events.length >= 1)
461
+ event = d.events.last
462
+ record = event.last
463
+
464
+ assert_true(record.has_key?("Description"))
465
+ assert_true(record.has_key?("EventData"))
466
+ assert_true(record.has_key?("Qualifiers"))
467
+ end
468
+ end
469
+
470
+ class PersistBookMark < self
471
+ TEST_PLUGIN_STORAGE_PATH = File.join( File.dirname(File.dirname(__FILE__)), 'tmp', 'in_windows_eventlog2', 'store' )
472
+ CONFIG2 = config_element("ROOT", "", {"tag" => "fluent.eventlog"}, [
473
+ config_element("storage", "", {
474
+ '@type' => 'local',
475
+ '@id' => 'test-02',
476
+ '@log_level' => "info",
477
+ 'path' => File.join(TEST_PLUGIN_STORAGE_PATH,
478
+ 'json', 'test-02.json'),
479
+ 'persistent' => true,
480
+ })
481
+ ])
482
+
483
+ def setup
484
+ FileUtils.rm_rf(TEST_PLUGIN_STORAGE_PATH)
485
+ FileUtils.mkdir_p(File.join(TEST_PLUGIN_STORAGE_PATH, 'json'))
486
+ FileUtils.chmod_R(0755, File.join(TEST_PLUGIN_STORAGE_PATH, 'json'))
487
+ end
488
+
489
+ def test_write
490
+ d = create_driver(CONFIG2)
491
+
492
+ assert !File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
493
+
494
+ service = Fluent::Plugin::EventService.new
495
+
496
+ d.run(expect_emits: 1) do
497
+ service.run
498
+ end
499
+
500
+ assert(d.events.length >= 1)
501
+ event = d.events.select {|e| e.last["EventID"] == "65500" }.last
502
+ record = event.last
503
+
504
+ prev_id = record["EventRecordID"].to_i
505
+ assert_equal("Application", record["Channel"])
506
+ assert_equal("65500", record["EventID"])
507
+ assert_equal("4", record["Level"])
508
+ assert_equal("fluent-plugins", record["ProviderName"])
509
+
510
+ assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
511
+
512
+ d2 = create_driver(CONFIG2)
513
+ d2.run(expect_emits: 1) do
514
+ service.run
515
+ end
516
+
517
+ events = d2.events.select {|e| e.last["EventID"] == "65500" }
518
+ assert(events.length == 1) # should be tailing after previous context.
519
+ event2 = events.last
520
+ record2 = event2.last
521
+
522
+ curr_id = record2["EventRecordID"].to_i
523
+ assert(curr_id > prev_id)
524
+
525
+ assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
526
+ end
527
+
528
+ def test_start_with_invalid_bookmark
529
+ invalid_storage_contents = <<-EOS
530
+ <BookmarkList>\r\n <Bookmark Channel='Application' RecordId='20063' IsCurrent='true'/>\r\n
531
+ EOS
532
+ d = create_driver(CONFIG2)
533
+ storage = d.instance.instance_variable_get(:@bookmarks_storage)
534
+ storage.put('application', invalid_storage_contents)
535
+ assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
536
+
537
+ d2 = create_driver(CONFIG2)
538
+ assert_raise(Fluent::ConfigError) do
539
+ d2.instance.start
540
+ end
541
+ assert_equal 0, d2.logs.grep(/This stored bookmark is incomplete for using. Referring `read_existing_events` parameter to subscribe:/).length
542
+ end
543
+
544
+ def test_start_with_empty_bookmark
545
+ invalid_storage_contents = <<-EOS
546
+ <BookmarkList>\r\n</BookmarkList>
547
+ EOS
548
+ d = create_driver(CONFIG2)
549
+ storage = d.instance.instance_variable_get(:@bookmarks_storage)
550
+ storage.put('application', invalid_storage_contents)
551
+ assert File.exist?(File.join(TEST_PLUGIN_STORAGE_PATH, 'json', 'test-02.json'))
552
+
553
+ d2 = create_driver(CONFIG2)
554
+ d2.instance.start
555
+ assert_equal 1, d2.logs.grep(/This stored bookmark is incomplete for using. Referring `read_existing_events` parameter to subscribe:/).length
556
+ end
557
+ end
558
+
559
+ def test_write_with_none_parser
560
+ d = create_driver(config_element("ROOT", "", {"tag" => "fluent.eventlog",
561
+ "render_as_xml" => true}, [
562
+ config_element("storage", "", {
563
+ '@type' => 'local',
564
+ 'persistent' => false
565
+ }),
566
+ config_element("parse", "", {
567
+ '@type' => 'none',
568
+ }),
569
+ ]))
570
+
571
+ service = Fluent::Plugin::EventService.new
572
+
573
+ d.run(expect_emits: 1) do
574
+ service.run
575
+ end
576
+
577
+ assert(d.events.length >= 1)
578
+ event = d.events.last
579
+ record = event.last
580
+
581
+ assert do
582
+ # record should be {message: <RAW XML EventLog>}.
583
+ record["message"]
584
+ end
585
+
586
+ assert_true(record.has_key?("Description"))
587
+ assert_true(record.has_key?("EventData"))
588
+ end
589
+
590
+ def test_write_with_winevt_xml_parser_without_qualifiers
591
+ d = create_driver(config_element("ROOT", "", {"tag" => "fluent.eventlog",
592
+ "render_as_xml" => true}, [
593
+ config_element("storage", "", {
594
+ '@type' => 'local',
595
+ 'persistent' => false
596
+ }),
597
+ config_element("parse", "", {
598
+ '@type' => 'winevt_xml',
599
+ 'preserve_qualifiers' => false
600
+ }),
601
+ ]))
602
+
603
+ service = Fluent::Plugin::EventService.new
604
+
605
+ omit "@parser.preserve_qualifiers does not respond" unless d.instance.instance_variable_get(:@parser).respond_to?(:preserve_qualifiers?)
606
+
607
+ d.run(expect_emits: 1) do
608
+ service.run
609
+ end
610
+
611
+ assert(d.events.length >= 1)
612
+ event = d.events.last
613
+ record = event.last
614
+
615
+ assert_true(record.has_key?("Description"))
616
+ assert_true(record.has_key?("EventData"))
617
+ assert_false(record.has_key?("Qualifiers"))
618
+ end
619
+ end