fluent-plugin-windows-eventlog 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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