Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(unit tests): Adding additional unit tests #3291

Merged
merged 8 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,6 @@
BlueprintName = "AWSCognitoAuthPluginUnitTests"
ReferencedContainer = "container:">
</BuildableReference>
<SkippedTests>
<Test
Identifier = "EscapeHatchTests">
</Test>
</SkippedTests>
</TestableReference>
<TestableReference
skipped = "NO">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,24 +76,6 @@ public struct AWSAuthCognitoSession: AuthSession,

}

/// Internal Helpers for managing session tokens
internal extension AWSAuthCognitoSession {
func areTokensExpiring(in seconds: TimeInterval? = nil) -> Bool {
thisisabhash marked this conversation as resolved.
Show resolved Hide resolved

guard let tokens = try? userPoolTokensResult.get(),
let idTokenClaims = try? AWSAuthService().getTokenClaims(tokenString: tokens.idToken).get(),
let accessTokenClaims = try? AWSAuthService().getTokenClaims(tokenString: tokens.idToken).get(),
let idTokenExpiration = idTokenClaims["exp"]?.doubleValue,
let accessTokenExpiration = accessTokenClaims["exp"]?.doubleValue else {
return true
}

// If the session expires < X minutes return it
return (Date(timeIntervalSince1970: idTokenExpiration).compare(Date(timeIntervalSinceNow: seconds ?? 0)) == .orderedDescending &&
Date(timeIntervalSince1970: accessTokenExpiration).compare(Date(timeIntervalSinceNow: seconds ?? 0)) == .orderedDescending)
}
}

