Skip to content

Commit

Permalink
Add delay to FakeRequests (#275)
Browse files Browse the repository at this point in the history
* Add test and initial implementation

* Add delay to other request types

* Clean up

* Clean up

* Tests
  • Loading branch information
3lvis authored Jul 10, 2024
1 parent 6bc97e6 commit 56901df
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 33 deletions.
11 changes: 10 additions & 1 deletion Sources/Networking/FakeRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ struct FakeRequest {
let responseType: Networking.ResponseType
let headerFields: [String: String]?
let statusCode: Int
let delay: Double

init(response: Any?, responseType: Networking.ResponseType, headerFields: [String : String]?, statusCode: Int, delay: Double) {
self.response = response
self.responseType = responseType
self.headerFields = headerFields
self.statusCode = statusCode
self.delay = delay
}

static func find(ofType type: Networking.RequestType, forPath path: String, in collection: [Networking.RequestType: [String: FakeRequest]]) throws -> FakeRequest? {
guard let requests = collection[type] else { return nil }
Expand Down Expand Up @@ -51,7 +60,7 @@ struct FakeRequest {

guard let stringData = responseString.data(using: .utf8) else { continue }
let finalJSON = try JSONSerialization.jsonObject(with: stringData, options: [])
return FakeRequest(response: finalJSON, responseType: fakeRequest.responseType, headerFields: fakeRequest.headerFields, statusCode: fakeRequest.statusCode)
return FakeRequest(response: finalJSON, responseType: fakeRequest.responseType, headerFields: fakeRequest.headerFields, statusCode: fakeRequest.statusCode, delay: fakeRequest.delay)
}
}

Expand Down
44 changes: 22 additions & 22 deletions Sources/Networking/Networking+HTTPRequests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public extension Networking {
/// - path: The path for the faked GET request.
/// - response: An `Any` that will be returned when a GET request is made to the specified path.
/// - statusCode: By default it's 200, if you provide any status code that is between 200 and 299 the response object will be returned, otherwise we will return an error containig the provided status code.
func fakeGET(_ path: String, response: Any?, headerFields: [String: String]? = nil, statusCode: Int = 200) {
registerFake(requestType: .get, path: path, headerFields: headerFields, response: response, responseType: .json, statusCode: statusCode)
func fakeGET(_ path: String, response: Any?, headerFields: [String: String]? = nil, statusCode: Int = 200, delay: Double = 0) {
registerFake(requestType: .get, path: path, headerFields: headerFields, response: response, responseType: .json, statusCode: statusCode, delay: delay)
}

/// Registers a fake GET request for the specified path using the contents of a file. After registering this, every GET request to the path, will return the contents of the registered file.
Expand All @@ -29,8 +29,8 @@ public extension Networking {
/// - path: The path for the faked GET request.
/// - fileName: The name of the file, whose contents will be registered as a reponse.
/// - bundle: The Bundle where the file is located.
func fakeGET(_ path: String, fileName: String, bundle: Bundle = Bundle.main) {
registerFake(requestType: .get, path: path, fileName: fileName, bundle: bundle)
func fakeGET(_ path: String, fileName: String, bundle: Bundle = Bundle.main, delay: Double = 0) {
registerFake(requestType: .get, path: path, fileName: fileName, bundle: bundle, delay: delay)
}

/// Cancels the GET request for the specified path. This causes the request to complete with error code URLError.cancelled.
Expand Down Expand Up @@ -61,8 +61,8 @@ public extension Networking {
/// - path: The path for the faked PATCH request.
/// - response: An `Any` that will be returned when a PATCH request is made to the specified path.
/// - statusCode: By default it's 200, if you provide any status code that is between 200 and 299 the response object will be returned, otherwise we will return an error containig the provided status code.
func fakePATCH(_ path: String, response: Any?, headerFields: [String: String]? = nil, statusCode: Int = 200) {
registerFake(requestType: .patch, path: path, headerFields: headerFields, response: response, responseType: .json, statusCode: statusCode)
func fakePATCH(_ path: String, response: Any?, headerFields: [String: String]? = nil, statusCode: Int = 200, delay: Double = 0) {
registerFake(requestType: .patch, path: path, headerFields: headerFields, response: response, responseType: .json, statusCode: statusCode, delay: delay)
}

/// Registers a fake PATCH request to the specified path using the contents of a file. After registering this, every PATCH request to the path, will return the contents of the registered file.
Expand All @@ -71,8 +71,8 @@ public extension Networking {
/// - path: The path for the faked PATCH request.
/// - fileName: The name of the file, whose contents will be registered as a reponse.
/// - bundle: The Bundle where the file is located.
func fakePATCH(_ path: String, fileName: String, bundle: Bundle = Bundle.main) {
registerFake(requestType: .patch, path: path, fileName: fileName, bundle: bundle)
func fakePATCH(_ path: String, fileName: String, bundle: Bundle = Bundle.main, delay: Double = 0) {
registerFake(requestType: .patch, path: path, fileName: fileName, bundle: bundle, delay: delay)
}

/// Cancels the PATCH request for the specified path. This causes the request to complete with error code URLError.cancelled.
Expand Down Expand Up @@ -103,8 +103,8 @@ public extension Networking {
/// - path: The path for the faked PUT request.
/// - response: An `Any` that will be returned when a PUT request is made to the specified path.
/// - statusCode: By default it's 200, if you provide any status code that is between 200 and 299 the response object will be returned, otherwise we will return an error containig the provided status code.
func fakePUT(_ path: String, response: Any?, headerFields: [String: String]? = nil, statusCode: Int = 200) {
registerFake(requestType: .put, path: path, headerFields: headerFields, response: response, responseType: .json, statusCode: statusCode)
func fakePUT(_ path: String, response: Any?, headerFields: [String: String]? = nil, statusCode: Int = 200, delay: Double = 0) {
registerFake(requestType: .put, path: path, headerFields: headerFields, response: response, responseType: .json, statusCode: statusCode, delay: delay)
}

/// Registers a fake PUT request to the specified path using the contents of a file. After registering this, every PUT request to the path, will return the contents of the registered file.
Expand All @@ -113,8 +113,8 @@ public extension Networking {
/// - path: The path for the faked PUT request.
/// - fileName: The name of the file, whose contents will be registered as a reponse.
/// - bundle: The Bundle where the file is located.
func fakePUT(_ path: String, fileName: String, bundle: Bundle = Bundle.main) {
registerFake(requestType: .put, path: path, fileName: fileName, bundle: bundle)
func fakePUT(_ path: String, fileName: String, bundle: Bundle = Bundle.main, delay: Double = 0) {
registerFake(requestType: .put, path: path, fileName: fileName, bundle: bundle, delay: delay)
}

/// Cancels the PUT request for the specified path. This causes the request to complete with error code URLError.cancelled.
Expand Down Expand Up @@ -155,8 +155,8 @@ public extension Networking {
/// - path: The path for the faked POST request.
/// - response: An `Any` that will be returned when a POST request is made to the specified path.
/// - statusCode: By default it's 200, if you provide any status code that is between 200 and 299 the response object will be returned, otherwise we will return an error containig the provided status code.
func fakePOST(_ path: String, response: Any?, headerFields: [String: String]? = nil, statusCode: Int = 200) {
registerFake(requestType: .post, path: path, headerFields: headerFields, response: response, responseType: .json, statusCode: statusCode)
func fakePOST(_ path: String, response: Any?, headerFields: [String: String]? = nil, statusCode: Int = 200, delay: Double = 0) {
registerFake(requestType: .post, path: path, headerFields: headerFields, response: response, responseType: .json, statusCode: statusCode, delay: delay)
}

/// Registers a fake POST request to the specified path using the contents of a file. After registering this, every POST request to the path, will return the contents of the registered file.
Expand All @@ -165,8 +165,8 @@ public extension Networking {
/// - path: The path for the faked POST request.
/// - fileName: The name of the file, whose contents will be registered as a reponse.
/// - bundle: The Bundle where the file is located.
func fakePOST(_ path: String, fileName: String, bundle: Bundle = Bundle.main) {
registerFake(requestType: .post, path: path, fileName: fileName, bundle: bundle)
func fakePOST(_ path: String, fileName: String, bundle: Bundle = Bundle.main, delay: Double = 0) {
registerFake(requestType: .post, path: path, fileName: fileName, bundle: bundle, delay: delay)
}

/// Cancels the POST request for the specified path. This causes the request to complete with error code URLError.cancelled.
Expand Down Expand Up @@ -197,8 +197,8 @@ public extension Networking {
/// - path: The path for the faked DELETE request.
/// - response: An `Any` that will be returned when a DELETE request is made to the specified path.
/// - statusCode: By default it's 200, if you provide any status code that is between 200 and 299 the response object will be returned, otherwise we will return an error containig the provided status code.
func fakeDELETE(_ path: String, response: Any?, headerFields: [String: String]? = nil, statusCode: Int = 200) {
registerFake(requestType: .delete, path: path, headerFields: headerFields, response: response, responseType: .json, statusCode: statusCode)
func fakeDELETE(_ path: String, response: Any?, headerFields: [String: String]? = nil, statusCode: Int = 200, delay: Double = 0) {
registerFake(requestType: .delete, path: path, headerFields: headerFields, response: response, responseType: .json, statusCode: statusCode, delay: delay)
}

/// Registers a fake DELETE request to the specified path using the contents of a file. After registering this, every DELETE request to the path, will return the contents of the registered file.
Expand All @@ -207,8 +207,8 @@ public extension Networking {
/// - path: The path for the faked DELETE request.
/// - fileName: The name of the file, whose contents will be registered as a reponse.
/// - bundle: The Bundle where the file is located.
func fakeDELETE(_ path: String, fileName: String, bundle: Bundle = Bundle.main) {
registerFake(requestType: .delete, path: path, fileName: fileName, bundle: bundle)
func fakeDELETE(_ path: String, fileName: String, bundle: Bundle = Bundle.main, delay: Double = 0) {
registerFake(requestType: .delete, path: path, fileName: fileName, bundle: bundle, delay: delay)
}

/// Cancels the DELETE request for the specified path. This causes the request to complete with error code URLError.cancelled.
Expand Down Expand Up @@ -259,8 +259,8 @@ public extension Networking {
/// - path: The path for the faked image download request.
/// - image: An image that will be returned when there's a request to the registered path.
/// - statusCode: The status code to be used when faking the request.
func fakeImageDownload(_ path: String, image: Image, headerFields: [String: String]? = nil, statusCode: Int = 200) {
registerFake(requestType: .get, path: path, headerFields: headerFields, response: image, responseType: .image, statusCode: statusCode)
func fakeImageDownload(_ path: String, image: Image, headerFields: [String: String]? = nil, statusCode: Int = 200, delay: Double = 0) {
registerFake(requestType: .get, path: path, headerFields: headerFields, response: image, responseType: .image, statusCode: statusCode, delay: delay)
}

/// Downloads data from a URL, caching the result.
Expand Down
20 changes: 16 additions & 4 deletions Sources/Networking/Networking+Private.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ extension Networking {
}
}

func registerFake(requestType: RequestType, path: String, fileName: String, bundle: Bundle) {
func registerFake(requestType: RequestType, path: String, fileName: String, bundle: Bundle, delay: Double) {
do {
if let result = try FileManager.json(from: fileName, bundle: bundle) {
registerFake(requestType: requestType, path: path, headerFields: nil, response: result, responseType: .json, statusCode: 200)
registerFake(requestType: requestType, path: path, headerFields: nil, response: result, responseType: .json, statusCode: 200, delay: delay)
}
} catch ParsingError.notFound {
fatalError("We couldn't find \(fileName), are you sure is there?")
Expand All @@ -52,9 +52,9 @@ extension Networking {
}
}

func registerFake(requestType: RequestType, path: String, headerFields: [String: String]?, response: Any?, responseType: ResponseType, statusCode: Int) {
func registerFake(requestType: RequestType, path: String, headerFields: [String: String]?, response: Any?, responseType: ResponseType, statusCode: Int, delay: Double) {
var requests = fakeRequests[requestType] ?? [String: FakeRequest]()
requests[path] = FakeRequest(response: response, responseType: responseType, headerFields: headerFields, statusCode: statusCode)
requests[path] = FakeRequest(response: response, responseType: responseType, headerFields: headerFields, statusCode: statusCode, delay: delay)
fakeRequests[requestType] = requests
}

Expand Down Expand Up @@ -86,6 +86,10 @@ extension Networking {

if let fakeRequest = try FakeRequest.find(ofType: requestType, forPath: path, in: fakeRequests) {
let (_, response, error) = try handleFakeRequest(fakeRequest, path: path, cacheName: cacheName, cachingLevel: cachingLevel)
if fakeRequest.delay > 0 {
let nanoseconds = UInt64(fakeRequest.delay * 1_000_000_000)
try? await Task.sleep(nanoseconds: nanoseconds)
}
return try JSONResult(body: fakeRequest.response, response: response, error: error)
} else {
switch cachingLevel {
Expand All @@ -110,6 +114,10 @@ extension Networking {
func handleDataRequest(_ requestType: RequestType, path: String, cacheName: String?, cachingLevel: CachingLevel, responseType: ResponseType) async throws -> DataResult {
if let fakeRequests = fakeRequests[requestType], let fakeRequest = fakeRequests[path] {
let (_, response, error) = try handleFakeRequest(fakeRequest, path: path, cacheName: cacheName, cachingLevel: cachingLevel)
if fakeRequest.delay > 0 {
let nanoseconds = UInt64(fakeRequest.delay * 1_000_000_000)
try? await Task.sleep(nanoseconds: nanoseconds)
}
return DataResult(body: fakeRequest.response, response: response, error: error)
} else {
let object = try objectFromCache(for: path, cacheName: cacheName, cachingLevel: cachingLevel, responseType: responseType)
Expand All @@ -132,6 +140,10 @@ extension Networking {
func handleImageRequest(_ requestType: RequestType, path: String, cacheName: String?, cachingLevel: CachingLevel, responseType: ResponseType) async throws -> ImageResult {
if let fakeRequests = fakeRequests[requestType], let fakeRequest = fakeRequests[path] {
let (_, response, error) = try handleFakeRequest(fakeRequest, path: path, cacheName: cacheName, cachingLevel: cachingLevel)
if fakeRequest.delay > 0 {
let nanoseconds = UInt64(fakeRequest.delay * 1_000_000_000)
try? await Task.sleep(nanoseconds: nanoseconds)
}
return ImageResult(body: fakeRequest.response, response: response, error: error)
} else {
let object = try objectFromCache(for: path, cacheName: cacheName, cachingLevel: cachingLevel, responseType: responseType)
Expand Down
Loading

0 comments on commit 56901df

Please sign in to comment.