Skip to content
Snippets Groups Projects
MessengerRestoreBackupTests.swift 6.64 KiB
Newer Older
import CustomDump
import XCTest
import XXClient
@testable import XXMessengerClient

final class MessengerRestoreBackupTests: XCTestCase {
  func testRestore() throws {
    let backupData = "backup-data".data(using: .utf8)!
    let backupPassphrase = "backup-passphrase"
    let ndfData = "ndf-data".data(using: .utf8)!
    let password = "password".data(using: .utf8)!
    let backupContacts: [Data] = (1...3).map { "contact-\($0)" }.map { $0.data(using: .utf8)! }
    let backupParams = BackupParams.stub
    let backupReport = BackupReport(
      restoredContacts: backupContacts,
      params: String(data: try! JSONEncoder().encode(backupParams), encoding: .utf8)!
    )
    let cMixParams = "cmix-params".data(using: .utf8)!
    let e2eParams = "e2e-params".data(using: .utf8)!
    let cMixId = 123
    let e2eId = 456
    let receptionIdentity = ReceptionIdentity(
      id: "reception-id".data(using: .utf8)!,
      rsaPrivatePem: "reception-rsaPrivatePem".data(using: .utf8)!,
      salt: "reception-salt".data(using: .utf8)!,
      dhKeyPrivate: "reception-dhKeyPrivate".data(using: .utf8)!,
      e2eGrp: "reception-e2eGrp".data(using: .utf8)!
    )
    let udEnvironmentFromNDF = UDEnvironment(
      address: "ud-address",
      cert: "ud-cert".data(using: .utf8)!,
      contact: "ud-contact".data(using: .utf8)!
    )

    var caughtActions: [CaughtAction] = []

    var env: MessengerEnvironment = .unimplemented
    env.downloadNDF.run = { ndfEnvironment in
      caughtActions.append(.didDownloadNDF(environment: ndfEnvironment))
      return ndfData
    }
    env.generateSecret.run = { _ in password }
    env.passwordStorage.save = { caughtActions.append(.didSavePassword(password: $0)) }
    env.passwordStorage.load = { password }
Dariusz Rybicki's avatar
Dariusz Rybicki committed
    env.fileManager.removeItem = { caughtActions.append(.didRemoveItem(path: $0)) }
    env.fileManager.createDirectory = { caughtActions.append(.didCreateDirectory(path: $0)) }
    env.newCMixFromBackup.run = {
      ndfJSON, storageDir, backupPassphrase, sessionPassword, backupFileContents in
      caughtActions.append(.didNewCMixFromBackup(
        ndfJSON: ndfJSON,
        storageDir: storageDir,
        backupPassphrase: backupPassphrase,
        sessionPassword: sessionPassword,
        backupFileContents: backupFileContents
      ))
      return backupReport
    }
    env.getCMixParams.run = { cMixParams }
    env.getE2EParams.run = { e2eParams }
    env.loadCMix.run = { storageDir, password, cMixParams in
      caughtActions.append(.didLoadCMix(
        storageDir: storageDir,
        password: password,
        cMixParams: cMixParams
      ))
      var cMix: CMix = .unimplemented
      cMix.getId.run = { cMixId }
      cMix.makeReceptionIdentity.run = { legacy in
        caughtActions.append(.cMixDidMakeReceptionIdentity(legacy: legacy))
        return receptionIdentity
      }
      cMix.startNetworkFollower.run = { timeoutMS in
        caughtActions.append(.cMixDidStartNetworkFollower(timeoutMS: timeoutMS))
      }
      return cMix
    }
    env.login.run = { ephemeral, cMixId, _, identity, e2eParams in
      caughtActions.append(.didLogin(
        ephemeral: ephemeral,
        cMixId: cMixId,
        identity: identity,
        e2eParamsJSON: e2eParams
      ))
      var e2e: E2E = .unimplemented
      e2e.getId.run = { e2eId }
      e2e.getUdEnvironmentFromNdf.run = { udEnvironmentFromNDF }
      return e2e
    }
    env.newUdManagerFromBackup.run = { params, _ in
      caughtActions.append(.didNewUdManagerFromBackup(params: params))
      return .unimplemented
    }
    env.authCallbacks.registered = {
      AuthCallbacks { _ in }
    }
    env.cMix.set = { _ in caughtActions.append(.didSetCMix) }
    env.e2e.set = { _ in caughtActions.append(.didSetE2E) }
    env.ud.set = { _ in caughtActions.append(.didSetUD) }
    env.isListeningForMessages.set = {
      caughtActions.append(.didSetIsListeningForMessages(isListening: $0))
    }

    let restore: MessengerRestoreBackup = .live(env)

    let result = try restore(
      backupData: backupData,
      backupPassphrase: backupPassphrase
    )

    XCTAssertNoDifference(caughtActions, [
      .didDownloadNDF(
        environment: env.ndfEnvironment
      ),
      .didSavePassword(
        password: password
      ),
Dariusz Rybicki's avatar
Dariusz Rybicki committed
      .didRemoveItem(
        path: env.storageDir
      ),
      .didCreateDirectory(
        path: env.storageDir
      ),
      .didNewCMixFromBackup(
        ndfJSON: String(data: ndfData, encoding: .utf8)!,
        storageDir: env.storageDir,
        backupPassphrase: backupPassphrase,
        sessionPassword: password,
        backupFileContents: backupData
      ),
      .didLoadCMix(
        storageDir: env.storageDir,
        password: password,
        cMixParams: cMixParams
      ),
      .didSetCMix,
      .cMixDidStartNetworkFollower(
        timeoutMS: 30_000
      ),
      .cMixDidMakeReceptionIdentity(
        legacy: true
      ),
      .didLogin(
        ephemeral: false,
        cMixId: cMixId,
        identity: receptionIdentity,
        e2eParamsJSON: e2eParams
      ),
      .didSetE2E,
      .didSetIsListeningForMessages(
        isListening: false
      ),
      .didNewUdManagerFromBackup(params: .init(
        e2eId: e2eId,
        environment: udEnvironmentFromNDF
    XCTAssertNoDifference(result, MessengerRestoreBackup.Result(
      restoredParams: backupParams,
      restoredContacts: backupContacts
    ))
  }

  func testDownloadNdfFailure() {
    struct Failure: Error, Equatable {}
    let failure = Failure()

    var env: MessengerEnvironment = .unimplemented
    env.downloadNDF.run = { _ in throw failure }
    let restore: MessengerRestoreBackup = .live(env)

    XCTAssertThrowsError(try restore(backupData: Data(), backupPassphrase: "")) { error in
      XCTAssertNoDifference(error as? Failure, failure)
    }
  }
}

private enum CaughtAction: Equatable {
  case didDownloadNDF(
    environment: NDFEnvironment
  )
  case didSavePassword(
    password: Data
  )
Dariusz Rybicki's avatar
Dariusz Rybicki committed
  case didRemoveItem(
    path: String
  )
  case didCreateDirectory(
    path: String
  )
  case didNewCMixFromBackup(
    ndfJSON: String,
    storageDir: String,
    backupPassphrase: String,
    sessionPassword: Data,
    backupFileContents: Data
  )
  case didLoadCMix(
    storageDir: String,
    password: Data,
    cMixParams: Data
  )
  case didLogin(
    ephemeral: Bool,
    cMixId: Int,
    identity: ReceptionIdentity,
    e2eParamsJSON: Data
  )
  case cMixDidMakeReceptionIdentity(
    legacy: Bool
  )
  case cMixDidStartNetworkFollower(
    timeoutMS: Int
  )
  case didNewUdManagerFromBackup(
    params: NewUdManagerFromBackup.Params
  )
  case didSetCMix
  case didSetE2E
  case didSetUD
  case didSetIsListeningForMessages(
    isListening: Bool
  )