diff --git a/DuckDuckGo/Common/Utilities/AlertPresenter.swift b/DuckDuckGo/Common/Utilities/AlertPresenter.swift index e5ed12fe9d..01f22cc391 100644 --- a/DuckDuckGo/Common/Utilities/AlertPresenter.swift +++ b/DuckDuckGo/Common/Utilities/AlertPresenter.swift @@ -19,21 +19,26 @@ import Foundation public protocol AlertPresenting { - func showAlert(_ alert: NSAlert) + func showSyncPausedAlert(title: String, informative: String) } public struct StandardAlertPresenter: AlertPresenting { public init () {} @MainActor - public func showAlert(_ alert: NSAlert) { - let response = alert.runModal() + public func showSyncPausedAlert(title: String, informative: String) { + Task { + await MainActor.run { + let alert = NSAlert.syncPaused(title: title, informative: informative) + let response = alert.runModal() - switch response { - case .alertSecondButtonReturn: - alert.window.sheetParent?.endSheet(alert.window) - WindowControllersManager.shared.showPreferencesTab(withSelectedPane: .sync) - default: - break + switch response { + case .alertSecondButtonReturn: + alert.window.sheetParent?.endSheet(alert.window) + WindowControllersManager.shared.showPreferencesTab(withSelectedPane: .sync) + default: + break + } + } } } } diff --git a/DuckDuckGo/Sync/SyncErrorHandler.swift b/DuckDuckGo/Sync/SyncErrorHandler.swift index 9a0eb8afb6..def0de47da 100644 --- a/DuckDuckGo/Sync/SyncErrorHandler.swift +++ b/DuckDuckGo/Sync/SyncErrorHandler.swift @@ -301,37 +301,31 @@ extension SyncErrorHandler: SyncErrorHandling { // swiftlint:disable:next cyclomatic_complexity private func showSyncPausedAlertIfNeeded(for errorType: AsyncErrorType) { - Task { - await MainActor.run { - var alert: NSAlert - switch errorType { - case .bookmarksCountLimitExceeded, .bookmarksRequestSizeLimitExceeded: - guard !didShowBookmarksSyncPausedError else { return } - alert = NSAlert.syncPaused(title: UserText.syncBookmarkPausedAlertTitle, informative: UserText.syncBookmarkPausedAlertDescription) - didShowBookmarksSyncPausedError = true - case .credentialsCountLimitExceeded, .credentialsRequestSizeLimitExceeded: - guard !didShowCredentialsSyncPausedError else { return } - alert = NSAlert.syncPaused(title: UserText.syncCredentialsPausedAlertTitle, informative: UserText.syncCredentialsPausedAlertDescription) - didShowCredentialsSyncPausedError = true - case .badRequestBookmarks: - guard !didShowBookmarksSyncPausedError else { return } - alert = NSAlert.syncPaused(title: UserText.syncBookmarkPausedAlertTitle, informative: UserText.syncBookmarksBadRequestAlertDescription) - didShowBookmarksSyncPausedError = true - case .badRequestCredentials: - guard !didShowCredentialsSyncPausedError else { return } - alert = NSAlert.syncPaused(title: UserText.syncBookmarkPausedAlertTitle, informative: UserText.syncCredentialsBadRequestAlertDescription) - didShowCredentialsSyncPausedError = true - case .invalidLoginCredentials: - guard !didShowInvalidLoginSyncPausedError else { return } - alert = NSAlert.syncPaused(title: UserText.syncPausedAlertTitle, informative: UserText.syncInvalidLoginAlertDescription) - didShowInvalidLoginSyncPausedError = true - case .tooManyRequests: - guard shouldShowAlertForNonActionableError() == true else { return } - alert = NSAlert.syncPaused(title: UserText.syncErrorAlertTitle, informative: UserText.syncTooManyRequestsAlertDescription) - lastErrorNotificationTime = Date() - } - alertPresenter.showAlert(alert) - } + switch errorType { + case .bookmarksCountLimitExceeded, .bookmarksRequestSizeLimitExceeded: + guard !didShowBookmarksSyncPausedError else { return } + alertPresenter.showSyncPausedAlert(title: UserText.syncBookmarkPausedAlertTitle, informative: UserText.syncBookmarkPausedAlertDescription) + didShowBookmarksSyncPausedError = true + case .credentialsCountLimitExceeded, .credentialsRequestSizeLimitExceeded: + guard !didShowCredentialsSyncPausedError else { return } + alertPresenter.showSyncPausedAlert(title: UserText.syncCredentialsPausedAlertTitle, informative: UserText.syncCredentialsPausedAlertDescription) + didShowCredentialsSyncPausedError = true + case .badRequestBookmarks: + guard !didShowBookmarksSyncPausedError else { return } + alertPresenter.showSyncPausedAlert(title: UserText.syncBookmarkPausedAlertTitle, informative: UserText.syncBookmarksBadRequestAlertDescription) + didShowBookmarksSyncPausedError = true + case .badRequestCredentials: + guard !didShowCredentialsSyncPausedError else { return } + alertPresenter.showSyncPausedAlert(title: UserText.syncBookmarkPausedAlertTitle, informative: UserText.syncCredentialsBadRequestAlertDescription) + didShowCredentialsSyncPausedError = true + case .invalidLoginCredentials: + guard !didShowInvalidLoginSyncPausedError else { return } + alertPresenter.showSyncPausedAlert(title: UserText.syncPausedAlertTitle, informative: UserText.syncInvalidLoginAlertDescription) + didShowInvalidLoginSyncPausedError = true + case .tooManyRequests: + guard shouldShowAlertForNonActionableError() == true else { return } + alertPresenter.showSyncPausedAlert(title: UserText.syncErrorAlertTitle, informative: UserText.syncTooManyRequestsAlertDescription) + lastErrorNotificationTime = Date() } } diff --git a/UnitTests/Sync/SyncErrorHandlerTests.swift b/UnitTests/Sync/SyncErrorHandlerTests.swift index 9de64a1fec..870e4615d2 100644 --- a/UnitTests/Sync/SyncErrorHandlerTests.swift +++ b/UnitTests/Sync/SyncErrorHandlerTests.swift @@ -229,19 +229,13 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation2 = XCTestExpectation(description: "Second Error handled") let error = SyncError.unexpectedStatusCode(409) - Task { - handler.handleBookmarkError(error) - expectation.fulfill() - } + handler.handleBookmarkError(error) handler = SyncErrorHandler(alertPresenter: alertPresenter) - Task { - handler.handleBookmarkError(error) - expectation2.fulfill() - } + handler.handleBookmarkError(error) + expectation2.fulfill() - await self.fulfillment(of: [expectation, expectation2], timeout: 4.0) XCTAssertEqual(alertPresenter.showAlertCount, 1) } @@ -249,12 +243,8 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation = XCTestExpectation(description: "Error handled") let error = SyncError.unexpectedStatusCode(409) - Task { - handler.handleCredentialError(_:)(error) - expectation.fulfill() - } + handler.handleCredentialError(_:)(error) - await self.fulfillment(of: [expectation], timeout: 4.0) XCTAssertTrue(alertPresenter.showAlertCalled) } @@ -263,19 +253,13 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation2 = XCTestExpectation(description: "Second Error handled") let error = SyncError.unexpectedStatusCode(409) - Task { - handler.handleCredentialError(error) - expectation.fulfill() - } + handler.handleCredentialError(error) + handler = SyncErrorHandler(alertPresenter: alertPresenter) - Task { - handler.handleCredentialError(error) - expectation2.fulfill() - } + handler.handleCredentialError(error) - await self.fulfillment(of: [expectation, expectation2], timeout: 4.0) XCTAssertEqual(alertPresenter.showAlertCount, 1) } @@ -283,12 +267,8 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation = XCTestExpectation(description: "Error handled") let error = SyncError.unexpectedStatusCode(413) - Task { - handler.handleBookmarkError(error) - expectation.fulfill() - } + handler.handleBookmarkError(error) - await self.fulfillment(of: [expectation], timeout: 4.0) XCTAssertTrue(alertPresenter.showAlertCalled) } @@ -297,19 +277,12 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation2 = XCTestExpectation(description: "Second Error handled") let error = SyncError.unexpectedStatusCode(413) - Task { - handler.handleBookmarkError(error) - expectation.fulfill() - } + handler.handleBookmarkError(error) handler = SyncErrorHandler(alertPresenter: alertPresenter) - Task { - handler.handleBookmarkError(error) - expectation2.fulfill() - } + handler.handleBookmarkError(error) - await self.fulfillment(of: [expectation, expectation2], timeout: 4.0) XCTAssertEqual(alertPresenter.showAlertCount, 1) } @@ -317,12 +290,8 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation = XCTestExpectation(description: "Error handled") let error = SyncError.unexpectedStatusCode(413) - Task { - handler.handleCredentialError(_:)(error) - expectation.fulfill() - } + handler.handleCredentialError(_:)(error) - await self.fulfillment(of: [expectation], timeout: 4.0) XCTAssertTrue(alertPresenter.showAlertCalled) } @@ -331,19 +300,12 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation2 = XCTestExpectation(description: "Second Error handled") let error = SyncError.unexpectedStatusCode(413) - Task { - handler.handleCredentialError(error) - expectation.fulfill() - } + handler.handleCredentialError(error) handler = SyncErrorHandler(alertPresenter: alertPresenter) - Task { - handler.handleCredentialError(error) - expectation2.fulfill() - } + handler.handleCredentialError(error) - await self.fulfillment(of: [expectation, expectation2], timeout: 4.0) XCTAssertEqual(alertPresenter.showAlertCount, 1) } @@ -352,19 +314,12 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation2 = XCTestExpectation(description: "Second Error handled") let error = SyncError.unexpectedStatusCode(413) - Task { - handler.handleCredentialError(error) - expectation.fulfill() - } + handler.handleCredentialError(error) handler = SyncErrorHandler(alertPresenter: alertPresenter) - Task { - handler.handleBookmarkError(_:)(error) - expectation2.fulfill() - } + handler.handleBookmarkError(_:)(error) - await self.fulfillment(of: [expectation, expectation2], timeout: 4.0) XCTAssertEqual(alertPresenter.showAlertCount, 2) } @@ -372,12 +327,8 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation = XCTestExpectation(description: "Error handled") let error = SyncError.unexpectedStatusCode(401) - Task { - handler.handleCredentialError(_:)(error) - expectation.fulfill() - } + handler.handleCredentialError(_:)(error) - await self.fulfillment(of: [expectation], timeout: 4.0) XCTAssertTrue(alertPresenter.showAlertCalled) } @@ -386,19 +337,12 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation2 = XCTestExpectation(description: "Second Error handled") let error = SyncError.unexpectedStatusCode(401) - Task { - handler.handleBookmarkError(_:)(error) - expectation.fulfill() - } + handler.handleBookmarkError(_:)(error) handler = SyncErrorHandler(alertPresenter: alertPresenter) - Task { - handler.handleBookmarkError(_:)(error) - expectation2.fulfill() - } + handler.handleBookmarkError(_:)(error) - await self.fulfillment(of: [expectation, expectation2], timeout: 4.0) XCTAssertEqual(alertPresenter.showAlertCount, 1) } @@ -406,12 +350,8 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation = XCTestExpectation(description: "Error handled") let error = SyncError.unexpectedStatusCode(429) - Task { - handler.handleCredentialError(_:)(error) - expectation.fulfill() - } + handler.handleCredentialError(_:)(error) - await self.fulfillment(of: [expectation], timeout: 4.0) XCTAssertFalse(alertPresenter.showAlertCalled) } @@ -419,12 +359,8 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation = XCTestExpectation(description: "Error handled") let error = SyncError.unexpectedStatusCode(418) - Task { - handler.handleCredentialError(_:)(error) - expectation.fulfill() - } + handler.handleCredentialError(_:)(error) - await self.fulfillment(of: [expectation], timeout: 4.0) XCTAssertFalse(alertPresenter.showAlertCalled) } @@ -432,12 +368,8 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation = XCTestExpectation(description: "Error handled") let error = SyncError.unexpectedStatusCode(429) - Task { - handler.handleCredentialError(_:)(error) - expectation.fulfill() - } + handler.handleCredentialError(_:)(error) - await self.fulfillment(of: [expectation], timeout: 4.0) XCTAssertFalse(alertPresenter.showAlertCalled) } @@ -445,14 +377,10 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation = XCTestExpectation(description: "Error handled") let error = SyncError.unexpectedStatusCode(429) - Task { - for _ in 0...8 { - handler.handleCredentialError(_:)(error) - } - expectation.fulfill() + for _ in 0...8 { + handler.handleCredentialError(_:)(error) } - await self.fulfillment(of: [expectation], timeout: 8.0) XCTAssertFalse(alertPresenter.showAlertCalled) } @@ -460,14 +388,10 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation = XCTestExpectation(description: "Error handled") let error = SyncError.unexpectedStatusCode(429) - Task { - for _ in 0...9 { - handler.handleCredentialError(_:)(error) - } - expectation.fulfill() + for _ in 0...9 { + handler.handleCredentialError(_:)(error) } - await self.fulfillment(of: [expectation], timeout: 8.0) let currentTime = Date() let timeDifference = currentTime.timeIntervalSince(userDefaults.value(forKey: UserDefaultsWrapper.Key.syncLastErrorNotificationTime.rawValue) as! Date) XCTAssertTrue(alertPresenter.showAlertCalled) @@ -478,14 +402,10 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation = XCTestExpectation(description: "Error handled") let error = SyncError.unexpectedStatusCode(418) - Task { - for _ in 0...20 { - handler.handleCredentialError(_:)(error) - } - expectation.fulfill() + for _ in 0...20 { + handler.handleCredentialError(_:)(error) } - await self.fulfillment(of: [expectation], timeout: 8.0) XCTAssertEqual(alertPresenter.showAlertCount, 1) } @@ -504,22 +424,14 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation2 = XCTestExpectation(description: "Secons Error handled") let error = SyncError.unexpectedStatusCode(401) - Task { - handler.handleBookmarkError(_:)(error) - expectation.fulfill() - } + handler.handleBookmarkError(_:)(error) - await self.fulfillment(of: [expectation], timeout: 4.0) XCTAssertTrue(handler.isSyncPaused) XCTAssertEqual(alertPresenter.showAlertCount, 1) handler.syncBookmarksSucceded() - Task { - handler.handleBookmarkError(_:)(error) - expectation2.fulfill() - } + handler.handleBookmarkError(_:)(error) - await self.fulfillment(of: [expectation2], timeout: 4.0) XCTAssertTrue(handler.isSyncPaused) XCTAssertEqual(alertPresenter.showAlertCount, 2) } @@ -529,22 +441,14 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation2 = XCTestExpectation(description: "Secons Error handled") let error = SyncError.unexpectedStatusCode(409) - Task { - handler.handleBookmarkError(_:)(error) - expectation.fulfill() - } + handler.handleBookmarkError(_:)(error) - await self.fulfillment(of: [expectation], timeout: 4.0) XCTAssertTrue(handler.isSyncBookmarksPaused) XCTAssertEqual(alertPresenter.showAlertCount, 1) handler.syncBookmarksSucceded() - Task { - handler.handleBookmarkError(_:)(error) - expectation2.fulfill() - } + handler.handleBookmarkError(_:)(error) - await self.fulfillment(of: [expectation2], timeout: 4.0) XCTAssertTrue(handler.isSyncBookmarksPaused) XCTAssertEqual(alertPresenter.showAlertCount, 2) } @@ -554,22 +458,14 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation2 = XCTestExpectation(description: "Secons Error handled") let error = SyncError.unexpectedStatusCode(413) - Task { - handler.handleCredentialError(_:)(error) - expectation.fulfill() - } + handler.handleCredentialError(_:)(error) - await self.fulfillment(of: [expectation], timeout: 4.0) XCTAssertTrue(handler.isSyncCredentialsPaused) XCTAssertEqual(alertPresenter.showAlertCount, 1) handler.syncCredentialsSucceded() - Task { - handler.handleCredentialError(_:)(error) - expectation2.fulfill() - } + handler.handleCredentialError(_:)(error) - await self.fulfillment(of: [expectation2], timeout: 4.0) XCTAssertTrue(handler.isSyncCredentialsPaused) XCTAssertEqual(alertPresenter.showAlertCount, 2) } @@ -584,24 +480,18 @@ final class SyncErrorHandlerTests: XCTestCase { XCTAssertTrue(abs(timeDifference) <= 5) } - func test_When400ErrorFiredAfter12HoursFromLastSuccessfulSync_ThenAlertShown() async { + func test_When429ErrorFiredAfter12HoursFromLastSuccessfulSync_ThenAlertShown() async { let expectation = XCTestExpectation(description: "Error handled") let expectation2 = XCTestExpectation(description: "Second Error handled") - let error = SyncError.unexpectedStatusCode(400) + let error = SyncError.unexpectedStatusCode(429) let thirteenHoursAgo = Calendar.current.date(byAdding: .hour, value: -13, to: Date())! - Task { - handler.handleCredentialError(_:)(error) - expectation.fulfill() - } + + handler.handleCredentialError(_:)(error) userDefaults.set(thirteenHoursAgo, forKey: UserDefaultsWrapper.Key.syncLastSuccesfullTime.rawValue) - Task { - handler.handleCredentialError(_:)(error) - expectation2.fulfill() - } + handler.handleCredentialError(_:)(error) - await self.fulfillment(of: [expectation, expectation2], timeout: 4.0) XCTAssertTrue(alertPresenter.showAlertCalled) XCTAssertEqual(alertPresenter.showAlertCount, 1) } @@ -612,12 +502,8 @@ final class SyncErrorHandlerTests: XCTestCase { let thirteenHoursAgo = Calendar.current.date(byAdding: .hour, value: -13, to: Date())! userDefaults.set(thirteenHoursAgo, forKey: UserDefaultsWrapper.Key.syncLastSuccesfullTime.rawValue) - Task { - handler.handleCredentialError(_:)(error) - expectation.fulfill() - } + handler.handleCredentialError(_:)(error) - await self.fulfillment(of: [expectation], timeout: 4.0) XCTAssertFalse(alertPresenter.showAlertCalled) } @@ -626,26 +512,18 @@ final class SyncErrorHandlerTests: XCTestCase { let expectation2 = XCTestExpectation(description: "SecondError handled") let error = SyncError.unexpectedStatusCode(429) - Task { - for _ in 0...9 { - handler.handleCredentialError(_:)(error) - } - expectation.fulfill() + for _ in 0...9 { + handler.handleCredentialError(_:)(error) } - await self.fulfillment(of: [expectation], timeout: 4.0) XCTAssertTrue(alertPresenter.showAlertCalled) let oneDayAgo = Calendar.current.date(byAdding: .hour, value: -25, to: Date())! userDefaults.set(oneDayAgo, forKey: UserDefaultsWrapper.Key.syncLastErrorNotificationTime.rawValue) - Task { - for _ in 0...9 { - handler.handleCredentialError(_:)(error) - } - expectation2.fulfill() + for _ in 0...9 { + handler.handleCredentialError(_:)(error) } - await self.fulfillment(of: [expectation2], timeout: 4.0) XCTAssertTrue(alertPresenter.showAlertCalled) XCTAssertEqual(alertPresenter.showAlertCount, 2) } @@ -679,11 +557,9 @@ final class SyncErrorHandlerTests: XCTestCase { class CapturingAlertPresenter: AlertPresenting { var showAlertCalled = false - var capturedAlert: NSAlert? var showAlertCount = 0 - func showAlert(_ alert: NSAlert) { + func showSyncPausedAlert(title: String, informative: String) { showAlertCalled = true - capturedAlert = alert showAlertCount += 1 } }