Skip to content

Commit 871a55d

Browse files
authored
chore: kickoff v1 release
2 parents e99749e + b00e1d7 commit 871a55d

File tree

16 files changed

+734
-110
lines changed

16 files changed

+734
-110
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,9 @@
1313
- [ ] PR title conforms to conventional commit style
1414
- [ ] If breaking change, documentation/changelog update with migration instructions
1515

16+
*DataStore checkpoints (check when completed)*
17+
18+
- [ ] Ran AWSDataStorePluginIntegrationTests (includes V2 and CPK)
19+
- [ ] Ran AWSDataStorePluginAuthIntegrationTests (includes MultiAuth, Cognito Auth, IAM Auth)
20+
1621
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

AmplifyPlugins/Analytics/AWSPinpointAnalyticsPlugin/AWSPinpointAnalyticsPlugin+ClientBehavior.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,14 @@ extension AWSPinpointAnalyticsPlugin {
107107
}
108108

109109
pinpoint.submitEvents().continueWith { (task) -> Any? in
110-
guard task.error == nil else {
111-
// TODO: some error mapping
112-
let error = task.error! as NSError
110+
if let error = task.error as? NSError{
111+
// For "No events to submit" errors, dispatch and empty array instead
112+
if error.domain == AWSPinpointAnalyticsErrorDomain,
113+
error.localizedDescription == "No events to submit." {
114+
Amplify.Hub.dispatchFlushEvents([])
115+
return nil
116+
}
117+
113118
Amplify.Hub.dispatchFlushEvents(AnalyticsErrorHelper.getDefaultError(error))
114119
return nil
115120
}

AmplifyPlugins/Analytics/AWSPinpointAnalyticsPlugin/Support/Constants/AnalyticsErrorConstants.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,9 @@ struct AnalyticsPluginErrorConstant {
9797
"Could not instantiate service configuration from pinpoint targeting region",
9898
"Make sure the pinpoint targeting region and cognito credentials provider are correct"
9999
)
100+
101+
static let deviceOffline: AnalyticsPluginErrorString = (
102+
"The device does not have internet access. Please ensure the device is online and try again.",
103+
""
104+
)
100105
}

AmplifyPlugins/Analytics/AWSPinpointAnalyticsPlugin/Support/Utils/AnalyticsErrorHelper.swift

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ import Foundation
1010

1111
class AnalyticsErrorHelper {
1212
static func getDefaultError(_ error: NSError) -> AnalyticsError {
13+
if error.isConnectivityError {
14+
return .unknown(
15+
AnalyticsPluginErrorConstant.deviceOffline.errorDescription,
16+
error
17+
)
18+
}
19+
1320
let errorMessage = """
1421
Domain: [\(error.domain)
1522
Code: [\(error.code)
@@ -18,6 +25,20 @@ class AnalyticsErrorHelper {
1825
LocalizedRecoverySuggestion: [\(error.localizedRecoverySuggestion ?? "")
1926
"""
2027

21-
return AnalyticsError.unknown(errorMessage)
28+
return AnalyticsError.unknown(errorMessage, error)
29+
}
30+
}
31+
32+
private extension NSError {
33+
private static let networkErrorCodes = [
34+
NSURLErrorCannotFindHost,
35+
NSURLErrorCannotConnectToHost,
36+
NSURLErrorNetworkConnectionLost,
37+
NSURLErrorDNSLookupFailed,
38+
NSURLErrorNotConnectedToInternet
39+
]
40+
41+
var isConnectivityError: Bool {
42+
return Self.networkErrorCodes.contains(where: { $0 == code })
2243
}
2344
}

AmplifyPlugins/Analytics/AWSPinpointAnalyticsPluginTests/AWSPinpointAnalyticsPluginClientBehaviorTests.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,34 @@ class AWSPinpointAnalyticsPluginClientBehaviorTests: AWSPinpointAnalyticsPluginT
350350
waitForExpectations(timeout: 1)
351351
}
352352

