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