diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index fb681164..9d2c2120 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -54,12 +54,6 @@ jobs: with: xcode-version: latest-stable - uses: actions/checkout@v2 - - uses: actions/cache@v2 - with: - path: /Users/runner/Library/Developer/Xcode/DerivedData/**/SourcePackages/checkouts - key: ${{ runner.os }}-spm-ios-${{ hashFiles('**/Package.resolved') }} - restore-keys: | - ${{ runner.os }}-spm-ios - uses: webfactory/ssh-agent@v0.5.3 with: ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }} @@ -74,12 +68,6 @@ jobs: with: xcode-version: latest-stable - uses: actions/checkout@v2 - - uses: actions/cache@v2 - with: - path: /Users/runner/Library/Developer/Xcode/DerivedData/**/SourcePackages/checkouts - key: ${{ runner.os }}-spm-tvos-${{ hashFiles('**/Package.resolved') }} - restore-keys: | - ${{ runner.os }}-spm-tvos - uses: webfactory/ssh-agent@v0.5.3 with: ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }} @@ -93,12 +81,6 @@ jobs: with: xcode-version: latest-stable - uses: actions/checkout@v2 - - uses: actions/cache@v2 - with: - path: /Users/runner/Library/Developer/Xcode/DerivedData/**/SourcePackages/checkouts - key: ${{ runner.os }}-spm-watchos-${{ hashFiles('**/Package.resolved') }} - restore-keys: | - ${{ runner.os }}-spm-watchos - uses: webfactory/ssh-agent@v0.5.3 with: ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }} @@ -112,12 +94,6 @@ jobs: with: xcode-version: latest-stable - uses: actions/checkout@v2 - - uses: actions/cache@v2 - with: - path: /Users/runner/Library/Developer/Xcode/DerivedData - key: ${{ runner.os }}-spm-examples-${{ hashFiles('**/Package.resolved') }} - restore-keys: | - ${{ runner.os }}-spm-examples - uses: webfactory/ssh-agent@v0.5.3 with: ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }} @@ -141,4 +117,20 @@ jobs: run: | cd Examples/apps/SegmentUIKitExample xcodebuild -workspace "SegmentUIKitExample.xcworkspace" -scheme "SegmentUIKitExample" -destination 'platform=macOS,variant=Mac Catalyst' - \ No newline at end of file + + + build_and_test_dest_examples: + needs: cancel_previous + runs-on: macos-11 + steps: + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest-stable + - uses: actions/checkout@v2 + - uses: webfactory/ssh-agent@v0.5.3 + with: + ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }} + - name: build for ios simulator + run: | + cd Examples/apps/DestinationsExample + xcodebuild -workspace "DestinationsExample.xcworkspace" -scheme "DestinationsExample" -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 11,OS=14.0' diff --git a/Sources/Segment/Analytics.swift b/Sources/Segment/Analytics.swift index d08b7a54..c1ff10a6 100644 --- a/Sources/Segment/Analytics.swift +++ b/Sources/Segment/Analytics.swift @@ -22,11 +22,7 @@ public class Analytics { internal var storage: Storage /// Enabled/disables debug logging to trace your data going through the SDK. - public static var debugLogsEnabled = false { - didSet { - SegmentLog.loggingEnabled = debugLogsEnabled - } - } + public static var debugLogsEnabled = false public var timeline: Timeline diff --git a/Sources/Segment/Plugins/Logger/ConsoleTarget.swift b/Sources/Segment/Plugins/Logger/ConsoleTarget.swift deleted file mode 100644 index a5940fc8..00000000 --- a/Sources/Segment/Plugins/Logger/ConsoleTarget.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// ConsoleTarget.swift -// ConsoleTarget -// -// Created by Cody Garvin on 8/19/21. -// - -import Foundation - -class ConsoleTarget: LogTarget { - func parseLog(_ log: LogMessage) { - var metadata = "" - if let function = log.function, let line = log.line { - metadata = " - \(function):\(line)" - } - print("[Segment \(log.kind.toString())\(metadata)]\n\(log.message)\n") - } -} diff --git a/Sources/Segment/Plugins/Logger/LogTarget.swift b/Sources/Segment/Plugins/Logger/LogTarget.swift deleted file mode 100644 index a12bc8c7..00000000 --- a/Sources/Segment/Plugins/Logger/LogTarget.swift +++ /dev/null @@ -1,220 +0,0 @@ -// -// LogTarget.swift -// LogTarget -// -// Created by Cody Garvin on 8/19/21. -// - -import Foundation - -// MARK: - Logging Types - -/// The foundation for building out a special logger. If logs need to be directed to a certain area, this is the -/// interface to start off with. For instance a console logger, a networking logger or offline storage logger -/// would all start off with LogTarget. -public protocol LogTarget { - - /// Implement this method to process logging messages. This is where the logic for the target will be - /// added. Feel free to add your own data queueing and offline storage. - /// - important: Use the Segment Network stack for Segment library compatibility and simplicity. - func parseLog(_ log: LogMessage) - - /// Optional method to implement. This helps respond to potential queueing events being flushed out. - /// Perhaps responding to backgrounding or networking events, this gives a chance to empty a queue - /// or pump a firehose of logs. - func flush() -} - -/// Used for analytics.log() types. This lets the system know what to filter on and how to set priorities. -public enum LogFilterKind: Int { - case error = 0 // Not Verbose (fail cases | non-recoverable errors) - case warning // Semi-verbose (deprecations | potential issues) - case debug // Verbose (everything of interest) - - func toString() -> String { - switch (self) { - case .error: - return "ERROR" - case .warning: - return "Warning" - case .debug: - return "Debug" - } - } -} - -/// The Segment logging system has three types of logs: log, metric and history. When adding a target that -/// responds to logs, it is possible to adhere to 1 to many. In other words, a LoggingType can be .log & -/// .history. This is used to tell which targets logs are directed to. -public struct LoggingType: Hashable { - - public enum LogDestination { - case log - case metric - case history - } - - /// Convenience .log logging type - static let log = LoggingType(types: [.log]) - /// Convenience .metric logging type - static let metric = LoggingType(types: [.metric]) - /// Convenience .history logging type - static let history = LoggingType(types: [.history]) - - - /// Designated initializer for LoggingType. Add all the destinations this LoggingType should support. - /// - Parameter types: The LoggingDestination(s) that this LoggingType will support. - public init(types: [LogDestination]) { - // TODO: Failable scenario if types empty - self.allTypes = types - } - - // - Private Properties and Methods - private let allTypes: [LogDestination] - - /// Convience method to find if the LoggingType supports a particular destination. - /// - Parameter destination: The particular destination being tested for conformance. - /// - Returns: If the destination exists in this LoggingType `true` or `false` will be returned. - internal func contains(_ destination: LogDestination) -> Bool { - return allTypes.contains(destination) - } -} - -/// The interface to the message being returned to `LogTarget` -> `parseLog()`. -public protocol LogMessage { - var kind: LogFilterKind { get } - var title: String? { get } - var message: String { get } - var event: RawEvent? { get } - var function: String? { get } - var line: Int? { get } - var logType: LoggingType.LogDestination { get } - var dateTime: Date { get } -} - - -public enum MetricType: Int { - case counter = 0 // Not Verbose - case gauge // Semi-verbose - - func toString() -> String { - var typeString = "Gauge" - if self == .counter { - typeString = "Counter" - } - return typeString - } - - static func fromString(_ string: String) -> Self { - var returnType = Self.counter - if string == "Gauge" { - returnType = .gauge - } - - return returnType - } -} - - -// MARK: - Public Logging API - -extension Analytics { - - /// The public logging method for capturing all general types of log messages related to Segment. - /// - Parameters: - /// - message: The main message of the log to be captured. - /// - kind: Usually .error, .warning or .debug, in order of serverity. This helps filter logs based on - /// this added metadata. - /// - function: The name of the function the log came from. This will be captured automatically. - /// - line: The line number in the function the log came from. This will be captured automatically. - public func log(message: String, kind: LogFilterKind? = nil, function: String = #function, line: Int = #line) { - apply { plugin in - // Check if we should send off the event - if SegmentLog.loggingEnabled == false { - return - } - if let loggerPlugin = plugin as? SegmentLog { - var filterKind = loggerPlugin.filterKind - if let logKind = kind { - filterKind = logKind - } - - let log = LogFactory.buildLog(destination: .log, title: "", message: message, kind: filterKind, function: function, line: line) - loggerPlugin.log(log, destination: .log) - } - } - } - - /// The public logging method for capturing metrics related to Segment or other libraries. - /// - Parameters: - /// - type: Metric type, usually .counter or .gauge. Select the one that makes sense for the metric. - /// - name: The title of the metric to track. - /// - value: The value associated with the metric. This would be an incrementing counter or time - /// or pressure gauge. - /// - tags: Any tags that should be associated with the metric. Any extra metadata that may help. - public func metric(_ type: MetricType, name: String, value: Double, tags: [String]? = nil) { - apply { plugin in - // Check if we should send off the event - if SegmentLog.loggingEnabled == false { - return - } - - if let loggerPlugin = plugin as? SegmentLog { - - let log = LogFactory.buildLog(destination: .metric, title: type.toString(), message: name, value: value, tags: tags) - loggerPlugin.log(log, destination: .metric) - } - } - } - - /// Used to track the history of events as the event data travels through the Segment Event Timeline. As - /// plugins manipulate the data at the `before`, `enrichment`, `destination`, - /// `destination timeline`, and `after` states, an event can be tracked. Starting with the first one - /// - Parameters: - /// - event: The timeline event that is to be processed. - /// - sender: Where the event came from. - /// - function: The name of the function the log came from. This will be captured automatically. - /// - line: The line number in the function the log came from. This will be captured automatically. - public func history(event: RawEvent, sender: AnyObject, function: String = #function, line: Int = #line) { - apply { plugin in - // Check if we should send off the event - if SegmentLog.loggingEnabled == false { - return - } - - if let loggerPlugin = plugin as? SegmentLog { - let log = LogFactory.buildLog(destination: .history, title: event.toString(), message: "", function: function, line: line, event: event, sender: sender) - loggerPlugin.log(log, destination: .metric) - } - } - } -} - -extension Analytics { - - /// Add a logging target to the system. These `targets` can handle logs in various ways. Consider - /// sending logs to the console, the OS and a web service. Three targets can handle these scenarios. - /// - Parameters: - /// - target: A `LogTarget` that has logic to parse and handle log messages. - /// - type: The type consists of `log`, `metric` or `history`. These correspond to the - /// public API on Analytics. - public func add(target: LogTarget, type: LoggingType) { - apply { (potentialLogger) in - if let logger = potentialLogger as? SegmentLog { - do { - try logger.add(target: target, for: type) - } catch { - Self.segmentLog(message: "Could not add target: \(error.localizedDescription)", kind: .error) - } - } - } - } - - public func logFlush() { - apply { (potentialLogger) in - if let logger = potentialLogger as? SegmentLog { - logger.flush() - } - } - } -} diff --git a/Sources/Segment/Plugins/Logger/SegmentLog.swift b/Sources/Segment/Plugins/Logger/SegmentLog.swift deleted file mode 100644 index bc3d5d98..00000000 --- a/Sources/Segment/Plugins/Logger/SegmentLog.swift +++ /dev/null @@ -1,204 +0,0 @@ -// -// SegmentLog.swift -// Segment -// -// Created by Cody Garvin on 12/14/20. -// - -import Foundation - -// MARK: - Plugin Implementation - -internal class SegmentLog: UtilityPlugin { - public var filterKind = LogFilterKind.debug - weak var analytics: Analytics? - - let type = PluginType.utility - - fileprivate var loggingMediator = [LoggingType: LogTarget]() - - // Default to no, enable to see local logs - internal static var loggingEnabled = false - - // For internal use only. Note: This will contain the last created instance - // of analytics when used in a multi-analytics environment. - internal static weak var sharedAnalytics: Analytics? = nil - - #if DEBUG - internal static var globalLogger: SegmentLog { - get { - let logger = SegmentLog() - logger.addTargets() - return logger - } - } - #endif - - required init() { } - - func configure(analytics: Analytics) { - self.analytics = analytics - SegmentLog.sharedAnalytics = analytics - addTargets() - } - - internal func addTargets() { - #if !os(Linux) - try? add(target: SystemTarget(), for: LoggingType.log) - #if DEBUG - try? add(target: ConsoleTarget(), for: LoggingType.log) - #endif - #else - try? add(target: ConsoleTarget(), for: LoggingType.log) - #endif - } - - func update(settings: Settings) { - // Check for the server-side flag - if let settingsDictionary = settings.plan?.dictionaryValue, - let enabled = settingsDictionary["logging_enabled"] as? Bool { - SegmentLog.loggingEnabled = enabled - } - } - - internal func log(_ logMessage: LogMessage, destination: LoggingType.LogDestination) { - - for (logType, target) in loggingMediator { - if logType.contains(destination) { - target.parseLog(logMessage) - } - } - } - - internal func add(target: LogTarget, for loggingType: LoggingType) throws { - - // Verify the target does not exist, if it does bail out - let filtered = loggingMediator.filter { (type: LoggingType, existingTarget: LogTarget) in - Swift.type(of: existingTarget) == Swift.type(of: target) - } - if filtered.isEmpty == false { throw NSError(domain: "Target already exists", code: 2002, userInfo: nil) } - - // Finally add the target - loggingMediator[loggingType] = target - } - - internal func flush() { - for (_, target) in loggingMediator { - target.flush() - } - - // TODO: Clean up history container here - } -} - -// MARK: - Internal Types - -internal struct LogFactory { - static func buildLog(destination: LoggingType.LogDestination, - title: String, - message: String, - kind: LogFilterKind = .debug, - function: String? = nil, - line: Int? = nil, - event: RawEvent? = nil, - sender: Any? = nil, - value: Double? = nil, - tags: [String]? = nil) -> LogMessage { - - switch destination { - case .log: - return GenericLog(kind: kind, message: message, function: function, line: line) - case .metric: - return MetricLog(title: title, message: message, value: value ?? 1, event: event, function: function, line: line) - case .history: - return HistoryLog(message: message, event: event, function: function, line: line, sender: sender) - } - } - - fileprivate struct GenericLog: LogMessage { - var kind: LogFilterKind - var title: String? - var message: String - var event: RawEvent? = nil - var function: String? - var line: Int? - var logType: LoggingType.LogDestination = .log - var dateTime = Date() - } - - fileprivate struct MetricLog: LogMessage { - var title: String? - var kind: LogFilterKind = .debug - var message: String - var value: Double - var event: RawEvent? - var function: String? = nil - var line: Int? = nil - var logType: LoggingType.LogDestination = .metric - var dateTime = Date() - } - - fileprivate struct HistoryLog: LogMessage { - var kind: LogFilterKind = .debug - var title: String? - var message: String - var event: RawEvent? - var function: String? - var line: Int? - var sender: Any? - var logType: LoggingType.LogDestination = .history - var dateTime = Date() - } -} - -public extension LogTarget { - // Make flush optional with an empty implementation. - func flush() { } -} - -internal extension Analytics { - /// The internal logging method for capturing all general types of log messages related to Segment. - /// - Parameters: - /// - message: The main message of the log to be captured. - /// - kind: Usually .error, .warning or .debug, in order of serverity. This helps filter logs based on - /// this added metadata. - /// - function: The name of the function the log came from. This will be captured automatically. - /// - line: The line number in the function the log came from. This will be captured automatically. - static func segmentLog(message: String, kind: LogFilterKind? = nil, function: String = #function, line: Int = #line) { - if let shared = SegmentLog.sharedAnalytics { - shared.apply { plugin in - if let loggerPlugin = plugin as? SegmentLog { - var filterKind = loggerPlugin.filterKind - if let logKind = kind { - filterKind = logKind - } - - let log = LogFactory.buildLog(destination: .log, title: "", message: message, kind: filterKind, function: function, line: line) - loggerPlugin.log(log, destination: .log) - } - } - } else { - #if DEBUG - let log = LogFactory.buildLog(destination: .log, title: "", message: message, kind: .debug, function: function, line: line) - SegmentLog.globalLogger.log(log, destination: .log) - #endif - } - } - - /// The internal logging method for capturing metrics related to Segment or other libraries. - /// - Parameters: - /// - type: Metric type, usually .counter or .gauge. Select the one that makes sense for the metric. - /// - name: The title of the metric to track. - /// - value: The value associated with the metric. This would be an incrementing counter or time - /// or pressure gauge. Defaults to 1 if not specified. - /// - tags: Any tags that should be associated with the metric. Any extra metadata that may help. - static func segmentMetric(_ type: MetricType, name: String, value: Double, tags: [String]? = nil) { - SegmentLog.sharedAnalytics?.apply { plugin in - - if let loggerPlugin = plugin as? SegmentLog { - let log = LogFactory.buildLog(destination: .metric, title: type.toString(), message: name, value: value, tags: tags) - loggerPlugin.log(log, destination: .metric) - } - } - } -} diff --git a/Sources/Segment/Plugins/Logger/SystemTarget.swift b/Sources/Segment/Plugins/Logger/SystemTarget.swift deleted file mode 100644 index 949f8f50..00000000 --- a/Sources/Segment/Plugins/Logger/SystemTarget.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// File.swift -// File -// -// Created by Cody Garvin on 8/20/21. -// - -#if !os(Linux) - -import Foundation -import os.log - -class SystemTarget: LogTarget { - - static let logCategory = OSLog(subsystem: "Segment", category: "Log") - static let metricsCategory = OSLog(subsystem: "Segment", category: "Metrics") - static let historyCategory = OSLog(subsystem: "Segment", category: "History") - - func parseLog(_ log: LogMessage) { - var metadata = "" - if let function = log.function, let line = log.line { - metadata = " - \(function):\(line)" - } - - os_log("[Segment %{public}@ %{public}@]\n%{public}@\n", - log: categoryFor(log: log), - type: osLogTypeFromFilterKind(kind: log.kind), - log.kind.toString(), metadata, log.message) // need to fix type - } - - private func categoryFor(log: LogMessage) -> OSLog { - switch log.logType { - case .log: - return SystemTarget.logCategory - case .metric: - return SystemTarget.metricsCategory - case .history: - return SystemTarget.historyCategory - } - } - - private func osLogTypeFromFilterKind(kind: LogFilterKind) -> OSLogType { - var osLogType: OSLogType - switch kind { - case .debug: - osLogType = .info - case .warning: - osLogType = .debug - case .error: - osLogType = .error - } - return osLogType - } -} - -#endif diff --git a/Sources/Segment/Plugins/SegmentDestination.swift b/Sources/Segment/Plugins/SegmentDestination.swift index d5087a97..79dfc4dd 100644 --- a/Sources/Segment/Plugins/SegmentDestination.swift +++ b/Sources/Segment/Plugins/SegmentDestination.swift @@ -153,7 +153,7 @@ public class SegmentDestination: DestinationPlugin, Subscriber { storage.remove(file: url) self.cleanupUploads() default: - analytics.logFlush() + break } analytics.log(message: "Processed: \(url.lastPathComponent)") diff --git a/Sources/Segment/Startup.swift b/Sources/Segment/Startup.swift index b52477ad..ae87b9db 100644 --- a/Sources/Segment/Startup.swift +++ b/Sources/Segment/Startup.swift @@ -11,7 +11,6 @@ import Sovran extension Analytics: Subscriber { internal func platformStartup() { - add(plugin: SegmentLog()) add(plugin: StartupQueue()) // add segment destination plugin unless diff --git a/Sources/Segment/Utilities/Logging.swift b/Sources/Segment/Utilities/Logging.swift new file mode 100644 index 00000000..89d627ae --- /dev/null +++ b/Sources/Segment/Utilities/Logging.swift @@ -0,0 +1,42 @@ +// +// Logging.swift +// +// +// Created by Brandon Sneed on 3/9/23. +// + +import Foundation + +extension Analytics { + internal enum LogKind { + case error + case warning + case debug + case none + + var string: String { + switch self { + case .error: + return "SEG_ERROR: " + case .warning: + return "SEG_WARNING: " + case .debug: + return "SEG_DEBUG: " + case .none: + return "" + } + } + } + + internal func log(message: String) { + Self.segmentLog(message: message, kind: .none) + } + + static internal func segmentLog(message: String, kind: LogKind) { + #if DEBUG + if Self.debugLogsEnabled { + print("\(kind)\(message)") + } + #endif + } +} diff --git a/Tests/Segment-Tests/LogTarget_Tests.swift b/Tests/Segment-Tests/LogTarget_Tests.swift deleted file mode 100644 index 75944c79..00000000 --- a/Tests/Segment-Tests/LogTarget_Tests.swift +++ /dev/null @@ -1,166 +0,0 @@ -// -// LogTarget_Tests.swift -// Segment-Tests -// -// Created by Cody Garvin on 10/18/21. -// - -import Foundation -import XCTest -@testable import Segment - -final class LogTarget_Tests: XCTestCase { - - var analytics: Analytics? - let mockLogger = LoggerMockPlugin() - - class LoggerMockPlugin: SegmentLog { - var logClosure: ((LogFilterKind, LogMessage) -> Void)? - var closure: (() -> Void)? - - override func log(_ logMessage: LogMessage, destination: LoggingType.LogDestination) { - super.log(logMessage, destination: destination) - logClosure?(logMessage.kind, logMessage) - } - - override func flush() { - super.flush() - closure?() - } - } - - override func setUp() { - analytics = Analytics(configuration: Configuration(writeKey: "test")) - analytics?.add(plugin: mockLogger) - - // Enable logging for all tests - SegmentLog.loggingEnabled = true - } - - override func tearDown() { - analytics = nil - - // Reset to default state the system should be in from start - SegmentLog.loggingEnabled = false - } - - func testMetric() { - - // Arrange - let expectation = XCTestExpectation(description: "Called") - - // Assert - mockLogger.logClosure = { (kind, message) in - expectation.fulfill() - XCTAssertEqual(message.message, "Metric of 5", "Message name not correctly passed") - XCTAssertEqual(message.title, "Counter", "Type of metricnot correctly passed") - } - - // Act - analytics?.metric(MetricType.fromString("Counter"), name: "Metric of 5", value: 5, tags: ["Test"]) - wait(for: [expectation], timeout: 1.0) - } - - func testHistory() { - - // Arrange - let expectation = XCTestExpectation(description: "Called") - - // Assert - mockLogger.logClosure = { (kind, message) in - expectation.fulfill() - XCTAssertEqual(message.function, "testHistory()", "Message function not correctly passed") - XCTAssertEqual(message.logType, .history, "Type of message not correctly passed") - } - - // Act - analytics?.history(event: TrackEvent(event: "Tester", properties: nil), sender: self) - wait(for: [expectation], timeout: 1.0) - } - - func testLoggingDisabled() { - - struct LogConsoleTarget: LogTarget { - var successClosure: ((String) -> Void) - - func parseLog(_ log: LogMessage) { - XCTFail("Log should not be called when logging is disabled") - } - } - - // Arrange - SegmentLog.loggingEnabled = false - let logConsoleTarget = LogConsoleTarget(successClosure: { (logMessage: String) in - // Assert - XCTFail("This should not be called") - }) - let loggingType = LoggingType.log - analytics?.add(target: logConsoleTarget, type: loggingType) - - // Act - analytics?.log(message: "Should hit our proper target") - } - - func testMetricDisabled() { - - struct LogConsoleTarget: LogTarget { - var successClosure: ((String) -> Void) - - func parseLog(_ log: LogMessage) { - XCTFail("Log should not be called when logging is disabled") - } - } - - // Arrange - SegmentLog.loggingEnabled = false - let logConsoleTarget = LogConsoleTarget(successClosure: { (logMessage: String) in - // Assert - XCTFail("This should not be called") - }) - let loggingType = LoggingType.log - analytics?.add(target: logConsoleTarget, type: loggingType) - - // Act - analytics?.metric(MetricType.fromString("Counter"), name: "Metric of 5", value: 5, tags: ["Test"]) - } - - func testHistoryDisabled() { - - struct LogConsoleTarget: LogTarget { - var successClosure: ((String) -> Void) - - func parseLog(_ log: LogMessage) { - XCTFail("Log should not be called when logging is disabled") - } - } - - // Arrange - SegmentLog.loggingEnabled = false - let logConsoleTarget = LogConsoleTarget(successClosure: { (logMessage: String) in - // Assert - XCTFail("This should not be called") - }) - let loggingType = LoggingType.log - analytics?.add(target: logConsoleTarget, type: loggingType) - - // Act - analytics?.history(event: TrackEvent(event: "Tester", properties: nil), sender: self) - } - - func testLoggingDisabledByDefault() { - SegmentLog.loggingEnabled = false - XCTAssertFalse(SegmentLog.loggingEnabled, "Logging should not default to enabled") - } - - func testLoggingEnabledFromAnalytics() { - SegmentLog.loggingEnabled = false - - Analytics.debugLogsEnabled = true - XCTAssertTrue(SegmentLog.loggingEnabled, "Logging should change to enabled") - - Analytics.debugLogsEnabled = false - XCTAssertFalse(SegmentLog.loggingEnabled, "Logging should reset to disabled") - } - -} - diff --git a/Tests/Segment-Tests/MemoryLeak_Tests.swift b/Tests/Segment-Tests/MemoryLeak_Tests.swift index 2f7e1f71..52ce0f67 100644 --- a/Tests/Segment-Tests/MemoryLeak_Tests.swift +++ b/Tests/Segment-Tests/MemoryLeak_Tests.swift @@ -29,7 +29,6 @@ final class MemoryLeak_Tests: XCTestCase { let segmentDest = analytics.find(pluginType: SegmentDestination.self)! let destMetadata = segmentDest.timeline.find(pluginType: DestinationMetadataPlugin.self)! let startupQueue = analytics.find(pluginType: StartupQueue.self)! - let segmentLog = analytics.find(pluginType: SegmentLog.self)! let context = analytics.find(pluginType: Context.self)! @@ -48,7 +47,6 @@ final class MemoryLeak_Tests: XCTestCase { #endif analytics.remove(plugin: startupQueue) - analytics.remove(plugin: segmentLog) analytics.remove(plugin: segmentDest) segmentDest.remove(plugin: destMetadata) @@ -69,7 +67,6 @@ final class MemoryLeak_Tests: XCTestCase { RunLoop.main.run(until: Date(timeIntervalSinceNow: 1)) - checkIfLeaked(segmentLog) checkIfLeaked(segmentDest) checkIfLeaked(destMetadata) checkIfLeaked(startupQueue) diff --git a/Tests/Segment-Tests/Metrics_Tests.swift b/Tests/Segment-Tests/Metrics_Tests.swift deleted file mode 100644 index 30494773..00000000 --- a/Tests/Segment-Tests/Metrics_Tests.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// Metrics_Tests.swift -// Segment-Tests -// -// Created by Cody Garvin on 12/18/20. -// - -import Foundation -import XCTest -@testable import Segment - - -final class Metrics_Tests: XCTestCase { - - func testBaseEventCreation() { - let analytics = Analytics(configuration: Configuration(writeKey: "test")) - let myDestination = MyDestination() - myDestination.add(plugin: GooberPlugin()) - - analytics.add(plugin: ZiggyPlugin()) - analytics.add(plugin: myDestination) - - let traits = MyTraits(email: "brandon@redf.net") - analytics.identify(userId: "brandon", traits: traits) - } -} - - diff --git a/Tests/Segment-Tests/SegmentLog_Tests.swift b/Tests/Segment-Tests/SegmentLog_Tests.swift deleted file mode 100644 index 146e3393..00000000 --- a/Tests/Segment-Tests/SegmentLog_Tests.swift +++ /dev/null @@ -1,280 +0,0 @@ -// -// SegmentLog_Tests.swift -// Segment-Tests -// -// Created by Cody Garvin on 12/18/20. -// - -import Foundation -import XCTest -@testable import Segment - -final class SegmentLog_Tests: XCTestCase { - - var analytics: Analytics? - let mockLogger = LoggerMockPlugin() - - class LoggerMockPlugin: SegmentLog { - var logClosure: ((LogFilterKind, LogMessage) -> Void)? - var closure: (() -> Void)? - - override func log(_ logMessage: LogMessage, destination: LoggingType.LogDestination) { - super.log(logMessage, destination: destination) - logClosure?(logMessage.kind, logMessage) - } - - override func flush() { - super.flush() - closure?() - } - } - - override func setUp() { - analytics = Analytics(configuration: Configuration(writeKey: "test")) - analytics?.add(plugin: mockLogger) - } - - override func tearDown() { - analytics = nil - SegmentLog.loggingEnabled = true - } - - func testLogging() { - - // Arrange - let expectation = XCTestExpectation(description: "Called") - - // Assert - mockLogger.logClosure = { (kind, message) in - expectation.fulfill() - - XCTAssertEqual(kind, .debug, "Type not correctly passed") - XCTAssertEqual(message.message, "Something Other Than Awesome", "Message not correctly passed") - } - - // Act - analytics?.log(message: "Something Other Than Awesome") - wait(for: [expectation], timeout: 1.0) - } - - func testWarningLogging() { - - // Arrange - let expectation = XCTestExpectation(description: "Called") - - // Assert - mockLogger.logClosure = { (kind, message) in - expectation.fulfill() - XCTAssertEqual(kind, .warning, "Type not correctly passed") - } - - // Act - analytics?.log(message: "Something Other Than Awesome", kind: .warning) - wait(for: [expectation], timeout: 1.0) - } - - func testErrorLogging() { - - // Arrange - let expectation = XCTestExpectation(description: "Called") - - // Assert - mockLogger.logClosure = { (kind, message) in - expectation.fulfill() - - XCTAssertEqual(kind, .error, "Type not correctly passed") - } - - // Act - analytics?.log(message: "Something Other Than Awesome", kind: .error) - wait(for: [expectation], timeout: 1.0) - } - - func testUpdateSettingsFalse() { - var settings = Settings(writeKey: "123456789") - settings.plan = try? JSON(["logging_enabled": false]) - mockLogger.update(settings: settings) - - XCTAssertFalse(SegmentLog.loggingEnabled, "Enabled logging was not set correctly") - } - - func testUpdateSettingsTrue() { - - SegmentLog.loggingEnabled = false - var settings = Settings(writeKey: "123456789") - settings.plan = try? JSON(["logging_enabled": true]) - mockLogger.update(settings: settings) - - XCTAssertTrue(SegmentLog.loggingEnabled, "Enabled logging was not set correctly") - } - - func testTargetSuccess() { - - // Arrange - let expectation = XCTestExpectation(description: "Called") - - struct LogConsoleTarget: LogTarget { - var successClosure: ((String) -> Void) - - func parseLog(_ log: LogMessage) { - print("[Segment Tests - \(log.function ?? ""):\(String(log.line ?? 0))] \(log.message)\n") - successClosure(log.message) - } - } - - let logConsoleTarget = LogConsoleTarget(successClosure: { (logMessage: String) in - expectation.fulfill() - }) - let loggingType = LoggingType.log - analytics?.add(target: logConsoleTarget, type: loggingType) - - // Act - analytics?.log(message: "Should hit our proper target") - wait(for: [expectation], timeout: 1.0) - } - - func testTargetFailure() { - - // Arrange - struct LogConsoleTarget: LogTarget { - var successClosure: ((String) -> Void) - - func parseLog(_ log: LogMessage) { - print("[Segment Tests - \(log.function ?? ""):\(String(log.line ?? 0))] \(log.message)\n") - successClosure(log.message) - } - } - - let logConsoleTarget = LogConsoleTarget(successClosure: { (logMessage: String) in - XCTFail("Should not hit this since it was registered for history") - }) - let loggingType = LoggingType.history - analytics?.add(target: logConsoleTarget, type: loggingType) - - // Act - analytics?.log(message: "Should hit our proper target") - } - - func testFlush() { - // Arrange - let expectation = XCTestExpectation(description: "Called") - - struct LogConsoleTarget: LogTarget { - var successClosure: ((String) -> Void) - - func parseLog(_ log: LogMessage) { - XCTFail("Log should not be called when logging is disabled") - } - } - - // Arrange - mockLogger.closure = { - expectation.fulfill() - } - - // Act - analytics?.flush() - - wait(for: [expectation], timeout: 1.0) - } - - func testLogFlush() { - // Arrange - let expectation = XCTestExpectation(description: "Called") - - struct LogConsoleTarget: LogTarget { - var successClosure: ((String) -> Void) - - func parseLog(_ log: LogMessage) { - XCTFail("Log should not be called when logging is disabled") - } - } - - // Arrange - mockLogger.closure = { - expectation.fulfill() - } - - // Act - analytics?.logFlush() - - wait(for: [expectation], timeout: 1.0) - } - - - func testInternalLog() { - // Arrange - let expectation = XCTestExpectation(description: "Called") - - - // Assert - mockLogger.logClosure = { (kind, message) in - expectation.fulfill() - XCTAssertEqual(kind, .warning, "Type not correctly passed") - } - - // Act - Analytics.segmentLog(message: "Should hit our proper target", kind: .warning) - wait(for: [expectation], timeout: 1.0) - } - - func testInternalMetricCounter() { - // Arrange - let expectation = XCTestExpectation(description: "Called") - - // Assert - mockLogger.logClosure = { (kind, message) in - expectation.fulfill() - XCTAssertEqual(message.message, "Metric of 5", "Message name not correctly passed") - XCTAssertEqual(message.title, "Counter", "Type of metric not correctly passed") - } - - // Act - Analytics.segmentMetric(MetricType.fromString("Counter"), name: "Metric of 5", value: 5, tags: ["Test"]) - wait(for: [expectation], timeout: 1.0) - } - - func testInternalMetricGauge() { - // Arrange - let expectation = XCTestExpectation(description: "Called") - - // Assert - mockLogger.logClosure = { (kind, message) in - expectation.fulfill() - XCTAssertEqual(message.message, "Metric of 5", "Message name not correctly passed") - XCTAssertEqual(message.title, "Gauge", "Type of metric not correctly passed") - } - - // Act - Analytics.segmentMetric(MetricType.fromString("Gauge"), name: "Metric of 5", value: 5, tags: ["Test"]) - wait(for: [expectation], timeout: 1.0) - } - - func testAddTargetTwice() { - - // Arrange - struct LogConsoleTarget: LogTarget { - func parseLog(_ log: LogMessage) {} - } - let expectation = XCTestExpectation(description: "Called") - mockLogger.logClosure = { (kind, logMessage) in - XCTAssertTrue(logMessage.message.contains("Could not add target")) - expectation.fulfill() - } - - // Arrange - SegmentLog.loggingEnabled = false - let logConsoleTarget = LogConsoleTarget() - let loggingType = LoggingType.log - - // Act - analytics?.add(target: logConsoleTarget, type: loggingType) - // Add a second time to get a duplicate error - analytics?.add(target: logConsoleTarget, type: loggingType) - - wait(for: [expectation], timeout: 1.0) - - } - -} - diff --git a/Tests/Segment-Tests/Support/TestUtilities.swift b/Tests/Segment-Tests/Support/TestUtilities.swift index 20dce445..a34dd31e 100644 --- a/Tests/Segment-Tests/Support/TestUtilities.swift +++ b/Tests/Segment-Tests/Support/TestUtilities.swift @@ -33,17 +33,9 @@ class GooberPlugin: EventPlugin { } func identify(event: IdentifyEvent) -> IdentifyEvent? { - let beginningTime = Date() var newEvent = IdentifyEvent(existing: event) newEvent.userId = "goober" - sleep(3) - let endingTime = Date() - let finalTime = endingTime.timeIntervalSince(beginningTime) - - Analytics.segmentMetric(.gauge, name: "Gauge Test", value: finalTime, tags: ["timing", "function_length"]) - return newEvent - //return nil } }