@@ -132,9 +132,9 @@ public void RichPayloadEventSourceSessionStateSentTest()
132132#pragma warning restore 618
133133 }
134134
135- /// <summary>
136- /// Tests tracking session state telemetry.
137- /// </summary>
135+ /// <summary>
136+ /// Tests tracking session state telemetry.
137+ /// </summary>
138138 [ TestMethod ]
139139 public void RichPayloadEventSourceSessionPerformanceCounterTest ( )
140140 {
@@ -147,6 +147,79 @@ public void RichPayloadEventSourceSessionPerformanceCounterTest()
147147#pragma warning restore 618
148148 }
149149
150+ /// <summary>
151+ /// Tests start/stop events for Operations.
152+ /// </summary>
153+ [ TestMethod ]
154+ public void RichPayloadEventSourceOperationStartStopTest ( )
155+ {
156+ if ( IsRunningOnEnvironmentSupportingRichPayloadEventSource ( ) )
157+ {
158+ var client = CreateTelemetryClient ( ) ;
159+
160+ using ( var listener = new TestFramework . TestEventListener ( ) )
161+ {
162+ listener . EnableEvents ( RichPayloadEventSource . Log . EventSourceInternal , EventLevel . Informational , RichPayloadEventSource . Keywords . Operations ) ;
163+
164+ // Simulate a Start/Stop request operation
165+ var requestTelemetry = new RequestTelemetry { Name = "Request" } ;
166+ using ( client . StartOperation ( requestTelemetry ) )
167+ {
168+ }
169+
170+ // Expect exactly two events (start and stop)
171+ var actualEvents = listener . Messages . Where ( m => m . Keywords . HasFlag ( RichPayloadEventSource . Keywords . Operations ) ) . Take ( 2 ) . ToArray ( ) ;
172+
173+ VerifyOperationEvent ( requestTelemetry , RequestTelemetry . TelemetryName , EventOpcode . Start , actualEvents [ 0 ] ) ;
174+ VerifyOperationEvent ( requestTelemetry , RequestTelemetry . TelemetryName , EventOpcode . Stop , actualEvents [ 1 ] ) ;
175+ }
176+ }
177+ else
178+ {
179+ // 4.5 doesn't have RichPayload events
180+ Assert . IsNull ( RichPayloadEventSource . Log . EventSourceInternal ) ;
181+ }
182+ }
183+
184+ /// <summary>
185+ /// Tests start/stop events for nested operations.
186+ /// </summary>
187+ [ TestMethod ]
188+ public void RichPayloadEventSourceNestedOperationStartStopTest ( )
189+ {
190+ if ( IsRunningOnEnvironmentSupportingRichPayloadEventSource ( ) )
191+ {
192+ var client = CreateTelemetryClient ( ) ;
193+
194+ using ( var listener = new TestFramework . TestEventListener ( ) )
195+ {
196+ listener . EnableEvents ( RichPayloadEventSource . Log . EventSourceInternal , EventLevel . Informational , RichPayloadEventSource . Keywords . Operations ) ;
197+
198+ // Simulate a Start/Stop request operation
199+ var requestTelemetry = new RequestTelemetry { Name = "Request" } ;
200+ var nestedOperation = new DependencyTelemetry { Name = "Dependency" } ;
201+ using ( client . StartOperation ( requestTelemetry ) )
202+ {
203+ using ( client . StartOperation ( nestedOperation ) )
204+ {
205+ }
206+ }
207+
208+ // Expect exactly four events (start, start, stop, stop)
209+ var actualEvents = listener . Messages . Where ( m=> m . Keywords . HasFlag ( RichPayloadEventSource . Keywords . Operations ) ) . Take ( 4 ) . ToArray ( ) ;
210+
211+ VerifyOperationEvent ( requestTelemetry , RequestTelemetry . TelemetryName , EventOpcode . Start , actualEvents [ 0 ] ) ;
212+ VerifyOperationEvent ( nestedOperation , OperationTelemetry . TelemetryName , EventOpcode . Start , actualEvents [ 1 ] ) ;
213+ VerifyOperationEvent ( nestedOperation , OperationTelemetry . TelemetryName , EventOpcode . Stop , actualEvents [ 2 ] ) ;
214+ VerifyOperationEvent ( requestTelemetry , RequestTelemetry . TelemetryName , EventOpcode . Stop , actualEvents [ 3 ] ) ;
215+ }
216+ }
217+ else
218+ {
219+ // 4.5 doesn't have RichPayload events
220+ Assert . IsNull ( RichPayloadEventSource . Log . EventSourceInternal ) ;
221+ }
222+ }
150223
151224 /// <summary>
152225 /// Tests sanitizing telemetry event
@@ -163,8 +236,7 @@ public void RichPayloadEventSourceSanitizeTest()
163236 ResponseCode = "200"
164237 } ;
165238
166- var client = new TelemetryClient ( ) ;
167- client . InstrumentationKey = Guid . NewGuid ( ) . ToString ( ) ;
239+ var client = CreateTelemetryClient ( ) ;
168240
169241 using ( var listener = new Microsoft . ApplicationInsights . TestFramework . TestEventListener ( ) )
170242 {
@@ -182,6 +254,16 @@ public void RichPayloadEventSourceSanitizeTest()
182254 }
183255
184256
257+ private TelemetryClient CreateTelemetryClient ( )
258+ {
259+ // The default InMemoryChannel creates a worker thread which, if left running, causes
260+ // System.AppDomainUnloadedException from the test runner.
261+ var channel = new TestFramework . StubTelemetryChannel ( ) ;
262+ var configuration = new TelemetryConfiguration ( Guid . NewGuid ( ) . ToString ( ) , channel ) ;
263+ var client = new TelemetryClient ( configuration ) { InstrumentationKey = configuration . InstrumentationKey } ;
264+ return client ;
265+ }
266+
185267 /// <summary>
186268 /// Helper method to setup shared context and call the desired tracking for testing.
187269 /// </summary>
@@ -192,8 +274,7 @@ private void DoTracking(EventKeywords keywords, ITelemetry item, Type dataType,
192274 {
193275 if ( IsRunningOnEnvironmentSupportingRichPayloadEventSource ( ) )
194276 {
195- var client = new TelemetryClient ( ) ;
196- client . InstrumentationKey = Guid . NewGuid ( ) . ToString ( ) ;
277+ var client = CreateTelemetryClient ( ) ;
197278
198279 using ( var listener = new Microsoft . ApplicationInsights . TestFramework . TestEventListener ( ) )
199280 {
@@ -285,6 +366,25 @@ private static void VerifyEventPayload(IEnumerable<PropertyInfo> expectedPropert
285366 }
286367 }
287368
369+ private static void VerifyOperationEvent ( OperationTelemetry expectedOperation , string expectedName , EventOpcode expectedOpCode , EventWrittenEventArgs actualEvent )
370+ {
371+ Assert . AreEqual ( expectedOpCode , actualEvent . Opcode ) ;
372+ #if ! NET45
373+ Assert . AreEqual ( expectedName , actualEvent . EventName ) ;
374+ #endif
375+ VerifyOperationPayload ( expectedOperation , actualEvent . Payload ) ;
376+ }
377+
378+ private static void VerifyOperationPayload ( OperationTelemetry expected , IReadOnlyList < object > actualPayload )
379+ {
380+ Assert . IsNotNull ( actualPayload ) ;
381+ Assert . AreEqual ( 4 , actualPayload . Count ) ;
382+ Assert . AreEqual ( expected . Context . InstrumentationKey , actualPayload [ 0 ] ) ;
383+ Assert . AreEqual ( expected . Id , actualPayload [ 1 ] ) ;
384+ Assert . AreEqual ( expected . Name , actualPayload [ 2 ] ) ;
385+ Assert . AreEqual ( expected . Context . Operation . Id , actualPayload [ 3 ] ) ;
386+ }
387+
288388 private static Type GetEnumerableType ( Type type )
289389 {
290390 foreach ( Type intType in type . GetInterfaces ( ) )
0 commit comments