@@ -127,6 +127,91 @@ public async Task StreamingErrorEndpoint_StreamIsTruncated()
127127 _output . WriteLine ( $ "Expected error: { ex . Message } ") ;
128128 }
129129 }
130+
131+ [ Fact ]
132+ public async Task OnCompletedCallback_IsExecuted ( )
133+ {
134+ var apiUrl = await _fixture . GetApiUrlAsync ( ) ;
135+ using var httpClient = new HttpClient ( ) ;
136+
137+ // First request registers the OnCompleted callback
138+ var response = await httpClient . GetWithRetryAsync ( $ "{ apiUrl } oncompleted-test") ;
139+ Assert . Equal ( HttpStatusCode . OK , response . StatusCode ) ;
140+ var body = await response . Content . ReadAsStringAsync ( ) ;
141+ _output . WriteLine ( $ "Body: { body } ") ;
142+ Assert . Contains ( "OnCompleted callback registered" , body ) ;
143+
144+ // Second request verifies the callback was executed
145+ var verifyResponse = await httpClient . GetWithRetryAsync ( $ "{ apiUrl } oncompleted-verify") ;
146+ Assert . Equal ( HttpStatusCode . OK , verifyResponse . StatusCode ) ;
147+ var verifyBody = await verifyResponse . Content . ReadAsStringAsync ( ) ;
148+ _output . WriteLine ( $ "Verify body: { verifyBody } ") ;
149+
150+ var doc = JsonDocument . Parse ( verifyBody ) ;
151+ Assert . True ( doc . RootElement . GetProperty ( "onCompletedExecuted" ) . GetBoolean ( ) ,
152+ "OnCompleted callback should have been executed" ) ;
153+ }
154+
155+ [ Fact ]
156+ public async Task CustomHeaders_PassedThroughApiGateway ( )
157+ {
158+ var apiUrl = await _fixture . GetApiUrlAsync ( ) ;
159+ using var httpClient = new HttpClient ( ) ;
160+
161+ var response = await httpClient . GetWithRetryAsync ( $ "{ apiUrl } custom-headers", HttpStatusCode . Created ) ;
162+
163+ _output . WriteLine ( $ "Status: { response . StatusCode } ") ;
164+ Assert . Equal ( HttpStatusCode . Created , response . StatusCode ) ;
165+
166+ var body = await response . Content . ReadAsStringAsync ( ) ;
167+ Assert . Contains ( "Custom headers response" , body ) ;
168+
169+ // Verify custom headers are present in the response
170+ Assert . True ( response . Headers . Contains ( "X-Custom-Header" ) , "X-Custom-Header should be present" ) ;
171+ Assert . Equal ( "custom-value" , response . Headers . GetValues ( "X-Custom-Header" ) . First ( ) ) ;
172+ Assert . True ( response . Headers . Contains ( "X-Another-Header" ) , "X-Another-Header should be present" ) ;
173+ Assert . Equal ( "another-value" , response . Headers . GetValues ( "X-Another-Header" ) . First ( ) ) ;
174+ }
175+
176+ [ Fact ]
177+ public async Task SetCookie_PassedThroughApiGateway ( )
178+ {
179+ var apiUrl = await _fixture . GetApiUrlAsync ( ) ;
180+ var handler = new HttpClientHandler { UseCookies = false } ;
181+ using var httpClient = new HttpClient ( handler ) ;
182+
183+ var response = await httpClient . GetWithRetryAsync ( $ "{ apiUrl } set-cookie") ;
184+
185+ Assert . Equal ( HttpStatusCode . OK , response . StatusCode ) ;
186+
187+ var body = await response . Content . ReadAsStringAsync ( ) ;
188+ _output . WriteLine ( $ "Body: { body } ") ;
189+ Assert . Contains ( "Cookies set" , body ) ;
190+
191+ // Verify Set-Cookie headers are present
192+ Assert . True ( response . Headers . Contains ( "Set-Cookie" ) , "Set-Cookie header should be present" ) ;
193+ var cookies = response . Headers . GetValues ( "Set-Cookie" ) . ToList ( ) ;
194+ _output . WriteLine ( $ "Cookies: { string . Join ( "; " , cookies ) } ") ;
195+ Assert . True ( cookies . Any ( c => c . Contains ( "session=abc123" ) ) , "session cookie should be present" ) ;
196+ Assert . True ( cookies . Any ( c => c . Contains ( "theme=dark" ) ) , "theme cookie should be present" ) ;
197+ }
198+
199+ [ Fact ]
200+ public async Task PostWithBody_EchoesRequestBody ( )
201+ {
202+ var apiUrl = await _fixture . GetApiUrlAsync ( ) ;
203+ using var httpClient = new HttpClient ( ) ;
204+
205+ var content = new StringContent ( "Hello from integration test" , Encoding . UTF8 , "text/plain" ) ;
206+ var response = await httpClient . PostWithRetryAsync ( $ "{ apiUrl } echo-body", content ) ;
207+
208+ _output . WriteLine ( $ "Status: { response . StatusCode } ") ;
209+ var body = await response . Content . ReadAsStringAsync ( ) ;
210+ _output . WriteLine ( $ "Body: { body } ") ;
211+
212+ Assert . Equal ( HttpStatusCode . OK , response . StatusCode ) ;
213+ Assert . Contains ( "Echo: Hello from integration test" , body ) ;
214+ }
130215 }
131216
132217 internal static class HttpClientExtension
@@ -151,6 +236,27 @@ public static async Task<HttpResponseMessage> GetWithRetryAsync(this HttpClient
151236 }
152237 throw new Exception ( $ "Failed to get expected status code { expectedCode } from { url } after { maxRetries } attempts") ;
153238 }
239+
240+ public static async Task < HttpResponseMessage > PostWithRetryAsync ( this HttpClient httpClient , string url , HttpContent content , HttpStatusCode expectedCode = HttpStatusCode . OK , int maxRetries = 5 , int delaySeconds = 5 )
241+ {
242+ for ( var i = 0 ; i < maxRetries ; i ++ )
243+ {
244+ try
245+ {
246+ var response = await httpClient . PostAsync ( url , content ) ;
247+ if ( response . StatusCode == expectedCode )
248+ {
249+ return response ;
250+ }
251+ }
252+ catch
253+ {
254+ // Ignore and retry
255+ }
256+ await Task . Delay ( TimeSpan . FromSeconds ( delaySeconds ) ) ;
257+ }
258+ throw new Exception ( $ "Failed to get expected status code { expectedCode } from { url } after { maxRetries } attempts") ;
259+ }
154260 }
155261
156262 /// <summary>
0 commit comments