Make the SessionDirectories type responsible for cleaning up data. (#3261)

This commit is contained in:
Doug
2024-09-11 14:32:03 +01:00
committed by GitHub
parent 84a3ffc135
commit af3a6ccbed
11 changed files with 192 additions and 80 deletions
@@ -57,4 +57,8 @@ extension FileManager {
return size return size
} }
func numberOfItems(at url: URL) throws -> Int {
try contentsOfDirectory(at: url, includingPropertiesForKeys: nil).count
}
} }
@@ -140,13 +140,7 @@ class AuthenticationService: AuthenticationServiceProtocol {
} }
private func rotateSessionDirectory() { private func rotateSessionDirectory() {
if FileManager.default.directoryExists(at: sessionDirectories.dataDirectory) { sessionDirectories.delete()
try? FileManager.default.removeItem(at: sessionDirectories.dataDirectory)
}
if FileManager.default.directoryExists(at: sessionDirectories.cacheDirectory) {
try? FileManager.default.removeItem(at: sessionDirectories.cacheDirectory)
}
sessionDirectories = .init() sessionDirectories = .init()
} }
@@ -110,8 +110,7 @@ class KeychainController: KeychainControllerProtocol {
fatalError("Something has gone mega wrong, all bets are off.") fatalError("Something has gone mega wrong, all bets are off.")
} }
let restorationToken = RestorationToken(session: session, let restorationToken = RestorationToken(session: session,
sessionDirectory: oldToken.sessionDirectory, sessionDirectories: oldToken.sessionDirectories,
cacheDirectory: oldToken.cacheDirectory,
passphrase: oldToken.passphrase, passphrase: oldToken.passphrase,
pusherNotificationClientIdentifier: oldToken.pusherNotificationClientIdentifier) pusherNotificationClientIdentifier: oldToken.pusherNotificationClientIdentifier)
setRestorationToken(restorationToken, forUsername: session.userId) setRestorationToken(restorationToken, forUsername: session.userId)
@@ -77,13 +77,7 @@ final class QRCodeLoginService: QRCodeLoginServiceProtocol {
} }
private func rotateSessionDirectory() { private func rotateSessionDirectory() {
if FileManager.default.directoryExists(at: sessionDirectories.dataDirectory) { sessionDirectories.delete()
try? FileManager.default.removeItem(at: sessionDirectories.dataDirectory)
}
if FileManager.default.directoryExists(at: sessionDirectories.cacheDirectory) {
try? FileManager.default.removeItem(at: sessionDirectories.cacheDirectory)
}
sessionDirectories = .init() sessionDirectories = .init()
} }
@@ -10,10 +10,17 @@ import MatrixRustSDK
struct RestorationToken: Equatable { struct RestorationToken: Equatable {
let session: MatrixRustSDK.Session let session: MatrixRustSDK.Session
let sessionDirectory: URL let sessionDirectories: SessionDirectories
let cacheDirectory: URL
let passphrase: String? let passphrase: String?
let pusherNotificationClientIdentifier: String? let pusherNotificationClientIdentifier: String?
enum CodingKeys: CodingKey {
case session
case sessionDirectory
case cacheDirectory
case passphrase
case pusherNotificationClientIdentifier
}
} }
extension RestorationToken: Codable { extension RestorationToken: Codable {
@@ -35,11 +42,19 @@ extension RestorationToken: Codable {
} }
self = try .init(session: session, self = try .init(session: session,
sessionDirectory: sessionDirectories.dataDirectory, sessionDirectories: sessionDirectories,
cacheDirectory: sessionDirectories.cacheDirectory,
passphrase: container.decodeIfPresent(String.self, forKey: .passphrase), passphrase: container.decodeIfPresent(String.self, forKey: .passphrase),
pusherNotificationClientIdentifier: container.decodeIfPresent(String.self, forKey: .pusherNotificationClientIdentifier)) pusherNotificationClientIdentifier: container.decodeIfPresent(String.self, forKey: .pusherNotificationClientIdentifier))
} }
func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(session, forKey: .session)
try container.encode(sessionDirectories.dataDirectory, forKey: .sessionDirectory)
try container.encode(sessionDirectories.cacheDirectory, forKey: .cacheDirectory)
try container.encode(passphrase, forKey: .passphrase)
try container.encode(pusherNotificationClientIdentifier, forKey: .pusherNotificationClientIdentifier)
}
} }
extension MatrixRustSDK.Session: Codable { extension MatrixRustSDK.Session: Codable {
@@ -13,6 +13,50 @@ struct SessionDirectories: Hashable, Codable {
var dataPath: String { dataDirectory.path(percentEncoded: false) } var dataPath: String { dataDirectory.path(percentEncoded: false) }
var cachePath: String { cacheDirectory.path(percentEncoded: false) } var cachePath: String { cacheDirectory.path(percentEncoded: false) }
// MARK: Data Management
/// Removes the directories from disk if they have been created.
func delete() {
do {
if FileManager.default.directoryExists(at: dataDirectory) {
try FileManager.default.removeItem(at: dataDirectory)
}
} catch {
MXLog.failure("Failed deleting the session data: \(error)")
}
do {
if FileManager.default.directoryExists(at: cacheDirectory) {
try FileManager.default.removeItem(at: cacheDirectory)
}
} catch {
MXLog.failure("Failed deleting the session caches: \(error)")
}
}
/// Deletes the Rust state store and event cache data, leaving the crypto store and both
/// session directories in place along with any other data that may have been written in them.
func deleteTransientUserData() {
do {
let prefix = "matrix-sdk-state"
try deleteFiles(at: dataDirectory, with: prefix)
} catch {
MXLog.failure("Failed clearing state store: \(error)")
}
do {
let prefix = "matrix-sdk-event-cache"
try deleteFiles(at: cacheDirectory, with: prefix)
} catch {
MXLog.failure("Failed clearing event cache store: \(error)")
}
}
private func deleteFiles(at url: URL, with prefix: String) throws {
let sessionDirectoryContents = try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil)
for url in sessionDirectoryContents where url.lastPathComponent.hasPrefix(prefix) {
try FileManager.default.removeItem(at: url)
}
}
} }
extension SessionDirectories { extension SessionDirectories {
@@ -14,7 +14,6 @@ class UserSessionStore: UserSessionStoreProtocol {
private let appSettings: AppSettings private let appSettings: AppSettings
private let networkMonitor: NetworkMonitorProtocol private let networkMonitor: NetworkMonitorProtocol
private let appHooks: AppHooks private let appHooks: AppHooks
private let matrixSDKStateKey = "matrix-sdk-state"
/// Whether or not there are sessions in the store. /// Whether or not there are sessions in the store.
var hasSessions: Bool { !keychainController.restorationTokens().isEmpty } var hasSessions: Bool { !keychainController.restorationTokens().isEmpty }
@@ -55,7 +54,7 @@ class UserSessionStore: UserSessionStoreProtocol {
// On any restoration failure reset the token and restart // On any restoration failure reset the token and restart
keychainController.removeRestorationTokenForUsername(credentials.userID) keychainController.removeRestorationTokenForUsername(credentials.userID)
deleteSessionDirectories(for: credentials) credentials.restorationToken.sessionDirectories.delete()
return .failure(error) return .failure(error)
} }
@@ -68,8 +67,7 @@ class UserSessionStore: UserSessionStoreProtocol {
let clientProxy = await setupProxyForClient(client) let clientProxy = await setupProxyForClient(client)
keychainController.setRestorationToken(RestorationToken(session: session, keychainController.setRestorationToken(RestorationToken(session: session,
sessionDirectory: sessionDirectories.dataDirectory, sessionDirectories: sessionDirectories,
cacheDirectory: sessionDirectories.cacheDirectory,
passphrase: passphrase, passphrase: passphrase,
pusherNotificationClientIdentifier: clientProxy.pusherNotificationClientIdentifier), pusherNotificationClientIdentifier: clientProxy.pusherNotificationClientIdentifier),
forUsername: userID) forUsername: userID)
@@ -87,7 +85,7 @@ class UserSessionStore: UserSessionStoreProtocol {
keychainController.removeRestorationTokenForUsername(userID) keychainController.removeRestorationTokenForUsername(userID)
if let credentials { if let credentials {
deleteSessionDirectories(for: credentials) credentials.restorationToken.sessionDirectories.delete()
} }
} }
@@ -96,7 +94,7 @@ class UserSessionStore: UserSessionStoreProtocol {
MXLog.error("Failed to clearing caches: Credentials missing") MXLog.error("Failed to clearing caches: Credentials missing")
return return
} }
deleteCaches(for: credentials) credentials.restorationToken.sessionDirectories.deleteTransientUserData()
} }
// MARK: - Private // MARK: - Private
@@ -125,8 +123,8 @@ class UserSessionStore: UserSessionStoreProtocol {
slidingSync: .restored, slidingSync: .restored,
sessionDelegate: keychainController, sessionDelegate: keychainController,
appHooks: appHooks) appHooks: appHooks)
.sessionPaths(dataPath: credentials.restorationToken.sessionDirectory.path(percentEncoded: false), .sessionPaths(dataPath: credentials.restorationToken.sessionDirectories.dataPath,
cachePath: credentials.restorationToken.cacheDirectory.path(percentEncoded: false)) cachePath: credentials.restorationToken.sessionDirectories.cachePath)
.username(username: credentials.userID) .username(username: credentials.userID)
.homeserverUrl(url: homeserverURL) .homeserverUrl(url: homeserverURL)
.passphrase(passphrase: credentials.restorationToken.passphrase) .passphrase(passphrase: credentials.restorationToken.passphrase)
@@ -148,37 +146,4 @@ class UserSessionStore: UserSessionStoreProtocol {
networkMonitor: networkMonitor, networkMonitor: networkMonitor,
appSettings: appSettings) appSettings: appSettings)
} }
private func deleteSessionDirectories(for credentials: KeychainCredentials) {
do {
try FileManager.default.removeItem(at: credentials.restorationToken.sessionDirectory)
} catch {
MXLog.failure("Failed deleting the session data: \(error)")
}
do {
try FileManager.default.removeItem(at: credentials.restorationToken.cacheDirectory)
} catch {
MXLog.failure("Failed deleting the session caches: \(error)")
}
}
private func deleteCaches(for credentials: KeychainCredentials) {
do {
try deleteContentsOfDirectory(at: credentials.restorationToken.sessionDirectory)
} catch {
MXLog.failure("Failed clearing state store: \(error)")
}
do {
try deleteContentsOfDirectory(at: credentials.restorationToken.cacheDirectory)
} catch {
MXLog.failure("Failed clearing event cache store: \(error)")
}
}
private func deleteContentsOfDirectory(at url: URL) throws {
let sessionDirectoryContents = try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil)
for url in sessionDirectoryContents where url.path.contains(matrixSDKStateKey) {
try FileManager.default.removeItem(at: url)
}
}
} }
+2 -2
View File
@@ -30,8 +30,8 @@ final class NSEUserSession {
slidingSync: .restored, slidingSync: .restored,
sessionDelegate: clientSessionDelegate, sessionDelegate: clientSessionDelegate,
appHooks: appHooks) appHooks: appHooks)
.sessionPaths(dataPath: credentials.restorationToken.sessionDirectory.path(percentEncoded: false), .sessionPaths(dataPath: credentials.restorationToken.sessionDirectories.dataPath,
cachePath: credentials.restorationToken.cacheDirectory.path(percentEncoded: false)) cachePath: credentials.restorationToken.sessionDirectories.cachePath)
.username(username: credentials.userID) .username(username: credentials.userID)
.homeserverUrl(url: homeserverURL) .homeserverUrl(url: homeserverURL)
.passphrase(passphrase: credentials.restorationToken.passphrase) .passphrase(passphrase: credentials.restorationToken.passphrase)
@@ -31,8 +31,7 @@ class KeychainControllerTests: XCTestCase {
homeserverUrl: "homeserverUrl", homeserverUrl: "homeserverUrl",
oidcData: "oidcData", oidcData: "oidcData",
slidingSyncVersion: .proxy(url: "https://my.sync.proxy")), slidingSyncVersion: .proxy(url: "https://my.sync.proxy")),
sessionDirectory: .homeDirectory.appending(component: UUID().uuidString), sessionDirectories: .init(),
cacheDirectory: .homeDirectory.appending(component: UUID().uuidString),
passphrase: "passphrase", passphrase: "passphrase",
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID")
keychain.setRestorationToken(restorationToken, forUsername: username) keychain.setRestorationToken(restorationToken, forUsername: username)
@@ -51,8 +50,7 @@ class KeychainControllerTests: XCTestCase {
homeserverUrl: "homeserverUrl", homeserverUrl: "homeserverUrl",
oidcData: "oidcData", oidcData: "oidcData",
slidingSyncVersion: .proxy(url: "https://my.sync.proxy")), slidingSyncVersion: .proxy(url: "https://my.sync.proxy")),
sessionDirectory: .homeDirectory.appending(component: UUID().uuidString), sessionDirectories: .init(),
cacheDirectory: .homeDirectory.appending(component: UUID().uuidString),
passphrase: "passphrase", passphrase: "passphrase",
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID")
keychain.setRestorationToken(restorationToken, forUsername: username) keychain.setRestorationToken(restorationToken, forUsername: username)
@@ -77,8 +75,7 @@ class KeychainControllerTests: XCTestCase {
homeserverUrl: "homeserverUrl", homeserverUrl: "homeserverUrl",
oidcData: "oidcData", oidcData: "oidcData",
slidingSyncVersion: .proxy(url: "https://my.sync.proxy")), slidingSyncVersion: .proxy(url: "https://my.sync.proxy")),
sessionDirectory: .homeDirectory.appending(component: UUID().uuidString), sessionDirectories: .init(),
cacheDirectory: .homeDirectory.appending(component: UUID().uuidString),
passphrase: "passphrase", passphrase: "passphrase",
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID")
keychain.setRestorationToken(restorationToken, forUsername: "@test\(index):example.com") keychain.setRestorationToken(restorationToken, forUsername: "@test\(index):example.com")
@@ -102,8 +99,7 @@ class KeychainControllerTests: XCTestCase {
homeserverUrl: "homeserverUrl", homeserverUrl: "homeserverUrl",
oidcData: "oidcData", oidcData: "oidcData",
slidingSyncVersion: .proxy(url: "https://my.sync.proxy")), slidingSyncVersion: .proxy(url: "https://my.sync.proxy")),
sessionDirectory: .homeDirectory.appending(component: UUID().uuidString), sessionDirectories: .init(),
cacheDirectory: .homeDirectory.appending(component: UUID().uuidString),
passphrase: "passphrase", passphrase: "passphrase",
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID")
keychain.setRestorationToken(restorationToken, forUsername: "@test\(index):example.com") keychain.setRestorationToken(restorationToken, forUsername: "@test\(index):example.com")
@@ -135,8 +131,7 @@ class KeychainControllerTests: XCTestCase {
homeserverUrl: "homeserverUrl", homeserverUrl: "homeserverUrl",
oidcData: "oidcData", oidcData: "oidcData",
slidingSyncVersion: .native), slidingSyncVersion: .native),
sessionDirectory: .homeDirectory.appending(component: UUID().uuidString), sessionDirectories: .init(),
cacheDirectory: .homeDirectory.appending(component: UUID().uuidString),
passphrase: "passphrase", passphrase: "passphrase",
pusherNotificationClientIdentifier: "pusherClientID") pusherNotificationClientIdentifier: "pusherClientID")
keychain.setRestorationToken(restorationToken, forUsername: username) keychain.setRestorationToken(restorationToken, forUsername: username)
+44 -7
View File
@@ -29,9 +29,9 @@ class RestorationTokenTests: XCTestCase {
XCTAssertEqual(decodedToken.session, originalToken.session, "The session should not be changed.") XCTAssertEqual(decodedToken.session, originalToken.session, "The session should not be changed.")
XCTAssertNil(decodedToken.passphrase, "There should not be a passphrase.") XCTAssertNil(decodedToken.passphrase, "There should not be a passphrase.")
XCTAssertNil(decodedToken.pusherNotificationClientIdentifier, "There should not be a push notification client ID.") XCTAssertNil(decodedToken.pusherNotificationClientIdentifier, "There should not be a push notification client ID.")
XCTAssertEqual(decodedToken.sessionDirectory, .sessionsBaseDirectory.appending(component: "@user_example.com"), XCTAssertEqual(decodedToken.sessionDirectories.dataDirectory, .sessionsBaseDirectory.appending(component: "@user_example.com"),
"The session directory should match the original location set by the Rust SDK from our base directory.") "The session directory should match the original location set by the Rust SDK from our base directory.")
XCTAssertEqual(decodedToken.cacheDirectory, .cachesBaseDirectory.appending(component: "@user_example.com"), XCTAssertEqual(decodedToken.sessionDirectories.cacheDirectory, .cachesBaseDirectory.appending(component: "@user_example.com"),
"The cache directory should be derived from the session directory but in the caches directory.") "The cache directory should be derived from the session directory but in the caches directory.")
} }
@@ -58,14 +58,44 @@ class RestorationTokenTests: XCTestCase {
XCTAssertEqual(decodedToken.passphrase, originalToken.passphrase, "The passphrase should not be changed.") XCTAssertEqual(decodedToken.passphrase, originalToken.passphrase, "The passphrase should not be changed.")
XCTAssertEqual(decodedToken.pusherNotificationClientIdentifier, originalToken.pusherNotificationClientIdentifier, XCTAssertEqual(decodedToken.pusherNotificationClientIdentifier, originalToken.pusherNotificationClientIdentifier,
"The push notification client identifier should not be changed.") "The push notification client identifier should not be changed.")
XCTAssertEqual(decodedToken.sessionDirectory, originalToken.sessionDirectory, "The session directory should not be changed.") XCTAssertEqual(decodedToken.sessionDirectories.dataDirectory, originalToken.sessionDirectory,
XCTAssertEqual(decodedToken.cacheDirectory, .cachesBaseDirectory.appending(component: sessionDirectoryName), "The session directory should not be changed.")
XCTAssertEqual(decodedToken.sessionDirectories.cacheDirectory, .cachesBaseDirectory.appending(component: sessionDirectoryName),
"The cache directory should be derived from the session directory but in the caches directory.") "The cache directory should be derived from the session directory but in the caches directory.")
} }
func testDecodeFromTokenV5() throws {
// Given an encoded restoration token in the 5th format that contains separate directories for session data and caches.
let sessionDirectoryName = UUID().uuidString
let originalToken = RestorationTokenV5(session: Session(accessToken: "1234",
refreshToken: "5678",
userId: "@user:example.com",
deviceId: "D3V1C3",
homeserverUrl: "https://matrix.example.com",
oidcData: "data-from-mas",
slidingSyncVersion: .native),
sessionDirectory: .sessionsBaseDirectory.appending(component: sessionDirectoryName),
cacheDirectory: .cachesBaseDirectory.appending(component: sessionDirectoryName),
passphrase: "passphrase",
pusherNotificationClientIdentifier: "pusher-identifier")
let data = try JSONEncoder().encode(originalToken)
// When decoding the data.
let decodedToken = try JSONDecoder().decode(RestorationToken.self, from: data)
// Then the output should be a valid token.
XCTAssertEqual(decodedToken.session, originalToken.session, "The session should not be changed.")
XCTAssertEqual(decodedToken.passphrase, originalToken.passphrase, "The passphrase should not be changed.")
XCTAssertEqual(decodedToken.pusherNotificationClientIdentifier, originalToken.pusherNotificationClientIdentifier,
"The push notification client identifier should not be changed.")
XCTAssertEqual(decodedToken.sessionDirectories.dataDirectory, originalToken.sessionDirectory,
"The session directory should not be changed.")
XCTAssertEqual(decodedToken.sessionDirectories.cacheDirectory, originalToken.cacheDirectory,
"The cache directory should not be changed.")
}
func testDecodeFromCurrentToken() throws { func testDecodeFromCurrentToken() throws {
// Given an encoded restoration token in the current format. // Given an encoded restoration token in the current format.
let sessionDirectoryName = UUID().uuidString
let originalToken = RestorationToken(session: Session(accessToken: "1234", let originalToken = RestorationToken(session: Session(accessToken: "1234",
refreshToken: "5678", refreshToken: "5678",
userId: "@user:example.com", userId: "@user:example.com",
@@ -73,8 +103,7 @@ class RestorationTokenTests: XCTestCase {
homeserverUrl: "https://matrix.example.com", homeserverUrl: "https://matrix.example.com",
oidcData: "data-from-mas", oidcData: "data-from-mas",
slidingSyncVersion: .native), slidingSyncVersion: .native),
sessionDirectory: .sessionsBaseDirectory.appending(component: sessionDirectoryName), sessionDirectories: .init(),
cacheDirectory: .cachesBaseDirectory.appending(component: sessionDirectoryName),
passphrase: "passphrase", passphrase: "passphrase",
pusherNotificationClientIdentifier: "pusher-identifier") pusherNotificationClientIdentifier: "pusher-identifier")
let data = try JSONEncoder().encode(originalToken) let data = try JSONEncoder().encode(originalToken)
@@ -97,3 +126,11 @@ struct RestorationTokenV4: Equatable, Codable {
let passphrase: String? let passphrase: String?
let pusherNotificationClientIdentifier: String? let pusherNotificationClientIdentifier: String?
} }
struct RestorationTokenV5: Equatable, Codable {
let session: MatrixRustSDK.Session
let sessionDirectory: URL
let cacheDirectory: URL
let passphrase: String?
let pusherNotificationClientIdentifier: String?
}
@@ -10,6 +10,8 @@ import XCTest
@testable import ElementX @testable import ElementX
class SessionDirectoriesTests: XCTestCase { class SessionDirectoriesTests: XCTestCase {
let fileManager = FileManager.default
func testInitWithUserID() { func testInitWithUserID() {
// Given only a user ID. // Given only a user ID.
let userID = "@user:matrix.org" let userID = "@user:matrix.org"
@@ -51,4 +53,67 @@ class SessionDirectoriesTests: XCTestCase {
XCTAssertEqual(returnedDataPath, originalDataPath) XCTAssertEqual(returnedDataPath, originalDataPath)
XCTAssertEqual(returnedCachePath, originalCachePath) XCTAssertEqual(returnedCachePath, originalCachePath)
} }
func testDeleteDirectories() throws {
// Given a new set of session directories.
let sessionDirectories = SessionDirectories()
try fileManager.createDirectory(at: sessionDirectories.dataDirectory, withIntermediateDirectories: true)
try fileManager.createDirectory(at: sessionDirectories.cacheDirectory, withIntermediateDirectories: true)
XCTAssertTrue(fileManager.directoryExists(at: sessionDirectories.dataDirectory))
XCTAssertTrue(fileManager.directoryExists(at: sessionDirectories.cacheDirectory))
// When deleting the directories.
sessionDirectories.delete()
// Then neither directory should exist on disk.
XCTAssertFalse(fileManager.directoryExists(at: sessionDirectories.dataDirectory))
XCTAssertFalse(fileManager.directoryExists(at: sessionDirectories.cacheDirectory))
}
func testDeleteTransientUserData() throws {
// Given a set of session directories with some databases.
let sessionDirectories = SessionDirectories()
try fileManager.createDirectory(at: sessionDirectories.dataDirectory, withIntermediateDirectories: true)
try fileManager.createDirectory(at: sessionDirectories.cacheDirectory, withIntermediateDirectories: true)
XCTAssertTrue(fileManager.directoryExists(at: sessionDirectories.dataDirectory))
XCTAssertTrue(fileManager.directoryExists(at: sessionDirectories.cacheDirectory))
sessionDirectories.generateMockData()
XCTAssertTrue(fileManager.fileExists(atPath: sessionDirectories.mockStateStorePath))
XCTAssertTrue(fileManager.fileExists(atPath: sessionDirectories.mockCryptoStorePath))
XCTAssertTrue(fileManager.fileExists(atPath: sessionDirectories.mockEventCachePath))
XCTAssertEqual(try fileManager.numberOfItems(at: sessionDirectories.dataDirectory), 6)
XCTAssertEqual(try fileManager.numberOfItems(at: sessionDirectories.cacheDirectory), 3)
// When deleting transient user data.
sessionDirectories.deleteTransientUserData()
// Then the data directory should only contain the crypto store and the cache directory should remain but be empty.
XCTAssertTrue(fileManager.directoryExists(at: sessionDirectories.dataDirectory))
XCTAssertEqual(try fileManager.numberOfItems(at: sessionDirectories.dataDirectory), 3)
XCTAssertFalse(fileManager.fileExists(atPath: sessionDirectories.mockStateStorePath))
XCTAssertTrue(fileManager.fileExists(atPath: sessionDirectories.mockCryptoStorePath))
XCTAssertTrue(fileManager.directoryExists(at: sessionDirectories.cacheDirectory))
XCTAssertEqual(try fileManager.numberOfItems(at: sessionDirectories.cacheDirectory), 0)
XCTAssertFalse(fileManager.fileExists(atPath: sessionDirectories.mockEventCachePath))
}
}
private extension SessionDirectories {
var mockStateStorePath: String { dataDirectory.appending(component: "matrix-sdk-state.sqlite3").path(percentEncoded: false) }
var mockCryptoStorePath: String { dataDirectory.appending(component: "matrix-sdk-crypto.sqlite3").path(percentEncoded: false) }
var mockEventCachePath: String { cacheDirectory.appending(component: "matrix-sdk-event-cache.sqlite3").path(percentEncoded: false) }
func generateMockData() {
generateMockDatabase(atPath: mockStateStorePath)
generateMockDatabase(atPath: mockCryptoStorePath)
generateMockDatabase(atPath: mockEventCachePath)
}
private func generateMockDatabase(atPath path: String) {
FileManager.default.createFile(atPath: path, contents: nil)
FileManager.default.createFile(atPath: path + "-shm", contents: nil)
FileManager.default.createFile(atPath: path + "-wal", contents: nil)
}
} }