From 4fbd94c0f2dde112f07e5bd0db52327bcdb702b6 Mon Sep 17 00:00:00 2001 From: Aashish Patil Date: Thu, 7 May 2026 11:26:55 -0700 Subject: [PATCH 1/4] chore(fdc): Use service classes to fetch auth and appcheck instances --- .../lib/src/firebase_data_connect.dart | 21 +++- .../src/cache/cache_manager_test.mocks.dart | 10 ++ .../test/src/firebase_data_connect_test.dart | 115 ++++++++++++++++++ .../src/firebase_data_connect_test.mocks.dart | 10 ++ 4 files changed, 151 insertions(+), 5 deletions(-) diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart index ec731343a66c..64ea12c069cb 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart @@ -33,7 +33,11 @@ class FirebaseDataConnect extends FirebasePluginPlatform { FirebaseDataConnect( {required this.app, required this.connectorConfig, + @Deprecated( + 'Passing an explicit instance is deprecated, internal handling is now automatic.') this.auth, + @Deprecated( + 'Passing an explicit instance is deprecated, internal handling is now automatic.') this.appCheck, CallerSDKType? sdkType, this.cacheSettings}) @@ -94,20 +98,23 @@ class FirebaseDataConnect extends FirebasePluginPlatform { } transportOptions ??= TransportOptions('firebasedataconnect.googleapis.com', null, true); + final effectiveAuth = auth ?? app.getService(); + final effectiveAppCheck = appCheck ?? app.getService(); + final rest = RestTransport( transportOptions!, options, app.options.appId, _sdkType, - appCheck, + effectiveAppCheck, ); final ws = WebSocketTransport( transportOptions!, options, app.options.appId, _sdkType, - appCheck, - auth, + effectiveAppCheck, + effectiveAuth, ); transport = _RoutingTransport(rest, ws); } @@ -198,14 +205,18 @@ class FirebaseDataConnect extends FirebasePluginPlatform { /// If pass in [appCheck], request session will get protected from abusing. static FirebaseDataConnect instanceFor( {FirebaseApp? app, + @Deprecated( + 'Passing an explicit instance is deprecated, internal handling is now automatic.') FirebaseAuth? auth, + @Deprecated( + 'Passing an explicit instance is deprecated, internal handling is now automatic.') FirebaseAppCheck? appCheck, CallerSDKType? sdkType, required ConnectorConfig connectorConfig, CacheSettings? cacheSettings}) { app ??= Firebase.app(); - auth ??= FirebaseAuth.instanceFor(app: app); - appCheck ??= FirebaseAppCheck.instanceFor(app: app); + auth ??= app.getService(); + appCheck ??= app.getService(); if (cachedInstances[app.name] != null && cachedInstances[app.name]![connectorConfig.toJson()] != null) { diff --git a/packages/firebase_data_connect/firebase_data_connect/test/src/cache/cache_manager_test.mocks.dart b/packages/firebase_data_connect/firebase_data_connect/test/src/cache/cache_manager_test.mocks.dart index 09f67581ad75..4f989b0bc28d 100644 --- a/packages/firebase_data_connect/firebase_data_connect/test/src/cache/cache_manager_test.mocks.dart +++ b/packages/firebase_data_connect/firebase_data_connect/test/src/cache/cache_manager_test.mocks.dart @@ -120,6 +120,16 @@ class MockFirebaseApp extends _i1.Mock implements _i3.FirebaseApp { returnValue: _i5.Future.value(), returnValueForMissingStub: _i5.Future.value(), ) as _i5.Future); + + @override + void registerService(T? service) => + super.noSuchMethod( + Invocation.method( + #registerService, + [service], + ), + returnValueForMissingStub: null, + ); } /// A class which mocks [ConnectorConfig]. diff --git a/packages/firebase_data_connect/firebase_data_connect/test/src/firebase_data_connect_test.dart b/packages/firebase_data_connect/firebase_data_connect/test/src/firebase_data_connect_test.dart index b4edc25b2a81..2170caba7347 100644 --- a/packages/firebase_data_connect/firebase_data_connect/test/src/firebase_data_connect_test.dart +++ b/packages/firebase_data_connect/firebase_data_connect/test/src/firebase_data_connect_test.dart @@ -38,6 +38,35 @@ class MockFirebaseAuth extends Mock implements FirebaseAuth { class MockFirebaseAppCheck extends Mock implements FirebaseAppCheck {} +class DynamicMockFirebaseApp extends Mock implements FirebaseApp { + DynamicMockFirebaseApp({ + required this.name, + required this.options, + this.mockAuth, + this.mockAppCheck, + }); + + @override + final String name; + + @override + final FirebaseOptions options; + + final FirebaseAuth? mockAuth; + final FirebaseAppCheck? mockAppCheck; + + @override + T? getService() { + if (T == FirebaseAppCheck) { + return mockAppCheck as T?; + } + if (T == FirebaseAuth) { + return mockAuth as T?; + } + return null; + } +} + class MockTransportOptions extends Mock implements TransportOptions {} class MockDataConnectTransport extends Mock implements DataConnectTransport {} @@ -195,5 +224,91 @@ void main() { equals(instance), ); }); + + test( + 'instanceFor discovers dynamic FirebaseAuth and FirebaseAppCheck from FirebaseApp registry when parameters are omitted', + () { + FirebaseDataConnect.cachedInstances.clear(); + + final dynamicApp = DynamicMockFirebaseApp( + name: 'dynamicAppName', + options: const FirebaseOptions( + apiKey: 'fake_api_key', + appId: 'fake_app_id', + messagingSenderId: 'fake_messaging_sender_id', + projectId: 'fake_project_id', + ), + mockAuth: mockAuth, + mockAppCheck: mockAppCheck, + ); + + when(mockConnectorConfig.toJson()) + .thenReturn('dynamicConnectorConfigStr'); + + final instance = FirebaseDataConnect.instanceFor( + app: dynamicApp, + connectorConfig: mockConnectorConfig, + ); + + expect(instance.auth, equals(mockAuth)); + expect(instance.appCheck, equals(mockAppCheck)); + }); + + test('instanceFor handles fallback to null if getService returns null', () { + FirebaseDataConnect.cachedInstances.clear(); + + final fallbackApp = DynamicMockFirebaseApp( + name: 'fallbackAppName', + options: const FirebaseOptions( + apiKey: 'fake_api_key', + appId: 'fake_app_id', + messagingSenderId: 'fake_messaging_sender_id', + projectId: 'fake_project_id', + ), + mockAuth: null, + mockAppCheck: null, + ); + + when(mockConnectorConfig.toJson()) + .thenReturn('fallbackConnectorConfigStr'); + + final instance = FirebaseDataConnect.instanceFor( + app: fallbackApp, + connectorConfig: mockConnectorConfig, + ); + + expect(instance.auth, isNull); + expect(instance.appCheck, isNull); + }); + + test( + 'checkTransport resolves dynamic service instances from registry just-in-time', + () { + FirebaseDataConnect.cachedInstances.clear(); + + final dynamicApp = DynamicMockFirebaseApp( + name: 'transportAppName', + options: const FirebaseOptions( + apiKey: 'fake_api_key', + appId: 'fake_app_id', + messagingSenderId: 'fake_messaging_sender_id', + projectId: 'fake_project_id', + ), + mockAuth: mockAuth, + mockAppCheck: mockAppCheck, + ); + + final instance = FirebaseDataConnect( + app: dynamicApp, + connectorConfig: mockConnectorConfig, + ); + + instance.checkTransport(); + + final dynamic routingTransport = instance.transport; + expect(routingTransport.rest.appCheck, equals(mockAppCheck)); + expect(routingTransport.websocket.auth, equals(mockAuth)); + expect(routingTransport.websocket.appCheck, equals(mockAppCheck)); + }); }); } diff --git a/packages/firebase_data_connect/firebase_data_connect/test/src/firebase_data_connect_test.mocks.dart b/packages/firebase_data_connect/firebase_data_connect/test/src/firebase_data_connect_test.mocks.dart index 06634cc3f1ec..23020e0b3009 100644 --- a/packages/firebase_data_connect/firebase_data_connect/test/src/firebase_data_connect_test.mocks.dart +++ b/packages/firebase_data_connect/firebase_data_connect/test/src/firebase_data_connect_test.mocks.dart @@ -120,6 +120,16 @@ class MockFirebaseApp extends _i1.Mock implements _i3.FirebaseApp { returnValue: _i5.Future.value(), returnValueForMissingStub: _i5.Future.value(), ) as _i5.Future); + + @override + void registerService(T? service) => + super.noSuchMethod( + Invocation.method( + #registerService, + [service], + ), + returnValueForMissingStub: null, + ); } /// A class which mocks [ConnectorConfig]. From 45a0c533b82dab9bd17da86be176a1e655d6b166 Mon Sep 17 00:00:00 2001 From: Aashish Patil Date: Thu, 7 May 2026 11:38:35 -0700 Subject: [PATCH 2/4] Gemini feedback --- .../lib/src/firebase_data_connect.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart index 64ea12c069cb..287f781c082a 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart @@ -98,23 +98,23 @@ class FirebaseDataConnect extends FirebasePluginPlatform { } transportOptions ??= TransportOptions('firebasedataconnect.googleapis.com', null, true); - final effectiveAuth = auth ?? app.getService(); - final effectiveAppCheck = appCheck ?? app.getService(); + auth ??= app.getService(); + appCheck ??= app.getService(); final rest = RestTransport( transportOptions!, options, app.options.appId, _sdkType, - effectiveAppCheck, + appCheck, ); final ws = WebSocketTransport( transportOptions!, options, app.options.appId, _sdkType, - effectiveAppCheck, - effectiveAuth, + appCheck, + auth, ); transport = _RoutingTransport(rest, ws); } From a9f6b011fdc183feccce16c241bb12daab39523a Mon Sep 17 00:00:00 2001 From: Aashish Patil Date: Thu, 7 May 2026 14:40:52 -0700 Subject: [PATCH 3/4] Cynthia feedback - reverting change. --- .../firebase_data_connect/lib/src/firebase_data_connect.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart b/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart index 287f781c082a..45ec2f1815cd 100644 --- a/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart +++ b/packages/firebase_data_connect/firebase_data_connect/lib/src/firebase_data_connect.dart @@ -215,8 +215,8 @@ class FirebaseDataConnect extends FirebasePluginPlatform { required ConnectorConfig connectorConfig, CacheSettings? cacheSettings}) { app ??= Firebase.app(); - auth ??= app.getService(); - appCheck ??= app.getService(); + auth ??= FirebaseAuth.instanceFor(app: app); + appCheck ??= FirebaseAppCheck.instanceFor(app: app); if (cachedInstances[app.name] != null && cachedInstances[app.name]![connectorConfig.toJson()] != null) { From afecc0c20ccdc4160dbfb9534d61d7fba7bf398f Mon Sep 17 00:00:00 2001 From: Aashish Patil Date: Thu, 7 May 2026 15:48:02 -0700 Subject: [PATCH 4/4] Adjust tests for the revert. --- .../test/src/firebase_data_connect_test.dart | 56 ------------------- 1 file changed, 56 deletions(-) diff --git a/packages/firebase_data_connect/firebase_data_connect/test/src/firebase_data_connect_test.dart b/packages/firebase_data_connect/firebase_data_connect/test/src/firebase_data_connect_test.dart index 2170caba7347..eabf82393de8 100644 --- a/packages/firebase_data_connect/firebase_data_connect/test/src/firebase_data_connect_test.dart +++ b/packages/firebase_data_connect/firebase_data_connect/test/src/firebase_data_connect_test.dart @@ -225,62 +225,6 @@ void main() { ); }); - test( - 'instanceFor discovers dynamic FirebaseAuth and FirebaseAppCheck from FirebaseApp registry when parameters are omitted', - () { - FirebaseDataConnect.cachedInstances.clear(); - - final dynamicApp = DynamicMockFirebaseApp( - name: 'dynamicAppName', - options: const FirebaseOptions( - apiKey: 'fake_api_key', - appId: 'fake_app_id', - messagingSenderId: 'fake_messaging_sender_id', - projectId: 'fake_project_id', - ), - mockAuth: mockAuth, - mockAppCheck: mockAppCheck, - ); - - when(mockConnectorConfig.toJson()) - .thenReturn('dynamicConnectorConfigStr'); - - final instance = FirebaseDataConnect.instanceFor( - app: dynamicApp, - connectorConfig: mockConnectorConfig, - ); - - expect(instance.auth, equals(mockAuth)); - expect(instance.appCheck, equals(mockAppCheck)); - }); - - test('instanceFor handles fallback to null if getService returns null', () { - FirebaseDataConnect.cachedInstances.clear(); - - final fallbackApp = DynamicMockFirebaseApp( - name: 'fallbackAppName', - options: const FirebaseOptions( - apiKey: 'fake_api_key', - appId: 'fake_app_id', - messagingSenderId: 'fake_messaging_sender_id', - projectId: 'fake_project_id', - ), - mockAuth: null, - mockAppCheck: null, - ); - - when(mockConnectorConfig.toJson()) - .thenReturn('fallbackConnectorConfigStr'); - - final instance = FirebaseDataConnect.instanceFor( - app: fallbackApp, - connectorConfig: mockConnectorConfig, - ); - - expect(instance.auth, isNull); - expect(instance.appCheck, isNull); - }); - test( 'checkTransport resolves dynamic service instances from registry just-in-time', () {