353+
/// Given: AWSPinpoint.submitEvents returns a "No events to submit." error
354+
/// When: AnalyticsPlugin.flushEvents is invoked
355+
/// Then: AWSPinpoint.submitEvents is invoked
356+
/// and Hub Analytics.flushEvents event is dispatched with an empty array of events
357+
func testFlushEvents_noEvents() {
358+
let error = NSError(domain: AWSPinpointAnalyticsErrorDomain,
359+
code: AWSPinpointAnalyticsErrorType.unknown.rawValue,
360+
userInfo: [NSLocalizedDescriptionKey: "No events to submit."])
361+
mockPinpoint.submitEventsResult = AWSTask<AnyObject>.init(error: error)
362+
let methodWasInvokedOnPlugin = expectation(description: "method was invoked on plugin")
363+
364+
_ = plugin.listen(to: .analytics, isIncluded: nil) { payload in
365+
if payload.eventName == HubPayload.EventName.Analytics.flushEvents {
366+
methodWasInvokedOnPlugin.fulfill()
367+
guard let pinpointEvents = payload.data as? [AWSPinpointEvent] else {
368+
XCTFail("Missing data")
369+
return
370+
}
371+
372+
XCTAssertTrue(pinpointEvents.isEmpty)
373+
}
374+
}
375+
376+
analyticsPlugin.flushEvents()
377+
mockPinpoint.verifySubmitEvents()
378+
waitForExpectations(timeout: 1)
379+
}
380+
353381
/// Given: AnalyticsPlugin is disabled
354382
/// When: AnalyticsPlugin.flushEvents is invoked
355383
/// Then: AWSPinpoint.submitEvents is not called

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/AWSDataStorePlugin+DataStoreBaseBehavior.swift

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -281,14 +281,17 @@ extension AWSDataStorePlugin: DataStoreBaseBehavior {
281281
dispatchedModelSynced.set(false)
282282
}
283283
if storageEngine == nil {
284-
285-
completion(.successfulVoid)
284+
queue.async {
285+
completion(.successfulVoid)
286+
}
286287
return
287288
}
288289

