Skip to content

Commit cc233d6

Browse files
authored
Fake Remote Config console for testing (#5633)
1 parent 4bd4f56 commit cc233d6

20 files changed

+441
-60
lines changed

.github/workflows/remoteconfig.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ jobs:
3131
FirebaseRemoteConfig/Tests/SwiftAPI/GoogleService-Info.plist "$plist_secret"
3232
- name: BuildAndUnitTest # can be replaced with pod lib lint with CocoaPods 1.10
3333
run: scripts/third_party/travis/retry.sh scripts/build.sh RemoteConfig ${{ matrix.target }} unit
34+
- name: Fake Console API Tests
35+
run: scripts/third_party/travis/retry.sh scripts/build.sh RemoteConfig iOS fakeconsole
3436
- name: IntegrationTest
3537
if: matrix.target == 'iOS'
3638
run: ([ -z $plist_secret ] || scripts/third_party/travis/retry.sh scripts/build.sh RemoteConfig iOS integration)

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ jobs:
194194
env:
195195
- PROJECT=RemoteConfig METHOD=pod-lib-lint
196196
script:
197-
- travis_retry ./scripts/if_changed.sh ./scripts/pod_lib_lint.rb FirebaseRemoteConfig.podspec --platforms=ios
197+
- travis_retry ./scripts/if_changed.sh ./scripts/pod_lib_lint.rb FirebaseRemoteConfig.podspec --platforms=ios --skip-tests
198198

199199
- stage: test
200200
osx_image: xcode10.3

FirebaseRemoteConfig.podspec

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,32 @@ app update.
7070
unit_tests.requires_arc = true
7171
end
7272

73-
s.test_spec 'swift-api' do |swift_api_tests|
74-
swift_api_tests.platforms = {:ios => '8.0', :osx => '10.11', :tvos => '10.0'}
75-
swift_api_tests.source_files = 'FirebaseRemoteConfig/Tests/SwiftAPI/*.swift'
76-
swift_api_tests.requires_app_host = true
77-
swift_api_tests.resources =
78-
'FirebaseRemoteConfig/Tests/SwiftAPI/GoogleService-Info.plist'
73+
# Run Swift API tests on a real backend.
74+
s.test_spec 'swift-api-tests' do |swift_api|
75+
swift_api.platforms = {:ios => '8.0', :osx => '10.11', :tvos => '10.0'}
76+
swift_api.source_files = 'FirebaseRemoteConfig/Tests/SwiftAPI/*.swift',
77+
'FirebaseRemoteConfig/Tests/FakeUtils/*.[hm]',
78+
'FirebaseRemoteConfig/Tests/FakeUtils/*.swift'
79+
swift_api.requires_app_host = true
80+
swift_api.pod_target_xcconfig = {
81+
'SWIFT_OBJC_BRIDGING_HEADER' => '$(PODS_TARGET_SRCROOT)/FirebaseRemoteConfig/Tests/FakeUtils/Bridging-Header.h'
82+
}
83+
swift_api.resources = 'FirebaseRemoteConfig/Tests/SwiftAPI/GoogleService-Info.plist'
84+
swift_api.dependency 'OCMock'
85+
end
86+
87+
# Run Swift API tests and tests requiring console changes on a Fake Console.
88+
s.test_spec 'fake-console-tests' do |fake_console|
89+
fake_console.platforms = {:ios => '8.0', :osx => '10.11', :tvos => '10.0'}
90+
fake_console.source_files = 'FirebaseRemoteConfig/Tests/SwiftAPI/*.swift',
91+
'FirebaseRemoteConfig/Tests/FakeUtils/*.[hm]',
92+
'FirebaseRemoteConfig/Tests/FakeUtils/*.swift',
93+
'FirebaseRemoteConfig/Tests/FakeConsole/*.swift'
94+
fake_console.requires_app_host = true
95+
fake_console.pod_target_xcconfig = {
96+
'SWIFT_OBJC_BRIDGING_HEADER' => '$(PODS_TARGET_SRCROOT)/FirebaseRemoteConfig/Tests/FakeUtils/Bridging-Header.h'
97+
}
98+
fake_console.resources = 'FirebaseRemoteConfig/Tests/FakeUtils/GoogleService-Info.plist'
99+
fake_console.dependency 'OCMock'
79100
end
80101
end

FirebaseRemoteConfig/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Unreleased
22
- [changed] Updated `fetchAndActivateWithCompletionHandler:` implementation to activate asynchronously. (#5617)
33
- [fixed] Remove undefined class via removing unused proto generated source files. (#4334)
4+
- [added] Add an URLSession Partial Mock to enable testing without a backend. (#5633)
45

56
# v4.4.11
67
- [fixed] Fixed a bug where settings updates weren't applied before fetches. (#4740)

FirebaseRemoteConfig/Sources/FIRRemoteConfig.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@
2323
#import <FirebaseCore/FIROptionsInternal.h>
2424
#import "FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.h"
2525
#import "FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h"
26+
#import "FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h"
2627
#import "FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h"
2728
#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"
2829
#import "FirebaseRemoteConfig/Sources/RCNConfigContent.h"
2930
#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
3031
#import "FirebaseRemoteConfig/Sources/RCNConfigExperiment.h"
31-
#import "FirebaseRemoteConfig/Sources/RCNConfigFetch.h"
3232
#import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h"
3333
#import "FirebaseRemoteConfig/Sources/RCNDevice.h"
3434

FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#import <FirebaseRemoteConfig/FIRRemoteConfig.h>
1818

1919
#import <FirebaseAnalyticsInterop/FIRAnalyticsInterop.h>
20+
#import <FirebaseRemoteConfig/RCNConfigFetch.h>
2021
#import <FirebaseRemoteConfig/RCNConfigSettings.h>
2122

2223
@class FIROptions;
@@ -34,6 +35,9 @@ NS_ASSUME_NONNULL_BEGIN
3435
/// Internal settings
3536
@property(nonatomic, readonly, strong) RCNConfigSettings *settings;
3637

38+
/// Config settings are custom settings.
39+
@property(nonatomic, readwrite, strong, nonnull) RCNConfigFetch *configFetch;
40+
3741
/// Returns the FIRRemoteConfig instance for your namespace and for the default Firebase App.
3842
/// This singleton object contains the complete set of Remote Config parameter values available to
3943
/// the app, including the Active Config and Default Config.. This object also caches values fetched

FirebaseRemoteConfig/Sources/RCNConfigFetch.h renamed to FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,6 @@ NS_ASSUME_NONNULL_BEGIN
3030
/// Completion handler invoked by NSSessionFetcher.
3131
typedef void (^RCNConfigFetcherCompletion)(NSData *data, NSURLResponse *response, NSError *error);
3232

33-
/// Test block used for global NSSessionFetcher.
34-
typedef void (^RCNConfigFetcherTestBlock)(RCNConfigFetcherCompletion completion);
35-
3633
@interface RCNConfigFetch : NSObject
3734

3835
- (instancetype)init NS_UNAVAILABLE;
@@ -56,8 +53,8 @@ typedef void (^RCNConfigFetcherTestBlock)(RCNConfigFetcherCompletion completion)
5653
/// Add the ability to update NSURLSession's timeout after a session has already been created.
5754
- (void)recreateNetworkSession;
5855

59-
/// Sets the test block to mock the fetch response instead of performing the fetch task from server.
60-
+ (void)setGlobalTestBlock:(RCNConfigFetcherTestBlock)block;
56+
/// Provide fetchSession for tests to override.
57+
@property(nonatomic, readwrite, strong, nonnull) NSURLSession *fetchSession;
6158

6259
NS_ASSUME_NONNULL_END
6360

FirebaseRemoteConfig/Sources/RCNFetch.m

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
#import "FirebaseRemoteConfig/Sources/RCNConfigFetch.h"
17+
#import "FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h"
1818

1919
#import <FirebaseCore/FIRApp.h>
2020
#import <FirebaseCore/FIRLogger.h>
@@ -66,8 +66,6 @@
6666
// Deprecated error code previously from FirebaseCore
6767
static const NSInteger FIRErrorCodeConfigFailed = -114;
6868

69-
static RCNConfigFetcherTestBlock gGlobalTestBlock;
70-
7169
#pragma mark - RCNConfig
7270

7371
@implementation RCNConfigFetch {
@@ -271,13 +269,7 @@ - (void)refreshInstallationsTokenWithCompletionHandler:
271269

272270
FIRLogInfo(kFIRLoggerRemoteConfig, @"I-RCN000022", @"Success to get iid : %@.",
273271
strongSelfQueue->_settings.configInstallationsIdentifier);
274-
[strongSelf
275-
getAnalyticsUserPropertiesWithCompletionHandler:^(NSDictionary *userProperties) {
276-
dispatch_async(strongSelf->_lockQueue, ^{
277-
[strongSelf fetchWithUserProperties:userProperties
278-
completionHandler:completionHandler];
279-
});
280-
}];
272+
[strongSelf doFetchCall:completionHandler];
281273
});
282274
}];
283275
};
@@ -286,6 +278,14 @@ - (void)refreshInstallationsTokenWithCompletionHandler:
286278
[installations authTokenWithCompletion:installationsTokenHandler];
287279
}
288280

