source/UberCoreTests/LoginManagerTests.swift (272 lines of code) (raw):

// // LoginManagerTests.swift // UberRides // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. import XCTest import CoreLocation import OHHTTPStubs import OHHTTPStubsSwift import WebKit @testable import UberCore class LoginManagerTests: XCTestCase { private let timeout: Double = 2 override func setUp() { super.setUp() Configuration.plistName = "testInfo" Configuration.restoreDefaults() Configuration.shared.isSandbox = true } override func tearDown() { Configuration.restoreDefaults() super.tearDown() } func testRidesAppDelegateContainsManager_afterNativeLogin() { let loginManager = LoginManager(loginType: .native) loginManager.login(requestedScopes: [.profile], presentingViewController: nil, completion: nil) XCTAssert(UberAppDelegate.shared.loginManager is LoginManager, "Expected RidesAppDelegate to have loginManager instance") } func testAuthentictorIsImplicit_whenLoginWithImplicitType() { let loginManager = LoginManager(loginType: .implicit) let presentingViewController = UIViewController() loginManager.login(requestedScopes: [.profile], presentingViewController: presentingViewController, completion: nil) XCTAssert(loginManager.authenticator is ImplicitGrantAuthenticator) XCTAssertTrue(loginManager.loggingIn) } func testAuthentictorIsAuthorizationCode_whenLoginWithAuthorizationCodeType() { let loginManager = LoginManager(loginType: .authorizationCode) let presentingViewController = UIViewController() loginManager.login(requestedScopes: [.profile], presentingViewController: presentingViewController, completion: nil) XCTAssert(loginManager.authenticator is AuthorizationCodeGrantAuthenticator) XCTAssertTrue(loginManager.loggingIn) } func testLoginFails_whenLoggingIn() { let expectation = self.expectation(description: "loginCompletion called") let loginCompletion: ((_ accessToken: AccessToken?, _ error: NSError?) -> Void) = { token, error in guard let error = error else { XCTFail() return } XCTAssertEqual(error.code, UberAuthenticationErrorType.unavailable.rawValue) expectation.fulfill() } let loginManagerMock = LoginManagerPartialMock() loginManagerMock.executeLoginClosure = { completionHandler in completionHandler?(nil, UberAuthenticationErrorFactory.errorForType(ridesAuthenticationErrorType: .unavailable)) } loginManagerMock.login(requestedScopes: [.profile], presentingViewController: nil, prefillValues: nil, completion: loginCompletion) waitForExpectations(timeout: 0.2, handler: nil) } func testOpenURLFails_whenInvalidSource() { let loginManager = LoginManager(loginType: .native) let testApp = UIApplication.shared guard let testURL = URL(string: "http://www.google.com") else { XCTFail() return } let testSourceApplication = "com.not.uber.app" let testAnnotation = "annotation" XCTAssertFalse(loginManager.application(testApp, open: testURL, sourceApplication: testSourceApplication, annotation: testAnnotation)) } func testOpenURLFails_whenNotNativeType() { let loginManager = LoginManager(loginType: .implicit) let testApp = UIApplication.shared guard let testURL = URL(string: "http://www.google.com") else { XCTFail() return } let testSourceApplication = "com.ubercab.foo" let testAnnotation = "annotation" XCTAssertFalse(loginManager.application(testApp, open: testURL, sourceApplication: testSourceApplication, annotation: testAnnotation)) } func testOpenURLSuccess_rides() { let loginManager = LoginManager(loginType: .native, productFlowPriority: [UberAuthenticationProductFlow(.rides)]) let testApp = UIApplication.shared guard let testURL = URL(string: "http://www.google.com") else { XCTFail() return } let testSourceApplication = "com.ubercab.foo" let testAnnotation = "annotation" let authenticatorMock = RidesNativeAuthenticatorPartialStub(scopes: [.profile]) authenticatorMock.consumeResponseCompletionValue = (nil, nil) loginManager.authenticator = authenticatorMock loginManager.loggingIn = true XCTAssertTrue(loginManager.application(testApp, open: testURL, sourceApplication: testSourceApplication, annotation: testAnnotation)) XCTAssertFalse(loginManager.loggingIn) XCTAssertNil(loginManager.authenticator) } func testOpenURLSuccess_eats() { let loginManager = LoginManager(loginType: .native, productFlowPriority: [UberAuthenticationProductFlow(.eats)]) let testApp = UIApplication.shared guard let testURL = URL(string: "http://www.google.com") else { XCTFail() return } let testSourceApplication = "com.ubercab.UberEats" let testAnnotation = "annotation" let authenticatorMock = EatsNativeAuthenticatorPartialStub(scopes: [.profile]) authenticatorMock.consumeResponseCompletionValue = (nil, nil) loginManager.authenticator = authenticatorMock loginManager.loggingIn = true XCTAssertTrue(loginManager.application(testApp, open: testURL, sourceApplication: testSourceApplication, annotation: testAnnotation)) XCTAssertFalse(loginManager.loggingIn) XCTAssertNil(loginManager.authenticator) } func testCancelLoginNotCalled_whenNotEnteringForeground() { let loginManager = LoginManager(loginType: .native) loginManager.loggingIn = true loginManager.applicationDidBecomeActive() XCTAssertNil(loginManager.authenticator) XCTAssertTrue(loginManager.loggingIn) } func testCancelLoginCalled_whenDidBecomeActive() { let loginManager = LoginManager(loginType: .native) loginManager.loggingIn = true loginManager.applicationWillEnterForeground() loginManager.applicationDidBecomeActive() XCTAssertNil(loginManager.authenticator) XCTAssertFalse(loginManager.loggingIn) } func testNativeLoginCompletionDoesFallback_whenUnavailableError_withConfiguration_alwaysUseAuthCodeFallback() { Configuration.shared.alwaysUseAuthCodeFallback = true let scopes = [UberScope.historyLite] let loginManager = LoginManager(loginType: .native) let nativeAuthenticatorStub = RidesNativeAuthenticatorPartialStub(scopes: []) nativeAuthenticatorStub.consumeResponseCompletionValue = (nil, UberAuthenticationErrorFactory.errorForType(ridesAuthenticationErrorType: .unavailable)) loginManager.authenticator = nativeAuthenticatorStub let viewController = UIViewController() loginManager.login(requestedScopes: scopes, presentingViewController: viewController, completion: nil) XCTAssertEqual(loginManager.loginType, LoginType.authorizationCode) } func testNativeLoginCompletionDoesFallback_whenUnavailableError_withPrivelegedScopes_rides() { Configuration.shared.useFallback = true let scopes = [UberScope.request] let loginManager = LoginManager(loginType: .native, productFlowPriority: [UberAuthenticationProductFlow(.rides)]) let nativeAuthenticatorStub = RidesNativeAuthenticatorPartialStub(scopes: []) nativeAuthenticatorStub.consumeResponseCompletionValue = (nil, UberAuthenticationErrorFactory.errorForType(ridesAuthenticationErrorType: .unavailable)) loginManager.authenticator = nativeAuthenticatorStub let viewController = UIViewController() loginManager.login(requestedScopes: scopes, presentingViewController: viewController, completion: nil) XCTAssertEqual(loginManager.loginType, LoginType.authorizationCode) } func testNativeLoginCompletionDoesFallback_whenUnavailableError_withPrivelegedScopes_eats() { Configuration.shared.useFallback = true let scopes = [UberScope.request] let loginManager = LoginManager(loginType: .native, productFlowPriority: [UberAuthenticationProductFlow(.eats)]) let nativeAuthenticatorStub = EatsNativeAuthenticatorPartialStub(scopes: []) nativeAuthenticatorStub.consumeResponseCompletionValue = (nil, UberAuthenticationErrorFactory.errorForType(ridesAuthenticationErrorType: .unavailable)) loginManager.authenticator = nativeAuthenticatorStub let viewController = UIViewController() loginManager.login(requestedScopes: scopes, presentingViewController: viewController, completion: nil) XCTAssertEqual(loginManager.loginType, LoginType.authorizationCode) } func testNativeLoginCompletionDoesFallback_whenUnavailableError_withGeneralScopes_rides() { let scopes = [UberScope.profile] let loginManager = LoginManager(loginType: .native, productFlowPriority: [UberAuthenticationProductFlow(.rides)]) let nativeAuthenticatorStub = RidesNativeAuthenticatorPartialStub(scopes: []) nativeAuthenticatorStub.consumeResponseCompletionValue = (nil, UberAuthenticationErrorFactory.errorForType(ridesAuthenticationErrorType: .unavailable)) loginManager.authenticator = nativeAuthenticatorStub let viewController = UIViewController() loginManager.login(requestedScopes: scopes, presentingViewController: viewController, completion: nil) XCTAssertEqual(loginManager.loginType, LoginType.implicit) } func testNativeLoginCompletionDoesFallback_whenUnavailableError_withGeneralScopes_eats() { let scopes = [UberScope.profile] let loginManager = LoginManager(loginType: .native, productFlowPriority: [UberAuthenticationProductFlow(.eats)]) let nativeAuthenticatorStub = EatsNativeAuthenticatorPartialStub(scopes: []) nativeAuthenticatorStub.consumeResponseCompletionValue = (nil, UberAuthenticationErrorFactory.errorForType(ridesAuthenticationErrorType: .unavailable)) loginManager.authenticator = nativeAuthenticatorStub let viewController = UIViewController() loginManager.login(requestedScopes: scopes, presentingViewController: viewController, completion: nil) XCTAssertEqual(loginManager.loginType, LoginType.implicit) } func testImplicitLogin_executesParRequest() { let expectation = expectation(description: "Implicit login PAR endpoint called") stub(condition: isPath("/oauth/v2/par")) { _ in expectation.fulfill() return HTTPStubsResponse() } let loginManager = LoginManager( loginType: .implicit, productFlowPriority: [UberAuthenticationProductFlow(.eats)] ) loginManager.login( requestedScopes: [UberScope.profile], presentingViewController: UIViewController(), prefillValues: Prefill(email: "test@test.com"), completion: nil ) waitForExpectations(timeout: 0.2, handler: nil) } func testAuthorizationCodeLogin_executesParRequest() { let expectation = expectation(description: "Authorization code login PAR endpoint called") stub(condition: isPath("/oauth/v2/par")) { _ in expectation.fulfill() return HTTPStubsResponse() } let loginManager = LoginManager( loginType: .authorizationCode, productFlowPriority: [UberAuthenticationProductFlow(.eats)] ) loginManager.login( requestedScopes: [UberScope.profile], presentingViewController: UIViewController(), prefillValues: Prefill(email: "test@test.com"), completion: nil ) waitForExpectations(timeout: 0.2, handler: nil) } func testLogin_withNoPrefillValues_doesNotExecutesParRequest() { let expectation = expectation(description: "No prefill login PAR endpoint not called") expectation.isInverted = true stub(condition: isPath("/oauth/v2/par")) { _ in expectation.fulfill() return HTTPStubsResponse() } let loginManager = LoginManager( loginType: .authorizationCode, productFlowPriority: [UberAuthenticationProductFlow(.eats)] ) loginManager.login( requestedScopes: [UberScope.profile], presentingViewController: UIViewController(), prefillValues: nil, completion: nil ) waitForExpectations(timeout: 0.2, handler: nil) } func testLogin_withEmptyPrefillValues_doesNotExecutesParRequest() { let expectation = expectation(description: "EmptyPrefill login PAR endpoint not called") expectation.isInverted = true stub(condition: isPath("/oauth/v2/par")) { _ in expectation.fulfill() return HTTPStubsResponse() } let loginManager = LoginManager( loginType: .authorizationCode, productFlowPriority: [UberAuthenticationProductFlow(.eats)] ) loginManager.login( requestedScopes: [UberScope.profile], presentingViewController: UIViewController(), prefillValues: Prefill(), completion: nil ) waitForExpectations(timeout: 0.2, handler: nil) } func testNativeLogin_doesNotExecuteParRequest() { let expectation = expectation(description: "Native login PAR endpoint not called") expectation.isInverted = true stub(condition: isPath("/oauth/v2/par")) { _ in expectation.fulfill() return HTTPStubsResponse() } let loginManager = LoginManager( loginType: .native, productFlowPriority: [UberAuthenticationProductFlow(.eats)] ) loginManager.login( requestedScopes: [UberScope.profile], presentingViewController: UIViewController(), prefillValues: Prefill(), completion: nil ) waitForExpectations(timeout: 0.2, handler: nil) } }