1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.ComponentModel; 6 using Xunit; 7 8 namespace System.Diagnostics.Tests 9 { 10 public class EventLogWriteEntryTests 11 { 12 private const string message = "EventLogWriteEntryTestsMessage"; 13 14 private readonly byte[] rawData = new byte[4] { 0, 1, 2, 3 }; 15 private readonly EventInstance eventInstance = new EventInstance(0, 1); 16 private readonly string[] insertStrings = { "ExtraText", "MoreText" }; 17 WriteLogEntry(string source, bool type = false, bool instance = false, bool category = false, bool data = false)18 private EventLogEntry WriteLogEntry(string source, bool type = false, bool instance = false, bool category = false, bool data = false) 19 { 20 using (EventLog eventLog = new EventLog()) 21 { 22 eventLog.Source = source; 23 if (instance) 24 { 25 Helpers.RetryOnWin7(() => EventLog.WriteEvent(source, eventInstance)); 26 if (data) 27 { 28 Helpers.RetryOnWin7(() => eventLog.WriteEntry(message, EventLogEntryType.Warning, (int)eventInstance.InstanceId, (short)eventInstance.CategoryId, rawData)); 29 return eventLog.Entries.LastOrDefault(); 30 } 31 else if (category) 32 { 33 Helpers.RetryOnWin7(() => eventLog.WriteEntry(message, EventLogEntryType.Warning, (int)eventInstance.InstanceId, (short)eventInstance.CategoryId)); 34 return eventLog.Entries.LastOrDefault(); 35 } 36 else 37 { 38 Helpers.RetryOnWin7(() => eventLog.WriteEntry(message, EventLogEntryType.Warning, (int)eventInstance.InstanceId)); 39 return eventLog.Entries.LastOrDefault(); 40 } 41 } 42 else if (type) 43 { 44 Helpers.RetryOnWin7(() => eventLog.WriteEntry(message, EventLogEntryType.Warning)); 45 } 46 else 47 { 48 Helpers.RetryOnWin7(() => eventLog.WriteEntry(message)); 49 } 50 51 return eventLog.Entries.LastOrDefault(); 52 } 53 } 54 WriteLogEntryWithSource(string source, bool type = false, bool instance = false, bool category = false, bool data = false)55 private EventLogEntry WriteLogEntryWithSource(string source, bool type = false, bool instance = false, bool category = false, bool data = false) 56 { 57 using (EventLog eventLog = new EventLog()) 58 { 59 eventLog.Source = source; 60 if (instance) 61 { 62 Helpers.RetryOnWin7(() => EventLog.WriteEvent(source, eventInstance)); 63 if (data) 64 { 65 Helpers.RetryOnWin7(() => EventLog.WriteEntry(source, message, EventLogEntryType.Warning, (int)eventInstance.InstanceId, (short)eventInstance.CategoryId, rawData)); 66 return eventLog.Entries.LastOrDefault(); 67 } 68 else if (category) 69 { 70 Helpers.RetryOnWin7(() => EventLog.WriteEntry(source, message, EventLogEntryType.Warning, (int)eventInstance.InstanceId, (short)eventInstance.CategoryId)); 71 return eventLog.Entries.LastOrDefault(); 72 } 73 else 74 { 75 Helpers.RetryOnWin7(() => EventLog.WriteEntry(source, message, EventLogEntryType.Warning, (int)eventInstance.InstanceId)); 76 return eventLog.Entries.LastOrDefault(); 77 } 78 } 79 else if (type) 80 { 81 Helpers.RetryOnWin7(() => EventLog.WriteEntry(source, message, EventLogEntryType.Warning)); 82 } 83 else 84 { 85 Helpers.RetryOnWin7(() => EventLog.WriteEntry(source, message)); 86 } 87 88 return eventLog.Entries.LastOrDefault(); 89 } 90 } 91 WriteLogEntryEventSource(string source, bool data = false)92 private EventLogEntry WriteLogEntryEventSource(string source, bool data = false) 93 { 94 if (data) 95 { 96 Helpers.RetryOnWin7(() => EventLog.WriteEvent(source, eventInstance, rawData, insertStrings)); 97 } 98 else 99 { 100 Helpers.RetryOnWin7(() => EventLog.WriteEvent(source, eventInstance, insertStrings)); 101 } 102 using (EventLog eventLog = new EventLog()) 103 { 104 eventLog.Source = source; 105 return eventLog.Entries.LastOrDefault(); 106 } 107 } 108 WriteLogEntryEvent(string source, bool data = false)109 private EventLogEntry WriteLogEntryEvent(string source, bool data = false) 110 { 111 using (EventLog eventLog = new EventLog()) 112 { 113 string[] insertStringsSingleton = { "ExtraText" }; 114 eventLog.Source = source; 115 if (data) 116 Helpers.RetryOnWin7(() => eventLog.WriteEvent(eventInstance, rawData, insertStringsSingleton)); 117 else 118 Helpers.RetryOnWin7(() => eventLog.WriteEvent(eventInstance, insertStringsSingleton)); 119 120 return eventLog.Entries.LastOrDefault(); 121 } 122 } 123 124 [ConditionalTheory(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] 125 [InlineData(false)] 126 [InlineData(true)] WriteEntry(bool sourceFlag)127 public void WriteEntry(bool sourceFlag) 128 { 129 string log = "Entry"; 130 string source = "Source" + nameof(WriteEntry); 131 try 132 { 133 EventLog.CreateEventSource(source, log); 134 EventLogEntry eventLogEntry; 135 136 if (sourceFlag) 137 eventLogEntry = WriteLogEntry(source); 138 else 139 eventLogEntry = WriteLogEntryWithSource(source); 140 141 if (eventLogEntry != null) 142 { 143 Assert.Contains(message, eventLogEntry.Message); 144 Assert.Equal(source, eventLogEntry.Source); 145 Assert.StartsWith(Environment.MachineName.ToLowerInvariant(), eventLogEntry.MachineName.ToLowerInvariant()); 146 Assert.Equal(eventLogEntry.TimeWritten, eventLogEntry.TimeGenerated); 147 } 148 } 149 finally 150 { 151 EventLog.DeleteEventSource(source); 152 Helpers.RetryOnWin7(() => EventLog.Delete(log)); 153 } 154 } 155 156 [ConditionalTheory(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] 157 [InlineData(false)] 158 [InlineData(true)] WriteEntryWithType(bool sourceFlag)159 public void WriteEntryWithType(bool sourceFlag) 160 { 161 string source = "Source" + nameof(WriteEntryWithType); 162 string log = "TypeEntry"; 163 try 164 { 165 EventLog.CreateEventSource(source, log); 166 EventLogEntry eventLogEntry; 167 if (sourceFlag) 168 eventLogEntry = WriteLogEntry(source, type: true); 169 else 170 eventLogEntry = WriteLogEntryWithSource(source, type: true); 171 172 if (eventLogEntry != null) 173 { 174 Assert.Contains(message, eventLogEntry.Message); 175 Assert.Equal(EventLogEntryType.Warning, eventLogEntry.EntryType); 176 } 177 } 178 finally 179 { 180 EventLog.DeleteEventSource(source); 181 Helpers.RetryOnWin7(() => EventLog.Delete(log)); 182 } 183 } 184 185 [ConditionalTheory(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] 186 [InlineData(false)] 187 [InlineData(true)] WriteEntryWithTypeAndId(bool sourceFlag)188 public void WriteEntryWithTypeAndId(bool sourceFlag) 189 { 190 string source = "Source" + nameof(WriteEntryWithTypeAndId); 191 string log = "InstanceEntry"; 192 try 193 { 194 EventLog.CreateEventSource(source, log); 195 EventLogEntry eventLogEntry; 196 if (sourceFlag) 197 eventLogEntry = WriteLogEntry(source, type: true, instance: true); 198 else 199 eventLogEntry = WriteLogEntryWithSource(source, type: true, instance: true); 200 201 if (eventLogEntry != null) 202 { 203 Assert.Contains(message, eventLogEntry.Message); 204 Assert.Equal((int)eventInstance.InstanceId, eventLogEntry.InstanceId); 205 } 206 } 207 finally 208 { 209 EventLog.DeleteEventSource(source); 210 Helpers.RetryOnWin7(() => EventLog.Delete(log)); 211 } 212 } 213 214 [ConditionalTheory(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] 215 [InlineData(false)] 216 [InlineData(true)] WriteEntryWithTypeIdAndCategory(bool sourceFlag)217 public void WriteEntryWithTypeIdAndCategory(bool sourceFlag) 218 { 219 string source = "Source" + nameof(WriteEntryWithTypeIdAndCategory); 220 string log = "CategoryEntry"; 221 try 222 { 223 EventLog.CreateEventSource(source, log); 224 EventLogEntry eventLogEntry; 225 if (sourceFlag) 226 eventLogEntry = WriteLogEntry(source, type: true, instance: true, category: true); 227 else 228 eventLogEntry = WriteLogEntryWithSource(source, type: true, instance: true, category: true); 229 230 // There is some prefix string already attached to the message passed 231 // The description for Event ID '0' in Source 'SourceWriteEntryWithTypeIDAndCategory' cannot be found. The local computer may not have the necessary registry information or message DLL files to display the message, or you may not have permission 232 // to access them. The following information is part of the event:'EventLogWriteEntryTestsMessage' 233 // The last part is the associated message 234 // The initial message is due in insufficient permission to access resource library EventLogMsgs.dll 235 if (eventLogEntry != null) 236 { 237 Assert.Contains(message, eventLogEntry.Message); 238 Assert.Equal((short)eventInstance.CategoryId, eventLogEntry.CategoryNumber); 239 Assert.Equal("(" + eventLogEntry.CategoryNumber + ")", eventLogEntry.Category); 240 } 241 } 242 finally 243 { 244 EventLog.DeleteEventSource(source); 245 Helpers.RetryOnWin7(() => EventLog.Delete(log)); 246 } 247 } 248 249 [ConditionalTheory(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] 250 [InlineData(false)] 251 [InlineData(true)] WriteEntryWithTypeIdCategoryAndData(bool sourceFlag)252 public void WriteEntryWithTypeIdCategoryAndData(bool sourceFlag) 253 { 254 string source = "Source" + nameof(WriteEntryWithTypeIdCategoryAndData); 255 string log = "EntryData"; 256 try 257 { 258 EventLog.CreateEventSource(source, log); 259 EventLogEntry eventLogEntry; 260 if (sourceFlag) 261 eventLogEntry = WriteLogEntry(source, type: true, instance: true, category: true, data: true); 262 else 263 eventLogEntry = WriteLogEntryWithSource(source, type: true, instance: true, category: true, data: true); 264 265 if (eventLogEntry != null) 266 { 267 Assert.Contains(message, eventLogEntry.Message); 268 Assert.Equal(rawData, eventLogEntry.Data); 269 } 270 } 271 finally 272 { 273 EventLog.DeleteEventSource(source); 274 Helpers.RetryOnWin7(() => EventLog.Delete(log)); 275 } 276 } 277 278 [ConditionalTheory(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] WriteEntryWithoutSource()279 public void WriteEntryWithoutSource() 280 { 281 using (EventLog eventLog = new EventLog()) 282 { 283 Assert.Throws<ArgumentException>(() => eventLog.WriteEntry(message)); 284 } 285 } 286 287 [ConditionalTheory(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] WriteEntryWithInvalidType()288 public void WriteEntryWithInvalidType() 289 { 290 using (EventLog eventLog = new EventLog()) 291 { 292 string source = "Source_" + nameof(WriteEntryWithInvalidType); 293 eventLog.Source = source; 294 Assert.Throws<InvalidEnumArgumentException>(() => eventLog.WriteEntry(message, (EventLogEntryType)7)); // 7 is a random number which is not associated with any type in EventLogEntryType 295 } 296 } 297 298 [ConditionalTheory(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] WriteEntryWithNullOrEmptySource()299 public void WriteEntryWithNullOrEmptySource() 300 { 301 Assert.Throws<ArgumentException>(() => EventLog.WriteEntry(null, message)); 302 Assert.Throws<ArgumentException>(() => EventLog.WriteEntry("", message)); 303 } 304 305 [ConditionalTheory(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] 306 [InlineData(false)] 307 [InlineData(true)] WriteEvent(bool SourceFlag)308 public void WriteEvent(bool SourceFlag) 309 { 310 string source = "Source_" + nameof(WriteEvent); 311 string log = "Event"; 312 try 313 { 314 EventLog.CreateEventSource(source, log); 315 EventLogEntry eventLogEntry; 316 if (SourceFlag) 317 eventLogEntry = WriteLogEntryEventSource(source); 318 else 319 eventLogEntry = WriteLogEntryEvent(source); 320 321 if (eventLogEntry != null) 322 Assert.All(insertStrings, message => eventLogEntry.Message.Contains(message)); 323 } 324 finally 325 { 326 EventLog.DeleteEventSource(source); 327 Helpers.RetryOnWin7(() => EventLog.Delete(log)); 328 } 329 } 330 331 [ConditionalTheory(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] 332 [InlineData(false)] 333 [InlineData(true)] WriteEventWithData(bool SourceFlag)334 public void WriteEventWithData(bool SourceFlag) 335 { 336 string log = "EventData"; 337 string source = "Source_" + nameof(WriteEventWithData); 338 try 339 { 340 EventLog.CreateEventSource(source, log); 341 EventLogEntry eventLogEntry; 342 343 if (SourceFlag) 344 eventLogEntry = WriteLogEntryEventSource(source, data: true); 345 else 346 eventLogEntry = WriteLogEntryEvent(source, data: true); 347 348 if (eventLogEntry != null) 349 Assert.Equal(rawData, eventLogEntry.Data); 350 } 351 finally 352 { 353 EventLog.DeleteEventSource(source); 354 Helpers.RetryOnWin7(() => EventLog.Delete(log)); 355 } 356 } 357 358 [ConditionalTheory(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] WriteEventInstanceNull()359 public void WriteEventInstanceNull() 360 { 361 string source = "Source_" + nameof(WriteEventInstanceNull); 362 Assert.Throws<ArgumentNullException>(() => Helpers.RetryOnWin7(() => EventLog.WriteEvent(source, null, insertStrings))); 363 } 364 365 [ConditionalTheory(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] WriteEventMessageValues_OutOfRange()366 public void WriteEventMessageValues_OutOfRange() 367 { 368 string source = "Source_" + nameof(WriteEventMessageValues_OutOfRange); 369 string[] message = new string[1]; 370 message[0] = new string('c', 32767); 371 Assert.Throws<ArgumentException>(() => Helpers.RetryOnWin7(() => EventLog.WriteEvent(source, eventInstance, message))); 372 } 373 374 [ConditionalFact(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] WriteWithoutExistingSource()375 public void WriteWithoutExistingSource() 376 { 377 string source = "Source_" + nameof(WriteWithoutExistingSource); 378 try 379 { 380 Helpers.RetryOnWin7(() => EventLog.WriteEvent(source, eventInstance, rawData, null)); 381 Assert.Equal("Application", EventLog.LogNameFromSourceName(source, ".")); 382 } 383 finally 384 { 385 EventLog.DeleteEventSource(source); 386 } 387 } 388 389 [ConditionalTheory(typeof(Helpers), nameof(Helpers.IsElevatedAndSupportsEventLogs))] SourceNameMaxLengthExceeded()390 public void SourceNameMaxLengthExceeded() 391 { 392 string source = new string('s', 254); 393 Assert.Throws<ArgumentException>(() => EventLog.WriteEntry(source, message)); 394 } 395 } 396 397 internal static class EventLogEntryCollectionExtensions 398 { LastOrDefault(this EventLogEntryCollection elec)399 internal static EventLogEntry LastOrDefault(this EventLogEntryCollection elec) 400 { 401 return Helpers.RetryOnWin7(() => elec.Count > 0 ? elec[elec.Count - 1] : null); 402 } 403 } 404 } 405