281+
- (void)doFetchCall:(FIRRemoteConfigFetchCompletion)completionHandler {
282+
[self getAnalyticsUserPropertiesWithCompletionHandler:^(NSDictionary *userProperties) {
283+
dispatch_async(self->_lockQueue, ^{
284+
[self fetchWithUserProperties:userProperties completionHandler:completionHandler];
285+
});
286+
}];
287+
}
288+
289289
- (void)getAnalyticsUserPropertiesWithCompletionHandler:
290290
(FIRAInteropUserPropertiesCallback)completionHandler {
291291
FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000060", @"Fetch with user properties completed.");
@@ -489,23 +489,13 @@ - (void)fetchWithUserProperties:(NSDictionary *)userProperties
489489
});
490490
};
491491

492-
if (gGlobalTestBlock) {
493-
gGlobalTestBlock(fetcherCompletion);
494-
return;
495-
}
496492
FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000061", @"Making remote config fetch.");
497493

498494
NSURLSessionDataTask *dataTask = [self URLSessionDataTaskWithContent:compressedContent
499495
completionHandler:fetcherCompletion];
500496
[dataTask resume];
501497
}
502498

503-
+ (void)setGlobalTestBlock:(RCNConfigFetcherTestBlock)block {
504-
FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000027",
505-
@"Set global test block for NSSessionFetcher, it will not fetch from server.");
506-
gGlobalTestBlock = [block copy];
507-
}
508-
509499
- (NSString *)constructServerURL {
510500
NSString *serverURLStr = [[NSString alloc] initWithString:kServerURLDomain];
511501
serverURLStr = [serverURLStr stringByAppendingString:kServerURLVersion];
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2020 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import FirebaseCore
16+
@testable import FirebaseRemoteConfig
17+
18+
import XCTest
19+
20+
class FakeConsoleTests: APITestBase {
21+
override func setUp() {
22+
super.setUp()
23+
fakeConsole.config = ["Key1": "Value1"]
24+
}
25+
26+
// Contrast with testUnchangedActivateWillError in APITests.swift.
27+
func testChangedActivateWillNotError() {
28+
let expectation = self.expectation(description: #function)
29+
config.fetch { status, error in
30+
if let error = error {
31+
XCTFail("Fetch Error \(error)")
32+
}
33+
XCTAssertEqual(status, RemoteConfigFetchStatus.success)
34+
self.config.activate { error in
35+
if let error = error {
36+
print("Activate Error \(error)")
37+
}
38+
XCTAssertEqual(self.config["Key1"].stringValue, "Value1")
39+
expectation.fulfill()
40+
}
41+
}
42+
waitForExpectations()
43+
44+
// Simulate updating console.
45+
fakeConsole.config = ["Key1": "Value2"]
46+
47+
let expectation2 = self.expectation(description: #function + "2")
48+
config.fetch { status, error in
49+
if let error = error {
50+
XCTFail("Fetch Error \(error)")
51+
}
52+
XCTAssertEqual(status, RemoteConfigFetchStatus.success)
53+
self.config.activate { error in
54+
XCTAssertNil(error)
55+
XCTAssertEqual(self.config["Key1"].stringValue, "Value2")
56+
expectation2.fulfill()
57+
}
58+
}
59+
waitForExpectations()
60+
}
61+
62+
private func waitForExpectations() {
63+
let kFIRStorageIntegrationTestTimeout = 10.0
64+
waitForExpectations(timeout: kFIRStorageIntegrationTestTimeout,
65+
handler: { (error) -> Void in
66+
if let error = error {
67+
print(error)
68+
}
69+
})
70+
}
71+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2020 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#import <FirebaseRemoteConfig/FIRRemoteConfig_Private.h>
16+
#import "FetchMocks.h"
17+
#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"

0 commit comments

Comments
 (0)