Skip to content

Commit 027140b

Browse files
authored
feat(datastore): process OperationDisabled error (#1104)
* feat(datastore): process OperationDisabled errors * feat(datastore): process OperationDisabled errors tests * test(datastore): AppSyncErrorType tests * test(datastore): ProcessMutationErrorFromCloudOperation test * chore(datastore): reduce swiftlint warnings * test(datastore): add AWSIncomingEventReconciliationQueue tests * chore(datastore): OperationDisabled error * test(datastore): add AWSModelReconciliationQueue tests * test(datastore): add AWSModelReconciliationQueue failure tests
1 parent 3eb7f48 commit 027140b

File tree

10 files changed

+279
-35
lines changed

10 files changed

+279
-35
lines changed

Amplify.xcodeproj/project.pbxproj

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,10 @@
140140
21A4ED5E259CD7F400E1047D /* CoreError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21A4ED5D259CD7F400E1047D /* CoreError.swift */; };
141141
21A4ED6E259CDA4600E1047D /* List+LazyLoad.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21A4ED6D259CDA4600E1047D /* List+LazyLoad.swift */; };
142142
21A4ED77259CDF6800E1047D /* List+Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21A4ED76259CDF6800E1047D /* List+Combine.swift */; };
143-
21A7C8AA25ACB6C8004355D6 /* ArrayLiteralListProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21A7C8A925ACB6C8004355D6 /* ArrayLiteralListProviderTests.swift */; };
144-
21A7C90225ACC4D1004355D6 /* MockDataStoreResponders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21A7C90125ACC4D1004355D6 /* MockDataStoreResponders.swift */; };
145143
21A4F26325A3CD3D00E1047D /* List+Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21A4F26225A3CD3D00E1047D /* List+Pagination.swift */; };
146144
21A4F8F325A77D9100E1047D /* ListPaginationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21A4F8F225A77D9100E1047D /* ListPaginationTests.swift */; };
145+
21A7C8AA25ACB6C8004355D6 /* ArrayLiteralListProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21A7C8A925ACB6C8004355D6 /* ArrayLiteralListProviderTests.swift */; };
146+
21A7C90225ACC4D1004355D6 /* MockDataStoreResponders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21A7C90125ACC4D1004355D6 /* MockDataStoreResponders.swift */; };
147147
21AD424B249BF0DA0016FE95 /* AnyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FACBAD522386160100E29E56 /* AnyModel.swift */; };
148148
21AD424C249BF0DE0016FE95 /* AnyModel+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA8EE776238626D60097E4F1 /* AnyModel+Codable.swift */; };
149149
21AD424D249BF0E50016FE95 /* AnyModel+Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA8EE78223862DDB0097E4F1 /* AnyModel+Schema.swift */; };
@@ -227,6 +227,8 @@
227227
6BEE081D2533CCFA00133961 /* OGCScenarioBPost.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BEE081B2533CCFA00133961 /* OGCScenarioBPost.swift */; };
228228
6BEE08242533D30800133961 /* OGCScenarioBMGroupPost.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BEE08222533D30800133961 /* OGCScenarioBMGroupPost.swift */; };
229229
6BEE08252533D30800133961 /* OGCScenarioBMGroupPost+Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BEE08232533D30800133961 /* OGCScenarioBMGroupPost+Schema.swift */; };
230+
7678B38426017D5300B4917F /* AppSyncErrorTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7678B38326017D5300B4917F /* AppSyncErrorTypeTests.swift */; };
231+
7678B38526017D5300B4917F /* AppSyncErrorTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7678B38326017D5300B4917F /* AppSyncErrorTypeTests.swift */; };
230232
7D5ED6C78E25246DDAF2F2EC /* Pods_Amplify.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84F3A76FB68CEFA45F4BB1BB /* Pods_Amplify.framework */; platformFilter = ios; };
231233
7F27B1DCE59C1E674172CCD6 /* Pods_Amplify_AmplifyTestConfigs_AmplifyTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 976D972EC2BBCAAD023694EB /* Pods_Amplify_AmplifyTestConfigs_AmplifyTests.framework */; };
232234
881246F5DCC59436DC932469 /* Pods_Amplify_AWSPluginsCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 35D92182B8445C8F9B0FAE94 /* Pods_Amplify_AWSPluginsCore.framework */; };
@@ -946,10 +948,10 @@
946948
21A4ED5D259CD7F400E1047D /* CoreError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreError.swift; sourceTree = "<group>"; };
947949
21A4ED6D259CDA4600E1047D /* List+LazyLoad.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "List+LazyLoad.swift"; sourceTree = "<group>"; };
948950
21A4ED76259CDF6800E1047D /* List+Combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "List+Combine.swift"; sourceTree = "<group>"; };
949-
21A7C8A925ACB6C8004355D6 /* ArrayLiteralListProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayLiteralListProviderTests.swift; sourceTree = "<group>"; };
950-
21A7C90125ACC4D1004355D6 /* MockDataStoreResponders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDataStoreResponders.swift; sourceTree = "<group>"; };
951951
21A4F26225A3CD3D00E1047D /* List+Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "List+Pagination.swift"; sourceTree = "<group>"; };
952952
21A4F8F225A77D9100E1047D /* ListPaginationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListPaginationTests.swift; sourceTree = "<group>"; };
953+
21A7C8A925ACB6C8004355D6 /* ArrayLiteralListProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayLiteralListProviderTests.swift; sourceTree = "<group>"; };
954+
21A7C90125ACC4D1004355D6 /* MockDataStoreResponders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDataStoreResponders.swift; sourceTree = "<group>"; };
953955
21AD4255249BFFDF0016FE95 /* DeprecatedTodo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DeprecatedTodo.swift; path = Deprecated/DeprecatedTodo.swift; sourceTree = "<group>"; };
954956
21C395B2245729EC00597EA2 /* AppSyncErrorType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSyncErrorType.swift; sourceTree = "<group>"; };
955957
21D79FD9237617C60057D00D /* SubscriptionEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionEvent.swift; sourceTree = "<group>"; };
@@ -1087,6 +1089,7 @@
10871089
71B6F506E5F3F00B0743A9BF /* Pods-Amplify-AWSPluginsCore-AWSPluginsTestConfigs-AWSPluginsTestCommon.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Amplify-AWSPluginsCore-AWSPluginsTestConfigs-AWSPluginsTestCommon.debug.xcconfig"; path = "Target Support Files/Pods-Amplify-AWSPluginsCore-AWSPluginsTestConfigs-AWSPluginsTestCommon/Pods-Amplify-AWSPluginsCore-AWSPluginsTestConfigs-AWSPluginsTestCommon.debug.xcconfig"; sourceTree = "<group>"; };
10881090
73C2E5FA55C85539AD9E39EE /* Pods_Amplify_AWSPluginsCore_CoreMLPredictionsPlugin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Amplify_AWSPluginsCore_CoreMLPredictionsPlugin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
10891091
7503342A8C13588E2B0DDBDE /* Pods-AmplifyFunctionalTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AmplifyFunctionalTests.debug.xcconfig"; path = "Target Support Files/Pods-AmplifyFunctionalTests/Pods-AmplifyFunctionalTests.debug.xcconfig"; sourceTree = "<group>"; };
1092+
7678B38326017D5300B4917F /* AppSyncErrorTypeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSyncErrorTypeTests.swift; sourceTree = "<group>"; };
10901093
77A2D125114EA0FFA11A7EFD /* Pods-AmplifyTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AmplifyTests.debug.xcconfig"; path = "Target Support Files/Pods-AmplifyTests/Pods-AmplifyTests.debug.xcconfig"; sourceTree = "<group>"; };
10911094
7A238096BAB328655B5E388F /* Pods-Amplify-AWSPluginsCore-CoreMLPredictionsPlugin.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Amplify-AWSPluginsCore-CoreMLPredictionsPlugin.debug.xcconfig"; path = "Target Support Files/Pods-Amplify-AWSPluginsCore-CoreMLPredictionsPlugin/Pods-Amplify-AWSPluginsCore-CoreMLPredictionsPlugin.debug.xcconfig"; sourceTree = "<group>"; };
10921095
7A7FD9B3CFF63FD16788A990 /* Pods-Amplify-AmplifyAWSPlugins-AWSPluginsCore-AWSPinpointAnalyticsPlugin-AWSPinpointAnalyticsPluginTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Amplify-AmplifyAWSPlugins-AWSPluginsCore-AWSPinpointAnalyticsPlugin-AWSPinpointAnalyticsPluginTests.release.xcconfig"; path = "Target Support Files/Pods-Amplify-AmplifyAWSPlugins-AWSPluginsCore-AWSPinpointAnalyticsPlugin-AWSPinpointAnalyticsPluginTests/Pods-Amplify-AmplifyAWSPlugins-AWSPluginsCore-AWSPinpointAnalyticsPlugin-AWSPinpointAnalyticsPluginTests.release.xcconfig"; sourceTree = "<group>"; };
@@ -2421,6 +2424,14 @@
24212424
path = Auth;
24222425
sourceTree = "<group>";
24232426
};
2427+
7678B38226017D2900B4917F /* API */ = {
2428+
isa = PBXGroup;
2429+
children = (
2430+
7678B38326017D5300B4917F /* AppSyncErrorTypeTests.swift */,
2431+
);
2432+
path = API;
2433+
sourceTree = "<group>";
2434+
};
24242435
95DAAB00237E63370028544F /* Models */ = {
24252436
isa = PBXGroup;
24262437
children = (
@@ -3096,6 +3107,7 @@
30963107
FA131AB82360FE070008381C /* AWSPluginsCoreTests */ = {
30973108
isa = PBXGroup;
30983109
children = (
3110+
7678B38226017D2900B4917F /* API */,
30993111
6BEE0815253114E600133961 /* Auth */,
31003112
FA131ABB2360FE070008381C /* Info.plist */,
31013113
2129BE2223948085006363A1 /* Model */,
@@ -4710,6 +4722,7 @@
47104722
6B9F7C5225267E1500F1F71C /* MockAWSAuthUser.swift in Sources */,
47114723
6B5087CD25673AC8000AB673 /* QueryPredicateEvaluateGeneratedTimeTests.swift in Sources */,
47124724
21AD425A249C0D910016FE95 /* AnyModelTester.swift in Sources */,
4725+
7678B38526017D5300B4917F /* AppSyncErrorTypeTests.swift in Sources */,
47134726
6BDF15B62541262000B5BE69 /* ModelWithOwnerAuthAndGroupWithGroupClaim.swift in Sources */,
47144727
2129BE3C2394828B006363A1 /* GraphQLRequestModelTests.swift in Sources */,
47154728
2183A56523EA4A8400232880 /* GraphQLListQueryTests.swift in Sources */,
@@ -5184,6 +5197,7 @@
51845197
FA47B8362350C2D60031A0E3 /* AutoUnsubscribeOperationTests.swift in Sources */,
51855198
976D4D5124DC8A370083F5AC /* GestureRecognizerTests.swift in Sources */,
51865199
B4F3E9F824314E2B00F23296 /* AuthCategoryConfigurationTests.swift in Sources */,
5200+
7678B38426017D5300B4917F /* AppSyncErrorTypeTests.swift in Sources */,
51875201
FA1C80D6258688BD006160E9 /* DefaultLoggingPluginAmplifyVersionableTests.swift in Sources */,
51885202
FAC2356E227A056600424678 /* AnalyticsCategoryClientAPITests.swift in Sources */,
51895203
B4BD6B3323708C0000A1F0A7 /* PredictionsCategoryClientAPITests.swift in Sources */,

AmplifyPlugins/Core/AWSPluginsCore/API/AppSyncErrorType.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public enum AppSyncErrorType: Equatable {
1313
private static let conditionalCheckFailedErrorString = "ConditionalCheckFailedException"
1414
private static let conflictUnhandledErrorString = "ConflictUnhandled"
1515
private static let unauthorizedErrorString = "Unauthorized"
16+
private static let operationDisabledErrorString = "OperationDisabled"
1617

1718
/// Conflict detection finds a version mismatch and the conflict handler rejects the mutation.
1819
/// See https://docs.aws.amazon.com/appsync/latest/devguide/conflict-detection-and-sync.html for more information
@@ -22,6 +23,11 @@ public enum AppSyncErrorType: Equatable {
2223

2324
case unauthorized
2425

26+
/// This error is not for general use unless you have consulted directly with AWS.
27+
/// When DataStore encounters this error, it will ignore it and continue running.
28+
/// This error is subject to be **deprecated/removed** in the future.
29+
case operationDisabled
30+
2531
case unknown(String)
2632

2733
public init(_ value: String) {
@@ -32,6 +38,8 @@ public enum AppSyncErrorType: Equatable {
3238
self = .conflictUnhandled
3339
case AppSyncErrorType.unauthorizedErrorString:
3440
self = .unauthorized
41+
case AppSyncErrorType.operationDisabledErrorString:
42+
self = .operationDisabled
3543
default:
3644
self = .unknown(value)
3745
}
@@ -45,6 +53,8 @@ public enum AppSyncErrorType: Equatable {
4553
return AppSyncErrorType.conflictUnhandledErrorString
4654
case .unauthorized:
4755
return AppSyncErrorType.unauthorizedErrorString
56+
case .operationDisabled:
57+
return AppSyncErrorType.operationDisabledErrorString
4858
case .unknown(let value):
4959
return value
5060
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
import XCTest
9+
@testable import Amplify
10+
@testable import AWSPluginsCore
11+
12+
class AppSyncErrorTypeTests: XCTestCase {
13+
func testAppSyncErrorTypeFromErrorString() {
14+
let errorTypes: [String: AppSyncErrorType] = [
15+
AppSyncErrorType.conflictUnhandled.rawValue: .conflictUnhandled,
16+
AppSyncErrorType.conditionalCheck.rawValue: .conditionalCheck,
17+
AppSyncErrorType.unauthorized.rawValue: .unauthorized,
18+
AppSyncErrorType.operationDisabled.rawValue: .operationDisabled,
19+
"unknownError": .unknown("unknownError")
20+
]
21+
for error in errorTypes {
22+
XCTAssertEqual(error.value, AppSyncErrorType(error.key))
23+
}
24+
}
25+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ class ProcessMutationErrorFromCloudOperation: AsynchronousOperation {
9292
// TODO: dispatch Hub event
9393
log.debug("Unauthorized mutation \(errorType)")
9494
finish(result: .success(nil))
95+
case .operationDisabled:
96+
log.debug("Operation disabled \(errorType)")
97+
finish(result: .success(nil))
9598
case .unknown(let errorType):
9699
log.debug("Unhandled error with errorType \(errorType)")
97100
finish(result: .success(nil))

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/SubscriptionSync/AWSIncomingEventReconciliationQueue.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import AWSPluginsCore
1010
import Combine
1111
import Foundation
1212

13-
//Used for testing:
13+
// Used for testing:
1414
@available(iOS 13.0, *)
1515
typealias IncomingEventReconciliationQueueFactory =
1616
([ModelSchema],
@@ -60,7 +60,7 @@ final class AWSIncomingEventReconciliationQueue: IncomingEventReconciliationQueu
6060
self.reconciliationQueueConnectionStatus = [:]
6161
self.modelReconciliationQueueFactory = modelReconciliationQueueFactory ??
6262
AWSModelReconciliationQueue.init(modelSchema:storageAdapter:api:modelPredicate:auth:incomingSubscriptionEvents:)
63-
//TODO: Add target for SyncEngine system to help prevent thread explosion and increase performance
63+
// TODO: Add target for SyncEngine system to help prevent thread explosion and increase performance
6464
// https://github.com/aws-amplify/amplify-ios/issues/399
6565
self.connectionStatusSerialQueue
6666
= DispatchQueue(label: "com.amazonaws.DataStore.AWSIncomingEventReconciliationQueue")
@@ -132,7 +132,8 @@ final class AWSIncomingEventReconciliationQueue: IncomingEventReconciliationQueu
132132
self.eventReconciliationQueueTopic.send(.initialized)
133133
}
134134
}
135-
case .disconnected(modelName: let modelName, reason: .unauthorized):
135+
case .disconnected(modelName: let modelName, reason: .operationDisabled),
136+
.disconnected(modelName: let modelName, reason: .unauthorized):
136137
connectionStatusSerialQueue.async {
137138
self.reconciliationQueues[modelName]?.cancel()
138139
self.modelReconciliationQueueSinks[modelName]?.cancel()

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/SubscriptionSync/ReconcileAndLocalSave/AWSModelReconciliationQueue.swift

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,11 @@ final class AWSModelReconciliationQueue: ModelReconciliationQueue {
184184
modelReconciliationQueueSubject.send(.disconnected(modelName: modelSchema.name, reason: .unauthorized))
185185
return
186186
}
187+
if case let .api(error, _) = dataStoreError,
188+
case let APIError.operationError(_, _, underlyingError) = error, isOperationDisabledError(underlyingError) {
189+
modelReconciliationQueueSubject.send(.disconnected(modelName: modelSchema.name, reason: .operationDisabled))
190+
return
191+
}
187192
log.error("receiveCompletion: error: \(dataStoreError)")
188193
modelReconciliationQueueSubject.send(completion: .failure(dataStoreError))
189194
}
@@ -230,7 +235,7 @@ extension AWSModelReconciliationQueue: Resettable {
230235

231236
}
232237

233-
// MARK: Auth errors handling
238+
// MARK: Errors handling
234239
@available(iOS 13.0, *)
235240
extension AWSModelReconciliationQueue {
236241
private typealias ResponseType = MutationSync<AnyModel>
@@ -241,14 +246,30 @@ extension AWSModelReconciliationQueue {
241246
return nil
242247
}
243248

249+
private func errorTypeValueFrom(graphQLError: GraphQLError) -> String? {
250+
guard case let .string(errorTypeValue) = graphQLError.extensions?["errorType"] else {
251+
return nil
252+
}
253+
return errorTypeValue
254+
}
255+
244256
private func isUnauthorizedError(_ error: Error?) -> Bool {
245257
if let responseError = error as? GraphQLResponseError<ResponseType>,
246258
let graphQLError = graphqlErrors(from: responseError)?.first,
247-
let extensions = graphQLError.extensions,
248-
case let .string(errorTypeValue) = extensions["errorType"],
259+
let errorTypeValue = errorTypeValueFrom(graphQLError: graphQLError),
249260
case .unauthorized = AppSyncErrorType(errorTypeValue) {
250261
return true
251262
}
252263
return false
253264
}
265+
266+
private func isOperationDisabledError(_ error: Error?) -> Bool {
267+
if let responseError = error as? GraphQLResponseError<ResponseType>,
268+
let graphQLError = graphqlErrors(from: responseError)?.first,
269+
let errorTypeValue = errorTypeValueFrom(graphQLError: graphQLError),
270+
case .operationDisabled = AppSyncErrorType(errorTypeValue) {
271+
return true
272+
}
273+
return false
274+
}
254275
}

AmplifyPlugins/DataStore/AWSDataStoreCategoryPlugin/Sync/SubscriptionSync/ReconcileAndLocalSave/ModelReconciliationQueue.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Combine
1111

1212
enum ModelConnectionDisconnectedReason {
1313
case unauthorized
14+
case operationDisabled
1415
}
1516

1617
enum ModelReconciliationQueueEvent {

AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginTests/Sync/MutationQueue/ProcessMutationErrorFromCloudOperationTests.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import Combine
1616

1717
// swiftlint:disable type_body_length
1818
// swiftlint:disable type_name
19+
// swiftlint:disable file_length
1920
@available(iOS 13.0, *)
2021
class ProcessMutationErrorFromCloudOperationTests: XCTestCase {
2122
// swiftlint:enable type_name
@@ -895,6 +896,42 @@ class ProcessMutationErrorFromCloudOperationTests: XCTestCase {
895896
wait(for: [expectErrorHandlerCalled], timeout: defaultAsyncWaitTimeout)
896897
wait(for: [expectCompletion], timeout: defaultAsyncWaitTimeout)
897898
}
899+
900+
/// Given: GraphQL "OperationDisabled" error
901+
/// - When:
902+
/// - API is called and response contains an "OperationDisabled" error
903+
/// - Then:
904+
/// - Completion handler is successfully called
905+
func testProcessOperationDisabledError() throws {
906+
let post = Post(title: "localTitle", content: "localContent", createdAt: .now())
907+
let mutationEvent = try MutationEvent(model: post, modelSchema: Post.schema, mutationType: .create)
908+
let expectCompletion = expectation(description: "Expect to complete error processing")
909+
let completion: (Result<MutationEvent?, Error>) -> Void = { result in
910+
if case .success(let mutationEventOptional) = result {
911+
XCTAssertNil(mutationEventOptional)
912+
expectCompletion.fulfill()
913+
return
914+
}
915+
XCTFail("Should have been successful")
916+
}
917+
918+
let graphQLError = try getGraphQLResponseError(withRemote: post,
919+
deleted: false,
920+
version: 0,
921+
errorType: .operationDisabled)
922+
923+
let operation = ProcessMutationErrorFromCloudOperation(
924+
dataStoreConfiguration: DataStoreConfiguration.default,
925+
mutationEvent: mutationEvent,
926+
api: mockAPIPlugin,
927+
storageAdapter: storageAdapter,
928+
graphQLResponseError: graphQLError,
929+
completion: completion)
930+
931+
let queue = OperationQueue()
932+
queue.addOperation(operation)
933+
wait(for: [expectCompletion], timeout: defaultAsyncWaitTimeout)
934+
}
898935
}
899936

900937
extension ProcessMutationErrorFromCloudOperationTests {

0 commit comments

Comments
 (0)