@@ -18,6 +18,9 @@ import 'package:sentry/src/transport/spotlight_http_transport.dart';
1818import 'package:sentry/src/utils/iterable_utils.dart' ;
1919import 'package:test/test.dart' ;
2020import 'package:sentry/src/noop_log_batcher.dart' ;
21+ import 'package:sentry/src/sentry_log_batcher.dart' ;
22+ import 'package:mockito/mockito.dart' ;
23+ import 'package:http/http.dart' as http;
2124
2225import 'mocks.dart' ;
2326import 'mocks/mock_client_report_recorder.dart' ;
@@ -2610,6 +2613,56 @@ void main() {
26102613 await client.captureEvent (fakeEvent, stackTrace: StackTrace .current);
26112614 });
26122615 });
2616+
2617+ group ('SentryClient close' , () {
2618+ late Fixture fixture;
2619+
2620+ setUp (() {
2621+ fixture = Fixture ();
2622+ });
2623+
2624+ test ('waits for log batcher flush before closing http client' , () async {
2625+ // Create a mock HTTP client that tracks when close is called
2626+ final mockHttpClient = MockHttpClient ();
2627+ fixture.options.httpClient = mockHttpClient;
2628+
2629+ fixture.options.enableLogs = true ;
2630+ final client = fixture.getSut ();
2631+
2632+ // Create a completer to control when flush completes
2633+ final flushCompleter = Completer <void >();
2634+ bool flushStarted = false ;
2635+
2636+ // Create a mock log batcher with async flush
2637+ final mockLogBatcher = MockLogBatcherWithAsyncFlush (
2638+ onFlush: () async {
2639+ flushStarted = true ;
2640+ // Wait for the completer to complete
2641+ await flushCompleter.future;
2642+ },
2643+ );
2644+ fixture.options.logBatcher = mockLogBatcher;
2645+
2646+ // Start close() in the background
2647+ final closeFuture = client.close ();
2648+
2649+ // Wait a bit longer to ensure flush has started
2650+ await Future .delayed (Duration (milliseconds: 50 ));
2651+
2652+ // Verify flush has started but HTTP client is not closed yet
2653+ expect (flushStarted, true , reason: 'Flush should have started' );
2654+ verifyNever (mockHttpClient.close ());
2655+
2656+ // Complete the flush
2657+ flushCompleter.complete ();
2658+
2659+ // Wait for close to complete
2660+ await closeFuture;
2661+
2662+ // Now verify HTTP client was closed
2663+ verify (mockHttpClient.close ()).called (1 );
2664+ });
2665+ });
26132666}
26142667
26152668Future <SentryEvent > eventFromEnvelope (SentryEnvelope envelope) async {
@@ -2804,6 +2857,25 @@ class Fixture {
28042857 }
28052858}
28062859
2860+ class MockHttpClient extends Mock implements http.Client {}
2861+
2862+ class MockLogBatcherWithAsyncFlush implements SentryLogBatcher {
2863+ final Future <void > Function () onFlush;
2864+ final addLogCalls = < SentryLog > [];
2865+
2866+ MockLogBatcherWithAsyncFlush ({required this .onFlush});
2867+
2868+ @override
2869+ void addLog (SentryLog log) {
2870+ addLogCalls.add (log);
2871+ }
2872+
2873+ @override
2874+ FutureOr <void > flush () async {
2875+ await onFlush ();
2876+ }
2877+ }
2878+
28072879class ExceptionWithCause {
28082880 ExceptionWithCause (this .cause, this .stackTrace);
28092881
0 commit comments