Skip to content

Commit

Permalink
Add ResumableTask to URLSessionImplementations.mustache (#18438)
Browse files Browse the repository at this point in the history
* Add `ResumableTask` to `URLSessionImplementations.mustache`

- Makes it testable
- Implementations can return something _other_ than a URLSessionDataTask if they want to implement another request format (sockets maybe?)
- Default implementation for `URLSession` provided

* Regenerate examples

* Add more properties and rename to `CancelableResumableTask`

* Regen samples

* Rename missed reference

* Missed some generated classes somehow

* Rename from `CancellableResumableTask` to `URLSessionDataTaskProtocol`

Rename from `resumableTask` to `dataTaskFromProtocol`

---------

Co-authored-by: welshm-ideogram <[email protected]>
  • Loading branch information
welshm and welshm-ideogram authored Apr 22, 2024
1 parent cbf52ae commit a724c75
Show file tree
Hide file tree
Showing 34 changed files with 459 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,9 @@ extension NullEncodable: Codable where Wrapped: Codable {
}
{{/useAlamofire}}
{{^useAlamofire}}
private var task: URLSessionTask?
private var task: URLSessionDataTaskProtocol?

internal func set(task: URLSessionTask) {
internal func set(task: URLSessionDataTaskProtocol) {
lock.lock()
defer { lock.unlock() }
self.task = task
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,33 @@ import MobileCoreServices
import UniformTypeIdentifiers
#endif

// Protocol defined for a session data task. This allows mocking out the URLSessionProtocol below since
// you may not want to create or return a real URLSessionDataTask.
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} protocol URLSessionDataTaskProtocol {
func resume()
var taskIdentifier: Int { get }

var progress: Progress { get }

func cancel()
}

// Protocol allowing implementations to alter what is returned or to test their implementations.
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} protocol URLSessionProtocol {
func dataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
// Task which performs the network fetch. Expected to be from URLSession.dataTask(with:completionHandler:) such that a network request
// is sent off when `.resume()` is called.
func dataTaskFromProtocol(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTaskProtocol
}

extension URLSession: URLSessionProtocol {
// Passthrough to URLSession.dataTask(with:completionHandler) since URLSessionDataTask conforms to URLSessionDataTaskProtocol and fetches the network data.
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func dataTaskFromProtocol(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, (any Error)?) -> Void) -> any URLSessionDataTaskProtocol {
return dataTask(with: request, completionHandler: completionHandler)
}
}

extension URLSession: URLSessionProtocol {}
extension URLSessionDataTask: URLSessionDataTaskProtocol {}

class URLSessionRequestBuilderFactory: RequestBuilderFactory {
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
Expand Down Expand Up @@ -136,7 +158,7 @@ private var credentialStore = SynchronizedDictionary<Int, URLCredential>()
}
}

