diff --git a/.codecov.yml b/.codecov.yml index 0410dd13d0..f6e03a6c06 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -80,6 +80,7 @@ ignore: - "shared" - "native" - "libs/**/*Test*/*" + - "**/TestSetupUtils*" flag_management: default_rules: # the rules that will be followed for any flag added, generally @@ -110,4 +111,4 @@ component_management: - "libs/SmartStore/SmartStore/" - component_id: MobileSync paths: - - "libs/MobileSync/MobileSync/" \ No newline at end of file + - "libs/MobileSync/MobileSync/" diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.m index ac7ae05152..b855bd9e50 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Common/SalesforceSDKManager.m @@ -195,6 +195,16 @@ + (void)initialize { + (void)initializeSDK { [self initializeSDKWithClass:InstanceClass]; +#ifdef DEBUG + // For debug app builds only, use test instant log in if applicable. + NSArray *arguments = [[NSProcessInfo processInfo] arguments]; + if ([arguments containsObject:@"-creds"]) { + NSString *creds = arguments[[arguments indexOfObject:@"-creds"] + 1]; + + [TestSetupUtils populateAuthCredentialsFromString:creds initializeSdk:NO]; + [TestSetupUtils synchronousAuthRefreshWithUserDidLoginNotification:YES]; + } +#endif } + (void)initializeSDKWithClass:(Class)className { @@ -231,6 +241,7 @@ + (instancetype)sharedManager { + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ + // For dev support Method sfsdkMotionEndedMethod = class_getInstanceMethod([UIWindow class], @selector(sfsdk_motionEnded:withEvent:)); IMP sfsdkMotionEndedImplementation = method_getImplementation(sfsdkMotionEndedMethod); diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/TestSetupUtils.h b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/TestSetupUtils.h index 7bfd1428ed..db654efbcc 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/TestSetupUtils.h +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/TestSetupUtils.h @@ -53,13 +53,45 @@ NS_ASSUME_NONNULL_BEGIN + (SFSDKTestCredentialsData *)populateAuthCredentialsFromConfigFileForClass:(Class)testClass; /** - Performs a synchronous refresh of the OAuth credentials, which will stage the remaining auth - data (access token, User ID, Org ID, etc.) in SFUserAccountManager. - `populateAuthCredentialsFromConfigFile` is required to run once before this method will attempt - to refresh authentication. + Loads a set of auth credentials from the provided JSON string, and configures + SFUserAccountManager and the current account with the data from that JSON. + Salesforce Mobile SDK will be initialized while populating test credentials. + @param testCredentialsJsonString The test credentials JSON as a string. + @return The configuration data used to configure SFUserAccountManager (useful + e.g. for hybrid apps which need the data to bootstrap SFHybridViewController). + */ ++ (SFSDKTestCredentialsData *)populateAuthCredentialsFromString:(NSString *)testCredentialsJsonString; + +/** + Loads a set of auth credentials from the provided JSON string, and configures + SFUserAccountManager and the current account with the data from that JSON. + @param testCredentialsJsonString The test credentials JSON as a string. + @param initializeSdk Indicates if Salesfore Mobile SDK should be initialized + while populating test credentials. + @return The configuration data used to configure SFUserAccountManager (useful + e.g. for hybrid apps which need the data to bootstrap SFHybridViewController). + */ ++ (SFSDKTestCredentialsData *)populateAuthCredentialsFromString:(NSString *)testCredentialsJsonString initializeSdk:(BOOL)initializeSdk; + +/** + Performs a synchronous refresh of the OAuth credentials, which will stage the + remaining auth data (access token, User ID, Org ID, etc.) in + SFUserAccountManager. `populateAuthCredentialsFromConfigFile` + is required to run once before this method will attempt to refresh authentication. + The "user did log in" notification will not be posted. */ + (void)synchronousAuthRefresh; +/** + Performs a synchronous refresh of the OAuth credentials, which will stage the + remaining auth data (access token, User ID, Org ID, etc.) in + SFUserAccountManager. `populateAuthCredentialsFromConfigFile` + is required to run once before this method will attempt to refresh authentication. + @param postUserDidLogIn Indicates if the "user did log in" notification should + be posted. + */ ++ (void)synchronousAuthRefreshWithUserDidLoginNotification:(BOOL)postUserDidLogIn; + + (SFOAuthCredentials *)newClientCredentials; @end diff --git a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/TestSetupUtils.m b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/TestSetupUtils.m index 2100789ced..d75a45314d 100644 --- a/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/TestSetupUtils.m +++ b/libs/SalesforceSDKCore/SalesforceSDKCore/Classes/Test/TestSetupUtils.m @@ -55,6 +55,71 @@ + (SFSDKTestCredentialsData *)populateAuthCredentialsFromConfigFileForClass:(Cla NSFileManager *fm = [NSFileManager defaultManager]; NSData *tokenJson = [fm contentsAtPath:tokenPath]; id jsonResponse = [SFJsonUtils objectFromJSONData:tokenJson]; + + return [TestSetupUtils authCredentialsFromJson:jsonResponse initializeSdk:YES]; + +} + ++ (SFSDKTestCredentialsData *)populateAuthCredentialsFromString:(NSString *)testCredentialsJsonString { + return [self populateAuthCredentialsFromString:testCredentialsJsonString initializeSdk:YES]; +} + ++ (SFSDKTestCredentialsData *)populateAuthCredentialsFromString:(NSString *)testCredentialsJsonString initializeSdk:(BOOL)initializeSdk { + + return [TestSetupUtils authCredentialsFromJson:[SFJsonUtils objectFromJSONString:testCredentialsJsonString] initializeSdk:initializeSdk]; +} + ++ (void)synchronousAuthRefresh { + [self synchronousAuthRefreshWithUserDidLoginNotification:NO]; +} + ++ (void)synchronousAuthRefreshWithUserDidLoginNotification:(BOOL)postUserDidLogIn +{ + // All of the setup and validation of prerequisite auth state is done in populateAuthCredentialsFromConfigFile. + // Make sure that method has run before this one. + NSAssert(credentials!=nil, @"You must call populateAuthCredentialsFromConfigFileForClass before synchronousAuthRefresh"); + __block SFSDKTestRequestListener *authListener = [[SFSDKTestRequestListener alloc] init]; + __block SFUserAccount *user = nil; + [[SFUserAccountManager sharedInstance] + refreshCredentials:credentials + completion:^(SFOAuthInfo *authInfo, SFUserAccount *userAccount) { + authListener.returnStatus = kTestRequestStatusDidLoad; + user = userAccount; + // Ensure tests don't change/corrupt the current user credentials. + if (user.credentials.refreshToken == nil) { + user.credentials = credentials; + } + if (postUserDidLogIn) { + NSDictionary *userInfo = @{kSFNotificationUserInfoAccountKey: userAccount, + kSFNotificationUserInfoAuthTypeKey: authInfo}; + [[NSNotificationCenter defaultCenter] postNotificationName:kSFNotificationUserDidLogIn + object:[SFUserAccountManager sharedInstance] + userInfo:userInfo]; + [[SFUserAccountManager sharedInstance] stopCurrentAuthentication:^(BOOL result){}]; + } + } failure:^(SFOAuthInfo *authInfo, NSError *error) { + authListener.lastError = error; + authListener.returnStatus = kTestRequestStatusDidFail; + }]; + [authListener waitForCompletion]; + [[SFUserAccountManager sharedInstance] setCurrentUserInternal:user]; + NSAssert([authListener.returnStatus isEqualToString:kTestRequestStatusDidLoad], @"After auth attempt, expected status '%@', got '%@'", + kTestRequestStatusDidLoad, + authListener.returnStatus); +} + ++ (SFOAuthCredentials *)newClientCredentials { + + NSString *identifier = [[SFUserAccountManager sharedInstance] uniqueUserAccountIdentifier:[SFUserAccountManager sharedInstance].oauthClientId]; + SFOAuthCredentials *creds = [[SFOAuthCredentials alloc] initWithIdentifier:identifier clientId:[SFUserAccountManager sharedInstance].oauthClientId encrypted:YES]; + creds.clientId = [SFUserAccountManager sharedInstance].oauthClientId; + creds.redirectUri = [SFUserAccountManager sharedInstance].oauthCompletionUrl; + creds.domain = [SFUserAccountManager sharedInstance].loginHost; + creds.accessToken = nil; + return creds; +} + ++ (SFSDKTestCredentialsData *)authCredentialsFromJson:(id)jsonResponse initializeSdk:(BOOL)initializeSdk { NSAssert(jsonResponse != nil, @"Error parsing JSON from config file: %@", [SFJsonUtils lastError]); NSDictionary *dictResponse = (NSDictionary *)jsonResponse; SFSDKTestCredentialsData *credsData = [[SFSDKTestCredentialsData alloc] initWithDict:dictResponse]; @@ -65,12 +130,14 @@ + (SFSDKTestCredentialsData *)populateAuthCredentialsFromConfigFileForClass:(Cla nil != credsData.identityUrl && nil != credsData.instanceUrl, @"config credentials are missing! %@", dictResponse); - + // check whether the test config file has never been edited NSAssert(![credsData.refreshToken isEqualToString:@"__INSERT_TOKEN_HERE__"], @"You need to obtain credentials for your test org and replace test_credentials.json"); - [SalesforceSDKManager initializeSDK]; - + if (initializeSdk) { + [SalesforceSDKManager initializeSDK]; + } + // Note: We need to fix this inconsistency for tests in the long run.There should be a clean way to refresh appConfigs for tests. The configs should apply across all components that need the config. SFSDKAppConfig *appconfig = [[SFSDKAppConfig alloc] init]; appconfig.oauthRedirectURI = credsData.redirectUri; @@ -98,41 +165,4 @@ + (SFSDKTestCredentialsData *)populateAuthCredentialsFromConfigFileForClass:(Cla return credsData; } -+ (void)synchronousAuthRefresh -{ - // All of the setup and validation of prerequisite auth state is done in populateAuthCredentialsFromConfigFile. - // Make sure that method has run before this one. - NSAssert(credentials!=nil, @"You must call populateAuthCredentialsFromConfigFileForClass before synchronousAuthRefresh"); - __block SFSDKTestRequestListener *authListener = [[SFSDKTestRequestListener alloc] init]; - __block SFUserAccount *user = nil; - [[SFUserAccountManager sharedInstance] - refreshCredentials:credentials - completion:^(SFOAuthInfo *authInfo, SFUserAccount *userAccount) { - authListener.returnStatus = kTestRequestStatusDidLoad; - user = userAccount; - // Ensure tests don't change/corrupt the current user credentials. - if(user.credentials.refreshToken == nil) { - user.credentials = credentials; - } - } failure:^(SFOAuthInfo *authInfo, NSError *error) { - authListener.lastError = error; - authListener.returnStatus = kTestRequestStatusDidFail; - }]; - [authListener waitForCompletion]; - [[SFUserAccountManager sharedInstance] setCurrentUserInternal:user]; - NSAssert([authListener.returnStatus isEqualToString:kTestRequestStatusDidLoad], @"After auth attempt, expected status '%@', got '%@'", - kTestRequestStatusDidLoad, - authListener.returnStatus); -} - -+ (SFOAuthCredentials *)newClientCredentials { - - NSString *identifier = [[SFUserAccountManager sharedInstance] uniqueUserAccountIdentifier:[SFUserAccountManager sharedInstance].oauthClientId]; - SFOAuthCredentials *creds = [[SFOAuthCredentials alloc] initWithIdentifier:identifier clientId:[SFUserAccountManager sharedInstance].oauthClientId encrypted:YES]; - creds.clientId = [SFUserAccountManager sharedInstance].oauthClientId; - creds.redirectUri = [SFUserAccountManager sharedInstance].oauthCompletionUrl; - creds.domain = [SFUserAccountManager sharedInstance].loginHost; - creds.accessToken = nil; - return creds; -} @end