| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- /*
- * 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 "FirebaseCore/Extension/FirebaseCoreInternal.h"
- #import "FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h"
- #import "FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h"
- #import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h"
- #import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h"
- #import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h"
- #import "FirebaseRemoteConfig/Sources/RCNPersonalization.h"
- #import "FirebaseRemoteConfig/Tests/Unit/RCNTestUtilities.h"
- #import "Interop/Analytics/Public/FIRAnalyticsInterop.h"
- @interface RCNConfigFetch (ForTest)
- - (NSURLSessionDataTask *)URLSessionDataTaskWithContent:(NSData *)content
- completionHandler:
- (RCNConfigFetcherCompletion)fetcherCompletion;
- - (void)fetchWithUserProperties:(NSDictionary *)userProperties
- completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler;
- @end
- @interface RCNPersonalizationTest : XCTestCase {
- NSDictionary *_configContainer;
- NSMutableArray<NSDictionary *> *_fakeLogs;
- id _analyticsMock;
- RCNPersonalization *_personalization;
- FIRRemoteConfig *_configInstance;
- }
- @end
- @implementation RCNPersonalizationTest
- - (void)setUp {
- [super setUp];
- _configContainer = @{
- RCNFetchResponseKeyEntries : @{
- @"key1" : [[FIRRemoteConfigValue alloc]
- initWithData:[@"value1" dataUsingEncoding:NSUTF8StringEncoding]
- source:FIRRemoteConfigSourceRemote],
- @"key2" : [[FIRRemoteConfigValue alloc]
- initWithData:[@"value2" dataUsingEncoding:NSUTF8StringEncoding]
- source:FIRRemoteConfigSourceRemote],
- @"key3" : [[FIRRemoteConfigValue alloc]
- initWithData:[@"value3" dataUsingEncoding:NSUTF8StringEncoding]
- source:FIRRemoteConfigSourceRemote]
- },
- RCNFetchResponseKeyPersonalizationMetadata : @{
- @"key1" : @{
- kPersonalizationId : @"p13n1",
- kArmIndex : @0,
- kChoiceId : @"id1",
- kGroup : @"BASELINE"
- },
- @"key2" :
- @{kPersonalizationId : @"p13n2", kArmIndex : @1, kChoiceId : @"id2", kGroup : @"P13N"}
- }
- };
- _fakeLogs = [[NSMutableArray alloc] init];
- _analyticsMock = OCMProtocolMock(@protocol(FIRAnalyticsInterop));
- OCMStub([_analyticsMock logEventWithOrigin:kAnalyticsOriginPersonalization
- name:[OCMArg isKindOfClass:[NSString class]]
- parameters:[OCMArg isKindOfClass:[NSDictionary class]]])
- .andDo(^(NSInvocation *invocation) {
- __unsafe_unretained NSDictionary *bundle;
- [invocation getArgument:&bundle atIndex:4];
- [self->_fakeLogs addObject:bundle];
- });
- _personalization = [[RCNPersonalization alloc] initWithAnalytics:_analyticsMock];
- // Always remove the database at the start of testing.
- NSString *DBPath = [RCNTestUtilities remoteConfigPathForTestDatabase];
- id DBMock = OCMClassMock([RCNConfigDBManager class]);
- OCMStub([DBMock remoteConfigPathForDatabase]).andReturn(DBPath);
- RCNConfigContent *configContent = [[RCNConfigContent alloc] initWithDBManager:DBMock];
- // Create a mock FIRRemoteConfig instance.
- _configInstance = OCMPartialMock([[FIRRemoteConfig alloc]
- initWithAppName:@"testApp"
- FIROptions:[[FIROptions alloc] initWithGoogleAppID:@"1:123:ios:test"
- GCMSenderID:@"testSender"]
- namespace:@"namespace"
- DBManager:DBMock
- configContent:configContent
- analytics:_analyticsMock]);
- [_configInstance setValue:[RCNPersonalizationTest mockFetchRequest] forKey:@"_configFetch"];
- }
- - (void)tearDown {
- [super tearDown];
- }
- - (void)testNonPersonalizationKey {
- [_fakeLogs removeAllObjects];
- [_personalization logArmActive:@"key3" config:_configContainer];
- OCMVerify(never(),
- [_analyticsMock logEventWithOrigin:kAnalyticsOriginPersonalization
- name:[OCMArg checkWithBlock:^BOOL(NSString *value) {
- return [value isEqualToString:kExternalEvent] ||
- [value isEqualToString:kInternalEvent];
- }]
- parameters:[OCMArg isKindOfClass:[NSDictionary class]]]);
- XCTAssertEqual([_fakeLogs count], 0);
- }
- - (void)testSinglePersonalizationKey {
- [_fakeLogs removeAllObjects];
- [_personalization logArmActive:@"key1" config:_configContainer];
- OCMVerify(times(2),
- [_analyticsMock logEventWithOrigin:kAnalyticsOriginPersonalization
- name:[OCMArg checkWithBlock:^BOOL(NSString *value) {
- return [value isEqualToString:kExternalEvent] ||
- [value isEqualToString:kInternalEvent];
- }]
- parameters:[OCMArg isKindOfClass:[NSDictionary class]]]);
- XCTAssertEqual([_fakeLogs count], 2);
- NSDictionary *logParams = @{
- kExternalRcParameterParam : @"key1",
- kExternalArmValueParam : @"value1",
- kExternalPersonalizationIdParam : @"p13n1",
- kExternalArmIndexParam : @0,
- kExternalGroupParam : @"BASELINE"
- };
- XCTAssertEqualObjects(_fakeLogs[0], logParams);
- NSDictionary *internalLogParams = @{kInternalChoiceIdParam : @"id1"};
- XCTAssertEqualObjects(_fakeLogs[1], internalLogParams);
- }
- - (void)testMultiplePersonalizationKeys {
- [_fakeLogs removeAllObjects];
- [_personalization logArmActive:@"key1" config:_configContainer];
- [_personalization logArmActive:@"key2" config:_configContainer];
- [_personalization logArmActive:@"key1" config:_configContainer];
- OCMVerify(times(4),
- [_analyticsMock logEventWithOrigin:kAnalyticsOriginPersonalization
- name:[OCMArg checkWithBlock:^BOOL(NSString *value) {
- return [value isEqualToString:kExternalEvent] ||
- [value isEqualToString:kInternalEvent];
- }]
- parameters:[OCMArg isKindOfClass:[NSDictionary class]]]);
- XCTAssertEqual([_fakeLogs count], 4);
- NSDictionary *logParams1 = @{
- kExternalRcParameterParam : @"key1",
- kExternalArmValueParam : @"value1",
- kExternalPersonalizationIdParam : @"p13n1",
- kExternalArmIndexParam : @0,
- kExternalGroupParam : @"BASELINE"
- };
- XCTAssertEqualObjects(_fakeLogs[0], logParams1);
- NSDictionary *internalLogParams1 = @{kInternalChoiceIdParam : @"id1"};
- XCTAssertEqualObjects(_fakeLogs[1], internalLogParams1);
- NSDictionary *logParams2 = @{
- kExternalRcParameterParam : @"key2",
- kExternalArmValueParam : @"value2",
- kExternalPersonalizationIdParam : @"p13n2",
- kExternalArmIndexParam : @1,
- kExternalGroupParam : @"P13N"
- };
- XCTAssertEqualObjects(_fakeLogs[2], logParams2);
- NSDictionary *internalLogParams2 = @{kInternalChoiceIdParam : @"id2"};
- XCTAssertEqualObjects(_fakeLogs[3], internalLogParams2);
- }
- - (void)testRemoteConfigIntegration {
- [_fakeLogs removeAllObjects];
- FIRRemoteConfigFetchAndActivateCompletion fetchAndActivateCompletion =
- ^void(FIRRemoteConfigFetchAndActivateStatus status, NSError *error) {
- OCMVerify(times(4), [self->_analyticsMock
- logEventWithOrigin:kAnalyticsOriginPersonalization
- name:[OCMArg checkWithBlock:^BOOL(NSString *value) {
- return [value isEqualToString:kExternalEvent] ||
- [value isEqualToString:kInternalEvent];
- }]
- parameters:[OCMArg isKindOfClass:[NSDictionary class]]]);
- XCTAssertEqual([self->_fakeLogs count], 4);
- NSDictionary *logParams1 = @{
- kExternalRcParameterParam : @"key1",
- kExternalArmValueParam : @"value1",
- kExternalPersonalizationIdParam : @"p13n1",
- kExternalArmIndexParam : @0,
- kExternalGroupParam : @"BASELINE"
- };
- XCTAssertEqualObjects(self->_fakeLogs[0], logParams1);
- NSDictionary *internalLogParams1 = @{kInternalChoiceIdParam : @"id1"};
- XCTAssertEqualObjects(self->_fakeLogs[1], internalLogParams1);
- NSDictionary *logParams2 = @{
- kExternalRcParameterParam : @"key1",
- kExternalArmValueParam : @"value1",
- kExternalPersonalizationIdParam : @"p13n1",
- kExternalArmIndexParam : @0,
- kExternalGroupParam : @"BASELINE"
- };
- XCTAssertEqualObjects(self->_fakeLogs[2], logParams2);
- NSDictionary *internalLogParams2 = @{kInternalChoiceIdParam : @"id2"};
- XCTAssertEqualObjects(self->_fakeLogs[3], internalLogParams2);
- };
- [_configInstance fetchAndActivateWithCompletionHandler:fetchAndActivateCompletion];
- [_configInstance configValueForKey:@"key1"];
- [_configInstance configValueForKey:@"key2"];
- }
- + (id)mockFetchRequest {
- id configFetch = OCMClassMock([RCNConfigFetch class]);
- OCMStub([configFetch fetchConfigWithExpirationDuration:0 completionHandler:OCMOCK_ANY])
- .ignoringNonObjectArgs()
- .andDo(^(NSInvocation *invocation) {
- __unsafe_unretained FIRRemoteConfigFetchCompletion handler;
- [invocation getArgument:&handler atIndex:3];
- [configFetch fetchWithUserProperties:[[NSDictionary alloc] init] completionHandler:handler];
- });
- OCMExpect([configFetch
- URLSessionDataTaskWithContent:[OCMArg any]
- completionHandler:[RCNPersonalizationTest mockResponseHandler]])
- .andReturn(nil);
- return configFetch;
- }
- + (id)mockResponseHandler {
- NSDictionary *response = @{
- RCNFetchResponseKeyState : RCNFetchResponseKeyStateUpdate,
- RCNFetchResponseKeyEntries : @{@"key1" : @"value1", @"key2" : @"value2", @"key3" : @"value3"},
- RCNFetchResponseKeyPersonalizationMetadata : @{
- @"key1" : @{
- kPersonalizationId : @"p13n1",
- kArmIndex : @0,
- kChoiceId : @"id1",
- kGroup : @"BASELINE"
- },
- @"key2" :
- @{kPersonalizationId : @"p13n2", kArmIndex : @1, kChoiceId : @"id2", kGroup : @"P13N"}
- }
- };
- return [OCMArg invokeBlockWithArgs:[NSJSONSerialization dataWithJSONObject:response
- options:0
- error:nil],
- [[NSHTTPURLResponse alloc]
- initWithURL:[NSURL URLWithString:@"https://firebase.com"]
- statusCode:200
- HTTPVersion:nil
- headerFields:@{@"etag" : @"etag1"}],
- [NSNull null], nil];
- }
- @end
|