mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-06 12:28:29 +00:00
Refactor LoggingTests utilising Rust's new ability to redirect log files at runtime. (#4353)
This commit is contained in:
@@ -8,6 +8,10 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
class UnitTestsAppCoordinator: AppCoordinatorProtocol {
|
class UnitTestsAppCoordinator: AppCoordinatorProtocol {
|
||||||
|
private let targetConfiguration: Target.ConfigurationResult
|
||||||
|
static let targetRageshakeURL = RemotePreference<RageshakeConfiguration>(.url("bugs.example.com/submit"))
|
||||||
|
static let targetAppHooks = AppHooks()
|
||||||
|
|
||||||
let windowManager: SecureWindowManagerProtocol
|
let windowManager: SecureWindowManagerProtocol
|
||||||
|
|
||||||
init(appDelegate: AppDelegate) {
|
init(appDelegate: AppDelegate) {
|
||||||
@@ -23,6 +27,17 @@ class UnitTestsAppCoordinator: AppCoordinatorProtocol {
|
|||||||
analyticsClient.isRunning = false
|
analyticsClient.isRunning = false
|
||||||
ServiceLocator.shared.register(analytics: AnalyticsService(client: analyticsClient,
|
ServiceLocator.shared.register(analytics: AnalyticsService(client: analyticsClient,
|
||||||
appSettings: ServiceLocator.shared.settings))
|
appSettings: ServiceLocator.shared.settings))
|
||||||
|
|
||||||
|
// As the tests take advantage of Rust's ability to redirect the log files, there is
|
||||||
|
// often some debris left from the previous run, so we wipe the entire directory.
|
||||||
|
// This is an NOT an advised way to delete logs in production, `Tracing.deleteLogFiles`
|
||||||
|
// exists for that purpose.
|
||||||
|
try? FileManager.default.removeItem(at: .appGroupLogsDirectory)
|
||||||
|
targetConfiguration = Target.tests.configure(logLevel: .info,
|
||||||
|
traceLogPacks: [],
|
||||||
|
sentryURL: nil,
|
||||||
|
rageshakeURL: Self.targetRageshakeURL,
|
||||||
|
appHooks: Self.targetAppHooks)
|
||||||
}
|
}
|
||||||
|
|
||||||
func start() { }
|
func start() { }
|
||||||
|
|||||||
+1
-1
Submodule Enterprise updated: 7761fe61ca...33a280ecbe
@@ -10,45 +10,22 @@
|
|||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
class LoggingTests: XCTestCase {
|
class LoggingTests: XCTestCase {
|
||||||
static var targetConfiguration: Target.ConfigurationResult?
|
|
||||||
|
|
||||||
private enum Constants {
|
private enum Constants {
|
||||||
static let genericFailure = "Test failed"
|
static let genericFailure = "Test failed"
|
||||||
}
|
}
|
||||||
|
|
||||||
override func setUpWithError() throws {
|
override func tearDown() async throws {
|
||||||
Tracing.deleteLogFiles(in: Tracing.logsDirectory)
|
Tracing.logsDirectoryOverride = nil
|
||||||
|
try reloadTracingFileWriter(configuration: .init(path: URL.appGroupLogsDirectory.path(percentEncoded: false),
|
||||||
|
filePrefix: "console-tests",
|
||||||
|
fileSuffix: "log",
|
||||||
|
maxFiles: 100))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testLogging() async throws {
|
func testFileLogging() throws {
|
||||||
let target = "tests"
|
try setupTest()
|
||||||
XCTAssertTrue(Tracing.logFiles.isEmpty)
|
|
||||||
|
|
||||||
if Self.targetConfiguration == nil {
|
|
||||||
Self.targetConfiguration = Target.tests.configure(logLevel: .info,
|
|
||||||
traceLogPacks: [],
|
|
||||||
sentryURL: nil,
|
|
||||||
rageshakeURL: ServiceLocator.shared.settings.bugReportRageshakeURL,
|
|
||||||
appHooks: AppHooks())
|
|
||||||
}
|
|
||||||
|
|
||||||
// There is something weird with Rust logging where the file writing handle doesn't
|
|
||||||
// notice that the file it is writing to was deleted, so we can't run these checks
|
|
||||||
// as separate tests. So instead we need to make sure we run all the tests that
|
|
||||||
// write logs in this single test case after configuring the log system.
|
|
||||||
|
|
||||||
try validateFileLogging()
|
|
||||||
try validateLogLevels()
|
|
||||||
try validateTargetName(target)
|
|
||||||
|
|
||||||
try validateRoomSummaryContentIsRedacted()
|
|
||||||
try await validateTimelineContentIsRedacted()
|
|
||||||
try validateRustMessageContentIsRedacted()
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateFileLogging() throws {
|
|
||||||
let infoLog = UUID().uuidString
|
let infoLog = UUID().uuidString
|
||||||
|
|
||||||
MXLog.info(infoLog)
|
MXLog.info(infoLog)
|
||||||
|
|
||||||
guard let logFile = Tracing.logFiles.first else {
|
guard let logFile = Tracing.logFiles.first else {
|
||||||
@@ -59,10 +36,12 @@ class LoggingTests: XCTestCase {
|
|||||||
try XCTAssertTrue(String(contentsOf: logFile).contains(infoLog))
|
try XCTAssertTrue(String(contentsOf: logFile).contains(infoLog))
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateLogLevels() throws {
|
func testLogLevels() throws {
|
||||||
let verboseLog = UUID().uuidString
|
try setupTest()
|
||||||
|
|
||||||
|
let verboseLog = UUID().uuidString
|
||||||
MXLog.verbose(verboseLog)
|
MXLog.verbose(verboseLog)
|
||||||
|
|
||||||
guard let logFile = Tracing.logFiles.first else {
|
guard let logFile = Tracing.logFiles.first else {
|
||||||
XCTFail(Constants.genericFailure)
|
XCTFail(Constants.genericFailure)
|
||||||
return
|
return
|
||||||
@@ -70,18 +49,23 @@ class LoggingTests: XCTestCase {
|
|||||||
|
|
||||||
try XCTAssertFalse(String(contentsOf: logFile).contains(verboseLog))
|
try XCTAssertFalse(String(contentsOf: logFile).contains(verboseLog))
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateTargetName(_ target: String) throws {
|
/// This is meant to test the `Target.tests.configure(…)`, but at this stage the test is somewhat pointless
|
||||||
|
/// as it is unlikely to have been called before `tearDown` has manually set the file prefix 😕.
|
||||||
|
func testTargetName() throws {
|
||||||
MXLog.info(UUID().uuidString)
|
MXLog.info(UUID().uuidString)
|
||||||
guard let logFile = Tracing.logFiles.first else {
|
guard let logFile = Tracing.logFiles.first else {
|
||||||
XCTFail(Constants.genericFailure)
|
XCTFail(Constants.genericFailure)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let target = "tests"
|
||||||
XCTAssertTrue(logFile.lastPathComponent.contains(target))
|
XCTAssertTrue(logFile.lastPathComponent.contains(target))
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateRoomSummaryContentIsRedacted() throws {
|
func testRoomSummaryContentIsRedacted() throws {
|
||||||
|
try setupTest()
|
||||||
|
|
||||||
// Given a room summary that contains sensitive information
|
// Given a room summary that contains sensitive information
|
||||||
let roomName = "Private Conversation"
|
let roomName = "Private Conversation"
|
||||||
let lastMessage = "Secret information"
|
let lastMessage = "Secret information"
|
||||||
@@ -123,7 +107,9 @@ class LoggingTests: XCTestCase {
|
|||||||
XCTAssertFalse(content.contains(heroName))
|
XCTAssertFalse(content.contains(heroName))
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateTimelineContentIsRedacted() async throws {
|
func testTimelineContentIsRedacted() async throws {
|
||||||
|
try setupTest()
|
||||||
|
|
||||||
// Given timeline items that contain text
|
// Given timeline items that contain text
|
||||||
let textAttributedString = "TextAttributed"
|
let textAttributedString = "TextAttributed"
|
||||||
let textMessage = TextRoomTimelineItem(id: .randomEvent,
|
let textMessage = TextRoomTimelineItem(id: .randomEvent,
|
||||||
@@ -183,14 +169,6 @@ class LoggingTests: XCTestCase {
|
|||||||
contentType: nil))
|
contentType: nil))
|
||||||
|
|
||||||
// When logging that value
|
// When logging that value
|
||||||
if Self.targetConfiguration == nil {
|
|
||||||
Self.targetConfiguration = Target.tests.configure(logLevel: .info,
|
|
||||||
traceLogPacks: [],
|
|
||||||
sentryURL: nil,
|
|
||||||
rageshakeURL: ServiceLocator.shared.settings.bugReportRageshakeURL,
|
|
||||||
appHooks: AppHooks())
|
|
||||||
}
|
|
||||||
|
|
||||||
MXLog.info(textMessage)
|
MXLog.info(textMessage)
|
||||||
MXLog.info(noticeMessage)
|
MXLog.info(noticeMessage)
|
||||||
MXLog.info(emoteMessage)
|
MXLog.info(emoteMessage)
|
||||||
@@ -227,7 +205,9 @@ class LoggingTests: XCTestCase {
|
|||||||
XCTAssertFalse(content.contains(fileMessage.body))
|
XCTAssertFalse(content.contains(fileMessage.body))
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateRustMessageContentIsRedacted() throws {
|
func testRustMessageContentIsRedacted() throws {
|
||||||
|
try setupTest()
|
||||||
|
|
||||||
// Given message content that contain text
|
// Given message content that contain text
|
||||||
let textString = "TextString"
|
let textString = "TextString"
|
||||||
let rustTextMessage = TextMessageContent(body: "",
|
let rustTextMessage = TextMessageContent(body: "",
|
||||||
@@ -292,6 +272,8 @@ class LoggingTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testLogFileSorting() async throws {
|
func testLogFileSorting() async throws {
|
||||||
|
try setupTest(redirectTracingFileWriter: false)
|
||||||
|
|
||||||
// Given a collection of log files.
|
// Given a collection of log files.
|
||||||
XCTAssertTrue(Tracing.logFiles.isEmpty)
|
XCTAssertTrue(Tracing.logFiles.isEmpty)
|
||||||
|
|
||||||
@@ -340,4 +322,26 @@ class LoggingTests: XCTestCase {
|
|||||||
"console.3.log",
|
"console.3.log",
|
||||||
"console.2.log"])
|
"console.2.log"])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Helpers
|
||||||
|
|
||||||
|
/// There is something weird with Rust logging where the file writing handle won't notice that the file it is writing
|
||||||
|
/// to has been deleted. So in order to run the tests that validate the file output, we must use a new directory
|
||||||
|
/// to start with a fresh state (as calling ``Tracing.deleteLogFiles`` would trigger the bug).
|
||||||
|
private func setupTest(name: String = #function, redirectTracingFileWriter: Bool = true) throws {
|
||||||
|
let testDirectory = URL.appGroupLogsDirectory.appending(component: name, directoryHint: .isDirectory)
|
||||||
|
Tracing.logsDirectoryOverride = testDirectory
|
||||||
|
try? FileManager.default.createDirectory(at: testDirectory, withIntermediateDirectories: true)
|
||||||
|
|
||||||
|
// Make an assertion before redirecting the logs as it the SDK is likely to put an empty file
|
||||||
|
// in the directory, ready to be written to.
|
||||||
|
XCTAssertTrue(Tracing.logFiles.isEmpty)
|
||||||
|
|
||||||
|
if redirectTracingFileWriter {
|
||||||
|
try reloadTracingFileWriter(configuration: .init(path: testDirectory.path(percentEncoded: false),
|
||||||
|
filePrefix: "console",
|
||||||
|
fileSuffix: "log",
|
||||||
|
maxFiles: 100))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user