Skip to content

Commit 5151046

Browse files
authored
chore: kickoff release
2 parents 4aa0e22 + 3b9ccc0 commit 5151046

File tree

6 files changed

+180
-13
lines changed

6 files changed

+180
-13
lines changed

.github/ISSUE_TEMPLATE/bug_report.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,15 @@ body:
9292
label: Relevant log output
9393
description: >-
9494
Include any relevant log output under
95-
`~/.amplify/logs/amplify-cli-<issue-date>.log`
95+
`~/.amplify/logs/amplify-cli-<issue-date>.log` (See: [Logs Guidance](https://github.com/aws-amplify/amplify-ios/blob/main/LogsGuidance.md))
96+
value: |
97+
<details>
98+
<summary>Log Messages</summary>
99+
100+
```
101+
INSERT LOG MESSAGES HERE
102+
```
103+
</details>
96104
render: shell
97105
- type: dropdown
98106
id: regression

AmplifyPlugins/Analytics/AWSPinpointAnalyticsPluginIntegrationTests/AWSPinpointAnalyticsPluginIntegrationTests.swift

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,40 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase {
7070
Amplify.Analytics.identifyUser(userId, withProfile: userProfile)
7171

7272
wait(for: [identifyUserEvent], timeout: TestCommonConstants.networkTimeout)
73+
74+
// Remove userId from the current endpoint
75+
let targetingClient = escapeHatch().targetingClient
76+
let currentProfile = targetingClient.currentEndpointProfile()
77+
currentProfile.user?.userId = ""
78+
targetingClient.update(currentProfile)
79+
}
80+
81+
/// Run this test when the number of endpoints for the userId exceeds the limit.
82+
/// The profile should have permissions to run the "mobiletargeting:DeleteUserEndpoints" action.
83+
func skip_testDeleteEndpointsForUser() throws {
84+
let userId = "userId"
85+
let escapeHatch = escapeHatch()
86+
let applicationId = escapeHatch.configuration.appId
87+
guard let targetingConfiguration = escapeHatch.configuration.targetingServiceConfiguration else {
88+
XCTFail("Targeting configuration is not defined.")
89+
return
90+
}
91+
92+
let deleteEndpointsRequest = AWSPinpointTargetingDeleteUserEndpointsRequest()!
93+
deleteEndpointsRequest.userId = userId
94+
deleteEndpointsRequest.applicationId = applicationId
95+
96+
let deleteExpectation = expectation(description: "Delete endpoints")
97+
let lowLevelClient = lowLevelClient(from: targetingConfiguration)
98+
lowLevelClient.deleteUserEndpoints(deleteEndpointsRequest) { response, error in
99+
guard error == nil else {
100+
XCTFail("Unexpected error when attempting to delete endpoints")
101+
deleteExpectation.fulfill()
102+
return
103+
}
104+
deleteExpectation.fulfill()
105+
}
106+
wait(for: [deleteExpectation], timeout: 1)
73107
}
74108

75109
func testRecordEventsAreFlushed() {
@@ -79,6 +113,7 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase {
79113
// TODO: Remove exposing AWSPinpointEvent
80114
guard let pinpointEvents = payload.data as? [AWSPinpointEvent] else {
81115
XCTFail("Missing data")
116+
flushEventsInvoked.fulfill()
82117
return
83118
}
84119
XCTAssertNotNil(pinpointEvents)
@@ -117,4 +152,17 @@ class AWSPinpointAnalyticsPluginIntergrationTests: XCTestCase {
117152
XCTAssertNotNil(awsPinpoint.configuration)
118153
XCTAssertTrue(awsPinpoint.configuration.enableAutoSessionRecording)
119154
}
155+
156+
private func escapeHatch() -> AWSPinpoint {
157+
guard let plugin = try? Amplify.Analytics.getPlugin(for: "awsPinpointAnalyticsPlugin"),
158+
let analyticsPlugin = plugin as? AWSPinpointAnalyticsPlugin else {
159+
fatalError("Unable to retrieve configuration")
160+
}
161+
return analyticsPlugin.getEscapeHatch()
162+
}
163+
164+
private func lowLevelClient(from configuration: AWSServiceConfiguration) -> AWSPinpointTargeting {
165+
AWSPinpointTargeting.register(with: configuration, forKey: "integrationTestsTargetingConfiguration")
166+
return AWSPinpointTargeting.init(forKey: "integrationTestsTargetingConfiguration")
167+
}
120168
}

AmplifyPlugins/Auth/AWSCognitoAuthPlugin/Dependency/AuthDeviceServiceAdapter.swift

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
//
77

88
import Amplify
9+
#if COCOAPODS
10+
import AWSMobileClient
11+
#else
12+
import AWSMobileClientXCF
13+
#endif
914

1015
struct AuthDeviceServiceAdapter: AuthDeviceServiceBehavior {
1116

@@ -19,8 +24,7 @@ struct AuthDeviceServiceAdapter: AuthDeviceServiceBehavior {
1924
completionHandler: @escaping (Result<[AuthDevice], AuthError>) -> Void) {
2025

2126
awsMobileClient.listDevices { result, error in
22-
if let error = error {
23-
let authError = AuthErrorHelper.toAuthError(error)
27+
if let authError = mapToAuthError(error) {
2428
completionHandler(.failure(authError))
2529
return
2630
}
@@ -42,8 +46,7 @@ struct AuthDeviceServiceAdapter: AuthDeviceServiceBehavior {
4246

4347
guard let device = request.device else {
4448
awsMobileClient.forgetCurrentDevice { error in
45-
if let error = error {
46-
let authError = AuthErrorHelper.toAuthError(error)
49+
if let authError = mapToAuthError(error) {
4750
completionHandler(.failure(authError))
4851
return
4952
}
@@ -52,8 +55,7 @@ struct AuthDeviceServiceAdapter: AuthDeviceServiceBehavior {
5255
return
5356
}
5457
awsMobileClient.forgetDevice(deviceId: device.id) { error in
55-
if let error = error {
56-
let authError = AuthErrorHelper.toAuthError(error)
58+
if let authError = mapToAuthError(error) {
5759
completionHandler(.failure(authError))
5860
return
5961
}
@@ -66,12 +68,29 @@ struct AuthDeviceServiceAdapter: AuthDeviceServiceBehavior {
6668
func rememberDevice(request: AuthRememberDeviceRequest,
6769
completionHandler: @escaping (Result<Void, AuthError>) -> Void) {
6870
awsMobileClient.updateDeviceStatus(remembered: true) { _, error in
69-
if let error = error {
70-
let authError = AuthErrorHelper.toAuthError(error)
71+
if let authError = mapToAuthError(error) {
7172
completionHandler(.failure(authError))
7273
return
7374
}
7475
completionHandler(.success(()))
7576
}
7677
}
78+
79+
private func mapToAuthError(_ error: Error?) -> AuthError? {
80+
guard let error = error else {
81+
return nil
82+
}
83+
84+
// `.notSignedIn` should be handled explicitly and not as part of AuthErrorHelper
85+
if let awsMobileClientError = error as? AWSMobileClientError,
86+
case .notSignedIn = awsMobileClientError {
87+
return AuthError.signedOut(
88+
AuthPluginErrorConstants.userSignedOutError.errorDescription,
89+
AuthPluginErrorConstants.userSignedOutError.recoverySuggestion,
90+
error
91+
)
92+
} else {
93+
return AuthErrorHelper.toAuthError(error)
94+
}
95+
}
7796
}

AmplifyPlugins/Auth/AWSCognitoAuthPlugin/Support/Constants/AuthPluginErrorConstants.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ struct AuthPluginErrorConstants {
143143
static let changePasswordUnableToSignInError: AuthPluginErrorString = (
144144
"Could not change password, the user session is expired",
145145
"Re-authenticate the user by using one of the signIn apis")
146+
147+
static let userSignedOutError: AuthPluginErrorString = (
148+
"There is no user signed in to the Auth category",
149+
"SignIn to Auth category by using one of the sign in methods and then try again")
146150
}
147151

148152
// Field validation errors

AmplifyPlugins/Auth/AWSCognitoAuthPluginIntegrationTests/AuthDeviceTests/AuthDeviceOperationTests.swift

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@
77

88
import XCTest
99
@testable import Amplify
10+
import AmplifyTestCommon
1011
import AWSCognitoAuthPlugin
12+
#if COCOAPODS
13+
import AWSMobileClient
14+
#else
15+
import AWSMobileClientXCF
16+
#endif
1117

1218
class AuthDeviceOperationTests: AWSAuthBaseTest {
1319

@@ -22,20 +28,60 @@ class AuthDeviceOperationTests: AWSAuthBaseTest {
2228
sleep(2)
2329
}
2430

31+
/// Test if forgetDevice returns deviceNotTracked error for a signed out user
32+
///
33+
/// - Given: A test with the user not signed in
34+
/// - When:
35+
/// - I invoke forgetDevice
36+
/// - Then:
37+
/// - I should get a notSignedIn error.
38+
///
39+
func testForgetDeviceWithSignedOutUser() {
40+
let forgetDeviceExpectation = expectation(description: "Received event result from forgetDevice")
41+
_ = Amplify.Auth.forgetDevice { result in
42+
forgetDeviceExpectation.fulfill()
43+
switch result {
44+
case .success:
45+
XCTFail("Forget device with signed out user should not return success")
46+
case .failure(let error):
47+
guard let cognitoError = error.underlyingError as? AWSMobileClientError,
48+
case .notSignedIn = cognitoError else {
49+
XCTFail("Should return notSignedIn")
50+
return
51+
}
52+
}
53+
}
54+
wait(for: [forgetDeviceExpectation], timeout: networkTimeout)
55+
}
56+
2557
/// Test if forgetDevice returns deviceNotTracked error for a unknown device
2658
///
27-
/// - Given: A test with the device not tracked
59+
/// - Given: A test with a device not tracked
2860
/// - When:
2961
/// - I invoke forgetDevice
3062
/// - Then:
3163
/// - I should get a deviceNotTracked error.
3264
///
33-
func testForgetDeviceWithUnknowdevice() {
65+
func testForgetDeviceWithUntrackedDevice() {
66+
let username = "integTest\(UUID().uuidString)"
67+
let password = "P123@\(UUID().uuidString)"
68+
let signInExpectation = expectation(description: "SignIn operation should complete")
69+
AuthSignInHelper.registerAndSignInUser(username: username, password: password,
70+
email: email) { didSucceed, error in
71+
signInExpectation.fulfill()
72+
XCTAssertTrue(didSucceed, "SignIn operation failed - \(String(describing: error))")
73+
}
74+
wait(for: [signInExpectation], timeout: networkTimeout)
75+
76+
let user = Amplify.Auth.getCurrentUser()
77+
XCTAssertNotNil(user)
78+
3479
let forgetDeviceExpectation = expectation(description: "Received event result from forgetDevice")
3580
_ = Amplify.Auth.forgetDevice { result in
81+
forgetDeviceExpectation.fulfill()
3682
switch result {
3783
case .success:
38-
XCTFail("Confirm signUp with non existing user should not return result")
84+
XCTFail("Forget device with untracked device should not return result")
3985
case .failure(let error):
4086
guard let cognitoError = error.underlyingError as? AWSCognitoAuthError,
4187
case .deviceNotTracked = cognitoError else {
@@ -44,7 +90,6 @@ class AuthDeviceOperationTests: AWSAuthBaseTest {
4490
}
4591

4692
}
47-
forgetDeviceExpectation.fulfill()
4893
}
4994
wait(for: [forgetDeviceExpectation], timeout: networkTimeout)
5095
}

LogsGuidance.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Logs Guidance
2+
3+
When providing logs in an issue please follow these recommendations.
4+
5+
1. Use an editor to clear out any sensitive information.
6+
2. Remove lines which are not relevant to the problem.
7+
3. Place the logs in the markdown syntax below.
8+
9+
## Screenshots vs Text Logs
10+
11+
Sharing logs as text will make it possible to search for log messages across issues and to trim logs to the relevant details. Collect logs from Xcode Console or the Console app by highlighting lines and copying them to an editor where the text can be prepared for sharing in a new issue.
12+
13+
### Stack Frames
14+
15+
To collect details about the stack frames while debugging, also copy lines from the Xcode Debug Navigator by selecting the stack frames and copying the text to an editor. Showing stack frames shows the backtrace of function calls which is helpful in understanding the context. You can also set a breakpoint which will run a Debugger Command such as `bt 5` which will print 5 of the backtrace from that point where the breakpoint is set. This text will appear in the Xcode Console where it can be copied with other log messages to provide useful context for resolving the issue.
16+
17+
1. Add a breakpoint to where you want to include more context
18+
2. Edit the breakpoint and select the checkbox at the bottom to automatically continue
19+
3. Add an Action which will be a Debugger Command
20+
4. Add `bt 5` to print the last 5 lines of the backtrace to the console
21+
5. Optionally also add action to log a message which can include an expression
22+
23+
Like the watch window displayed while debugging, a log message from a breakpoint can evalulate an expression to print out those details in the Xcode console. For a variable named `info`, simply add `@info@` to the log message text field. You may want to add debugging features to your code which can provide a string or dictionary which provides useful information which can be used when logging from a breakpoint.
24+
25+
## Sensitive Information
26+
27+
Logs should be trimmed of details which should not be shared publicly, such as user names and credentials. Use an editor to find references using either a keyword search or regular expression and either delete that information or replace it with placeholder text if it helps provide context.
28+
29+
## Collapsible details in markdown
30+
31+
Including a lot of log messages in a GitHub issue is helpful but also requires a lot of scrolling. It can be difficult to also copy that log to an editor to filter to the most useful details. GitHub markdown supports collapsing details with the syntax below. It is just the `<details>` tags which must include a `<summary>` tag at the start.
32+
33+
Beyond just making it possible to collapse the details, n button appears at the top right when it is expanded to let you copy to your clipboard making it easy to bring it to an editor.
34+
35+
````markdown
36+
<details>
37+
<summary>Log Messages</summary>
38+
39+
```
40+
INSERT LOG MESSAGES HERE
41+
```
42+
</details>
43+
````

0 commit comments

Comments
 (0)