-
Notifications
You must be signed in to change notification settings - Fork 136
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add generic handler for requests in APIBaseTask
Unifies request + response handling for APIBaseTask instead of having individual methods for get, post, and delete.
- Loading branch information
Showing
3 changed files
with
236 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
173 changes: 173 additions & 0 deletions
173
Modules/Server/Tests/PocketCastsServerTests/APIBaseTaskTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
@testable import PocketCastsServer | ||
import XCTest | ||
|
||
final class APIBaseTaskTests: XCTestCase { | ||
|
||
func testGetRequest() { | ||
|
||
let expectation = self.expectation(description: "APIBaseTask should complete") | ||
let task = ApiBaseTask(urlConnection: URLConnection { request -> (Data?, URLResponse?) in | ||
XCTAssertEqual(request.httpMethod, "GET") | ||
expectation.fulfill() | ||
return (nil, HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)) | ||
}) | ||
|
||
let (_, response) = task.getToServer(url: "http://pocketcasts.com", token: "") | ||
|
||
XCTAssertEqual(response?.statusCode, 200) | ||
|
||
OperationQueue.main.addOperation(task) | ||
self.waitForExpectations(timeout: 5) | ||
} | ||
|
||
func testGetHeadersRequest() { | ||
let expectation = self.expectation(description: "APIBaseTask should complete") | ||
let task = ApiBaseTask(urlConnection: URLConnection { request -> (Data?, URLResponse?) in | ||
XCTAssertEqual(request.value(forHTTPHeaderField: "Test"), "TestValue") | ||
XCTAssertEqual(request.httpMethod, "GET") | ||
expectation.fulfill() | ||
return (nil, HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)) | ||
}) | ||
|
||
let (_, response) = task.getToServer(url: "http://pocketcasts.com", token: "", customHeaders: ["Test": "TestValue"]) | ||
|
||
XCTAssertEqual(response?.statusCode, 200) | ||
|
||
OperationQueue.main.addOperation(task) | ||
self.waitForExpectations(timeout: 5) | ||
} | ||
|
||
func testPostRequest() { | ||
let expectation = self.expectation(description: "APIBaseTask should complete") | ||
let task = ApiBaseTask(urlConnection: URLConnection { request -> (Data?, URLResponse?) in | ||
XCTAssertEqual(request.httpMethod, "POST") | ||
expectation.fulfill() | ||
return (nil, HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)) | ||
}) | ||
|
||
let (_, statusCode) = task.postToServer(url: "http://pocketcasts.com", token: "", data: Data()) | ||
|
||
XCTAssertEqual(statusCode, 200) | ||
|
||
OperationQueue.main.addOperation(task) | ||
self.waitForExpectations(timeout: 5) | ||
} | ||
|
||
func testEmptyResponsePostRequest() { | ||
let expectation = self.expectation(description: "APIBaseTask should complete") | ||
let task = ApiBaseTask(urlConnection: URLConnection { request -> (Data?, URLResponse?) in | ||
XCTAssertEqual(request.httpMethod, "POST") | ||
expectation.fulfill() | ||
return (nil, nil) | ||
}) | ||
|
||
let (data, statusCode) = task.postToServer(url: "http://pocketcasts.com", token: "", data: Data()) | ||
|
||
XCTAssertNil(data) | ||
XCTAssertEqual(statusCode, 500) | ||
|
||
OperationQueue.main.addOperation(task) | ||
self.waitForExpectations(timeout: 5) | ||
} | ||
|
||
func testDeleteRequest() { | ||
let expectation = self.expectation(description: "APIBaseTask should complete") | ||
let task = ApiBaseTask(urlConnection: URLConnection { request -> (Data?, URLResponse?) in | ||
XCTAssertEqual(request.httpMethod, "DELETE") | ||
expectation.fulfill() | ||
return (nil, HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)) | ||
}) | ||
|
||
let (_, statusCode) = task.deleteToServer(url: "http://pocketcasts.com", token: "", data: Data()) | ||
|
||
XCTAssertEqual(statusCode, 200) | ||
|
||
OperationQueue.main.addOperation(task) | ||
self.waitForExpectations(timeout: 5) | ||
} | ||
|
||
func testEmptyResponseDeleteRequest() { | ||
let expectation = self.expectation(description: "APIBaseTask should complete") | ||
let task = ApiBaseTask(urlConnection: URLConnection { request -> (Data?, URLResponse?) in | ||
XCTAssertEqual(request.httpMethod, "DELETE") | ||
expectation.fulfill() | ||
return (nil, nil) | ||
}) | ||
|
||
let (data, statusCode) = task.deleteToServer(url: "http://pocketcasts.com", token: nil, data: Data()) | ||
|
||
XCTAssertNil(data) | ||
XCTAssertEqual(statusCode, 500) | ||
|
||
OperationQueue.main.addOperation(task) | ||
self.waitForExpectations(timeout: 5) | ||
} | ||
|
||
// MARK: Generic Request tests | ||
|
||
/// Mocks requests for testing with standard checks for HTTPMethod and expectation to wait on response from callbacks. | ||
/// - Parameters: | ||
/// - httpMethod: The httpMethod to send | ||
/// - handler: An optional handler to produce a Data and HTTPURLResponse for a given URLRequest | ||
/// - Returns: Data and HTTPURLResponse | ||
private func genericRequest(httpMethod: HTTPMethod, handler: ((URLRequest) -> (Data?, HTTPURLResponse?))? = nil) -> (Data?, HTTPURLResponse?) { | ||
let expectation = self.expectation(description: "APIBaseTask should complete") | ||
let task = ApiBaseTask(urlConnection: URLConnection { request -> (Data?, HTTPURLResponse?) in | ||
XCTAssertEqual(request.httpMethod, httpMethod.rawValue) | ||
expectation.fulfill() | ||
if let response = handler?(request) { | ||
return response | ||
} else { | ||
return (nil, HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)) | ||
} | ||
}) | ||
|
||
let url = URL(string: "http://pocketcasts.com")! | ||
let (data, response) = task.requestToServer(url: url, method: httpMethod, token: nil, retryOnUnauthorized: false, customHeaders: nil, data: nil) | ||
|
||
OperationQueue.main.addOperation(task) | ||
self.waitForExpectations(timeout: 5) | ||
|
||
return (data, response) | ||
} | ||
|
||
func testGenericGetRequest() { | ||
let (data, response) = genericRequest(httpMethod: .get) | ||
|
||
XCTAssertNil(data) | ||
XCTAssertEqual(response?.statusCode, 200) | ||
} | ||
|
||
func testGenericPostRequest() { | ||
let (data, response) = genericRequest(httpMethod: .post) | ||
|
||
XCTAssertNil(data) | ||
XCTAssertEqual(response?.statusCode, 200) | ||
} | ||
|
||
func testGenericEmptyResponsePostRequest() { | ||
let (data, response) = genericRequest(httpMethod: .post) { _ in | ||
return (nil, nil) | ||
} | ||
|
||
XCTAssertNil(data) | ||
XCTAssertEqual(response?.statusCode, 500) | ||
} | ||
|
||
func testGenericDeleteRequest() { | ||
let (data, response) = genericRequest(httpMethod: .delete) | ||
|
||
XCTAssertNil(data) | ||
XCTAssertEqual(response?.statusCode, 200) | ||
} | ||
|
||
func testGenericEmptyResponseDeleteRequest() { | ||
let (data, response) = genericRequest(httpMethod: .delete) { _ in | ||
return (nil, nil) | ||
} | ||
|
||
XCTAssertNil(data) | ||
XCTAssertEqual(response?.statusCode, 500) | ||
} | ||
|
||
} |
31 changes: 31 additions & 0 deletions
31
Modules/Server/Tests/PocketCastsServerTests/MockRequestHandler.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
@testable import PocketCastsServer | ||
import XCTest | ||
|
||
struct MockRequestHandler { | ||
typealias Handler = ((URLRequest) throws -> (Data?, URLResponse?)) | ||
|
||
let handler: Handler | ||
|
||
init(handler: @escaping ((URLRequest) throws -> (Data?, URLResponse?))) { | ||
self.handler = handler | ||
} | ||
} | ||
|
||
extension MockRequestHandler: RequestHandler { | ||
func send(request: URLRequest, completion: @escaping (Data?, URLResponse?, Error?) -> Void) { | ||
do { | ||
let (data, response) = try handler(request) | ||
completion(data, response, nil) | ||
} catch let error { | ||
completion(nil, nil, error) | ||
} | ||
} | ||
} | ||
|
||
extension URLConnection { | ||
/// A convenient initializer to pass a block which returns data, response, and error for a given URLRequest. | ||
/// - Parameter mockHandler: The handler block (URLRequest) throws -> (Data, URLResponse?) | ||
convenience init(mockHandler: @escaping MockRequestHandler.Handler) { | ||
self.init(handler: MockRequestHandler(handler: mockHandler)) | ||
} | ||
} |