289290
storageEngine.stopSync { result in
290291
self.storageEngine = nil
291-
completion(result)
292+
self.queue.async {
293+
completion(result)
294+
}
292295
}
293296
}
294297
}
@@ -309,12 +312,16 @@ extension AWSDataStorePlugin: DataStoreBaseBehavior {
309312
dispatchedModelSynced.set(false)
310313
}
311314
if storageEngine == nil {
312-
completion(.successfulVoid)
315+
queue.async {
316+
completion(.successfulVoid)
317+
}
313318
return
314319
}
315320
storageEngine.clear { result in
316321
self.storageEngine = nil
317-
completion(result)
322+
self.queue.async {
323+
completion(result)
324+
}
318325
}
319326
}
320327
}

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/AWSDataStorePlugin.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ final public class AWSDataStorePlugin: DataStoreCategoryPlugin {
4646

4747
var storageEngine: StorageEngineBehavior!
4848
var storageEngineInitQueue = DispatchQueue(label: "AWSDataStorePlugin.storageEngineInitQueue")
49+
let queue = DispatchQueue(label: "AWSDataStorePlugin.queue", target: DispatchQueue.global())
4950
var storageEngineBehaviorFactory: StorageEngineBehaviorFactory
5051

5152
var iStorageEngineSink: Any?

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/MutationSync/OutgoingMutationQueue/ProcessMutationErrorFromCloudOperation.swift

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,25 +55,42 @@ class ProcessMutationErrorFromCloudOperation: AsynchronousOperation {
5555
return
5656
}
5757

58-
if let apiError = apiError, isAuthSignedOutError(apiError: apiError) {
58+
if let apiError = apiError {
59+
if isAuthSignedOutError(apiError: apiError) {
60+
log.verbose("User is signed out, passing error back to the error handler, and removing mutation event.")
61+
} else if let underlyingError = apiError.underlyingError {
62+
log.debug("Received APIError: \(apiError.localizedDescription) with underlying error: \(underlyingError.localizedDescription)")
63+
} else {
64+
log.debug("Received APIError: \(apiError.localizedDescription)")
65+
}
5966
dataStoreConfiguration.errorHandler(DataStoreError.api(apiError, mutationEvent))
6067
finish(result: .success(nil))
6168
return
6269
}
6370

64-
guard let graphQLResponseError = graphQLResponseError,
65-
case let .error(graphQLErrors) = graphQLResponseError else {
66-
finish(result: .success(nil))
67-
return
71+
guard let graphQLResponseError = graphQLResponseError else {
72+
dataStoreConfiguration.errorHandler(
73+
DataStoreError.api(APIError.unknown("This is unexpected. Missing APIError and GraphQLError.", ""),
74+
mutationEvent))
75+
finish(result: .success(nil))
76+
return
77+
}
78+
79+
guard case let .error(graphQLErrors) = graphQLResponseError else {
80+
dataStoreConfiguration.errorHandler(DataStoreError.api(graphQLResponseError, mutationEvent))
81+
finish(result: .success(nil))
82+
return
6883
}
6984

7085
guard graphQLErrors.count == 1 else {
7186
log.error("Received more than one error response: \(String(describing: graphQLResponseError))")
87+
dataStoreConfiguration.errorHandler(DataStoreError.api(graphQLResponseError, mutationEvent))
7288
finish(result: .success(nil))
7389
return
7490
}
7591

7692
guard let graphQLError = graphQLErrors.first else {
93+
dataStoreConfiguration.errorHandler(DataStoreError.api(graphQLResponseError, mutationEvent))
7794
finish(result: .success(nil))
7895
return
7996
}
@@ -85,22 +102,26 @@ class ProcessMutationErrorFromCloudOperation: AsynchronousOperation {
85102
let payload = HubPayload(eventName: HubPayload.EventName.DataStore.conditionalSaveFailed,
86103
data: mutationEvent)
87104
Amplify.Hub.dispatch(to: .dataStore, payload: payload)
105+
dataStoreConfiguration.errorHandler(DataStoreError.api(graphQLResponseError, mutationEvent))
88106
finish(result: .success(nil))
89107
case .conflictUnhandled:
90108
processConflictUnhandled(extensions)
91109
case .unauthorized:
92-
// TODO: dispatch Hub event
93110
log.debug("Unauthorized mutation \(errorType)")
111+
dataStoreConfiguration.errorHandler(DataStoreError.api(graphQLResponseError, mutationEvent))
94112
finish(result: .success(nil))
95113
case .operationDisabled:
96114
log.debug("Operation disabled \(errorType)")
115+
dataStoreConfiguration.errorHandler(DataStoreError.api(graphQLResponseError, mutationEvent))
97116
finish(result: .success(nil))
98117
case .unknown(let errorType):
99118
log.debug("Unhandled error with errorType \(errorType)")
119+
dataStoreConfiguration.errorHandler(DataStoreError.api(graphQLResponseError, mutationEvent))
100120
finish(result: .success(nil))
101121
}
102122
} else {
103123
log.debug("GraphQLError missing extensions and errorType \(graphQLError)")
124+
dataStoreConfiguration.errorHandler(DataStoreError.api(graphQLResponseError, mutationEvent))
104125
finish(result: .success(nil))
105126
}
106127
}

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/RequestRetryablePolicy.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ class RequestRetryablePolicy: RequestRetryable {
3838
.cannotConnectToHost,
3939
.cannotFindHost,
4040
.timedOut,
41-
.dataNotAllowed:
41+
.dataNotAllowed,
42+
.cannotParseResponse:
4243
let waitMillis = retryDelayInMillseconds(for: attemptNumber)
4344
return RequestRetryAdvice(shouldRetry: true, retryInterval: .milliseconds(waitMillis))
4445
default:

0 commit comments

Comments
 (0)