Verify Element X with an existing Element Classic account. (#5374)
* Read and import the secrets from ClassicAppAccounts. * Record snapshots. * Add some documentation, tidy up tests and fix the dismissal of the backup instructions. * Workaround flakey tests (the fulfilments weren't always firing). * Allow a custom Classic App deep link URL to be configured.
This commit is contained in:
@@ -14,6 +14,7 @@ extension AuthenticationClientFactoryMock {
|
||||
struct Configuration {
|
||||
var homeserverClients = [
|
||||
"matrix.org": ClientSDKMock(configuration: .init()),
|
||||
"https://matrix-client.matrix.org": ClientSDKMock(configuration: .init()),
|
||||
"example.com": ClientSDKMock(configuration: .init(serverAddress: "example.com",
|
||||
homeserverURL: "https://matrix.example.com",
|
||||
slidingSyncVersion: .native,
|
||||
@@ -51,5 +52,12 @@ extension AuthenticationClientFactoryMock {
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksClosure = { address, _, _, _ in
|
||||
guard let client = configuration.homeserverClients[address] else {
|
||||
throw ClientBuildError.ServerUnreachable(message: "Not a known homeserver.")
|
||||
}
|
||||
return client
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,18 @@ import Foundation
|
||||
import MatrixRustSDK
|
||||
|
||||
extension ClassicAppManagerMock {
|
||||
struct Configuration { }
|
||||
struct Configuration {
|
||||
var accounts: [ClassicAppAccount]
|
||||
var availableSecrets: ClassicAppAccount.AvailableSecrets = .complete
|
||||
var secretsBundle: SecretsBundleWithUserId?
|
||||
}
|
||||
|
||||
convenience init(_ configuration: Configuration) {
|
||||
self.init()
|
||||
|
||||
loadAccountsClosure = { configuration.accounts }
|
||||
availableSecretsForReturnValue = configuration.availableSecrets
|
||||
secretsBundleForReturnValue = configuration.secretsBundle
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +30,7 @@ extension ClassicAppAccount {
|
||||
displayName: "Alice",
|
||||
avatarURL: nil,
|
||||
serverName: "matrix.org",
|
||||
homeserverURL: "https://matrix-client.matrix.org/",
|
||||
homeserverURL: "https://matrix-client.matrix.org",
|
||||
cryptoStoreURL: .cachesDirectory,
|
||||
cryptoStorePassphrase: "1234567890",
|
||||
accessToken: "accessToken")
|
||||
@@ -33,7 +41,7 @@ extension ClassicAppAccount {
|
||||
displayName: "Dan",
|
||||
avatarURL: .mockMXCUserAvatar,
|
||||
serverName: "matrix.org",
|
||||
homeserverURL: "https://matrix-client.matrix.org/",
|
||||
homeserverURL: "https://matrix-client.matrix.org",
|
||||
cryptoStoreURL: .cachesDirectory,
|
||||
cryptoStorePassphrase: "1234567890",
|
||||
accessToken: "accessToken")
|
||||
|
||||
@@ -1946,6 +1946,80 @@ class AuthenticationClientFactoryMock: AuthenticationClientFactoryProtocol, @unc
|
||||
return makeClientHomeserverAddressSessionDirectoriesPassphraseClientSessionDelegateAppSettingsAppHooksReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - makeInMemoryClient
|
||||
|
||||
var makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksThrowableError: Error?
|
||||
var makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksUnderlyingCallsCount = 0
|
||||
var makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksCalled: Bool {
|
||||
return makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksCallsCount > 0
|
||||
}
|
||||
var makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksReceivedArguments: (homeserverAddress: String, clientSessionDelegate: ClientSessionDelegate, appSettings: AppSettings, appHooks: AppHooks)?
|
||||
var makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksReceivedInvocations: [(homeserverAddress: String, clientSessionDelegate: ClientSessionDelegate, appSettings: AppSettings, appHooks: AppHooks)] = []
|
||||
|
||||
var makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksUnderlyingReturnValue: ClientProtocol!
|
||||
var makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksReturnValue: ClientProtocol! {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksUnderlyingReturnValue
|
||||
} else {
|
||||
var returnValue: ClientProtocol? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksUnderlyingReturnValue
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksUnderlyingReturnValue = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksUnderlyingReturnValue = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksClosure: ((String, ClientSessionDelegate, AppSettings, AppHooks) async throws -> ClientProtocol)?
|
||||
|
||||
func makeInMemoryClient(homeserverAddress: String, clientSessionDelegate: ClientSessionDelegate, appSettings: AppSettings, appHooks: AppHooks) async throws -> ClientProtocol {
|
||||
if let error = makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksThrowableError {
|
||||
throw error
|
||||
}
|
||||
makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksCallsCount += 1
|
||||
makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksReceivedArguments = (homeserverAddress: homeserverAddress, clientSessionDelegate: clientSessionDelegate, appSettings: appSettings, appHooks: appHooks)
|
||||
DispatchQueue.main.async {
|
||||
self.makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksReceivedInvocations.append((homeserverAddress: homeserverAddress, clientSessionDelegate: clientSessionDelegate, appSettings: appSettings, appHooks: appHooks))
|
||||
}
|
||||
if let makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksClosure = makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksClosure {
|
||||
return try await makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksClosure(homeserverAddress, clientSessionDelegate, appSettings, appHooks)
|
||||
} else {
|
||||
return makeInMemoryClientHomeserverAddressClientSessionDelegateAppSettingsAppHooksReturnValue
|
||||
}
|
||||
}
|
||||
}
|
||||
class BannedRoomProxyMock: BannedRoomProxyProtocol, @unchecked Sendable {
|
||||
var info: BaseRoomInfoProxyProtocol {
|
||||
@@ -2309,6 +2383,154 @@ class ClassicAppManagerMock: ClassicAppManagerProtocol, @unchecked Sendable {
|
||||
return loadAccountsReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - availableSecrets
|
||||
|
||||
var availableSecretsForThrowableError: Error?
|
||||
var availableSecretsForUnderlyingCallsCount = 0
|
||||
var availableSecretsForCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return availableSecretsForUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = availableSecretsForUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
availableSecretsForUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
availableSecretsForUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var availableSecretsForCalled: Bool {
|
||||
return availableSecretsForCallsCount > 0
|
||||
}
|
||||
var availableSecretsForReceivedAccount: ClassicAppAccount?
|
||||
var availableSecretsForReceivedInvocations: [ClassicAppAccount] = []
|
||||
|
||||
var availableSecretsForUnderlyingReturnValue: ClassicAppAccount.AvailableSecrets!
|
||||
var availableSecretsForReturnValue: ClassicAppAccount.AvailableSecrets! {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return availableSecretsForUnderlyingReturnValue
|
||||
} else {
|
||||
var returnValue: ClassicAppAccount.AvailableSecrets? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = availableSecretsForUnderlyingReturnValue
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
availableSecretsForUnderlyingReturnValue = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
availableSecretsForUnderlyingReturnValue = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var availableSecretsForClosure: ((ClassicAppAccount) async throws -> ClassicAppAccount.AvailableSecrets)?
|
||||
|
||||
func availableSecrets(for account: ClassicAppAccount) async throws -> ClassicAppAccount.AvailableSecrets {
|
||||
if let error = availableSecretsForThrowableError {
|
||||
throw error
|
||||
}
|
||||
availableSecretsForCallsCount += 1
|
||||
availableSecretsForReceivedAccount = account
|
||||
DispatchQueue.main.async {
|
||||
self.availableSecretsForReceivedInvocations.append(account)
|
||||
}
|
||||
if let availableSecretsForClosure = availableSecretsForClosure {
|
||||
return try await availableSecretsForClosure(account)
|
||||
} else {
|
||||
return availableSecretsForReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - secretsBundle
|
||||
|
||||
var secretsBundleForThrowableError: Error?
|
||||
var secretsBundleForUnderlyingCallsCount = 0
|
||||
var secretsBundleForCallsCount: Int {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return secretsBundleForUnderlyingCallsCount
|
||||
} else {
|
||||
var returnValue: Int? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = secretsBundleForUnderlyingCallsCount
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
secretsBundleForUnderlyingCallsCount = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
secretsBundleForUnderlyingCallsCount = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var secretsBundleForCalled: Bool {
|
||||
return secretsBundleForCallsCount > 0
|
||||
}
|
||||
var secretsBundleForReceivedAccount: ClassicAppAccount?
|
||||
var secretsBundleForReceivedInvocations: [ClassicAppAccount] = []
|
||||
|
||||
var secretsBundleForUnderlyingReturnValue: SecretsBundleWithUserId!
|
||||
var secretsBundleForReturnValue: SecretsBundleWithUserId! {
|
||||
get {
|
||||
if Thread.isMainThread {
|
||||
return secretsBundleForUnderlyingReturnValue
|
||||
} else {
|
||||
var returnValue: SecretsBundleWithUserId? = nil
|
||||
DispatchQueue.main.sync {
|
||||
returnValue = secretsBundleForUnderlyingReturnValue
|
||||
}
|
||||
|
||||
return returnValue!
|
||||
}
|
||||
}
|
||||
set {
|
||||
if Thread.isMainThread {
|
||||
secretsBundleForUnderlyingReturnValue = newValue
|
||||
} else {
|
||||
DispatchQueue.main.sync {
|
||||
secretsBundleForUnderlyingReturnValue = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var secretsBundleForClosure: ((ClassicAppAccount) async throws -> SecretsBundleWithUserId)?
|
||||
|
||||
func secretsBundle(for account: ClassicAppAccount) async throws -> SecretsBundleWithUserId {
|
||||
if let error = secretsBundleForThrowableError {
|
||||
throw error
|
||||
}
|
||||
secretsBundleForCallsCount += 1
|
||||
secretsBundleForReceivedAccount = account
|
||||
DispatchQueue.main.async {
|
||||
self.secretsBundleForReceivedInvocations.append(account)
|
||||
}
|
||||
if let secretsBundleForClosure = secretsBundleForClosure {
|
||||
return try await secretsBundleForClosure(account)
|
||||
} else {
|
||||
return secretsBundleForReturnValue
|
||||
}
|
||||
}
|
||||
}
|
||||
class ClientProxyMock: ClientProxyProtocol, @unchecked Sendable {
|
||||
var actionsPublisher: AnyPublisher<ClientProxyAction, Never> {
|
||||
|
||||
@@ -46,11 +46,16 @@ extension ClientSDKMock {
|
||||
serverReturnValue = "https://\(configuration.serverAddress)"
|
||||
homeserverReturnValue = configuration.homeserverURL
|
||||
urlForOidcOidcConfigurationPromptLoginHintDeviceIdAdditionalScopesReturnValue = OAuthAuthorizationDataSDKMock(configuration: configuration)
|
||||
loginUsernamePasswordInitialDeviceNameDeviceIdClosure = { username, password, _, _ in
|
||||
loginUsernamePasswordInitialDeviceNameDeviceIdClosure = { [weak self] username, password, _, _ in
|
||||
guard username == configuration.validCredentials.username,
|
||||
password == configuration.validCredentials.password else {
|
||||
throw MockError.generic // use the matrix error
|
||||
}
|
||||
if username.hasPrefix("@"), username.contains(":") {
|
||||
self?.userIdReturnValue = username
|
||||
} else {
|
||||
self?.userIdReturnValue = "@\(username):\(configuration.serverAddress)"
|
||||
}
|
||||
}
|
||||
|
||||
userIdReturnValue = configuration.userID
|
||||
|
||||
Reference in New Issue
Block a user