| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- // Copyright 2025 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- @testable import FirebaseRemoteConfig
- import FirebaseRemoteConfigInterop
- import XCTest
- import FirebaseCore
- import FirebaseCoreExtension
- class RemoteConfigComponentTests: XCTestCase {
- var app: FirebaseApp?
- override func tearDown() {
- // Clear out any apps that were called with `configure`.
- FirebaseApp.resetApps()
- RemoteConfigComponent.clearAllComponentInstances()
- super.tearDown()
- }
- func testRemoteConfigInstanceCreationAndCaching() {
- // Create the provider to vend Remote Config instances.
- let provider = providerForTest()
- // Create a Remote Config instance from the provider.
- let sharedNamespace = "some_namespace"
- let config = provider.remoteConfig(forNamespace: sharedNamespace)
- XCTAssertNotNil(config)
- // Fetch an instance with the same namespace - should be the same instance.
- let sameConfig = provider.remoteConfig(forNamespace: sharedNamespace)
- XCTAssertNotNil(sameConfig)
- XCTAssertEqual(config, sameConfig)
- }
- func testSeparateInstancesForDifferentNamespaces() {
- // Create the provider to vend Remote Config instances.
- let provider = providerForTest()
- // Create a Remote Config instance from the provider.
- let config = provider.remoteConfig(forNamespace: "namespace1")
- XCTAssertNotNil(config)
- // Fetch another instance with a different namespace.
- let config2 = provider.remoteConfig(forNamespace: "namespace2")
- XCTAssertNotNil(config2)
- XCTAssertNotEqual(config, config2)
- }
- func testSeparateInstancesForDifferentApps() throws {
- let provider = providerForTest()
- // Create a Remote Config instance from the provider.
- let sharedNamespace = "some_namespace"
- let config = provider.remoteConfig(forNamespace: sharedNamespace)
- XCTAssertNotNil(config)
- // Use a new app and new povider, ensure the instances with the same
- // namespace are different.
- let secondAppName = try XCTUnwrap(provider.app?.name.appending("2"))
- let secondApp = FirebaseApp(instanceWithName: secondAppName, options: fakeOptions())
- let separateProvider = RemoteConfigComponent(app: secondApp)
- let separateConfig = separateProvider.remoteConfig(forNamespace: sharedNamespace)
- XCTAssertNotNil(separateConfig)
- XCTAssertNotEqual(config, separateConfig)
- }
- func testInitialization() {
- // Explicitly instantiate the component here in case the `providerForTest`
- // ever changes to mock something.
- let appName = generatedTestAppName()
- let app = FirebaseApp(instanceWithName: appName, options: fakeOptions())
- let provider = RemoteConfigComponent(app: app)
- XCTAssertNotNil(provider)
- XCTAssertNotNil(provider.app)
- }
- func testRegistersAsLibrary() throws {
- // Now component has two register, one is provider and another one is Interop
- XCTAssertEqual(RemoteConfigComponent.componentsToRegister().count, 2)
- // Configure a test app to fetch instances of provider and interop
- let appName = generatedTestAppName()
- FirebaseApp.configure(name: appName, options: fakeOptions())
- let app = try XCTUnwrap(FirebaseApp.app(name: appName))
- // Attempt to fetch the component and verify it's a valid instance.
- let provider = app.container.instance(for: RemoteConfigProvider.self) as AnyObject
- let interop = app.container.instance(for: RemoteConfigInterop.self) as AnyObject
- XCTAssertNotNil(provider)
- XCTAssertNotNil(interop)
- // Ensure that the instance that comes from the container is cached.
- let sameProvider = app.container.instance(for: RemoteConfigProvider.self) as AnyObject
- let sameInterop = app.container.instance(for: RemoteConfigInterop.self) as AnyObject
- XCTAssertNotNil(sameProvider)
- XCTAssertNotNil(sameInterop)
- XCTAssertTrue(provider === sameProvider)
- XCTAssertTrue(interop === sameInterop)
- XCTAssertTrue(provider === interop)
- }
- func testTwoAppsCreateTwoComponents() throws {
- let appName = generatedTestAppName()
- FirebaseApp.configure(name: appName, options: fakeOptions())
- let app = try XCTUnwrap(FirebaseApp.app(name: appName))
- FirebaseApp.configure(options: fakeOptions())
- let defaultApp = try XCTUnwrap(FirebaseApp.app())
- XCTAssertNotEqual(app, defaultApp)
- let provider = app.container.instance(for: RemoteConfigProvider.self) as AnyObject
- let interop = app.container.instance(for: RemoteConfigInterop.self) as AnyObject
- let defaultProvider = defaultApp.container.instance(for: RemoteConfigProvider.self) as AnyObject
- let defaultAppInterop = defaultApp.container
- .instance(for: RemoteConfigInterop.self) as AnyObject
- XCTAssertTrue(provider === interop)
- XCTAssertTrue(defaultProvider === defaultAppInterop)
- // Check two apps get their own component to register
- XCTAssertFalse(interop === defaultAppInterop)
- }
- // TODO: Consider either using the shared exception catcher or removing
- // exception from implementation (preferred).
- func testThrowsWithEmptyGoogleAppID() {
- let options = fakeOptions()
- options.googleAppID = ""
- // Create the provider to vend Remote Config instances.
- let appName = generatedTestAppName()
- let app = FirebaseApp(instanceWithName: appName, options: options)
- /* component */ _ = RemoteConfigComponent(app: app)
- // Creating a Remote Config instance should fail since the projectID is empty.
- // XCTAssertThrowsError(component.remoteConfig(forNamespace: "some_namespace"))
- }
- // TODO: Consider either using the shared exception catcher or removing
- // exception from implementation (preferred).
- func testThrowsWithNilGCMSenderID() {
- let options = fakeOptions()
- options.gcmSenderID = ""
- // Create the provider to vend Remote Config instances.
- let appName = generatedTestAppName()
- let app = FirebaseApp(instanceWithName: appName, options: options)
- /* component */ _ = RemoteConfigComponent(app: app)
- // Creating a Remote Config instance should fail since the projectID is empty.
- // XCTAssertThrowsError(component.remoteConfig(forNamespace: "some_namespace"))
- }
- // TODO: Consider either using the shared exception catcher or removing
- // exception from implementation (preferred).
- func testThrowsWithEmptyProjectID() {
- let options = fakeOptions()
- options.projectID = ""
- // Create the provider to vend Remote Config instances.
- let appName = generatedTestAppName()
- let app = FirebaseApp(instanceWithName: appName, options: options)
- /* component */ _ = RemoteConfigComponent(app: app)
- // Creating a Remote Config instance should fail since the projectID is empty.
- // XCTAssertThrowsError(component.remoteConfig(forNamespace: "some_namespace"))
- }
- // TODO: Consider either using the shared exception catcher or removing
- // exception from implementation (preferred).
- func testThrowsWithNilProjectID() {
- let options = fakeOptions()
- options.projectID = nil
- // Create the provider to vend Remote Config instances.
- let appName = generatedTestAppName()
- let app = FirebaseApp(instanceWithName: appName, options: options)
- /* component */ _ = RemoteConfigComponent(app: app)
- // Creating a Remote Config instance should fail since the projectID is empty.
- // XCTAssertThrowsError(component.remoteConfig(forNamespace: "some_namespace"))
- }
- // MARK: - Helpers
- // Helper function to create fake options
- func fakeOptions() -> FirebaseOptions {
- let options = FirebaseOptions(googleAppID: "1:123:ios:123abc",
- gcmSenderID: "correct_gcm_sender_id")
- options.apiKey = "AIzaSy-ApiKeyWithValidFormat_0123456789"
- options.projectID = "project-id"
- return options
- }
- private func generatedTestAppName() -> String {
- TestUtilities.generatedTestAppName(for: name)
- }
- private func providerForTest() -> RemoteConfigComponent {
- // Create the provider to vend Remote Config instances.
- let appName = generatedTestAppName()
- let options = fakeOptions().copy() as! FirebaseOptions
- // The app is weakly retained by `RemoteConfigComponent` so strongly
- // retain it by the class instance to keep it from deinitializing.
- app = FirebaseApp(instanceWithName: appName, options: options)
- let provider = RemoteConfigComponent(app: app!)
- XCTAssertNotNil(provider)
- XCTAssertFalse(provider.app?.options.googleAppID.isEmpty ?? true)
- XCTAssertFalse(provider.app?.options.gcmSenderID.isEmpty ?? true)
- return provider
- }
- }
|