From 4b9d9c9e004c7d832910dfa420ecb153ec822bc0 Mon Sep 17 00:00:00 2001 From: Ian Saultz <52051793+atierian@users.noreply.github.com> Date: Tue, 9 Jan 2024 10:09:56 -0500 Subject: [PATCH 1/8] chore: clarify wording in closed issue visibility comment (#3463) --- .github/workflows/issue_closed.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/issue_closed.yml b/.github/workflows/issue_closed.yml index 929ad0ebf2..9d1e630e1e 100644 --- a/.github/workflows/issue_closed.yml +++ b/.github/workflows/issue_closed.yml @@ -30,5 +30,5 @@ jobs: message: | ### ⚠️COMMENT VISIBILITY WARNING⚠️ Comments on closed issues are hard for our team to see. - If you need more assistance, please either tag a team member or open a new issue that references this one. + If you need more assistance, please open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so. From c11781f5ab5773d0fe79aeacb4b8a716d87b378a Mon Sep 17 00:00:00 2001 From: Sebastian Villena <97059974+ruisebas@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:27:16 -0500 Subject: [PATCH 2/8] fix(Analytics): Making PinpointEndpointProfile a struct. (#3457) --- ...npointAnalyticsPlugin+ClientBehavior.swift | 2 +- ...ntAnalyticsPluginClientBehaviorTests.swift | 4 +- ...pointAnalyticsPluginIntegrationTests.swift | 2 +- .../Endpoint/EndpointClient.swift | 2 + .../Endpoint/PinpointEndpointProfile.swift | 14 ++-- .../EndpointClientTests.swift | 10 +-- ...hNotificationsPlugin+ClientBehaviour.swift | 4 +- ...ificationsPluginClientBehaviourTests.swift | 78 ++++++++++--------- .../Mocks/MockAWSPinpoint.swift | 2 +- 9 files changed, 64 insertions(+), 54 deletions(-) diff --git a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+ClientBehavior.swift b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+ClientBehavior.swift index ddc52e2657..c2e168e217 100644 --- a/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+ClientBehavior.swift +++ b/AmplifyPlugins/Analytics/Sources/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+ClientBehavior.swift @@ -18,7 +18,7 @@ extension AWSPinpointAnalyticsPlugin { } Task { - let currentEndpointProfile = await pinpoint.currentEndpointProfile() + var currentEndpointProfile = await pinpoint.currentEndpointProfile() currentEndpointProfile.addUserId(userId) if let userProfile = userProfile { currentEndpointProfile.addUserProfile(userProfile) diff --git a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginClientBehaviorTests.swift b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginClientBehaviorTests.swift index 9a0529e260..0c7bad83fb 100644 --- a/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginClientBehaviorTests.swift +++ b/AmplifyPlugins/Analytics/Tests/AWSPinpointAnalyticsPluginUnitTests/AWSPinpointAnalyticsPluginClientBehaviorTests.swift @@ -57,7 +57,7 @@ class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginT plan: testPlan, location: testLocation, properties: testProperties) - let expectedEndpointProfile = PinpointEndpointProfile(applicationId: "appId", + var expectedEndpointProfile = PinpointEndpointProfile(applicationId: "appId", endpointId: "endpointId") expectedEndpointProfile.addUserId(testIdentityId) expectedEndpointProfile.addUserProfile(userProfile) @@ -108,7 +108,7 @@ class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginT plan: testPlan, location: testLocation, properties: testProperties) - let expectedEndpointProfile = PinpointEndpointProfile(applicationId: "appId", + var expectedEndpointProfile = PinpointEndpointProfile(applicationId: "appId", endpointId: "endpointId") expectedEndpointProfile.addUserId(testIdentityId) expectedEndpointProfile.addUserProfile(userProfile) diff --git a/AmplifyPlugins/Analytics/Tests/AnalyticsHostApp/AWSPinpointAnalyticsPluginIntegrationTests/AWSPinpointAnalyticsPluginIntegrationTests.swift b/AmplifyPlugins/Analytics/Tests/AnalyticsHostApp/AWSPinpointAnalyticsPluginIntegrationTests/AWSPinpointAnalyticsPluginIntegrationTests.swift index 81bf50c52e..acf152fdbc 100644 --- a/AmplifyPlugins/Analytics/Tests/AnalyticsHostApp/AWSPinpointAnalyticsPluginIntegrationTests/AWSPinpointAnalyticsPluginIntegrationTests.swift +++ b/AmplifyPlugins/Analytics/Tests/AnalyticsHostApp/AWSPinpointAnalyticsPluginIntegrationTests/AWSPinpointAnalyticsPluginIntegrationTests.swift @@ -75,7 +75,7 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase { // Remove userId from the current endpoint let endpointClient = endpointClient() - let currentProfile = await endpointClient.currentEndpointProfile() + var currentProfile = await endpointClient.currentEndpointProfile() currentProfile.addUserId("") try await endpointClient.updateEndpointProfile(with: currentProfile) } diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointClient.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointClient.swift index ac034e3653..f2203a7d0c 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointClient.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/EndpointClient.swift @@ -94,6 +94,7 @@ actor EndpointClient: EndpointClientBehaviour { } private func configure(endpointProfile: PinpointEndpointProfile) async -> PinpointEndpointProfile { + var endpointProfile = endpointProfile var deviceToken: PinpointEndpointProfile.DeviceToken? if let tokenData = Self.getStoredData(from: keychain, forKey: Constants.deviceTokenKey, fallbackTo: userDefaults) { deviceToken = tokenData.asHexString() @@ -109,6 +110,7 @@ actor EndpointClient: EndpointClientBehaviour { } private func updateEndpoint(with endpointProfile: PinpointEndpointProfile) async throws { + var endpointProfile = endpointProfile endpointProfile.effectiveDate = Date() let input = createUpdateInput(from: endpointProfile) log.verbose("UpdateEndpointInput: \(input)") diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/PinpointEndpointProfile.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/PinpointEndpointProfile.swift index 45ba969c2a..c2d6cca523 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/PinpointEndpointProfile.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Endpoint/PinpointEndpointProfile.swift @@ -10,7 +10,7 @@ import AWSPinpoint import Foundation @_spi(InternalAWSPinpoint) -public class PinpointEndpointProfile: Codable { +public struct PinpointEndpointProfile: Codable, Equatable { typealias DeviceToken = String var applicationId: String @@ -45,11 +45,11 @@ public class PinpointEndpointProfile: Codable { self.user = user } - public func addUserId(_ userId: String) { + public mutating func addUserId(_ userId: String) { user.userId = userId } - public func addUserProfile(_ userProfile: UserProfile) { + public mutating func addUserProfile(_ userProfile: UserProfile) { if let email = userProfile.email { setCustomProperty(email, forKey: Constants.AttributeKeys.email) } @@ -75,18 +75,18 @@ public class PinpointEndpointProfile: Codable { } } - public func setAPNsToken(_ apnsToken: Data) { + public mutating func setAPNsToken(_ apnsToken: Data) { deviceToken = apnsToken.asHexString() } - private func addCustomProperties(_ properties: [String: UserProfilePropertyValue]?) { + private mutating func addCustomProperties(_ properties: [String: UserProfilePropertyValue]?) { guard let properties = properties else { return } for (key, value) in properties { setCustomProperty(value, forKey: key) } } - private func addUserAttributes(_ attributes: [String: [String]]?) { + private mutating func addUserAttributes(_ attributes: [String: [String]]?) { guard let attributes = attributes else { return } let userAttributes = user.userAttributes ?? [:] user.userAttributes = userAttributes.merging( @@ -95,7 +95,7 @@ public class PinpointEndpointProfile: Codable { ) } - private func setCustomProperty(_ value: UserProfilePropertyValue, + private mutating func setCustomProperty(_ value: UserProfilePropertyValue, forKey key: String) { if let value = value as? String { attributes[key] = [value] diff --git a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/EndpointClientTests.swift b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/EndpointClientTests.swift index 5931cc7154..d1b42f5dfd 100644 --- a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/EndpointClientTests.swift +++ b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/EndpointClientTests.swift @@ -75,7 +75,7 @@ class EndpointClientTests: XCTestCase { XCTAssertNotNil(keychain.dataValues[EndpointClient.Constants.endpointProfileKey]) XCTAssertNotNil(keychain.dataValues[EndpointClient.Constants.deviceTokenKey]) XCTAssertEqual(archiver.decodeCount, 1) - XCTAssertTrue(endpointProfile === storedEndpointProfile, "Expected stored PinpointEndpointProfile object") + XCTAssertNotEqual(endpointProfile, storedEndpointProfile, "Expected updated PinpointEndpointProfile object") XCTAssertEqual(endpointProfile.applicationId, currentApplicationId) XCTAssertEqual(endpointProfile.endpointId, currentEndpointId) XCTAssertEqual(endpointProfile.deviceToken, newToken.asHexString()) @@ -104,7 +104,7 @@ class EndpointClientTests: XCTestCase { XCTAssertEqual(keychain.dataForKeyCountMap[EndpointClient.Constants.endpointProfileKey], 1) XCTAssertEqual(keychain.dataForKeyCountMap[EndpointClient.Constants.deviceTokenKey], 1) XCTAssertEqual(archiver.decodeCount, 0) - XCTAssertFalse(endpointProfile === storedEndpointProfile, "Expected new PinpointEndpointProfile object") + XCTAssertNotEqual(endpointProfile, storedEndpointProfile, "Expected new PinpointEndpointProfile object") XCTAssertEqual(endpointProfile.applicationId, currentApplicationId) XCTAssertEqual(endpointProfile.endpointId, currentEndpointId) XCTAssertEqual(endpointProfile.deviceToken, newToken?.asHexString()) @@ -128,7 +128,7 @@ class EndpointClientTests: XCTestCase { func testUpdateEndpointProfile_withAPNsToken_withoutStoredToken_shouldSaveToken() async { keychain.resetCounters() - let endpoint = PinpointEndpointProfile(applicationId: "applicationId", + var endpoint = PinpointEndpointProfile(applicationId: "applicationId", endpointId: "endpointId") endpoint.setAPNsToken(Data(hexString: newTokenHex)!) try? await endpointClient.updateEndpointProfile(with: endpoint) @@ -142,7 +142,7 @@ class EndpointClientTests: XCTestCase { storeToken("oldToken") keychain.resetCounters() - let endpoint = PinpointEndpointProfile(applicationId: "applicationId", + var endpoint = PinpointEndpointProfile(applicationId: "applicationId", endpointId: "endpointId") endpoint.setAPNsToken(Data(hexString: newTokenHex)!) try? await endpointClient.updateEndpointProfile(with: endpoint) @@ -156,7 +156,7 @@ class EndpointClientTests: XCTestCase { storeToken(newTokenHex) keychain.resetCounters() - let endpoint = PinpointEndpointProfile(applicationId: "applicationId", + var endpoint = PinpointEndpointProfile(applicationId: "applicationId", endpointId: "endpointId") endpoint.setAPNsToken(Data(hexString: newTokenHex)!) try? await endpointClient.updateEndpointProfile(with: endpoint) diff --git a/AmplifyPlugins/Notifications/Push/Sources/AWSPinpointPushNotificationsPlugin/AWSPinpointPushNotificationsPlugin+ClientBehaviour.swift b/AmplifyPlugins/Notifications/Push/Sources/AWSPinpointPushNotificationsPlugin/AWSPinpointPushNotificationsPlugin+ClientBehaviour.swift index f85e79be0b..92435992b7 100644 --- a/AmplifyPlugins/Notifications/Push/Sources/AWSPinpointPushNotificationsPlugin/AWSPinpointPushNotificationsPlugin+ClientBehaviour.swift +++ b/AmplifyPlugins/Notifications/Push/Sources/AWSPinpointPushNotificationsPlugin/AWSPinpointPushNotificationsPlugin+ClientBehaviour.swift @@ -20,7 +20,7 @@ import AppKit extension AWSPinpointPushNotificationsPlugin { public func identifyUser(userId: String, userProfile: UserProfile?) async throws { - let currentEndpointProfile = await pinpoint.currentEndpointProfile() + var currentEndpointProfile = await pinpoint.currentEndpointProfile() currentEndpointProfile.addUserId(userId) if let userProfile = userProfile { currentEndpointProfile.addUserProfile(userProfile) @@ -30,7 +30,7 @@ extension AWSPinpointPushNotificationsPlugin { } public func registerDevice(apnsToken: Data) async throws { - let currentEndpointProfile = await pinpoint.currentEndpointProfile() + var currentEndpointProfile = await pinpoint.currentEndpointProfile() currentEndpointProfile.setAPNsToken(apnsToken) do { try await pinpoint.updateEndpoint(with: currentEndpointProfile, diff --git a/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/AWSPinpointPushNotificationsPluginClientBehaviourTests.swift b/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/AWSPinpointPushNotificationsPluginClientBehaviourTests.swift index c1b57e7396..5a0925bf8c 100644 --- a/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/AWSPinpointPushNotificationsPluginClientBehaviourTests.swift +++ b/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/AWSPinpointPushNotificationsPluginClientBehaviourTests.swift @@ -25,7 +25,8 @@ class AWSPinpointPushNotificationsPluginClientBehaviourTests: AWSPinpointPushNot XCTAssertEqual(mockPinpoint.currentEndpointProfileCount, 1) XCTAssertEqual(mockPinpoint.updateEndpointCount, 1) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.user.userId, "newUserId") + let updatedEndpoint = try XCTUnwrap(mockPinpoint.updatedPinpointEndpointProfile) + XCTAssertEqual(updatedEndpoint.user.userId, "newUserId") } func testIdentifyUser_withProfile_shouldUpdateUserProfile() async throws { @@ -38,13 +39,14 @@ class AWSPinpointPushNotificationsPluginClientBehaviourTests: AWSPinpointPushNot XCTAssertEqual(mockPinpoint.currentEndpointProfileCount, 1) XCTAssertEqual(mockPinpoint.updateEndpointCount, 1) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.user.userId, "newUserId") - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.attributes.count, 3) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.attributes["name"]?.first, "Name") - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.attributes["email"]?.first, "Email") - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.attributes["plan"]?.first, "Plan") - XCTAssertTrue(mockPinpoint.mockedPinpointEndpointProfile.metrics.isEmpty) - XCTAssertNil(mockPinpoint.mockedPinpointEndpointProfile.user.userAttributes) + let updatedEndpoint = try XCTUnwrap(mockPinpoint.updatedPinpointEndpointProfile) + XCTAssertEqual(updatedEndpoint.user.userId, "newUserId") + XCTAssertEqual(updatedEndpoint.attributes.count, 3) + XCTAssertEqual(updatedEndpoint.attributes["name"]?.first, "Name") + XCTAssertEqual(updatedEndpoint.attributes["email"]?.first, "Email") + XCTAssertEqual(updatedEndpoint.attributes["plan"]?.first, "Plan") + XCTAssertTrue(updatedEndpoint.metrics.isEmpty) + XCTAssertNil(updatedEndpoint.user.userAttributes) } func testIdentifyUser_withAnalyticsProfile_shouldUpdateUserProfile() async throws { @@ -60,14 +62,15 @@ class AWSPinpointPushNotificationsPluginClientBehaviourTests: AWSPinpointPushNot XCTAssertEqual(mockPinpoint.currentEndpointProfileCount, 1) XCTAssertEqual(mockPinpoint.updateEndpointCount, 1) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.user.userId, "newUserId") - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.attributes.count, 2) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.attributes["attribute"]?.first, "string") - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.attributes["boolAttribute"]?.first, "true") - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.metrics["metric"], 2.0) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.metrics["intMetric"], 1) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.metrics.count, 2) - XCTAssertNil(mockPinpoint.mockedPinpointEndpointProfile.user.userAttributes) + let updatedEndpoint = try XCTUnwrap(mockPinpoint.updatedPinpointEndpointProfile) + XCTAssertEqual(updatedEndpoint.user.userId, "newUserId") + XCTAssertEqual(updatedEndpoint.attributes.count, 2) + XCTAssertEqual(updatedEndpoint.attributes["attribute"]?.first, "string") + XCTAssertEqual(updatedEndpoint.attributes["boolAttribute"]?.first, "true") + XCTAssertEqual(updatedEndpoint.metrics["metric"], 2.0) + XCTAssertEqual(updatedEndpoint.metrics["intMetric"], 1) + XCTAssertEqual(updatedEndpoint.metrics.count, 2) + XCTAssertNil(updatedEndpoint.user.userAttributes) } func testIdentifyUser_withBasicProfile_shouldUpdateUserProfile() async throws { @@ -83,14 +86,15 @@ class AWSPinpointPushNotificationsPluginClientBehaviourTests: AWSPinpointPushNot XCTAssertEqual(mockPinpoint.currentEndpointProfileCount, 1) XCTAssertEqual(mockPinpoint.updateEndpointCount, 1) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.user.userId, "newUserId") - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.attributes.count, 2) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.attributes["attribute"]?.first, "string") - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.attributes["boolAttribute"]?.first, "true") - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.metrics["metric"], 2.0) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.metrics["intMetric"], 1) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.metrics.count, 2) - XCTAssertNil(mockPinpoint.mockedPinpointEndpointProfile.user.userAttributes) + let updatedEndpoint = try XCTUnwrap(mockPinpoint.updatedPinpointEndpointProfile) + XCTAssertEqual(updatedEndpoint.user.userId, "newUserId") + XCTAssertEqual(updatedEndpoint.attributes.count, 2) + XCTAssertEqual(updatedEndpoint.attributes["attribute"]?.first, "string") + XCTAssertEqual(updatedEndpoint.attributes["boolAttribute"]?.first, "true") + XCTAssertEqual(updatedEndpoint.metrics["metric"], 2.0) + XCTAssertEqual(updatedEndpoint.metrics["intMetric"], 1) + XCTAssertEqual(updatedEndpoint.metrics.count, 2) + XCTAssertNil(updatedEndpoint.user.userAttributes) } func testIdentifyUser_withPinpointProfile_shouldUpdateUserProfile() async throws { @@ -110,26 +114,29 @@ class AWSPinpointPushNotificationsPluginClientBehaviourTests: AWSPinpointPushNot XCTAssertEqual(mockPinpoint.currentEndpointProfileCount, 1) XCTAssertEqual(mockPinpoint.updateEndpointCount, 1) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.attributes["attribute"]?.first, "string") - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.attributes["attributes"]?.count, 2) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.attributes["attributes"]?.first, "string") - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.attributes["boolAttribute"]?.first, "true") - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.metrics["metric"], 2) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.metrics["intMetric"], 1) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.user.userId, "newUserId") - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.user.userAttributes?["roles"]?.count, 2) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.user.userAttributes?["roles"]?.first, "Test") + let updatedEndpoint = try XCTUnwrap(mockPinpoint.updatedPinpointEndpointProfile) + XCTAssertEqual(updatedEndpoint.attributes["attribute"]?.first, "string") + XCTAssertEqual(updatedEndpoint.attributes["attributes"]?.count, 2) + XCTAssertEqual(updatedEndpoint.attributes["attributes"]?.first, "string") + XCTAssertEqual(updatedEndpoint.attributes["boolAttribute"]?.first, "true") + XCTAssertEqual(updatedEndpoint.metrics["metric"], 2) + XCTAssertEqual(updatedEndpoint.metrics["intMetric"], 1) + XCTAssertEqual(updatedEndpoint.user.userId, "newUserId") + XCTAssertEqual(updatedEndpoint.user.userAttributes?["roles"]?.count, 2) + XCTAssertEqual(updatedEndpoint.user.userAttributes?["roles"]?.first, "Test") } func testIdentifyUser_withPinpointProfileOptedOutOfMessages_shouldUpdateUserProfileOptOutValue() async throws { try await plugin.identifyUser(userId: "newUserId", userProfile: nil) - let updatedEndpoint = try XCTUnwrap(mockPinpoint.updatedPinpointEndpointProfile) + var updatedEndpoint = try XCTUnwrap(mockPinpoint.updatedPinpointEndpointProfile) XCTAssertFalse(updatedEndpoint.isOptOut) try await plugin.identifyUser(userId: "newUserId", userProfile: PinpointUserProfile(optedOutOfMessages: true)) + updatedEndpoint = try XCTUnwrap(mockPinpoint.updatedPinpointEndpointProfile) XCTAssertTrue(updatedEndpoint.isOptOut) try await plugin.identifyUser(userId: "newUserId", userProfile: PinpointUserProfile(name: "User")) + updatedEndpoint = try XCTUnwrap(mockPinpoint.updatedPinpointEndpointProfile) XCTAssertTrue(updatedEndpoint.isOptOut) } @@ -140,7 +147,8 @@ class AWSPinpointPushNotificationsPluginClientBehaviourTests: AWSPinpointPushNot XCTAssertEqual(mockPinpoint.currentEndpointProfileCount, 1) XCTAssertEqual(mockPinpoint.updateEndpointCount, 1) - XCTAssertEqual(mockPinpoint.mockedPinpointEndpointProfile.deviceToken, apnsToken.asHexString()) + let updatedEndpoint = try XCTUnwrap(mockPinpoint.updatedPinpointEndpointProfile) + XCTAssertEqual(updatedEndpoint.deviceToken, apnsToken.asHexString()) } // MARK: - Record Notification received tests diff --git a/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/Mocks/MockAWSPinpoint.swift b/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/Mocks/MockAWSPinpoint.swift index e13f274932..4bac908f59 100644 --- a/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/Mocks/MockAWSPinpoint.swift +++ b/AmplifyPlugins/Notifications/Push/Tests/AWSPinpointPushNotificationsPluginUnitTests/Mocks/MockAWSPinpoint.swift @@ -43,7 +43,7 @@ class MockAWSPinpoint: AWSPinpointBehavior { ) func currentEndpointProfile() async -> PinpointEndpointProfile { currentEndpointProfileCount += 1 - return mockedPinpointEndpointProfile + return updatedPinpointEndpointProfile ?? mockedPinpointEndpointProfile } var updateEndpointCount = 0 From 0d8f12a0ae3c15e750457d28d8b86ad379f385f4 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Tue, 9 Jan 2024 14:22:39 -0800 Subject: [PATCH 3/8] ci: add action workflow for ensuring minimum sdk version support (#3462) * ci: add action workflow for ensuring minimum xcode version support * resolve comment * fix typo --- .../get_platform_parameters/action.yml | 8 ++- .github/workflows/build_amplify_swift.yml | 30 ++++++++--- ...uild_minimum_supported_swift_platforms.yml | 50 +++++++++++++++++++ 3 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/build_minimum_supported_swift_platforms.yml diff --git a/.github/composite_actions/get_platform_parameters/action.yml b/.github/composite_actions/get_platform_parameters/action.yml index d007eca053..0fc0945e11 100644 --- a/.github/composite_actions/get_platform_parameters/action.yml +++ b/.github/composite_actions/get_platform_parameters/action.yml @@ -28,11 +28,17 @@ runs: XCODE_VERSION=${{ inputs.xcode_version }} case $XCODE_VERSION in - 14.3|15.0) ;; + 14.0.1|14.3|15.0) ;; *) echo "Unsupported Xcode version: $XCODE_VERSION"; exit 1 ;; esac DESTINATION_MAPPING='{ + "14.0.1": { + "iOS": "platform=iOS Simulator,name=iPhone 14,OS=16.0", + "tvOS": "platform=tvOS Simulator,name=Apple TV 4K (2nd generation),OS=16.0", + "watchOS": "platform=watchOS Simulator,name=Apple Watch Series 8 (45mm),OS=9.0", + "macOS": "platform=macOS,arch=x86_64" + }, "14.3": { "iOS": "platform=iOS Simulator,name=iPhone 14,OS=16.4", "tvOS": "platform=tvOS Simulator,name=Apple TV 4K (3rd generation),OS=16.4", diff --git a/.github/workflows/build_amplify_swift.yml b/.github/workflows/build_amplify_swift.yml index bfefc79014..d2975c4a82 100644 --- a/.github/workflows/build_amplify_swift.yml +++ b/.github/workflows/build_amplify_swift.yml @@ -6,6 +6,18 @@ on: type: string required: true + xcode-version: + type: string + default: '14.3' + + os-runner: + type: string + default: 'macos-13' + + cacheable: + type: boolean + default: true + permissions: contents: read actions: write @@ -13,7 +25,7 @@ permissions: jobs: build-amplify-swift: name: Build Amplify-Package | ${{ inputs.platform }} - runs-on: macos-13 + runs-on: ${{ inputs.os-runner }} steps: - name: Checkout repository uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 @@ -25,10 +37,11 @@ jobs: uses: ./.github/composite_actions/get_platform_parameters with: platform: ${{ inputs.platform }} - xcode_version: '14.3' - + xcode_version: ${{ inputs.xcode-version }} + - name: Attempt to use the dependencies cache id: dependencies-cache + if: inputs.cacheable timeout-minutes: 4 continue-on-error: true uses: actions/cache/restore@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 @@ -40,6 +53,7 @@ jobs: - name: Attempt to restore the build cache from main id: build-cache + if: inputs.cacheable timeout-minutes: 4 continue-on-error: true uses: actions/cache/restore@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 @@ -55,20 +69,20 @@ jobs: scheme: Amplify-Package destination: ${{ steps.platform.outputs.destination }} sdk: ${{ steps.platform.outputs.sdk }} - xcode_path: /Applications/Xcode_14.3.app + xcode_path: /Applications/Xcode_${{ inputs.xcode-version }}.app cloned_source_packages_path: ~/Library/Developer/Xcode/DerivedData/Amplify derived_data_path: ${{ github.workspace }}/Build disable_package_resolution: ${{ steps.dependencies-cache.outputs.cache-hit }} - name: Save the dependencies cache in main - if: steps.dependencies-cache.outputs.cache-hit != 'true' && github.ref_name == 'main' + if: inputs.cacheable && steps.dependencies-cache.outputs.cache-hit != 'true' && github.ref_name == 'main' uses: actions/cache/save@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 with: path: ~/Library/Developer/Xcode/DerivedData/Amplify key: ${{ steps.dependencies-cache.outputs.cache-primary-key }} - + - name: Delete the old build cache - if: steps.build-cache.outputs.cache-hit && github.ref_name == 'main' + if: inputs.cacheable && steps.build-cache.outputs.cache-hit && github.ref_name == 'main' env: GH_TOKEN: ${{ github.token }} continue-on-error: true @@ -76,7 +90,7 @@ jobs: gh cache delete ${{ steps.build-cache.outputs.cache-primary-key }} - name: Save the build cache - if: github.ref_name == 'main' + if: inputs.cacheable && github.ref_name == 'main' uses: actions/cache/save@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 with: path: ${{ github.workspace }}/Build diff --git a/.github/workflows/build_minimum_supported_swift_platforms.yml b/.github/workflows/build_minimum_supported_swift_platforms.yml new file mode 100644 index 0000000000..a86f8b99b0 --- /dev/null +++ b/.github/workflows/build_minimum_supported_swift_platforms.yml @@ -0,0 +1,50 @@ +name: Build with Minimum Supported Xcode Versions +on: + workflow_dispatch: + push: + branches: + - main + +permissions: + contents: read + actions: write + +jobs: + build-amplify-with-minimum-supported-xcode: + name: Build Amplify Swift for ${{ matrix.platform }} + strategy: + fail-fast: false + matrix: + include: + - os-runner: macos-12 + xcode-version: 14.0.1 + platform: iOS + + - os-runner: macos-12 + xcode-version: 14.0.1 + platform: macOS + + - os-runner: macos-12 + xcode-version: 14.0.1 + platform: tvOS + + - os-runner: macos-12 + xcode-version: 14.0.1 + platform: watchOS + + uses: ./.github/workflows/build_amplify_swift.yml + with: + os-runner: ${{ matrix.os-runner }} + xcode-version: ${{ matrix.xcode-version }} + platform: ${{ matrix.platform }} + cacheable: false + + confirm-pass: + runs-on: ubuntu-latest + name: Confirm Passing Build Steps + if: ${{ !cancelled() }} + needs: [ build-amplify-with-minimum-supported-xcode ] + env: + EXIT_CODE: ${{ contains(needs.*.result, 'failure') && 1 || 0 }} + steps: + - run: exit $EXIT_CODE From 003e1f32d8f679efdeaabbb9d23b06d6502fdcff Mon Sep 17 00:00:00 2001 From: Sebastian Villena <97059974+ruisebas@users.noreply.github.com> Date: Wed, 10 Jan 2024 16:52:27 -0500 Subject: [PATCH 4/8] fix(Analytics): Updating session stop time for cached events. (#3405) --- .../Analytics/AnalyticsClient.swift | 5 + .../Analytics/EventRecorder.swift | 8 ++ .../AnalyticsEventSQLStorage.swift | 16 +++ .../LocalStorage/AnalyticsEventStorage.swift | 4 + .../PinpointEvent+PinpointClientTypes.swift | 56 ++++----- .../Session/PinpointSession.swift | 58 ++++++--- .../Session/SessionClient.swift | 111 ++++++++++-------- .../Mocks/MockAnalyticsClient.swift | 5 + .../Mocks/MockAnalyticsEventStorage.swift | 5 + .../Mocks/MockEventRecorder.swift | 5 + .../SessionClientTests.swift | 53 +-------- 11 files changed, 187 insertions(+), 139 deletions(-) diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/AnalyticsClient.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/AnalyticsClient.swift index 51fb69a888..c7db089487 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/AnalyticsClient.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/AnalyticsClient.swift @@ -31,6 +31,7 @@ public protocol AnalyticsClientBehaviour: Actor { onSubmit: SubmitResult?) @discardableResult func submitEvents() async throws -> [PinpointEvent] + func update(_ session: PinpointSession) async throws nonisolated func createAppleMonetizationEvent(with transaction: SKPaymentTransaction, with product: SKProduct) -> PinpointEvent @@ -262,6 +263,10 @@ 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?) { diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/EventRecorder.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/EventRecorder.swift index 0beb869b77..0291d2f412 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/EventRecorder.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/EventRecorder.swift @@ -28,6 +28,10 @@ protocol AnalyticsEventRecording: Actor { 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 /// Submit all locally stored events /// - Returns: A collection of events submitted to Pinpoint @@ -78,6 +82,10 @@ actor EventRecorder: AnalyticsEventRecording { setAttributes: attributes) } + func update(_ session: PinpointSession) throws { + try storage.updateSession(session) + } + /// Submit all locally stored events in batches. If a previous submission is in progress, it waits until it's completed before proceeding. /// When the submission for an event is accepted, the event is removed from local storage /// When the submission for an event is rejected, the event retry count is incremented in the local storage. Events that exceed the maximum retry count (3) are purged. diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventSQLStorage.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventSQLStorage.swift index 1c7363627c..c0597a6e98 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventSQLStorage.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventSQLStorage.swift @@ -115,6 +115,22 @@ class AnalyticsEventSQLStorage: AnalyticsEventStorage { sessionId, eventType]) } + + func updateSession(_ session: PinpointSession) throws { + let updateStatement = """ + UPDATE Event + SET sessionStartTime = ?, sessionStopTime = ? + WHERE sessionId = ? + """ + _ = try dbAdapter.executeQuery( + updateStatement, + [ + session.startTime.asISO8601String, + session.stopTime?.asISO8601String, + session.sessionId + ] + ) + } /// Get the oldest event with limit /// - Parameter limit: The number of query result to limit diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventStorage.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventStorage.swift index e74a7e35b0..d5aea17167 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventStorage.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/LocalStorage/AnalyticsEventStorage.swift @@ -29,6 +29,10 @@ protocol AnalyticsEventStorage { 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 /// Get the oldest event with limit /// - Parameter limit: The number of query result to limit diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/PinpointEvent+PinpointClientTypes.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/PinpointEvent+PinpointClientTypes.swift index a916d7dc2b..b198b5e45d 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/PinpointEvent+PinpointClientTypes.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Analytics/PinpointEvent+PinpointClientTypes.swift @@ -10,31 +10,36 @@ import AWSPluginsCore import Foundation extension PinpointEvent { - var clientTypeSession: PinpointClientTypes.Session? { - #if os(watchOS) - // 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 - if let duration = session.duration, duration > Int.max { - return nil + private var clientTypeSession: PinpointClientTypes.Session? { + var sessionDuration: Int? = nil + 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 + guard let intDuration = Int(exactly: duration) else { return nil } + sessionDuration = intDuration } - #endif - return PinpointClientTypes.Session(duration: Int(session.duration), - id: session.sessionId, - startTimestamp: session.startTime.asISO8601String, - stopTimestamp: session.stopTime?.asISO8601String) + + return .init( + duration: sessionDuration, + id: session.sessionId, + startTimestamp: session.startTime.asISO8601String, + stopTimestamp: session.stopTime?.asISO8601String + ) } var clientTypeEvent: PinpointClientTypes.Event { - return PinpointClientTypes.Event(appPackageName: Bundle.main.appPackageName, - appTitle: Bundle.main.appName, - appVersionCode: Bundle.main.appVersion, - attributes: attributes, - clientSdkVersion: AmplifyAWSServiceConfiguration.amplifyVersion, - eventType: eventType, - metrics: metrics, - sdkName: AmplifyAWSServiceConfiguration.platformName, - session: clientTypeSession, - timestamp: eventDate.asISO8601String) + return .init( + appPackageName: Bundle.main.appPackageName, + appTitle: Bundle.main.appName, + appVersionCode: Bundle.main.appVersion, + attributes: attributes, + clientSdkVersion: AmplifyAWSServiceConfiguration.amplifyVersion, + eventType: eventType, + metrics: metrics, + sdkName: AmplifyAWSServiceConfiguration.platformName, + session: clientTypeSession, + timestamp: eventDate.asISO8601String + ) } } @@ -55,12 +60,3 @@ extension Bundle { object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "" } } - -private extension Int { - init?(_ value: Int64?) { - guard let value = value else { - return nil - } - self.init(value) - } -} diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/PinpointSession.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/PinpointSession.swift index 819d76bc43..3a43fc8bce 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/PinpointSession.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/PinpointSession.swift @@ -8,19 +8,33 @@ import Foundation @_spi(InternalAWSPinpoint) -public class PinpointSession: Codable { +public struct PinpointSession: Codable { + private enum State: Codable { + case active + case paused(date: Date) + case stopped(date: Date) + } typealias SessionId = String let sessionId: SessionId let startTime: Date - private(set) var stopTime: Date? + var stopTime: Date? { + switch state { + case .active: + return nil + case .paused(let stopTime), + .stopped(let stopTime): + return stopTime + } + } + + private var state: State = .active init(appId: String, uniqueId: String) { sessionId = Self.generateSessionId(appId: appId, uniqueId: uniqueId) startTime = Date() - stopTime = nil } init(sessionId: SessionId, @@ -28,33 +42,45 @@ public class PinpointSession: Codable { stopTime: Date?) { self.sessionId = sessionId self.startTime = startTime - self.stopTime = stopTime + if let stopTime { + self.state = .stopped(date: stopTime) + } } var isPaused: Bool { - return stopTime != nil + if case .paused = state { + return true + } + + return false + } + + var isStopped: Bool { + if case .stopped = state { + return true + } + + return false } var duration: Date.Millisecond? { /// According to Pinpoint's documentation, `duration` is only required if `stopTime` is not nil. - guard let endTime = stopTime else { - return nil - } - return endTime.millisecondsSince1970 - startTime.millisecondsSince1970 + guard let stopTime else { return nil } + return stopTime.millisecondsSince1970 - startTime.millisecondsSince1970 } - func stop() { - guard stopTime == nil else { return } - stopTime = Date() + mutating func stop() { + guard !isStopped else { return } + state = .stopped(date: stopTime ?? Date()) } - func pause() { + mutating func pause() { guard !isPaused else { return } - stopTime = Date() + state = .paused(date: Date()) } - func resume() { - stopTime = nil + mutating func resume() { + state = .active } private static func generateSessionId(appId: String, diff --git a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/SessionClient.swift b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/SessionClient.swift index 4f653d69d1..6d1fb27a03 100644 --- a/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/SessionClient.swift +++ b/AmplifyPlugins/Internal/Sources/InternalAWSPinpoint/Session/SessionClient.swift @@ -6,6 +6,7 @@ // import Amplify +import AWSPluginsCore import Foundation @_spi(InternalAWSPinpoint) @@ -14,7 +15,6 @@ public protocol SessionClientBehaviour: AnyObject { var analyticsClient: AnalyticsClientBehaviour? { get set } func startPinpointSession() - func validateOrRetrieveSession(_ session: PinpointSession?) -> PinpointSession func startTrackingSessions(backgroundTimeout: TimeInterval) } @@ -34,6 +34,7 @@ class SessionClient: SessionClientBehaviour { private let configuration: SessionClientConfiguration private let sessionClientQueue = DispatchQueue(label: Constants.queue, attributes: .concurrent) + private let analyticsTaskQueue = TaskQueue() private let userDefaults: UserDefaultsBehaviour private var sessionBackgroundTimeout: TimeInterval = .zero @@ -49,14 +50,16 @@ class SessionClient: SessionClientBehaviour { self.configuration = configuration self.endpointClient = endpointClient self.userDefaults = userDefaults - session = Self.retrieveStoredSession(from: userDefaults, using: archiver) ?? PinpointSession.invalid + session = Self.retrieveStoredSession(from: userDefaults, using: archiver) ?? .none } var currentSession: PinpointSession { - if session == PinpointSession.invalid { - startNewSession() + sessionClientQueue.sync(flags: .barrier) { + if session == .none { + startNewSession() + } + return session } - return session } func startPinpointSession() { @@ -65,9 +68,11 @@ class SessionClient: SessionClientBehaviour { return } + log.verbose("Starting a new Pinpoint Session") sessionClientQueue.sync(flags: .barrier) { - if session != PinpointSession.invalid { - endSession() + if session != .none { + log.verbose("There is a previous session") + endSession(andSave: false) } startNewSession() } @@ -77,7 +82,7 @@ class SessionClient: SessionClientBehaviour { sessionBackgroundTimeout = backgroundTimeout activityTracker.backgroundTrackingTimeout = backgroundTimeout activityTracker.beginActivityTracking { [weak self] newState in - guard let self = self else { return } + guard let self else { return } self.log.verbose("New state received: \(newState)") self.sessionClientQueue.sync(flags: .barrier) { self.respond(to: newState) @@ -85,20 +90,6 @@ class SessionClient: SessionClientBehaviour { } } - func validateOrRetrieveSession(_ session: PinpointSession?) -> PinpointSession { - if let session = session, !session.sessionId.isEmpty { - return session - } - - if let storedSession = Self.retrieveStoredSession(from: userDefaults, using: archiver) { - return storedSession - } - - return PinpointSession(sessionId: PinpointSession.Constants.defaultSessionId, - startTime: Date(), - stopTime: Date()) - } - private static func retrieveStoredSession(from userDefaults: UserDefaultsBehaviour, using archiver: AmplifyArchiverBehaviour) -> PinpointSession? { guard let sessionData = userDefaults.data(forKey: Constants.sessionKey), @@ -117,10 +108,11 @@ class SessionClient: SessionClientBehaviour { log.info("Session Started.") // Update Endpoint and record Session Start event - Task { - try? await endpointClient.updateEndpointProfile() - log.verbose("Firing Session Event: Start") - record(eventType: Constants.Events.start) + analyticsTaskQueue.async { [weak self] in + guard let self else { return } + try? await self.endpointClient.updateEndpointProfile() + self.log.verbose("Firing Session Event: Start") + await self.record(eventType: Constants.Events.start) } } @@ -134,22 +126,33 @@ class SessionClient: SessionClientBehaviour { } private func pauseSession() { + log.verbose("Attempting to pause session") session.pause() saveSession() log.info("Session Paused.") - log.verbose("Firing Session Event: Pause") - record(eventType: Constants.Events.pause) + analyticsTaskQueue.async { [weak self] in + guard let self else { return } + self.log.verbose("Firing Session Event: Pause") + await self.record(eventType: Constants.Events.pause) + } } private func resumeSession() { + log.verbose("Attempting to resume session") + if session.isStopped { + log.verbose("Session has been stopped. Starting a new one...") + startNewSession() + return + } + guard session.isPaused else { - log.verbose("Session Resume Failed: Session is already runnning.") + log.verbose("Session Resume Failed: Session is not paused") return } guard !isSessionExpired(session) else { log.verbose("Session has expired. Starting a fresh one...") - endSession() + endSession(andSave: false) startNewSession() return } @@ -157,20 +160,38 @@ class SessionClient: SessionClientBehaviour { session.resume() saveSession() log.info("Session Resumed.") - - log.verbose("Firing Session Event: Resume") - record(eventType: Constants.Events.resume) + analyticsTaskQueue.async { [weak self] in + guard let self else { return } + self.log.verbose("Firing Session Event: Resume") + await self.record(eventType: Constants.Events.resume) + } } - private func endSession() { + private func endSession(andSave shouldSave: Bool = true) { + log.verbose("Attempting to end session") + guard !session.isStopped else { + log.verbose("Session End Failed: Session is already stopped") + return + } session.stop() log.info("Session Stopped.") + analyticsTaskQueue.async { [weak self, session] in + guard let self = self, + let analyticsClient = self.analyticsClient else { + return + } + self.log.verbose("Removing remote global attributes") + await analyticsClient.removeAllRemoteGlobalAttributes() + + self.log.verbose("Updating session for existing events") + try? await analyticsClient.update(session) - Task { - log.verbose("Removing remote global attributes") - await analyticsClient?.removeAllRemoteGlobalAttributes() - log.verbose("Firing Session Event: Stop") - record(eventType: Constants.Events.stop) + self.log.verbose("Firing Session Event: Stop") + await self.record(eventType: Constants.Events.stop) + + if shouldSave { + self.saveSession() + } } } @@ -183,16 +204,14 @@ class SessionClient: SessionClientBehaviour { return now - stopTime > sessionBackgroundTimeout } - private func record(eventType: String) { + private func record(eventType: String) async { guard let analyticsClient = analyticsClient else { log.error("Pinpoint Analytics is disabled.") return } let event = analyticsClient.createEvent(withEventType: eventType) - Task { - try? await analyticsClient.record(event) - } + try? await analyticsClient.record(event) } private func respond(to newState: ApplicationState) { @@ -203,8 +222,8 @@ class SessionClient: SessionClientBehaviour { case .runningInBackground(let isStale): if isStale { endSession() - Task { - try? await analyticsClient?.submitEvents() + analyticsTaskQueue.async { [weak self] in + _ = try? await self?.analyticsClient?.submitEvents() } } else { pauseSession() @@ -243,5 +262,5 @@ extension SessionClient { } extension PinpointSession { - static var invalid = PinpointSession(sessionId: "InvalidId", startTime: Date(), stopTime: nil) + static var none = PinpointSession(sessionId: "InvalidId", startTime: Date(), stopTime: nil) } diff --git a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockAnalyticsClient.swift b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockAnalyticsClient.swift index 72c48c74c5..307fb0775e 100644 --- a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockAnalyticsClient.swift +++ b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockAnalyticsClient.swift @@ -102,6 +102,11 @@ actor MockAnalyticsClient: AnalyticsClientBehaviour { return [] } + var updateSessionCount = 0 + func update(_ session: InternalAWSPinpoint.PinpointSession) async throws { + updateSessionCount += 1 + } + func resetCounters() { recordCount = 0 submitEventsCount = 0 diff --git a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockAnalyticsEventStorage.swift b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockAnalyticsEventStorage.swift index 97d0a99d72..ebc515a641 100644 --- a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockAnalyticsEventStorage.swift +++ b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockAnalyticsEventStorage.swift @@ -75,4 +75,9 @@ class MockAnalyticsEventStorage: AnalyticsEventStorage { func checkDiskSize(limit: Byte) throws { checkDiskSizeCallCount += 1 } + + var updateSessionCount = 0 + func updateSession(_ session: PinpointSession) throws { + updateSessionCount += 1 + } } diff --git a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockEventRecorder.swift b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockEventRecorder.swift index e73512324b..50044a2a55 100644 --- a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockEventRecorder.swift +++ b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/Mocks/MockEventRecorder.swift @@ -34,4 +34,9 @@ actor MockEventRecorder: AnalyticsEventRecording { submitCount += 1 return [] } + + var updateSessionCount = 0 + func update(_ session: InternalAWSPinpoint.PinpointSession) throws { + updateSessionCount += 1 + } } diff --git a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/SessionClientTests.swift b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/SessionClientTests.swift index c48b4f76aa..9799d3a172 100644 --- a/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/SessionClientTests.swift +++ b/AmplifyPlugins/Internal/Tests/InternalAWSPinpointUnitTests/SessionClientTests.swift @@ -114,47 +114,6 @@ class SessionClientTests: XCTestCase { XCTAssertEqual(userDefaults.saveCount, 0) } - func testValidateSession_withValidSession_andStoredSession_shouldReturnValidSession() async { - storeSession() - await resetCounters() - let session = PinpointSession(sessionId: "valid", startTime: Date(), stopTime: nil) - let retrievedSession = client.validateOrRetrieveSession(session) - - XCTAssertEqual(userDefaults.dataForKeyCount, 0) - XCTAssertEqual(archiver.decodeCount, 0) - XCTAssertEqual(retrievedSession.sessionId, "valid") - } - - func testValidateSession_withInvalidSession_andStoredSession_shouldReturnStoredSession() async { - storeSession() - await resetCounters() - let session = PinpointSession(sessionId: "", startTime: Date(), stopTime: nil) - let retrievedSession = client.validateOrRetrieveSession(session) - - XCTAssertEqual(userDefaults.dataForKeyCount, 1) - XCTAssertEqual(archiver.decodeCount, 1) - XCTAssertEqual(retrievedSession.sessionId, "stored") - } - - func testValidateSession_withInvalidSession_andWithoutStoredSession_shouldCreateDefaultSession() async { - await resetCounters() - let session = PinpointSession(sessionId: "", startTime: Date(), stopTime: nil) - let retrievedSession = client.validateOrRetrieveSession(session) - - XCTAssertEqual(userDefaults.dataForKeyCount, 1) - XCTAssertEqual(archiver.decodeCount, 0) - XCTAssertEqual(retrievedSession.sessionId, PinpointSession.Constants.defaultSessionId) - } - - func testValidateSession_withNilSession_andWithoutStoredSession_shouldCreateDefaultSession() async { - await resetCounters() - let retrievedSession = client.validateOrRetrieveSession(nil) - - XCTAssertEqual(userDefaults.dataForKeyCount, 1) - XCTAssertEqual(archiver.decodeCount, 0) - XCTAssertEqual(retrievedSession.sessionId, PinpointSession.Constants.defaultSessionId) - } - func testStartPinpointSession_shouldRecordStartEvent() async { await resetCounters() let expectationStartSession = expectation(description: "Start event for new session") @@ -218,7 +177,7 @@ class SessionClientTests: XCTestCase { XCTAssertEqual(event.eventType, SessionClient.Constants.Events.pause) } - func testApplicationMovedToBackground_stale_shouldRecordStopEvent_andSubmit() async { + func testApplicationMovedToBackground_stale_shouldRecordStopEvent_andSaveSession_andSubmitEvents() async { let expectationStartSession = expectation(description: "Start event for new session") client.startPinpointSession() client.startTrackingSessions(backgroundTimeout: sessionTimeout) @@ -233,8 +192,8 @@ class SessionClientTests: XCTestCase { activityTracker.callback?(.runningInBackground(isStale: true)) await fulfillment(of: [expectationStopSession, expectationSubmitEvents], timeout: 1) - XCTAssertEqual(archiver.encodeCount, 0) - XCTAssertEqual(userDefaults.saveCount, 0) + XCTAssertEqual(archiver.encodeCount, 1) + XCTAssertEqual(userDefaults.saveCount, 1) let createCount = await analyticsClient.createEventCount XCTAssertEqual(createCount, 1) let recordCount = await analyticsClient.recordCount @@ -327,7 +286,7 @@ class SessionClientTests: XCTestCase { XCTAssertNotNil(events.first(where: { $0.eventType == SessionClient.Constants.Events.start })) } #endif - func testApplicationTerminated_shouldRecordStopEvent() async { + func testApplicationTerminated_shouldRecordStopEvent_andSaveSession() async { let expectationStart = expectation(description: "Start event for new session") await analyticsClient.setRecordExpectation(expectationStart) client.startPinpointSession() @@ -340,8 +299,8 @@ class SessionClientTests: XCTestCase { activityTracker.callback?(.terminated) await fulfillment(of: [expectationStop], timeout: 1) - XCTAssertEqual(archiver.encodeCount, 0) - XCTAssertEqual(userDefaults.saveCount, 0) + XCTAssertEqual(archiver.encodeCount, 1) + XCTAssertEqual(userDefaults.saveCount, 1) let createCount = await analyticsClient.createEventCount XCTAssertEqual(createCount, 1) let recordCount = await analyticsClient.recordCount From 3719cca94917b9e5e5063dd4c00304698fbbce45 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Thu, 11 Jan 2024 12:29:07 -0800 Subject: [PATCH 5/8] ci: change to use xcode version with alias (#3465) --- .../get_platform_parameters/action.yml | 83 ++++++++++++++----- .../run_xcodebuild_test/action.yml | 3 +- .github/workflows/build_amplify_swift.yml | 12 +-- ...uild_minimum_supported_swift_platforms.yml | 21 +---- .github/workflows/integ_test_analytics.yml | 1 - .../workflows/integ_test_api_functional.yml | 1 - .../integ_test_api_graphql_auth_directive.yml | 1 - .../workflows/integ_test_api_graphql_iam.yml | 1 - .../integ_test_api_graphql_lambda_auth.yml | 1 - .../integ_test_api_graphql_lazy_load.yml | 1 - .../integ_test_api_graphql_user_pool.yml | 1 - .github/workflows/integ_test_api_rest_iam.yml | 1 - .../integ_test_api_rest_user_pool.yml | 1 - .github/workflows/integ_test_auth.yml | 2 - .../integ_test_datastore_auth_cognito.yml | 1 - .../integ_test_datastore_auth_iam.yml | 1 - .../workflows/integ_test_datastore_base.yml | 1 - .../workflows/integ_test_datastore_cpk.yml | 1 - .../integ_test_datastore_lazy_load.yml | 1 - .../integ_test_datastore_multi_auth.yml | 1 - .github/workflows/integ_test_datastore_v2.yml | 1 - .github/workflows/integ_test_geo.yml | 1 - .github/workflows/integ_test_logging.yml | 3 +- .github/workflows/integ_test_predictions.yml | 1 - .../integ_test_push_notifications.yml | 9 +- .github/workflows/integ_test_storage.yml | 1 - .github/workflows/run_integration_tests.yml | 15 +++- .github/workflows/run_unit_tests.yml | 6 +- .../workflows/run_unit_tests_platforms.yml | 1 - .github/workflows/stress_test.yml | 61 ++++++++++---- 30 files changed, 134 insertions(+), 101 deletions(-) diff --git a/.github/composite_actions/get_platform_parameters/action.yml b/.github/composite_actions/get_platform_parameters/action.yml index 0fc0945e11..35353e4c98 100644 --- a/.github/composite_actions/get_platform_parameters/action.yml +++ b/.github/composite_actions/get_platform_parameters/action.yml @@ -5,62 +5,99 @@ inputs: required: true type: string xcode_version: - description: 'The version of Xcode. Valid values are 14.3 and 15.0' - required: true + description: "The version of Xcode. Available aliases are 'latest' and 'minimum'" + default: 'latest' + type: string + destination: + description: "The destination associated with the given platform and Xcode version" + default: '' type: string + outputs: destination: description: "The destination associated with the given platform and Xcode version" - value: ${{ steps.platform.outputs.destination }} + value: ${{ steps.get-destination.outputs.destination }} sdk: description: "The SDK associated with the given platform" - value: ${{ steps.platform.outputs.sdk }} + value: ${{ steps.get-sdk.outputs.sdk }} + xcode-version: + description: "The Xcode version to build with" + value: ${{ steps.get-xcode-version.outputs.xcode-version }} + runs: using: "composite" steps: - - id: platform + - name: Validate platform run: | - PLATFORM=${{ inputs.platform }} - case $PLATFORM in + INPUT_PLATFORM=${{ inputs.platform }} + case $INPUT_PLATFORM in iOS|tvOS|watchOS|macOS) ;; - *) echo "Unsupported platform: $PLATFORM"; exit 1 ;; + *) echo "Unsupported platform: $INPUT_PLATFORM"; exit 1 ;; esac + shell: bash + + - id: get-xcode-version + run: | + LATEST_XCODE_VERSION=14.3.1 + MINIMUM_XCODE_VERSION=14.0.1 - XCODE_VERSION=${{ inputs.xcode_version }} - case $XCODE_VERSION in - 14.0.1|14.3|15.0) ;; - *) echo "Unsupported Xcode version: $XCODE_VERSION"; exit 1 ;; + INPUT_XCODE_VERSION=${{ inputs.xcode_version }} + + case $INPUT_XCODE_VERSION in + latest) + XCODE_VERSION=$LATEST_XCODE_VERSION ;; + minimum) + XCODE_VERSION=$MINIMUM_XCODE_VERSION ;; + *) + XCODE_VERSION=$INPUT_XCODE_VERSION ;; esac + echo "xcode-version=$XCODE_VERSION" >> $GITHUB_OUTPUT + + shell: bash + + - id: get-destination + run: | + INPUT_PLATFORM=${{ inputs.platform }} + INPUT_DESTINATION='${{ inputs.destination }}' + INPUT_XCODE_VERSION=${{ inputs.xcode_version }} DESTINATION_MAPPING='{ - "14.0.1": { + "minimum": { "iOS": "platform=iOS Simulator,name=iPhone 14,OS=16.0", "tvOS": "platform=tvOS Simulator,name=Apple TV 4K (2nd generation),OS=16.0", "watchOS": "platform=watchOS Simulator,name=Apple Watch Series 8 (45mm),OS=9.0", "macOS": "platform=macOS,arch=x86_64" }, - "14.3": { + "latest": { "iOS": "platform=iOS Simulator,name=iPhone 14,OS=16.4", "tvOS": "platform=tvOS Simulator,name=Apple TV 4K (3rd generation),OS=16.4", "watchOS": "platform=watchOS Simulator,name=Apple Watch Series 8 (45mm),OS=9.4", "macOS": "platform=macOS,arch=x86_64" - }, - "15.0": { - "iOS": "platform=iOS Simulator,name=iPhone 15,OS=latest", - "tvOS": "platform=tvOS Simulator,name=Apple TV 4K (3rd generation),OS=latest", - "watchOS": "platform=watchOS Simulator,name=Apple Watch Series 9 (45mm),OS=latest", - "macOS": "platform=macOS,arch=x86_64" } }' + if [ -z "$INPUT_DESTINATION" ]; then + DESTINATION=$(echo $DESTINATION_MAPPING | jq -r ".\"$INPUT_XCODE_VERSION\".$INPUT_PLATFORM") + else + DESTINATION=$INPUT_DESTINATION + fi + + if [ -z "$DESTINATION" ]; then + echo "No available destination to build for" + exit 1 + fi + echo "destination=$DESTINATION" >> $GITHUB_OUTPUT + shell: bash + + - id: get-sdk + run: | + INPUT_PLATFORM=${{ inputs.platform }} SDK_MAPPING='{ "iOS": "iphonesimulator", "tvOS": "appletvsimulator", "watchOS": "watchsimulator", "macOS": "macosx" }' - - echo "destination=$(echo $DESTINATION_MAPPING | jq -r ."\"$XCODE_VERSION\"".$PLATFORM)" >> $GITHUB_OUTPUT - echo "sdk=$(echo $SDK_MAPPING | jq -r .$PLATFORM)" >> $GITHUB_OUTPUT + echo "sdk=$(echo $SDK_MAPPING | jq -r .$INPUT_PLATFORM)" >> $GITHUB_OUTPUT shell: bash diff --git a/.github/composite_actions/run_xcodebuild_test/action.yml b/.github/composite_actions/run_xcodebuild_test/action.yml index 3f377b7ef5..b025621254 100644 --- a/.github/composite_actions/run_xcodebuild_test/action.yml +++ b/.github/composite_actions/run_xcodebuild_test/action.yml @@ -12,9 +12,8 @@ inputs: required: false type: string destination: - required: false + required: true type: string - default: 'platform=iOS Simulator,name=iPhone 13,OS=latest' sdk: required: false type: string diff --git a/.github/workflows/build_amplify_swift.yml b/.github/workflows/build_amplify_swift.yml index d2975c4a82..095edbcfab 100644 --- a/.github/workflows/build_amplify_swift.yml +++ b/.github/workflows/build_amplify_swift.yml @@ -8,7 +8,7 @@ on: xcode-version: type: string - default: '14.3' + default: 'latest' os-runner: type: string @@ -43,7 +43,7 @@ jobs: id: dependencies-cache if: inputs.cacheable timeout-minutes: 4 - continue-on-error: true + continue-on-error: ${{ inputs.cacheable }} uses: actions/cache/restore@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 with: path: ~/Library/Developer/Xcode/DerivedData/Amplify @@ -55,7 +55,7 @@ jobs: id: build-cache if: inputs.cacheable timeout-minutes: 4 - continue-on-error: true + continue-on-error: ${{ inputs.cacheable }} uses: actions/cache/restore@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 # v3.3.1 with: path: ${{ github.workspace }}/Build @@ -63,13 +63,13 @@ jobs: - name: Build Amplify for Swift id: build-package - continue-on-error: true + continue-on-error: ${{ inputs.cacheable }} uses: ./.github/composite_actions/run_xcodebuild with: scheme: Amplify-Package destination: ${{ steps.platform.outputs.destination }} sdk: ${{ steps.platform.outputs.sdk }} - xcode_path: /Applications/Xcode_${{ inputs.xcode-version }}.app + xcode_path: /Applications/Xcode_${{ steps.platform.outputs.xcode-version }}.app cloned_source_packages_path: ~/Library/Developer/Xcode/DerivedData/Amplify derived_data_path: ${{ github.workspace }}/Build disable_package_resolution: ${{ steps.dependencies-cache.outputs.cache-hit }} @@ -85,7 +85,7 @@ jobs: if: inputs.cacheable && steps.build-cache.outputs.cache-hit && github.ref_name == 'main' env: GH_TOKEN: ${{ github.token }} - continue-on-error: true + continue-on-error: ${{ inputs.cacheable }} run: | gh cache delete ${{ steps.build-cache.outputs.cache-primary-key }} diff --git a/.github/workflows/build_minimum_supported_swift_platforms.yml b/.github/workflows/build_minimum_supported_swift_platforms.yml index a86f8b99b0..6b4e7f5d4c 100644 --- a/.github/workflows/build_minimum_supported_swift_platforms.yml +++ b/.github/workflows/build_minimum_supported_swift_platforms.yml @@ -15,27 +15,12 @@ jobs: strategy: fail-fast: false matrix: - include: - - os-runner: macos-12 - xcode-version: 14.0.1 - platform: iOS - - - os-runner: macos-12 - xcode-version: 14.0.1 - platform: macOS - - - os-runner: macos-12 - xcode-version: 14.0.1 - platform: tvOS - - - os-runner: macos-12 - xcode-version: 14.0.1 - platform: watchOS + platform: [iOS, macOS, tvOS, watchOS] uses: ./.github/workflows/build_amplify_swift.yml with: - os-runner: ${{ matrix.os-runner }} - xcode-version: ${{ matrix.xcode-version }} + os-runner: macos-12 + xcode-version: 'minimum' platform: ${{ matrix.platform }} cacheable: false diff --git a/.github/workflows/integ_test_analytics.yml b/.github/workflows/integ_test_analytics.yml index 6f0de7f368..a848bd91ed 100644 --- a/.github/workflows/integ_test_analytics.yml +++ b/.github/workflows/integ_test_analytics.yml @@ -39,7 +39,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSPinpointAnalyticsPluginIntegrationTestsWatch' || 'AWSPinpointAnalyticsPluginIntegrationTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/Analytics/Tests/AnalyticsHostApp - xcode_version: '14.3' resource_subfolder: analytics timeout-minutes: 30 secrets: inherit diff --git a/.github/workflows/integ_test_api_functional.yml b/.github/workflows/integ_test_api_functional.yml index a63a05eb28..c908c8a1e2 100644 --- a/.github/workflows/integ_test_api_functional.yml +++ b/.github/workflows/integ_test_api_functional.yml @@ -39,7 +39,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSAPIPluginFunctionalTestsWatch' || 'AWSAPIPluginFunctionalTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/API/Tests/APIHostApp - xcode_version: '14.3' resource_subfolder: api timeout-minutes: 45 secrets: inherit diff --git a/.github/workflows/integ_test_api_graphql_auth_directive.yml b/.github/workflows/integ_test_api_graphql_auth_directive.yml index 33dba6c1d5..7c87361a7d 100644 --- a/.github/workflows/integ_test_api_graphql_auth_directive.yml +++ b/.github/workflows/integ_test_api_graphql_auth_directive.yml @@ -33,7 +33,6 @@ jobs: scheme: AWSAPIPluginGraphQLAuthDirectiveTests platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/API/Tests/APIHostApp - xcode_version: '14.3' resource_subfolder: api timeout-minutes: 45 secrets: inherit diff --git a/.github/workflows/integ_test_api_graphql_iam.yml b/.github/workflows/integ_test_api_graphql_iam.yml index e1631664ea..699d31235f 100644 --- a/.github/workflows/integ_test_api_graphql_iam.yml +++ b/.github/workflows/integ_test_api_graphql_iam.yml @@ -33,7 +33,6 @@ jobs: scheme: AWSAPIPluginGraphQLIAMTests platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/API/Tests/APIHostApp - xcode_version: '14.3' resource_subfolder: api timeout-minutes: 45 secrets: inherit diff --git a/.github/workflows/integ_test_api_graphql_lambda_auth.yml b/.github/workflows/integ_test_api_graphql_lambda_auth.yml index 49388053a2..ca34cf9eb6 100644 --- a/.github/workflows/integ_test_api_graphql_lambda_auth.yml +++ b/.github/workflows/integ_test_api_graphql_lambda_auth.yml @@ -39,7 +39,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSAPIPluginGraphQLLambdaAuthTestsWatch' || 'AWSAPIPluginGraphQLLambdaAuthTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/API/Tests/APIHostApp - xcode_version: '14.3' resource_subfolder: api timeout-minutes: 45 secrets: inherit diff --git a/.github/workflows/integ_test_api_graphql_lazy_load.yml b/.github/workflows/integ_test_api_graphql_lazy_load.yml index 849c329625..b0456fcab6 100644 --- a/.github/workflows/integ_test_api_graphql_lazy_load.yml +++ b/.github/workflows/integ_test_api_graphql_lazy_load.yml @@ -33,7 +33,6 @@ jobs: scheme: AWSAPIPluginLazyLoadTests platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/API/Tests/APIHostApp - xcode_version: '14.3' resource_subfolder: api timeout-minutes: 45 secrets: inherit diff --git a/.github/workflows/integ_test_api_graphql_user_pool.yml b/.github/workflows/integ_test_api_graphql_user_pool.yml index 21f1205eb6..fef6418944 100644 --- a/.github/workflows/integ_test_api_graphql_user_pool.yml +++ b/.github/workflows/integ_test_api_graphql_user_pool.yml @@ -33,7 +33,6 @@ jobs: scheme: AWSAPIPluginGraphQLUserPoolTests platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/API/Tests/APIHostApp - xcode_version: '14.3' resource_subfolder: api timeout-minutes: 45 secrets: inherit \ No newline at end of file diff --git a/.github/workflows/integ_test_api_rest_iam.yml b/.github/workflows/integ_test_api_rest_iam.yml index 18a14615bf..8f4e198e71 100644 --- a/.github/workflows/integ_test_api_rest_iam.yml +++ b/.github/workflows/integ_test_api_rest_iam.yml @@ -39,7 +39,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSAPIPluginRESTIAMTestsWatch' || 'AWSAPIPluginRESTIAMTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/API/Tests/APIHostApp - xcode_version: '14.3' resource_subfolder: api timeout-minutes: 45 secrets: inherit diff --git a/.github/workflows/integ_test_api_rest_user_pool.yml b/.github/workflows/integ_test_api_rest_user_pool.yml index 96c141316e..2919eb92e1 100644 --- a/.github/workflows/integ_test_api_rest_user_pool.yml +++ b/.github/workflows/integ_test_api_rest_user_pool.yml @@ -33,7 +33,6 @@ jobs: scheme: AWSAPIPluginRESTUserPoolTests platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/API/Tests/APIHostApp - xcode_version: '14.3' resource_subfolder: api timeout-minutes: 45 secrets: inherit diff --git a/.github/workflows/integ_test_auth.yml b/.github/workflows/integ_test_auth.yml index e90900e0ee..c7722b5745 100644 --- a/.github/workflows/integ_test_auth.yml +++ b/.github/workflows/integ_test_auth.yml @@ -44,7 +44,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AuthIntegrationTestsWatch' || 'AuthIntegrationTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/Auth/Tests/AuthHostApp/ - xcode_version: '14.3' resource_subfolder: auth timeout-minutes: 30 secrets: inherit @@ -56,7 +55,6 @@ jobs: scheme: AuthHostedUIApp platform: iOS project_path: ./AmplifyPlugins/Auth/Tests/AuthHostedUIApp/ - xcode_version: '14.3' resource_subfolder: auth timeout-minutes: 30 secrets: inherit diff --git a/.github/workflows/integ_test_datastore_auth_cognito.yml b/.github/workflows/integ_test_datastore_auth_cognito.yml index cd611d7f82..2cbba332bf 100644 --- a/.github/workflows/integ_test_datastore_auth_cognito.yml +++ b/.github/workflows/integ_test_datastore_auth_cognito.yml @@ -39,7 +39,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSDataStorePluginAuthCognitoTestsWatch' || 'AWSDataStorePluginAuthCognitoTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/DataStore/Tests/DataStoreHostApp - xcode_version: '14.3' resource_subfolder: datastore timeout-minutes: 120 secrets: inherit diff --git a/.github/workflows/integ_test_datastore_auth_iam.yml b/.github/workflows/integ_test_datastore_auth_iam.yml index 9c5c25a948..745bd83950 100644 --- a/.github/workflows/integ_test_datastore_auth_iam.yml +++ b/.github/workflows/integ_test_datastore_auth_iam.yml @@ -39,7 +39,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSDataStorePluginAuthIAMTestsWatch' || 'AWSDataStorePluginAuthIAMTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/DataStore/Tests/DataStoreHostApp - xcode_version: '14.3' resource_subfolder: datastore timeout-minutes: 120 secrets: inherit diff --git a/.github/workflows/integ_test_datastore_base.yml b/.github/workflows/integ_test_datastore_base.yml index 5a3ca820df..55a503636d 100644 --- a/.github/workflows/integ_test_datastore_base.yml +++ b/.github/workflows/integ_test_datastore_base.yml @@ -39,7 +39,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSDataStorePluginIntegrationTestsWatch' || 'AWSDataStorePluginIntegrationTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/DataStore/Tests/DataStoreHostApp - xcode_version: '14.3' resource_subfolder: datastore timeout-minutes: 120 secrets: inherit diff --git a/.github/workflows/integ_test_datastore_cpk.yml b/.github/workflows/integ_test_datastore_cpk.yml index 350def730c..ceb1e8f840 100644 --- a/.github/workflows/integ_test_datastore_cpk.yml +++ b/.github/workflows/integ_test_datastore_cpk.yml @@ -39,7 +39,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSDataStorePluginCPKTestsWatch' || 'AWSDataStorePluginCPKTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/DataStore/Tests/DataStoreHostApp - xcode_version: '14.3' resource_subfolder: datastore timeout-minutes: 120 secrets: inherit diff --git a/.github/workflows/integ_test_datastore_lazy_load.yml b/.github/workflows/integ_test_datastore_lazy_load.yml index c54e405359..1c0bffa14f 100644 --- a/.github/workflows/integ_test_datastore_lazy_load.yml +++ b/.github/workflows/integ_test_datastore_lazy_load.yml @@ -39,7 +39,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSDataStorePluginLazyLoadTestsWatch' || 'AWSDataStorePluginLazyLoadTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/DataStore/Tests/DataStoreHostApp - xcode_version: '14.3' resource_subfolder: datastore timeout-minutes: 120 secrets: inherit diff --git a/.github/workflows/integ_test_datastore_multi_auth.yml b/.github/workflows/integ_test_datastore_multi_auth.yml index df5ccd69bd..78f7334bba 100644 --- a/.github/workflows/integ_test_datastore_multi_auth.yml +++ b/.github/workflows/integ_test_datastore_multi_auth.yml @@ -39,7 +39,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSDataStorePluginMultiAuthTestsWatch' || 'AWSDataStorePluginMultiAuthTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/DataStore/Tests/DataStoreHostApp - xcode_version: '14.3' resource_subfolder: datastore timeout-minutes: 120 secrets: inherit diff --git a/.github/workflows/integ_test_datastore_v2.yml b/.github/workflows/integ_test_datastore_v2.yml index 1b44b75248..8cee2019e9 100644 --- a/.github/workflows/integ_test_datastore_v2.yml +++ b/.github/workflows/integ_test_datastore_v2.yml @@ -39,7 +39,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSDataStorePluginV2TestsWatch' || 'AWSDataStorePluginV2Tests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/DataStore/Tests/DataStoreHostApp - xcode_version: '14.3' resource_subfolder: datastore timeout-minutes: 120 secrets: inherit diff --git a/.github/workflows/integ_test_geo.yml b/.github/workflows/integ_test_geo.yml index 2bc9cb0ced..38c3fbd7b3 100644 --- a/.github/workflows/integ_test_geo.yml +++ b/.github/workflows/integ_test_geo.yml @@ -39,7 +39,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSLocationGeoPluginIntegrationTestsWatch' || 'AWSLocationGeoPluginIntegrationTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/Geo/Tests/GeoHostApp/ - xcode_version: '14.3' resource_subfolder: geo timeout-minutes: 30 secrets: inherit diff --git a/.github/workflows/integ_test_logging.yml b/.github/workflows/integ_test_logging.yml index d591dcfe33..f2b4987433 100644 --- a/.github/workflows/integ_test_logging.yml +++ b/.github/workflows/integ_test_logging.yml @@ -39,7 +39,8 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSCloudWatchLoggingPluginIntegrationTestsWatch' || 'AWSCloudWatchLoggingPluginIntegrationTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginHostApp - xcode_version: ${{ matrix.platform == 'watchOS' && '15.0' || '14.3' }} resource_subfolder: logging + xcode_version: ${{ matrix.platform == 'watchOS' && '15.0' || 'latest' }} + destination: ${{ matrix.platform == 'watchOS' && 'platform=watchOS Simulator,name=Apple Watch Series 8 (45mm),OS=10.2' || '' }} timeout-minutes: 60 secrets: inherit diff --git a/.github/workflows/integ_test_predictions.yml b/.github/workflows/integ_test_predictions.yml index 7cf53e3378..3d9cdcf627 100644 --- a/.github/workflows/integ_test_predictions.yml +++ b/.github/workflows/integ_test_predictions.yml @@ -39,7 +39,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSPredictionsPluginIntegrationTestsWatch' || 'AWSPredictionsPluginIntegrationTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/Predictions/Tests/PredictionsHostApp - xcode_version: '14.3' resource_subfolder: predictions timeout-minutes: 30 secrets: inherit diff --git a/.github/workflows/integ_test_push_notifications.yml b/.github/workflows/integ_test_push_notifications.yml index a600fbd68b..ff8c2c6a2a 100644 --- a/.github/workflows/integ_test_push_notifications.yml +++ b/.github/workflows/integ_test_push_notifications.yml @@ -42,14 +42,13 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - + - name: Get build parameters for ${{ matrix.platform}} id: platform uses: ./.github/composite_actions/get_platform_parameters with: platform: ${{ matrix.platform }} - xcode_version: '14.3' - + - name: Create the test configuration directory run: mkdir -p ~/.aws-amplify/amplify-ios/testconfiguration/ @@ -102,7 +101,7 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'PushNotificationWatchTests' || 'PushNotificationHostApp' }} destination: ${{ steps.platform.outputs.destination }} sdk: ${{ steps.platform.outputs.sdk }} - xcode_path: /Applications/Xcode_14.3.app + xcode_path: /Applications/Xcode_${{ steps.platform.outputs.xcode-version }}.app project_path: ./AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp generate_coverage: false cloned_source_packages_path: ~/Library/Developer/Xcode/DerivedData/Amplify @@ -117,7 +116,7 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'PushNotificationWatchTests' || 'PushNotificationHostApp' }} destination: ${{ steps.platform.outputs.destination }} sdk: ${{ steps.platform.outputs.sdk }} - xcode_path: /Applications/Xcode_14.3.app + xcode_path: /Applications/Xcode_${{ steps.platform.outputs.xcode-version }}.app project_path: ./AmplifyPlugins/Notifications/Push/Tests/PushNotificationHostApp generate_coverage: false cloned_source_packages_path: ~/Library/Developer/Xcode/DerivedData/Amplify diff --git a/.github/workflows/integ_test_storage.yml b/.github/workflows/integ_test_storage.yml index 22fc5bb90e..f088584063 100644 --- a/.github/workflows/integ_test_storage.yml +++ b/.github/workflows/integ_test_storage.yml @@ -39,7 +39,6 @@ jobs: scheme: ${{ matrix.platform == 'watchOS' && 'AWSS3StoragePluginIntegrationTestsWatch' || 'AWSS3StoragePluginIntegrationTests' }} platform: ${{ matrix.platform }} project_path: ./AmplifyPlugins/Storage/Tests/StorageHostApp/ - xcode_version: '14.3' resource_subfolder: storage timeout-minutes: 30 secrets: inherit diff --git a/.github/workflows/run_integration_tests.yml b/.github/workflows/run_integration_tests.yml index 41bec24f2b..36adfa4645 100644 --- a/.github/workflows/run_integration_tests.yml +++ b/.github/workflows/run_integration_tests.yml @@ -2,6 +2,9 @@ name: Run tests for the given parameters on: workflow_call: inputs: + os-runner: + type: string + default: 'macos-13' scheme: description: 'The scheme to run the tests' required: true @@ -15,7 +18,10 @@ on: type: string xcode_version: description: 'The verion of Xcode used to run these tests' - required: true + default: 'latest' + type: string + destination: + default: '' type: string resource_subfolder: required: true @@ -33,7 +39,7 @@ permissions: jobs: integration-tests: name: ${{ inputs.platform }} Tests | ${{ inputs.scheme }} - runs-on: macos-13 + runs-on: ${{ inputs.os-runner }} if: inputs.platform != 'macOS' # macOS is not supported for Integration Tests timeout-minutes: ${{ inputs.timeout-minutes }} environment: IntegrationTest @@ -49,6 +55,7 @@ jobs: with: platform: ${{ inputs.platform }} xcode_version: ${{ inputs.xcode_version }} + destination: ${{ inputs.destination }} - name: Create the test configuration directory run: mkdir -p ~/.aws-amplify/amplify-ios/testconfiguration/ @@ -90,7 +97,7 @@ jobs: scheme: ${{ inputs.scheme }} destination: ${{ steps.platform.outputs.destination }} sdk: ${{ steps.platform.outputs.sdk }} - xcode_path: /Applications/Xcode_${{ inputs.xcode_version }}.app + xcode_path: /Applications/Xcode_${{ steps.platform.outputs.xcode-version }}.app project_path: ${{ inputs.project_path }} generate_coverage: false cloned_source_packages_path: ~/Library/Developer/Xcode/DerivedData/Amplify @@ -107,7 +114,7 @@ jobs: scheme: ${{ inputs.scheme }} destination: ${{ steps.platform.outputs.destination }} sdk: ${{ steps.platform.outputs.sdk }} - xcode_path: /Applications/Xcode_${{ inputs.xcode_version }}.app + xcode_path: /Applications/Xcode_${{ steps.platform.outputs.xcode-version }}.app project_path: ${{ inputs.project_path }} generate_coverage: false cloned_source_packages_path: ~/Library/Developer/Xcode/DerivedData/Amplify diff --git a/.github/workflows/run_unit_tests.yml b/.github/workflows/run_unit_tests.yml index e87cd68de8..af91b4b226 100644 --- a/.github/workflows/run_unit_tests.yml +++ b/.github/workflows/run_unit_tests.yml @@ -15,7 +15,7 @@ on: type: string xcode_version: description: 'The version of Xcode used to run these tests' - required: true + default: 'latest' type: string timeout-minutes: description: 'The timeout for each execution' @@ -77,7 +77,7 @@ jobs: scheme: ${{ inputs.scheme }} destination: ${{ steps.platform.outputs.destination }} sdk: ${{ steps.platform.outputs.sdk }} - xcode_path: /Applications/Xcode_${{ inputs.xcode_version }}.app + xcode_path: /Applications/Xcode_${{ steps.platform.outputs.xcode-version }}.app generate_coverage: ${{ inputs.generate_coverage_report }} cloned_source_packages_path: ~/Library/Developer/Xcode/DerivedData/Amplify derived_data_path: ${{ github.workspace }}/Build @@ -92,7 +92,7 @@ jobs: scheme: ${{ inputs.scheme }} destination: ${{ steps.platform.outputs.destination }} sdk: ${{ steps.platform.outputs.sdk }} - xcode_path: /Applications/Xcode_${{ inputs.xcode_version }}.app + xcode_path: /Applications/Xcode_${{ steps.platform.outputs.xcode-version }}.app project_path: ${{ inputs.project_path }} generate_coverage: ${{ inputs.generate_coverage_report }} cloned_source_packages_path: ~/Library/Developer/Xcode/DerivedData/Amplify diff --git a/.github/workflows/run_unit_tests_platforms.yml b/.github/workflows/run_unit_tests_platforms.yml index f5df65aafa..4cfc4b75af 100644 --- a/.github/workflows/run_unit_tests_platforms.yml +++ b/.github/workflows/run_unit_tests_platforms.yml @@ -36,6 +36,5 @@ jobs: with: scheme: ${{ inputs.scheme }} platform: ${{ matrix.platform }} - xcode_version: '14.3' generate_coverage_report: ${{ github.event_name != 'workflow_dispatch' && matrix.platform == 'iOS' && inputs.generate_coverage_report }} timeout-minutes: ${{ inputs.timeout-minutes }} \ No newline at end of file diff --git a/.github/workflows/stress_test.yml b/.github/workflows/stress_test.yml index 805d6232d3..acc637d883 100644 --- a/.github/workflows/stress_test.yml +++ b/.github/workflows/stress_test.yml @@ -6,7 +6,7 @@ on: permissions: id-token: write - contents: read + contents: read concurrency: group: ${{ github.head_ref || github.run_id }} @@ -29,10 +29,25 @@ jobs: aws_region: ${{ secrets.AWS_REGION }} aws_s3_bucket: ${{ secrets.AWS_S3_BUCKET_INTEG_V2 }} - auth-stress-test: + get-platform-build-params: + runs-on: macos-13 needs: prepare-for-test + outputs: + platform-params: ${{ steps.platform.outputs }} + steps: + - name: Get build parameters + id: platform + uses: ./.github/composite_actions/get_platform_parameters + with: + platform: 'iOS' + + auth-stress-test: + needs: get-platform-build-params runs-on: macos-13 environment: IntegrationTest + env: + DESTINATION: ${{ needs.get-platform-build-params.outputs.platform-params.destination }} + XCODE_VERSION: ${{ needs.get-platform-build-params.outputs.platform-params.xcode-version }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 with: @@ -54,13 +69,16 @@ jobs: with: project_path: ./AmplifyPlugins/Auth/Tests/AuthHostApp/ scheme: AuthStressTests - destination: 'platform=iOS Simulator,name=iPhone 14,OS=16.4' - xcode_path: '/Applications/Xcode_14.3.app' + destination: ${{ env.DESTINATION }} + xcode_path: '/Applications/Xcode_${{ env.XCODE_VERSION }}.app' geo-stress-test: - needs: prepare-for-test + needs: get-platform-build-params runs-on: macos-13 environment: IntegrationTest + env: + DESTINATION: ${{ needs.get-platform-build-params.outputs.platform-params.destination }} + XCODE_VERSION: ${{ needs.get-platform-build-params.outputs.platform-params.xcode-version }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 with: @@ -82,13 +100,16 @@ jobs: with: project_path: ./AmplifyPlugins/Geo/Tests/GeoHostApp/ scheme: GeoStressTests - destination: 'platform=iOS Simulator,name=iPhone 14,OS=16.4' - xcode_path: '/Applications/Xcode_14.3.app' + destination: ${{ env.DESTINATION }} + xcode_path: '/Applications/Xcode_${{ env.XCODE_VERSION }}.app' storage-stress-test: - needs: prepare-for-test + needs: get-platform-build-params runs-on: macos-13 environment: IntegrationTest + env: + DESTINATION: ${{ needs.get-platform-build-params.outputs.platform-params.destination }} + XCODE_VERSION: ${{ needs.get-platform-build-params.outputs.platform-params.xcode-version }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 with: @@ -110,13 +131,16 @@ jobs: with: project_path: ./AmplifyPlugins/Storage/Tests/StorageHostApp/ scheme: StorageStressTests - destination: 'platform=iOS Simulator,name=iPhone 14,OS=16.4' - xcode_path: '/Applications/Xcode_14.3.app' - + destination: ${{ env.DESTINATION }} + xcode_path: '/Applications/Xcode_${{ env.XCODE_VERSION }}.app' + datastore-stress-test: - needs: prepare-for-test + needs: get-platform-build-params runs-on: macos-13 environment: IntegrationTest + env: + DESTINATION: ${{ needs.get-platform-build-params.outputs.platform-params.destination }} + XCODE_VERSION: ${{ needs.get-platform-build-params.outputs.platform-params.xcode-version }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 with: @@ -138,13 +162,16 @@ jobs: with: project_path: ./AmplifyPlugins/DataStore/Tests/DataStoreHostApp scheme: DatastoreStressTests - destination: 'platform=iOS Simulator,name=iPhone 14,OS=16.4' - xcode_path: '/Applications/Xcode_14.3.app' + destination: ${{ env.DESTINATION }} + xcode_path: '/Applications/Xcode_${{ env.XCODE_VERSION }}.app' graphql-api-stress-test: - needs: prepare-for-test + needs: get-platform-build-params runs-on: macos-13 environment: IntegrationTest + env: + DESTINATION: ${{ needs.get-platform-build-params.outputs.platform-params.destination }} + XCODE_VERSION: ${{ needs.get-platform-build-params.outputs.platform-params.xcode-version }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 with: @@ -166,5 +193,5 @@ jobs: with: project_path: ./AmplifyPlugins/API/Tests/APIHostApp scheme: GraphQLAPIStressTests - destination: 'platform=iOS Simulator,name=iPhone 14,OS=16.4' - xcode_path: '/Applications/Xcode_14.3.app' \ No newline at end of file + destination: ${{ env.DESTINATION }} + xcode_path: '/Applications/Xcode_${{ env.XCODE_VERSION }}.app' \ No newline at end of file From 3b9772285d4d76ce935e7d5fc8cefaefe40e35a9 Mon Sep 17 00:00:00 2001 From: Di Wu Date: Fri, 12 Jan 2024 13:01:53 -0800 Subject: [PATCH 6/8] ci: fix stress test workflow (#3469) --- .github/workflows/stress_test.yml | 39 ++++++++++++++----------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/.github/workflows/stress_test.yml b/.github/workflows/stress_test.yml index acc637d883..32764beef5 100644 --- a/.github/workflows/stress_test.yml +++ b/.github/workflows/stress_test.yml @@ -16,6 +16,9 @@ jobs: prepare-for-test: runs-on: macos-13 environment: IntegrationTest + outputs: + destination: ${{ steps.platform.outputs.destination }} + xcode-version: ${{ steps.platform.outputs.xcode-version }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 with: @@ -29,12 +32,6 @@ jobs: aws_region: ${{ secrets.AWS_REGION }} aws_s3_bucket: ${{ secrets.AWS_S3_BUCKET_INTEG_V2 }} - get-platform-build-params: - runs-on: macos-13 - needs: prepare-for-test - outputs: - platform-params: ${{ steps.platform.outputs }} - steps: - name: Get build parameters id: platform uses: ./.github/composite_actions/get_platform_parameters @@ -42,12 +39,12 @@ jobs: platform: 'iOS' auth-stress-test: - needs: get-platform-build-params + needs: prepare-for-test runs-on: macos-13 environment: IntegrationTest env: - DESTINATION: ${{ needs.get-platform-build-params.outputs.platform-params.destination }} - XCODE_VERSION: ${{ needs.get-platform-build-params.outputs.platform-params.xcode-version }} + DESTINATION: ${{ needs.prepare-for-test.outputs.destination }} + XCODE_VERSION: ${{ needs.prepare-for-test.outputs.xcode-version }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 with: @@ -73,12 +70,12 @@ jobs: xcode_path: '/Applications/Xcode_${{ env.XCODE_VERSION }}.app' geo-stress-test: - needs: get-platform-build-params + needs: prepare-for-test runs-on: macos-13 environment: IntegrationTest env: - DESTINATION: ${{ needs.get-platform-build-params.outputs.platform-params.destination }} - XCODE_VERSION: ${{ needs.get-platform-build-params.outputs.platform-params.xcode-version }} + DESTINATION: ${{ needs.prepare-for-test.outputs.destination }} + XCODE_VERSION: ${{ needs.prepare-for-test.outputs.xcode-version }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 with: @@ -104,12 +101,12 @@ jobs: xcode_path: '/Applications/Xcode_${{ env.XCODE_VERSION }}.app' storage-stress-test: - needs: get-platform-build-params + needs: prepare-for-test runs-on: macos-13 environment: IntegrationTest env: - DESTINATION: ${{ needs.get-platform-build-params.outputs.platform-params.destination }} - XCODE_VERSION: ${{ needs.get-platform-build-params.outputs.platform-params.xcode-version }} + DESTINATION: ${{ needs.prepare-for-test.outputs.destination }} + XCODE_VERSION: ${{ needs.prepare-for-test.outputs.xcode-version }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 with: @@ -135,12 +132,12 @@ jobs: xcode_path: '/Applications/Xcode_${{ env.XCODE_VERSION }}.app' datastore-stress-test: - needs: get-platform-build-params + needs: prepare-for-test runs-on: macos-13 environment: IntegrationTest env: - DESTINATION: ${{ needs.get-platform-build-params.outputs.platform-params.destination }} - XCODE_VERSION: ${{ needs.get-platform-build-params.outputs.platform-params.xcode-version }} + DESTINATION: ${{ needs.prepare-for-test.outputs.destination }} + XCODE_VERSION: ${{ needs.prepare-for-test.outputs.xcode-version }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 with: @@ -166,12 +163,12 @@ jobs: xcode_path: '/Applications/Xcode_${{ env.XCODE_VERSION }}.app' graphql-api-stress-test: - needs: get-platform-build-params + needs: prepare-for-test runs-on: macos-13 environment: IntegrationTest env: - DESTINATION: ${{ needs.get-platform-build-params.outputs.platform-params.destination }} - XCODE_VERSION: ${{ needs.get-platform-build-params.outputs.platform-params.xcode-version }} + DESTINATION: ${{ needs.prepare-for-test.outputs.destination }} + XCODE_VERSION: ${{ needs.prepare-for-test.outputs.xcode-version }} steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 with: From a961c646d76bb25a8d68472f4d9baba0b627b76e Mon Sep 17 00:00:00 2001 From: Harsh <6162866+harsh62@users.noreply.github.com> Date: Mon, 15 Jan 2024 11:19:53 -0500 Subject: [PATCH 7/8] fix(Auth): Fix multiple continuation resumes in hostedUI (#3466) * fix(Auth): Fix multiple continuation resumes in hostedUI * use weak self. * updated with review comments * adding back return statements. * worked on review comment * fixing availability on iOS --- .../HostedUIASWebAuthenticationSession.swift | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/HostedUI/HostedUIASWebAuthenticationSession.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/HostedUI/HostedUIASWebAuthenticationSession.swift index 45cc3124c2..20f21d5262 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/HostedUI/HostedUIASWebAuthenticationSession.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Support/HostedUI/HostedUIASWebAuthenticationSession.swift @@ -24,14 +24,15 @@ class HostedUIASWebAuthenticationSession: NSObject, HostedUISessionBehavior { #if os(iOS) || os(macOS) self.webPresentation = presentationAnchor - return try await withCheckedThrowingContinuation { + return try await withCheckedThrowingContinuation { [weak self] (continuation: CheckedContinuation<[URLQueryItem], Error>) in + guard let self else { return } let aswebAuthenticationSession = createAuthenticationSession( url: url, callbackURLScheme: callbackScheme, - completionHandler: { url, error in - + completionHandler: { [weak self] url, error in + guard let self else { return } if let url = url { let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) let queryItems = urlComponents?.queryItems ?? [] @@ -44,9 +45,10 @@ class HostedUIASWebAuthenticationSession: NSObject, HostedUISessionBehavior { let message = "\(error) \(errorDescription)" return continuation.resume( throwing: HostedUIError.serviceMessage(message)) + } else { + return continuation.resume( + returning: queryItems) } - return continuation.resume( - returning: queryItems) } else if let error = error { return continuation.resume( throwing: self.convertHostedUIError(error)) @@ -59,7 +61,13 @@ class HostedUIASWebAuthenticationSession: NSObject, HostedUISessionBehavior { aswebAuthenticationSession.prefersEphemeralWebBrowserSession = inPrivate DispatchQueue.main.async { - aswebAuthenticationSession.start() + var canStart = true + if #available(macOS 10.15.4, iOS 13.4, *) { + canStart = aswebAuthenticationSession.canStart + } + if canStart { + aswebAuthenticationSession.start() + } } } From f9b02de67502f3536fbf36be9ae0ce214269e424 Mon Sep 17 00:00:00 2001 From: Harsh <6162866+harsh62@users.noreply.github.com> Date: Mon, 15 Jan 2024 11:38:54 -0500 Subject: [PATCH 8/8] fix(Auth): properly redacting session information (#3472) * fix(Auth): properly redacting session information * missing a bracket --- .../Task/Protocols/AmplifyAuthTask.swift | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/Protocols/AmplifyAuthTask.swift b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/Protocols/AmplifyAuthTask.swift index ecd2a9a15a..de7fec46ff 100644 --- a/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/Protocols/AmplifyAuthTask.swift +++ b/AmplifyPlugins/Auth/Sources/AWSCognitoAuthPlugin/Task/Protocols/AmplifyAuthTask.swift @@ -31,11 +31,11 @@ extension AmplifyAuthTask where Self: DefaultLogger { do { log.info("Starting execution for \(eventName)") let valueReturned = try await execute() - log.info("Successfully completed execution for \(eventName) with result:\n\(prettify(valueReturned))") + log.info("Successfully completed execution for \(eventName) with result:\n\(valueReturned)") dispatch(result: .success(valueReturned)) return valueReturned } catch let error as Failure { - log.error("Failed execution for \(eventName) with error:\n\(prettify(error))") + log.error("Failed execution for \(eventName) with error:\n\(error)") dispatch(result: .failure(error)) throw error } @@ -47,10 +47,4 @@ extension AmplifyAuthTask where Self: DefaultLogger { let payload = HubPayload(eventName: eventName, context: nil, data: result) Amplify.Hub.dispatch(to: channel, payload: payload) } - - private func prettify(_ value: T) -> String { - var result = "" - dump(value, to: &result) - return result - } }