import XCTest @testable import AWSS3StoragePlugin @testable import Amplify class MockMultipartUploadClient: StorageMultipartUploadClient { enum Failure: Error { case sessionNotIntegrated case mockFailure } var uploadPartCount = 0 var completeMultipartUploadCount = 0 var abortMultipartUploadCount = 0 var errorCount = 0 var taskIdentifier = 100 let uploadFile: UploadFile var session: StorageMultipartUploadSession? var didCreate: ((StorageMultipartUploadSession) -> Void)? var didStartPartUpload: ((StorageMultipartUploadSession, PartNumber) -> Void)? var didTransferBytesForPartUpload: ((StorageMultipartUploadSession, PartNumber, Int) -> Void)? var shouldFailPartUpload: ((StorageMultipartUploadSession, PartNumber) -> Bool)? var didCompletePartUpload: ((StorageMultipartUploadSession, PartNumber, String, TaskIdentifier) -> Void)? var didFailPartUpload: ((StorageMultipartUploadSession, PartNumber, Error) -> Void)? var didCompleteMultipartUpload: ((StorageMultipartUploadSession, UploadID) -> Void)? var didAbortMultipartUpload: ((StorageMultipartUploadSession, UploadID) -> Void)? init(uploadFile: UploadFile? = nil) { self.uploadFile = uploadFile ?? UploadFile(fileURL: URL(fileURLWithPath: "/tmp/upload.txt"), temporaryFileCreated: true, size: UInt64(Bytes.megabytes(42).bytes)) } func integrate(session: StorageMultipartUploadSession) { self.session = session } func createMultipartUpload() throws { guard let session = session else { throw Failure.sessionNotIntegrated } let uploadId = UUID().uuidString session.handle(multipartUploadEvent: .created(uploadFile: uploadFile, uploadId: uploadId)) didCreate?(session) } func uploadPart(partNumber: PartNumber, multipartUpload: StorageMultipartUpload, subTask: StorageTransferTask) throws { guard let _ = multipartUpload.uploadFile, let _ = multipartUpload.uploadId, let _ = multipartUpload.partSize, let part = multipartUpload.part(for: partNumber) else { fatalError() } print("Upload Part \(partNumber)") guard let session = session else { throw Failure.sessionNotIntegrated } uploadPartCount += 1 defer { taskIdentifier += 1 } subTask.sessionTask = MockStorageSessionTask(taskIdentifier: taskIdentifier, state: .suspended) session.handle(uploadPartEvent: .started(partNumber: partNumber, taskIdentifier: taskIdentifier)) didStartPartUpload?(session, partNumber) let bytesTransferred = part.bytes / 2 session.handle(uploadPartEvent: .progressUpdated(partNumber: partNumber, bytesTransferred: bytesTransferred, taskIdentifier: taskIdentifier)) didTransferBytesForPartUpload?(session, partNumber, bytesTransferred) if shouldFailPartUpload?(session, partNumber) ?? false { session.handle(uploadPartEvent: .failed(partNumber: partNumber, error: Failure.mockFailure)) return } if let part = session.part(for: partNumber) { if part.inProgress { let eTag = UUID().uuidString session.handle(uploadPartEvent: .completed(partNumber: partNumber, eTag: eTag, taskIdentifier: taskIdentifier)) didCompletePartUpload?(session, partNumber, eTag, taskIdentifier) } } } func completeMultipartUpload(uploadId: UploadID) throws { guard let session = session else { throw Failure.sessionNotIntegrated } completeMultipartUploadCount += 1 session.handle(multipartUploadEvent: .completed(uploadId: uploadId)) didCompleteMultipartUpload?(session, uploadId) } func abortMultipartUpload(uploadId: UploadID, error: Error?) throws { guard let session = session else { throw Failure.sessionNotIntegrated } abortMultipartUploadCount += 1 session.handle(multipartUploadEvent: .aborted(uploadId: uploadId, error: error)) didAbortMultipartUpload?(session, uploadId) } func cancelUploadTasks(taskIdentifiers: [TaskIdentifier], done: @escaping () -> Void) { print("Canceling upload tasks") done() } }