diff --git a/.code-samples.meilisearch.yaml b/.code-samples.meilisearch.yaml index ddff43bd..c607f114 100644 --- a/.code-samples.meilisearch.yaml +++ b/.code-samples.meilisearch.yaml @@ -133,7 +133,7 @@ async_guide_filter_by_ids_1: |- } } async_guide_filter_by_statuses_1: |- - client.getTasks(params: TasksQuery(statuses: ["failed", "canceled"])) { result in + client.getTasks(params: TasksQuery(statuses: [.failed, .canceled])) { result in switch result { case .success(let taskResult): print(taskResult) @@ -142,7 +142,7 @@ async_guide_filter_by_statuses_1: |- } } async_guide_filter_by_types_1: |- - client.getTasks(params: TasksQuery(types: ["dumpCreation", "indexSwap"])) { result in + client.getTasks(params: TasksQuery(types: [.dumpCreation, .indexSwap])) { result in switch result { case .success(let taskResult): print(taskResult) @@ -417,15 +417,6 @@ search_post_1: |- print(error) } } -get_task_by_index_1: |- - client.index("movies").getTask(taskUid: 1) { (result) in - switch result { - case .success(let task): - print(task) - case .failure(let error): - print(error) - } - } get_task_1: |- client.getTask(taskUid: 1) { (result) in switch result { @@ -436,7 +427,7 @@ get_task_1: |- } } get_all_tasks_1: |- - client.getTasks() { (result) in + client.getTasks { (result) in switch result { case .success(let tasks): print(tasks) @@ -444,6 +435,24 @@ get_all_tasks_1: |- print(error) } } +delete_tasks_1: |- + client.deleteTasks(filter: DeleteTasksQuery(uids: [1, 2])) { (result) in + switch result { + case .success(let taskInfo): + print(taskInfo) + case .failure(let error): + print(error) + } + } +cancel_tasks_1: |- + client.cancelTasks(filter: CancelTasksQuery(uids: [1, 2])) { (result) in + switch result { + case .success(let taskInfo): + print(taskInfo) + case .failure(let error): + print(error) + } + } get_one_key_1: |- client.getKey(keyOrUid: "6062abda-a5aa-4414-ac91-ecd7944c0f8d") { result in switch result { diff --git a/README.md b/README.md index c245ed87..c9b48ecc 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ To do a simple search using the client, you can create a Swift script like this: ) { result in switch result { case .success(let task): - print(task) // => Task(uid: 0, status: "enqueued", ...) + print(task) // => Task(uid: 0, status: Task.Status.enqueued, ...) case .failure(let error): print(error.localizedDescription) } diff --git a/Sources/MeiliSearch/Client.swift b/Sources/MeiliSearch/Client.swift index 7e2f32ba..b8567c08 100755 --- a/Sources/MeiliSearch/Client.swift +++ b/Sources/MeiliSearch/Client.swift @@ -201,6 +201,34 @@ public struct MeiliSearch { self.tasks.getTasks(params: params, completion) } + /** + Cancel any number of enqueued or processing tasks, stopping them from continuing to run + + - parameter filter: The filter in which chooses which tasks will be canceled + - parameter completion: The completion closure is used to notify when the server + completes the query request, it returns a `Result` object that contains `TaskInfo` + value. If the request was successful or `Error` if a failure occurred. + */ + public func cancelTasks( + filter: CancelTasksQuery, + completion: @escaping (Result) -> Void) { + self.tasks.cancelTasks(filter, completion) + } + + /** + Delete a finished (succeeded, failed, or canceled) task + + - parameter filter: The filter in which chooses which tasks will be deleted + - parameter completion: The completion closure is used to notify when the server + completes the query request, it returns a `Result` object that contains `TaskInfo` + value. If the request was successful or `Error` if a failure occurred. + */ + public func deleteTasks( + filter: DeleteTasksQuery, + completion: @escaping (Result) -> Void) { + self.tasks.deleteTasks(filter, completion) + } + // MARK: Keys /** diff --git a/Sources/MeiliSearch/Error.swift b/Sources/MeiliSearch/Error.swift index 774d12fa..f48d7b99 100644 --- a/Sources/MeiliSearch/Error.swift +++ b/Sources/MeiliSearch/Error.swift @@ -9,9 +9,13 @@ import Foundation public extension MeiliSearch { // MARK: Error struct MSErrorResponse: Decodable, Encodable, Equatable { + /// A human-readable description of the error public let message: String + /// The error code (https://www.meilisearch.com/docs/reference/errors/error_codes) public let code: String + /// The error type (https://www.meilisearch.com/docs/reference/errors/overview#errors) public let type: String + /// A link to the relevant section of the documentation public let link: String? } diff --git a/Sources/MeiliSearch/Keys.swift b/Sources/MeiliSearch/Keys.swift index aa32adec..8f0ad8da 100644 --- a/Sources/MeiliSearch/Keys.swift +++ b/Sources/MeiliSearch/Keys.swift @@ -23,7 +23,7 @@ struct Keys { return } do { - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let key: Key = try decoder.decode(Key.self, from: data) completion(.success(key)) } catch { diff --git a/Sources/MeiliSearch/Model/Task.swift b/Sources/MeiliSearch/Model/Task.swift deleted file mode 100644 index 13a85a3b..00000000 --- a/Sources/MeiliSearch/Model/Task.swift +++ /dev/null @@ -1,131 +0,0 @@ -import Foundation -#if canImport(FoundationNetworking) - import FoundationNetworking -#endif - -/** - `Task` instances represent the current transaction status, use the `uid` value to - verify the status of your transaction. - */ -public struct Task: Codable, Equatable { - - // MARK: Properties - - /// Unique ID for the current `Task`. - public let uid: Int - - /// Unique ID for the current `Task`. - public let indexUid: String - - /// Returns if the task has been successful or not. - public let status: Task.Status - - /// Type of the task. - public let type: String - - /// Details of the task. - public let details: Details? - - /// Duration of the task process. - public let duration: String? - - /// Date when the task has been enqueued. - public let enqueuedAt: String - - /// Date when the task has been processed. - public let processedAt: Date? - - /// Type of `Task`. - public struct Details: Codable, Equatable { - - // MARK: Properties - - /// Number of documents sent - public let receivedDocuments: Int? - - /// Number of documents successfully indexed/updated in Meilisearch - public let indexedDocuments: Int? - - /// Number of deleted documents - public let deletedDocuments: Int? - - /// Primary key on index creation - public let primaryKey: String? - - /// Ranking rules on settings actions - public let rankingRules: [String]? - - /// Searchable attributes on settings actions - public let searchableAttributes: [String]? - - /// Displayed attributes on settings actions - public let displayedAttributes: [String]? - - /// Filterable attributes on settings actions - public let filterableAttributes: [String]? - - /// Sortable attributes on settings actions - public let sortableAttributes: [String]? - - /// Stop words on settings actions - public let stopWords: [String]? - - /// Synonyms on settings actions - public let synonyms: [String: [String]]? - - /// Distinct attribute on settings actions - public let distinctAttribute: String? - - /// List of tokens that will be considered as word separators by Meilisearch. - public let separatorTokens: [String]? - - /// List of tokens that will not be considered as word separators by Meilisearch. - public let nonSeparatorTokens: [String]? - - /// List of words on which the segmentation will be overridden. - public let dictionary: [String]? - - /// Settings for index level pagination rules - public let pagination: Pagination? - - /// Typo tolerance on settings actions - public let typoTolerance: TypoTolerance? - } - /// Error information in case of failed update. - public let error: MeiliSearch.MSErrorResponse? - - public enum Status: Codable, Equatable { - /// When a task was successfully enqueued and is waiting to be processed. - case enqueued - /// When a task is still being processed. - case processing - /// When a task was successfully processed. - case succeeded - /// When a task had an error and could not be completed for some reason. - case failed - - public enum StatusError: Error { - case unknown - } - - public init(from decoder: Decoder) throws { - let container: SingleValueDecodingContainer = try decoder.singleValueContainer() - let rawStatus: String = try container.decode(String.self) - - switch rawStatus { - case "enqueued": - self = Status.enqueued - case "processing": - self = Status.processing - case "succeeded": - self = Status.succeeded - case "failed": - self = Status.failed - default: - throw StatusError.unknown - } - } - - public func encode(to encoder: Encoder) throws { } - } -} diff --git a/Sources/MeiliSearch/Model/Task/Task.swift b/Sources/MeiliSearch/Model/Task/Task.swift new file mode 100644 index 00000000..8cadacb1 --- /dev/null +++ b/Sources/MeiliSearch/Model/Task/Task.swift @@ -0,0 +1,65 @@ +import Foundation + +/** + `Task` instances represent the current transaction status, use the `uid` value to + verify the status of your transaction. + */ +public struct Task: Decodable, Equatable { + /// Unique ID for the current `Task`. + public let uid: Int + + /// Unique identifier of the targeted index + public let indexUid: String? + + /// Returns if the task has been successful or not. + public let status: Status + + /// Type of the task. + public let type: TaskType + + /// Details of the task. + public let details: Details? + + /// Duration of the task process. + public let duration: String? + + /// Date when the task has been enqueued. + public let enqueuedAt: Date + + /// Date when the task has been started. + public let startedAt: Date? + + /// Date when the task has been finished, regardless of status. + public let finishedAt: Date? + + /// ID of the the `Task` which caused this to be canceled. + public let canceledBy: Int? + + /// Error information in case of failed update. + public let error: MeiliSearch.MSErrorResponse? + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + let type = try container.decode(TaskType.self, forKey: .type) + + self.uid = try container.decode(Int.self, forKey: .uid) + self.indexUid = try container.decodeIfPresent(String.self, forKey: .indexUid) + self.status = try container.decode(Status.self, forKey: .status) + self.type = type + self.duration = try container.decodeIfPresent(String.self, forKey: .duration) + self.enqueuedAt = try container.decode(Date.self, forKey: .enqueuedAt) + self.startedAt = try container.decodeIfPresent(Date.self, forKey: .startedAt) + self.finishedAt = try container.decodeIfPresent(Date.self, forKey: .finishedAt) + self.canceledBy = try container.decodeIfPresent(Int.self, forKey: .canceledBy) + self.error = try container.decodeIfPresent(MeiliSearch.MSErrorResponse.self, forKey: .error) + + // we ignore errors thrown by `superDecoder` to handle cases where no details are provided by the API + // for example when the type is `snapshotCreation`. + let detailsDecoder = try? container.superDecoder(forKey: .details) + self.details = try Details(decoder: detailsDecoder, type: type) + } + + enum CodingKeys: String, CodingKey { + case uid, indexUid, status, type, details, duration, enqueuedAt, startedAt, finishedAt, canceledBy, error + } +} diff --git a/Sources/MeiliSearch/Model/Task/TaskDetails.swift b/Sources/MeiliSearch/Model/Task/TaskDetails.swift new file mode 100644 index 00000000..571a16f7 --- /dev/null +++ b/Sources/MeiliSearch/Model/Task/TaskDetails.swift @@ -0,0 +1,110 @@ +import Foundation + +public extension Task { + enum Details: Equatable { + case indexCreation(TaskIndexCreationDetails) + case indexUpdate(TaskIndexUpdateDetails) + case indexDeletion(TaskIndexDeletionDetails) + case indexSwap(TaskIndexSwapDetails) + case documentAdditionOrUpdate(TaskDocumentAdditionOrUpdateDetails) + case documentDeletion(TaskDocumentDeletionDetails) + case settingsUpdate(Setting) + case dumpCreation(TaskDumpCreationDetails) + case taskCancelation(TaskCancellationDetails) + case taskDeletion(TaskDeletionDetails) + + init?(decoder: Decoder?, type: TaskType) throws { + guard let decoder = decoder else { + return nil + } + + switch type { + case .indexCreation: + self = try .indexCreation(.init(from: decoder)) + case .indexUpdate: + self = try .indexUpdate(.init(from: decoder)) + case .indexDeletion: + self = try .indexDeletion(.init(from: decoder)) + case .indexSwap: + self = try .indexSwap(.init(from: decoder)) + case .documentAdditionOrUpdate: + self = try .documentAdditionOrUpdate(.init(from: decoder)) + case .documentDeletion: + self = try .documentDeletion(.init(from: decoder)) + case .settingsUpdate: + self = try .settingsUpdate(.init(from: decoder)) + case .dumpCreation: + self = try .dumpCreation(.init(from: decoder)) + case .taskCancelation: + self = try .taskCancelation(.init(from: decoder)) + case .taskDeletion: + self = try .taskDeletion(.init(from: decoder)) + case .snapshotCreation: + // as per documentation: "The details object is set to null for snapshotCreation tasks." + return nil + case .unknown: + // we do not handle this type, and as such even if details exist we do not support them here + return nil + } + } + } + + struct TaskDocumentAdditionOrUpdateDetails: Decodable, Equatable { + /// Number of documents sent + public let receivedDocuments: Int? + + /// Number of documents successfully indexed/updated in Meilisearch + public let indexedDocuments: Int? + } + + struct TaskDocumentDeletionDetails: Decodable, Equatable { + /// Number of documents queued for deletion + public let providedIds: Int? + /// The filter used to delete documents. nil if it was not specified + public let originalFilter: String? + /// Number of documents deleted. nil while the task status is enqueued or processing + public let deletedDocuments: Int? + } + + struct TaskIndexCreationDetails: Decodable, Equatable { + /// Value of the primaryKey field supplied during index creation. nil if it was not specified + public let primaryKey: String? + } + + struct TaskIndexUpdateDetails: Decodable, Equatable { + /// Value of the primaryKey field supplied during index update. nil if it was not specified + public let primaryKey: String? + } + + struct TaskIndexDeletionDetails: Decodable, Equatable { + /// Number of deleted documents. This should equal the total number of documents in the deleted index. nil while the task status is enqueued or processing + public let deletedDocuments: Int? + } + + struct TaskIndexSwapDetails: Decodable, Equatable { + // To be populated under https://github.com/meilisearch/meilisearch-swift/issues/367 + } + + struct TaskCancellationDetails: Decodable, Equatable { + /// The number of matched tasks. If the API key used for the request doesn’t have access to an index, tasks relating to that index will not be included in matchedTasks + public let matchedTasks: Int? + /// The number of tasks successfully canceled. If the task cancelation fails, this will be 0. nil when the task status is enqueued or processing + public let canceledTasks: Int? + /// The filter used in the cancel task request + public let originalFilter: String? + } + + struct TaskDeletionDetails: Decodable, Equatable { + /// The number of matched tasks. If the API key used for the request doesn’t have access to an index, tasks relating to that index will not be included in matchedTasks + public let matchedTasks: Int? + /// The number of tasks successfully deleted. If the task deletion fails, this will be 0. nil when the task status is enqueued or processing + public let deletedTasks: Int? + /// The filter used in the delete task request + public let originalFilter: String? + } + + struct TaskDumpCreationDetails: Decodable, Equatable { + /// The generated uid of the dump. This is also the name of the generated dump file. nil when the task status is enqueued, processing, canceled, or failed + public let dumpUid: String? + } +} diff --git a/Sources/MeiliSearch/Model/TaskInfo.swift b/Sources/MeiliSearch/Model/Task/TaskInfo.swift similarity index 88% rename from Sources/MeiliSearch/Model/TaskInfo.swift rename to Sources/MeiliSearch/Model/Task/TaskInfo.swift index d64c72a9..70d6af1c 100644 --- a/Sources/MeiliSearch/Model/TaskInfo.swift +++ b/Sources/MeiliSearch/Model/Task/TaskInfo.swift @@ -5,9 +5,6 @@ import Foundation verify the status of your transaction. */ public struct TaskInfo: Codable, Equatable { - - // MARK: Properties - /// Unique ID for the current `TaskInfo`. public let taskUid: Int @@ -18,10 +15,10 @@ public struct TaskInfo: Codable, Equatable { public let status: Task.Status /// Type of the task. - public let type: String + public let type: TaskType /// Date when the task has been enqueued. - public let enqueuedAt: String + public let enqueuedAt: Date public enum CodingKeys: String, CodingKey { case taskUid, indexUid, status, type, enqueuedAt diff --git a/Sources/MeiliSearch/Model/Task/TaskStatus.swift b/Sources/MeiliSearch/Model/Task/TaskStatus.swift new file mode 100644 index 00000000..b55f2dc3 --- /dev/null +++ b/Sources/MeiliSearch/Model/Task/TaskStatus.swift @@ -0,0 +1,45 @@ +import Foundation + +public extension Task { + enum Status: String, Codable, Equatable { + /// When a task was successfully enqueued and is waiting to be processed. + case enqueued + /// When a task is still being processed. + case processing + /// When a task was successfully processed. + case succeeded + /// When a task had an error and could not be completed for some reason. + case failed + /// When a task has been canceled. + case canceled + + public enum StatusError: Error { + case unknown + } + + public init(from decoder: Decoder) throws { + let container: SingleValueDecodingContainer = try decoder.singleValueContainer() + let rawStatus: String = try container.decode(String.self) + + switch rawStatus { + case "enqueued": + self = Status.enqueued + case "processing": + self = Status.processing + case "succeeded": + self = Status.succeeded + case "failed": + self = Status.failed + case "canceled": + self = Status.canceled + default: + throw StatusError.unknown + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(rawValue) + } + } +} diff --git a/Sources/MeiliSearch/Model/Task/TaskType.swift b/Sources/MeiliSearch/Model/Task/TaskType.swift new file mode 100644 index 00000000..48c3f680 --- /dev/null +++ b/Sources/MeiliSearch/Model/Task/TaskType.swift @@ -0,0 +1,97 @@ +import Foundation + +/** + `TaskType`defines the possible types of task which could be returned by the `/tasks` API + */ +public enum TaskType: Codable, Equatable, LosslessStringConvertible { + case indexCreation + case indexUpdate + case indexDeletion + case indexSwap + case documentAdditionOrUpdate + case documentDeletion + case settingsUpdate + case dumpCreation + case taskCancelation + case taskDeletion + case snapshotCreation + + // Captures task types which are not currently known by the Swift package. + // This allows for a future proofing should the MeiliSearch executable introduce new values. + case unknown(String) + + public init(from decoder: Decoder) throws { + let value = try decoder.singleValueContainer().decode(String.self) + self.init(rawValue: value) + } + + internal init(rawValue: String) { + switch rawValue { + case "indexCreation": + self = .indexCreation + case "indexUpdate": + self = .indexUpdate + case "indexDeletion": + self = .indexDeletion + case "indexSwap": + self = .indexSwap + case "documentAdditionOrUpdate": + self = .documentAdditionOrUpdate + case "documentDeletion": + self = .documentDeletion + case "settingsUpdate": + self = .settingsUpdate + case "dumpCreation": + self = .dumpCreation + case "taskCancelation": + self = .taskCancelation + case "taskDeletion": + self = .taskDeletion + case "snapshotCreation": + self = .snapshotCreation + default: + self = .unknown(rawValue) + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(description) + } + + // MARK: LosslessStringConvertible + // ensures that when TaskType is converted to String, the "unknown" context is ignored + + public init?(_ description: String) { + self.init(rawValue: description) + } + + public var description: String { + switch self { + case .indexCreation: + return "indexCreation" + case .indexUpdate: + return "indexUpdate" + case .indexDeletion: + return "indexDeletion" + case .indexSwap: + return "indexSwap" + case .documentAdditionOrUpdate: + return "documentAdditionOrUpdate" + case .documentDeletion: + return "documentDeletion" + case .settingsUpdate: + return "settingsUpdate" + case .dumpCreation: + return "dumpCreation" + case .taskCancelation: + return "taskCancelation" + case .taskDeletion: + return "taskDeletion" + case .snapshotCreation: + return "snapshotCreation" + case .unknown(let unknownTaskTypeValue): + return unknownTaskTypeValue + } + } +} diff --git a/Sources/MeiliSearch/Model/TasksResults.swift b/Sources/MeiliSearch/Model/Task/TasksResults.swift similarity index 77% rename from Sources/MeiliSearch/Model/TasksResults.swift rename to Sources/MeiliSearch/Model/Task/TasksResults.swift index aaca9ecc..64e039b2 100644 --- a/Sources/MeiliSearch/Model/TasksResults.swift +++ b/Sources/MeiliSearch/Model/Task/TasksResults.swift @@ -3,8 +3,7 @@ import Foundation /** `TasksResults` is a wrapper used in the tasks routes to handle the returned data. */ - -public struct TasksResults: Codable, Equatable { +public struct TasksResults: Decodable, Equatable { /// Results list containing objects of `Task`. public let results: [Task] /// Integer value used to retrieve the next batch of tasks. @@ -13,4 +12,6 @@ public struct TasksResults: Codable, Equatable { public let from: Int? /// Max number of records to be returned in one request. public let limit: Int + /// Total number of tasks matching the filter or query + public let total: Int } diff --git a/Sources/MeiliSearch/QueryParameters/CancelTasksQuery.swift b/Sources/MeiliSearch/QueryParameters/CancelTasksQuery.swift new file mode 100644 index 00000000..4cef573c --- /dev/null +++ b/Sources/MeiliSearch/QueryParameters/CancelTasksQuery.swift @@ -0,0 +1,51 @@ +import Foundation + +/** + `CancelTasksQuery` class represent the options used to filter a cancel tasks call. + */ +public class CancelTasksQuery: Queryable { + /// List of strings with all the types the response should contain. + public let types: [TaskType] + /// List of strings with all the statuses the response should contain. + public let statuses: [Task.Status] + /// Filter tasks response by a particular list of index Uids strings + public let indexUids: [String] + /// Filter tasks based on a list of task's uids. + public let uids: [Int] + /// Filter tasks based on the date before the task were enqueued at. + public let beforeEnqueuedAt: Date? + /// Filter tasks based on the date after the task were enqueued at. + public let afterEnqueuedAt: Date? + /// Filter tasks based on the date before the task were started. + public let beforeStartedAt: Date? + /// Filter tasks based on the date after the task were started at. + public let afterStartedAt: Date? + + init( + types: [TaskType]? = nil, statuses: [Task.Status]? = nil, + indexUids: [String]? = nil, uids: [Int]? = nil, + beforeEnqueuedAt: Date? = nil, afterEnqueuedAt: Date? = nil, + beforeStartedAt: Date? = nil, afterStartedAt: Date? = nil + ) { + self.types = types ?? [] + self.statuses = statuses ?? [] + self.indexUids = indexUids ?? [] + self.uids = uids ?? [] + self.beforeEnqueuedAt = beforeEnqueuedAt + self.afterEnqueuedAt = afterEnqueuedAt + self.beforeStartedAt = beforeStartedAt + self.afterStartedAt = afterStartedAt + } + + internal func buildQuery() -> [String: Codable?] { + [ + "uids": uids.isEmpty ? nil : uids.map(String.init).joined(separator: ","), + "types": types.isEmpty ? nil : types.map({ $0.description }).joined(separator: ","), + "statuses": statuses.isEmpty ? nil : statuses.map({ $0.rawValue }).joined(separator: ","), + "indexUids": indexUids.isEmpty ? nil : indexUids.joined(separator: ","), + "beforeEnqueuedAt": Formatter.formatOptionalDate(date: beforeEnqueuedAt), + "afterEnqueuedAt": Formatter.formatOptionalDate(date: afterEnqueuedAt), + "beforeStartedAt": Formatter.formatOptionalDate(date: beforeStartedAt), + ] + } +} diff --git a/Sources/MeiliSearch/QueryParameters/DeleteTasksQuery.swift b/Sources/MeiliSearch/QueryParameters/DeleteTasksQuery.swift new file mode 100644 index 00000000..b720bc06 --- /dev/null +++ b/Sources/MeiliSearch/QueryParameters/DeleteTasksQuery.swift @@ -0,0 +1,64 @@ +import Foundation + +/** + `DeleteTasksQuery` class represent the options used to filter a delete tasks call. + */ +public class DeleteTasksQuery: Queryable { + /// List of strings with all the types the response should contain. + public let types: [TaskType] + /// List of strings with all the statuses the response should contain. + public let statuses: [Task.Status] + /// Filter tasks response by a particular list of index Uids strings + public let indexUids: [String] + /// Filter tasks based on a list of task's uids. + public let uids: [Int] + /// Filter tasks based on a list of task's uids which were used to cancel other tasks. + public let canceledBy: [Int] + /// Filter tasks based on the date before the task were enqueued at. + public let beforeEnqueuedAt: Date? + /// Filter tasks based on the date after the task were enqueued at. + public let afterEnqueuedAt: Date? + /// Filter tasks based on the date before the task were started. + public let beforeStartedAt: Date? + /// Filter tasks based on the date after the task were started at. + public let afterStartedAt: Date? + /// Filter tasks based on the date before the task was finished. + public let beforeFinishedAt: Date? + /// Filter tasks based on the date after the task was finished. + public let afterFinishedAt: Date? + + init( + statuses: [Task.Status]? = nil, types: [TaskType]? = nil, + indexUids: [String]? = nil, uids: [Int]? = nil, canceledBy: [Int]? = nil, + beforeEnqueuedAt: Date? = nil, afterEnqueuedAt: Date? = nil, + beforeStartedAt: Date? = nil, afterStartedAt: Date? = nil, + beforeFinishedAt: Date? = nil, afterFinishedAt: Date? = nil + ) { + self.statuses = statuses ?? [] + self.types = types ?? [] + self.indexUids = indexUids ?? [] + self.uids = uids ?? [] + self.canceledBy = canceledBy ?? [] + self.beforeEnqueuedAt = beforeEnqueuedAt + self.afterEnqueuedAt = afterEnqueuedAt + self.beforeStartedAt = beforeStartedAt + self.afterStartedAt = afterStartedAt + self.beforeFinishedAt = beforeFinishedAt + self.afterFinishedAt = afterFinishedAt + } + + internal func buildQuery() -> [String: Codable?] { + [ + "uids": uids.isEmpty ? nil : uids.map(String.init).joined(separator: ","), + "types": types.isEmpty ? nil : types.map({ $0.description }).joined(separator: ","), + "statuses": statuses.isEmpty ? nil : statuses.map({ $0.rawValue }).joined(separator: ","), + "indexUids": indexUids.isEmpty ? nil : indexUids.joined(separator: ","), + "canceledBy": canceledBy.isEmpty ? nil : canceledBy.map(String.init).joined(separator: ","), + "beforeEnqueuedAt": Formatter.formatOptionalDate(date: beforeEnqueuedAt), + "afterEnqueuedAt": Formatter.formatOptionalDate(date: afterEnqueuedAt), + "beforeStartedAt": Formatter.formatOptionalDate(date: beforeStartedAt), + "beforeFinishedAt": Formatter.formatOptionalDate(date: beforeFinishedAt), + "afterFinishedAt": Formatter.formatOptionalDate(date: afterFinishedAt), + ] + } +} diff --git a/Sources/MeiliSearch/QueryParameters/TasksQuery.swift b/Sources/MeiliSearch/QueryParameters/TasksQuery.swift index 7e5980de..d8eda862 100644 --- a/Sources/MeiliSearch/QueryParameters/TasksQuery.swift +++ b/Sources/MeiliSearch/QueryParameters/TasksQuery.swift @@ -13,9 +13,9 @@ public class TasksQuery: Queryable { /// Integer value used to retrieve the next batch of tasks. private var next: Int? /// List of strings with all the types the response should contain. - private var types: [String] + private var types: [TaskType] /// List of strings with all the statuses the response should contain. - private var statuses: [String] + private var statuses: [Task.Status] /// Filter tasks response by a particular list of index Uids strings var indexUids: [String] /// Filter tasks based on a list of task's uids. @@ -37,7 +37,7 @@ public class TasksQuery: Queryable { init( limit: Int? = nil, from: Int? = nil, next: Int? = nil, - statuses: [String]? = nil, types: [String]? = nil, + statuses: [Task.Status]? = nil, types: [TaskType]? = nil, indexUids: [String]? = nil, uids: [Int]? = nil, canceledBy: [Int]? = nil, beforeEnqueuedAt: Date? = nil, afterEnqueuedAt: Date? = nil, afterFinishedAt: Date? = nil, beforeStartedAt: Date? = nil, @@ -65,8 +65,8 @@ public class TasksQuery: Queryable { "from": from, "next": next, "uids": uids.isEmpty ? nil : uids.map(String.init).joined(separator: ","), - "types": types.isEmpty ? nil : types.joined(separator: ","), - "statuses": statuses.isEmpty ? nil : statuses.joined(separator: ","), + "types": types.isEmpty ? nil : types.map({ $0.description }).joined(separator: ","), + "statuses": statuses.isEmpty ? nil : statuses.map({ $0.rawValue }).joined(separator: ","), "indexUids": indexUids.isEmpty ? nil : indexUids.joined(separator: ","), "canceledBy": canceledBy.isEmpty ? nil : canceledBy.map(String.init).joined(separator: ","), "beforeEnqueuedAt": Formatter.formatOptionalDate(date: beforeEnqueuedAt), diff --git a/Sources/MeiliSearch/Request.swift b/Sources/MeiliSearch/Request.swift index bb73d4cc..9b363575 100755 --- a/Sources/MeiliSearch/Request.swift +++ b/Sources/MeiliSearch/Request.swift @@ -96,10 +96,15 @@ public final class Request { func post( api: String, + param: String? = nil, headers: [String: String] = [:], - _ data: Data, + _ data: Data?, _ completion: @escaping (Result) -> Void) { - guard let url = URL(string: config.url(api: api)) else { + var urlString: String = config.url(api: api) + if let param: String = param, !param.isEmpty { + urlString += param + } + guard let url = URL(string: urlString) else { completion(.failure(MeiliSearch.Error.invalidURL())) return } @@ -178,9 +183,14 @@ public final class Request { func delete( api: String, + param: String? = nil, headers: [String: String] = [:], _ completion: @escaping (Result) -> Void) { - guard let url = URL(string: config.url(api: api)) else { + var urlString: String = config.url(api: api) + if let param: String = param, !param.isEmpty { + urlString += param + } + guard let url = URL(string: urlString) else { completion(.failure(MeiliSearch.Error.invalidURL())) return } diff --git a/Sources/MeiliSearch/Tasks.swift b/Sources/MeiliSearch/Tasks.swift index a226fd7e..624884c9 100644 --- a/Sources/MeiliSearch/Tasks.swift +++ b/Sources/MeiliSearch/Tasks.swift @@ -136,4 +136,44 @@ struct Tasks { } } } + + // MARK: Cancel Tasks + + func cancelTasks( + _ params: CancelTasksQuery, + _ completion: @escaping (Result) -> Void) { + self.request.post(api: "/tasks/cancel", param: params.toQuery(), nil) { result in + switch result { + case .success(let data): + do { + let task: Result = try Constants.resultDecoder(data: data) + completion(task) + } catch { + completion(.failure(error)) + } + case .failure(let error): + completion(.failure(error)) + } + } + } + + // MARK: Delete Tasks + + func deleteTasks( + _ params: DeleteTasksQuery, + _ completion: @escaping (Result) -> Void) { + self.request.delete(api: "/tasks", param: params.toQuery()) { result in + switch result { + case .success(let data): + do { + let task: Result = try Constants.resultDecoder(data: data) + completion(task) + } catch { + completion(.failure(error)) + } + case .failure(let error): + completion(.failure(error)) + } + } + } } diff --git a/Tests/MeiliSearchIntegrationTests/DocumentsTests.swift b/Tests/MeiliSearchIntegrationTests/DocumentsTests.swift index fd71110a..ff95cb18 100755 --- a/Tests/MeiliSearchIntegrationTests/DocumentsTests.swift +++ b/Tests/MeiliSearchIntegrationTests/DocumentsTests.swift @@ -6,7 +6,7 @@ import Foundation #endif // swiftlint:disable force_unwrapping -// swiftlint:disable force_try + private let movies: [Movie] = [ Movie(id: 123, title: "Pride and Prejudice", comment: "A great book"), Movie(id: 456, title: "Le Petit Prince", comment: "A french book"), @@ -24,10 +24,10 @@ class DocumentsTests: XCTestCase { private var session: URLSessionProtocol! private let uid: String = "books_test" - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() session = URLSession(configuration: .ephemeral) - client = try! MeiliSearch(host: currentHost(), apiKey: "masterKey", session: session) + client = try MeiliSearch(host: currentHost(), apiKey: "masterKey", session: session) index = self.client.index(self.uid) let expectation = XCTestExpectation(description: "Create index if it does not exist") self.client.createIndex(uid: uid) { result in @@ -63,26 +63,13 @@ class DocumentsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("documentAdditionOrUpdate", task.type) + XCTAssertEqual("documentAdditionOrUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let indexedDocuments = details.indexedDocuments { - XCTAssertEqual(8, indexedDocuments) - } else { - XCTFail("IndexedDocuments field should not be nil") - } + if case .documentAdditionOrUpdate(let details) = task.details { + XCTAssertEqual(8, details.indexedDocuments) + XCTAssertEqual(8, details.receivedDocuments) } else { - XCTFail("IndexedDocuments field should exists in details field of task") - } - - if let details = task.details { - if let receivedDocuments = details.receivedDocuments { - XCTAssertEqual(8, receivedDocuments) - } else { - XCTFail("receivedDocuments field should not be nil") - } - } else { - XCTFail("receivedDocuments field should exists in details field of task") + XCTFail("documentAdditionOrUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -111,7 +98,7 @@ class DocumentsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("documentAdditionOrUpdate", task.type) + XCTAssertEqual("documentAdditionOrUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) expectation.fulfill() case .failure(let error): @@ -143,7 +130,7 @@ class DocumentsTests: XCTestCase { switch result { case .success(let task): XCTAssertEqual(Task.Status.succeeded, task.status) - XCTAssertEqual("documentAdditionOrUpdate", task.type) + XCTAssertEqual("documentAdditionOrUpdate", task.type.description) self.index.getDocuments(params: DocumentsQuery(limit: 1, offset: 1, fields: ["id", "title"])) { (result: Result, Swift.Error>) in switch result { @@ -189,9 +176,9 @@ class DocumentsTests: XCTestCase { self.wait(for: [expectation], timeout: 3.0) } - func testAddAndGetOneDocumentWithIntIdentifierAndSucceed() { + func testAddAndGetOneDocumentWithIntIdentifierAndSucceed() throws { let movie = Movie(id: 10, title: "test", comment: "test movie") - let documents: Data = try! JSONEncoder().encode([movie]) + let documents: Data = try JSONEncoder().encode([movie]) let expectation = XCTestExpectation(description: "Add or replace Movies document") self.index.addDocuments( @@ -204,7 +191,7 @@ class DocumentsTests: XCTestCase { switch result { case .success(let task): XCTAssertEqual(Task.Status.succeeded, task.status) - XCTAssertEqual("documentAdditionOrUpdate", task.type) + XCTAssertEqual("documentAdditionOrUpdate", task.type.description) self.index.getDocument(10 ) { (result: Result) in switch result { @@ -232,9 +219,9 @@ class DocumentsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testAddAndGetOneDocument() { + func testAddAndGetOneDocument() throws { let movie = Movie(id: 10, title: "test", comment: "test movie") - let documents: Data = try! JSONEncoder().encode([movie]) + let documents: Data = try JSONEncoder().encode([movie]) let expectation = XCTestExpectation(description: "Add or replace Movies document") self.index.addDocuments( @@ -247,7 +234,7 @@ class DocumentsTests: XCTestCase { switch result { case .success(let task): XCTAssertEqual(Task.Status.succeeded, task.status) - XCTAssertEqual("documentAdditionOrUpdate", task.type) + XCTAssertEqual("documentAdditionOrUpdate", task.type.description) self.index.getDocument("10" ) { (result: Result) in switch result { @@ -275,10 +262,10 @@ class DocumentsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testUpdateDocument() { + func testUpdateDocument() throws { let identifier: Int = 1844 let movie: Movie = movies.first(where: { (movie: Movie) in movie.id == identifier })! - let documents: Data = try! JSONEncoder().encode([movie]) + let documents: Data = try JSONEncoder().encode([movie]) let expectation = XCTestExpectation(description: "Add or update Movies document") @@ -292,7 +279,7 @@ class DocumentsTests: XCTestCase { switch result { case .success(let task): XCTAssertEqual(Task.Status.succeeded, task.status) - XCTAssertEqual("documentAdditionOrUpdate", task.type) + XCTAssertEqual("documentAdditionOrUpdate", task.type.description) expectation.fulfill() case .failure: XCTFail("Failed to wait for task") @@ -309,8 +296,8 @@ class DocumentsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testDeleteOneDocument() { - let documents: Data = try! JSONEncoder().encode(movies) + func testDeleteOneDocument() throws { + let documents: Data = try JSONEncoder().encode(movies) let expectation = XCTestExpectation(description: "Delete one Movie") self.index.addDocuments( @@ -335,7 +322,7 @@ class DocumentsTests: XCTestCase { switch result { case .success(let task): XCTAssertEqual(Task.Status.succeeded, task.status) - XCTAssertEqual("documentDeletion", task.type) + XCTAssertEqual("documentDeletion", task.type.description) deleteExpectation.fulfill() case .failure: XCTFail("Failed to wait for task") @@ -351,8 +338,8 @@ class DocumentsTests: XCTestCase { self.wait(for: [deleteExpectation], timeout: 3.0) } - func testDeleteAllDocuments() { - let documents: Data = try! JSONEncoder().encode(movies) + func testDeleteAllDocuments() throws { + let documents: Data = try JSONEncoder().encode(movies) let expectation = XCTestExpectation(description: "Add documents") self.index.addDocuments( @@ -377,17 +364,13 @@ class DocumentsTests: XCTestCase { switch result { case .success(let task): XCTAssertEqual(Task.Status.succeeded, task.status) - XCTAssertEqual("documentDeletion", task.type) - if let details = task.details { - if let deletedDocuments = details.deletedDocuments { - XCTAssertGreaterThanOrEqual(deletedDocuments, 8) - } else { - XCTFail("deletedDocuments field should not be nil") - deleteExpectation.fulfill() - } + XCTAssertEqual("documentDeletion", task.type.description) + if case .documentDeletion(let details) = task.details { + // It's possible for this to number to be greater than 8 (the number of documents we have inserted) due + // to other integration tests populating the shared index. + XCTAssertGreaterThanOrEqual(details.deletedDocuments ?? -1, 8) } else { - XCTFail("deletedDocuments field should exists in details field of task") - deleteExpectation.fulfill() + XCTFail("documentDeletion details should be set by task") } deleteExpectation.fulfill() case .failure: @@ -405,8 +388,8 @@ class DocumentsTests: XCTestCase { self.wait(for: [deleteExpectation], timeout: TESTS_TIME_OUT) } - func testDeleteBatchDocuments() { - let documents: Data = try! JSONEncoder().encode(movies) + func testDeleteBatchDocuments() throws { + let documents: Data = try JSONEncoder().encode(movies) let expectation = XCTestExpectation(description: "Add documents") self.index.addDocuments( @@ -433,7 +416,7 @@ class DocumentsTests: XCTestCase { switch result { case .success(let task): XCTAssertEqual(Task.Status.succeeded, task.status) - XCTAssertEqual("documentDeletion", task.type) + XCTAssertEqual("documentDeletion", task.type.description) deleteExpectation.fulfill() case .failure: XCTFail("Failed to wait for task") @@ -450,8 +433,8 @@ class DocumentsTests: XCTestCase { } @available(*, deprecated, message: "Testing deprecated methods - marked deprecated to avoid additional warnings below.") - func testDeprecatedDeleteBatchDocuments() { - let documents: Data = try! JSONEncoder().encode(movies) + func testDeprecatedDeleteBatchDocuments() throws { + let documents: Data = try JSONEncoder().encode(movies) let expectation = XCTestExpectation(description: "Add documents") self.index.addDocuments( @@ -478,7 +461,7 @@ class DocumentsTests: XCTestCase { switch result { case .success(let task): XCTAssertEqual(Task.Status.succeeded, task.status) - XCTAssertEqual("documentDeletion", task.type) + XCTAssertEqual("documentDeletion", task.type.description) deleteExpectation.fulfill() case .failure: XCTFail("Failed to wait for task") @@ -495,4 +478,3 @@ class DocumentsTests: XCTestCase { } } // swiftlint:enable force_unwrapping -// swiftlint:enable force_try diff --git a/Tests/MeiliSearchIntegrationTests/DumpsTests.swift b/Tests/MeiliSearchIntegrationTests/DumpsTests.swift index bb5dbe60..fc5db922 100644 --- a/Tests/MeiliSearchIntegrationTests/DumpsTests.swift +++ b/Tests/MeiliSearchIntegrationTests/DumpsTests.swift @@ -5,18 +5,17 @@ import Foundation import FoundationNetworking #endif -// swiftlint:disable force_try class DumpsTests: XCTestCase { private var client: MeiliSearch! private var session: URLSessionProtocol! // MARK: Setup - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() if client == nil { session = URLSession(configuration: .ephemeral) - client = try! MeiliSearch(host: currentHost(), apiKey: "masterKey", session: session) + client = try MeiliSearch(host: currentHost(), apiKey: "masterKey", session: session) } } @@ -38,4 +37,3 @@ class DumpsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } } -// swiftlint:enable force_try diff --git a/Tests/MeiliSearchIntegrationTests/IndexesTests.swift b/Tests/MeiliSearchIntegrationTests/IndexesTests.swift index d3f3ea9d..1a35568a 100644 --- a/Tests/MeiliSearchIntegrationTests/IndexesTests.swift +++ b/Tests/MeiliSearchIntegrationTests/IndexesTests.swift @@ -5,19 +5,18 @@ import Foundation import FoundationNetworking #endif -// swiftlint:disable force_try class IndexesTests: XCTestCase { private var client: MeiliSearch! private var session: URLSessionProtocol! private let uid: String = "books_test" private var index: Indexes! - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() if client == nil { session = URLSession(configuration: .ephemeral) - client = try! MeiliSearch(host: currentHost(), apiKey: "masterKey", session: session) + client = try MeiliSearch(host: currentHost(), apiKey: "masterKey", session: session) } index = self.client.index(self.uid) @@ -57,7 +56,7 @@ class IndexesTests: XCTestCase { self.client.waitForTask(task: task, options: WaitOptions(timeOut: 10.0)) { result in switch result { case .success(let task): - XCTAssertEqual("indexCreation", task.type) + XCTAssertEqual("indexCreation", task.type.description) XCTAssertEqual(task.status, Task.Status.succeeded) createExpectation.fulfill() case .failure(let error): @@ -93,7 +92,7 @@ class IndexesTests: XCTestCase { createGenericIndex(client: self.client, uid: self.uid ) { result in switch result { case .success(let task): - XCTAssertEqual("indexCreation", task.type) + XCTAssertEqual("indexCreation", task.type.description) XCTAssertEqual(task.status, Task.Status.succeeded) createExpectation.fulfill() case .failure(let error): @@ -111,7 +110,7 @@ class IndexesTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("indexCreation", task.type) + XCTAssertEqual("indexCreation", task.type.description) XCTAssertEqual(task.status, Task.Status.failed) if let error = task.error { XCTAssertEqual(error.code, "index_already_exists") @@ -221,14 +220,10 @@ class IndexesTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("indexUpdate", task.type) + XCTAssertEqual("indexUpdate", task.type.description) XCTAssertEqual(task.status, Task.Status.succeeded) - if let details = task.details { - if let primaryKey = details.primaryKey { - XCTAssertEqual("random", primaryKey) - } else { - XCTFail("Primary key should not be nil") - } + if case .indexUpdate(let details) = task.details, let primaryKey = details.primaryKey { + XCTAssertEqual("random", primaryKey) } else { XCTFail("Primary key should exists in details field of task") } @@ -267,7 +262,7 @@ class IndexesTests: XCTestCase { deleteIndex(client: self.client, uid: self.uid) { result in switch result { case .success(let task): - XCTAssertEqual("indexDeletion", task.type) + XCTAssertEqual("indexDeletion", task.type.description) XCTAssertEqual(task.status, Task.Status.succeeded) deleteException.fulfill() case .failure(let error): @@ -279,4 +274,3 @@ class IndexesTests: XCTestCase { self.wait(for: [deleteException], timeout: TESTS_TIME_OUT) } } -// swiftlint:enable force_try diff --git a/Tests/MeiliSearchIntegrationTests/KeysTests.swift b/Tests/MeiliSearchIntegrationTests/KeysTests.swift index f0342e54..c2e301b7 100644 --- a/Tests/MeiliSearchIntegrationTests/KeysTests.swift +++ b/Tests/MeiliSearchIntegrationTests/KeysTests.swift @@ -5,18 +5,17 @@ import Foundation import FoundationNetworking #endif -// swiftlint:disable force_try class KeysTests: XCTestCase { private var client: MeiliSearch! private var session: URLSessionProtocol! // MARK: Setup - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() session = URLSession(configuration: .ephemeral) - client = try! MeiliSearch(host: currentHost(), apiKey: "masterKey", session: session) + client = try MeiliSearch(host: currentHost(), apiKey: "masterKey", session: session) let semaphore = XCTestExpectation(description: "Setup: delete all keys") diff --git a/Tests/MeiliSearchIntegrationTests/SearchTests.swift b/Tests/MeiliSearchIntegrationTests/SearchTests.swift index be6dc51f..45af94eb 100644 --- a/Tests/MeiliSearchIntegrationTests/SearchTests.swift +++ b/Tests/MeiliSearchIntegrationTests/SearchTests.swift @@ -18,7 +18,7 @@ private let books: [Book] = [ ] // swiftlint:disable force_unwrapping -// swiftlint:disable force_try + private let nestedBooks: [NestedBook] = [ NestedBook(id: 123, title: "Pride and Prejudice", info: InfoNested(comment: "A great book", reviewNb: 100), genres: ["Classic Regency nove"]), NestedBook(id: 456, title: "Le Petit Prince", info: InfoNested(comment: "A french book", reviewNb: 100), genres: ["Novel"]), @@ -35,11 +35,11 @@ class SearchTests: XCTestCase { // MARK: Setup - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() session = URLSession(configuration: .ephemeral) - client = try! MeiliSearch(host: currentHost(), apiKey: "masterKey", session: session) + client = try MeiliSearch(host: currentHost(), apiKey: "masterKey", session: session) index = self.client.index(self.uid) nestedIndex = self.client.index(self.nested_uid) @@ -1132,4 +1132,3 @@ class SearchTests: XCTestCase { } } // swiftlint:enable force_unwrapping -// swiftlint:enable force_try diff --git a/Tests/MeiliSearchIntegrationTests/SettingsTests.swift b/Tests/MeiliSearchIntegrationTests/SettingsTests.swift index 6fda8e84..00d749cb 100644 --- a/Tests/MeiliSearchIntegrationTests/SettingsTests.swift +++ b/Tests/MeiliSearchIntegrationTests/SettingsTests.swift @@ -5,7 +5,6 @@ import Foundation import FoundationNetworking #endif -// swiftlint:disable force_try class SettingsTests: XCTestCase { private var client: MeiliSearch! private var index: Indexes! @@ -48,11 +47,11 @@ class SettingsTests: XCTestCase { // MARK: Setup - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() session = URLSession(configuration: .ephemeral) - client = try! MeiliSearch(host: currentHost(), apiKey: "masterKey", session: session) + client = try MeiliSearch(host: currentHost(), apiKey: "masterKey", session: session) index = self.client.index(self.uid) let createExpectation = XCTestExpectation(description: "Create Movies index") @@ -132,16 +131,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let filterableAttributes = details.filterableAttributes { - XCTAssertEqual(newFilterableAttributes, filterableAttributes) - } else { - XCTFail("filterableAttributes should not be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(newFilterableAttributes, details.filterableAttributes) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -169,7 +164,7 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) expectation.fulfill() case .failure(let error): @@ -218,16 +213,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let displayedAttributes = details.displayedAttributes { - XCTAssertEqual(newDisplayedAttributes, displayedAttributes) - } else { - XCTFail("displayedAttributes should not be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(newDisplayedAttributes, details.displayedAttributes) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -255,7 +246,7 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) expectation.fulfill() case .failure(let error): @@ -303,16 +294,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let distinctAttribute = details.distinctAttribute { - XCTAssertEqual(newDistinctAttribute, distinctAttribute) - } else { - XCTFail("distinctAttribute should not be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(newDistinctAttribute, details.distinctAttribute) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -339,7 +326,7 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) expectation.fulfill() case .failure(let error): @@ -393,16 +380,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let rankingRules = details.rankingRules { - XCTAssertEqual(newRankingRules, rankingRules) - } else { - XCTFail("rankingRules should not be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(newRankingRules, details.rankingRules) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -430,7 +413,7 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) expectation.fulfill() case .failure(let error): @@ -483,16 +466,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let searchableAttributes = details.searchableAttributes { - XCTAssertEqual(newSearchableAttributes, searchableAttributes) - } else { - XCTFail("searchableAttributes should not be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(newSearchableAttributes, details.searchableAttributes) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -520,7 +499,7 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) expectation.fulfill() case .failure(let error): @@ -577,16 +556,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let typoTolerance = details.typoTolerance { - XCTAssertEqual(newTypoTolerance, typoTolerance) - } else { - XCTFail("typoTolerance should not be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(newTypoTolerance, details.typoTolerance) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -614,7 +589,7 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) expectation.fulfill() case .failure(let error): @@ -668,16 +643,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let separatorTokens = details.separatorTokens { - XCTAssertEqual(newSeparatorTokens, separatorTokens) - } else { - XCTFail("separatorTokens should not be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(newSeparatorTokens, details.separatorTokens) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -705,7 +676,7 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) expectation.fulfill() case .failure(let error): @@ -759,16 +730,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let nonSeparatorTokens = details.nonSeparatorTokens { - XCTAssertEqual(newNonSeparatorTokens, nonSeparatorTokens) - } else { - XCTFail("nonSeparatorTokens should not be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(newNonSeparatorTokens, details.nonSeparatorTokens) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -796,7 +763,7 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) expectation.fulfill() case .failure(let error): @@ -850,16 +817,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let dictionary = details.dictionary { - XCTAssertEqual(newDictionary.sorted(), dictionary.sorted()) - } else { - XCTFail("dictionary should not be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(newDictionary.sorted(), details.dictionary?.sorted()) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -887,7 +850,7 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) expectation.fulfill() case .failure(let error): @@ -937,16 +900,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let pagination = details.pagination { - XCTAssertEqual(newPaginationSettings, pagination) - } else { - XCTFail("pagination should not be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(newPaginationSettings, details.pagination) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -974,7 +933,7 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) expectation.fulfill() case .failure(let error): @@ -1024,16 +983,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let stopWords = details.stopWords { - XCTAssertEqual(newStopWords, stopWords) - } else { - XCTFail("stopWords should not be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(newStopWords, details.stopWords) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -1062,16 +1017,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let stopWords = details.stopWords { - XCTAssertEqual(emptyStopWords, stopWords) - } else { - XCTFail("stopWords should be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(emptyStopWords, details.stopWords) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -1100,16 +1051,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if details.stopWords == nil { - XCTAssertEqual(nilStopWords, details.stopWords) - } else { - XCTFail("stopWords should be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(nilStopWords, details.stopWords) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -1137,7 +1084,7 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) expectation.fulfill() case .failure(let error): @@ -1192,16 +1139,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let synonyms = details.synonyms { - XCTAssertEqual(newSynonyms, synonyms) - } else { - XCTFail("synonyms should not be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(newSynonyms, details.synonyms) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -1230,16 +1173,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if let synonyms = details.synonyms { - XCTAssertEqual(newSynonyms, synonyms) - } else { - XCTFail("synonyms should not be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(newSynonyms, details.synonyms) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -1269,16 +1208,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { - if details.synonyms == nil { - XCTAssertEqual(newSynonyms, details.synonyms) - } else { - XCTFail("synonyms should not be nil") - } + if case .settingsUpdate(let details) = task.details { + XCTAssertEqual(newSynonyms, details.synonyms) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -1306,7 +1241,7 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) expectation.fulfill() case .failure(let error): @@ -1379,14 +1314,14 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { + if case .settingsUpdate(let details) = task.details { XCTAssertEqual(expectedSettingResult.rankingRules, details.rankingRules) XCTAssertEqual(expectedSettingResult.searchableAttributes, details.searchableAttributes) XCTAssertEqual(expectedSettingResult.stopWords, details.stopWords) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -1412,12 +1347,12 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { + if case .settingsUpdate(let details) = task.details { XCTAssertEqual(expectedSettingResult.rankingRules, details.rankingRules) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } overrideSettingsExpectation.fulfill() case .failure(let error): @@ -1476,9 +1411,9 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) - if let details = task.details { + if case .settingsUpdate(let details) = task.details { XCTAssertEqual(expectedSettingResult.rankingRules, details.rankingRules) XCTAssertEqual(expectedSettingResult.searchableAttributes, details.searchableAttributes) XCTAssertEqual(expectedSettingResult.displayedAttributes, details.displayedAttributes) @@ -1490,7 +1425,7 @@ class SettingsTests: XCTestCase { XCTAssertEqual(expectedSettingResult.dictionary, details.dictionary) XCTAssertEqual(expectedSettingResult.pagination.maxTotalHits, details.pagination?.maxTotalHits) } else { - XCTFail("details should exists in details field of task") + XCTFail("settingsUpdate details should be set by task") } expectation.fulfill() case .failure(let error): @@ -1518,7 +1453,7 @@ class SettingsTests: XCTestCase { self.client.waitForTask(task: task) { result in switch result { case .success(let task): - XCTAssertEqual("settingsUpdate", task.type) + XCTAssertEqual("settingsUpdate", task.type.description) XCTAssertEqual(Task.Status.succeeded, task.status) expectation.fulfill() case .failure(let error): @@ -1537,4 +1472,3 @@ class SettingsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } } -// swiftlint:enable force_try diff --git a/Tests/MeiliSearchIntegrationTests/TaskTests.swift b/Tests/MeiliSearchIntegrationTests/TaskTests.swift index e108a145..75bc4716 100644 --- a/Tests/MeiliSearchIntegrationTests/TaskTests.swift +++ b/Tests/MeiliSearchIntegrationTests/TaskTests.swift @@ -5,7 +5,6 @@ import Foundation import FoundationNetworking #endif -// swiftlint:disable force_try class TasksTests: XCTestCase { private var client: MeiliSearch! private var index: Indexes! @@ -14,10 +13,10 @@ class TasksTests: XCTestCase { // MARK: Setup - override func setUp() { - super.setUp() + override func setUpWithError() throws { + try super.setUpWithError() session = URLSession(configuration: .ephemeral) - client = try! MeiliSearch(host: currentHost(), apiKey: "masterKey", session: session) + client = try MeiliSearch(host: currentHost(), apiKey: "masterKey", session: session) index = self.client.index(self.uid) let createExpectation = XCTestExpectation(description: "Create Movies index") createGenericIndex(client: self.client, uid: self.uid) { result in @@ -43,7 +42,7 @@ class TasksTests: XCTestCase { self.index.getTask(taskUid: task.taskUid) { result in switch result { case .success(let task): - XCTAssertEqual(task.type, "documentAdditionOrUpdate") + XCTAssertEqual(task.type.description, "documentAdditionOrUpdate") addDocExpectation.fulfill() case .failure(let error): dump(error) @@ -75,6 +74,9 @@ class TasksTests: XCTestCase { case .success(let tasks): // Only one because index has been deleted and recreated XCTAssertEqual(tasks.results.count, 1) + XCTAssertEqual(tasks.total, 1) + XCTAssertNotNil(tasks.results[0].startedAt) + XCTAssertNotNil(tasks.results[0].finishedAt) expectation.fulfill() case .failure(let error): dump(error) @@ -105,7 +107,7 @@ class TasksTests: XCTestCase { self.client.getTask(taskUid: task.taskUid) { result in switch result { case .success(let task): - XCTAssertEqual(task.type, "indexCreation") + XCTAssertEqual(task.type.description, "indexCreation") addDocExpectation.fulfill() case .failure(let error): dump(error) @@ -152,6 +154,69 @@ class TasksTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } + func testCancelTask() { + let addDocExpectation = XCTestExpectation(description: "Add documents") + addDocuments(client: self.client, uid: self.uid, primaryKey: nil) { result in + switch result { + case .success(let task): + self.client.cancelTasks(filter: .init(uids: [task.uid])) { _ in + self.client.getTasks { result in + switch result { + case .success(let tasks): + XCTAssertGreaterThanOrEqual(tasks.results.count, 2) + XCTAssertEqual(tasks.results[0].type, .taskCancelation) + XCTAssertEqual(tasks.results[1].type, .documentAdditionOrUpdate) + case .failure(let error): + dump(error) + XCTFail("Failed to get tasks") + } + addDocExpectation.fulfill() + } + } + + case .failure: + XCTFail("Failed to add document") + addDocExpectation.fulfill() + } + } + self.wait(for: [addDocExpectation], timeout: TESTS_TIME_OUT) + } + + func testDeleteTask() { + let addDocExpectation = XCTestExpectation(description: "Add documents") + addDocuments(client: self.client, uid: self.uid, primaryKey: nil) { result in + switch result { + case .success(let task): + self.client.deleteTasks(filter: .init(uids: [task.uid])) { result in + switch result { + case .success(let taskInfo): + self.client.waitForTask(task: taskInfo) { _ in + self.client.getTasks { result in + switch result { + case .success(let tasks): + XCTAssertEqual(tasks.results[0].type, .taskDeletion) + XCTAssertNotEqual(tasks.results[1].uid, task.uid) + case .failure(let error): + dump(error) + XCTFail("Failed to get tasks") + } + + addDocExpectation.fulfill() + } + } + case .failure: + XCTFail("Failed to delete document") + addDocExpectation.fulfill() + } + } + case .failure: + XCTFail("Failed to add document") + addDocExpectation.fulfill() + } + } + self.wait(for: [addDocExpectation], timeout: TESTS_TIME_OUT) + } + func testWaitForTask() { let createIndexExpectation = XCTestExpectation(description: "Add documents") @@ -161,7 +226,7 @@ class TasksTests: XCTestCase { self.client.waitForTask(task: task, options: WaitOptions(timeOut: 1, interval: 0.5)) { result in switch result { case .success(let task): - XCTAssertEqual(task.type, "indexCreation") + XCTAssertEqual(task.type.description, "indexCreation") createIndexExpectation.fulfill() case .failure(let error): dump(error) @@ -186,7 +251,7 @@ class TasksTests: XCTestCase { self.client.waitForTask(taskUid: task.taskUid, options: WaitOptions(timeOut: 1, interval: 0.5)) { result in switch result { case .success(let task): - XCTAssertEqual(task.type, "indexCreation") + XCTAssertEqual(task.type.description, "indexCreation") createIndexExpectation.fulfill() case .failure(let error): dump(error) diff --git a/Tests/MeiliSearchIntegrationTests/Utils.swift b/Tests/MeiliSearchIntegrationTests/Utils.swift index a81207a3..8e780f8a 100644 --- a/Tests/MeiliSearchIntegrationTests/Utils.swift +++ b/Tests/MeiliSearchIntegrationTests/Utils.swift @@ -5,7 +5,6 @@ import Foundation import XCTest @testable import MeiliSearch -// swiftlint:disable force_try private let movies: [Movie] = [ Movie(id: 123, title: "Pride and Prejudice", comment: "A great book"), Movie(id: 456, title: "Le Petit Prince", comment: "A french book"), @@ -99,7 +98,13 @@ public func addDocuments(client: MeiliSearch, uid: String, primaryKey: String?, public func addDocuments(client: MeiliSearch, uid: String, dataset: [T], primaryKey: String?, _ completion: @escaping(Result) -> Void) { let jsonEncoder = JSONEncoder() - let documents: Data = try! jsonEncoder.encode(dataset) + let documents: Data + do { + documents = try jsonEncoder.encode(dataset) + } catch { + completion(.failure(error)) + return + } let index = client.index(uid) client.deleteIndex(uid) { result in diff --git a/Tests/MeiliSearchUnitTests/DocumentsTests.swift b/Tests/MeiliSearchUnitTests/DocumentsTests.swift index ccbf6555..0526b5e0 100755 --- a/Tests/MeiliSearchUnitTests/DocumentsTests.swift +++ b/Tests/MeiliSearchUnitTests/DocumentsTests.swift @@ -6,7 +6,7 @@ import Foundation #endif // swiftlint:disable force_unwrapping -// swiftlint:disable force_try + // swiftlint:disable line_length private struct Movie: Codable, Equatable { let id: Int @@ -28,21 +28,21 @@ class DocumentsTests: XCTestCase { private var uid: String = "movies_test" private let session = MockURLSession() - override func setUp() { - super.setUp() - client = try! MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) + override func setUpWithError() throws { + try super.setUpWithError() + client = try MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) index = self.client.index(self.uid) } - func testAddDocuments() { + func testAddDocuments() throws { let jsonString = """ {"taskUid":0,"indexUid":"books_test","status":"enqueued","type":"documentAdditionOrUpdate","enqueuedAt":"2022-07-21T21:47:50.565717794Z"} """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let jsonData = jsonString.data(using: .utf8)! - let stubTask: TaskInfo = try! decoder.decode(TaskInfo.self, from: jsonData) + let stubTask: TaskInfo = try decoder.decode(TaskInfo.self, from: jsonData) session.pushData(jsonString, code: 202) // Start the test with the mocked server @@ -69,15 +69,15 @@ class DocumentsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testAddDataDocuments() { + func testAddDataDocuments() throws { let jsonString = """ {"taskUid":0,"indexUid":"books_test","status":"enqueued","type":"documentAdditionOrUpdate","enqueuedAt":"2022-07-21T21:47:50.565717794Z"} """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let jsonData = jsonString.data(using: .utf8)! - let stubTask: TaskInfo = try! decoder.decode(TaskInfo.self, from: jsonData) + let stubTask: TaskInfo = try decoder.decode(TaskInfo.self, from: jsonData) session.pushData(jsonString, code: 202) let documentJsonString = """ @@ -112,15 +112,15 @@ class DocumentsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testUpdateDataDocuments() { + func testUpdateDataDocuments() throws { let jsonString = """ {"taskUid":0,"indexUid":"books_test","status":"enqueued","type":"documentAdditionOrUpdate","enqueuedAt":"2022-07-21T21:47:50.565717794Z"} """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let jsonData = jsonString.data(using: .utf8)! - let stubTask: TaskInfo = try! decoder.decode(TaskInfo.self, from: jsonData) + let stubTask: TaskInfo = try decoder.decode(TaskInfo.self, from: jsonData) session.pushData(jsonString, code: 202) let documentJsonString = """ [{ @@ -149,15 +149,15 @@ class DocumentsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testUpdateDocuments() { + func testUpdateDocuments() throws { let jsonString = """ {"taskUid":0,"indexUid":"books_test","status":"enqueued","type":"documentAdditionOrUpdate","enqueuedAt":"2022-07-21T21:47:50.565717794Z"} """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let jsonData = jsonString.data(using: .utf8)! - let stubTask: TaskInfo = try! decoder.decode(TaskInfo.self, from: jsonData) + let stubTask: TaskInfo = try decoder.decode(TaskInfo.self, from: jsonData) session.pushData(jsonString, code: 202) let movie = Movie( @@ -185,7 +185,7 @@ class DocumentsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testGetDocument() { + func testGetDocument() throws { let jsonString = """ { "id": 25684, @@ -198,10 +198,10 @@ class DocumentsTests: XCTestCase { // Prepare the mock server session.pushData(jsonString, code: 200) - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder decoder.dateDecodingStrategy = .formatted(Formatter.iso8601) let data = jsonString.data(using: .utf8)! - let stubMovie: Movie = try! decoder.decode(Movie.self, from: data) + let stubMovie: Movie = try decoder.decode(Movie.self, from: data) let identifier: String = "25684" // Start the test with the mocked server @@ -232,7 +232,7 @@ class DocumentsTests: XCTestCase { session.pushData(jsonString, code: 200) do { - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder decoder.dateDecodingStrategy = .formatted(Formatter.iso8601) let data = jsonString.data(using: .utf8)! let stubMovie: Movie = try decoder.decode(Movie.self, from: data) @@ -289,7 +289,7 @@ class DocumentsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testGetDocuments() { + func testGetDocuments() throws { let jsonString = """ { "results": [ @@ -316,10 +316,10 @@ class DocumentsTests: XCTestCase { // Prepare the mock server session.pushData(jsonString, code: 200) - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder decoder.dateDecodingStrategy = .formatted(Formatter.iso8601) let data = jsonString.data(using: .utf8)! - let stubMovies: DocumentsResults = try! decoder.decode(DocumentsResults.self, from: data) + let stubMovies: DocumentsResults = try decoder.decode(DocumentsResults.self, from: data) // Start the test with the mocked server let expectation = XCTestExpectation(description: "Get Movies documents") @@ -336,15 +336,15 @@ class DocumentsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testDeleteDocument() { + func testDeleteDocument() throws { let jsonString = """ {"taskUid":0,"indexUid":"books_test","status":"enqueued","type":"documentAdditionOrUpdate","enqueuedAt":"2022-07-21T21:47:50.565717794Z"} """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let jsonData = jsonString.data(using: .utf8)! - let stubTask: TaskInfo = try! decoder.decode(TaskInfo.self, from: jsonData) + let stubTask: TaskInfo = try decoder.decode(TaskInfo.self, from: jsonData) session.pushData(jsonString, code: 202) let identifier: String = "25684" @@ -364,15 +364,15 @@ class DocumentsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testDeleteAllDocuments() { + func testDeleteAllDocuments() throws { let jsonString = """ {"taskUid":0,"indexUid":"books_test","status":"enqueued","type":"documentAdditionOrUpdate","enqueuedAt":"2022-07-21T21:47:50.565717794Z"} """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let jsonData = jsonString.data(using: .utf8)! - let stubTask: TaskInfo = try! decoder.decode(TaskInfo.self, from: jsonData) + let stubTask: TaskInfo = try decoder.decode(TaskInfo.self, from: jsonData) session.pushData(jsonString, code: 202) // Start the test with the mocked server @@ -390,15 +390,15 @@ class DocumentsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testDeleteBatchDocuments() { + func testDeleteBatchDocuments() throws { let jsonString = """ {"taskUid":0,"indexUid":"books_test","status":"enqueued","type":"documentAdditionOrUpdate","enqueuedAt":"2022-07-21T21:47:50.565717794Z"} """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let jsonData = jsonString.data(using: .utf8)! - let stubTask: TaskInfo = try! decoder.decode(TaskInfo.self, from: jsonData) + let stubTask: TaskInfo = try decoder.decode(TaskInfo.self, from: jsonData) session.pushData(jsonString, code: 202) let documentsIdentifiers: [String] = ["23488", "153738", "437035", "363869"] @@ -418,15 +418,15 @@ class DocumentsTests: XCTestCase { } @available(*, deprecated, message: "Testing deprecated methods - marked deprecated to avoid additional warnings below.") - func testDeprecatedDeleteBatchDocuments() { + func testDeprecatedDeleteBatchDocuments() throws { let jsonString = """ {"taskUid":0,"indexUid":"books_test","status":"enqueued","type":"documentAdditionOrUpdate","enqueuedAt":"2022-07-21T21:47:50.565717794Z"} """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let jsonData = jsonString.data(using: .utf8)! - let stubTask: TaskInfo = try! decoder.decode(TaskInfo.self, from: jsonData) + let stubTask: TaskInfo = try decoder.decode(TaskInfo.self, from: jsonData) session.pushData(jsonString, code: 202) let documentsIdentifiers: [Int] = [23488, 153738, 437035, 363869] @@ -447,5 +447,5 @@ class DocumentsTests: XCTestCase { } // swiftlint:enable force_unwrapping // swiftlint:enable force_cast -// swiftlint:enable force_try + // swiftlint:enable line_length diff --git a/Tests/MeiliSearchUnitTests/DumpsTests.swift b/Tests/MeiliSearchUnitTests/DumpsTests.swift index 56f6b694..f2d27660 100644 --- a/Tests/MeiliSearchUnitTests/DumpsTests.swift +++ b/Tests/MeiliSearchUnitTests/DumpsTests.swift @@ -2,17 +2,17 @@ import XCTest // swiftlint:disable force_unwrapping -// swiftlint:disable force_try + class DumpsTests: XCTestCase { private var client: MeiliSearch! private let session = MockURLSession() - override func setUp() { - super.setUp() - client = try! MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) + override func setUpWithError() throws { + try super.setUpWithError() + client = try MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) } - func testCreateDump() { + func testCreateDump() throws { // Prepare the mock server let json = """ @@ -21,7 +21,7 @@ class DumpsTests: XCTestCase { let data = json.data(using: .utf8)! - let stubDump: TaskInfo = try! Constants.customJSONDecoder.decode(TaskInfo.self, from: data) + let stubDump: TaskInfo = try Constants.customJSONDecoder.decode(TaskInfo.self, from: data) session.pushData(json) @@ -43,4 +43,3 @@ class DumpsTests: XCTestCase { } } // swiftlint:enable force_unwrapping -// swiftlint:enable force_try diff --git a/Tests/MeiliSearchUnitTests/IndexesTests.swift b/Tests/MeiliSearchUnitTests/IndexesTests.swift index c32c1f4b..a2ea1133 100755 --- a/Tests/MeiliSearchUnitTests/IndexesTests.swift +++ b/Tests/MeiliSearchUnitTests/IndexesTests.swift @@ -1,16 +1,15 @@ @testable import MeiliSearch import XCTest -// swiftlint:disable force_try class IndexesTests: XCTestCase { private var client: MeiliSearch! private var index: Indexes! private let uid: String = "movies_test" private let session = MockURLSession() - override func setUp() { - super.setUp() - client = try! MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) + override func setUpWithError() throws { + try super.setUpWithError() + client = try MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) index = client.index(self.uid) } @@ -240,7 +239,8 @@ class IndexesTests: XCTestCase { "results": [], "limit": 20, "from": 5, - "next": 98 + "next": 98, + "total": 6 } """ @@ -250,7 +250,7 @@ class IndexesTests: XCTestCase { // Start the test with the mocked server let expectation = XCTestExpectation(description: "Get keys with parameters") - self.index.getTasks(params: TasksQuery(limit: 20, from: 5, next: 98, types: ["indexCreation"])) { result in + self.index.getTasks(params: TasksQuery(limit: 20, from: 5, next: 98, types: [.indexCreation])) { result in switch result { case .success: let requestQuery = self.session.nextDataTask.request?.url?.query @@ -320,4 +320,3 @@ class IndexesTests: XCTestCase { } } // swiftlint:enable force_unwrapping -// swiftlint:enable force_try diff --git a/Tests/MeiliSearchUnitTests/KeysTests.swift b/Tests/MeiliSearchUnitTests/KeysTests.swift index 9db15635..9eeda04b 100644 --- a/Tests/MeiliSearchUnitTests/KeysTests.swift +++ b/Tests/MeiliSearchUnitTests/KeysTests.swift @@ -1,17 +1,15 @@ @testable import MeiliSearch import XCTest -// swiftlint:disable force_try class KeysTests: XCTestCase { private var client: MeiliSearch! private var index: Indexes! private let uid: String = "movies_test" private let session = MockURLSession() - override func setUp() { - super.setUp() - - client = try! MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) + override func setUpWithError() throws { + try super.setUpWithError() + client = try MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) index = client.index(self.uid) } @@ -50,4 +48,3 @@ class KeysTests: XCTestCase { } } // swiftlint:enable force_unwrapping -// swiftlint:enable force_try diff --git a/Tests/MeiliSearchUnitTests/QueryParameters/TasksQueryTests.swift b/Tests/MeiliSearchUnitTests/QueryParameters/TasksQueryTests.swift index 78a5ca4c..b2fe61d1 100644 --- a/Tests/MeiliSearchUnitTests/QueryParameters/TasksQueryTests.swift +++ b/Tests/MeiliSearchUnitTests/QueryParameters/TasksQueryTests.swift @@ -8,7 +8,7 @@ class TasksQueryTests: XCTestCase { func testRenderedQuery() { let data: [[String: TasksQuery]] = [ ["?limit=2": TasksQuery(limit: 2)], - ["?from=99&limit=2&types=name,title": TasksQuery(limit: 2, from: 99, types: ["name", "title"])], + ["?from=99&limit=2&types=indexSwap,dumpCreation": TasksQuery(limit: 2, from: 99, types: [.indexSwap, .dumpCreation])], ["?limit=2": TasksQuery(limit: 2, next: nil)], ["?from=2": TasksQuery(from: 2)], ["?indexUids=my-index,123": TasksQuery(indexUids: ["my-index", "123"])], diff --git a/Tests/MeiliSearchUnitTests/SearchTests.swift b/Tests/MeiliSearchUnitTests/SearchTests.swift index a1a42f71..cd9ef8e3 100644 --- a/Tests/MeiliSearchUnitTests/SearchTests.swift +++ b/Tests/MeiliSearchUnitTests/SearchTests.swift @@ -2,7 +2,7 @@ import XCTest // swiftlint:disable force_unwrapping -// swiftlint:disable force_try + private struct Movie: Codable, Equatable { let id: Int let title: String @@ -24,13 +24,13 @@ class SearchTests: XCTestCase { private var index: Indexes! private let session = MockURLSession() - override func setUp() { - super.setUp() - client = try! MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) + override func setUpWithError() throws { + try super.setUpWithError() + client = try MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) index = client.index("movies_test") } - func testSearchForBotmanMovie() { + func testSearchForBotmanMovie() throws { let jsonString = """ { "hits": [ @@ -59,7 +59,7 @@ class SearchTests: XCTestCase { // Prepare the mock server let data = jsonString.data(using: .utf8)! - let stubSearchResult: Searchable = try! Constants.customJSONDecoder.decode(Searchable.self, from: data) + let stubSearchResult: Searchable = try Constants.customJSONDecoder.decode(Searchable.self, from: data) session.pushData(jsonString) // Start the test with the mocked server @@ -121,7 +121,7 @@ class SearchTests: XCTestCase { XCTAssertEqual(stubSearchResult, searchResult) } - func testSearchForBotmanMovieFacets() { + func testSearchForBotmanMovieFacets() throws { let jsonString = """ { "hits": [ @@ -150,7 +150,7 @@ class SearchTests: XCTestCase { // Prepare the mock server let data = jsonString.data(using: .utf8)! - let stubSearchResult: Searchable = try! Constants.customJSONDecoder.decode(Searchable.self, from: data) + let stubSearchResult: Searchable = try Constants.customJSONDecoder.decode(Searchable.self, from: data) session.pushData(jsonString) // Start the test with the mocked server @@ -287,7 +287,7 @@ class SearchTests: XCTestCase { wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testSearchWithFinitePagination() { + func testSearchWithFinitePagination() throws { let jsonString = """ { "hits": [ @@ -317,7 +317,7 @@ class SearchTests: XCTestCase { // Prepare the mock server let data = jsonString.data(using: .utf8)! - let stubSearchResult: Searchable = try! Constants.customJSONDecoder.decode(Searchable.self, from: data) + let stubSearchResult: Searchable = try Constants.customJSONDecoder.decode(Searchable.self, from: data) session.pushData(jsonString) // Start the test with the mocked server @@ -348,4 +348,3 @@ class SearchTests: XCTestCase { } } // swiftlint:enable force_unwrapping -// swiftlint:enable force_try diff --git a/Tests/MeiliSearchUnitTests/SettingsTests.swift b/Tests/MeiliSearchUnitTests/SettingsTests.swift index 642000d9..9edd3d44 100644 --- a/Tests/MeiliSearchUnitTests/SettingsTests.swift +++ b/Tests/MeiliSearchUnitTests/SettingsTests.swift @@ -86,7 +86,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let jsonData = Data(jsonString.utf8) let stubTask: TaskInfo = try decoder.decode(TaskInfo.self, from: jsonData) @@ -115,7 +115,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let data: Data = Data(jsonString.utf8) let stubTask: TaskInfo = try decoder.decode(TaskInfo.self, from: data) session.pushData(jsonString) @@ -176,7 +176,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -214,7 +214,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -271,7 +271,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -304,7 +304,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -370,7 +370,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -403,7 +403,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -458,7 +458,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -487,7 +487,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -544,7 +544,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -578,7 +578,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -634,7 +634,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -671,7 +671,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -725,7 +725,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -755,7 +755,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -810,7 +810,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -840,7 +840,7 @@ class SettingsTests: XCTestCase { """ // Prepare the mock server - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder let stubTask: TaskInfo = try decoder.decode( TaskInfo.self, from: Data(jsonString.utf8)) @@ -892,16 +892,14 @@ class SettingsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testUpdateTypoTolerance() { + func testUpdateTypoTolerance() throws { let jsonString = """ {"taskUid":0,"indexUid":"movies_test","status":"enqueued","type":"settingsUpdate","enqueuedAt":"2022-07-27T19:03:50.494232841Z"} """ // Prepare the mock server - let decoder = JSONDecoder() - let stubTask: TaskInfo = try! decoder.decode( - TaskInfo.self, - from: jsonString.data(using: .utf8)!) + let decoder = Constants.customJSONDecoder + let stubTask: TaskInfo = try decoder.decode(TaskInfo.self, from: Data(jsonString.utf8)) session.pushData(jsonString) let typoTolerance: TypoTolerance = .init(enabled: false) @@ -922,16 +920,14 @@ class SettingsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testResetTypoTolerance() { + func testResetTypoTolerance() throws { let jsonString = """ {"taskUid":0,"indexUid":"movies_test","status":"enqueued","type":"settingsUpdate","enqueuedAt":"2022-07-27T19:03:50.494232841Z"} """ // Prepare the mock server - let decoder = JSONDecoder() - let stubTask: TaskInfo = try! decoder.decode( - TaskInfo.self, - from: jsonString.data(using: .utf8)!) + let decoder = Constants.customJSONDecoder + let stubTask: TaskInfo = try decoder.decode(TaskInfo.self, from: Data(jsonString.utf8)) session.pushData(jsonString) // Start the test with the mocked server @@ -952,13 +948,13 @@ class SettingsTests: XCTestCase { private func buildStubSetting(from json: String) throws -> Setting { let data = Data(json.utf8) - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder return try decoder.decode(Setting.self, from: data) } private func buildStubSettingResult(from json: String) throws -> SettingResult { let data = Data(json.utf8) - let decoder = JSONDecoder() + let decoder = Constants.customJSONDecoder return try decoder.decode(SettingResult.self, from: data) } } diff --git a/Tests/MeiliSearchUnitTests/StatsTests.swift b/Tests/MeiliSearchUnitTests/StatsTests.swift index d9e509c0..601284c5 100755 --- a/Tests/MeiliSearchUnitTests/StatsTests.swift +++ b/Tests/MeiliSearchUnitTests/StatsTests.swift @@ -2,20 +2,20 @@ import XCTest // swiftlint:disable force_unwrapping -// swiftlint:disable force_try + class StatsTests: XCTestCase { private var client: MeiliSearch! private var index: Indexes! private var uid: String = "movies_test" private let session = MockURLSession() - override func setUp() { - super.setUp() - client = try! MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) + override func setUpWithError() throws { + try super.setUpWithError() + client = try MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) index = client.index(self.uid) } - func testStats() { + func testStats() throws { let jsonString = """ { "numberOfDocuments": 19654, @@ -32,7 +32,7 @@ class StatsTests: XCTestCase { // Prepare the mock server let jsonData = jsonString.data(using: .utf8)! - let stubStats: Stat = try! Constants.customJSONDecoder.decode(Stat.self, from: jsonData) + let stubStats: Stat = try Constants.customJSONDecoder.decode(Stat.self, from: jsonData) session.pushData(jsonString) @@ -51,7 +51,7 @@ class StatsTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testAllStats() { + func testAllStats() throws { let jsonString = """ { "databaseSize": 447819776, @@ -82,7 +82,7 @@ class StatsTests: XCTestCase { """ // Prepare the mock server let jsonData = jsonString.data(using: .utf8)! - let stubAllStats: AllStats = try! Constants.customJSONDecoder.decode(AllStats.self, from: jsonData) + let stubAllStats: AllStats = try Constants.customJSONDecoder.decode(AllStats.self, from: jsonData) session.pushData(jsonString) @@ -103,4 +103,3 @@ class StatsTests: XCTestCase { } } // swiftlint:enable force_unwrapping -// swiftlint:enable force_try diff --git a/Tests/MeiliSearchUnitTests/SystemTests.swift b/Tests/MeiliSearchUnitTests/SystemTests.swift index b0f44c53..0fa08ac4 100755 --- a/Tests/MeiliSearchUnitTests/SystemTests.swift +++ b/Tests/MeiliSearchUnitTests/SystemTests.swift @@ -2,18 +2,18 @@ import XCTest // swiftlint:disable force_unwrapping -// swiftlint:disable force_try + class SystemTests: XCTestCase { private var client: MeiliSearch! private let session = MockURLSession() - override func setUp() { - super.setUp() - client = try! MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) + override func setUpWithError() throws { + try super.setUpWithError() + client = try MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) } - func testHealthStatusAvailable() { + func testHealthStatusAvailable() throws { // Prepare the mock server let jsonString = """ @@ -24,7 +24,7 @@ class SystemTests: XCTestCase { let jsonData = jsonString.data(using: .utf8)! - let expectedHealthBody: Health = try! Constants.customJSONDecoder.decode(Health.self, from: jsonData) + let expectedHealthBody: Health = try Constants.customJSONDecoder.decode(Health.self, from: jsonData) session.pushData(jsonString, code: 200) @@ -93,7 +93,7 @@ class SystemTests: XCTestCase { self.wait(for: [expectation], timeout: TESTS_TIME_OUT) } - func testVersion() { + func testVersion() throws { // Prepare the mock server let jsonString = """ @@ -106,7 +106,7 @@ class SystemTests: XCTestCase { let jsonData = jsonString.data(using: .utf8)! - let stubVersion: Version = try! Constants.customJSONDecoder.decode(Version.self, from: jsonData) + let stubVersion: Version = try Constants.customJSONDecoder.decode(Version.self, from: jsonData) session.pushData(jsonString) @@ -128,4 +128,3 @@ class SystemTests: XCTestCase { } } // swiftlint:enable force_unwrapping -// swiftlint:enable force_try diff --git a/Tests/MeiliSearchUnitTests/TasksTests.swift b/Tests/MeiliSearchUnitTests/TasksTests.swift index d45df6f3..a27a5f69 100644 --- a/Tests/MeiliSearchUnitTests/TasksTests.swift +++ b/Tests/MeiliSearchUnitTests/TasksTests.swift @@ -1,16 +1,15 @@ @testable import MeiliSearch import XCTest -// swiftlint:disable force_try class TasksTests: XCTestCase { private var client: MeiliSearch! private var index: Indexes! private let uid: String = "movies_test" private let session = MockURLSession() - override func setUp() { - super.setUp() - client = try! MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) + override func setUpWithError() throws { + try super.setUpWithError() + client = try MeiliSearch(host: "http://localhost:7700", apiKey: "masterKey", session: session) index = client.index(self.uid) } @@ -20,7 +19,8 @@ class TasksTests: XCTestCase { "results": [], "limit": 20, "from": 5, - "next": 98 + "next": 98, + "total": 6 } """ @@ -30,7 +30,7 @@ class TasksTests: XCTestCase { // Start the test with the mocked server let expectation = XCTestExpectation(description: "Get keys with parameters") - self.client.getTasks(params: TasksQuery(limit: 20, from: 5, next: 98, types: ["indexCreation"])) { result in + self.client.getTasks(params: TasksQuery(limit: 20, from: 5, next: 98, types: [.indexCreation])) { result in switch result { case .success: let requestQuery = self.session.nextDataTask.request?.url?.query @@ -49,4 +49,3 @@ class TasksTests: XCTestCase { } } // swiftlint:enable force_unwrapping -// swiftlint:enable force_try