From 164be73816eab7725027ac10741a40004ad80107 Mon Sep 17 00:00:00 2001 From: Pushkar Kulkarni Date: Tue, 18 Oct 2016 15:24:13 +0530 Subject: [PATCH] Implementation of URLSessionTask.cancel() --- .../NSURLSession/NSURLSessionTask.swift | 16 ++++++-- TestFoundation/TestNSURLSession.swift | 39 ++++++++++++++++--- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/Foundation/NSURLSession/NSURLSessionTask.swift b/Foundation/NSURLSession/NSURLSessionTask.swift index 6f33cc638b..5856d5d464 100644 --- a/Foundation/NSURLSession/NSURLSessionTask.swift +++ b/Foundation/NSURLSession/NSURLSessionTask.swift @@ -194,8 +194,18 @@ open class URLSessionTask : NSObject, NSCopying { * cases, the task may signal other work before it acknowledges the * cancelation. -cancel may be sent to a task that has been suspended. */ - open func cancel() { NSUnimplemented() } - + open func cancel() { + workQueue.sync { + guard self.state == .running || self.state == .suspended else { return } + self.state = .canceling + self.workQueue.async { + self.internalState = .transferFailed + let urlError = URLError(_nsError: NSError(domain: NSURLErrorDomain, code: NSURLErrorCancelled, userInfo: nil)) + self.completeTask(withError: urlError) + } + } + } + /* * The current state of the task within the session. */ @@ -866,7 +876,7 @@ extension URLSessionTask { } func completeTask(withError error: Error) { self.error = error - + guard case .transferFailed = internalState else { fatalError("Trying to complete the task, but its transfer isn't complete / failed.") } diff --git a/TestFoundation/TestNSURLSession.swift b/TestFoundation/TestNSURLSession.swift index d86e749515..cce15087a5 100644 --- a/TestFoundation/TestNSURLSession.swift +++ b/TestFoundation/TestNSURLSession.swift @@ -32,6 +32,7 @@ class TestURLSession : XCTestCase { ("test_finishTaskAndInvalidate", test_finishTasksAndInvalidate), ("test_taskError", test_taskError), ("test_taskCopy", test_taskCopy), + ("test_cancelTask", test_cancelTask), ] } @@ -297,6 +298,26 @@ class TestURLSession : XCTestCase { XCTAssert(task.isEqual(task.copy())) } + + func test_cancelTask() { + let serverReady = ServerSemaphore() + globalDispatchQueue.async { + do { + try self.runServer(with: serverReady) + } catch { + XCTAssertTrue(true) + return + } + } + serverReady.wait() + let url = URL(string: "http://127.0.0.1:\(serverPort)/Peru")! + let d = DataTask(with: expectation(description: "Task to be canceled")) + d.cancelExpectation = expectation(description: "URLSessionTask wasn't canceled") + d.run(with: url) + d.cancel() + waitForExpectations(timeout: 12) + } + } class SessionDelegate: NSObject, URLSessionDelegate { @@ -314,6 +335,8 @@ class DataTask : NSObject { var capital = "unknown" var session: URLSession! = nil var task: URLSessionDataTask! = nil + var cancelExpectation: XCTestExpectation? + public var error = false init(with expectation: XCTestExpectation) { @@ -335,20 +358,26 @@ class DataTask : NSObject { task = session.dataTask(with: url) task.resume() } + + func cancel() { + task.cancel() + } } extension DataTask : URLSessionDataDelegate { - public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { - capital = String(data: data, encoding: String.Encoding.utf8)! - dataTaskExpectation.fulfill() - } + public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { + capital = String(data: data, encoding: String.Encoding.utf8)! + dataTaskExpectation.fulfill() + } } extension DataTask : URLSessionTaskDelegate { public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { guard let e = error as? URLError else { return } - XCTAssertEqual(e.code, .timedOut, "Unexpected error code") dataTaskExpectation.fulfill() + if let cancellation = cancelExpectation { + cancellation.fulfill() + } self.error = true } }