| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998 |
- /*
- * 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/OCMStubRecorder.h>
- #import <OCMock/OCMock.h>
- #import <XCTest/XCTest.h>
- #import "FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.h"
- #import "FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h"
- #import "FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h"
- #import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h"
- #import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"
- #import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
- #import "FirebaseRemoteConfig/Sources/RCNConfigExperiment.h"
- #import "FirebaseRemoteConfig/Sources/RCNConfigRealtime.h"
- #import "FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.h"
- #import "FirebaseRemoteConfig/Tests/Unit/RCNTestUtilities.h"
- #import <GoogleUtilities/GULNSData+zlib.h>
- #import "FirebaseCore/Extension/FirebaseCoreInternal.h"
- @import FirebaseRemoteConfigInterop;
- @protocol FIRRolloutsStateSubscriber;
- @interface RCNConfigFetch (ForTest)
- - (instancetype)initWithContent:(RCNConfigContent *)content
- DBManager:(RCNConfigDBManager *)DBManager
- settings:(RCNConfigSettings *)settings
- experiment:(RCNConfigExperiment *)experiment
- queue:(dispatch_queue_t)queue
- namespace:firebaseNamespace
- app:firebaseApp;
- /// Skip fetching user properties from analytics because we cannot mock the action here. Instead
- /// overriding the method to skip.
- - (void)fetchWithUserPropertiesCompletionHandler:(NSString *)fetchTypeHeader
- completionHandler:(FIRAInteropUserPropertiesCallback)block;
- - (NSURLSessionDataTask *)URLSessionDataTaskWithContent:(NSData *)content
- fetchTypeHeader:(NSString *)fetchTypeHeader
- completionHandler:
- (RCNConfigFetcherCompletion)fetcherCompletion;
- - (void)fetchConfigWithExpirationDuration:(NSTimeInterval)expirationDuration
- completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler;
- - (void)realtimeFetchConfigWithNoExpirationDuration:(NSInteger)fetchAttemptNumber
- completionHandler:(RCNConfigFetchCompletion)completionHandler;
- - (void)fetchWithUserProperties:(NSDictionary *)userProperties
- fetchTypeHeader:(NSString *)fetchTypeHeader
- completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler
- updateCompletionHandler:(RCNConfigFetchCompletion)updateCompletionHandler;
- - (NSString *)constructServerURL;
- - (NSURLSession *)currentNetworkSession;
- @end
- @interface RCNConfigRealtime (ForTest)
- - (instancetype _Nonnull)init:(RCNConfigFetch *_Nonnull)configFetch
- settings:(RCNConfigSettings *_Nonnull)settings
- namespace:(NSString *_Nonnull)namespace
- options:(FIROptions *_Nonnull)options;
- - (void)fetchLatestConfig:(NSInteger)remainingAttempts targetVersion:(NSInteger)targetVersion;
- - (void)scheduleFetch:(NSInteger)remainingAttempts targetVersion:(NSInteger)targetVersion;
- - (void)autoFetch:(NSInteger)remainingAttempts targetVersion:(NSInteger)targetVersion;
- - (void)beginRealtimeStream;
- - (void)pauseRealtimeStream;
- - (void)createRequestBodyWithCompletion:(void (^)(NSData *_Nonnull requestBody))completion;
- - (FIRConfigUpdateListenerRegistration *_Nonnull)addConfigUpdateListener:
- (RCNConfigUpdateCompletion _Nonnull)listener;
- - (void)removeConfigUpdateListener:(RCNConfigUpdateCompletion _Nonnull)listener;
- - (void)evaluateStreamResponse:(NSDictionary *)response error:(NSError *)dataError;
- @end
- @interface FIRRemoteConfig (ForTest)
- - (void)updateWithNewInstancesForConfigFetch:(RCNConfigFetch *)configFetch
- configContent:(RCNConfigContent *)configContent
- configSettings:(RCNConfigSettings *)configSettings
- configExperiment:(RCNConfigExperiment *)configExperiment;
- - (void)updateWithNewInstancesForConfigRealtime:(RCNConfigRealtime *)configRealtime;
- @end
- @implementation FIRRemoteConfig (ForTest)
- - (void)updateWithNewInstancesForConfigFetch:(RCNConfigFetch *)configFetch
- configContent:(RCNConfigContent *)configContent
- configSettings:(RCNConfigSettings *)configSettings
- configExperiment:(RCNConfigExperiment *)configExperiment {
- [self setValue:configFetch forKey:@"_configFetch"];
- [self setValue:configContent forKey:@"_configContent"];
- [self setValue:configSettings forKey:@"_settings"];
- [self setValue:configExperiment forKey:@"_configExperiment"];
- }
- - (void)updateWithNewInstancesForConfigRealtime:(RCNConfigRealtime *)configRealtime {
- [self setValue:configRealtime forKey:@"_configRealtime"];
- }
- @end
- @interface RCNConfigDBManager (Test)
- - (void)removeDatabaseOnDatabaseQueueAtPath:(NSString *)path;
- @end
- @interface RCNUserDefaultsManager (Test)
- + (NSUserDefaults *)sharedUserDefaultsForBundleIdentifier:(NSString *)bundleIdentifier;
- @end
- @interface RCNConfigSettings (Test)
- - (NSString *)nextRequestWithUserProperties:(NSDictionary *)userProperties;
- @end
- typedef NS_ENUM(NSInteger, RCNTestRCInstance) {
- RCNTestRCInstanceDefault,
- RCNTestRCInstanceSecondNamespace,
- RCNTestRCInstanceSecondApp,
- RCNTestRCNumTotalInstances
- };
- @interface RCNRemoteConfigTest : XCTestCase {
- NSTimeInterval _expectationTimeout;
- NSTimeInterval _checkCompletionTimeout;
- NSMutableArray<FIRRemoteConfig *> *_configInstances;
- NSMutableArray<NSDictionary<NSString *, NSString *> *> *_entries;
- NSArray<NSDictionary *> *_rolloutMetadata;
- NSMutableArray<NSDictionary<NSString *, id> *> *_response;
- NSMutableArray<NSData *> *_responseData;
- NSMutableArray<NSURLResponse *> *_URLResponse;
- NSMutableArray<id> *_configFetch;
- NSMutableArray<id> *_configRealtime;
- RCNConfigDBManager *_DBManager;
- NSUserDefaults *_userDefaults;
- NSString *_userDefaultsSuiteName;
- NSString *_DBPath;
- id _DBManagerMock;
- id _experimentMock;
- id _userDefaultsMock;
- NSString *_fullyQualifiedNamespace;
- RCNConfigSettings *_settings;
- dispatch_queue_t _queue;
- NSString *_namespaceGoogleMobilePlatform;
- }
- @end
- @implementation RCNRemoteConfigTest
- - (void)setUp {
- [super setUp];
- FIRSetLoggerLevel(FIRLoggerLevelMax);
- _expectationTimeout = 5;
- _checkCompletionTimeout = 1.0;
- // Always remove the database at the start of testing.
- _DBPath = [RCNTestUtilities remoteConfigPathForTestDatabase];
- _DBManagerMock = OCMClassMock([RCNConfigDBManager class]);
- OCMStub([_DBManagerMock remoteConfigPathForDatabase]).andReturn(_DBPath);
- _DBManager = [[RCNConfigDBManager alloc] init];
- _userDefaultsSuiteName = [RCNTestUtilities userDefaultsSuiteNameForTestSuite];
- _userDefaults = [[NSUserDefaults alloc] initWithSuiteName:_userDefaultsSuiteName];
- _userDefaultsMock = OCMClassMock([RCNUserDefaultsManager class]);
- OCMStub([_userDefaultsMock sharedUserDefaultsForBundleIdentifier:[OCMArg any]])
- .andReturn(_userDefaults);
- _experimentMock = OCMClassMock([RCNConfigExperiment class]);
- OCMStub([_experimentMock
- updateExperimentsWithHandler:([OCMArg invokeBlockWithArgs:[NSNull null], nil])]);
- RCNConfigContent *configContent = [[RCNConfigContent alloc] initWithDBManager:_DBManager];
- _configInstances = [[NSMutableArray alloc] initWithCapacity:3];
- _entries = [[NSMutableArray alloc] initWithCapacity:3];
- _response = [[NSMutableArray alloc] initWithCapacity:3];
- _responseData = [[NSMutableArray alloc] initWithCapacity:3];
- _URLResponse = [[NSMutableArray alloc] initWithCapacity:3];
- _configFetch = [[NSMutableArray alloc] initWithCapacity:3];
- _configRealtime = [[NSMutableArray alloc] initWithCapacity:3];
- _namespaceGoogleMobilePlatform = FIRRemoteConfigConstants.FIRNamespaceGoogleMobilePlatform;
- // Populate the default, second app, second namespace instances.
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- // Fake a response for default instance.
- NSMutableDictionary<NSString *, NSString *> *valuesDict = [[NSMutableDictionary alloc] init];
- for (int count = 1; count <= 100; count++) {
- NSString *key = [NSString stringWithFormat:@"key%d-%d", count, i];
- NSString *value = [NSString stringWithFormat:@"value%d-%d", count, i];
- valuesDict[key] = value;
- }
- _entries[i] = valuesDict;
- NSString *currentAppName = nil;
- FIROptions *currentOptions = nil;
- NSString *currentNamespace = nil;
- switch (i) {
- case RCNTestRCInstanceSecondNamespace:
- currentAppName = RCNTestsDefaultFIRAppName;
- currentOptions = [self firstAppOptions];
- currentNamespace = RCNTestsPerfNamespace;
- break;
- case RCNTestRCInstanceSecondApp:
- currentAppName = RCNTestsSecondFIRAppName;
- currentOptions = [self secondAppOptions];
- currentNamespace = _namespaceGoogleMobilePlatform;
- break;
- case RCNTestRCInstanceDefault:
- default:
- currentAppName = RCNTestsDefaultFIRAppName;
- currentOptions = [self firstAppOptions];
- currentNamespace = RCNTestsFIRNamespace;
- break;
- }
- _fullyQualifiedNamespace =
- [NSString stringWithFormat:@"%@:%@", currentNamespace, currentAppName];
- FIRRemoteConfig *config =
- OCMPartialMock([[FIRRemoteConfig alloc] initWithAppName:currentAppName
- FIROptions:currentOptions
- namespace:currentNamespace
- DBManager:_DBManager
- configContent:configContent
- analytics:nil]);
- _configInstances[i] = config;
- _settings = [[RCNConfigSettings alloc] initWithDatabaseManager:_DBManager
- namespace:_fullyQualifiedNamespace
- firebaseAppName:currentAppName
- googleAppID:currentOptions.googleAppID];
- _queue = dispatch_queue_create(
- [[NSString stringWithFormat:@"testqueue: %d", i] cStringUsingEncoding:NSUTF8StringEncoding],
- DISPATCH_QUEUE_SERIAL);
- _configFetch[i] =
- OCMPartialMock([[RCNConfigFetch alloc] initWithContent:configContent
- DBManager:_DBManager
- settings:_settings
- analytics:nil
- experiment:_experimentMock
- queue:_queue
- namespace:_fullyQualifiedNamespace
- options:currentOptions]);
- _configRealtime[i] = OCMPartialMock([[RCNConfigRealtime alloc] init:_configFetch[i]
- settings:_settings
- namespace:_fullyQualifiedNamespace
- options:currentOptions]);
- _settings.configInstallationsIdentifier = @"iid";
- OCMStubRecorder *mock = OCMStub([_configFetch[i] fetchConfigWithExpirationDuration:0
- completionHandler:OCMOCK_ANY]);
- mock = [mock ignoringNonObjectArgs];
- mock.andDo(^(NSInvocation *invocation) {
- __unsafe_unretained void (^handler)(FIRRemoteConfigFetchStatus status,
- NSError *_Nullable error) = nil;
- [invocation getArgument:&handler atIndex:3];
- [self->_configFetch[i] fetchWithUserProperties:[[NSDictionary alloc] init]
- fetchTypeHeader:@"Base/1"
- completionHandler:handler
- updateCompletionHandler:nil];
- });
- _rolloutMetadata = @[ @{
- RCNFetchResponseKeyRolloutID : @"1",
- RCNFetchResponseKeyVariantID : @"0",
- RCNFetchResponseKeyAffectedParameterKeys : @[ _entries[i].allKeys[0] ]
- } ];
- _response[i] = @{
- @"state" : @"UPDATE",
- @"entries" : _entries[i],
- RCNFetchResponseKeyRolloutMetadata : _rolloutMetadata
- };
- _responseData[i] = [NSJSONSerialization dataWithJSONObject:_response[i] options:0 error:nil];
- _URLResponse[i] = [[NSHTTPURLResponse alloc]
- initWithURL:[NSURL URLWithString:@"https://firebase.com"]
- statusCode:200
- HTTPVersion:nil
- headerFields:@{@"etag" : [NSString stringWithFormat:@"etag1-%d", i]}];
- id completionBlock =
- [OCMArg invokeBlockWithArgs:_responseData[i], _URLResponse[i], [NSNull null], nil];
- OCMStub([_configFetch[i] URLSessionDataTaskWithContent:[OCMArg any]
- fetchTypeHeader:[OCMArg any]
- completionHandler:completionBlock])
- .andReturn(nil);
- [_configInstances[i] updateWithNewInstancesForConfigFetch:_configFetch[i]
- configContent:configContent
- configSettings:_settings
- configExperiment:_experimentMock];
- [_configInstances[i] updateWithNewInstancesForConfigRealtime:_configRealtime[i]];
- }
- }
- - (void)tearDown {
- [_DBManager removeDatabaseOnDatabaseQueueAtPath:_DBPath];
- [FIRRemoteConfigComponent clearAllComponentInstances];
- [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:_userDefaultsSuiteName];
- [_DBManagerMock stopMocking];
- _DBManagerMock = nil;
- [_userDefaultsMock stopMocking];
- _userDefaultsMock = nil;
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- [(id)_configInstances[i] stopMocking];
- [(id)_configFetch[i] stopMocking];
- }
- [_configInstances removeAllObjects];
- [_configFetch removeAllObjects];
- [_configRealtime removeAllObjects];
- _configInstances = nil;
- _configFetch = nil;
- [super tearDown];
- }
- - (void)testFetchConfigWithNilCallback {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString stringWithFormat:@"Set defaults no callback expectation - instance %d", i]];
- XCTAssertEqual(_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusNoFetchYet);
- [_configInstances[i] fetchWithExpirationDuration:43200 completionHandler:nil];
- dispatch_after(
- dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_checkCompletionTimeout * NSEC_PER_SEC)),
- dispatch_get_main_queue(), ^{
- XCTAssertEqual(self->_configInstances[i].lastFetchStatus,
- FIRRemoteConfigFetchStatusSuccess);
- [expectations[i] fulfill];
- });
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- - (void)testFetchConfigsSuccessfully {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] =
- [self expectationWithDescription:
- [NSString stringWithFormat:@"Test fetch configs successfully - instance %d", i]];
- XCTAssertEqual(_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusNoFetchYet);
- FIRRemoteConfigFetchCompletion fetchCompletion = ^void(FIRRemoteConfigFetchStatus status,
- NSError *error) {
- XCTAssertEqual(self->_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusSuccess);
- XCTAssertNil(error);
- [self->_configInstances[i] activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
- XCTAssertTrue(changed);
- NSString *key1 = [NSString stringWithFormat:@"key1-%d", i];
- NSString *key2 = [NSString stringWithFormat:@"key2-%d", i];
- NSString *value1 = [NSString stringWithFormat:@"value1-%d", i];
- NSString *value2 = [NSString stringWithFormat:@"value2-%d", i];
- XCTAssertEqualObjects(self->_configInstances[i][key1].stringValue, value1);
- XCTAssertEqualObjects(self->_configInstances[i][key2].stringValue, value2);
- OCMVerify([self->_configInstances[i] objectForKeyedSubscript:key1]);
- XCTAssertEqual(status, FIRRemoteConfigFetchStatusSuccess,
- @"Callback of first successful config "
- @"fetch. Status must equal to FIRRemoteConfigFetchStatusSuccessFresh.");
- XCTAssertNotNil(self->_configInstances[i].lastFetchTime);
- XCTAssertGreaterThan(self->_configInstances[i].lastFetchTime.timeIntervalSince1970, 0,
- @"last fetch time interval should be set.");
- [expectations[i] fulfill];
- }];
- };
- [_configInstances[i] fetchWithExpirationDuration:43200 completionHandler:fetchCompletion];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- - (void)testFetchAndActivate {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] =
- [self expectationWithDescription:
- [NSString stringWithFormat:@"Test fetch configs successfully - instance %d", i]];
- XCTAssertEqual(_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusNoFetchYet);
- FIRRemoteConfigFetchAndActivateCompletion fetchAndActivateCompletion = ^void(
- FIRRemoteConfigFetchAndActivateStatus status, NSError *error) {
- XCTAssertEqual(self->_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusSuccess);
- XCTAssertNil(error);
- NSString *key1 = [NSString stringWithFormat:@"key1-%d", i];
- NSString *key2 = [NSString stringWithFormat:@"key2-%d", i];
- NSString *value1 = [NSString stringWithFormat:@"value1-%d", i];
- NSString *value2 = [NSString stringWithFormat:@"value2-%d", i];
- XCTAssertEqualObjects(self->_configInstances[i][key1].stringValue, value1);
- XCTAssertEqualObjects(self->_configInstances[i][key2].stringValue, value2);
- OCMVerify([self->_configInstances[i] objectForKeyedSubscript:key1]);
- XCTAssertEqual(
- status, FIRRemoteConfigFetchAndActivateStatusSuccessFetchedFromRemote,
- @"Callback of first successful config "
- @"fetchAndActivate status must equal to FIRRemoteConfigFetchAndStatusSuccessFromRemote.");
- XCTAssertNotNil(self->_configInstances[i].lastFetchTime);
- XCTAssertGreaterThan(self->_configInstances[i].lastFetchTime.timeIntervalSince1970, 0,
- @"last fetch time interval should be set.");
- [expectations[i] fulfill];
- };
- // Update the minimum fetch interval to 0. This disables the cache and forces a remote fetch
- // request.
- FIRRemoteConfigSettings *settings = [[FIRRemoteConfigSettings alloc] init];
- settings.minimumFetchInterval = 0;
- [_configInstances[i] setConfigSettings:settings];
- [_configInstances[i] fetchAndActivateWithCompletionHandler:fetchAndActivateCompletion];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- // TODO: Try splitting into smaller tests.
- - (void)testFetchConfigsSuccessfullyWithNewActivateMethodSignature {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] =
- [self expectationWithDescription:
- [NSString stringWithFormat:@"Test fetch configs successfully - instance %d", i]];
- XCTAssertEqual(_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusNoFetchYet);
- FIRRemoteConfigFetchCompletion fetchCompletion = ^(FIRRemoteConfigFetchStatus status,
- NSError *error) {
- XCTAssertEqual(self->_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusSuccess);
- XCTAssertNil(error);
- [self->_configInstances[i] activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
- XCTAssertTrue(changed);
- XCTAssertNil(error);
- NSString *key1 = [NSString stringWithFormat:@"key1-%d", i];
- NSString *key2 = [NSString stringWithFormat:@"key2-%d", i];
- NSString *value1 = [NSString stringWithFormat:@"value1-%d", i];
- NSString *value2 = [NSString stringWithFormat:@"value2-%d", i];
- XCTAssertEqualObjects(self->_configInstances[i][key1].stringValue, value1);
- XCTAssertEqualObjects(self->_configInstances[i][key2].stringValue, value2);
- OCMVerify([self->_configInstances[i] objectForKeyedSubscript:key1]);
- XCTAssertEqual(status, FIRRemoteConfigFetchStatusSuccess,
- @"Callback of first successful config "
- @"fetch. Status must equal to FIRRemoteConfigFetchStatusSuccessFresh.");
- XCTAssertNotNil(self->_configInstances[i].lastFetchTime);
- XCTAssertGreaterThan(self->_configInstances[i].lastFetchTime.timeIntervalSince1970, 0,
- @"last fetch time interval should be set.");
- // A second activate should have no effect.
- [self->_configInstances[i]
- activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
- XCTAssertFalse(changed);
- XCTAssertNil(error);
- }];
- [expectations[i] fulfill];
- }];
- };
- [_configInstances[i] fetchWithExpirationDuration:43200 completionHandler:fetchCompletion];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- - (void)testEnumeratingConfigResults {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString stringWithFormat:@"Test enumerating configs successfully - instance %d", i]];
- XCTAssertEqual(_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusNoFetchYet);
- FIRRemoteConfigFetchCompletion fetchCompletion = ^void(FIRRemoteConfigFetchStatus status,
- NSError *error) {
- XCTAssertEqual(self->_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusSuccess);
- XCTAssertNil(error);
- [self->_configInstances[i] activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
- XCTAssertTrue(changed);
- NSString *key5 = [NSString stringWithFormat:@"key5-%d", i];
- NSString *key19 = [NSString stringWithFormat:@"key19-%d", i];
- NSString *value5 = [NSString stringWithFormat:@"value5-%d", i];
- NSString *value19 = [NSString stringWithFormat:@"value19-%d", i];
- XCTAssertEqualObjects(self->_configInstances[i][key5].stringValue, value5);
- XCTAssertEqualObjects(self->_configInstances[i][key19].stringValue, value19);
- // Test enumerating config values.
- for (NSString *key in self->_configInstances[i]) {
- if ([key isEqualToString:key5]) {
- XCTAssertEqualObjects(self->_configInstances[i][key5].stringValue, value5);
- }
- if ([key isEqualToString:key19]) {
- XCTAssertEqualObjects(self->_configInstances[i][key19].stringValue, value19);
- }
- }
- XCTAssertEqual(status, FIRRemoteConfigFetchStatusSuccess,
- @"Callback of first successful config "
- @"fetch. Status must equal to FIRRemoteConfigFetchStatusSuccessFresh.");
- XCTAssertNotNil(self->_configInstances[i].lastFetchTime);
- XCTAssertGreaterThan(self->_configInstances[i].lastFetchTime.timeIntervalSince1970, 0,
- @"last fetch time interval should be set.");
- [expectations[i] fulfill];
- }];
- };
- [_configInstances[i] fetchWithExpirationDuration:43200 completionHandler:fetchCompletion];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- - (void)testFetchAndActivate3pNamespaceUpdatesExperiments {
- [[_experimentMock expect] updateExperimentsWithResponse:[OCMArg any]];
- XCTestExpectation *expectation = [self
- expectationWithDescription:[NSString stringWithFormat:@"FetchAndActivate call for 'firebase' "
- @"namespace updates experiment data"]];
- XCTAssertEqual(_configInstances[RCNTestRCInstanceDefault].lastFetchStatus,
- FIRRemoteConfigFetchStatusNoFetchYet);
- FIRRemoteConfigFetchAndActivateCompletion fetchAndActivateCompletion =
- ^void(FIRRemoteConfigFetchAndActivateStatus status, NSError *error) {
- XCTAssertEqual(status, FIRRemoteConfigFetchAndActivateStatusSuccessFetchedFromRemote);
- XCTAssertNil(error);
- XCTAssertEqual(self->_configInstances[RCNTestRCInstanceDefault].lastFetchStatus,
- FIRRemoteConfigFetchStatusSuccess);
- XCTAssertNotNil(self->_configInstances[RCNTestRCInstanceDefault].lastFetchTime);
- XCTAssertGreaterThan(
- self->_configInstances[RCNTestRCInstanceDefault].lastFetchTime.timeIntervalSince1970, 0,
- @"last fetch time interval should be set.");
- [expectation fulfill];
- };
- [_configInstances[RCNTestRCInstanceDefault]
- fetchAndActivateWithCompletionHandler:fetchAndActivateCompletion];
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- - (void)testFetchAndActivateOtherNamespaceDoesntUpdateExperiments {
- [[_experimentMock reject] updateExperimentsWithResponse:[OCMArg any]];
- XCTestExpectation *expectation = [self
- expectationWithDescription:
- [NSString stringWithFormat:@"FetchAndActivate call for namespace other than 'firebase' "
- @"doesn't update experiment data"]];
- XCTAssertEqual(_configInstances[RCNTestRCInstanceSecondNamespace].lastFetchStatus,
- FIRRemoteConfigFetchStatusNoFetchYet);
- FIRRemoteConfigFetchAndActivateCompletion fetchAndActivateCompletion =
- ^void(FIRRemoteConfigFetchAndActivateStatus status, NSError *error) {
- XCTAssertEqual(status, FIRRemoteConfigFetchAndActivateStatusSuccessFetchedFromRemote);
- XCTAssertNil(error);
- XCTAssertEqual(self->_configInstances[RCNTestRCInstanceSecondNamespace].lastFetchStatus,
- FIRRemoteConfigFetchStatusSuccess);
- XCTAssertNotNil(self->_configInstances[RCNTestRCInstanceSecondNamespace].lastFetchTime);
- XCTAssertGreaterThan(self->_configInstances[RCNTestRCInstanceSecondNamespace]
- .lastFetchTime.timeIntervalSince1970,
- 0, @"last fetch time interval should be set.");
- [expectation fulfill];
- };
- [_configInstances[RCNTestRCInstanceSecondNamespace]
- fetchAndActivateWithCompletionHandler:fetchAndActivateCompletion];
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- - (void)testFetchConfigsFailed {
- // Override the setup values to return back an error status.
- RCNConfigContent *configContent = [[RCNConfigContent alloc] initWithDBManager:_DBManager];
- // Populate the default, second app, second namespace instances.
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- NSString *currentAppName = nil;
- FIROptions *currentOptions = nil;
- NSString *currentNamespace = nil;
- switch (i) {
- case RCNTestRCInstanceSecondNamespace:
- currentAppName = RCNTestsDefaultFIRAppName;
- currentOptions = [self firstAppOptions];
- currentNamespace = RCNTestsPerfNamespace;
- break;
- case RCNTestRCInstanceSecondApp:
- currentAppName = RCNTestsSecondFIRAppName;
- currentOptions = [self secondAppOptions];
- currentNamespace = _namespaceGoogleMobilePlatform;
- break;
- case RCNTestRCInstanceDefault:
- default:
- currentAppName = RCNTestsDefaultFIRAppName;
- currentOptions = [self firstAppOptions];
- currentNamespace = RCNTestsFIRNamespace;
- break;
- }
- RCNUserDefaultsManager *userDefaultsManager =
- [[RCNUserDefaultsManager alloc] initWithAppName:currentAppName
- bundleID:[NSBundle mainBundle].bundleIdentifier
- namespace:_fullyQualifiedNamespace];
- userDefaultsManager.lastFetchTime = 0;
- FIRRemoteConfig *config =
- OCMPartialMock([[FIRRemoteConfig alloc] initWithAppName:currentAppName
- FIROptions:currentOptions
- namespace:currentNamespace
- DBManager:_DBManager
- configContent:configContent
- analytics:nil]);
- _configInstances[i] = config;
- _configFetch[i] =
- OCMPartialMock([[RCNConfigFetch alloc] initWithContent:configContent
- DBManager:_DBManager
- settings:_settings
- analytics:nil
- experiment:nil
- queue:_queue
- namespace:_fullyQualifiedNamespace
- options:currentOptions]);
- _configRealtime[i] = OCMPartialMock([[RCNConfigRealtime alloc] init:_configFetch[i]
- settings:_settings
- namespace:_fullyQualifiedNamespace
- options:currentOptions]);
- OCMStub([_configFetch[i] fetchConfigWithExpirationDuration:43200 completionHandler:OCMOCK_ANY])
- .andDo(^(NSInvocation *invocation) {
- __unsafe_unretained void (^handler)(FIRRemoteConfigFetchStatus status,
- NSError *_Nullable error) = nil;
- [invocation getArgument:&handler atIndex:3];
- [self->_configFetch[i] fetchWithUserProperties:[[NSDictionary alloc] init]
- fetchTypeHeader:@"Base/1"
- completionHandler:handler
- updateCompletionHandler:nil];
- });
- _response[i] = @{};
- _responseData[i] = [NSJSONSerialization dataWithJSONObject:_response[i] options:0 error:nil];
- _URLResponse[i] =
- [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"https://firebase.com"]
- statusCode:500
- HTTPVersion:nil
- headerFields:@{@"etag" : @"etag1"}];
- [_configInstances[i] updateWithNewInstancesForConfigFetch:_configFetch[i]
- configContent:configContent
- configSettings:_settings
- configExperiment:nil];
- }
- // Make the fetch calls for all instances.
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString stringWithFormat:@"Test enumerating configs successfully - instance %d", i]];
- XCTAssertEqual(_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusNoFetchYet);
- FIRRemoteConfigFetchCompletion fetchCompletion = ^void(FIRRemoteConfigFetchStatus status,
- NSError *error) {
- XCTAssertEqual(self->_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusFailure);
- [self->_configInstances[i] activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
- XCTAssertFalse(changed);
- XCTAssertNil(error);
- FIRRemoteConfigValue *value = self->_configInstances[RCNTestRCInstanceDefault][@"key1"];
- XCTAssertEqual((int)value.source, (int)FIRRemoteConfigSourceStatic);
- XCTAssertEqualObjects(value.stringValue, @"");
- XCTAssertEqual(value.boolValue, NO);
- [expectations[i] fulfill];
- }];
- };
- [_configInstances[i] fetchWithExpirationDuration:43200 completionHandler:fetchCompletion];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- // TODO(mandard): Break up test with helper methods.
- - (void)testFetchConfigsFailedErrorNoNetwork {
- // Override the setup values to return back an error status.
- RCNConfigContent *configContent = [[RCNConfigContent alloc] initWithDBManager:_DBManager];
- // Populate the default, second app, second namespace instances.
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- NSString *currentAppName = nil;
- FIROptions *currentOptions = nil;
- NSString *currentNamespace = nil;
- switch (i) {
- case RCNTestRCInstanceSecondNamespace:
- currentAppName = RCNTestsDefaultFIRAppName;
- currentOptions = [self firstAppOptions];
- currentNamespace = RCNTestsPerfNamespace;
- break;
- case RCNTestRCInstanceSecondApp:
- currentAppName = RCNTestsSecondFIRAppName;
- currentOptions = [self secondAppOptions];
- currentNamespace = _namespaceGoogleMobilePlatform;
- break;
- case RCNTestRCInstanceDefault:
- default:
- currentAppName = RCNTestsDefaultFIRAppName;
- currentOptions = [self firstAppOptions];
- currentNamespace = RCNTestsFIRNamespace;
- break;
- }
- NSString *fullyQualifiedNamespace =
- [NSString stringWithFormat:@"%@:%@", currentNamespace, currentAppName];
- RCNUserDefaultsManager *userDefaultsManager =
- [[RCNUserDefaultsManager alloc] initWithAppName:currentAppName
- bundleID:[NSBundle mainBundle].bundleIdentifier
- namespace:fullyQualifiedNamespace];
- userDefaultsManager.lastFetchTime = 0;
- FIRRemoteConfig *config =
- OCMPartialMock([[FIRRemoteConfig alloc] initWithAppName:currentAppName
- FIROptions:currentOptions
- namespace:currentNamespace
- DBManager:_DBManager
- configContent:configContent
- analytics:nil]);
- _configInstances[i] = config;
- RCNConfigSettings *settings =
- [[RCNConfigSettings alloc] initWithDatabaseManager:_DBManager
- namespace:fullyQualifiedNamespace
- firebaseAppName:currentAppName
- googleAppID:currentOptions.googleAppID];
- dispatch_queue_t queue = dispatch_queue_create(
- [[NSString stringWithFormat:@"testqueue: %d", i] cStringUsingEncoding:NSUTF8StringEncoding],
- DISPATCH_QUEUE_SERIAL);
- _configFetch[i] = OCMPartialMock([[RCNConfigFetch alloc] initWithContent:configContent
- DBManager:_DBManager
- settings:settings
- analytics:nil
- experiment:nil
- queue:queue
- namespace:fullyQualifiedNamespace
- options:currentOptions]);
- _configRealtime[i] = OCMPartialMock([[RCNConfigRealtime alloc] init:_configFetch[i]
- settings:settings
- namespace:fullyQualifiedNamespace
- options:currentOptions]);
- OCMStub([_configFetch[i] fetchConfigWithExpirationDuration:43200 completionHandler:OCMOCK_ANY])
- .andDo(^(NSInvocation *invocation) {
- __unsafe_unretained void (^handler)(FIRRemoteConfigFetchStatus status,
- NSError *_Nullable error) = nil;
- [invocation getArgument:&handler atIndex:3];
- [self->_configFetch[i] fetchWithUserProperties:[[NSDictionary alloc] init]
- fetchTypeHeader:@"Base/1"
- completionHandler:handler
- updateCompletionHandler:nil];
- });
- _response[i] = @{};
- _responseData[i] = [NSJSONSerialization dataWithJSONObject:_response[i] options:0 error:nil];
- // A no network error is accompanied with an HTTP status code of 0.
- _URLResponse[i] =
- [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"https://firebase.com"]
- statusCode:0
- HTTPVersion:nil
- headerFields:@{@"etag" : @"etag1"}];
- [_configInstances[i] updateWithNewInstancesForConfigFetch:_configFetch[i]
- configContent:configContent
- configSettings:settings
- configExperiment:nil];
- }
- // Make the fetch calls for all instances.
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString stringWithFormat:@"Test enumerating configs successfully - instance %d", i]];
- XCTAssertEqual(_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusNoFetchYet);
- FIRRemoteConfigFetchCompletion fetchCompletion = ^void(FIRRemoteConfigFetchStatus status,
- NSError *error) {
- XCTAssertEqual(self->_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusFailure);
- [self->_configInstances[i] activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
- XCTAssertFalse(changed);
- XCTAssertNil(error);
- // No such key, still return a static value.
- FIRRemoteConfigValue *value = self->_configInstances[RCNTestRCInstanceDefault][@"key1"];
- XCTAssertEqual((int)value.source, (int)FIRRemoteConfigSourceStatic);
- XCTAssertEqualObjects(value.stringValue, @"");
- XCTAssertEqual(value.boolValue, NO);
- [expectations[i] fulfill];
- }];
- };
- [_configInstances[i] fetchWithExpirationDuration:43200 completionHandler:fetchCompletion];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- - (void)testFetchFailedNoNetworkErrorDoesNotThrottle {
- RCNConfigContent *configContent = [[RCNConfigContent alloc] initWithDBManager:_DBManager];
- NSString *currentAppName = RCNTestsDefaultFIRAppName;
- FIROptions *currentOptions = [self firstAppOptions];
- NSString *currentNamespace = RCNTestsFIRNamespace;
- NSString *fullyQualifiedNamespace =
- [NSString stringWithFormat:@"%@:%@", currentNamespace, currentAppName];
- RCNUserDefaultsManager *userDefaultsManager =
- [[RCNUserDefaultsManager alloc] initWithAppName:currentAppName
- bundleID:[NSBundle mainBundle].bundleIdentifier
- namespace:fullyQualifiedNamespace];
- userDefaultsManager.lastFetchTime = 0;
- FIRRemoteConfig *config = OCMPartialMock([[FIRRemoteConfig alloc] initWithAppName:currentAppName
- FIROptions:currentOptions
- namespace:currentNamespace
- DBManager:_DBManager
- configContent:configContent
- analytics:nil]);
- RCNConfigSettings *settings =
- [[RCNConfigSettings alloc] initWithDatabaseManager:_DBManager
- namespace:fullyQualifiedNamespace
- firebaseAppName:currentAppName
- googleAppID:currentOptions.googleAppID];
- dispatch_queue_t queue = dispatch_queue_create(
- [[NSString stringWithFormat:@"testqueue"] cStringUsingEncoding:NSUTF8StringEncoding],
- DISPATCH_QUEUE_SERIAL);
- RCNConfigFetch *configFetch =
- OCMPartialMock([[RCNConfigFetch alloc] initWithContent:configContent
- DBManager:_DBManager
- settings:settings
- analytics:nil
- experiment:nil
- queue:queue
- namespace:fullyQualifiedNamespace
- options:currentOptions]);
- OCMStub([configFetch fetchConfigWithExpirationDuration:43200 completionHandler:OCMOCK_ANY])
- .andDo(^(NSInvocation *invocation) {
- __unsafe_unretained void (^handler)(FIRRemoteConfigFetchStatus status,
- NSError *_Nullable error) = nil;
- [invocation getArgument:&handler atIndex:3];
- [configFetch fetchWithUserProperties:[[NSDictionary alloc] init]
- fetchTypeHeader:@"Base/1"
- completionHandler:handler
- updateCompletionHandler:nil];
- });
- _responseData[0] = [NSJSONSerialization dataWithJSONObject:@{} options:0 error:nil];
- // A no network error is accompanied with an HTTP status code of 0.
- _URLResponse[0] =
- [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"https://firebase.com"]
- statusCode:0
- HTTPVersion:nil
- headerFields:@{@"etag" : @"etag1"}];
- [config updateWithNewInstancesForConfigFetch:configFetch
- configContent:configContent
- configSettings:settings
- configExperiment:nil];
- XCTestExpectation *expectation =
- [self expectationWithDescription:@"Network error doesn't increase throttle interval"];
- XCTAssertEqual(config.lastFetchStatus, FIRRemoteConfigFetchStatusNoFetchYet);
- FIRRemoteConfigFetchCompletion fetchCompletion =
- ^void(FIRRemoteConfigFetchStatus status, NSError *error) {
- XCTAssertEqual(config.lastFetchStatus, FIRRemoteConfigFetchStatusFailure);
- XCTAssertEqual(settings.exponentialBackoffRetryInterval, 0);
- [expectation fulfill];
- };
- [config fetchWithExpirationDuration:43200 completionHandler:fetchCompletion];
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- // Activate should return false if a fetch response returns 200 with NO_CHANGE as the response body.
- - (void)testActivateOnFetchNoChangeStatus {
- // Override the setup values to return back an error status.
- RCNConfigContent *configContent = [[RCNConfigContent alloc] initWithDBManager:_DBManager];
- // Populate the default, second app, second namespace instances.
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- NSString *currentAppName = nil;
- FIROptions *currentOptions = nil;
- NSString *currentNamespace = nil;
- switch (i) {
- case RCNTestRCInstanceSecondNamespace:
- currentAppName = RCNTestsDefaultFIRAppName;
- currentOptions = [self firstAppOptions];
- currentNamespace = RCNTestsPerfNamespace;
- break;
- case RCNTestRCInstanceSecondApp:
- currentAppName = RCNTestsSecondFIRAppName;
- currentOptions = [self secondAppOptions];
- currentNamespace = _namespaceGoogleMobilePlatform;
- break;
- case RCNTestRCInstanceDefault:
- default:
- currentAppName = RCNTestsDefaultFIRAppName;
- currentOptions = [self firstAppOptions];
- currentNamespace = RCNTestsFIRNamespace;
- break;
- }
- NSString *fullyQualifiedNamespace =
- [NSString stringWithFormat:@"%@:%@", currentNamespace, currentAppName];
- RCNUserDefaultsManager *userDefaultsManager =
- [[RCNUserDefaultsManager alloc] initWithAppName:currentAppName
- bundleID:[NSBundle mainBundle].bundleIdentifier
- namespace:fullyQualifiedNamespace];
- userDefaultsManager.lastFetchTime = 10;
- FIRRemoteConfig *config =
- OCMPartialMock([[FIRRemoteConfig alloc] initWithAppName:currentAppName
- FIROptions:currentOptions
- namespace:currentNamespace
- DBManager:_DBManager
- configContent:configContent
- analytics:nil]);
- _configInstances[i] = config;
- RCNConfigSettings *settings =
- [[RCNConfigSettings alloc] initWithDatabaseManager:_DBManager
- namespace:fullyQualifiedNamespace
- firebaseAppName:currentAppName
- googleAppID:currentOptions.googleAppID];
- // Start the test with the assumption that we have some data that was fetched and activated.
- settings.lastETag = @"etag1";
- settings.lastETagUpdateTime = 100;
- settings.lastApplyTimeInterval = 101;
- dispatch_queue_t queue =
- dispatch_queue_create([[NSString stringWithFormat:@"testNoStatusFetchQueue: %d", i]
- cStringUsingEncoding:NSUTF8StringEncoding],
- DISPATCH_QUEUE_SERIAL);
- _configFetch[i] = OCMPartialMock([[RCNConfigFetch alloc] initWithContent:configContent
- DBManager:_DBManager
- settings:settings
- analytics:nil
- experiment:nil
- queue:queue
- namespace:fullyQualifiedNamespace
- options:currentOptions]);
- _configRealtime[i] = OCMPartialMock([[RCNConfigRealtime alloc] init:_configFetch[i]
- settings:settings
- namespace:fullyQualifiedNamespace
- options:currentOptions]);
- OCMStub([_configFetch[i] fetchConfigWithExpirationDuration:43200 completionHandler:OCMOCK_ANY])
- .andDo(^(NSInvocation *invocation) {
- __unsafe_unretained void (^handler)(FIRRemoteConfigFetchStatus status,
- NSError *_Nullable error) = nil;
- [invocation getArgument:&handler atIndex:3];
- [self->_configFetch[i] fetchWithUserProperties:[[NSDictionary alloc] init]
- fetchTypeHeader:@"Base/1"
- completionHandler:handler
- updateCompletionHandler:nil];
- });
- _response[i] = @{@"state" : @"NO_CHANGE"};
- _responseData[i] = [NSJSONSerialization dataWithJSONObject:_response[i] options:0 error:nil];
- _URLResponse[i] =
- [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"https://firebase.com"]
- statusCode:200
- HTTPVersion:nil
- headerFields:@{@"etag" : @"etag1"}];
- id completionBlock =
- [OCMArg invokeBlockWithArgs:_responseData[i], _URLResponse[i], [NSNull null], nil];
- OCMStub([_configFetch[i] URLSessionDataTaskWithContent:[OCMArg any]
- fetchTypeHeader:@"Base/1"
- completionHandler:completionBlock])
- .andReturn(nil);
- [_configInstances[i] updateWithNewInstancesForConfigFetch:_configFetch[i]
- configContent:configContent
- configSettings:settings
- configExperiment:nil];
- }
- // Make the fetch calls for all instances.
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString stringWithFormat:@"Test enumerating configs successfully - instance %d", i]];
- XCTAssertEqual(_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusNoFetchYet);
- // Make sure activate returns false in fetch completion.
- FIRRemoteConfigFetchCompletion fetchCompletion = ^void(FIRRemoteConfigFetchStatus status,
- NSError *error) {
- XCTAssertEqual(self->_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusSuccess);
- [self->_configInstances[i] activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
- XCTAssertFalse(changed);
- XCTAssertNil(error);
- [expectations[i] fulfill];
- }];
- };
- [_configInstances[i] fetchWithExpirationDuration:43200 completionHandler:fetchCompletion];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- - (void)testConfigValueForKey {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] =
- [self expectationWithDescription:
- [NSString stringWithFormat:@"Test configValueForKey: method - instance %d", i]];
- XCTAssertEqual(_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusNoFetchYet);
- FIRRemoteConfigFetchCompletion fetchCompletion = ^void(FIRRemoteConfigFetchStatus status,
- NSError *error) {
- XCTAssertEqual(status, FIRRemoteConfigFetchStatusSuccess);
- XCTAssertNil(error);
- [self->_configInstances[i] activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
- XCTAssertTrue(changed);
- NSString *key1 = [NSString stringWithFormat:@"key1-%d", i];
- NSString *key2 = [NSString stringWithFormat:@"key2-%d", i];
- NSString *key3 = [NSString stringWithFormat:@"key3-%d", i];
- NSString *key7 = [NSString stringWithFormat:@"key7-%d", i];
- NSString *value1 = [NSString stringWithFormat:@"value1-%d", i];
- NSString *value2 = [NSString stringWithFormat:@"value2-%d", i];
- NSString *value3 = [NSString stringWithFormat:@"value3-%d", i];
- NSString *value7 = [NSString stringWithFormat:@"value7-%d", i];
- XCTAssertEqualObjects(self->_configInstances[i][key1].stringValue, value1);
- XCTAssertEqualObjects(self->_configInstances[i][key2].stringValue, value2);
- OCMVerify([self->_configInstances[i] objectForKeyedSubscript:key1]);
- XCTAssertEqualObjects([self->_configInstances[i] configValueForKey:key3].stringValue,
- value3);
- if (i == RCNTestRCInstanceDefault) {
- XCTAssertEqualObjects([self->_configInstances[i] configValueForKey:key7].stringValue,
- value7);
- }
- XCTAssertEqualObjects([self->_configInstances[i] configValueForKey:key7].stringValue,
- value7);
- XCTAssertNotNil([self->_configInstances[i] configValueForKey:nil]);
- XCTAssertEqual([self->_configInstances[i] configValueForKey:nil].source,
- FIRRemoteConfigSourceStatic);
- XCTAssertEqual([self->_configInstances[i] configValueForKey:nil].source,
- FIRRemoteConfigSourceStatic);
- XCTAssertEqual([self->_configInstances[i] configValueForKey:nil source:-1].source,
- FIRRemoteConfigSourceStatic);
- [expectations[i] fulfill];
- }];
- };
- [_configInstances[i] fetchWithExpirationDuration:43200 completionHandler:fetchCompletion];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- - (void)testFetchConfigWithDefaultSets {
- NSMutableArray<XCTestExpectation *> *fetchConfigsExpectation =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- fetchConfigsExpectation[i] = [self
- expectationWithDescription:
- [NSString stringWithFormat:@"Test fetch configs with defaults set - instance %d", i]];
- NSString *key1 = [NSString stringWithFormat:@"key1-%d", i];
- NSString *key2 = [NSString stringWithFormat:@"key2-%d", i];
- NSString *key0 = [NSString stringWithFormat:@"key0-%d", i];
- NSString *value1 = [NSString stringWithFormat:@"value1-%d", i];
- NSString *value2 = [NSString stringWithFormat:@"value2-%d", i];
- NSDictionary<NSString *, NSString *> *defaults = @{key1 : @"default key1", key0 : @"value0-0"};
- [_configInstances[i] setDefaults:defaults];
- FIRRemoteConfigFetchCompletion fetchCompletion = ^void(FIRRemoteConfigFetchStatus status,
- NSError *error) {
- XCTAssertEqual(self->_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusSuccess);
- XCTAssertNil(error);
- XCTAssertEqualObjects(self->_configInstances[i][key1].stringValue, @"default key1");
- XCTAssertEqual(self->_configInstances[i][key1].source, FIRRemoteConfigSourceDefault);
- [self->_configInstances[i] activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
- XCTAssertTrue(changed);
- XCTAssertEqualObjects(self->_configInstances[i][key1].stringValue, value1);
- XCTAssertEqual(self->_configInstances[i][key1].source, FIRRemoteConfigSourceRemote);
- XCTAssertEqualObjects([self->_configInstances[i] defaultValueForKey:key1].stringValue,
- @"default key1");
- XCTAssertEqualObjects(self->_configInstances[i][key2].stringValue, value2);
- XCTAssertEqualObjects(self->_configInstances[i][key0].stringValue, @"value0-0");
- XCTAssertNil([self->_configInstances[i] defaultValueForKey:nil]);
- OCMVerify([self->_configInstances[i] objectForKeyedSubscript:key1]);
- XCTAssertEqual(status, FIRRemoteConfigFetchStatusSuccess,
- @"Callback of first successful config "
- @"fetch. Status must equal to FIRRemoteConfigFetchStatusSuccess.");
- [fetchConfigsExpectation[i] fulfill];
- }];
- };
- [_configInstances[i] fetchWithExpirationDuration:43200 completionHandler:fetchCompletion];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- - (void)testDefaultsSetsOnly {
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- NSString *key1 = [NSString stringWithFormat:@"key1-%d", i];
- NSString *key2 = [NSString stringWithFormat:@"key2-%d", i];
- NSString *key3 = [NSString stringWithFormat:@"key3-%d", i];
- NSString *key4 = [NSString stringWithFormat:@"key4-%d", i];
- NSString *key5 = [NSString stringWithFormat:@"key5-%d", i];
- NSString *defaultValue1 = @"default value1";
- NSData *defaultValue2 = [defaultValue1 dataUsingEncoding:NSUTF8StringEncoding];
- NSNumber *defaultValue3 = [NSNumber numberWithFloat:3.1415926];
- NSDate *defaultValue4 = [NSDate date];
- BOOL defaultValue5 = NO;
- NSMutableDictionary<NSString *, id> *defaults = [NSMutableDictionary dictionaryWithDictionary:@{
- key1 : defaultValue1,
- key2 : defaultValue2,
- key3 : defaultValue3,
- key4 : defaultValue4,
- key5 : @(defaultValue5),
- }];
- [_configInstances[i] setDefaults:defaults];
- if (i == RCNTestRCInstanceSecondNamespace) {
- [defaults setObject:@"2860" forKey:@"experience"];
- [_configInstances[i] setDefaults:defaults];
- }
- // Remove objects right away to make sure dispatch_async gets the copy.
- [defaults removeAllObjects];
- FIRRemoteConfig *config = _configInstances[i];
- XCTAssertEqualObjects(config[key1].stringValue, defaultValue1, @"Should support string format");
- XCTAssertEqualObjects(config[key2].dataValue, defaultValue2, @"Should support data format");
- XCTAssertEqual(config[key3].numberValue.longValue, defaultValue3.longValue,
- @"Should support number format");
- NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
- [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
- NSString *strValueOfDate = [dateFormatter stringFromDate:(NSDate *)defaultValue4];
- XCTAssertEqualObjects(
- config[key4].stringValue, strValueOfDate,
- @"Date format can be set as an input from plist, but output coming out of "
- @"defaultConfig as string.");
- XCTAssertEqual(config[key5].boolValue, defaultValue5, @"Should support bool format");
- if (i == RCNTestRCInstanceSecondNamespace) {
- XCTAssertEqualObjects(
- [_configInstances[i] configValueForKey:@"experience"].stringValue, @"2860",
- @"Only default config has the key, must equal to default config value.");
- }
- // Reset default sets
- [_configInstances[i] setDefaults:nil];
- XCTAssertEqual([_configInstances[i] allKeysFromSource:FIRRemoteConfigSourceDefault].count, 0);
- }
- }
- - (void)testSetDefaultsWithNilParams {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString stringWithFormat:@"Set defaults no callback expectation - instance %d", i]];
- // Should work when passing nil.
- [_configInstances[i] setDefaults:nil];
- [_configInstances[i] setDefaults:nil];
- dispatch_after(
- dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_checkCompletionTimeout * NSEC_PER_SEC)),
- dispatch_get_main_queue(), ^{
- XCTAssertEqual(
- [self->_configInstances[i] allKeysFromSource:FIRRemoteConfigSourceDefault].count, 0);
- [expectations[i] fulfill];
- });
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- - (void)testFetchConfigOverwriteDefaultSet {
- NSMutableArray<XCTestExpectation *> *fetchConfigsExpectation =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- fetchConfigsExpectation[i] = [self
- expectationWithDescription:
- [NSString stringWithFormat:@"Test fetch configs with defaults set - instance %d", i]];
- NSString *key1 = [NSString stringWithFormat:@"key1-%d", i];
- NSString *value1 = [NSString stringWithFormat:@"value1-%d", i];
- [_configInstances[i] setDefaults:@{key1 : @"default key1"}];
- FIRRemoteConfigValue *value = _configInstances[i][key1];
- XCTAssertEqualObjects(value.stringValue, @"default key1");
- XCTAssertEqual(value.source, FIRRemoteConfigSourceDefault);
- value = _configInstances[i][@"A key doesn't exist"];
- XCTAssertEqual(value.source, FIRRemoteConfigSourceStatic);
- FIRRemoteConfigFetchCompletion fetchCompletion = ^void(FIRRemoteConfigFetchStatus status,
- NSError *error) {
- XCTAssertEqual(self->_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusSuccess);
- XCTAssertNil(error);
- [self->_configInstances[i] activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
- XCTAssertTrue(changed);
- XCTAssertEqualObjects(self->_configInstances[i][key1].stringValue, value1);
- XCTAssertEqual(self->_configInstances[i][key1].source, FIRRemoteConfigSourceRemote);
- XCTAssertEqualObjects([self->_configInstances[i] defaultValueForKey:key1].stringValue,
- @"default key1");
- OCMVerify([self->_configInstances[i] objectForKeyedSubscript:key1]);
- XCTAssertEqual(status, FIRRemoteConfigFetchStatusSuccess,
- @"Callback of first successful config "
- @"fetch. Status must equal to FIRRemoteConfigFetchStatusSuccess.");
- [fetchConfigsExpectation[i] fulfill];
- }];
- };
- [_configInstances[i] fetchWithExpirationDuration:43200 completionHandler:fetchCompletion];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- - (void)testGetConfigValueBySource {
- NSMutableArray<XCTestExpectation *> *fetchConfigsExpectation =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- fetchConfigsExpectation[i] =
- [self expectationWithDescription:
- [NSString stringWithFormat:@"Test get config value by source - instance %d", i]];
- NSString *key1 = [NSString stringWithFormat:@"key1-%d", i];
- NSString *value1 = [NSString stringWithFormat:@"value1-%d", i];
- NSDictionary<NSString *, NSString *> *defaults = @{key1 : @"default value1"};
- [_configInstances[i] setDefaults:defaults];
- FIRRemoteConfigFetchCompletion fetchCompletion = ^void(FIRRemoteConfigFetchStatus status,
- NSError *error) {
- XCTAssertEqual(self->_configInstances[i].lastFetchStatus, FIRRemoteConfigFetchStatusSuccess);
- XCTAssertNil(error);
- XCTAssertEqualObjects(self->_configInstances[i][key1].stringValue, @"default value1");
- XCTAssertEqual(self->_configInstances[i][key1].source, FIRRemoteConfigSourceDefault);
- [self->_configInstances[i] activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
- XCTAssertTrue(changed);
- XCTAssertEqualObjects(self->_configInstances[i][key1].stringValue, value1);
- XCTAssertEqual(self->_configInstances[i][key1].source, FIRRemoteConfigSourceRemote);
- FIRRemoteConfigValue *value;
- if (i == RCNTestRCInstanceDefault) {
- value = [self->_configInstances[i] configValueForKey:key1
- source:FIRRemoteConfigSourceRemote];
- XCTAssertEqualObjects(value.stringValue, value1);
- value = [self->_configInstances[i] configValueForKey:key1
- source:FIRRemoteConfigSourceDefault];
- XCTAssertEqualObjects(value.stringValue, @"default value1");
- value = [self->_configInstances[i] configValueForKey:key1
- source:FIRRemoteConfigSourceStatic];
- } else {
- value = [self->_configInstances[i] configValueForKey:key1
- source:FIRRemoteConfigSourceRemote];
- XCTAssertEqualObjects(value.stringValue, value1);
- value = [self->_configInstances[i] configValueForKey:key1
- source:FIRRemoteConfigSourceDefault];
- XCTAssertEqualObjects(value.stringValue, @"default value1");
- value = [self->_configInstances[i] configValueForKey:key1
- source:FIRRemoteConfigSourceStatic];
- }
- XCTAssertEqualObjects(value.stringValue, @"");
- XCTAssertEqualObjects(value.numberValue, @(0));
- XCTAssertEqual(value.boolValue, NO);
- XCTAssertEqual(status, FIRRemoteConfigFetchStatusSuccess,
- @"Callback of first successful config "
- @"fetch. Status must equal to FIRRemoteConfigFetchStatusSuccess.");
- [fetchConfigsExpectation[i] fulfill];
- }];
- };
- [_configInstances[i] fetchWithExpirationDuration:43200 completionHandler:fetchCompletion];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- - (void)testInvalidKeyOrNamespace {
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- FIRRemoteConfigValue *value = [_configInstances[i] configValueForKey:nil];
- XCTAssertNotNil(value);
- XCTAssertEqual(value.source, FIRRemoteConfigSourceStatic);
- value = [_configInstances[i] configValueForKey:nil];
- XCTAssertNotNil(value);
- XCTAssertEqual(value.source, FIRRemoteConfigSourceStatic);
- value = [_configInstances[i] configValueForKey:nil source:5];
- XCTAssertNotNil(value);
- XCTAssertEqual(value.source, FIRRemoteConfigSourceStatic);
- }
- }
- // Remote Config converts UTC times in the plists to local times. This utility function makes it
- // possible to check the times when running the tests in any timezone.
- static NSString *UTCToLocal(NSString *utcTime) {
- // Create a UTC dateFormatter.
- NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
- [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
- [dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
- NSDate *date = [dateFormatter dateFromString:utcTime];
- [dateFormatter setTimeZone:[NSTimeZone localTimeZone]];
- return [dateFormatter stringFromDate:date];
- }
- // Manage different bundle locations for Swift Package Manager, CocoaPods static, CocoaPods dynamic.
- - (void)setDefaultsFor:(FIRRemoteConfig *)config {
- #if SWIFT_PACKAGE
- NSBundle *bundle = SWIFTPM_MODULE_BUNDLE;
- NSString *plistFile = [bundle pathForResource:@"Defaults-testInfo" ofType:@"plist"];
- #else
- NSBundle *bundle = [NSBundle mainBundle];
- NSString *plistFile = [bundle pathForResource:@"Defaults-testInfo" ofType:@"plist"];
- if (plistFile != nil) {
- [config setDefaultsFromPlistFileName:@"Defaults-testInfo"];
- return;
- }
- // We've linked dynamically and the plist file is in the test's bundle.
- for (bundle in [NSBundle allBundles]) {
- plistFile = [bundle pathForResource:@"Defaults-testInfo" ofType:@"plist"];
- if (plistFile != nil) {
- break;
- }
- }
- #endif
- NSDictionary *defaults = [[NSDictionary alloc] initWithContentsOfFile:plistFile];
- [config setDefaults:defaults];
- }
- - (void)testSetDefaultsFromPlist {
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- FIRRemoteConfig *config = _configInstances[i];
- [self setDefaultsFor:config];
- XCTAssertEqualObjects(_configInstances[i][@"lastCheckTime"].stringValue,
- UTCToLocal(@"2016-02-28 18:33:31"));
- XCTAssertEqual(_configInstances[i][@"isPaidUser"].boolValue, YES);
- XCTAssertEqualObjects(_configInstances[i][@"dataValue"].stringValue, @"2.4");
- XCTAssertEqualObjects(_configInstances[i][@"New item"].numberValue, @(2.4));
- XCTAssertEqualObjects(_configInstances[i][@"Languages"].stringValue, @"English");
- XCTAssertEqualObjects(_configInstances[i][@"FileInfo"].stringValue,
- @"To setup default config.");
- XCTAssertEqualObjects(_configInstances[i][@"format"].stringValue, @"key to value.");
- XCTAssertEqualObjects(_configInstances[i][@"arrayValue"].JSONValue,
- ((id) @[ @"foo", @"bar", @"baz" ]));
- XCTAssertEqualObjects(_configInstances[i][@"dictValue"].JSONValue,
- ((id) @{@"foo" : @"foo", @"bar" : @"bar", @"baz" : @"baz"}));
- // If given a wrong file name, the default will not be set and kept as previous results.
- [_configInstances[i] setDefaultsFromPlistFileName:@""];
- XCTAssertEqualObjects(_configInstances[i][@"lastCheckTime"].stringValue,
- UTCToLocal(@"2016-02-28 18:33:31"));
- [_configInstances[i] setDefaultsFromPlistFileName:@"non-existed_file"];
- XCTAssertEqualObjects(_configInstances[i][@"dataValue"].stringValue, @"2.4");
- [_configInstances[i] setDefaultsFromPlistFileName:nil];
- XCTAssertEqualObjects(_configInstances[i][@"New item"].numberValue, @(2.4));
- [_configInstances[i] setDefaultsFromPlistFileName:@""];
- XCTAssertEqualObjects(_configInstances[i][@"Languages"].stringValue, @"English");
- }
- }
- - (void)testAllKeysFromSource {
- NSMutableArray<XCTestExpectation *> *fetchConfigsExpectation =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- fetchConfigsExpectation[i] = [self
- expectationWithDescription:[NSString
- stringWithFormat:@"Test allKeys methods - instance %d", i]];
- NSString *key1 = [NSString stringWithFormat:@"key1-%d", i];
- NSString *key0 = [NSString stringWithFormat:@"key0-%d", i];
- NSDictionary<NSString *, NSString *> *defaults = @{key1 : @"default key1", key0 : @"value0-0"};
- [_configInstances[i] setDefaults:defaults];
- FIRRemoteConfigFetchCompletion fetchCompletion = ^void(FIRRemoteConfigFetchStatus status,
- NSError *error) {
- XCTAssertEqual(status, FIRRemoteConfigFetchStatusSuccess);
- XCTAssertNil(error);
- [self->_configInstances[i] activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
- XCTAssertTrue(changed);
- XCTAssertEqual(
- [self->_configInstances[i] allKeysFromSource:FIRRemoteConfigSourceRemote].count, 100);
- XCTAssertEqual(
- [self->_configInstances[i] allKeysFromSource:FIRRemoteConfigSourceDefault].count, 2);
- XCTAssertEqual(
- [self->_configInstances[i] allKeysFromSource:FIRRemoteConfigSourceStatic].count, 0);
- [fetchConfigsExpectation[i] fulfill];
- }];
- };
- [_configInstances[i] fetchWithExpirationDuration:43200 completionHandler:fetchCompletion];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- - (void)testAllKeysWithPrefix {
- NSMutableArray<XCTestExpectation *> *fetchConfigsExpectation =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- fetchConfigsExpectation[i] = [self
- expectationWithDescription:[NSString
- stringWithFormat:@"Test allKeys methods - instance %d", i]];
- FIRRemoteConfigFetchCompletion fetchCompletion = ^void(FIRRemoteConfigFetchStatus status,
- NSError *error) {
- XCTAssertEqual(status, FIRRemoteConfigFetchStatusSuccess);
- XCTAssertNil(error);
- NSLog(@"Testing _configInstances %d", i);
- [self->_configInstances[i] activateWithCompletion:^(BOOL changed, NSError *_Nullable error) {
- XCTAssertTrue(changed);
- // Test keysWithPrefix: method.
- XCTAssertEqual([self->_configInstances[i] keysWithPrefix:@"key1"].count, 12);
- XCTAssertEqual([self->_configInstances[i] keysWithPrefix:@"key"].count, 100);
- XCTAssertEqual([self->_configInstances[i] keysWithPrefix:@"invalid key"].count, 0);
- XCTAssertEqual([self->_configInstances[i] keysWithPrefix:nil].count, 100);
- XCTAssertEqual([self->_configInstances[i] keysWithPrefix:@""].count, 100);
- [fetchConfigsExpectation[i] fulfill];
- }];
- };
- [_configInstances[i] fetchWithExpirationDuration:43200 completionHandler:fetchCompletion];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- /// Test the minimum fetch interval is applied and read back correctly.
- - (void)testSetMinimumFetchIntervalConfigSetting {
- NSMutableArray<XCTestExpectation *> *fetchConfigsExpectation =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- fetchConfigsExpectation[i] = [self
- expectationWithDescription:
- [NSString stringWithFormat:@"Test minimumFetchInterval expectation - instance %d", i]];
- FIRRemoteConfigSettings *settings = [[FIRRemoteConfigSettings alloc] init];
- settings.minimumFetchInterval = 123;
- [_configInstances[i] setConfigSettings:settings];
- XCTAssertEqual([_configInstances[i] configSettings].minimumFetchInterval, 123);
- FIRRemoteConfigFetchCompletion fetchCompletion =
- ^void(FIRRemoteConfigFetchStatus status, NSError *error) {
- XCTAssertFalse([self->_configInstances[i].settings hasMinimumFetchIntervalElapsed:43200]);
- // Update minimum fetch interval.
- FIRRemoteConfigSettings *settings = [[FIRRemoteConfigSettings alloc] init];
- settings.minimumFetchInterval = 0;
- [self->_configInstances[i] setConfigSettings:settings];
- XCTAssertEqual([self->_configInstances[i] configSettings].minimumFetchInterval, 0);
- XCTAssertTrue([self->_configInstances[i].settings hasMinimumFetchIntervalElapsed:0]);
- [fetchConfigsExpectation[i] fulfill];
- };
- [_configInstances[i] fetchWithExpirationDuration:43200 completionHandler:fetchCompletion];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout
- handler:^(NSError *error) {
- XCTAssertNil(error);
- }];
- }
- /// Test the fetch timeout is properly set and read back.
- - (void)testSetFetchTimeoutConfigSetting {
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- FIRRemoteConfigSettings *settings = [[FIRRemoteConfigSettings alloc] init];
- settings.fetchTimeout = 1;
- [_configInstances[i] setConfigSettings:settings];
- XCTAssertEqual([_configInstances[i] configSettings].fetchTimeout, 1);
- NSURLSession *networkSession = [_configFetch[i] currentNetworkSession];
- XCTAssertNotNil(networkSession);
- XCTAssertEqual(networkSession.configuration.timeoutIntervalForResource, 1);
- XCTAssertEqual(networkSession.configuration.timeoutIntervalForRequest, 1);
- }
- }
- - (void)testFetchRequestWithUserPropertiesOnly {
- NSDictionary *userProperties = @{@"user_key" : @"user_value"};
- NSString *req = [_settings nextRequestWithUserProperties:userProperties];
- XCTAssertTrue([req containsString:@"analytics_user_properties:{\"user_key\":\"user_value\"}"]);
- XCTAssertFalse([req containsString:@"first_open_time"]);
- }
- - (void)testFetchRequestWithFirstOpenTimeAndUserProperties {
- NSDictionary *userProperties = @{@"_fot" : @1649116800000, @"user_key" : @"user_value"};
- NSString *req = [_settings nextRequestWithUserProperties:userProperties];
- XCTAssertTrue([req containsString:@"first_open_time:'2022-04-05T00:00:00Z'"]);
- XCTAssertTrue([req containsString:@"analytics_user_properties:{\"user_key\":\"user_value\"}"]);
- }
- - (void)testFetchRequestFirstOpenTimeOnly {
- NSDictionary *userProperties = @{@"_fot" : @1650315600000};
- NSString *req = [_settings nextRequestWithUserProperties:userProperties];
- XCTAssertTrue([req containsString:@"first_open_time:'2022-04-18T21:00:00Z'"]);
- XCTAssertFalse([req containsString:@"analytics_user_properties"]);
- }
- #pragma mark - Public Factory Methods
- - (void)testConfigureConfigWithValidInput {
- // Configure the default app with our options and ensure the Remote Config instance is set up
- // properly.
- if (![FIRApp isDefaultAppConfigured]) {
- XCTAssertNoThrow([FIRApp configureWithOptions:[self firstAppOptions]]);
- }
- XCTAssertNoThrow([FIRRemoteConfig remoteConfig]);
- FIRRemoteConfig *config = [FIRRemoteConfig remoteConfig];
- XCTAssertNotNil(config);
- // Ensure the same instance is returned from the singleton.
- FIRRemoteConfig *sameConfig = [FIRRemoteConfig remoteConfig];
- XCTAssertNotNil(sameConfig);
- XCTAssertEqual(config, sameConfig);
- // Ensure the app name is stored properly.
- XCTAssertEqual([config valueForKey:@"_appName"], kFIRDefaultAppName);
- }
- #pragma mark - Realtime tests
- - (void)testRealtimeAddConfigUpdateListenerWithValidListener {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString
- stringWithFormat:@"Test Realtime add listener successfully - instance %d", i]];
- OCMStub([_configRealtime[i] beginRealtimeStream]).andDo(nil);
- id completion = ^void(FIRRemoteConfigUpdate *_Nullable configUpdate, NSError *_Nullable error) {
- if (error != nil) {
- NSLog(@"Callback");
- }
- };
- [_configRealtime[i] addConfigUpdateListener:completion];
- dispatch_after(
- dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_checkCompletionTimeout * NSEC_PER_SEC)),
- dispatch_get_main_queue(), ^{
- OCMVerify([self->_configRealtime[i] beginRealtimeStream]);
- OCMVerify([self->_configRealtime[i] addConfigUpdateListener:completion]);
- [expectations[i] fulfill];
- });
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- }
- - (void)testRealtimeAddConfigUpdateListenerWithInvalidListener {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString
- stringWithFormat:@"Test Realtime add listener unsuccessfully - instance %d", i]];
- id completion = nil;
- [_configRealtime[i] addConfigUpdateListener:completion];
- dispatch_after(
- dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_checkCompletionTimeout * NSEC_PER_SEC)),
- dispatch_get_main_queue(), ^{
- OCMVerify(never(), [self->_configRealtime[i] beginRealtimeStream]);
- [expectations[i] fulfill];
- });
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- }
- - (void)testRemoveRealtimeListener {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString
- stringWithFormat:@"Test Realtime remove listeners successfully - instance %d", i]];
- id completion = ^void(FIRRemoteConfigUpdate *_Nullable configUpdate, NSError *_Nullable error) {
- if (error != nil) {
- NSLog(@"Callback");
- }
- };
- OCMStub([_configRealtime[i] beginRealtimeStream]).andDo(nil);
- FIRConfigUpdateListenerRegistration *registration =
- [_configRealtime[i] addConfigUpdateListener:completion];
- [registration remove];
- dispatch_after(
- dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_checkCompletionTimeout * NSEC_PER_SEC)),
- dispatch_get_main_queue(), ^{
- OCMVerify([self->_configRealtime[i] addConfigUpdateListener:completion]);
- OCMVerify([self->_configRealtime[i] removeConfigUpdateListener:completion]);
- OCMVerify([self->_configRealtime[i] pauseRealtimeStream]);
- [expectations[i] fulfill];
- });
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- }
- - (void)testRealtimeFetch {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString stringWithFormat:@"Test Realtime Autofetch successfully - instance %d", i]];
- OCMStub([_configFetch[i] realtimeFetchConfigWithNoExpirationDuration:1
- completionHandler:OCMOCK_ANY])
- .andDo(nil);
- OCMStub([_configRealtime[i] scheduleFetch:1 targetVersion:1]).andDo(nil);
- [_configRealtime[i] fetchLatestConfig:3 targetVersion:1];
- dispatch_after(
- dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_checkCompletionTimeout * NSEC_PER_SEC)),
- dispatch_get_main_queue(), ^{
- OCMVerify([self->_configFetch[i] realtimeFetchConfigWithNoExpirationDuration:1
- completionHandler:OCMOCK_ANY]);
- [expectations[i] fulfill];
- });
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- }
- - (void)testAutofetch {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString stringWithFormat:@"Test Realtime Autofetch successfully - instance %d", i]];
- OCMStub([_configRealtime[i] scheduleFetch:1 targetVersion:1]).andDo(nil);
- [_configRealtime[i] autoFetch:1 targetVersion:1];
- dispatch_after(
- dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_checkCompletionTimeout * NSEC_PER_SEC)),
- dispatch_get_main_queue(), ^{
- OCMVerify([self->_configRealtime[i] scheduleFetch:1 targetVersion:1]);
- [expectations[i] fulfill];
- });
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- }
- - (void)testAddOnConfigUpdateMethodSuccess {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString
- stringWithFormat:@"Test public realtime method successfully - instance %d", i]];
- OCMStub([_configRealtime[i] beginRealtimeStream]).andDo(nil);
- id completion = ^void(FIRRemoteConfigUpdate *_Nullable configUpdate, NSError *_Nullable error) {
- if (error != nil) {
- NSLog(@"Callback");
- }
- };
- [_configInstances[i] addOnConfigUpdateListener:completion];
- dispatch_after(
- dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_checkCompletionTimeout * NSEC_PER_SEC)),
- dispatch_get_main_queue(), ^{
- OCMVerify([self->_configRealtime[i] addConfigUpdateListener:completion]);
- [expectations[i] fulfill];
- });
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- }
- - (void)testAddOnConfigUpdateMethodFail {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString stringWithFormat:@"Test public realtime method and fails - instance %d", i]];
- id completion = nil;
- [_configInstances[i] addOnConfigUpdateListener:completion];
- dispatch_after(
- dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_checkCompletionTimeout * NSEC_PER_SEC)),
- dispatch_get_main_queue(), ^{
- OCMVerify(never(), [self->_configRealtime[i] beginRealtimeStream]);
- [expectations[i] fulfill];
- });
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- }
- - (void)testRealtimeDisabled {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString
- stringWithFormat:@"Test isRealtimeDisabled flag and makes it true - instance %d",
- i]];
- OCMStub([_configRealtime[i] pauseRealtimeStream]).andDo(nil);
- NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
- [dictionary setValue:@"true" forKey:@"featureDisabled"];
- [dictionary setValue:@"1" forKey:@"latestTemplateVersionNumber"];
- [_configRealtime[i] evaluateStreamResponse:dictionary error:nil];
- dispatch_after(
- dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_checkCompletionTimeout * NSEC_PER_SEC)),
- dispatch_get_main_queue(), ^{
- OCMVerify([self->_configRealtime[i] pauseRealtimeStream]);
- OCMVerify(never(), [self->_configRealtime[i] autoFetch:5 targetVersion:1]);
- [expectations[i] fulfill];
- });
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- }
- - (void)testRealtimeStreamRequestBody {
- XCTestExpectation *requestBodyExpectation = [self expectationWithDescription:@"requestBody"];
- __block NSData *requestBody;
- [_configRealtime[0] createRequestBodyWithCompletion:^(NSData *_Nonnull data) {
- requestBody = data;
- [requestBodyExpectation fulfill];
- }];
- [self waitForExpectations:@[ requestBodyExpectation ] timeout:5.0];
- NSError *error;
- NSData *uncompressedRequest = [NSData gul_dataByInflatingGzippedData:requestBody error:&error];
- NSString *strData = [[NSString alloc] initWithData:uncompressedRequest
- encoding:NSUTF8StringEncoding];
- XCTAssertTrue([strData containsString:@"project:'correct_gcm_sender_id'"]);
- XCTAssertTrue([strData containsString:@"namespace:'firebase'"]);
- XCTAssertTrue([strData containsString:@"lastKnownVersionNumber:'0'"]);
- XCTAssertTrue([strData containsString:@"appId:'1:123:ios:123abc'"]);
- XCTAssertTrue([strData containsString:@"sdkVersion:"]);
- XCTAssertTrue([strData containsString:@"appInstanceId:'iid'"]);
- }
- - (void)testFetchAndActivateRolloutsNotifyInterop {
- XCTestExpectation *notificationExpectation =
- [self expectationForNotification:@"FIRRolloutsStateDidChangeNotification"
- object:nil
- handler:nil];
- XCTAssertEqual(_configInstances[RCNTestRCInstanceDefault].lastFetchStatus,
- FIRRemoteConfigFetchStatusNoFetchYet);
- FIRRemoteConfigFetchAndActivateCompletion fetchAndActivateCompletion =
- ^void(FIRRemoteConfigFetchAndActivateStatus status, NSError *error) {
- XCTAssertEqual(status, FIRRemoteConfigFetchAndActivateStatusSuccessFetchedFromRemote);
- XCTAssertNil(error);
- XCTAssertEqual(self->_configInstances[RCNTestRCInstanceDefault].lastFetchStatus,
- FIRRemoteConfigFetchStatusSuccess);
- XCTAssertNotNil(self->_configInstances[RCNTestRCInstanceDefault].lastFetchTime);
- XCTAssertGreaterThan(
- self->_configInstances[RCNTestRCInstanceDefault].lastFetchTime.timeIntervalSince1970, 0,
- @"last fetch time interval should be set.");
- [notificationExpectation fulfill];
- };
- [_configInstances[RCNTestRCInstanceDefault]
- fetchAndActivateWithCompletionHandler:fetchAndActivateCompletion];
- [self waitForExpectations:@[ notificationExpectation ] timeout:_expectationTimeout];
- }
- - (void)testURLSessionDelegateHandlesChunkedJSON {
- NSString *testString = @"} {\"testKey\":\"testValue\"}";
- NSData *testData = [testString dataUsingEncoding:NSUTF8StringEncoding];
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString
- stringWithFormat:@"Test delegate method handling chunked JSON - instance %d", i]];
- NSURLSession *networkSession = [_configFetch[i] currentNetworkSession];
- NSURLSessionDataTask *dataTask = [_configFetch[i] URLSessionDataTaskWithContent:[OCMArg any]
- fetchTypeHeader:[OCMArg any]
- completionHandler:nil];
- XCTAssertNoThrow([_configRealtime[i] URLSession:networkSession
- dataTask:dataTask
- didReceiveData:testData]);
- [expectations[i] fulfill];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- - (void)testSetCustomSignals {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:[NSString
- stringWithFormat:@"Set custom signals - instance %d", i]];
- NSDictionary<NSString *, NSObject *> *testSignals = @{
- @"signal1" : @"stringValue",
- @"signal2" : @"stringValue2",
- };
- [_configInstances[i] setCustomSignals:testSignals
- withCompletion:^(NSError *_Nullable error) {
- XCTAssertNil(error);
- NSDictionary<NSString *, NSString *> *retrievedSignals =
- self->_configInstances[i].settings.customSignals;
- XCTAssertEqualObjects(retrievedSignals, testSignals);
- [expectations[i] fulfill];
- }];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- - (void)testSetCustomSignalsMultipleTimes {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] = [self
- expectationWithDescription:
- [NSString stringWithFormat:@"Set custom signals multiple times - instance %d", i]];
- // First set of signals
- NSDictionary<NSString *, NSObject *> *testSignals1 = @{
- @"signal1" : @"stringValue1",
- @"signal2" : @"stringValue2",
- };
- // Second set of signals (overwrites, remove and adds new)
- NSDictionary<NSString *, NSObject *> *testSignals2 = @{
- @"signal1" : @"updatedValue1",
- @"signal2" : [NSNull null],
- @"signal3" : @5,
- };
- // Expected final set of signals
- NSDictionary<NSString *, NSString *> *expectedSignals = @{
- @"signal1" : @"updatedValue1",
- @"signal3" : @"5",
- };
- [_configInstances[i] setCustomSignals:testSignals1
- withCompletion:^(NSError *_Nullable error) {
- XCTAssertNil(error);
- [self->_configInstances[i]
- setCustomSignals:testSignals2
- withCompletion:^(NSError *_Nullable error) {
- XCTAssertNil(error);
- NSDictionary<NSString *, NSString *> *retrievedSignals =
- self->_configInstances[i].settings.customSignals;
- XCTAssertEqualObjects(retrievedSignals, expectedSignals);
- [expectations[i] fulfill];
- }];
- }];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- - (void)testSetCustomSignals_invalidInput_throwsException {
- NSMutableArray<XCTestExpectation *> *expectations =
- [[NSMutableArray alloc] initWithCapacity:RCNTestRCNumTotalInstances];
- for (int i = 0; i < RCNTestRCNumTotalInstances; i++) {
- expectations[i] =
- [self expectationWithDescription:
- [NSString stringWithFormat:@"Set custom signals expects error - instance %d", i]];
- // Invalid value type.
- NSDictionary<NSString *, NSObject *> *invalidSignals1 = @{@"name" : [NSDate date]};
- // Key length exceeds limit.
- NSDictionary<NSString *, NSObject *> *invalidSignals2 =
- @{[@"a" stringByPaddingToLength:251 withString:@"a" startingAtIndex:0] : @"value"};
- // Value length exceeds limit.
- NSDictionary<NSString *, NSObject *> *invalidSignals3 =
- @{@"key" : [@"a" stringByPaddingToLength:501 withString:@"a" startingAtIndex:0]};
- [_configInstances[i]
- setCustomSignals:invalidSignals1
- withCompletion:^(NSError *_Nullable error) {
- XCTAssertNotNil(error);
- XCTAssertEqual(error.code, FIRRemoteConfigCustomSignalsErrorInvalidValueType);
- }];
- [_configInstances[i]
- setCustomSignals:invalidSignals2
- withCompletion:^(NSError *_Nullable error) {
- XCTAssertNotNil(error);
- XCTAssertEqual(error.code, FIRRemoteConfigCustomSignalsErrorLimitExceeded);
- }];
- [_configInstances[i]
- setCustomSignals:invalidSignals3
- withCompletion:^(NSError *_Nullable error) {
- XCTAssertNotNil(error);
- XCTAssertEqual(error.code, FIRRemoteConfigCustomSignalsErrorLimitExceeded);
- [expectations[i] fulfill];
- }];
- }
- [self waitForExpectationsWithTimeout:_expectationTimeout handler:nil];
- }
- #pragma mark - Test Helpers
- - (FIROptions *)firstAppOptions {
- // TODO: Evaluate if we want to hardcode things here instead.
- FIROptions *options = [[FIROptions alloc] initWithGoogleAppID:@"1:123:ios:123abc"
- GCMSenderID:@"correct_gcm_sender_id"];
- options.APIKey = @"AIzaSy-ApiKeyWithValidFormat_0123456789";
- options.projectID = @"abc-xyz-123";
- return options;
- }
- - (FIROptions *)secondAppOptions {
- NSBundle *bundle = [NSBundle bundleForClass:[self class]];
- #if SWIFT_PACKAGE
- bundle = SWIFTPM_MODULE_BUNDLE;
- #endif
- NSString *plistPath = [bundle pathForResource:@"SecondApp-GoogleService-Info" ofType:@"plist"];
- FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:plistPath];
- XCTAssertNotNil(options);
- return options;
- }
- @end
|