diff --git a/Metatext.xcodeproj/project.pbxproj b/Metatext.xcodeproj/project.pbxproj index 7f8f297..f013ecc 100644 --- a/Metatext.xcodeproj/project.pbxproj +++ b/Metatext.xcodeproj/project.pbxproj @@ -144,6 +144,7 @@ D0EC8DCC24DFA06700A08489 /* IdentitiesService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DCA24DFA06700A08489 /* IdentitiesService.swift */; }; D0EC8DCE24DFB64200A08489 /* AuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DCD24DFB64200A08489 /* AuthenticationService.swift */; }; D0EC8DCF24DFB64200A08489 /* AuthenticationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DCD24DFB64200A08489 /* AuthenticationService.swift */; }; + D0EC8DD424DFE38900A08489 /* AuthenticationServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DD324DFE38900A08489 /* AuthenticationServiceTests.swift */; }; D0ED1B6E24CE100C00B4899C /* AddIdentityViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED1B6D24CE100C00B4899C /* AddIdentityViewModelTests.swift */; }; D0ED1BB724CE47F400B4899C /* WebAuthSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED1BB624CE47F400B4899C /* WebAuthSession.swift */; }; D0ED1BB824CE47F400B4899C /* WebAuthSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED1BB624CE47F400B4899C /* WebAuthSession.swift */; }; @@ -251,6 +252,7 @@ D0EC8DC724DF8B3C00A08489 /* SecretsService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecretsService.swift; sourceTree = ""; }; D0EC8DCA24DFA06700A08489 /* IdentitiesService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentitiesService.swift; sourceTree = ""; }; D0EC8DCD24DFB64200A08489 /* AuthenticationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationService.swift; sourceTree = ""; }; + D0EC8DD324DFE38900A08489 /* AuthenticationServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationServiceTests.swift; sourceTree = ""; }; D0ED1B6D24CE100C00B4899C /* AddIdentityViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddIdentityViewModelTests.swift; sourceTree = ""; }; D0ED1BB624CE47F400B4899C /* WebAuthSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebAuthSession.swift; sourceTree = ""; }; D0ED1BC024CED48800B4899C /* HTTPClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPClient.swift; sourceTree = ""; }; @@ -428,8 +430,9 @@ D0666A2224C677B400F3F04B /* Tests */ = { isa = PBXGroup; children = ( - D0ED1B6C24CE0EED00B4899C /* View Models */, D0666A2524C677B400F3F04B /* Info.plist */, + D0EC8DD024DFE34F00A08489 /* Services */, + D0ED1B6C24CE0EED00B4899C /* View Models */, ); path = Tests; sourceTree = ""; @@ -531,6 +534,14 @@ path = "Mastodon API Stubs"; sourceTree = ""; }; + D0EC8DD024DFE34F00A08489 /* Services */ = { + isa = PBXGroup; + children = ( + D0EC8DD324DFE38900A08489 /* AuthenticationServiceTests.swift */, + ); + path = Services; + sourceTree = ""; + }; D0ED1B6C24CE0EED00B4899C /* View Models */ = { isa = PBXGroup; children = ( @@ -914,6 +925,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D0EC8DD424DFE38900A08489 /* AuthenticationServiceTests.swift in Sources */, D0ED1B6E24CE100C00B4899C /* AddIdentityViewModelTests.swift in Sources */, D052BBC724D749C800A80A7A /* RootViewModelTests.swift in Sources */, ); diff --git a/Shared/Services/IdentityService.swift b/Shared/Services/IdentityService.swift index 47ba511..efd6169 100644 --- a/Shared/Services/IdentityService.swift +++ b/Shared/Services/IdentityService.swift @@ -4,36 +4,33 @@ import Foundation import Combine class IdentityService { - @Published var identity: Identity + @Published private(set) var identity: Identity let observationErrors: AnyPublisher private let networkClient: MastodonClient private let environment: AppEnvironment private let observationErrorsInput = PassthroughSubject() - private var cancellables = Set() init(identityID: UUID, environment: AppEnvironment) throws { self.environment = environment observationErrors = observationErrorsInput.eraseToAnyPublisher() - networkClient = MastodonClient(configuration: environment.URLSessionConfiguration) - networkClient.accessToken = try SecretsService( - identityID: identityID, - keychainService: environment.keychainService) - .item(.accessToken) let observation = environment.identityDatabase.identityObservation(id: identityID).share() - var initialIdentity: Identity? - observation.first().sink( + _ = observation.first().sink( receiveCompletion: { _ in }, receiveValue: { initialIdentity = $0 }) - .store(in: &cancellables) guard let identity = initialIdentity else { throw IdentityDatabaseError.identityNotFound } self.identity = identity + networkClient = MastodonClient(configuration: environment.URLSessionConfiguration) networkClient.instanceURL = identity.url + networkClient.accessToken = try SecretsService( + identityID: identityID, + keychainService: environment.keychainService) + .item(.accessToken) observation.catch { [weak self] error -> Empty in self?.observationErrorsInput.send(error) diff --git a/Tests/Services/AuthenticationServiceTests.swift b/Tests/Services/AuthenticationServiceTests.swift new file mode 100644 index 0000000..d76567f --- /dev/null +++ b/Tests/Services/AuthenticationServiceTests.swift @@ -0,0 +1,31 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import XCTest +import Combine +import CombineExpectations +@testable import Metatext + +class AuthenticationServiceTests: XCTestCase { + func testAddIdentity() throws { + let environment = AppEnvironment.fresh() + let sut = AuthenticationService(environment: environment) + let instanceURL = URL(string: "https://mastodon.social")! + let addedIDRecorder = sut.authenticate(instanceURL: instanceURL).record() + + let addedIdentityID = try wait(for: addedIDRecorder.next(), timeout: 1) + let identityRecorder = environment.identityDatabase.identityObservation(id: addedIdentityID).record() + let addedIdentity = try wait(for: identityRecorder.next(), timeout: 1) + + XCTAssertEqual(addedIdentity.id, addedIdentityID) + XCTAssertEqual(addedIdentity.url, URL(string: "https://mastodon.social")!) + + let secretsService = SecretsService(identityID: addedIdentity.id, keychainService: environment.keychainService) + + XCTAssertEqual( + try secretsService.item(.clientID) as String?, "AUTHORIZATION_CLIENT_ID_STUB_VALUE") + XCTAssertEqual( + try secretsService.item(.clientSecret) as String?, "AUTHORIZATION_CLIENT_SECRET_STUB_VALUE") + XCTAssertEqual( + try secretsService.item(.accessToken) as String?, "ACCESS_TOKEN_STUB_VALUE") + } +} diff --git a/Tests/View Models/AddIdentityViewModelTests.swift b/Tests/View Models/AddIdentityViewModelTests.swift index fb485bc..8affc4f 100644 --- a/Tests/View Models/AddIdentityViewModelTests.swift +++ b/Tests/View Models/AddIdentityViewModelTests.swift @@ -18,17 +18,7 @@ class AddIdentityViewModelTests: XCTestCase { let identityRecorder = environment.identityDatabase.identityObservation(id: addedIdentityID).record() let addedIdentity = try wait(for: identityRecorder.next(), timeout: 1) - XCTAssertEqual(addedIdentity.id, addedIdentityID) XCTAssertEqual(addedIdentity.url, URL(string: "https://mastodon.social")!) - - let secretsService = SecretsService(identityID: addedIdentity.id, keychainService: environment.keychainService) - - XCTAssertEqual( - try secretsService.item(.clientID) as String?, "AUTHORIZATION_CLIENT_ID_STUB_VALUE") - XCTAssertEqual( - try secretsService.item(.clientSecret) as String?, "AUTHORIZATION_CLIENT_SECRET_STUB_VALUE") - XCTAssertEqual( - try secretsService.item(.accessToken) as String?, "ACCESS_TOKEN_STUB_VALUE") } func testAddIdentityWithoutScheme() throws {