1 // Copyright (c) 2022 650 Industries, Inc. All rights reserved. 2 3 import XCTest 4 5 @testable import EXUpdates 6 @testable import ExpoModulesCore 7 8 @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) 9 class EXUpdatesLogReaderTests: XCTestCase { setUpnull10 override func setUp() { 11 clearLogSync() 12 } 13 test_ReadLogsAsDictionariesnull14 func test_ReadLogsAsDictionaries() { 15 let logReader = UpdatesLogReader() 16 17 // Mark the date 18 let epoch = Date() 19 20 // Write a log message 21 logErrorSync(message: "Test message", code: .noUpdatesAvailable) 22 23 // Write another log message 24 logWarnSync(message: "Warning message", code: .assetsFailedToLoad, updateId: "myUpdateId", assetId: "myAssetId") 25 26 // Use reader to retrieve messages 27 var logEntries: [[String: Any]] = [] 28 do { 29 logEntries = try logReader.getLogEntries(newerThan: epoch) 30 } catch { 31 XCTFail("logEntries call failed: \(error.localizedDescription)") 32 } 33 34 // Verify number of log entries and decoded values 35 XCTAssertTrue(logEntries.count >= 2) 36 37 // Check number of entries and values in each entry 38 39 let logEntry: [String: Any] = logEntries[logEntries.count - 2] 40 41 XCTAssertTrue(logEntry["timestamp"] as? UInt == UInt(epoch.timeIntervalSince1970) * 1_000) 42 XCTAssertTrue(logEntry["message"] as? String == "Test message") 43 XCTAssertTrue(logEntry["code"] as? String == "NoUpdatesAvailable") 44 XCTAssertTrue(logEntry["level"] as? String == "error") 45 XCTAssertNil(logEntry["updateId"]) 46 XCTAssertNil(logEntry["assetId"]) 47 XCTAssertFalse((logEntry["stacktrace"] as? [String] ?? []).isEmpty) 48 49 let logEntry2: [String: Any] = logEntries[logEntries.count - 1] 50 XCTAssertTrue(logEntry2["timestamp"] as? UInt == UInt(epoch.timeIntervalSince1970) * 1_000) 51 XCTAssertTrue(logEntry2["message"] as? String == "Warning message") 52 XCTAssertTrue(logEntry2["code"] as? String == "AssetsFailedToLoad") 53 XCTAssertTrue(logEntry2["level"] as? String == "warn") 54 XCTAssertTrue(logEntry2["updateId"] as? String == "myUpdateId") 55 XCTAssertTrue(logEntry2["assetId"] as? String == "myAssetId") 56 XCTAssertNil(logEntry2["stacktrace"]) 57 } 58 test_PurgeOldLogsnull59 func test_PurgeOldLogs() { 60 let logReader = UpdatesLogReader() 61 62 let date1 = Date() 63 purgeEntriesSync(logReader: logReader, olderThan: date1) 64 65 logErrorSync(message: "Test message", code: .noUpdatesAvailable) 66 RunLoop.current.run(until: Date().addingTimeInterval(1)) 67 68 let date2 = Date() 69 logWarnSync(message: "Test message", code: .assetsFailedToLoad, updateId: "myUpdateId", assetId: "myAssetId") 70 71 let entries1: [String] = logReader.getLogEntries(newerThan: date1) 72 .filter {entryString in 73 entryString.contains("Test message") 74 } 75 XCTAssertEqual(2, entries1.count) 76 77 let entries2: [String] = logReader.getLogEntries(newerThan: date2) 78 .filter {entryString in 79 entryString.contains("Test message") 80 } 81 XCTAssertEqual(1, entries2.count) 82 83 purgeEntriesSync(logReader: logReader, olderThan: date2) 84 85 let entries3: [String] = logReader.getLogEntries(newerThan: date1) 86 .filter {entryString in 87 entryString.contains("Test message") 88 } 89 90 XCTAssertEqual(1, entries3.count) 91 } 92 93 // MARK: - - Private methods 94 clearLogSyncnull95 func clearLogSync() { 96 let expectation = self.expectation(description: "log cleared") 97 let persistentLog = PersistentFileLog(category: UpdatesLogger.EXPO_UPDATES_LOG_CATEGORY) 98 persistentLog.clearEntries { _ in 99 expectation.fulfill() 100 } 101 wait(for: [expectation], timeout: 0.5) 102 } 103 logErrorSyncnull104 func logErrorSync(message: String, code: UpdatesErrorCode) { 105 let expectation = self.expectation(description: "error logged") 106 let persistentLog = PersistentFileLog(category: UpdatesLogger.EXPO_UPDATES_LOG_CATEGORY) 107 let logEntryString = "xx" + UpdatesLogger().logEntryString(message: message, code: code, level: .error, updateId: nil, assetId: nil) 108 persistentLog.appendEntry(entry: logEntryString) {_ in 109 expectation.fulfill() 110 } 111 wait(for: [expectation], timeout: 0.5) 112 } 113 logWarnSyncnull114 func logWarnSync(message: String, code: UpdatesErrorCode, updateId: String?, assetId: String?) { 115 let expectation = self.expectation(description: "error logged") 116 let persistentLog = PersistentFileLog(category: UpdatesLogger.EXPO_UPDATES_LOG_CATEGORY) 117 let logEntryString = "xx" + UpdatesLogger().logEntryString(message: message, code: code, level: .warn, updateId: updateId, assetId: assetId) 118 persistentLog.appendEntry(entry: logEntryString) {_ in 119 expectation.fulfill() 120 } 121 wait(for: [expectation], timeout: 0.5) 122 } 123 purgeEntriesSyncnull124 func purgeEntriesSync(logReader: UpdatesLogReader, olderThan: Date) { 125 let expectation = self.expectation(description: "logs purged") 126 logReader.purgeLogEntries(olderThan: olderThan) { _ in 127 expectation.fulfill() 128 } 129 wait(for: [expectation], timeout: 0.5) 130 } 131 } 132