218 lines
6.4 KiB
Swift
218 lines
6.4 KiB
Swift
//
|
|
// FeedlyLogoutOperationTests.swift
|
|
// AccountTests
|
|
//
|
|
// Created by Kiel Gillard on 15/11/19.
|
|
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
|
|
//
|
|
|
|
import XCTest
|
|
@testable import Account
|
|
import RSCore
|
|
import Secrets
|
|
|
|
class FeedlyLogoutOperationTests: XCTestCase {
|
|
|
|
private var account: Account!
|
|
private let support = FeedlyTestSupport()
|
|
|
|
override func setUp() {
|
|
super.setUp()
|
|
account = support.makeTestAccount()
|
|
}
|
|
|
|
override func tearDown() {
|
|
if let account = account {
|
|
support.destroy(account)
|
|
}
|
|
super.tearDown()
|
|
}
|
|
|
|
private func getTokens(for account: Account) throws -> (accessToken: Credentials, refreshToken: Credentials) {
|
|
guard let accessToken = try account.retrieveCredentials(type: .oauthAccessToken), let refreshToken = try account.retrieveCredentials(type: .oauthRefreshToken) else {
|
|
XCTFail("Unable to retrieve access and/or refresh token from account.")
|
|
throw CredentialsError.incompleteCredentials
|
|
}
|
|
return (accessToken, refreshToken)
|
|
}
|
|
|
|
class TestFeedlyLogoutService: FeedlyLogoutService {
|
|
var mockResult: Result<Void, Error>?
|
|
var logoutExpectation: XCTestExpectation?
|
|
|
|
func logout(completion: @escaping (Result<Void, Error>) -> ()) {
|
|
guard let result = mockResult else {
|
|
XCTFail("Missing mock result. Test may time out because the completion will not be called.")
|
|
return
|
|
}
|
|
DispatchQueue.main.async {
|
|
completion(result)
|
|
self.logoutExpectation?.fulfill()
|
|
}
|
|
}
|
|
}
|
|
|
|
func testCancel() {
|
|
let service = TestFeedlyLogoutService()
|
|
service.logoutExpectation = expectation(description: "Did Call Logout")
|
|
service.logoutExpectation?.isInverted = true
|
|
|
|
let accessToken: Credentials
|
|
let refreshToken: Credentials
|
|
do {
|
|
(accessToken, refreshToken) = try getTokens(for: account)
|
|
} catch {
|
|
XCTFail("Could not retrieve credentials to verify their integrity later.")
|
|
return
|
|
}
|
|
|
|
let logout = FeedlyLogoutOperation(account: account, service: service, log: support.log)
|
|
|
|
// If this expectation is not fulfilled, the operation is not calling `didFinish`.
|
|
let completionExpectation = expectation(description: "Did Finish")
|
|
logout.completionBlock = { _ in
|
|
completionExpectation.fulfill()
|
|
}
|
|
|
|
MainThreadOperationQueue.shared.add(logout)
|
|
|
|
MainThreadOperationQueue.shared.cancelOperations([logout])
|
|
|
|
waitForExpectations(timeout: 1)
|
|
|
|
XCTAssertTrue(logout.isCanceled)
|
|
|
|
do {
|
|
let accountAccessToken = try account.retrieveCredentials(type: .oauthAccessToken)
|
|
let accountRefreshToken = try account.retrieveCredentials(type: .oauthRefreshToken)
|
|
|
|
XCTAssertEqual(accountAccessToken, accessToken)
|
|
XCTAssertEqual(accountRefreshToken, refreshToken)
|
|
} catch {
|
|
XCTFail("Could not verify tokens were left intact. Did the operation delete them?")
|
|
}
|
|
}
|
|
|
|
func testLogoutSuccess() {
|
|
let service = TestFeedlyLogoutService()
|
|
service.logoutExpectation = expectation(description: "Did Call Logout")
|
|
service.mockResult = .success(())
|
|
|
|
let logout = FeedlyLogoutOperation(account: account, service: service, log: support.log)
|
|
|
|
// If this expectation is not fulfilled, the operation is not calling `didFinish`.
|
|
let completionExpectation = expectation(description: "Did Finish")
|
|
logout.completionBlock = { _ in
|
|
completionExpectation.fulfill()
|
|
}
|
|
|
|
MainThreadOperationQueue.shared.add(logout)
|
|
|
|
waitForExpectations(timeout: 1)
|
|
|
|
XCTAssertFalse(logout.isCanceled)
|
|
|
|
do {
|
|
let accountAccessToken = try account.retrieveCredentials(type: .oauthAccessToken)
|
|
let accountRefreshToken = try account.retrieveCredentials(type: .oauthRefreshToken)
|
|
|
|
XCTAssertNil(accountAccessToken)
|
|
XCTAssertNil(accountRefreshToken)
|
|
} catch {
|
|
XCTFail("Could not verify tokens were deleted.")
|
|
}
|
|
}
|
|
|
|
class TestLogoutDelegate: FeedlyOperationDelegate {
|
|
var error: Error?
|
|
var didFailExpectation: XCTestExpectation?
|
|
|
|
func feedlyOperation(_ operation: FeedlyOperation, didFailWith error: Error) {
|
|
self.error = error
|
|
didFailExpectation?.fulfill()
|
|
}
|
|
}
|
|
|
|
func testLogoutMissingAccessToken() {
|
|
support.removeCredentials(matching: .oauthAccessToken, from: account)
|
|
|
|
let (_, service) = support.makeMockNetworkStack()
|
|
service.credentials = nil
|
|
|
|
let logout = FeedlyLogoutOperation(account: account, service: service, log: support.log)
|
|
|
|
let delegate = TestLogoutDelegate()
|
|
delegate.didFailExpectation = expectation(description: "Did Fail")
|
|
|
|
logout.delegate = delegate
|
|
|
|
// If this expectation is not fulfilled, the operation is not calling `didFinish`.
|
|
let completionExpectation = expectation(description: "Did Finish")
|
|
logout.completionBlock = { _ in
|
|
completionExpectation.fulfill()
|
|
}
|
|
|
|
MainThreadOperationQueue.shared.add(logout)
|
|
|
|
waitForExpectations(timeout: 1)
|
|
|
|
XCTAssertFalse(logout.isCanceled)
|
|
|
|
do {
|
|
let accountAccessToken = try account.retrieveCredentials(type: .oauthAccessToken)
|
|
XCTAssertNil(accountAccessToken)
|
|
} catch {
|
|
XCTFail("Could not verify tokens were deleted.")
|
|
}
|
|
|
|
XCTAssertNotNil(delegate.error, "Should have failed with error.")
|
|
if let error = delegate.error {
|
|
switch error {
|
|
case CredentialsError.incompleteCredentials:
|
|
break
|
|
default:
|
|
XCTFail("Expected \(CredentialsError.incompleteCredentials)")
|
|
}
|
|
}
|
|
}
|
|
|
|
func testLogoutFailure() {
|
|
let service = TestFeedlyLogoutService()
|
|
service.logoutExpectation = expectation(description: "Did Call Logout")
|
|
service.mockResult = .failure(URLError(.timedOut))
|
|
|
|
let accessToken: Credentials
|
|
let refreshToken: Credentials
|
|
do {
|
|
(accessToken, refreshToken) = try getTokens(for: account)
|
|
} catch {
|
|
XCTFail("Could not retrieve credentials to verify their integrity later.")
|
|
return
|
|
}
|
|
|
|
let logout = FeedlyLogoutOperation(account: account, service: service, log: support.log)
|
|
|
|
// If this expectation is not fulfilled, the operation is not calling `didFinish`.
|
|
let completionExpectation = expectation(description: "Did Finish")
|
|
logout.completionBlock = { _ in
|
|
completionExpectation.fulfill()
|
|
}
|
|
|
|
MainThreadOperationQueue.shared.add(logout)
|
|
|
|
waitForExpectations(timeout: 1)
|
|
|
|
XCTAssertFalse(logout.isCanceled)
|
|
|
|
do {
|
|
let accountAccessToken = try account.retrieveCredentials(type: .oauthAccessToken)
|
|
let accountRefreshToken = try account.retrieveCredentials(type: .oauthRefreshToken)
|
|
|
|
XCTAssertEqual(accountAccessToken, accessToken)
|
|
XCTAssertEqual(accountRefreshToken, refreshToken)
|
|
} catch {
|
|
XCTFail("Could not verify tokens were left intact. Did the operation delete them?")
|
|
}
|
|
}
|
|
}
|