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