let dataTask = urlSession.dataTask(with: request) { data, response, error in
let dataTask = urlSession.dataTaskFromProtocol(with: request) { data, response, error in
apiResponseQueue.async {
self.processRequestResponse(urlRequest: request, data: data, response: response, error: error, completion: completion)
cleanupRequest()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ open class Response<T> {

public final class RequestTask {
private var lock = NSRecursiveLock()
private var task: URLSessionTask?
private var task: URLSessionDataTaskProtocol?

internal func set(task: URLSessionTask) {
internal func set(task: URLSessionDataTaskProtocol) {
lock.lock()
defer { lock.unlock() }
self.task = task
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,33 @@ import MobileCoreServices
import UniformTypeIdentifiers
#endif

// Protocol defined for a session data task. This allows mocking out the URLSessionProtocol below since
// you may not want to create or return a real URLSessionDataTask.
public protocol URLSessionDataTaskProtocol {
func resume()

var taskIdentifier: Int { get }

var progress: Progress { get }

func cancel()
}

// Protocol allowing implementations to alter what is returned or to test their implementations.
public protocol URLSessionProtocol {
func dataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
// Task which performs the network fetch. Expected to be from URLSession.dataTask(with:completionHandler:) such that a network request
// is sent off when `.resume()` is called.
func dataTaskFromProtocol(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTaskProtocol
}

extension URLSession: URLSessionProtocol {
// Passthrough to URLSession.dataTask(with:completionHandler) since URLSessionDataTask conforms to URLSessionDataTaskProtocol and fetches the network data.
public func dataTaskFromProtocol(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, (any Error)?) -> Void) -> any URLSessionDataTaskProtocol {
return dataTask(with: request, completionHandler: completionHandler)
}
}

extension URLSession: URLSessionProtocol {}
extension URLSessionDataTask: URLSessionDataTaskProtocol {}

class URLSessionRequestBuilderFactory: RequestBuilderFactory {
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
Expand Down Expand Up @@ -136,7 +158,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
}
}

let dataTask = urlSession.dataTask(with: request) { data, response, error in
let dataTask = urlSession.dataTaskFromProtocol(with: request) { data, response, error in
apiResponseQueue.async {
self.processRequestResponse(urlRequest: request, data: data, response: response, error: error, completion: completion)
cleanupRequest()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ open class Response<T> {

public final class RequestTask: @unchecked Sendable {
private var lock = NSRecursiveLock()
private var task: URLSessionTask?
private var task: URLSessionDataTaskProtocol?

internal func set(task: URLSessionTask) {
internal func set(task: URLSessionDataTaskProtocol) {
lock.lock()
defer { lock.unlock() }
self.task = task
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,33 @@ import MobileCoreServices
import UniformTypeIdentifiers
#endif

// Protocol defined for a session data task. This allows mocking out the URLSessionProtocol below since
// you may not want to create or return a real URLSessionDataTask.
public protocol URLSessionDataTaskProtocol {
func resume()

var taskIdentifier: Int { get }

var progress: Progress { get }

func cancel()
}

// Protocol allowing implementations to alter what is returned or to test their implementations.
public protocol URLSessionProtocol {
func dataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
// Task which performs the network fetch. Expected to be from URLSession.dataTask(with:completionHandler:) such that a network request
// is sent off when `.resume()` is called.
func dataTaskFromProtocol(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTaskProtocol
}

extension URLSession: URLSessionProtocol {
// Passthrough to URLSession.dataTask(with:completionHandler) since URLSessionDataTask conforms to URLSessionDataTaskProtocol and fetches the network data.
public func dataTaskFromProtocol(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, (any Error)?) -> Void) -> any URLSessionDataTaskProtocol {
return dataTask(with: request, completionHandler: completionHandler)
}
}

extension URLSession: URLSessionProtocol {}
extension URLSessionDataTask: URLSessionDataTaskProtocol {}

class URLSessionRequestBuilderFactory: RequestBuilderFactory {
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
Expand Down Expand Up @@ -136,7 +158,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
}
}

let dataTask = urlSession.dataTask(with: request) { data, response, error in
let dataTask = urlSession.dataTaskFromProtocol(with: request) { data, response, error in
apiResponseQueue.async {
self.processRequestResponse(urlRequest: request, data: data, response: response, error: error, completion: completion)
cleanupRequest()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ open class Response<T> {

public final class RequestTask {
private var lock = NSRecursiveLock()
private var task: URLSessionTask?
private var task: URLSessionDataTaskProtocol?

internal func set(task: URLSessionTask) {
internal func set(task: URLSessionDataTaskProtocol) {
lock.lock()
defer { lock.unlock() }
self.task = task
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,33 @@ import MobileCoreServices
import UniformTypeIdentifiers
#endif

// Protocol defined for a session data task. This allows mocking out the URLSessionProtocol below since
// you may not want to create or return a real URLSessionDataTask.
public protocol URLSessionDataTaskProtocol {
func resume()

var taskIdentifier: Int { get }

var progress: Progress { get }

func cancel()
}

// Protocol allowing implementations to alter what is returned or to test their implementations.
public protocol URLSessionProtocol {
func dataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
// Task which performs the network fetch. Expected to be from URLSession.dataTask(with:completionHandler:) such that a network request
// is sent off when `.resume()` is called.
func dataTaskFromProtocol(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTaskProtocol
}

extension URLSession: URLSessionProtocol {
// Passthrough to URLSession.dataTask(with:completionHandler) since URLSessionDataTask conforms to URLSessionDataTaskProtocol and fetches the network data.
public func dataTaskFromProtocol(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, (any Error)?) -> Void) -> any URLSessionDataTaskProtocol {
return dataTask(with: request, completionHandler: completionHandler)
}
}

extension URLSession: URLSessionProtocol {}
extension URLSessionDataTask: URLSessionDataTaskProtocol {}

class URLSessionRequestBuilderFactory: RequestBuilderFactory {
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
Expand Down Expand Up @@ -136,7 +158,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
}
}

let dataTask = urlSession.dataTask(with: request) { data, response, error in
let dataTask = urlSession.dataTaskFromProtocol(with: request) { data, response, error in
apiResponseQueue.async {
self.processRequestResponse(urlRequest: request, data: data, response: response, error: error, completion: completion)
cleanupRequest()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ open class Response<T> {

public final class RequestTask {
private var lock = NSRecursiveLock()
private var task: URLSessionTask?
private var task: URLSessionDataTaskProtocol?

internal func set(task: URLSessionTask) {
internal func set(task: URLSessionDataTaskProtocol) {
lock.lock()
defer { lock.unlock() }
self.task = task
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,33 @@ import MobileCoreServices
import UniformTypeIdentifiers
#endif

// Protocol defined for a session data task. This allows mocking out the URLSessionProtocol below since
// you may not want to create or return a real URLSessionDataTask.
public protocol URLSessionDataTaskProtocol {
func resume()

var taskIdentifier: Int { get }

var progress: Progress { get }

func cancel()
}

// Protocol allowing implementations to alter what is returned or to test their implementations.
public protocol URLSessionProtocol {
func dataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
// Task which performs the network fetch. Expected to be from URLSession.dataTask(with:completionHandler:) such that a network request
// is sent off when `.resume()` is called.
func dataTaskFromProtocol(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTaskProtocol
}

extension URLSession: URLSessionProtocol {
// Passthrough to URLSession.dataTask(with:completionHandler) since URLSessionDataTask conforms to URLSessionDataTaskProtocol and fetches the network data.
public func dataTaskFromProtocol(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, (any Error)?) -> Void) -> any URLSessionDataTaskProtocol {
return dataTask(with: request, completionHandler: completionHandler)
}
}

extension URLSession: URLSessionProtocol {}
extension URLSessionDataTask: URLSessionDataTaskProtocol {}

class URLSessionRequestBuilderFactory: RequestBuilderFactory {
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
Expand Down Expand Up @@ -136,7 +158,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
}
}

let dataTask = urlSession.dataTask(with: request) { data, response, error in
let dataTask = urlSession.dataTaskFromProtocol(with: request) { data, response, error in
apiResponseQueue.async {
self.processRequestResponse(urlRequest: request, data: data, response: response, error: error, completion: completion)
cleanupRequest()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ open class Response<T> {

public final class RequestTask {
private var lock = NSRecursiveLock()
private var task: URLSessionTask?
private var task: URLSessionDataTaskProtocol?

internal func set(task: URLSessionTask) {
internal func set(task: URLSessionDataTaskProtocol) {
lock.lock()
defer { lock.unlock() }
self.task = task
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,33 @@ import MobileCoreServices
import UniformTypeIdentifiers
#endif

// Protocol defined for a session data task. This allows mocking out the URLSessionProtocol below since
// you may not want to create or return a real URLSessionDataTask.
public protocol URLSessionDataTaskProtocol {
func resume()

var taskIdentifier: Int { get }

var progress: Progress { get }

func cancel()
}

// Protocol allowing implementations to alter what is returned or to test their implementations.
public protocol URLSessionProtocol {
func dataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
// Task which performs the network fetch. Expected to be from URLSession.dataTask(with:completionHandler:) such that a network request
// is sent off when `.resume()` is called.
func dataTaskFromProtocol(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTaskProtocol
}

extension URLSession: URLSessionProtocol {
// Passthrough to URLSession.dataTask(with:completionHandler) since URLSessionDataTask conforms to URLSessionDataTaskProtocol and fetches the network data.
public func dataTaskFromProtocol(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, (any Error)?) -> Void) -> any URLSessionDataTaskProtocol {
return dataTask(with: request, completionHandler: completionHandler)
}
}

extension URLSession: URLSessionProtocol {}
extension URLSessionDataTask: URLSessionDataTaskProtocol {}

class URLSessionRequestBuilderFactory: RequestBuilderFactory {
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
Expand Down Expand Up @@ -136,7 +158,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
}
}

let dataTask = urlSession.dataTask(with: request) { data, response, error in
let dataTask = urlSession.dataTaskFromProtocol(with: request) { data, response, error in
apiResponseQueue.async {
self.processRequestResponse(urlRequest: request, data: data, response: response, error: error, completion: completion)
cleanupRequest()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,9 @@ open class Response<T> {

public final class RequestTask {
private var lock = NSRecursiveLock()
private var task: URLSessionTask?
private var task: URLSessionDataTaskProtocol?

internal func set(task: URLSessionTask) {
internal func set(task: URLSessionDataTaskProtocol) {
lock.lock()
defer { lock.unlock() }
self.task = task
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,33 @@ import MobileCoreServices
import UniformTypeIdentifiers
#endif

// Protocol defined for a session data task. This allows mocking out the URLSessionProtocol below since
// you may not want to create or return a real URLSessionDataTask.
public protocol URLSessionDataTaskProtocol {
func resume()

var taskIdentifier: Int { get }

var progress: Progress { get }

func cancel()
}

// Protocol allowing implementations to alter what is returned or to test their implementations.
public protocol URLSessionProtocol {
func dataTask(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask
// Task which performs the network fetch. Expected to be from URLSession.dataTask(with:completionHandler:) such that a network request
// is sent off when `.resume()` is called.
func dataTaskFromProtocol(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTaskProtocol
}

extension URLSession: URLSessionProtocol {
// Passthrough to URLSession.dataTask(with:completionHandler) since URLSessionDataTask conforms to URLSessionDataTaskProtocol and fetches the network data.
public func dataTaskFromProtocol(with request: URLRequest, completionHandler: @escaping @Sendable (Data?, URLResponse?, (any Error)?) -> Void) -> any URLSessionDataTaskProtocol {
return dataTask(with: request, completionHandler: completionHandler)
}
}

extension URLSession: URLSessionProtocol {}
extension URLSessionDataTask: URLSessionDataTaskProtocol {}

class URLSessionRequestBuilderFactory: RequestBuilderFactory {
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
Expand Down Expand Up @@ -136,7 +158,7 @@ open class URLSessionRequestBuilder<T>: RequestBuilder<T> {
}
}

let dataTask = urlSession.dataTask(with: request) { data, response, error in
let dataTask = urlSession.dataTaskFromProtocol(with: request) { data, response, error in
apiResponseQueue.async {
self.processRequestResponse(urlRequest: request, data: data, response: response, error: error, completion: completion)
cleanupRequest()
Expand Down
Loading

0 comments on commit a724c75

Please sign in to comment.