@@ -5,13 +5,24 @@ namespace Sentry.Extensions.AI.Tests;
55
66public class SentryInstrumentedFunctionTests
77{
8+ private class Fixture
9+ {
10+ public IHub Hub { get ; } = Substitute . For < IHub > ( ) ;
11+
12+ public Fixture ( )
13+ {
14+ Hub . IsEnabled . Returns ( true ) ;
15+ }
16+ }
17+
18+ private readonly Fixture _fixture = new ( ) ;
19+
820 [ Fact ]
921 public async Task InvokeCoreAsync_WithValidFunction_ReturnsResult ( )
1022 {
1123 // Arrange
12- using var sentryDisposable = SentryHelpers . InitializeSdk ( ) ;
1324 var testFunction = AIFunctionFactory . Create ( ( ) => "test result" , "TestFunction" , "Test function description" ) ;
14- var sentryFunction = new SentryInstrumentedFunction ( testFunction ) ;
25+ var sentryFunction = new SentryInstrumentedFunction ( testFunction , _fixture . Hub ) ;
1526 var arguments = new AIFunctionArguments ( ) ;
1627
1728 // Act
@@ -28,17 +39,20 @@ public async Task InvokeCoreAsync_WithValidFunction_ReturnsResult()
2839 {
2940 Assert . Equal ( "test result" , result ) ;
3041 }
42+
3143 Assert . Equal ( "TestFunction" , sentryFunction . Name ) ;
3244 Assert . Equal ( "Test function description" , sentryFunction . Description ) ;
45+ _fixture . Hub . Received ( 1 ) . StartTransaction (
46+ Arg . Any < ITransactionContext > ( ) ,
47+ Arg . Any < IReadOnlyDictionary < string , object ? > > ( ) ) ;
3348 }
3449
3550 [ Fact ]
3651 public async Task InvokeCoreAsync_WithNullResult_ReturnsNull ( )
3752 {
3853 // Arrange
39- using var sentryDisposable = SentryHelpers . InitializeSdk ( ) ;
4054 var testFunction = AIFunctionFactory . Create ( object ? ( ) => null , "TestFunction" , "Test function description" ) ;
41- var sentryFunction = new SentryInstrumentedFunction ( testFunction ) ;
55+ var sentryFunction = new SentryInstrumentedFunction ( testFunction , _fixture . Hub ) ;
4256 var arguments = new AIFunctionArguments ( ) ;
4357
4458 // Act
@@ -53,16 +67,19 @@ public async Task InvokeCoreAsync_WithNullResult_ReturnsNull()
5367 {
5468 Assert . Null ( result ) ;
5569 }
70+
71+ _fixture . Hub . Received ( 1 ) . StartTransaction (
72+ Arg . Any < ITransactionContext > ( ) ,
73+ Arg . Any < IReadOnlyDictionary < string , object ? > > ( ) ) ;
5674 }
5775
5876 [ Fact ]
5977 public async Task InvokeCoreAsync_WithJsonNullResult_ReturnsJsonElement ( )
6078 {
6179 // Arrange
62- using var sentryDisposable = SentryHelpers . InitializeSdk ( ) ;
6380 var jsonNullElement = JsonSerializer . Deserialize < JsonElement > ( "null" ) ;
6481 var testFunction = AIFunctionFactory . Create ( ( ) => jsonNullElement , "TestFunction" , "Test function description" ) ;
65- var sentryFunction = new SentryInstrumentedFunction ( testFunction ) ;
82+ var sentryFunction = new SentryInstrumentedFunction ( testFunction , _fixture . Hub ) ;
6683 var arguments = new AIFunctionArguments ( ) ;
6784
6885 // Act
@@ -73,16 +90,18 @@ public async Task InvokeCoreAsync_WithJsonNullResult_ReturnsJsonElement()
7390 Assert . IsType < JsonElement > ( result ) ;
7491 var jsonResult = ( JsonElement ) result ;
7592 Assert . Equal ( JsonValueKind . Null , jsonResult . ValueKind ) ;
93+ _fixture . Hub . Received ( 1 ) . StartTransaction (
94+ Arg . Any < ITransactionContext > ( ) ,
95+ Arg . Any < IReadOnlyDictionary < string , object ? > > ( ) ) ;
7696 }
7797
7898 [ Fact ]
7999 public async Task InvokeCoreAsync_WithJsonElementResult_CallsToStringForSpanOutput ( )
80100 {
81101 // Arrange
82- using var sentryDisposable = SentryHelpers . InitializeSdk ( ) ;
83102 var jsonElement = JsonSerializer . Deserialize < JsonElement > ( "\" test output\" " ) ;
84103 var testFunction = AIFunctionFactory . Create ( ( ) => jsonElement , "TestFunction" , "Test function description" ) ;
85- var sentryFunction = new SentryInstrumentedFunction ( testFunction ) ;
104+ var sentryFunction = new SentryInstrumentedFunction ( testFunction , _fixture . Hub ) ;
86105 var arguments = new AIFunctionArguments ( ) ;
87106
88107 // Act
@@ -93,16 +112,22 @@ public async Task InvokeCoreAsync_WithJsonElementResult_CallsToStringForSpanOutp
93112 Assert . IsType < JsonElement > ( result ) ;
94113 var jsonResult = ( JsonElement ) result ;
95114 Assert . Equal ( "test output" , jsonResult . GetString ( ) ) ;
115+ _fixture . Hub . Received ( 1 ) . StartTransaction (
116+ Arg . Any < ITransactionContext > ( ) ,
117+ Arg . Any < IReadOnlyDictionary < string , object ? > > ( ) ) ;
96118 }
97119
98120 [ Fact ]
99121 public async Task InvokeCoreAsync_WithComplexResult_ReturnsObject ( )
100122 {
101123 // Arrange
102- using var sentryDisposable = SentryHelpers . InitializeSdk ( ) ;
103- var resultObject = new { message = "test" , count = 42 } ;
124+ var resultObject = new
125+ {
126+ message = "test" ,
127+ count = 42
128+ } ;
104129 var testFunction = AIFunctionFactory . Create ( ( ) => resultObject , "TestFunction" , "Test function description" ) ;
105- var sentryFunction = new SentryInstrumentedFunction ( testFunction ) ;
130+ var sentryFunction = new SentryInstrumentedFunction ( testFunction , _fixture . Hub ) ;
106131 var arguments = new AIFunctionArguments ( ) ;
107132
108133 // Act
@@ -122,67 +147,81 @@ public async Task InvokeCoreAsync_WithComplexResult_ReturnsObject()
122147 {
123148 Assert . Equal ( resultObject , result ) ;
124149 }
150+
151+ _fixture . Hub . Received ( 1 ) . StartTransaction (
152+ Arg . Any < ITransactionContext > ( ) ,
153+ Arg . Any < IReadOnlyDictionary < string , object ? > > ( ) ) ;
125154 }
126155
127156 [ Fact ]
128157 public async Task InvokeCoreAsync_WhenFunctionThrows_PropagatesException ( )
129158 {
130159 // Arrange
131- using var sentryDisposable = SentryHelpers . InitializeSdk ( ) ;
132160 var expectedException = new InvalidOperationException ( "Test exception" ) ;
133- var testFunction = AIFunctionFactory . Create ( new Func < object > ( ( ) => throw expectedException ) , "TestFunction" , "Test function description" ) ;
134- var sentryFunction = new SentryInstrumentedFunction ( testFunction ) ;
161+ var testFunction = AIFunctionFactory . Create ( new Func < object > ( ( ) => throw expectedException ) , "TestFunction" ,
162+ "Test function description" ) ;
163+ var sentryFunction = new SentryInstrumentedFunction ( testFunction , _fixture . Hub ) ;
135164 var arguments = new AIFunctionArguments ( ) ;
136165
137166 // Act & Assert
138167 var actualException = await Assert . ThrowsAsync < InvalidOperationException > ( async ( ) =>
139168 await sentryFunction . InvokeAsync ( arguments ) ) ;
140169
141170 Assert . Equal ( expectedException . Message , actualException . Message ) ;
171+ _fixture . Hub . Received ( 1 ) . StartTransaction (
172+ Arg . Any < ITransactionContext > ( ) ,
173+ Arg . Any < IReadOnlyDictionary < string , object ? > > ( ) ) ;
142174 }
143175
144176 [ Fact ]
145177 public async Task InvokeCoreAsync_WithCancellation_PropagatesCancellation ( )
146178 {
147179 // Arrange
148- using var sentryDisposable = SentryHelpers . InitializeSdk ( ) ;
149180 var testFunction = AIFunctionFactory . Create ( ( CancellationToken cancellationToken ) =>
150181 {
151182 cancellationToken . ThrowIfCancellationRequested ( ) ;
152183 return "result" ;
153184 } , "TestFunction" , "Test function description" ) ;
154185
155- var sentryFunction = new SentryInstrumentedFunction ( testFunction ) ;
186+ var sentryFunction = new SentryInstrumentedFunction ( testFunction , _fixture . Hub ) ;
156187 var arguments = new AIFunctionArguments ( ) ;
157188 var cts = new CancellationTokenSource ( ) ;
158189 await cts . CancelAsync ( ) ;
159190
160191 // Act & Assert
161192 await Assert . ThrowsAsync < OperationCanceledException > ( async ( ) =>
162193 await sentryFunction . InvokeAsync ( arguments , cts . Token ) ) ;
194+ _fixture . Hub . Received ( 1 ) . StartTransaction (
195+ Arg . Any < ITransactionContext > ( ) ,
196+ Arg . Any < IReadOnlyDictionary < string , object ? > > ( ) ) ;
163197 }
164198
165199 [ Fact ]
166200 public async Task InvokeCoreAsync_WithParameters_PassesParametersCorrectly ( )
167201 {
168202 // Arrange
169- using var sentryDisposable = SentryHelpers . InitializeSdk ( ) ;
170203 var receivedArguments = ( AIFunctionArguments ? ) null ;
171204 var testFunction = AIFunctionFactory . Create ( ( AIFunctionArguments args ) =>
172205 {
173206 receivedArguments = args ;
174207 return "result" ;
175208 } , "TestFunction" , "Test function description" ) ;
176209
177- var sentryFunction = new SentryInstrumentedFunction ( testFunction ) ;
178- var arguments = new AIFunctionArguments { [ "param1" ] = "value1" } ;
210+ var sentryFunction = new SentryInstrumentedFunction ( testFunction , _fixture . Hub ) ;
211+ var arguments = new AIFunctionArguments
212+ {
213+ [ "param1" ] = "value1"
214+ } ;
179215
180216 // Act
181217 await sentryFunction . InvokeAsync ( arguments ) ;
182218
183219 // Assert
184220 Assert . NotNull ( receivedArguments ) ;
185221 Assert . Equal ( "value1" , receivedArguments [ "param1" ] ) ;
222+ _fixture . Hub . Received ( 1 ) . StartTransaction (
223+ Arg . Any < ITransactionContext > ( ) ,
224+ Arg . Any < IReadOnlyDictionary < string , object ? > > ( ) ) ;
186225 }
187226
188227 [ Fact ]
@@ -192,23 +231,10 @@ public void Constructor_PreservesInnerFunctionProperties()
192231 var testFunction = AIFunctionFactory . Create ( ( ) => "test" , "TestFunction" , "Test function description" ) ;
193232
194233 // Act
195- var sentryFunction = new SentryInstrumentedFunction ( testFunction ) ;
234+ var sentryFunction = new SentryInstrumentedFunction ( testFunction , _fixture . Hub ) ;
196235
197236 // Assert
198237 Assert . Equal ( "TestFunction" , sentryFunction . Name ) ;
199238 Assert . Equal ( "Test function description" , sentryFunction . Description ) ;
200239 }
201240}
202-
203- internal static class SentryHelpers
204- {
205- public static IDisposable InitializeSdk ( )
206- {
207- return SentrySdk . Init ( options =>
208- {
209- options . Dsn = ValidDsn ;
210- options . TracesSampleRate = 1.0 ;
211- options . Debug = false ;
212- } ) ;
213- }
214- }
0 commit comments