extension AWSAuthCognitoSession: Equatable {
public static func == (lhs: AWSAuthCognitoSession, rhs: AWSAuthCognitoSession) -> Bool {
switch (lhs.getCognitoTokens(), rhs.getCognitoTokens()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ public struct AWSCognitoUserPoolTokens: AuthCognitoTokens {
case (.some(let idTokenValue), .none):
expirationDoubleValue = idTokenValue
case (.none, .none):
expirationDoubleValue = 0
expirationDoubleValue = Date().timeIntervalSince1970
}

self.expiration = Date().addingTimeInterval(TimeInterval((expirationDoubleValue ?? 0)))
self.expiration = Date(timeIntervalSince1970: TimeInterval(expirationDoubleValue))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,6 @@ struct AuthCognitoSignedOutSessionHelper {
return authSession
}

/// Guest/SignedOut session with any unhandled error
///
/// The unhandled error is passed as identityId and aws credentials result. UserSub and Cognito Tokens will still
/// have signOut error.
///
/// - Parameter error: Unhandled error
/// - Returns: Session will have isSignedIn = false
private static func makeSignedOutSession(withUnhandledError error: AuthError) -> AWSAuthCognitoSession {

let identityIdError = error
let awsCredentialsError = error

let tokensError = makeCognitoTokensSignedOutError()

let authSession = AWSAuthCognitoSession(isSignedIn: false,
identityIdResult: .failure(identityIdError),
awsCredentialsResult: .failure(awsCredentialsError),
cognitoTokensResult: .failure(tokensError))
return authSession
}

/// Guest/SignOut session when the guest access is not enabled.
/// - Returns: Session with isSignedIn = false
static func makeSessionWithNoGuestAccess() -> AWSAuthCognitoSession {
Expand All @@ -68,26 +47,6 @@ struct AuthCognitoSignedOutSessionHelper {
return authSession
}

private static func makeOfflineSignedOutSession() -> AWSAuthCognitoSession {
let identityIdError = AuthError.service(
AuthPluginErrorConstants.identityIdOfflineError.errorDescription,
AuthPluginErrorConstants.identityIdOfflineError.recoverySuggestion,
AWSCognitoAuthError.network)

let awsCredentialsError = AuthError.service(
AuthPluginErrorConstants.awsCredentialsOfflineError.errorDescription,
AuthPluginErrorConstants.awsCredentialsOfflineError.recoverySuggestion,
AWSCognitoAuthError.network)

let tokensError = makeCognitoTokensSignedOutError()

let authSession = AWSAuthCognitoSession(isSignedIn: false,
identityIdResult: .failure(identityIdError),
awsCredentialsResult: .failure(awsCredentialsError),
cognitoTokensResult: .failure(tokensError))
return authSession
}

/// Guest/SignedOut session with couldnot retreive either aws credentials or identity id.
/// - Returns: Session will have isSignedIn = false
private static func makeSignedOutSessionWithServiceIssue() -> AWSAuthCognitoSession {
Expand All @@ -109,13 +68,6 @@ struct AuthCognitoSignedOutSessionHelper {
return authSession
}

private static func makeUserSubSignedOutError() -> AuthError {
let userSubError = AuthError.signedOut(
AuthPluginErrorConstants.userSubSignOutError.errorDescription,
AuthPluginErrorConstants.userSubSignOutError.recoverySuggestion)
return userSubError
}

private static func makeCognitoTokensSignedOutError() -> AuthError {
let tokensError = AuthError.signedOut(
AuthPluginErrorConstants.cognitoTokensSignOutError.errorDescription,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class HostedUIASWebAuthenticationSession: NSObject, HostedUISessionBehavior {
callback: @escaping (Result<[URLQueryItem], HostedUIError>) -> Void) {
#if os(iOS) || os(macOS)
self.webPresentation = presentationAnchor
let aswebAuthenticationSession = ASWebAuthenticationSession(
let aswebAuthenticationSession = createAuthenticationSession(
url: url,
callbackURLScheme: callbackScheme,
completionHandler: { url, error in
Expand Down Expand Up @@ -58,6 +58,16 @@ class HostedUIASWebAuthenticationSession: NSObject, HostedUISessionBehavior {
}

#if os(iOS) || os(macOS)
var authenticationSessionFactory = ASWebAuthenticationSession.init(url:callbackURLScheme:completionHandler:)

private func createAuthenticationSession(
url: URL,
callbackURLScheme: String?,
completionHandler: @escaping ASWebAuthenticationSession.CompletionHandler
) -> ASWebAuthenticationSession {
return authenticationSessionFactory(url, callbackURLScheme, completionHandler)
}

private func convertHostedUIError(_ error: Error) -> HostedUIError {
if let asWebAuthError = error as? ASWebAuthenticationSessionError {
switch asWebAuthError.code {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,122 @@ class MigrateLegacyCredentialStoreTests: XCTestCase {

await fulfillment(
of: [migrationCompletionInvoked],

timeout: 0.1
)
}

/// - Given: A credential store with an invalid environment
/// - When: The migration legacy store action is executed
/// - Then: An error event of type configuration is dispatched
func testExecute_withInvalidEnvironment_shouldDispatchError() async {
let expectation = expectation(description: "noEnvironment")
let action = MigrateLegacyCredentialStore()
await action.execute(
withDispatcher: MockDispatcher { event in
guard let event = event as? CredentialStoreEvent,
case let .throwError(error) = event.eventType else {
XCTFail("Expected failure due to no CredentialEnvironment")
expectation.fulfill()
return
}
XCTAssertEqual(error, .configuration(message: AuthPluginErrorConstants.configurationError))
expectation.fulfill()
},
environment: MockInvalidEnvironment()
)
await fulfillment(of: [expectation], timeout: 1)
}

/// - Given: A credential store with an environment that only has identity pool
/// - When: The migration legacy store action is executed
/// - Then:
/// - A .loadCredentialStore event with type .amplifyCredentials is dispatched
/// - An .identityPoolOnly credential is saved
func testExecute_withoutUserPool_andWithoutLoginsTokens_shouldDispatchLoadEvent() async {
let expectation = expectation(description: "noUserPoolTokens")
let action = MigrateLegacyCredentialStore()
await action.execute(
withDispatcher: MockDispatcher { event in
guard let event = event as? CredentialStoreEvent,
case .loadCredentialStore(let type) = event.eventType else {
XCTFail("Expected .loadCredentialStore")
expectation.fulfill()
return
}
XCTAssertEqual(type, .amplifyCredentials)
expectation.fulfill()
},
environment: CredentialEnvironment(
authConfiguration: .identityPools(.testData),
credentialStoreEnvironment: BasicCredentialStoreEnvironment(
amplifyCredentialStoreFactory: {
MockAmplifyCredentialStoreBehavior(
saveCredentialHandler: { codableCredentials in
guard let amplifyCredentials = codableCredentials as? AmplifyCredentials,
case .identityPoolOnly(_, let credentials) = amplifyCredentials else {
XCTFail("Expected .identityPoolOnly")
return
}
XCTAssertFalse(credentials.sessionToken.isEmpty)
}
)
},
legacyKeychainStoreFactory: { _ in
MockKeychainStoreBehavior(data: "hostedUI")
}),
logger: MigrateLegacyCredentialStore.log
)
)
await fulfillment(of: [expectation], timeout: 1)
}

/// - Given: A credential store with an environment that only has identity pool
/// - When: The migration legacy store action is executed
/// - A .loadCredentialStore event with type .amplifyCredentials is dispatched
/// - An .identityPoolWithFederation credential is saved
func testExecute_withoutUserPool_andWithLoginsTokens_shouldDispatchLoadEvent() async {
let expectation = expectation(description: "noUserPoolTokens")
let action = MigrateLegacyCredentialStore()
await action.execute(
withDispatcher: MockDispatcher { event in
guard let event = event as? CredentialStoreEvent,
case .loadCredentialStore(let type) = event.eventType else {
XCTFail("Expected .loadCredentialStore")
expectation.fulfill()
return
}
XCTAssertEqual(type, .amplifyCredentials)
expectation.fulfill()
},
environment: CredentialEnvironment(
authConfiguration: .identityPools(.testData),
credentialStoreEnvironment: BasicCredentialStoreEnvironment(
amplifyCredentialStoreFactory: {
MockAmplifyCredentialStoreBehavior(
saveCredentialHandler: { codableCredentials in
guard let amplifyCredentials = codableCredentials as? AmplifyCredentials,
case .identityPoolWithFederation(let token, _, _) = amplifyCredentials else {
XCTFail("Expected .identityPoolWithFederation")
return
}

XCTAssertEqual(token.token, "token")
XCTAssertEqual(token.provider.userPoolProviderName, "provider")
}
)
},
legacyKeychainStoreFactory: { _ in
let data = try! JSONEncoder().encode([
"provider": "token"
])
return MockKeychainStoreBehavior(
data: String(decoding: data, as: UTF8.self)
)
}),
logger: action.log
)
)
await fulfillment(of: [expectation], timeout: 1)
}
}
Loading
Loading