diff --git a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+ClientBehavior.swift b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+ClientBehavior.swift index c2e168e217..343b51094e 100644 --- a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+ClientBehavior.swift +++ b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+ClientBehavior.swift @@ -10,8 +10,8 @@ import AWSPinpoint import Foundation @_spi(InternalAWSPinpoint) import InternalAWSPinpoint -extension AWSPinpointAnalyticsPlugin { - public func identifyUser(userId: String, userProfile: AnalyticsUserProfile?) { +public extension AWSPinpointAnalyticsPlugin { + func identifyUser(userId: String, userProfile: AnalyticsUserProfile?) { if !isEnabled { log.warn("Cannot identify user. Analytics is disabled. Call Amplify.Analytics.enable() to enable") return @@ -20,12 +20,14 @@ extension AWSPinpointAnalyticsPlugin { Task { var currentEndpointProfile = await pinpoint.currentEndpointProfile() currentEndpointProfile.addUserId(userId) - if let userProfile = userProfile { + if let userProfile { currentEndpointProfile.addUserProfile(userProfile) } do { - try await pinpoint.updateEndpoint(with: currentEndpointProfile, - source: .analytics) + try await pinpoint.updateEndpoint( + with: currentEndpointProfile, + source: .analytics + ) Amplify.Hub.dispatchIdentifyUser(userId, userProfile: userProfile) } catch { Amplify.Hub.dispatchIdentifyUser(AnalyticsErrorHelper.getDefaultError(error)) @@ -33,7 +35,7 @@ extension AWSPinpointAnalyticsPlugin { } } - public func record(event: AnalyticsEvent) { + func record(event: AnalyticsEvent) { if !isEnabled { log.warn("Cannot record events. Analytics is disabled. Call Amplify.Analytics.enable() to enable") return @@ -55,12 +57,12 @@ extension AWSPinpointAnalyticsPlugin { } } - public func record(eventWithName eventName: String) { + func record(eventWithName eventName: String) { let event = BasicAnalyticsEvent(name: eventName) record(event: event) } - public func registerGlobalProperties(_ properties: [String: AnalyticsPropertyValue]) { + func registerGlobalProperties(_ properties: [String: AnalyticsPropertyValue]) { // TODO: check if there is a limit on total number of properties properties.forEach { key, _ in guard key.count >= 1, key.count <= 50 else { @@ -75,13 +77,13 @@ extension AWSPinpointAnalyticsPlugin { } } - public func unregisterGlobalProperties(_ keys: Set?) { + func unregisterGlobalProperties(_ keys: Set?) { Task { await unregisterGlobalProperties(keys) } } - public func flushEvents() { + func flushEvents() { if !isEnabled { log.warn("Cannot flushEvents. Analytics is disabled. Call Amplify.Analytics.enable() to enable") return @@ -105,18 +107,18 @@ extension AWSPinpointAnalyticsPlugin { } } - public func enable() { + func enable() { isEnabled = true } - public func disable() { + func disable() { isEnabled = false } /// Retrieve the escape hatch to perform actions directly on PinpointClient. /// /// - Returns: PinpointClientProtocol instance - public func getEscapeHatch() -> PinpointClientProtocol { + func getEscapeHatch() -> PinpointClientProtocol { pinpoint.pinpointClient } @@ -128,7 +130,7 @@ extension AWSPinpointAnalyticsPlugin { } private func unregisterGlobalProperties(_ keys: Set?) async { - guard let keys = keys else { + guard let keys else { for (key, value) in globalProperties { await pinpoint.removeGlobalProperty(value, forKey: key) } diff --git a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+Configure.swift b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+Configure.swift index 2acad0b80b..33a9cd9850 100644 --- a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+Configure.swift +++ b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+Configure.swift @@ -11,7 +11,7 @@ import Foundation @_spi(InternalAWSPinpoint) import InternalAWSPinpoint import Network -extension AWSPinpointAnalyticsPlugin { +public extension AWSPinpointAnalyticsPlugin { /// Configures AWSPinpointAnalyticsPlugin with the specified configuration. /// /// This method will be invoked as part of the Amplify configuration flow. @@ -19,7 +19,7 @@ extension AWSPinpointAnalyticsPlugin { /// - Parameter configuration: The configuration specified for this plugin /// - Throws: /// - PluginError.pluginConfigurationError: If one of the configuration values is invalid or empty - public func configure(using configuration: Any?) throws { + func configure(using configuration: Any?) throws { let pluginConfiguration: AWSPinpointAnalyticsPluginConfiguration if let config = configuration as? AmplifyOutputsData { print(config) @@ -45,7 +45,7 @@ extension AWSPinpointAnalyticsPlugin { } /// Configure AWSPinpointAnalyticsPlugin programatically using AWSPinpointAnalyticsPluginConfiguration - public func configure(using configuration: AWSPinpointAnalyticsPluginConfiguration) throws { + func configure(using configuration: AWSPinpointAnalyticsPluginConfiguration) throws { let pinpoint = try AWSPinpointFactory.sharedPinpoint( appId: configuration.appId, region: configuration.region @@ -82,10 +82,12 @@ extension AWSPinpointAnalyticsPlugin { // MARK: Internal /// Internal configure method to set the properties of the plugin - func configure(pinpoint: AWSPinpointBehavior, - networkMonitor: NetworkMonitor, - globalProperties: AtomicDictionary = [:], - isEnabled: Bool = true) { + internal func configure( + pinpoint: AWSPinpointBehavior, + networkMonitor: NetworkMonitor, + globalProperties: AtomicDictionary = [:], + isEnabled: Bool = true + ) { self.pinpoint = pinpoint self.networkMonitor = networkMonitor self.globalProperties = globalProperties diff --git a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+Options.swift b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+Options.swift index 9849e6e9f5..ac44e7e82f 100644 --- a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+Options.swift +++ b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+Options.swift @@ -7,8 +7,8 @@ import Foundation -extension AWSPinpointAnalyticsPlugin { - public struct Options { +public extension AWSPinpointAnalyticsPlugin { + struct Options { static let defaultAutoFlushEventsInterval: TimeInterval = 60 static let defaultTrackAppSession = true @@ -16,14 +16,18 @@ extension AWSPinpointAnalyticsPlugin { public let trackAppSessions: Bool #if os(macOS) - public init(autoFlushEventsInterval: TimeInterval = 60, - trackAppSessions: Bool = true) { + public init( + autoFlushEventsInterval: TimeInterval = 60, + trackAppSessions: Bool = true + ) { self.autoFlushEventsInterval = autoFlushEventsInterval self.trackAppSessions = trackAppSessions } #else - public init(autoFlushEventsInterval: TimeInterval = 60, - trackAppSessions: Bool = true) { + public init( + autoFlushEventsInterval: TimeInterval = 60, + trackAppSessions: Bool = true + ) { self.autoFlushEventsInterval = autoFlushEventsInterval self.trackAppSessions = trackAppSessions } diff --git a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+Reset.swift b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+Reset.swift index c6e43f86da..3c2c0dc32f 100644 --- a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+Reset.swift +++ b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+Reset.swift @@ -9,9 +9,9 @@ import Amplify import Foundation @_spi(InternalAWSPinpoint) import InternalAWSPinpoint -extension AWSPinpointAnalyticsPlugin { +public extension AWSPinpointAnalyticsPlugin { /// Resets the state of the plugin - public func reset() async { + func reset() async { if pinpoint != nil { pinpoint = nil } diff --git a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Configuration/AWSPinpointAnalyticsPluginConfiguration.swift b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Configuration/AWSPinpointAnalyticsPluginConfiguration.swift index 44456d7c60..1d625d7518 100644 --- a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Configuration/AWSPinpointAnalyticsPluginConfiguration.swift +++ b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Configuration/AWSPinpointAnalyticsPluginConfiguration.swift @@ -6,8 +6,8 @@ // @_spi(InternalAmplifyConfiguration) import Amplify -import AWSPinpoint import AWSClientRuntime +import AWSPinpoint import Foundation @_spi(InternalAWSPinpoint) import InternalAWSPinpoint @@ -58,9 +58,11 @@ public struct AWSPinpointAnalyticsPluginConfiguration { if let options { configOptions = options } else { - configOptions = .init( - autoFlushEventsInterval: try Self.getAutoFlushEventsInterval(configObject), - trackAppSessions: try Self.getTrackAppSessions(configObject)) + configOptions = try .init( + autoFlushEventsInterval: Self.getAutoFlushEventsInterval(configObject), + trackAppSessions: Self.getTrackAppSessions(configObject) + ) + } let autoSessionTrackingInterval = try Self.getAutoSessionTrackingInterval(configObject) @@ -71,14 +73,18 @@ public struct AWSPinpointAnalyticsPluginConfiguration { Self.logger.warn("Having different regions for Analytics and Targeting operations is not supported. The Analytics region will be used.") } - self.init(appId: pluginConfiguration.appId, - region: pluginConfiguration.region, - autoSessionTrackingInterval: autoSessionTrackingInterval, - options: configOptions) + self.init( + appId: pluginConfiguration.appId, + region: pluginConfiguration.region, + autoSessionTrackingInterval: autoSessionTrackingInterval, + options: configOptions + ) } - init(_ configuration: AmplifyOutputsData, - options: AWSPinpointAnalyticsPlugin.Options) throws { + init( + _ configuration: AmplifyOutputsData, + options: AWSPinpointAnalyticsPlugin.Options + ) throws { guard let analyticsConfig = configuration.analytics else { throw PluginError.pluginConfigurationError( AnalyticsPluginErrorConstant.missingAnalyticsCategoryConfiguration.errorDescription, @@ -93,16 +99,20 @@ public struct AWSPinpointAnalyticsPluginConfiguration { ) } - self.init(appId: pinpointAnalyticsConfig.appId, - region: pinpointAnalyticsConfig.awsRegion, - autoSessionTrackingInterval: Self.defaultAutoSessionTrackingInterval, - options: options) + self.init( + appId: pinpointAnalyticsConfig.appId, + region: pinpointAnalyticsConfig.awsRegion, + autoSessionTrackingInterval: Self.defaultAutoSessionTrackingInterval, + options: options + ) } - init(appId: String, - region: String, - autoSessionTrackingInterval: TimeInterval, - options: AWSPinpointAnalyticsPlugin.Options) { + init( + appId: String, + region: String, + autoSessionTrackingInterval: TimeInterval, + options: AWSPinpointAnalyticsPlugin.Options + ) { self.appId = appId self.region = region self.autoSessionTrackingInterval = autoSessionTrackingInterval @@ -148,7 +158,7 @@ public struct AWSPinpointAnalyticsPluginConfiguration { private static func getAutoSessionTrackingInterval(_ configuration: [String: JSONValue]) throws -> TimeInterval { guard let autoSessionTrackingInterval = configuration[autoSessionTrackingIntervalKey] else { - return Self.defaultAutoSessionTrackingInterval + return defaultAutoSessionTrackingInterval } guard case let .number(autoSessionTrackingIntervalValue) = autoSessionTrackingInterval else { diff --git a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Constants/AnalyticsErrorConstants.swift b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Constants/AnalyticsErrorConstants.swift index 2ea40f5eb7..49cc32f2ba 100644 --- a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Constants/AnalyticsErrorConstants.swift +++ b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Constants/AnalyticsErrorConstants.swift @@ -10,7 +10,7 @@ import Foundation typealias AnalyticsPluginErrorString = (errorDescription: ErrorDescription, recoverySuggestion: RecoverySuggestion) -struct AnalyticsPluginErrorConstant { +enum AnalyticsPluginErrorConstant { static let decodeConfigurationError: AnalyticsPluginErrorString = ( "Unable to decode configuration", "Make sure the plugin configuration is JSONValue" diff --git a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Extensions/AWSPinpointAnalyticsPlugin+HubCategory.swift b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Extensions/AWSPinpointAnalyticsPlugin+HubCategory.swift index a51cb40aee..286274402c 100644 --- a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Extensions/AWSPinpointAnalyticsPlugin+HubCategory.swift +++ b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Extensions/AWSPinpointAnalyticsPlugin+HubCategory.swift @@ -11,8 +11,10 @@ import Foundation extension HubCategory { func dispatchIdentifyUser(_ identityId: String, userProfile: AnalyticsUserProfile?) { - let payload = HubPayload(eventName: HubPayload.EventName.Analytics.identifyUser, - data: (identityId, userProfile)) + let payload = HubPayload( + eventName: HubPayload.EventName.Analytics.identifyUser, + data: (identityId, userProfile) + ) dispatch(to: .analytics, payload: payload) } diff --git a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Extensions/PinpointEvent+AnalyticsEvent.swift b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Extensions/PinpointEvent+AnalyticsEvent.swift index bc51eec63c..f42e5cd596 100644 --- a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Extensions/PinpointEvent+AnalyticsEvent.swift +++ b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Extensions/PinpointEvent+AnalyticsEvent.swift @@ -9,8 +9,8 @@ import Amplify import Foundation @_spi(InternalAWSPinpoint) import InternalAWSPinpoint -extension PinpointEvent { - public func asAnalyticsEvent() -> AnalyticsEvent { +public extension PinpointEvent { + func asAnalyticsEvent() -> AnalyticsEvent { var properties: AnalyticsProperties = [:] for attribute in attributes { @@ -21,12 +21,14 @@ extension PinpointEvent { properties[metric.key] = metric.value } - return BasicAnalyticsEvent(name: eventType, - properties: properties) + return BasicAnalyticsEvent( + name: eventType, + properties: properties + ) } } -extension Array where Element == PinpointEvent { +extension [PinpointEvent] { func asAnalyticsEventArray() -> [AnalyticsEvent] { map { $0.asAnalyticsEvent() } } diff --git a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/AWSPinpoint+AnalyticsErrorConvertible.swift b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/AWSPinpoint+AnalyticsErrorConvertible.swift index 42c5464f9e..d042e981cb 100644 --- a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/AWSPinpoint+AnalyticsErrorConvertible.swift +++ b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/AWSPinpoint+AnalyticsErrorConvertible.swift @@ -5,10 +5,10 @@ // SPDX-License-Identifier: Apache-2.0 // -import Foundation import Amplify import AWSPinpoint import ClientRuntime +import Foundation extension AWSPinpoint.BadRequestException: AnalyticsErrorConvertible { var analyticsError: AnalyticsError { diff --git a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/AnalyticsErrorConvertible.swift b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/AnalyticsErrorConvertible.swift index e21c889309..d422e9a13e 100644 --- a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/AnalyticsErrorConvertible.swift +++ b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/AnalyticsErrorConvertible.swift @@ -5,8 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 // -import Foundation import Amplify +import Foundation protocol AnalyticsErrorConvertible { var analyticsError: AnalyticsError { get } diff --git a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/AnalyticsErrorHelper.swift b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/AnalyticsErrorHelper.swift index da6a74fe7b..93167a2d8a 100644 --- a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/AnalyticsErrorHelper.swift +++ b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/AnalyticsErrorHelper.swift @@ -5,9 +5,9 @@ // SPDX-License-Identifier: Apache-2.0 // -import Foundation import Amplify import AwsCommonRuntimeKit +import Foundation enum AnalyticsErrorHelper { static func getDefaultError(_ error: Error) -> AnalyticsError { diff --git a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/CommonRunTimeError+AnalyticsErrorConvertible.swift b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/CommonRunTimeError+AnalyticsErrorConvertible.swift index b65918f472..07784736d3 100644 --- a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/CommonRunTimeError+AnalyticsErrorConvertible.swift +++ b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/Support/Utils/CommonRunTimeError+AnalyticsErrorConvertible.swift @@ -5,10 +5,10 @@ // SPDX-License-Identifier: Apache-2.0 // -import Foundation import Amplify -@_spi(InternalAWSPinpoint) import InternalAWSPinpoint import AwsCommonRuntimeKit +import Foundation +@_spi(InternalAWSPinpoint) import InternalAWSPinpoint extension CommonRunTimeError: AnalyticsErrorConvertible { var analyticsError: AnalyticsError { diff --git a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginAmplifyVersionableTests.swift b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginAmplifyVersionableTests.swift index e9922169db..cdbb482f27 100644 --- a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginAmplifyVersionableTests.swift +++ b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginAmplifyVersionableTests.swift @@ -5,8 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 // -import XCTest import AWSPinpointAnalyticsPlugin +import XCTest // swiftlint:disable:next type_name class AWSPinpointAnalyticsPluginAmplifyVersionableTests: XCTestCase { diff --git a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginClientBehaviorTests.swift b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginClientBehaviorTests.swift index 92c4636fd3..d78ec37ffb 100644 --- a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginClientBehaviorTests.swift +++ b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginClientBehaviorTests.swift @@ -7,10 +7,10 @@ import Amplify import AWSPinpoint -@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint -@testable import AWSPinpointAnalyticsPlugin -@testable import AmplifyTestCommon import XCTest +@testable import AmplifyTestCommon +@testable import AWSPinpointAnalyticsPlugin +@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint // swiftlint:disable:next type_name class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginTestBase { @@ -18,16 +18,20 @@ class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginT let testIdentityId = "identityId" let testEmail = "testEmail" let testPlan = "testPlan" - let testProperties: [String: AnalyticsPropertyValue] = ["keyString": "value", - "keyInt": 123, - "keyDouble": 1.2, - "keyBool": true] - let testLocation = AnalyticsUserProfile.Location(latitude: 12, - longitude: 34, - postalCode: "98122", - city: "Seattle", - region: "WA", - country: "USA") + let testProperties: [String: AnalyticsPropertyValue] = [ + "keyString": "value", + "keyInt": 123, + "keyDouble": 1.2, + "keyBool": true + ] + let testLocation = AnalyticsUserProfile.Location( + latitude: 12, + longitude: 34, + postalCode: "98122", + city: "Seattle", + region: "WA", + country: "USA" + ) // MARK: IdentifyUser API @@ -52,13 +56,17 @@ class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginT } } - let userProfile = AnalyticsUserProfile(name: testName, - email: testEmail, - plan: testPlan, - location: testLocation, - properties: testProperties) - var expectedEndpointProfile = PinpointEndpointProfile(applicationId: "appId", - endpointId: "endpointId") + let userProfile = AnalyticsUserProfile( + name: testName, + email: testEmail, + plan: testPlan, + location: testLocation, + properties: testProperties + ) + var expectedEndpointProfile = PinpointEndpointProfile( + applicationId: "appId", + endpointId: "endpointId" + ) expectedEndpointProfile.addUserId(testIdentityId) expectedEndpointProfile.addUserProfile(userProfile) @@ -86,8 +94,10 @@ class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginT /// Then: AWSPinpoint.currentEndpoint and updateEndpoint methods are called /// and Hub Analytics.identifyUser event is dispatched with an error func testIdentifyUserDispatchesErrorForPinpointError() async throws { - mockPinpoint.updateEndpointProfileResult = .failure(NSError(domain: "domain", - code: 1)) + mockPinpoint.updateEndpointProfileResult = .failure(NSError( + domain: "domain", + code: 1 + )) let analyticsEventReceived = expectation(description: "Analytics event was received on the hub plugin") _ = plugin.listen(to: .analytics, isIncluded: nil) { payload in @@ -103,13 +113,17 @@ class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginT } } - let userProfile = AnalyticsUserProfile(name: testName, - email: testEmail, - plan: testPlan, - location: testLocation, - properties: testProperties) - var expectedEndpointProfile = PinpointEndpointProfile(applicationId: "appId", - endpointId: "endpointId") + let userProfile = AnalyticsUserProfile( + name: testName, + email: testEmail, + plan: testPlan, + location: testLocation, + properties: testProperties + ) + var expectedEndpointProfile = PinpointEndpointProfile( + applicationId: "appId", + endpointId: "endpointId" + ) expectedEndpointProfile.addUserId(testIdentityId) expectedEndpointProfile.addUserProfile(userProfile) @@ -170,9 +184,11 @@ class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginT /// Then: AWSPinpoint.createEvent and record methods are called /// and Hub Analytics.record event is dispatched with a error func testRecordEventDispatchesErrorForPinpointError() async { - mockPinpoint.recordResult = .failure(NSError(domain: "domain", - code: 1, - userInfo: nil)) + mockPinpoint.recordResult = .failure(NSError( + domain: "domain", + code: 1, + userInfo: nil + )) let expectedPinpointEvent = PinpointEvent(eventType: testName, session: PinpointSession(appId: "", uniqueId: "")) mockPinpoint.createEventResult = expectedPinpointEvent expectedPinpointEvent.addProperties(testProperties) @@ -246,9 +262,11 @@ class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginT /// Then: AWSPinpoint.createEvent and record methods are called /// and Hub Analytics.record event is dispatched with a error func testRecordEventWithNameDispatchesErrorForPinpointError() async { - mockPinpoint.recordResult = .failure(NSError(domain: "domain", - code: 1, - userInfo: nil)) + mockPinpoint.recordResult = .failure(NSError( + domain: "domain", + code: 1, + userInfo: nil + )) let expectedPinpointEvent = PinpointEvent(eventType: testName, session: PinpointSession(appId: "", uniqueId: "")) mockPinpoint.createEventResult = expectedPinpointEvent @@ -281,9 +299,9 @@ class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginT func testRegisterGlobalProperties() async { mockPinpoint.addGlobalPropertyExpectation = expectation(description: "Add global property called") mockPinpoint.addGlobalPropertyExpectation?.expectedFulfillmentCount = testProperties.count - + analyticsPlugin.registerGlobalProperties(testProperties) - + await fulfillment(of: [mockPinpoint.addGlobalPropertyExpectation!], timeout: 1) XCTAssertEqual(analyticsPlugin.globalProperties.count, testProperties.count) XCTAssertTrue(mockPinpoint.addGlobalMetricCalled > 0) @@ -310,7 +328,7 @@ class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginT func testUnregisterGlobalProperties() async { mockPinpoint.removeGlobalPropertyExpectation = expectation(description: "Remove global property called") mockPinpoint.removeGlobalPropertyExpectation?.expectedFulfillmentCount = testProperties.count - + analyticsPlugin.globalProperties = AtomicDictionary(initialValue: testProperties) analyticsPlugin.unregisterGlobalProperties(Set(testProperties.keys)) @@ -343,8 +361,10 @@ class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginT /// Then: AWSPinpoint.submitEvents is invoked /// and Hub Analytics.flushEvents event is dispatched with submitted events func testFlushEvents_isOnline() async { - let result = [PinpointEvent(eventType: "1", session: PinpointSession(appId: "", uniqueId: "")), - PinpointEvent(eventType: "2", session: PinpointSession(appId: "", uniqueId: ""))] + let result = [ + PinpointEvent(eventType: "1", session: PinpointSession(appId: "", uniqueId: "")), + PinpointEvent(eventType: "2", session: PinpointSession(appId: "", uniqueId: "")) + ] mockNetworkMonitor.isOnline = true mockPinpoint.submitEventsResult = .success(result) let methodWasInvokedOnPlugin = expectation(description: "method was invoked on plugin") @@ -365,7 +385,7 @@ class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginT await fulfillment(of: [methodWasInvokedOnPlugin], timeout: 1) mockPinpoint.verifySubmitEvents() } - + /// Given: The device does not have internet access /// When: AnalyticsPlugin.flushEvents is invoked /// Then: AWSPinpoint.submitEvents is invoked @@ -407,9 +427,11 @@ class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginT /// Then: AWSPinpoint.submitEvents is invoked /// and Hub Analytics.flushEvents event is dispatched with error func testFlushEventsDispatchesErrorForPinpointError() async { - mockPinpoint.submitEventsResult = .failure(NSError(domain: "domain", - code: 1, - userInfo: nil)) + mockPinpoint.submitEventsResult = .failure(NSError( + domain: "domain", + code: 1, + userInfo: nil + )) let methodWasInvokedOnPlugin = expectation(description: "method was invoked on plugin") _ = plugin.listen(to: .analytics, isIncluded: nil) { payload in diff --git a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginConfigureTests.swift b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginConfigureTests.swift index 4c14742004..3c65df01f5 100644 --- a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginConfigureTests.swift +++ b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginConfigureTests.swift @@ -5,19 +5,19 @@ // SPDX-License-Identifier: Apache-2.0 // +import XCTest @testable @_spi(InternalAmplifyConfiguration) import Amplify @testable import AmplifyTestCommon -@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint @testable import AWSPinpointAnalyticsPlugin -import XCTest +@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint class AWSPinpointAnalyticsPluginConfigureTests: AWSPinpointAnalyticsPluginTestBase { - + override func setUp() async throws { AWSPinpointFactory.credentialsProvider = MockCredentialsProvider() try await super.setUp() } - + // MARK: Plugin Key test func testPluginKey() { @@ -95,7 +95,8 @@ class AWSPinpointAnalyticsPluginConfigureTests: AWSPinpointAnalyticsPluginTestBa let analyticsPlugin = AWSPinpointAnalyticsPlugin( options: .init( autoFlushEventsInterval: 50, - trackAppSessions: true)) + trackAppSessions: true + )) try analyticsPlugin.configure(using: analyticsPluginConfig) XCTAssertNotNil(analyticsPlugin.pinpoint) @@ -115,7 +116,8 @@ class AWSPinpointAnalyticsPluginConfigureTests: AWSPinpointAnalyticsPluginTestBa XCTFail("Analytics configuration should not succeed") } catch { guard let pluginError = error as? PluginError, - case .pluginConfigurationError = pluginError else { + case .pluginConfigurationError = pluginError + else { XCTFail("Should throw invalidConfiguration exception. But received \(error) ") return } @@ -126,8 +128,10 @@ class AWSPinpointAnalyticsPluginConfigureTests: AWSPinpointAnalyticsPluginTestBa func testConfigure_WithAmplifyOutputs() { let config = AmplifyOutputsData.init(analytics: .init( - amazonPinpoint: .init(awsRegion: testRegion, - appId: testAppId))) + amazonPinpoint: .init( + awsRegion: testRegion, + appId: testAppId + ))) do { let analyticsPlugin = AWSPinpointAnalyticsPlugin() @@ -148,13 +152,16 @@ class AWSPinpointAnalyticsPluginConfigureTests: AWSPinpointAnalyticsPluginTestBa func testConfigure_WithAmplifyOutputsAndOptions() { let config = AmplifyOutputsData.init(analytics: .init( - amazonPinpoint: .init(awsRegion: testRegion, - appId: testAppId))) + amazonPinpoint: .init( + awsRegion: testRegion, + appId: testAppId + ))) do { let analyticsPlugin = AWSPinpointAnalyticsPlugin(options: .init( autoFlushEventsInterval: 100, - trackAppSessions: false)) + trackAppSessions: false + )) try analyticsPlugin.configure(using: config) XCTAssertNotNil(analyticsPlugin.pinpoint) diff --git a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginResetTests.swift b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginResetTests.swift index a5338f8e5e..b2e8be43be 100644 --- a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginResetTests.swift +++ b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginResetTests.swift @@ -7,8 +7,8 @@ import Amplify @_spi(InternalAWSPinpoint) import InternalAWSPinpoint -@testable import AWSPinpointAnalyticsPlugin import XCTest +@testable import AWSPinpointAnalyticsPlugin class AWSPinpointAnalyticsPluginResetTests: AWSPinpointAnalyticsPluginTestBase { func testReset() async { diff --git a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginTestBase.swift b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginTestBase.swift index 6e637db34a..bfefb36938 100644 --- a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginTestBase.swift +++ b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginTestBase.swift @@ -5,11 +5,11 @@ // SPDX-License-Identifier: Apache-2.0 // +import XCTest @testable import Amplify @testable import AmplifyTestCommon -@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint @testable import AWSPinpointAnalyticsPlugin -import XCTest +@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint class AWSPinpointAnalyticsPluginTestBase: XCTestCase { var analyticsPlugin: AWSPinpointAnalyticsPlugin! @@ -24,7 +24,8 @@ class AWSPinpointAnalyticsPluginTestBase: XCTestCase { var plugin: HubCategoryPlugin { guard let plugin = try? Amplify.Hub.getPlugin(for: "awsHubPlugin"), - plugin.key == "awsHubPlugin" else { + plugin.key == "awsHubPlugin" + else { fatalError("Could not access awsHubPlugin") } return plugin @@ -36,8 +37,10 @@ class AWSPinpointAnalyticsPluginTestBase: XCTestCase { mockPinpoint = MockAWSPinpoint() mockNetworkMonitor = MockNetworkMonitor() - analyticsPlugin.configure(pinpoint: mockPinpoint, - networkMonitor: mockNetworkMonitor) + analyticsPlugin.configure( + pinpoint: mockPinpoint, + networkMonitor: mockNetworkMonitor + ) await Amplify.reset() let config = AmplifyConfiguration() diff --git a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Configuration/AWSPinpointAnalyticsPluginAmplifyOutputsConfigurationTests.swift b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Configuration/AWSPinpointAnalyticsPluginAmplifyOutputsConfigurationTests.swift index e4aeffa943..129a735cbd 100644 --- a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Configuration/AWSPinpointAnalyticsPluginAmplifyOutputsConfigurationTests.swift +++ b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Configuration/AWSPinpointAnalyticsPluginAmplifyOutputsConfigurationTests.swift @@ -5,10 +5,10 @@ // SPDX-License-Identifier: Apache-2.0 // -@testable @_spi(InternalAmplifyConfiguration) import Amplify import XCTest -@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint +@testable @_spi(InternalAmplifyConfiguration) import Amplify @testable import AWSPinpointAnalyticsPlugin +@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint // swiftlint:disable:next type_name class AWSPinpointAnalyticsPluginAmplifyOutputsConfigurationTests: XCTestCase { @@ -34,20 +34,29 @@ class AWSPinpointAnalyticsPluginAmplifyOutputsConfigurationTests: XCTestCase { XCTAssertNotNil(result) XCTAssertEqual(result.appId, testAppId) XCTAssertEqual(result.region, testRegion) - XCTAssertEqual(result.options.autoFlushEventsInterval, - AWSPinpointAnalyticsPlugin.Options.defaultAutoFlushEventsInterval) - XCTAssertEqual(result.options.trackAppSessions, - AWSPinpointAnalyticsPlugin.Options.defaultTrackAppSession) - XCTAssertEqual(result.autoSessionTrackingInterval, - AWSPinpointAnalyticsPluginConfiguration.defaultAutoSessionTrackingInterval) + XCTAssertEqual( + result.options.autoFlushEventsInterval, + AWSPinpointAnalyticsPlugin.Options.defaultAutoFlushEventsInterval + ) + XCTAssertEqual( + result.options.trackAppSessions, + AWSPinpointAnalyticsPlugin.Options.defaultTrackAppSession + ) + XCTAssertEqual( + result.autoSessionTrackingInterval, + AWSPinpointAnalyticsPluginConfiguration.defaultAutoSessionTrackingInterval + ) } func testConfiguration_OptionsOverride() throws { let config = AmplifyOutputsData(analytics: .init(amazonPinpoint: .init(awsRegion: testRegion, appId: appId))) let result = try AWSPinpointAnalyticsPluginConfiguration( config, - options: .init(autoFlushEventsInterval: 100, - trackAppSessions: false)) + options: .init( + autoFlushEventsInterval: 100, + trackAppSessions: false + ) + ) XCTAssertNotNil(result) XCTAssertEqual(result.appId, testAppId) XCTAssertEqual(result.region, testRegion) @@ -65,8 +74,10 @@ class AWSPinpointAnalyticsPluginAmplifyOutputsConfigurationTests: XCTestCase { XCTFail("Expected to catch PluginError.pluginConfigurationError.") return } - XCTAssertEqual(errorDescription, - AnalyticsPluginErrorConstant.missingAnalyticsCategoryConfiguration.errorDescription) + XCTAssertEqual( + errorDescription, + AnalyticsPluginErrorConstant.missingAnalyticsCategoryConfiguration.errorDescription + ) } } @@ -79,8 +90,10 @@ class AWSPinpointAnalyticsPluginAmplifyOutputsConfigurationTests: XCTestCase { XCTFail("Expected to catch PluginError.pluginConfigurationError.") return } - XCTAssertEqual(errorDescription, - AnalyticsPluginErrorConstant.missingAmazonPinpointConfiguration.errorDescription) + XCTAssertEqual( + errorDescription, + AnalyticsPluginErrorConstant.missingAmazonPinpointConfiguration.errorDescription + ) } } } diff --git a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Configuration/AWSPinpointAnalyticsPluginConfigurationTests.swift b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Configuration/AWSPinpointAnalyticsPluginConfigurationTests.swift index f7b8f7216f..2407a7fea3 100644 --- a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Configuration/AWSPinpointAnalyticsPluginConfigurationTests.swift +++ b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Configuration/AWSPinpointAnalyticsPluginConfigurationTests.swift @@ -7,8 +7,8 @@ import Amplify import XCTest -@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint @testable import AWSPinpointAnalyticsPlugin +@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint // swiftlint:disable:next type_name class AWSPinpointAnalyticsPluginConfigurationTests: XCTestCase { @@ -42,17 +42,23 @@ class AWSPinpointAnalyticsPluginConfigurationTests: XCTestCase { XCTAssertNotNil(config) XCTAssertEqual(config.appId, testAppId) XCTAssertEqual(config.region, testRegion) - XCTAssertEqual(config.options.autoFlushEventsInterval, - AWSPinpointAnalyticsPlugin.Options.defaultAutoFlushEventsInterval) - XCTAssertEqual(config.options.trackAppSessions, - AWSPinpointAnalyticsPlugin.Options.defaultTrackAppSession) - XCTAssertEqual(config.autoSessionTrackingInterval, - AWSPinpointAnalyticsPluginConfiguration.defaultAutoSessionTrackingInterval) + XCTAssertEqual( + config.options.autoFlushEventsInterval, + AWSPinpointAnalyticsPlugin.Options.defaultAutoFlushEventsInterval + ) + XCTAssertEqual( + config.options.trackAppSessions, + AWSPinpointAnalyticsPlugin.Options.defaultTrackAppSession + ) + XCTAssertEqual( + config.autoSessionTrackingInterval, + AWSPinpointAnalyticsPluginConfiguration.defaultAutoSessionTrackingInterval + ) } catch { XCTFail("Failed to instantiate analytics plugin configuration") } } - + func testConfigureSuccess_withoutTargetingConfiguration() throws { let analyticsPluginConfig = JSONValue( dictionaryLiteral: @@ -64,12 +70,18 @@ class AWSPinpointAnalyticsPluginConfigurationTests: XCTestCase { XCTAssertNotNil(config) XCTAssertEqual(config.appId, testAppId) XCTAssertEqual(config.region, testRegion) - XCTAssertEqual(config.options.autoFlushEventsInterval, - AWSPinpointAnalyticsPlugin.Options.defaultAutoFlushEventsInterval) - XCTAssertEqual(config.options.trackAppSessions, - AWSPinpointAnalyticsPlugin.Options.defaultTrackAppSession) - XCTAssertEqual(config.autoSessionTrackingInterval, - AWSPinpointAnalyticsPluginConfiguration.defaultAutoSessionTrackingInterval) + XCTAssertEqual( + config.options.autoFlushEventsInterval, + AWSPinpointAnalyticsPlugin.Options.defaultAutoFlushEventsInterval + ) + XCTAssertEqual( + config.options.trackAppSessions, + AWSPinpointAnalyticsPlugin.Options.defaultTrackAppSession + ) + XCTAssertEqual( + config.autoSessionTrackingInterval, + AWSPinpointAnalyticsPluginConfiguration.defaultAutoSessionTrackingInterval + ) } catch { XCTFail("Failed to instantiate analytics plugin configuration") } @@ -88,10 +100,14 @@ class AWSPinpointAnalyticsPluginConfigurationTests: XCTestCase { XCTAssertEqual(config.appId, testAppId) XCTAssertEqual(config.region, testRegion) XCTAssertEqual(config.options.autoFlushEventsInterval, testAutoFlushInterval) - XCTAssertEqual(config.options.trackAppSessions, - AWSPinpointAnalyticsPlugin.Options.defaultTrackAppSession) - XCTAssertEqual(config.autoSessionTrackingInterval, - AWSPinpointAnalyticsPluginConfiguration.defaultAutoSessionTrackingInterval) + XCTAssertEqual( + config.options.trackAppSessions, + AWSPinpointAnalyticsPlugin.Options.defaultTrackAppSession + ) + XCTAssertEqual( + config.autoSessionTrackingInterval, + AWSPinpointAnalyticsPluginConfiguration.defaultAutoSessionTrackingInterval + ) } catch { XCTFail("Failed to instantiate analytics plugin configuration") } @@ -110,8 +126,10 @@ class AWSPinpointAnalyticsPluginConfigurationTests: XCTestCase { XCTFail("Expected PluginError pluginConfigurationError, got: \(error)") return } - XCTAssertEqual(errorDescription, - AnalyticsPluginErrorConstant.invalidAutoFlushEventsInterval.errorDescription) + XCTAssertEqual( + errorDescription, + AnalyticsPluginErrorConstant.invalidAutoFlushEventsInterval.errorDescription + ) } } @@ -127,11 +145,15 @@ class AWSPinpointAnalyticsPluginConfigurationTests: XCTestCase { XCTAssertNotNil(config) XCTAssertEqual(config.appId, testAppId) XCTAssertEqual(config.region, testRegion) - XCTAssertEqual(config.options.autoFlushEventsInterval, - AWSPinpointAnalyticsPlugin.Options.defaultAutoFlushEventsInterval) + XCTAssertEqual( + config.options.autoFlushEventsInterval, + AWSPinpointAnalyticsPlugin.Options.defaultAutoFlushEventsInterval + ) XCTAssertEqual(config.options.trackAppSessions, testTrackAppSession) - XCTAssertEqual(config.autoSessionTrackingInterval, - AWSPinpointAnalyticsPluginConfiguration.defaultAutoSessionTrackingInterval) + XCTAssertEqual( + config.autoSessionTrackingInterval, + AWSPinpointAnalyticsPluginConfiguration.defaultAutoSessionTrackingInterval + ) } catch { XCTFail("Failed to instantiate analytics plugin configuration") } @@ -149,8 +171,10 @@ class AWSPinpointAnalyticsPluginConfigurationTests: XCTestCase { XCTAssertNotNil(config) XCTAssertEqual(config.appId, testAppId) XCTAssertEqual(config.region, testRegion) - XCTAssertEqual(config.options.autoFlushEventsInterval, - AWSPinpointAnalyticsPlugin.Options.defaultAutoFlushEventsInterval) + XCTAssertEqual( + config.options.autoFlushEventsInterval, + AWSPinpointAnalyticsPlugin.Options.defaultAutoFlushEventsInterval + ) XCTAssertEqual(config.options.trackAppSessions, AWSPinpointAnalyticsPlugin.Options.defaultTrackAppSession) XCTAssertEqual(config.autoSessionTrackingInterval, testAutoSessionTrackingInterval) } catch { @@ -171,8 +195,10 @@ class AWSPinpointAnalyticsPluginConfigurationTests: XCTestCase { XCTFail("Expected PluginError pluginConfigurationError, got: \(error)") return } - XCTAssertEqual(errorDescription, - AnalyticsPluginErrorConstant.invalidAutoSessionTrackingInterval.errorDescription) + XCTAssertEqual( + errorDescription, + AnalyticsPluginErrorConstant.invalidAutoSessionTrackingInterval.errorDescription + ) } } @@ -184,13 +210,15 @@ class AWSPinpointAnalyticsPluginConfigurationTests: XCTestCase { XCTFail("Expected PluginError pluginConfigurationError, got: \(error)") return } - XCTAssertEqual(errorDescription, - AnalyticsPluginErrorConstant.configurationObjectExpected.errorDescription) + XCTAssertEqual( + errorDescription, + AnalyticsPluginErrorConstant.configurationObjectExpected.errorDescription + ) } } func testConfigureThrowsErrorForMissingPinpointAnalyticsConfiguration() { - + let analyticsPluginConfig = JSONValue( dictionaryLiteral: (AWSPinpointAnalyticsPluginConfiguration.regionConfigKey, region) @@ -201,8 +229,10 @@ class AWSPinpointAnalyticsPluginConfigurationTests: XCTestCase { XCTFail("Expected PluginError pluginConfigurationError, got: \(error)") return } - XCTAssertEqual(errorDescription, - AnalyticsPluginErrorConstant.missingPinpointAnalyicsConfiguration.errorDescription) + XCTAssertEqual( + errorDescription, + AnalyticsPluginErrorConstant.missingPinpointAnalyicsConfiguration.errorDescription + ) } } @@ -218,8 +248,10 @@ class AWSPinpointAnalyticsPluginConfigurationTests: XCTestCase { XCTFail("Expected PluginError pluginConfigurationError, got: \(error)") return } - XCTAssertEqual(errorDescription, - AWSPinpointErrorConstants.pinpointConfigurationExpected.errorDescription) + XCTAssertEqual( + errorDescription, + AWSPinpointErrorConstants.pinpointConfigurationExpected.errorDescription + ) } } diff --git a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockAWSPinpoint+Analytics.swift b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockAWSPinpoint+Analytics.swift index 9466403f55..8de6ddffea 100644 --- a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockAWSPinpoint+Analytics.swift +++ b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockAWSPinpoint+Analytics.swift @@ -7,13 +7,13 @@ import Amplify import AWSPinpoint -@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint -@testable import AWSPinpointAnalyticsPlugin import Foundation import StoreKit +@testable import AWSPinpointAnalyticsPlugin +@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint extension MockAWSPinpoint { - public func addGlobalProperty(_ value: AnalyticsPropertyValue, forKey: String) { + func addGlobalProperty(_ value: AnalyticsPropertyValue, forKey: String) { if let value = value as? String { addGlobalAttribute(value, forKey: forKey) } else if let value = value as? Int { @@ -26,7 +26,7 @@ extension MockAWSPinpoint { addGlobalPropertyExpectation?.fulfill() } - public func removeGlobalProperty(_ value: AnalyticsPropertyValue, forKey: String) { + func removeGlobalProperty(_ value: AnalyticsPropertyValue, forKey: String) { if value is String || value is Bool { removeGlobalAttribute(forKey: forKey) } else if value is Int || value is Double { @@ -35,14 +35,14 @@ extension MockAWSPinpoint { removeGlobalPropertyExpectation?.fulfill() } - public func addGlobalAttribute(_ theValue: String, forKey theKey: String) { + func addGlobalAttribute(_ theValue: String, forKey theKey: String) { addGlobalAttributeCalled += 1 addGlobalAttributeValue = theValue addGlobalAttributeKey = theKey } - public func addGlobalAttribute(_ theValue: String, forKey theKey: String, forEventType theEventType: String) { + func addGlobalAttribute(_ theValue: String, forKey theKey: String, forEventType theEventType: String) { addGlobalAttributeCalled += 1 addGlobalAttributeValue = theValue @@ -50,14 +50,14 @@ extension MockAWSPinpoint { addGlobalAttributeEventType = theEventType } - public func addGlobalMetric(_ theValue: Double, forKey theKey: String) { + func addGlobalMetric(_ theValue: Double, forKey theKey: String) { addGlobalMetricCalled += 1 addGlobalMetricValue = theValue addGlobalMetricKey = theKey } - public func addGlobalMetric(_ theValue: Double, forKey theKey: String, forEventType theEventType: String) { + func addGlobalMetric(_ theValue: Double, forKey theKey: String, forEventType theEventType: String) { addGlobalMetricCalled += 1 addGlobalMetricValue = theValue @@ -65,30 +65,30 @@ extension MockAWSPinpoint { addGlobalMetricEventType = theEventType } - public func removeGlobalAttribute(forKey theKey: String) { + func removeGlobalAttribute(forKey theKey: String) { removeGlobalAttributeCalled += 1 removeGlobalAttributeKey = theKey } - public func removeGlobalAttribute(forKey theKey: String, forEventType theEventType: String) { + func removeGlobalAttribute(forKey theKey: String, forEventType theEventType: String) { removeGlobalAttributeCalled += 1 removeGlobalAttributeKey = theKey removeGlobalAttributeEventType = theEventType } - public func removeGlobalMetric(forKey theKey: String) { + func removeGlobalMetric(forKey theKey: String) { removeGlobalMetricCalled += 1 removeGlobalMetricKey = theKey } - public func removeGlobalMetric(forKey theKey: String, forEventType theEventType: String) { + func removeGlobalMetric(forKey theKey: String, forEventType theEventType: String) { removeGlobalMetricCalled += 1 removeGlobalMetricKey = theKey removeglobalMetricEventType = theEventType } - public func record(_ theEvent: PinpointEvent) async throws { + func record(_ theEvent: PinpointEvent) async throws { recordCalled += 1 recordEvent = theEvent @@ -97,15 +97,17 @@ extension MockAWSPinpoint { } } - public func createEvent(withEventType theEventType: String) -> PinpointEvent { + func createEvent(withEventType theEventType: String) -> PinpointEvent { createEventCalled += 1 createEventEventType = theEventType return createEventResult ?? createEmptyEvent() } - public func createAppleMonetizationEvent(with transaction: SKPaymentTransaction, - with product: SKProduct) -> PinpointEvent { + func createAppleMonetizationEvent( + with transaction: SKPaymentTransaction, + with product: SKProduct + ) -> PinpointEvent { createAppleMonetizationEventCalled += 1 createAppleMonetizationEventTransaction = transaction createAppleMonetizationEventProduct = product @@ -113,10 +115,12 @@ extension MockAWSPinpoint { return createAppleMonetizationEventResult ?? createEmptyEvent() } - public func createVirtualMonetizationEvent(withProductId theProductId: String, - withItemPrice theItemPrice: Double, - withQuantity theQuantity: Int, - withCurrency theCurrency: String) -> PinpointEvent { + func createVirtualMonetizationEvent( + withProductId theProductId: String, + withItemPrice theItemPrice: Double, + withQuantity theQuantity: Int, + withCurrency theCurrency: String + ) -> PinpointEvent { createVirtualMonetizationEventCalled += 1 createVirtualMonetizationEventProductId = theProductId createVirtualMonetizationEventItemPrice = theItemPrice @@ -126,11 +130,11 @@ extension MockAWSPinpoint { return createVirtualMonetizationEventResult ?? createEmptyEvent() } - public func submitEvents() async throws { + func submitEvents() async throws { submitEventsCalled += 1 } - public func submitEvents() async throws -> [PinpointEvent] { + func submitEvents() async throws -> [PinpointEvent] { submitEventsCalled += 1 switch submitEventsResult { case .success(let result): @@ -143,20 +147,24 @@ extension MockAWSPinpoint { } private func createEmptyEvent() -> PinpointEvent { - return PinpointEvent(eventType: "", - session: PinpointSession(appId: "", uniqueId: "")) + return PinpointEvent( + eventType: "", + session: PinpointSession(appId: "", uniqueId: "") + ) } - - public func setAutomaticSubmitEventsInterval(_ interval: TimeInterval, - onSubmit: AnalyticsClientBehaviour.SubmitResult?) { - + + func setAutomaticSubmitEventsInterval( + _ interval: TimeInterval, + onSubmit: AnalyticsClientBehaviour.SubmitResult? + ) { + } - - public func startTrackingSessions(backgroundTimeout: TimeInterval) { - + + func startTrackingSessions(backgroundTimeout: TimeInterval) { + } - func setRemoteGlobalAttributes(_ attributes: [String : String]) async { + func setRemoteGlobalAttributes(_ attributes: [String: String]) async { } } diff --git a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockAWSPinpoint+Targeting.swift b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockAWSPinpoint+Targeting.swift index 429d2ffd8d..3dd090cf08 100644 --- a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockAWSPinpoint+Targeting.swift +++ b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockAWSPinpoint+Targeting.swift @@ -6,18 +6,18 @@ // import AWSPinpoint -@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint -@testable import AWSPinpointAnalyticsPlugin import Foundation +@testable import AWSPinpointAnalyticsPlugin +@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint extension MockAWSPinpoint { - public func currentEndpointProfile() -> PinpointEndpointProfile { + func currentEndpointProfile() -> PinpointEndpointProfile { currentEndpointProfileCalled += 1 return PinpointEndpointProfile(applicationId: applicationId, endpointId: endpointId) } - public func updateEndpointProfile() async throws { + func updateEndpointProfile() async throws { updateEndpointProfileCalled += 1 if case let .failure(error) = updateEndpointProfileResult { @@ -25,8 +25,10 @@ extension MockAWSPinpoint { } } - public func updateEndpoint(with endpointProfile: PinpointEndpointProfile, - source: AWSPinpointSource) async throws { + func updateEndpoint( + with endpointProfile: PinpointEndpointProfile, + source: AWSPinpointSource + ) async throws { updateEndpointProfileCalled += 1 updateEndpointProfileValue = endpointProfile @@ -35,27 +37,27 @@ extension MockAWSPinpoint { } } - public func addAttributes(_ attributes: [String], forKey key: String) { + func addAttributes(_ attributes: [String], forKey key: String) { addAttributeCalled += 1 addAttributeValue = attributes addAttributeKey = key } - public func removeAttributes(forKey key: String) { + func removeAttributes(forKey key: String) { removeAttributeCalled += 1 removeAttributeKey = key } - public func addMetric(_ metric: Double, forKey key: String) { + func addMetric(_ metric: Double, forKey key: String) { addMetricCalled += 1 addMetricValue = metric addMetricKey = key } - public func removeMetric(forKey theKey: String) { + func removeMetric(forKey theKey: String) { removeMetricCalled += 1 removeMetricKey = theKey diff --git a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockAWSPinpoint.swift b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockAWSPinpoint.swift index 9c445fb449..1e80ceca3d 100644 --- a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockAWSPinpoint.swift +++ b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockAWSPinpoint.swift @@ -10,8 +10,8 @@ import Foundation import StoreKit import XCTest -@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint @testable import AWSPinpointAnalyticsPlugin +@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint class MockAWSPinpoint: AWSPinpointBehavior { let applicationId = "applicationId" @@ -81,7 +81,7 @@ class MockAWSPinpoint: AWSPinpointBehavior { var createAppleMonetizationEventResult: PinpointEvent? var createVirtualMonetizationEventResult: PinpointEvent? var submitEventsResult: Result<[PinpointEvent], Error>? - + var addGlobalPropertyExpectation: XCTestExpectation? var removeGlobalPropertyExpectation: XCTestExpectation? @@ -216,17 +216,21 @@ extension MockAWSPinpoint { XCTAssertEqual(createEventEventType, theEventType) } - public func verifyCreateAppleMonetizationEvent(with transaction: SKPaymentTransaction, - with product: SKProduct) { + public func verifyCreateAppleMonetizationEvent( + with transaction: SKPaymentTransaction, + with product: SKProduct + ) { XCTAssertEqual(createAppleMonetizationEventCalled, 1) XCTAssertEqual(createAppleMonetizationEventTransaction, transaction) XCTAssertEqual(createAppleMonetizationEventProduct, product) } - public func verifyCreateVirtualMonetizationEvent(withProductId theProductId: String, - withItemPrice theItemPrice: Double, - withQuantity theQuantity: Int, - withCurrency theCurrency: String) { + public func verifyCreateVirtualMonetizationEvent( + withProductId theProductId: String, + withItemPrice theItemPrice: Double, + withQuantity theQuantity: Int, + withCurrency theCurrency: String + ) { XCTAssertEqual(createVirtualMonetizationEventCalled, 1) XCTAssertEqual(createVirtualMonetizationEventProductId, theProductId) XCTAssertEqual(createVirtualMonetizationEventItemPrice, theItemPrice) diff --git a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockNetworkMonitor.swift b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockNetworkMonitor.swift index bcd1099b71..9298fcdd46 100644 --- a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockNetworkMonitor.swift +++ b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/Mocks/MockNetworkMonitor.swift @@ -5,8 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 // -@testable import AWSPinpointAnalyticsPlugin import Foundation +@testable import AWSPinpointAnalyticsPlugin class MockNetworkMonitor: NetworkMonitor { var isOnline = true diff --git a/AmplifyPlugins/Analytics/Tests/AnalyticsHostApp/AWSPinpointAnalyticsPluginIntegrationTests/AWSPinpointAnalyticsPluginIntegrationTests.swift b/AmplifyPlugins/Analytics/Tests/AnalyticsHostApp/AWSPinpointAnalyticsPluginIntegrationTests/AWSPinpointAnalyticsPluginIntegrationTests.swift index 3716620822..de5427eaff 100644 --- a/AmplifyPlugins/Analytics/Tests/AnalyticsHostApp/AWSPinpointAnalyticsPluginIntegrationTests/AWSPinpointAnalyticsPluginIntegrationTests.swift +++ b/AmplifyPlugins/Analytics/Tests/AnalyticsHostApp/AWSPinpointAnalyticsPluginIntegrationTests/AWSPinpointAnalyticsPluginIntegrationTests.swift @@ -5,14 +5,14 @@ // SPDX-License-Identifier: Apache-2.0 // -import XCTest import AWSPinpoint +import XCTest -@testable import Amplify -@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint -@testable import AWSPinpointAnalyticsPlugin import AWSCognitoAuthPlugin import Network +@testable import Amplify +@testable import AWSPinpointAnalyticsPlugin +@_spi(InternalAWSPinpoint) @testable import InternalAWSPinpoint // swiftlint:disable:next type_name class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { @@ -20,7 +20,7 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { static let amplifyConfiguration = "testconfiguration/AWSPinpointAnalyticsPluginIntegrationTests-amplifyconfiguration" static let amplifyOutputs = "testconfiguration/AWSPinpointAnalyticsPluginIntegrationTests-amplify_outputs" static let analyticsPluginKey = "awsPinpointAnalyticsPlugin" - + var useGen2Configuration: Bool { ProcessInfo.processInfo.arguments.contains("GEN2") } @@ -65,21 +65,27 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { } } - let location = AnalyticsUserProfile.Location(latitude: 47.606209, - longitude: -122.332069, - postalCode: "98122", - city: "Seattle", - region: "WA", - country: "USA") - let properties = ["userPropertyStringKey": "userProperyStringValue", - "userPropertyIntKey": 123, - "userPropertyDoubleKey": 12.34, - "userPropertyBoolKey": true] as [String: AnalyticsPropertyValue] - let userProfile = AnalyticsUserProfile(name: "name", - email: "email", - plan: "plan", - location: location, - properties: properties) + let location = AnalyticsUserProfile.Location( + latitude: 47.606209, + longitude: -122.332069, + postalCode: "98122", + city: "Seattle", + region: "WA", + country: "USA" + ) + let properties = [ + "userPropertyStringKey": "userProperyStringValue", + "userPropertyIntKey": 123, + "userPropertyDoubleKey": 12.34, + "userPropertyBoolKey": true + ] as [String: AnalyticsPropertyValue] + let userProfile = AnalyticsUserProfile( + name: "name", + email: "email", + plan: "plan", + location: location, + properties: properties + ) Amplify.Analytics.identifyUser(userId: userId, userProfile: userProfile) await fulfillment(of: [identifyUserEvent], timeout: TestCommonConstants.networkTimeout) @@ -96,8 +102,10 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { func skip_testDeleteEndpointsForUser() async throws { let userId = "userId" let applicationId = await endpointClient().currentEndpointProfile().applicationId - let deleteEndpointsRequest = DeleteUserEndpointsInput(applicationId: applicationId, - userId: userId) + let deleteEndpointsRequest = DeleteUserEndpointsInput( + applicationId: applicationId, + userId: userId + ) do { let response = try await pinpointClient().deleteUserEndpoints(input: deleteEndpointsRequest) XCTAssertNotNil(response.endpointsResponse) @@ -118,7 +126,7 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { } } networkMonitor.start(queue: DispatchQueue(label: "AWSPinpointAnalyticsPluginIntergrationTests.NetworkMonitor")) - + let flushEventsInvoked = expectation(description: "Flush events invoked") _ = Amplify.Hub.listen(to: .analytics, isIncluded: nil) { payload in if payload.eventName == HubPayload.EventName.Analytics.flushEvents { @@ -132,25 +140,29 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { } } - let globalProperties = ["globalPropertyStringKey": "eventProperyStringValue", - "globalPropertyIntKey": 123, - "globalPropertyDoubleKey": 12.34, - "globalPropertyBoolKey": true] as [String: AnalyticsPropertyValue] + let globalProperties = [ + "globalPropertyStringKey": "eventProperyStringValue", + "globalPropertyIntKey": 123, + "globalPropertyDoubleKey": 12.34, + "globalPropertyBoolKey": true + ] as [String: AnalyticsPropertyValue] Amplify.Analytics.registerGlobalProperties(globalProperties) - let properties = ["eventPropertyStringKey": "eventProperyStringValue", - "eventPropertyIntKey": 123, - "eventPropertyDoubleKey": 12.34, - "eventPropertyBoolKey": true] as [String: AnalyticsPropertyValue] + let properties = [ + "eventPropertyStringKey": "eventProperyStringValue", + "eventPropertyIntKey": 123, + "eventPropertyDoubleKey": 12.34, + "eventPropertyBoolKey": true + ] as [String: AnalyticsPropertyValue] let event = BasicAnalyticsEvent(name: "eventName", properties: properties) Amplify.Analytics.record(event: event) - + await fulfillment(of: [onlineExpectation], timeout: TestCommonConstants.networkTimeout) Amplify.Analytics.flushEvents() await fulfillment(of: [flushEventsInvoked], timeout: TestCommonConstants.networkTimeout) } - + /// Given: Analytics plugin /// When: An analytics event is recorded and flushed after the plugin is enabled /// Then: Flush Hub event is received @@ -163,7 +175,7 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { } } networkMonitor.start(queue: DispatchQueue(label: "AWSPinpointAnalyticsPluginIntergrationTests.NetworkMonitor")) - + let flushEventsInvoked = expectation(description: "Flush events invoked") _ = Amplify.Hub.listen(to: .analytics, isIncluded: nil) { payload in if payload.eventName == HubPayload.EventName.Analytics.flushEvents { @@ -176,29 +188,33 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { flushEventsInvoked.fulfill() } } - + Amplify.Analytics.disable() Amplify.Analytics.enable() - let globalProperties = ["globalPropertyStringKey": "eventProperyStringValue", - "globalPropertyIntKey": 123, - "globalPropertyDoubleKey": 12.34, - "globalPropertyBoolKey": true] as [String: AnalyticsPropertyValue] + let globalProperties = [ + "globalPropertyStringKey": "eventProperyStringValue", + "globalPropertyIntKey": 123, + "globalPropertyDoubleKey": 12.34, + "globalPropertyBoolKey": true + ] as [String: AnalyticsPropertyValue] Amplify.Analytics.registerGlobalProperties(globalProperties) - let properties = ["eventPropertyStringKey": "eventProperyStringValue", - "eventPropertyIntKey": 123, - "eventPropertyDoubleKey": 12.34, - "eventPropertyBoolKey": true] as [String: AnalyticsPropertyValue] + let properties = [ + "eventPropertyStringKey": "eventProperyStringValue", + "eventPropertyIntKey": 123, + "eventPropertyDoubleKey": 12.34, + "eventPropertyBoolKey": true + ] as [String: AnalyticsPropertyValue] let event = BasicAnalyticsEvent(name: "eventName", properties: properties) Amplify.Analytics.record(event: event) - + await fulfillment(of: [onlineExpectation], timeout: TestCommonConstants.networkTimeout) Amplify.Analytics.flushEvents() await fulfillment(of: [flushEventsInvoked], timeout: TestCommonConstants.networkTimeout) } - + /// Given: Analytics plugin /// When: An analytics event is recorded and flushed after the plugin is disabled /// Then: Flush Hub event is not received @@ -211,7 +227,7 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { } } networkMonitor.start(queue: DispatchQueue(label: "AWSPinpointAnalyticsPluginIntergrationTests.NetworkMonitor")) - + let flushEventsInvoked = expectation(description: "Flush events invoked") _ = Amplify.Hub.listen(to: .analytics, isIncluded: nil) { payload in if payload.eventName == HubPayload.EventName.Analytics.flushEvents { @@ -219,27 +235,31 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { } } flushEventsInvoked.isInverted = true - + Amplify.Analytics.disable() - - let globalProperties = ["globalPropertyStringKey": "eventProperyStringValue", - "globalPropertyIntKey": 123, - "globalPropertyDoubleKey": 12.34, - "globalPropertyBoolKey": true] as [String: AnalyticsPropertyValue] + + let globalProperties = [ + "globalPropertyStringKey": "eventProperyStringValue", + "globalPropertyIntKey": 123, + "globalPropertyDoubleKey": 12.34, + "globalPropertyBoolKey": true + ] as [String: AnalyticsPropertyValue] Amplify.Analytics.registerGlobalProperties(globalProperties) - let properties = ["eventPropertyStringKey": "eventProperyStringValue", - "eventPropertyIntKey": 123, - "eventPropertyDoubleKey": 12.34, - "eventPropertyBoolKey": true] as [String: AnalyticsPropertyValue] + let properties = [ + "eventPropertyStringKey": "eventProperyStringValue", + "eventPropertyIntKey": 123, + "eventPropertyDoubleKey": 12.34, + "eventPropertyBoolKey": true + ] as [String: AnalyticsPropertyValue] let event = BasicAnalyticsEvent(name: "eventName", properties: properties) Amplify.Analytics.record(event: event) - + await fulfillment(of: [onlineExpectation], timeout: TestCommonConstants.networkTimeout) Amplify.Analytics.flushEvents() await fulfillment(of: [flushEventsInvoked], timeout: TestCommonConstants.networkTimeout) } - + /// Given: Analytics plugin /// When: An analytics event is recorded and flushed with global properties registered /// Then: Flush Hub event is received with global properties @@ -253,7 +273,7 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { } } networkMonitor.start(queue: DispatchQueue(label: "AWSPinpointAnalyticsPluginIntergrationTests.NetworkMonitor")) - + let flushEventsInvoked = expectation(description: "Flush events invoked") _ = Amplify.Hub.listen(to: .analytics, isIncluded: nil) { payload in if payload.eventName == HubPayload.EventName.Analytics.flushEvents { @@ -275,19 +295,23 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { flushEventsInvoked.fulfill() } } - - let globalProperties = ["globalPropertyStringKey": "GlobalProperyStringValue", - "globalPropertyIntKey": 321, - "globalPropertyDoubleKey": 43.21, - "globalPropertyBoolKey": true] as [String: AnalyticsPropertyValue] + + let globalProperties = [ + "globalPropertyStringKey": "GlobalProperyStringValue", + "globalPropertyIntKey": 321, + "globalPropertyDoubleKey": 43.21, + "globalPropertyBoolKey": true + ] as [String: AnalyticsPropertyValue] Amplify.Analytics.registerGlobalProperties(globalProperties) - let properties = ["eventPropertyStringKey": "eventProperyStringValue", - "eventPropertyIntKey": 123, - "eventPropertyDoubleKey": 12.34, - "eventPropertyBoolKey": true] as [String: AnalyticsPropertyValue] + let properties = [ + "eventPropertyStringKey": "eventProperyStringValue", + "eventPropertyIntKey": 123, + "eventPropertyDoubleKey": 12.34, + "eventPropertyBoolKey": true + ] as [String: AnalyticsPropertyValue] let event = BasicAnalyticsEvent(name: "eventName", properties: properties) Amplify.Analytics.record(event: event) - + await fulfillment(of: [onlineExpectation], timeout: TestCommonConstants.networkTimeout) Amplify.Analytics.flushEvents() @@ -307,7 +331,7 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { } } networkMonitor.start(queue: DispatchQueue(label: "AWSPinpointAnalyticsPluginIntergrationTests.NetworkMonitor")) - + let flushEventsInvoked = expectation(description: "Flush events invoked") _ = Amplify.Hub.listen(to: .analytics, isIncluded: nil) { payload in if payload.eventName == HubPayload.EventName.Analytics.flushEvents { @@ -329,20 +353,24 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { flushEventsInvoked.fulfill() } } - - let globalProperties = ["globalPropertyStringKey": "GlobalProperyStringValue", - "globalPropertyIntKey": 321, - "globalPropertyDoubleKey": 43.21, - "globalPropertyBoolKey": true] as [String: AnalyticsPropertyValue] + + let globalProperties = [ + "globalPropertyStringKey": "GlobalProperyStringValue", + "globalPropertyIntKey": 321, + "globalPropertyDoubleKey": 43.21, + "globalPropertyBoolKey": true + ] as [String: AnalyticsPropertyValue] Amplify.Analytics.registerGlobalProperties(globalProperties) Amplify.Analytics.unregisterGlobalProperties() - let properties = ["eventPropertyStringKey": "eventProperyStringValue", - "eventPropertyIntKey": 123, - "eventPropertyDoubleKey": 12.34, - "eventPropertyBoolKey": true] as [String: AnalyticsPropertyValue] + let properties = [ + "eventPropertyStringKey": "eventProperyStringValue", + "eventPropertyIntKey": 123, + "eventPropertyDoubleKey": 12.34, + "eventPropertyBoolKey": true + ] as [String: AnalyticsPropertyValue] let event = BasicAnalyticsEvent(name: "eventName", properties: properties) Amplify.Analytics.record(event: event) - + await fulfillment(of: [onlineExpectation], timeout: TestCommonConstants.networkTimeout) Amplify.Analytics.flushEvents() @@ -358,11 +386,12 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { } let awsPinpoint = pinpointAnalyticsPlugin.getEscapeHatch() XCTAssertNotNil(awsPinpoint) - } - + } + private func plugin() -> AWSPinpointAnalyticsPlugin { guard let plugin = try? Amplify.Analytics.getPlugin(for: "awsPinpointAnalyticsPlugin"), - let analyticsPlugin = plugin as? AWSPinpointAnalyticsPlugin else { + let analyticsPlugin = plugin as? AWSPinpointAnalyticsPlugin + else { fatalError("Unable to retrieve configuration") } diff --git a/AmplifyPlugins/Analytics/Tests/AnalyticsHostApp/AnalyticsStressTests/AnalyticsStressTests.swift b/AmplifyPlugins/Analytics/Tests/AnalyticsHostApp/AnalyticsStressTests/AnalyticsStressTests.swift index 308dcfd1fb..736a2117b9 100644 --- a/AmplifyPlugins/Analytics/Tests/AnalyticsHostApp/AnalyticsStressTests/AnalyticsStressTests.swift +++ b/AmplifyPlugins/Analytics/Tests/AnalyticsHostApp/AnalyticsStressTests/AnalyticsStressTests.swift @@ -5,20 +5,20 @@ // SPDX-License-Identifier: Apache-2.0 // -import XCTest import AWSPinpoint +import XCTest -@testable import Amplify -@testable import AWSPinpointAnalyticsPlugin import AWSCognitoAuthPlugin import Network +@testable import Amplify +@testable import AWSPinpointAnalyticsPlugin final class AnalyticsStressTests: XCTestCase { static let amplifyConfiguration = "testconfiguration/AWSAmplifyStressTests-amplifyconfiguration" static let analyticsPluginKey = "awsPinpointAnalyticsPlugin" let concurrencyLimit = 50 - + override func setUp() { do { let config = try TestConfigHelper.retrieveAmplifyConfiguration(forResource: Self.amplifyConfiguration) @@ -35,7 +35,7 @@ final class AnalyticsStressTests: XCTestCase { } // MARK: - Stress Tests - + /// - Given: Analytics plugin configured with valid configuration /// - When: 50 different events with 5 attributes are recorded simultaneously /// - Then: Operations are successful @@ -48,17 +48,19 @@ final class AnalyticsStressTests: XCTestCase { } } networkMonitor.start(queue: DispatchQueue(label: "AWSPinpointAnalyticsPluginIntergrationTests.NetworkMonitor")) - + await fulfillment(of: [onlineExpectation], timeout: TestCommonConstants.networkTimeout) - + let recordExpectation = expectation(description: "Records are successfully recorded") recordExpectation.expectedFulfillmentCount = concurrencyLimit - for eventNumber in 0...concurrencyLimit { - let properties = ["eventPropertyStringKey1": "eventProperyStringValue1", - "eventPropertyStringKey2": "eventProperyStringValue2", - "eventPropertyStringKey3": "eventProperyStringValue3", - "eventPropertyStringKey4": "eventProperyStringValue4", - "eventPropertyStringKey5": "eventProperyStringValue5"] as [String: AnalyticsPropertyValue] + for eventNumber in 0 ... concurrencyLimit { + let properties = [ + "eventPropertyStringKey1": "eventProperyStringValue1", + "eventPropertyStringKey2": "eventProperyStringValue2", + "eventPropertyStringKey3": "eventProperyStringValue3", + "eventPropertyStringKey4": "eventProperyStringValue4", + "eventPropertyStringKey5": "eventProperyStringValue5" + ] as [String: AnalyticsPropertyValue] let event = BasicAnalyticsEvent(name: "eventName" + String(eventNumber), properties: properties) Amplify.Analytics.record(event: event) recordExpectation.fulfill() @@ -66,7 +68,7 @@ final class AnalyticsStressTests: XCTestCase { await fulfillment(of: [recordExpectation], timeout: TestCommonConstants.networkTimeout) } - + /// - Given: Analytics plugin configured with valid configuration /// - When: 50 different events with 20 attributes are recorded simultaneously /// - Then: Operations are successful @@ -79,34 +81,36 @@ final class AnalyticsStressTests: XCTestCase { } } networkMonitor.start(queue: DispatchQueue(label: "AWSPinpointAnalyticsPluginIntergrationTests.NetworkMonitor")) - + await fulfillment(of: [onlineExpectation], timeout: TestCommonConstants.networkTimeout) - + let recordExpectation = expectation(description: "Records are successfully recorded") recordExpectation.expectedFulfillmentCount = concurrencyLimit - for eventNumber in 0...concurrencyLimit { + for eventNumber in 0 ... concurrencyLimit { Task { - let properties = ["eventPropertyStringKey1": "eventProperyStringValue1", - "eventPropertyStringKey2": "eventProperyStringValue2", - "eventPropertyStringKey3": "eventProperyStringValue3", - "eventPropertyStringKey4": "eventProperyStringValue4", - "eventPropertyStringKey5": "eventProperyStringValue5", - "eventPropertyIntKey1": 123, - "eventPropertyIntKey2": 123, - "eventPropertyIntKey3": 123, - "eventPropertyIntKey4": 123, - "eventPropertyIntKey5": 123, - "eventPropertyDoubleKey1": 12.34, - "eventPropertyDoubleKey2": 12.34, - "eventPropertyDoubleKey3": 12.34, - "eventPropertyDoubleKey4": 12.34, - "eventPropertyDoubleKey5": 12.34, - "eventPropertyBoolKey1": true, - "eventPropertyBoolKey2": true, - "eventPropertyBoolKey3": true, - "eventPropertyBoolKey4": true, - "eventPropertyBoolKey5": true] as [String: AnalyticsPropertyValue] + let properties = [ + "eventPropertyStringKey1": "eventProperyStringValue1", + "eventPropertyStringKey2": "eventProperyStringValue2", + "eventPropertyStringKey3": "eventProperyStringValue3", + "eventPropertyStringKey4": "eventProperyStringValue4", + "eventPropertyStringKey5": "eventProperyStringValue5", + "eventPropertyIntKey1": 123, + "eventPropertyIntKey2": 123, + "eventPropertyIntKey3": 123, + "eventPropertyIntKey4": 123, + "eventPropertyIntKey5": 123, + "eventPropertyDoubleKey1": 12.34, + "eventPropertyDoubleKey2": 12.34, + "eventPropertyDoubleKey3": 12.34, + "eventPropertyDoubleKey4": 12.34, + "eventPropertyDoubleKey5": 12.34, + "eventPropertyBoolKey1": true, + "eventPropertyBoolKey2": true, + "eventPropertyBoolKey3": true, + "eventPropertyBoolKey4": true, + "eventPropertyBoolKey5": true + ] as [String: AnalyticsPropertyValue] let event = BasicAnalyticsEvent(name: "eventName" + String(eventNumber), properties: properties) Amplify.Analytics.record(event: event) recordExpectation.fulfill() diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/AWSPinpointBehavior.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/AWSPinpointBehavior.swift index 9f4c7d5d7a..e46287ddff 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/AWSPinpointBehavior.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/AWSPinpointBehavior.swift @@ -46,8 +46,10 @@ public protocol AWSPinpointBehavior { /// the automatic submission is disabled /// - Parameter interval: How much to wait between submissions /// - Parameter onSubmit: An optional callback to be run after each submission happens - func setAutomaticSubmitEventsInterval(_ interval: TimeInterval, - onSubmit: AnalyticsClientBehaviour.SubmitResult?) + func setAutomaticSubmitEventsInterval( + _ interval: TimeInterval, + onSubmit: AnalyticsClientBehaviour.SubmitResult? + ) // MARK: Session /// Beings automatically tracking session activity in the device. @@ -67,8 +69,10 @@ public protocol AWSPinpointBehavior { /// Updates the current endpoint with the provided profile /// - Parameter endpointProfile: The new endpoint profile /// - Parameter source: The source that originates this endpoint update, i.e. analytics or pushNotifications - func updateEndpoint(with endpointProfile: PinpointEndpointProfile, - source: AWSPinpointSource) async throws + func updateEndpoint( + with endpointProfile: PinpointEndpointProfile, + source: AWSPinpointSource + ) async throws } @_spi(InternalAWSPinpoint) diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/AnalyticsClient.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/AnalyticsClient.swift index c7db089487..9374091b5c 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/AnalyticsClient.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/AnalyticsClient.swift @@ -5,14 +5,14 @@ // SPDX-License-Identifier: Apache-2.0 // -import Foundation -import StoreKit import Amplify import AWSPinpoint +import Foundation +import StoreKit @_spi(InternalAWSPinpoint) public protocol AnalyticsClientBehaviour: Actor { - typealias SubmitResult = ((Result<[PinpointEvent], Error>) -> Void) + typealias SubmitResult = (Result<[PinpointEvent], Error>) -> Void nonisolated var pinpointClient: PinpointClientProtocol { get } func addGlobalAttribute(_ attribute: String, forKey key: String) @@ -27,18 +27,24 @@ public protocol AnalyticsClientBehaviour: Actor { func setRemoteGlobalAttributes(_ attributes: [String: String]) func removeAllRemoteGlobalAttributes() - func setAutomaticSubmitEventsInterval(_ interval: TimeInterval, - onSubmit: SubmitResult?) + func setAutomaticSubmitEventsInterval( + _ interval: TimeInterval, + onSubmit: SubmitResult? + ) @discardableResult func submitEvents() async throws -> [PinpointEvent] func update(_ session: PinpointSession) async throws - nonisolated func createAppleMonetizationEvent(with transaction: SKPaymentTransaction, - with product: SKProduct) -> PinpointEvent - nonisolated func createVirtualMonetizationEvent(withProductId productId: String, - withItemPrice itemPrice: Double, - withQuantity quantity: Int, - withCurrency currency: String) -> PinpointEvent + nonisolated func createAppleMonetizationEvent( + with transaction: SKPaymentTransaction, + with product: SKProduct + ) -> PinpointEvent + nonisolated func createVirtualMonetizationEvent( + withProductId productId: String, + withItemPrice itemPrice: Double, + withQuantity quantity: Int, + withCurrency currency: String + ) -> PinpointEvent nonisolated func createEvent(withEventType eventType: String) -> PinpointEvent } @@ -67,8 +73,10 @@ actor AnalyticsClient: AnalyticsClientBehaviour { private lazy var eventTypeAttributes: [String: PinpointEventAttributes] = [:] private lazy var eventTypeMetrics: [String: PinpointEventMetrics] = [:] - init(eventRecorder: AnalyticsEventRecording, - sessionProvider: @escaping SessionProvider) { + init( + eventRecorder: AnalyticsEventRecording, + sessionProvider: @escaping SessionProvider + ) { self.eventRecorder = eventRecorder self.sessionProvider = sessionProvider } @@ -76,28 +84,42 @@ actor AnalyticsClient: AnalyticsClientBehaviour { // Actors no longer use 'convenience' for inits. This is a warning in swift 5.7 and an error in swift 6+. // However, 'convenience' is required to build with swift <5.7 #if swift(>=5.7) - init(applicationId: String, - pinpointClient: PinpointClientProtocol, - endpointClient: EndpointClientBehaviour, - sessionProvider: @escaping SessionProvider) throws { - let dbAdapter = try SQLiteLocalStorageAdapter(prefixPath: Constants.eventRecorderStoragePathPrefix, - databaseName: applicationId) - let eventRecorder = try EventRecorder(appId: applicationId, - storage: AnalyticsEventSQLStorage(dbAdapter: dbAdapter), - pinpointClient: pinpointClient, endpointClient: endpointClient) + init( + applicationId: String, + pinpointClient: PinpointClientProtocol, + endpointClient: EndpointClientBehaviour, + sessionProvider: @escaping SessionProvider + ) throws { + let dbAdapter = try SQLiteLocalStorageAdapter( + prefixPath: Constants.eventRecorderStoragePathPrefix, + databaseName: applicationId + ) + let eventRecorder = try EventRecorder( + appId: applicationId, + storage: AnalyticsEventSQLStorage(dbAdapter: dbAdapter), + pinpointClient: pinpointClient, + endpointClient: endpointClient + ) self.init(eventRecorder: eventRecorder, sessionProvider: sessionProvider) } #else - convenience init(applicationId: String, - pinpointClient: PinpointClientProtocol, - endpointClient: EndpointClientBehaviour, - sessionProvider: @escaping SessionProvider) throws { - let dbAdapter = try SQLiteLocalStorageAdapter(prefixPath: Constants.eventRecorderStoragePathPrefix, - databaseName: applicationId) - let eventRecorder = try EventRecorder(appId: applicationId, - storage: AnalyticsEventSQLStorage(dbAdapter: dbAdapter), - pinpointClient: pinpointClient, endpointClient: endpointClient) + convenience init( + applicationId: String, + pinpointClient: PinpointClientProtocol, + endpointClient: EndpointClientBehaviour, + sessionProvider: @escaping SessionProvider + ) throws { + let dbAdapter = try SQLiteLocalStorageAdapter( + prefixPath: Constants.eventRecorderStoragePathPrefix, + databaseName: applicationId + ) + let eventRecorder = try EventRecorder( + appId: applicationId, + storage: AnalyticsEventSQLStorage(dbAdapter: dbAdapter), + pinpointClient: pinpointClient, + endpointClient: endpointClient + ) self.init(eventRecorder: eventRecorder, sessionProvider: sessionProvider) } @@ -160,65 +182,91 @@ actor AnalyticsClient: AnalyticsClientBehaviour { } // MARK: - Monetization events - nonisolated func createAppleMonetizationEvent(with transaction: SKPaymentTransaction, - with product: SKProduct) -> PinpointEvent { + nonisolated func createAppleMonetizationEvent( + with transaction: SKPaymentTransaction, + with product: SKProduct + ) -> PinpointEvent { let numberFormatter = NumberFormatter() numberFormatter.locale = product.priceLocale numberFormatter.numberStyle = .currency numberFormatter.isLenient = true - return createMonetizationEvent(withStore: Constants.PurchaseEvent.appleStore, - productId: product.productIdentifier, - quantity: transaction.payment.quantity, - itemPrice: product.price.doubleValue, - currencyCode: product.priceLocale.currencyCode, - formattedItemPrice: numberFormatter.string(from: product.price), - transactionId: transaction.transactionIdentifier) + return createMonetizationEvent( + withStore: Constants.PurchaseEvent.appleStore, + productId: product.productIdentifier, + quantity: transaction.payment.quantity, + itemPrice: product.price.doubleValue, + currencyCode: product.priceLocale.currencyCode, + formattedItemPrice: numberFormatter.string(from: product.price), + transactionId: transaction.transactionIdentifier + ) } - nonisolated func createVirtualMonetizationEvent(withProductId productId: String, - withItemPrice itemPrice: Double, - withQuantity quantity: Int, - withCurrency currency: String) -> PinpointEvent { - return createMonetizationEvent(withStore: Constants.PurchaseEvent.virtual, - productId: productId, - quantity: quantity, - itemPrice: itemPrice, - currencyCode: currency) + nonisolated func createVirtualMonetizationEvent( + withProductId productId: String, + withItemPrice itemPrice: Double, + withQuantity quantity: Int, + withCurrency currency: String + ) -> PinpointEvent { + return createMonetizationEvent( + withStore: Constants.PurchaseEvent.virtual, + productId: productId, + quantity: quantity, + itemPrice: itemPrice, + currencyCode: currency + ) } - private nonisolated func createMonetizationEvent(withStore store: String, - productId: String, - quantity: Int, - itemPrice: Double, - currencyCode: String?, - formattedItemPrice: String? = nil, - priceLocale: Locale? = nil, - transactionId: String? = nil) -> PinpointEvent { - let monetizationEvent = PinpointEvent(eventType: Constants.PurchaseEvent.name, - session: sessionProvider()) - monetizationEvent.addAttribute(store, - forKey: Constants.PurchaseEvent.Keys.store) - monetizationEvent.addAttribute(productId, - forKey: Constants.PurchaseEvent.Keys.productId) - monetizationEvent.addMetric(quantity, - forKey: Constants.PurchaseEvent.Keys.quantity) - monetizationEvent.addMetric(itemPrice, - forKey: Constants.PurchaseEvent.Keys.itemPrice) - - if let currencyCode = currencyCode { - monetizationEvent.addAttribute(currencyCode, - forKey: Constants.PurchaseEvent.Keys.currency) + private nonisolated func createMonetizationEvent( + withStore store: String, + productId: String, + quantity: Int, + itemPrice: Double, + currencyCode: String?, + formattedItemPrice: String? = nil, + priceLocale: Locale? = nil, + transactionId: String? = nil + ) -> PinpointEvent { + let monetizationEvent = PinpointEvent( + eventType: Constants.PurchaseEvent.name, + session: sessionProvider() + ) + monetizationEvent.addAttribute( + store, + forKey: Constants.PurchaseEvent.Keys.store + ) + monetizationEvent.addAttribute( + productId, + forKey: Constants.PurchaseEvent.Keys.productId + ) + monetizationEvent.addMetric( + quantity, + forKey: Constants.PurchaseEvent.Keys.quantity + ) + monetizationEvent.addMetric( + itemPrice, + forKey: Constants.PurchaseEvent.Keys.itemPrice + ) + + if let currencyCode { + monetizationEvent.addAttribute( + currencyCode, + forKey: Constants.PurchaseEvent.Keys.currency + ) } - if let formattedItemPrice = formattedItemPrice { - monetizationEvent.addAttribute(formattedItemPrice, - forKey: Constants.PurchaseEvent.Keys.priceFormatted) + if let formattedItemPrice { + monetizationEvent.addAttribute( + formattedItemPrice, + forKey: Constants.PurchaseEvent.Keys.priceFormatted + ) } - if let transactionId = transactionId { - monetizationEvent.addAttribute(transactionId, - forKey: Constants.PurchaseEvent.Keys.transactionId) + if let transactionId { + monetizationEvent.addAttribute( + transactionId, + forKey: Constants.PurchaseEvent.Keys.transactionId + ) } return monetizationEvent @@ -227,8 +275,10 @@ actor AnalyticsClient: AnalyticsClientBehaviour { // MARK: - Event recording nonisolated func createEvent(withEventType eventType: String) -> PinpointEvent { precondition(!eventType.isEmpty, "Event types must be at least 1 character in length.") - return PinpointEvent(eventType: eventType, - session: sessionProvider()) + return PinpointEvent( + eventType: eventType, + session: sessionProvider() + ) } func record(_ event: PinpointEvent) async throws { @@ -263,13 +313,15 @@ actor AnalyticsClient: AnalyticsClientBehaviour { func submitEvents() async throws -> [PinpointEvent] { return try await eventRecorder.submitAllEvents() } - + func update(_ session: PinpointSession) async throws { try await eventRecorder.update(session) } - func setAutomaticSubmitEventsInterval(_ interval: TimeInterval, - onSubmit: SubmitResult?) { + func setAutomaticSubmitEventsInterval( + _ interval: TimeInterval, + onSubmit: SubmitResult? + ) { guard automaticSubmitEventsInterval != interval else { let message = interval == .zero ? "disabled" : "set to \(interval) seconds" log.verbose("Automatic Submission of Events' interval is already \(message).") @@ -287,7 +339,7 @@ actor AnalyticsClient: AnalyticsClientBehaviour { automaticSubmitEventsTimer = RepeatingTimer.createRepeatingTimer( timeInterval: automaticSubmitEventsInterval, eventHandler: { [weak self] in - guard let self = self else { return } + guard let self else { return } Task { self.log.debug("AutoFlushTimer triggered, flushing events") do { @@ -297,7 +349,8 @@ actor AnalyticsClient: AnalyticsClientBehaviour { onSubmit?(.failure(error)) } } - }) + } + ) automaticSubmitEventsTimer?.resume() } } @@ -313,13 +366,13 @@ extension AnalyticsClient: DefaultLogger { } extension AnalyticsClient { - private struct Constants { - struct PurchaseEvent { + private enum Constants { + enum PurchaseEvent { static let name = "_monetization.purchase" static let appleStore = "Apple" static let virtual = "Virtual" - struct Keys { + enum Keys { static let productId = "_product_id" static let quantity = "_quantity" static let itemPrice = "_item_price" diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/EventRecorder.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/EventRecorder.swift index 0291d2f412..cf155d9bde 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/EventRecorder.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/EventRecorder.swift @@ -7,9 +7,9 @@ import Amplify import AWSCognitoAuthPlugin +import enum AwsCommonRuntimeKit.CommonRunTimeError import AWSPinpoint import ClientRuntime -import enum AwsCommonRuntimeKit.CommonRunTimeError import Foundation /// AnalyticsEventRecording saves and submits pinpoint events @@ -25,10 +25,12 @@ protocol AnalyticsEventRecording: Actor { /// - ofType: event type /// - withSessionId: session identifier /// - setAttributes: event attributes - func updateAttributesOfEvents(ofType: String, - withSessionId: PinpointSession.SessionId, - setAttributes: [String: String]) throws - + func updateAttributesOfEvents( + ofType: String, + withSessionId: PinpointSession.SessionId, + setAttributes: [String: String] + ) throws + /// Updates the session information of the events that match the same sessionId. /// - Parameter session: The session to update func update(_ session: PinpointSession) throws @@ -53,10 +55,12 @@ actor EventRecorder: AnalyticsEventRecording { /// - storage: A storage object that conforms to AnalyticsEventStorage /// - pinpointClient: A Pinpoint client /// - endpointClient: An EndpointClientBehaviour client - init(appId: String, - storage: AnalyticsEventStorage, - pinpointClient: PinpointClientProtocol, - endpointClient: EndpointClientBehaviour) throws { + init( + appId: String, + storage: AnalyticsEventStorage, + pinpointClient: PinpointClientProtocol, + endpointClient: EndpointClientBehaviour + ) throws { self.appId = appId self.storage = storage self.pinpointClient = pinpointClient @@ -74,12 +78,16 @@ actor EventRecorder: AnalyticsEventRecording { try storage.checkDiskSize(limit: Constants.pinpointClientByteLimitDefault) } - func updateAttributesOfEvents(ofType eventType: String, - withSessionId sessionId: PinpointSession.SessionId, - setAttributes attributes: [String: String]) throws { - try storage.updateEvents(ofType: eventType, - withSessionId: sessionId, - setAttributes: attributes) + func updateAttributesOfEvents( + ofType eventType: String, + withSessionId sessionId: PinpointSession.SessionId, + setAttributes attributes: [String: String] + ) throws { + try storage.updateEvents( + ofType: eventType, + withSessionId: sessionId, + setAttributes: attributes + ) } func update(_ session: PinpointSession) throws { @@ -128,8 +136,10 @@ actor EventRecorder: AnalyticsEventRecording { } } - private func submit(pinpointEvents: [PinpointEvent], - endpointProfile: PinpointEndpointProfile) async throws { + private func submit( + pinpointEvents: [PinpointEvent], + endpointProfile: PinpointEndpointProfile + ) async throws { var clientEvents = [String: PinpointClientTypes.Event]() var pinpointEventsById = [String: PinpointEvent]() for event in pinpointEvents { @@ -138,11 +148,15 @@ actor EventRecorder: AnalyticsEventRecording { } let publicEndpoint = endpointClient.convertToPublicEndpoint(endpointProfile) - let eventsBatch = PinpointClientTypes.EventsBatch(endpoint: publicEndpoint, - events: clientEvents) + let eventsBatch = PinpointClientTypes.EventsBatch( + endpoint: publicEndpoint, + events: clientEvents + ) let batchItem = [endpointProfile.endpointId: eventsBatch] - let putEventsInput = PutEventsInput(applicationId: appId, - eventsRequest: .init(batchItem: batchItem)) + let putEventsInput = PutEventsInput( + applicationId: appId, + eventsRequest: .init(batchItem: batchItem) + ) await identifySource(for: pinpointEvents) do { @@ -155,7 +169,7 @@ actor EventRecorder: AnalyticsEventRecording { throw AnalyticsError.unknown(errorMessage) } - let endpointResponseMap = results.compactMap { $0.value.endpointItemResponse } + let endpointResponseMap = results.compactMap(\.value.endpointItemResponse) for endpointResponse in endpointResponseMap { if HttpStatusCode.accepted.rawValue == endpointResponse.statusCode { log.verbose("EndpointProfile updated successfully.") @@ -164,7 +178,7 @@ actor EventRecorder: AnalyticsEventRecording { } } - let eventsResponseMap = results.compactMap { $0.value.eventsItemResponse } + let eventsResponseMap = results.compactMap(\.value.eventsItemResponse) for (eventId, eventResponse) in eventsResponseMap.flatMap({ $0 }) { guard let event = pinpointEventsById[eventId] else { continue } let responseMessage = eventResponse.message ?? "Unknown" @@ -181,11 +195,10 @@ actor EventRecorder: AnalyticsEventRecording { } else { // On other failures, increment the event retry counter incrementEventRetry(eventId: eventId) - let retryMessage: String - if event.retryCount < Constants.maxNumberOfRetries { - retryMessage = "Event will be retried" + let retryMessage = if event.retryCount < Constants.maxNumberOfRetries { + "Event will be retried" } else { - retryMessage = "Event will be discarded because it exceeded its max retry attempts" + "Event will be discarded because it exceeded its max retry attempts" } log.verbose("Submit attempt #\(event.retryCount + 1) for event with id \(eventId) failed.") log.error("Unable to successfully deliver event with id \(eventId) to the server. \(retryMessage). Error: \(responseMessage)") @@ -326,9 +339,11 @@ actor EventRecorder: AnalyticsEventRecording { events.forEach { incrementEventRetry(eventId: $0.id) } } - private func retry(times: Int = Constants.defaultNumberOfRetriesForStorageOperations, - onErrorMessage: String, - _ closure: () throws -> Void) { + private func retry( + times: Int = Constants.defaultNumberOfRetriesForStorageOperations, + onErrorMessage: String, + _ closure: () throws -> Void + ) { do { try closure() } catch { @@ -357,30 +372,30 @@ extension EventRecorder: DefaultLogger { public static var log: Logger { Amplify.Logging.logger(forCategory: CategoryType.analytics.displayName, forNamespace: String(describing: self)) } - nonisolated public var log: Logger { + public nonisolated var log: Logger { Self.log } } extension EventRecorder { - private struct Constants { + private enum Constants { static let maxEventsSubmittedPerBatch = 100 - static let pinpointClientByteLimitDefault = 5 * 1024 * 1024 // 5MB - static let pinpointClientBatchRecordByteLimitDefault = 512 * 1024 // 0.5MB - static let pinpointClientBatchRecordByteLimitMax = 4 * 1024 * 1024 // 4MB + static let pinpointClientByteLimitDefault = 5 * 1_024 * 1_024 // 5MB + static let pinpointClientBatchRecordByteLimitDefault = 512 * 1_024 // 0.5MB + static let pinpointClientBatchRecordByteLimitMax = 4 * 1_024 * 1_024 // 4MB static let acceptedResponseMessage = "Accepted" static let defaultNumberOfRetriesForStorageOperations = 1 static let maxNumberOfRetries = 3 } } -private extension Array where Element == PinpointEvent { +private extension [PinpointEvent] { func numberOfPushNotificationsEvents() -> Int { - let pushNotificationsEvents = filter({ event in + let pushNotificationsEvents = filter { event in event.eventType.contains(".opened_notification") || event.eventType.contains(".received_foreground") || event.eventType.contains(".received_background") - }) + } return pushNotificationsEvents.count } } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventSQLStorage.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventSQLStorage.swift index c0597a6e98..91f7df443b 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventSQLStorage.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventSQLStorage.swift @@ -5,8 +5,8 @@ // SPDX-License-Identifier: Apache-2.0 // -import Foundation import Amplify +import Foundation import SQLite /// This is a temporary placeholder class to interface with the SQLiteLocalStorageAdapter @@ -101,9 +101,11 @@ class AnalyticsEventSQLStorage: AnalyticsEventStorage { _ = try dbAdapter.executeQuery(deleteStatement, []) } - func updateEvents(ofType eventType: String, - withSessionId sessionId: PinpointSession.SessionId, - setAttributes attributes: [String: String]) throws { + func updateEvents( + ofType eventType: String, + withSessionId sessionId: PinpointSession.SessionId, + setAttributes attributes: [String: String] + ) throws { let updateStatement = """ UPDATE Event SET attributes = ? @@ -113,9 +115,10 @@ class AnalyticsEventSQLStorage: AnalyticsEventStorage { _ = try dbAdapter.executeQuery(updateStatement, [ PinpointEvent.archiveEventAttributes(attributes), sessionId, - eventType]) + eventType + ]) } - + func updateSession(_ session: PinpointSession) throws { let updateStatement = """ UPDATE Event @@ -226,15 +229,15 @@ class AnalyticsEventSQLStorage: AnalyticsEventStorage { } /// Check the disk usage limit of the local database. - /// If database is over the limit then delete all dirty events and oldest event + /// If database is over the limit then delete all dirty events and oldest event /// - Parameter limit: the size limit of the database in Byte unit func checkDiskSize(limit: Byte) throws { if dbAdapter.diskBytesUsed > limit { - try self.deleteDirtyEvents() + try deleteDirtyEvents() } if dbAdapter.diskBytesUsed > limit { - try self.deleteOldestEvent() + try deleteOldestEvent() } } } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventStorage.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventStorage.swift index d5aea17167..8fcf6db67c 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventStorage.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventStorage.swift @@ -26,10 +26,12 @@ protocol AnalyticsEventStorage { /// - ofType: event type /// - sessionId: session identifier /// - setAttributes: event attributes - func updateEvents(ofType: String, - withSessionId: PinpointSession.SessionId, - setAttributes: [String: String]) throws - + func updateEvents( + ofType: String, + withSessionId: PinpointSession.SessionId, + setAttributes: [String: String] + ) throws + /// Updates the session information of the events that match the same sessionId. /// - Parameter session: The session to update func updateSession(_ session: PinpointSession) throws diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/PinpointEvent+Bindings.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/PinpointEvent+Bindings.swift index 571d60b41d..7ebc4965af 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/PinpointEvent+Bindings.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/PinpointEvent+Bindings.swift @@ -55,7 +55,8 @@ extension PinpointEvent { let dateFormatter = DateFormatter.iso8601Formatter guard let sessionId = element[EventPropertyIndex.sessionId] as? String, let startTimeString = element[EventPropertyIndex.sessionStartTime] as? String, - let startTime = dateFormatter.date(from: startTimeString) else { + let startTime = dateFormatter.date(from: startTimeString) + else { return nil } @@ -68,7 +69,8 @@ extension PinpointEvent { guard let eventType = element[EventPropertyIndex.eventType] as? String, let eventTimestampValue = element[EventPropertyIndex.eventTimestamp] as? String, - let timestamp = dateFormatter.date(from: eventTimestampValue) else { + let timestamp = dateFormatter.date(from: eventTimestampValue) + else { return nil } @@ -100,7 +102,7 @@ extension PinpointEvent { return pinpointEvent } - struct EventPropertyIndex { + enum EventPropertyIndex { static let id = 0 static let attributes = 1 static let eventType = 2 diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/SQLiteLocalStorageAdapter.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/SQLiteLocalStorageAdapter.swift index ae32ef37fd..0c4f147cd6 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/SQLiteLocalStorageAdapter.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/SQLiteLocalStorageAdapter.swift @@ -23,15 +23,19 @@ final class SQLiteLocalStorageAdapter: SQLStorageProtocol { /// - prefixPath: A prefix to be used for the database path. Defaults to none. /// - databaseName: The database name /// - fileManager: A FileManagerBehaviour instance to interact with the disk. Defaults to FileManager.default - init(prefixPath: String = "", - databaseName: String, - fileManager: FileManagerBehaviour = FileManager.default) throws { + init( + prefixPath: String = "", + databaseName: String, + fileManager: FileManagerBehaviour = FileManager.default + ) throws { let dbDirectoryPath = try Self.getTmpPath() .appendingPathComponent(prefixPath) var dbFilePath = dbDirectoryPath.appendingPathComponent(databaseName) if !fileManager.fileExists(atPath: dbDirectoryPath.path) { - try fileManager.createDirectory(atPath: dbDirectoryPath.path, - withIntermediateDirectories: true) + try fileManager.createDirectory( + atPath: dbDirectoryPath.path, + withIntermediateDirectories: true + ) } let connection: Connection @@ -77,7 +81,7 @@ final class SQLiteLocalStorageAdapter: SQLStorageProtocol { /// Create a SQL table /// - Parameter statement: SQL statement to create a table func createTable(_ statement: String) throws { - guard let connection = connection else { + guard let connection else { throw LocalStorageError.missingConnection } @@ -94,7 +98,7 @@ final class SQLiteLocalStorageAdapter: SQLStorageProtocol { /// - bindings: A collection of SQL bindings to prepare with the query statement /// - Returns: A SQL statement result from the query func executeQuery(_ statement: String, _ bindings: [Binding?]) throws -> Statement { - guard let connection = connection else { + guard let connection else { throw LocalStorageError.missingConnection } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/PinpointEvent+PinpointClientTypes.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/PinpointEvent+PinpointClientTypes.swift index e2c78b496e..ef39960ac0 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/PinpointEvent+PinpointClientTypes.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/PinpointEvent+PinpointClientTypes.swift @@ -7,12 +7,12 @@ import AWSPinpoint import AWSPluginsCore -import InternalAmplifyCredentials import Foundation +import InternalAmplifyCredentials extension PinpointEvent { private var clientTypeSession: PinpointClientTypes.Session? { - var sessionDuration: Int? = nil + var sessionDuration: Int? if let duration = session.duration { // If the session duration cannot be represented by Int, return a nil session instead. // This is extremely unlikely to happen since a session's stopTime is set when the app is closed diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/PinpointEvent.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/PinpointEvent.swift index a8296abaed..9d92cd94f8 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/PinpointEvent.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/PinpointEvent.swift @@ -17,14 +17,16 @@ public class PinpointEvent: AnalyticsPropertiesModel { let eventDate: Date let session: PinpointSession let retryCount: Int - private(set) public lazy var attributes: [String: String] = [:] - private(set) public lazy var metrics: [String: Double] = [:] - - init(id: String = UUID().uuidString, - eventType: String, - eventDate: Date = Date(), - session: PinpointSession, - retryCount: Int = 0) { + public private(set) lazy var attributes: [String: String] = [:] + public private(set) lazy var metrics: [String: Double] = [:] + + init( + id: String = UUID().uuidString, + eventType: String, + eventDate: Date = Date(), + session: PinpointSession, + retryCount: Int = 0 + ) { self.id = id self.eventType = eventType self.eventDate = eventDate diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Configuration/AWSPinpointPluginConfiguration.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Configuration/AWSPinpointPluginConfiguration.swift index 6c2969fa3d..ec22d2fbb0 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Configuration/AWSPinpointPluginConfiguration.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Configuration/AWSPinpointPluginConfiguration.swift @@ -6,8 +6,8 @@ // @_spi(InternalAmplifyConfiguration) import Amplify -import AWSPinpoint import AWSClientRuntime +import AWSPinpoint import Foundation @_spi(InternalAWSPinpoint) @@ -26,14 +26,16 @@ public struct AWSPinpointPluginConfiguration { ) } - self.init( - appId: try AWSPinpointPluginConfiguration.getAppId(configObject), - region: try AWSPinpointPluginConfiguration.getRegion(configObject) + try self.init( + appId: AWSPinpointPluginConfiguration.getAppId(configObject), + region: AWSPinpointPluginConfiguration.getRegion(configObject) ) } - public init(appId: String, - region: String) { + public init( + appId: String, + region: String + ) { self.appId = appId self.region = region } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/AWSPinpointFactory.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/AWSPinpointFactory.swift index 05f64ea9e1..4eaf2e06e1 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/AWSPinpointFactory.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/AWSPinpointFactory.swift @@ -24,8 +24,10 @@ public class AWSPinpointFactory { static var provisioningProfileReader: ProvisioningProfileReader = .default - public static func sharedPinpoint(appId: String, - region: String) throws -> AWSPinpointBehavior { + public static func sharedPinpoint( + appId: String, + region: String + ) throws -> AWSPinpointBehavior { let key = PinpointContextKey(appId: appId, region: region) if let existingContext = instances[key] { return existingContext diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext+AWSPinpointBehavior.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext+AWSPinpointBehavior.swift index 30fe00f951..0b15e93011 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext+AWSPinpointBehavior.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext+AWSPinpointBehavior.swift @@ -31,8 +31,10 @@ extension PinpointContext: AWSPinpointBehavior { await endpointClient.currentEndpointProfile() } - func updateEndpoint(with endpointProfile: PinpointEndpointProfile, - source: AWSPinpointSource) async throws { + func updateEndpoint( + with endpointProfile: PinpointEndpointProfile, + source: AWSPinpointSource + ) async throws { await PinpointRequestsRegistry.shared.registerSource(source, for: .updateEndpoint) try await endpointClient.updateEndpointProfile(with: endpointProfile) } @@ -61,8 +63,10 @@ extension PinpointContext: AWSPinpointBehavior { await analyticsClient.setRemoteGlobalAttributes(attributes) } - func setAutomaticSubmitEventsInterval(_ interval: TimeInterval, - onSubmit: AnalyticsClientBehaviour.SubmitResult?) { + func setAutomaticSubmitEventsInterval( + _ interval: TimeInterval, + onSubmit: AnalyticsClientBehaviour.SubmitResult? + ) { Task { await analyticsClient.setAutomaticSubmitEventsInterval(interval, onSubmit: onSubmit) } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext.swift index 4267e99084..59e67ebd44 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Context/PinpointContext.swift @@ -49,14 +49,16 @@ extension FileManager: FileManagerBehaviour, DefaultLogger { } func createDirectory(atPath path: String, withIntermediateDirectories createIntermediates: Bool) throws { - try createDirectory(atPath: path, - withIntermediateDirectories: createIntermediates, - attributes: nil) + try createDirectory( + atPath: path, + withIntermediateDirectories: createIntermediates, + attributes: nil + ) } func fileSize(for url: URL) -> Byte { do { - let attributes = try self.attributesOfItem(atPath: url.path) + let attributes = try attributesOfItem(atPath: url.path) return attributes[.size] as? Byte ?? 0 } catch { log.error("Error getting file size with error \(error)") @@ -81,10 +83,12 @@ struct PinpointContextConfiguration { /// Setting this flag to true will set the Endpoint Profile to have a channel type of "APNS_SANDBOX". let isDebug: Bool - init(appId: String, - region: String, - credentialsProvider: CredentialsProviding, - isDebug: Bool = false) { + init( + appId: String, + region: String, + credentialsProvider: CredentialsProviding, + isDebug: Bool = false + ) { self.appId = appId self.region = region self.credentialsProvider = credentialsProvider @@ -109,58 +113,78 @@ class PinpointContext { private let configuration: PinpointContextConfiguration private let storage: PinpointContextStorage - init(with configuration: PinpointContextConfiguration, - endpointInformationProvider: EndpointInformationProvider = DefaultEndpointInformationProvider(), - userDefaults: UserDefaultsBehaviour = UserDefaults.standard, - keychainStore: KeychainStoreBehavior = KeychainStore(service: PinpointContext.Constants.Keychain.service), - fileManager: FileManagerBehaviour = FileManager.default, - archiver: AmplifyArchiverBehaviour = AmplifyArchiver(), - remoteNotificationsHelper: RemoteNotificationsBehaviour = .default) throws { + init( + with configuration: PinpointContextConfiguration, + endpointInformationProvider: EndpointInformationProvider = DefaultEndpointInformationProvider(), + userDefaults: UserDefaultsBehaviour = UserDefaults.standard, + keychainStore: KeychainStoreBehavior = KeychainStore(service: PinpointContext.Constants.Keychain.service), + fileManager: FileManagerBehaviour = FileManager.default, + archiver: AmplifyArchiverBehaviour = AmplifyArchiver(), + remoteNotificationsHelper: RemoteNotificationsBehaviour = .default + ) throws { self.configuration = configuration - storage = PinpointContextStorage(userDefaults: userDefaults, - keychainStore: keychainStore, - fileManager: fileManager, - archiver: archiver) - uniqueId = Self.retrieveUniqueId(applicationId: configuration.appId, storage: storage) - - let pinpointClient = try PinpointClient(region: configuration.region, - credentialsProvider: configuration.credentialsProvider) - - endpointClient = EndpointClient(configuration: .init(appId: configuration.appId, - uniqueDeviceId: uniqueId, - isDebug: configuration.isDebug), - pinpointClient: pinpointClient, - endpointInformationProvider: endpointInformationProvider, - userDefaults: userDefaults, - keychain: keychainStore, - remoteNotificationsHelper: remoteNotificationsHelper) - - sessionClient = SessionClient(archiver: archiver, - configuration: .init(appId: configuration.appId, - uniqueDeviceId: uniqueId), - endpointClient: endpointClient, - userDefaults: userDefaults) + self.storage = PinpointContextStorage( + userDefaults: userDefaults, + keychainStore: keychainStore, + fileManager: fileManager, + archiver: archiver + ) + self.uniqueId = Self.retrieveUniqueId(applicationId: configuration.appId, storage: storage) + + let pinpointClient = try PinpointClient( + region: configuration.region, + credentialsProvider: configuration.credentialsProvider + ) + + self.endpointClient = EndpointClient( + configuration: .init( + appId: configuration.appId, + uniqueDeviceId: uniqueId, + isDebug: configuration.isDebug + ), + pinpointClient: pinpointClient, + endpointInformationProvider: endpointInformationProvider, + userDefaults: userDefaults, + keychain: keychainStore, + remoteNotificationsHelper: remoteNotificationsHelper + ) + + self.sessionClient = SessionClient( + archiver: archiver, + configuration: .init( + appId: configuration.appId, + uniqueDeviceId: uniqueId + ), + endpointClient: endpointClient, + userDefaults: userDefaults + ) let sessionProvider: () -> PinpointSession = { [weak sessionClient] in - guard let sessionClient = sessionClient else { + guard let sessionClient else { fatalError("SessionClient was deallocated") } return sessionClient.currentSession } - analyticsClient = try AnalyticsClient(applicationId: configuration.appId, - pinpointClient: pinpointClient, - endpointClient: endpointClient, - sessionProvider: sessionProvider) + self.analyticsClient = try AnalyticsClient( + applicationId: configuration.appId, + pinpointClient: pinpointClient, + endpointClient: endpointClient, + sessionProvider: sessionProvider + ) sessionClient.analyticsClient = analyticsClient sessionClient.startPinpointSession() setAutomaticSubmitEventsInterval(Constants.defaultAutomaticSubmissionInterval) } - private static func legacyPreferencesFilePath(applicationId: String, - storage: PinpointContextStorage) -> String? { - let applicationSupportDirectoryUrls = storage.fileManager.urls(for: .applicationSupportDirectory, - in: .userDomainMask) + private static func legacyPreferencesFilePath( + applicationId: String, + storage: PinpointContextStorage + ) -> String? { + let applicationSupportDirectoryUrls = storage.fileManager.urls( + for: .applicationSupportDirectory, + in: .userDomainMask + ) let preferencesFileUrl = applicationSupportDirectoryUrls.first? .appendingPathComponent(Constants.Preferences.mobileAnalyticsRoot) .appendingPathComponent(applicationId) @@ -169,10 +193,15 @@ class PinpointContext { return preferencesFileUrl?.path } - private static func removeLegacyPreferencesFile(applicationId: String, - storage: PinpointContextStorage) { - guard let preferencesPath = legacyPreferencesFilePath(applicationId: applicationId, - storage: storage) else { + private static func removeLegacyPreferencesFile( + applicationId: String, + storage: PinpointContextStorage + ) { + guard let preferencesPath = legacyPreferencesFilePath( + applicationId: applicationId, + storage: storage + ) + else { return } @@ -183,13 +212,20 @@ class PinpointContext { } } - private static func legacyUniqueId(applicationId: String, - storage: PinpointContextStorage) -> String? { - guard let preferencesPath = legacyPreferencesFilePath(applicationId: applicationId, - storage: storage), + private static func legacyUniqueId( + applicationId: String, + storage: PinpointContextStorage + ) -> String? { + guard let preferencesPath = legacyPreferencesFilePath( + applicationId: applicationId, + storage: storage + ), storage.fileManager.fileExists(atPath: preferencesPath), - let preferencesJson = try? JSONSerialization.jsonObject(with: Data(contentsOf: URL(fileURLWithPath: preferencesPath)), - options: .mutableContainers) as? [String: String] else { + let preferencesJson = try? JSONSerialization.jsonObject( + with: Data(contentsOf: URL(fileURLWithPath: preferencesPath)), + options: .mutableContainers + ) as? [String: String] + else { return nil } @@ -198,20 +234,22 @@ class PinpointContext { /** Attempts to retrieve a previously generated Device Unique ID. - + This value can be present in 3 places: 1. In a preferences file stored in disk 2. In UserDefauls 3. In the Keychain - + 1 and 2 are legacy storage options that are supportted for backwards compability, but once retrieved those values will be migrated to the Keychain. - + If no existing Device Unique ID is found, a new one will be generated and stored in the Keychain. - + - Returns: A string representing the Device Unique ID */ - private static func retrieveUniqueId(applicationId: String, - storage: PinpointContextStorage) -> String { + private static func retrieveUniqueId( + applicationId: String, + storage: PinpointContextStorage + ) -> String { // 1. Look for the UniqueId in the Keychain if let deviceUniqueId = try? storage.keychainStore._getString(Constants.Keychain.uniqueIdKey) { return deviceUniqueId @@ -282,15 +320,15 @@ extension PinpointContext: DefaultLogger { } extension PinpointContext { - struct Constants { + enum Constants { static let defaultAutomaticSubmissionInterval: TimeInterval = 60 - struct Preferences { + enum Preferences { static let mobileAnalyticsRoot = "com.amazonaws.MobileAnalytics" static let fileName = "preferences" static let uniqueIdKey = "UniqueId" } - struct Keychain { + enum Keychain { static let service = "com.amazonaws.AWSPinpointContext" static let uniqueIdKey = "com.amazonaws.AWSPinpointContextKeychainUniqueIdKey" } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointClient.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointClient.swift index e89118f4bb..f71e0f824a 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointClient.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointClient.swift @@ -40,13 +40,14 @@ actor EndpointClient: EndpointClientBehaviour { private var endpointProfile: PinpointEndpointProfile? private static let defaultDateFormatter = ISO8601DateFormatter() - init(configuration: EndpointClient.Configuration, - pinpointClient: PinpointClientProtocol, - archiver: AmplifyArchiverBehaviour = AmplifyArchiver(), - endpointInformationProvider: EndpointInformationProvider, - userDefaults: UserDefaultsBehaviour = UserDefaults.standard, - keychain: KeychainStoreBehavior = KeychainStore(service: PinpointContext.Constants.Keychain.service), - remoteNotificationsHelper: RemoteNotificationsBehaviour = .default + init( + configuration: EndpointClient.Configuration, + pinpointClient: PinpointClientProtocol, + archiver: AmplifyArchiverBehaviour = AmplifyArchiver(), + endpointInformationProvider: EndpointInformationProvider, + userDefaults: UserDefaultsBehaviour = UserDefaults.standard, + keychain: KeychainStoreBehavior = KeychainStore(service: PinpointContext.Constants.Keychain.service), + remoteNotificationsHelper: RemoteNotificationsBehaviour = .default ) { self.configuration = configuration self.pinpointClient = pinpointClient @@ -76,7 +77,7 @@ actor EndpointClient: EndpointClientBehaviour { private func retrieveOrCreateEndpointProfile() async -> PinpointEndpointProfile { // 1. Look for the local endpointProfile variable - if let endpointProfile = endpointProfile { + if let endpointProfile { return endpointProfile } @@ -89,8 +90,10 @@ actor EndpointClient: EndpointClientBehaviour { try? keychain._remove(Constants.endpointProfileKey) // Create a new PinpointEndpointProfile - return await configure(endpointProfile: PinpointEndpointProfile(applicationId: configuration.appId, - endpointId: configuration.uniqueDeviceId)) + return await configure(endpointProfile: PinpointEndpointProfile( + applicationId: configuration.appId, + endpointId: configuration.uniqueDeviceId + )) } private func configure(endpointProfile: PinpointEndpointProfile) async -> PinpointEndpointProfile { @@ -132,7 +135,8 @@ actor EndpointClient: EndpointClientBehaviour { private func updateStoredAPNsToken(from endpointProfile: PinpointEndpointProfile) { do { guard let deviceToken = endpointProfile.deviceToken, - let apnsToken = Data(hexString: deviceToken) else { + let apnsToken = Data(hexString: deviceToken) + else { try keychain._remove(Constants.deviceTokenKey) return } @@ -152,18 +156,22 @@ actor EndpointClient: EndpointClientBehaviour { let channelType = getChannelType(from: endpointProfile) let effectiveDate = getEffectiveDateIso8601FractionalSeconds(from: endpointProfile) let optOut = getOptOut(from: endpointProfile) - let endpointRequest = PinpointClientTypes.EndpointRequest(address: endpointProfile.deviceToken, - attributes: endpointProfile.attributes, - channelType: channelType, - demographic: endpointProfile.demographic, - effectiveDate: effectiveDate, - location: endpointProfile.location, - metrics: endpointProfile.metrics, - optOut: optOut, - user: endpointProfile.user) - return UpdateEndpointInput(applicationId: endpointProfile.applicationId, - endpointId: endpointProfile.endpointId, - endpointRequest: endpointRequest) + let endpointRequest = PinpointClientTypes.EndpointRequest( + address: endpointProfile.deviceToken, + attributes: endpointProfile.attributes, + channelType: channelType, + demographic: endpointProfile.demographic, + effectiveDate: effectiveDate, + location: endpointProfile.location, + metrics: endpointProfile.metrics, + optOut: optOut, + user: endpointProfile.user + ) + return UpdateEndpointInput( + applicationId: endpointProfile.applicationId, + endpointId: endpointProfile.endpointId, + endpointRequest: endpointRequest + ) } nonisolated func convertToPublicEndpoint(_ endpointProfile: PinpointEndpointProfile) -> PinpointClientTypes.PublicEndpoint { @@ -179,22 +187,23 @@ actor EndpointClient: EndpointClientBehaviour { location: endpointProfile.location, metrics: endpointProfile.metrics, optOut: optOut, - user: endpointProfile.user) + user: endpointProfile.user + ) return publicEndpoint } - nonisolated private func getChannelType(from endpointProfile: PinpointEndpointProfile) -> PinpointClientTypes.ChannelType? { + private nonisolated func getChannelType(from endpointProfile: PinpointEndpointProfile) -> PinpointClientTypes.ChannelType? { if endpointProfile.deviceToken == nil { return nil } return endpointProfile.isDebug ? .apnsSandbox : .apns } - nonisolated private func getEffectiveDateIso8601FractionalSeconds(from endpointProfile: PinpointEndpointProfile) -> String { + private nonisolated func getEffectiveDateIso8601FractionalSeconds(from endpointProfile: PinpointEndpointProfile) -> String { endpointProfile.effectiveDate.asISO8601String } - nonisolated private func getOptOut(from endpointProfile: PinpointEndpointProfile) -> String? { + private nonisolated func getOptOut(from endpointProfile: PinpointEndpointProfile) -> String? { if endpointProfile.deviceToken == nil { return nil } @@ -245,8 +254,8 @@ extension EndpointClient: DefaultLogger { } extension EndpointClient { - struct Constants { - struct OptOut { + enum Constants { + enum OptOut { static let all = "ALL" static let none = "NONE" } @@ -257,20 +266,24 @@ extension EndpointClient { } extension PinpointClientTypes.EndpointDemographic { - struct Constants { + enum Constants { static let appleMake = "apple" static let unknown = "Unknown" } - init(device: EndpointInformation, - locale: String = Locale.autoupdatingCurrent.identifier, - timezone: String = TimeZone.current.identifier) { - self.init(appVersion: device.appVersion, - locale: locale, - make: Constants.appleMake, - model: device.model, - platform: device.platform.name, - platformVersion: device.platform.version, - timezone: timezone) + init( + device: EndpointInformation, + locale: String = Locale.autoupdatingCurrent.identifier, + timezone: String = TimeZone.current.identifier + ) { + self.init( + appVersion: device.appVersion, + locale: locale, + make: Constants.appleMake, + model: device.model, + platform: device.platform.name, + platformVersion: device.platform.version, + timezone: timezone + ) } } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/PinpointEndpointProfile.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/PinpointEndpointProfile.swift index c2d6cca523..9530f66267 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/PinpointEndpointProfile.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/PinpointEndpointProfile.swift @@ -25,15 +25,17 @@ public struct PinpointEndpointProfile: Codable, Equatable { private(set) var attributes: [String: [String]] = [:] private(set) var metrics: [String: Double] = [:] - init(applicationId: String, - endpointId: String, - deviceToken: DeviceToken? = nil, - effectiveDate: Date = Date(), - isDebug: Bool = false, - isOptOut: Bool = false, - location: PinpointClientTypes.EndpointLocation = .init(), - demographic: PinpointClientTypes.EndpointDemographic = .init(), - user: PinpointClientTypes.EndpointUser = .init()) { + init( + applicationId: String, + endpointId: String, + deviceToken: DeviceToken? = nil, + effectiveDate: Date = Date(), + isDebug: Bool = false, + isOptOut: Bool = false, + location: PinpointClientTypes.EndpointLocation = .init(), + demographic: PinpointClientTypes.EndpointDemographic = .init(), + user: PinpointClientTypes.EndpointUser = .init() + ) { self.applicationId = applicationId self.endpointId = endpointId self.deviceToken = deviceToken @@ -80,14 +82,14 @@ public struct PinpointEndpointProfile: Codable, Equatable { } private mutating func addCustomProperties(_ properties: [String: UserProfilePropertyValue]?) { - guard let properties = properties else { return } + guard let properties else { return } for (key, value) in properties { setCustomProperty(value, forKey: key) } } private mutating func addUserAttributes(_ attributes: [String: [String]]?) { - guard let attributes = attributes else { return } + guard let attributes else { return } let userAttributes = user.userAttributes ?? [:] user.userAttributes = userAttributes.merging( attributes, @@ -95,8 +97,10 @@ public struct PinpointEndpointProfile: Codable, Equatable { ) } - private mutating func setCustomProperty(_ value: UserProfilePropertyValue, - forKey key: String) { + private mutating func setCustomProperty( + _ value: UserProfilePropertyValue, + forKey key: String + ) { if let value = value as? String { attributes[key] = [value] } else if let values = value as? [String] { @@ -111,16 +115,16 @@ public struct PinpointEndpointProfile: Codable, Equatable { } } -extension Optional where Wrapped == PinpointEndpointProfile.DeviceToken { +extension PinpointEndpointProfile.DeviceToken? { var isNotEmpty: Bool { - guard let self = self else { return false } + guard let self else { return false } return !self.isEmpty } } extension PinpointEndpointProfile { - struct Constants { - struct AttributeKeys { + enum Constants { + enum AttributeKeys { static let email = "email" static let name = "name" static let plan = "plan" diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/CommonRunTimeError+isConnectivityError.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/CommonRunTimeError+isConnectivityError.swift index c3a3c3dd20..7e651b1f2d 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/CommonRunTimeError+isConnectivityError.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/CommonRunTimeError+isConnectivityError.swift @@ -6,8 +6,8 @@ // import Amplify -import AwsCIo import AwsCHttp +import AwsCIo import AwsCommonRuntimeKit import AWSPinpoint import ClientRuntime diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/Date+Formatting.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/Date+Formatting.swift index d1dfabbe31..3c31e11d38 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/Date+Formatting.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/Date+Formatting.swift @@ -29,7 +29,7 @@ extension Date { typealias Millisecond = Int64 var millisecondsSince1970: Millisecond { - return Int64(self.timeIntervalSince1970 * 1000) + return Int64(timeIntervalSince1970 * 1_000) } var asISO8601String: String { @@ -39,7 +39,7 @@ extension Date { extension Date.Millisecond { var asDate: Date { - return Date(timeIntervalSince1970: TimeInterval(self / 1000)) - .addingTimeInterval(TimeInterval(Double(self % 1000) / 1000 )) + return Date(timeIntervalSince1970: TimeInterval(self / 1_000)) + .addingTimeInterval(TimeInterval(Double(self % 1_000) / 1_000 )) } } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift index 1d7a9d7cd9..7322ededbb 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/PinpointClient+CredentialsProvider.swift @@ -6,8 +6,8 @@ // import AWSClientRuntime -import AWSPluginsCore import AWSPinpoint +import AWSPluginsCore @_spi(PluginHTTPClientEngine) import InternalAmplifyCredentials extension PinpointClient { diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/SDKModels+AmplifyStringConvertible.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/SDKModels+AmplifyStringConvertible.swift index 3421574914..ad66c348fc 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/SDKModels+AmplifyStringConvertible.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Extensions/SDKModels+AmplifyStringConvertible.swift @@ -17,7 +17,7 @@ extension PutEventsOutput: AmplifyStringConvertible { public func encode(to encoder: Encoder) throws { var encodeContainer = encoder.container(keyedBy: CodingKeys.self) - if let eventsResponse = self.eventsResponse { + if let eventsResponse { try encodeContainer.encode(eventsResponse, forKey: .eventsResponse) } } @@ -32,7 +32,7 @@ extension UpdateEndpointOutput: AmplifyStringConvertible { public func encode(to encoder: Encoder) throws { var encodeContainer = encoder.container(keyedBy: CodingKeys.self) - if let messageBody = self.messageBody { + if let messageBody { try encodeContainer.encode(messageBody, forKey: .messageBody) } } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/ActivityTracking/ActivityTracker.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/ActivityTracking/ActivityTracker.swift index d85da389d3..782c19ddbc 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/ActivityTracking/ActivityTracker.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/ActivityTracking/ActivityTracker.swift @@ -28,7 +28,7 @@ enum ApplicationState { case runningInBackground(isStale: Bool) case terminated - struct Resolver { + enum Resolver { static func resolve(currentState: ApplicationState, event: ActivityEvent) -> ApplicationState { if case .terminated = currentState { log.warn("Unexpected state transition. Received event \(event) in \(currentState) state.") @@ -122,25 +122,33 @@ class ActivityTracker: ActivityTrackerBehaviour { applicationWillTerminateNotification ] - init(backgroundTrackingTimeout: TimeInterval = .infinity, - stateMachine: StateMachine? = nil) { + init( + backgroundTrackingTimeout: TimeInterval = .infinity, + stateMachine: StateMachine? = nil + ) { self.backgroundTrackingTimeout = backgroundTrackingTimeout - self.stateMachine = stateMachine ?? StateMachine(initialState: .initializing, - resolver: ApplicationState.Resolver.resolve(currentState:event:)) + self.stateMachine = stateMachine ?? StateMachine( + initialState: .initializing, + resolver: ApplicationState.Resolver.resolve(currentState:event:) + ) for notification in ActivityTracker.notifications { - NotificationCenter.default.addObserver(self, - selector: #selector(handleApplicationStateChange), - name: notification, - object: nil) + NotificationCenter.default.addObserver( + self, + selector: #selector(handleApplicationStateChange), + name: notification, + object: nil + ) } } deinit { for notification in ActivityTracker.notifications { - NotificationCenter.default.removeObserver(self, - name: notification, - object: nil) + NotificationCenter.default.removeObserver( + self, + name: notification, + object: nil + ) } stateMachineSubscriberToken = nil } @@ -197,7 +205,7 @@ class ActivityTracker: ActivityTrackerBehaviour { #if canImport(UIKit) extension ActivityTracker { - struct Constants { + enum Constants { static let backgroundTask = "com.amazonaws.AWSPinpointSessionBackgroundTask" } } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/ActivityTracking/StateMachine.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/ActivityTracking/StateMachine.swift index 58bbe66676..32afd7d2c9 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/ActivityTracking/StateMachine.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/ActivityTracking/StateMachine.swift @@ -15,8 +15,10 @@ extension AnyCancellable: StateMachineSubscriberToken {} class StateMachine { typealias Reducer = (State, Event) -> State - private let queue = DispatchQueue(label: "com.amazonaws.Amplify.StateMachine<\(State.self), \(Event.self)>", - target: DispatchQueue.global()) + private let queue = DispatchQueue( + label: "com.amazonaws.Amplify.StateMachine<\(State.self), \(Event.self)>", + target: DispatchQueue.global() + ) private var reducer: Reducer #if canImport(Combine) diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/PinpointSession.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/PinpointSession.swift index 3a43fc8bce..5d5e435299 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/PinpointSession.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/PinpointSession.swift @@ -27,19 +27,25 @@ public struct PinpointSession: Codable { return stopTime } } - + private var state: State = .active - init(appId: String, - uniqueId: String) { - sessionId = Self.generateSessionId(appId: appId, - uniqueId: uniqueId) - startTime = Date() + init( + appId: String, + uniqueId: String + ) { + self.sessionId = Self.generateSessionId( + appId: appId, + uniqueId: uniqueId + ) + self.startTime = Date() } - init(sessionId: SessionId, - startTime: Date, - stopTime: Date?) { + init( + sessionId: SessionId, + startTime: Date, + stopTime: Date? + ) { self.sessionId = sessionId self.startTime = startTime if let stopTime { @@ -54,7 +60,7 @@ public struct PinpointSession: Codable { return false } - + var isStopped: Bool { if case .stopped = state { return true @@ -83,8 +89,10 @@ public struct PinpointSession: Codable { state = .active } - private static func generateSessionId(appId: String, - uniqueId: String) -> SessionId { + private static func generateSessionId( + appId: String, + uniqueId: String + ) -> SessionId { let now = Date() let dateFormatter = DateFormatter() dateFormatter.timeZone = TimeZone(abbreviation: Constants.Date.defaultTimezone) @@ -98,12 +106,16 @@ public struct PinpointSession: Codable { dateFormatter.dateFormat = Constants.Date.timeFormat let timestampTime = dateFormatter.string(from: now) - let appIdKey = appId.padding(toLength: Constants.maxAppKeyLength, - withPad: Constants.paddingChar, - startingAt: 0) - let uniqueIdKey = uniqueId.padding(toLength: Constants.maxUniqueIdLength, - withPad: Constants.paddingChar, - startingAt: 0) + let appIdKey = appId.padding( + toLength: Constants.maxAppKeyLength, + withPad: Constants.paddingChar, + startingAt: 0 + ) + let uniqueIdKey = uniqueId.padding( + toLength: Constants.maxUniqueIdLength, + withPad: Constants.paddingChar, + startingAt: 0 + ) // Create Session ID formatted as - - -