| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- /*
- * Copyright 2019 Google
- *
- * 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.
- */
- #import <OCMock/OCMock.h>
- #import <XCTest/XCTest.h>
- #import "FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h"
- #import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"
- #import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
- #import "FirebaseRemoteConfig/Tests/Unit/RCNTestUtilities.h"
- @interface RCNConfigSettings (ExposedTestCase)
- - (RCNConfigFetchRequest *)nextRequestWithUserProperties:(NSDictionary *)userProperties
- fetchedConfig:(NSDictionary *)fetchedConfig;
- - (void)updateInternalContentWithResponse:(RCNConfigFetchResponse *)response;
- - (void)updateConfigContentWithResponse:(RCNConfigFetchResponse *)response;
- - (void)updateFetchTimeWithSuccessFetch:(BOOL)isSuccessfulFetch;
- - (BOOL)hasCachedData;
- - (BOOL)isCachedDataFresh;
- @end
- @interface RCNConfigSettingsTest : XCTestCase {
- RCNConfigSettings *_mockSettings;
- }
- @end
- @implementation RCNConfigSettingsTest
- - (void)setUp {
- [super setUp];
- // Mock the read/write DB operations, which are not needed in these tests.
- _mockSettings = [[RCNConfigSettings alloc] initWithDatabaseManager:nil];
- }
- - (void)testCrashShouldNotHappenWithoutMainBundleID {
- id mockBundle = OCMPartialMock([NSBundle mainBundle]);
- OCMStub([NSBundle mainBundle]).andReturn(mockBundle);
- OCMStub([mockBundle bundleIdentifier]).andReturn(nil);
- _mockSettings =
- [[RCNConfigSettings alloc] initWithDatabaseManager:[[RCNConfigDBManager alloc] init]];
- [mockBundle stopMocking];
- }
- #ifdef FIX_OR_DELETE
- - (void)testUpdateInternalMetadata {
- RCNConfigFetchResponse *response = [[RCNConfigFetchResponse alloc] init];
- // Mock internal metadata array with all_packages prefix key
- response.internalMetadataArray = [RCNTestUtilities entryArrayWithKeyValuePair:@{
- [NSString stringWithFormat:@"%@:%@", RCNInternalMetadataAllPackagesPrefix,
- RCNHTTPConnectionTimeoutInMillisecondsKey] : @"50",
- [NSString stringWithFormat:@"%@:%@", RCNInternalMetadataAllPackagesPrefix,
- RCNHTTPReadTimeoutInMillisecondsKey] : @"2000000",
- [NSString stringWithFormat:@"%@:%@", RCNInternalMetadataAllPackagesPrefix,
- RCNThrottledSuccessFetchTimeIntervalInSecondsKey] : @"300",
- [NSString stringWithFormat:@"%@:%@", RCNInternalMetadataAllPackagesPrefix,
- RCNThrottledSuccessFetchCountKey] : @"-6",
- [NSString stringWithFormat:@"%@:%@", RCNInternalMetadataAllPackagesPrefix,
- RCNThrottledFailureFetchTimeIntervalInSecondsKey] : @"10000000",
- [NSString stringWithFormat:@"%@:%@", RCNInternalMetadataAllPackagesPrefix,
- RCNThrottledFailureFetchCountKey] : @"21",
- }];
- [_mockSettings updateInternalContentWithResponse:response];
- XCTAssertEqual(
- [_mockSettings internalMetadataValueForKey:RCNHTTPConnectionTimeoutInMillisecondsKey
- minValue:RCNHTTPConnectionTimeoutInMillisecondsMin
- maxValue:RCNHTTPConnectionTimeoutInMillisecondsMax
- defaultValue:RCNHTTPConnectionTimeoutInMillisecondsDefault],
- RCNHTTPConnectionTimeoutInMillisecondsMin,
- @"HTTP Connection Timeout must be within the range.");
- XCTAssertEqual(
- [_mockSettings internalMetadataValueForKey:RCNHTTPReadTimeoutInMillisecondsKey
- minValue:RCNHTTPReadTimeoutInMillisecondsMin
- maxValue:RCNHTTPReadTimeoutInMillisecondsMax
- defaultValue:RCNHTTPReadTimeoutInMillisecondsDefault],
- RCNHTTPReadTimeoutInMillisecondsMax, @"HTTP Read Timeout must be within the range");
- XCTAssertEqual(
- [_mockSettings
- internalMetadataValueForKey:RCNThrottledSuccessFetchTimeIntervalInSecondsKey
- minValue:RCNThrottledSuccessFetchTimeIntervalInSecondsMin
- maxValue:RCNThrottledSuccessFetchTimeIntervalInSecondsMax
- defaultValue:RCNThrottledSuccessFetchTimeIntervalInSecondsDefault],
- RCNThrottledSuccessFetchTimeIntervalInSecondsMin,
- @"Throttling success internal must be within the range");
- XCTAssertEqual([_mockSettings internalMetadataValueForKey:RCNThrottledSuccessFetchCountKey
- minValue:RCNThrottledSuccessFetchCountMin
- maxValue:RCNThrottledSuccessFetchCountMax
- defaultValue:RCNThrottledSuccessFetchCountDefault],
- RCNThrottledSuccessFetchCountMin);
- XCTAssertEqual(
- [_mockSettings
- internalMetadataValueForKey:RCNThrottledFailureFetchTimeIntervalInSecondsKey
- minValue:RCNThrottledFailureFetchTimeIntervalInSecondsMin
- maxValue:RCNThrottledFailureFetchTimeIntervalInSecondsMax
- defaultValue:RCNThrottledFailureFetchTimeIntervalInSecondsDefault],
- RCNThrottledFailureFetchTimeIntervalInSecondsMax);
- XCTAssertEqual([_mockSettings internalMetadataValueForKey:RCNThrottledFailureFetchCountKey
- minValue:RCNThrottledFailureFetchCountMin
- maxValue:RCNThrottledFailureFetchCountMax
- defaultValue:RCNThrottledFailureFetchCountDefault],
- RCNThrottledFailureFetchCountMax);
- // Mock internal metadata array with bundle_identifier prefix key.
- // bundle_identifier prefixed key should override all_packages prefix key
- NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
- response.internalMetadataArray = [RCNTestUtilities entryArrayWithKeyValuePair:@{
- [NSString stringWithFormat:@"%@:%@", bundleIdentifier,
- RCNHTTPConnectionTimeoutInMillisecondsKey] : @"70000",
- [NSString stringWithFormat:@"%@:%@", bundleIdentifier, RCNHTTPReadTimeoutInMillisecondsKey] :
- @"70000",
- [NSString stringWithFormat:@"%@:%@", bundleIdentifier,
- RCNThrottledSuccessFetchTimeIntervalInSecondsKey] : @"1800",
- [NSString stringWithFormat:@"%@:%@", bundleIdentifier, RCNThrottledSuccessFetchCountKey] :
- @"100",
- [NSString stringWithFormat:@"%@:%@", bundleIdentifier,
- RCNThrottledFailureFetchTimeIntervalInSecondsKey] : @"1800",
- [NSString stringWithFormat:@"%@:%@", bundleIdentifier, RCNThrottledFailureFetchCountKey] : @"0",
- }];
- [_mockSettings updateInternalContentWithResponse:response];
- XCTAssertEqual(
- [_mockSettings internalMetadataValueForKey:RCNHTTPConnectionTimeoutInMillisecondsKey
- minValue:RCNHTTPConnectionTimeoutInMillisecondsMin
- maxValue:RCNHTTPConnectionTimeoutInMillisecondsMax
- defaultValue:RCNHTTPConnectionTimeoutInMillisecondsDefault],
- 70000);
- XCTAssertEqual(
- [_mockSettings internalMetadataValueForKey:RCNHTTPReadTimeoutInMillisecondsKey
- minValue:RCNHTTPReadTimeoutInMillisecondsMin
- maxValue:RCNHTTPReadTimeoutInMillisecondsMax
- defaultValue:RCNHTTPReadTimeoutInMillisecondsDefault],
- 70000);
- XCTAssertEqual(
- [_mockSettings
- internalMetadataValueForKey:RCNThrottledSuccessFetchTimeIntervalInSecondsKey
- minValue:RCNThrottledSuccessFetchTimeIntervalInSecondsMin
- maxValue:RCNThrottledSuccessFetchTimeIntervalInSecondsMax
- defaultValue:RCNThrottledSuccessFetchTimeIntervalInSecondsDefault],
- 1800);
- XCTAssertEqual([_mockSettings internalMetadataValueForKey:RCNThrottledSuccessFetchCountKey
- minValue:RCNThrottledSuccessFetchCountMin
- maxValue:RCNThrottledSuccessFetchCountMax
- defaultValue:RCNThrottledSuccessFetchCountDefault],
- 20);
- XCTAssertEqual(
- [_mockSettings
- internalMetadataValueForKey:RCNThrottledFailureFetchTimeIntervalInSecondsKey
- minValue:RCNThrottledFailureFetchTimeIntervalInSecondsMin
- maxValue:RCNThrottledFailureFetchTimeIntervalInSecondsMax
- defaultValue:RCNThrottledFailureFetchTimeIntervalInSecondsDefault],
- 1800);
- XCTAssertEqual([_mockSettings internalMetadataValueForKey:RCNThrottledFailureFetchCountKey
- minValue:RCNThrottledFailureFetchCountMin
- maxValue:RCNThrottledFailureFetchCountMax
- defaultValue:RCNThrottledFailureFetchCountDefault],
- 1);
- }
- - (void)testInternalMetadataOverride {
- // Mock response after fetching.
- RCNConfigFetchResponse *response = [[RCNConfigFetchResponse alloc] init];
- NSString *onePackageKey =
- [NSString stringWithFormat:@"%@:%@", [[NSBundle mainBundle] bundleIdentifier],
- RCNThrottledSuccessFetchCountKey];
- NSString *allPackageKey =
- [NSString stringWithFormat:@"%@:%@", RCNInternalMetadataAllPackagesPrefix,
- RCNThrottledSuccessFetchCountKey];
- [_mockSettings updateInternalContentWithResponse:response];
- XCTAssertEqual([_mockSettings internalMetadataValueForKey:RCNThrottledSuccessFetchCountKey
- minValue:RCNThrottledSuccessFetchCountMin
- maxValue:RCNThrottledSuccessFetchCountMax
- defaultValue:RCNThrottledSuccessFetchCountDefault],
- RCNThrottledSuccessFetchCountDefault,
- @"Fetch with no internal metadata, must return default value.");
- response.internalMetadataArray =
- [RCNTestUtilities entryArrayWithKeyValuePair:@{onePackageKey : @"8", allPackageKey : @"9"}];
- [_mockSettings updateInternalContentWithResponse:response];
- XCTAssertEqual([_mockSettings internalMetadataValueForKey:RCNThrottledSuccessFetchCountKey
- minValue:RCNThrottledSuccessFetchCountMin
- maxValue:RCNThrottledSuccessFetchCountMax
- defaultValue:RCNThrottledSuccessFetchCountDefault],
- 8, @"Fetch with both keys, must return the one with package key.");
- [response.internalMetadataArray removeAllObjects];
- [_mockSettings updateInternalContentWithResponse:response];
- XCTAssertEqual(
- [_mockSettings internalMetadataValueForKey:RCNThrottledSuccessFetchCountKey
- minValue:RCNThrottledSuccessFetchCountMin
- maxValue:RCNThrottledSuccessFetchCountMax
- defaultValue:RCNThrottledSuccessFetchCountDefault],
- 9, @"Fetch with no internal metadata, must return the one with previous all_packages key.");
- [response.internalMetadataArray removeAllObjects];
- response.internalMetadataArray = [RCNTestUtilities entryArrayWithKeyValuePair:@{
- onePackageKey : @"6",
- }];
- [_mockSettings updateInternalContentWithResponse:response];
- XCTAssertEqual([_mockSettings internalMetadataValueForKey:RCNThrottledSuccessFetchCountKey
- minValue:RCNThrottledSuccessFetchCountMin
- maxValue:RCNThrottledSuccessFetchCountMax
- defaultValue:RCNThrottledSuccessFetchCountDefault],
- 6, @"Fetch with one package key, must return the one with package key.");
- }
- - (void)testThrottlingFresh {
- NSTimeInterval endTimestamp = [_mockSettings cachedDataThrottledEndTimestamp];
- NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
- XCTAssertTrue(endTimestamp <= now);
- // Fetch failed once.
- [_mockSettings updateFetchTimeWithSuccessFetch:NO];
- endTimestamp = [_mockSettings cachedDataThrottledEndTimestamp];
- now = [[NSDate date] timeIntervalSince1970];
- XCTAssertTrue(endTimestamp <= now);
- // Fetch succeeded once.
- [_mockSettings updateFetchTimeWithSuccessFetch:YES];
- endTimestamp = [_mockSettings cachedDataThrottledEndTimestamp];
- now = [[NSDate date] timeIntervalSince1970];
- XCTAssertTrue(endTimestamp <= now);
- // The failure fetch rate is 5. Try another 3 times, and do not go over the limit.
- for (int i = 0; i < 3; i++) {
- [_mockSettings updateFetchTimeWithSuccessFetch:NO];
- }
- endTimestamp = [_mockSettings cachedDataThrottledEndTimestamp];
- now = [[NSDate date] timeIntervalSince1970];
- XCTAssertTrue(endTimestamp <= now);
- // The success fetch rate is 5. Try another 4 times, which should go over the limit afterwards.
- for (int i = 0; i < 4; i++) {
- [_mockSettings updateFetchTimeWithSuccessFetch:YES];
- }
- endTimestamp = [_mockSettings cachedDataThrottledEndTimestamp];
- now = [[NSDate date] timeIntervalSince1970];
- // Now it should go over the limit.
- XCTAssertFalse(endTimestamp <= now);
- XCTAssertTrue([_mockSettings hasCachedData]);
- }
- #endif
- - (void)testResetDigestInNextRequest {
- NSDictionary *digestPerNamespace = @{@"firebase" : @"1234", @"p4" : @"5678"};
- [_mockSettings setNamespaceToDigest:digestPerNamespace];
- RCNNamedValue *firebaseDigest = [[RCNNamedValue alloc] init];
- firebaseDigest.name = @"firebase";
- firebaseDigest.value = @"1234";
- RCNNamedValue *p4Digest = [[RCNNamedValue alloc] init];
- p4Digest.name = @"p4";
- p4Digest.value = @"5678";
- // Test where each namespace's fetched config is a non-empty dictionary, request should include
- // the namespace's digest.
- NSDictionary *fetchedConfig =
- @{@"firebase" : @{@"a" : @"b", @"c" : @"d"}, @"p4" : @{@"p4key" : @"p4value"}};
- RCNConfigFetchRequest *request = [_mockSettings nextRequestWithUserProperties:nil
- fetchedConfig:fetchedConfig];
- XCTAssertEqual(request.packageDataArray.count, 1);
- NSArray *expectedArray = @[ firebaseDigest, p4Digest ];
- XCTAssertEqualObjects(request.packageDataArray[0].namespaceDigestArray, expectedArray);
- // Test when the namespace's fetched config doesn't exist, reset the digest by not included
- // in the request.
- fetchedConfig = @{@"firebase" : @{@"a" : @"b", @"c" : @"d"}};
- request = [_mockSettings nextRequestWithUserProperties:nil fetchedConfig:fetchedConfig];
- XCTAssertEqual(request.packageDataArray.count, 1);
- XCTAssertEqualObjects(request.packageDataArray[0].namespaceDigestArray, @[ firebaseDigest ]);
- // Test when a namespace's fetched config is empty, reset the digest.
- fetchedConfig = @{@"firebase" : @{@"a" : @"b", @"c" : @"d"}, @"p4" : @{}};
- request = [_mockSettings nextRequestWithUserProperties:nil fetchedConfig:fetchedConfig];
- XCTAssertEqual(request.packageDataArray.count, 1);
- XCTAssertEqualObjects(request.packageDataArray[0].namespaceDigestArray, @[ firebaseDigest ]);
- // Test when a namespace's fetched config is a invalid format (non-dictionary), reset the digest.
- fetchedConfig = @{@"firebase" : @{@"a" : @"b", @"c" : @"d"}, @"p4" : @[]};
- request = [_mockSettings nextRequestWithUserProperties:nil fetchedConfig:fetchedConfig];
- XCTAssertEqual(request.packageDataArray.count, 1);
- XCTAssertEqualObjects(request.packageDataArray[0].namespaceDigestArray, @[ firebaseDigest ]);
- // Test when a namespace's fetched config is a invalid format (non-dictionary), reset the digest.
- fetchedConfig = @{@"firebase" : @{@"a" : @"b", @"c" : @"d"}, @"p4" : @"wrong format of config"};
- request = [_mockSettings nextRequestWithUserProperties:nil fetchedConfig:fetchedConfig];
- XCTAssertEqual(request.packageDataArray.count, 1);
- XCTAssertEqualObjects(request.packageDataArray[0].namespaceDigestArray, @[ firebaseDigest ]);
- }
- @end
|