From 80de53fd9aacc1a3c2c5468a811fc74275984dfa Mon Sep 17 00:00:00 2001 From: Nate Armstrong Date: Thu, 31 Mar 2016 14:55:01 -0600 Subject: [PATCH 1/4] Notify delegate when task finishes --- DVR/Session.swift | 5 +++++ DVR/Tests/SessionTests.swift | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/DVR/Session.swift b/DVR/Session.swift index 4d95076..fe42088 100644 --- a/DVR/Session.swift +++ b/DVR/Session.swift @@ -17,6 +17,9 @@ public class Session: NSURLSession { private var completedInteractions = [Interaction]() private var completionBlock: (Void -> Void)? + override public var delegate: NSURLSessionDelegate? { + return backingSession.delegate + } // MARK: - Initializers @@ -110,6 +113,8 @@ public class Session: NSURLSession { if !recording && outstandingTasks.count == 0 { finishRecording() } + + (delegate as? NSURLSessionTaskDelegate)?.URLSession?(self, task: task, didCompleteWithError: nil) } diff --git a/DVR/Tests/SessionTests.swift b/DVR/Tests/SessionTests.swift index add2d8b..9b62b8b 100644 --- a/DVR/Tests/SessionTests.swift +++ b/DVR/Tests/SessionTests.swift @@ -133,4 +133,30 @@ class SessionTests: XCTestCase { waitForExpectationsWithTimeout(1, handler: nil) } + + func testDelegate() { + class Delegate: NSObject, NSURLSessionTaskDelegate { + let expectation: XCTestExpectation + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + @objc private func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) { + expectation.fulfill() + } + } + + let expectation = expectationWithDescription("didCompleteWithError") + let delegate = Delegate(expectation: expectation) + let config = NSURLSessionConfiguration.defaultSessionConfiguration() + let backingSession = NSURLSession(configuration: config, delegate: delegate, delegateQueue: nil) + let session = Session(cassetteName: "example", backingSession: backingSession) + session.recordingEnabled = false + + let task = session.dataTaskWithRequest(request) + task.resume() + + waitForExpectationsWithTimeout(1, handler: nil) + } } From 166010ef8daef96ce4d1cb014e6c40d799357124 Mon Sep 17 00:00:00 2001 From: Nate Armstrong Date: Thu, 31 Mar 2016 16:42:57 -0600 Subject: [PATCH 2/4] Use interaction for SessionDataTask response When using a delegate it is common to get the response from the NSURLSessionTask in `URLSession:task:didCompleteWithError:`. However, the response is never set on a SessionDataTask object so we must override it with the interaction response. Unfortunately this means we have to make the `interaction` a property of SessionDataTask which adds state but the `response` is unavailable otherwise. --- DVR/Session.swift | 4 +++- DVR/SessionDataTask.swift | 6 ++++++ DVR/Tests/SessionTests.swift | 4 +++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/DVR/Session.swift b/DVR/Session.swift index fe42088..dcf5ef8 100644 --- a/DVR/Session.swift +++ b/DVR/Session.swift @@ -114,7 +114,9 @@ public class Session: NSURLSession { finishRecording() } - (delegate as? NSURLSessionTaskDelegate)?.URLSession?(self, task: task, didCompleteWithError: nil) + if let delegate = delegate as? NSURLSessionTaskDelegate { + delegate.URLSession?(self, task: task, didCompleteWithError: nil) + } } diff --git a/DVR/SessionDataTask.swift b/DVR/SessionDataTask.swift index 679d9ea..2bf1ca2 100644 --- a/DVR/SessionDataTask.swift +++ b/DVR/SessionDataTask.swift @@ -13,6 +13,11 @@ class SessionDataTask: NSURLSessionDataTask { let request: NSURLRequest let completion: Completion? private let queue = dispatch_queue_create("com.venmo.DVR.sessionDataTaskQueue", nil) + private var interaction: Interaction? + + override var response: NSURLResponse? { + return interaction?.response + } // MARK: - Initializers @@ -35,6 +40,7 @@ class SessionDataTask: NSURLSessionDataTask { // Find interaction if let interaction = session.cassette?.interactionForRequest(request) { + self.interaction = interaction // Forward completion if let completion = completion { dispatch_async(queue) { diff --git a/DVR/Tests/SessionTests.swift b/DVR/Tests/SessionTests.swift index 9b62b8b..b6b9a96 100644 --- a/DVR/Tests/SessionTests.swift +++ b/DVR/Tests/SessionTests.swift @@ -134,15 +134,17 @@ class SessionTests: XCTestCase { waitForExpectationsWithTimeout(1, handler: nil) } - func testDelegate() { + func testTaskDelegate() { class Delegate: NSObject, NSURLSessionTaskDelegate { let expectation: XCTestExpectation + var response: NSURLResponse? init(expectation: XCTestExpectation) { self.expectation = expectation } @objc private func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) { + response = task.response expectation.fulfill() } } From f84aa7f7676d9bfc9291da213f8eae48b1dafa74 Mon Sep 17 00:00:00 2001 From: Nate Armstrong Date: Thu, 31 Mar 2016 16:58:45 -0600 Subject: [PATCH 3/4] Notify data delegate when task finishes --- DVR/Session.swift | 4 ++++ DVR/Tests/SessionTests.swift | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/DVR/Session.swift b/DVR/Session.swift index dcf5ef8..3ccba99 100644 --- a/DVR/Session.swift +++ b/DVR/Session.swift @@ -114,6 +114,10 @@ public class Session: NSURLSession { finishRecording() } + if let delegate = delegate as? NSURLSessionDataDelegate, task = task as? NSURLSessionDataTask, data = interaction.responseData { + delegate.URLSession?(self, dataTask: task, didReceiveData: data) + } + if let delegate = delegate as? NSURLSessionTaskDelegate { delegate.URLSession?(self, task: task, didCompleteWithError: nil) } diff --git a/DVR/Tests/SessionTests.swift b/DVR/Tests/SessionTests.swift index b6b9a96..3ff4e05 100644 --- a/DVR/Tests/SessionTests.swift +++ b/DVR/Tests/SessionTests.swift @@ -161,4 +161,30 @@ class SessionTests: XCTestCase { waitForExpectationsWithTimeout(1, handler: nil) } + + func testDataDelegate() { + class Delegate: NSObject, NSURLSessionDataDelegate { + let expectation: XCTestExpectation + + init(expectation: XCTestExpectation) { + self.expectation = expectation + } + + @objc func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) { + expectation.fulfill() + } + } + + let expectation = expectationWithDescription("didCompleteWithError") + let delegate = Delegate(expectation: expectation) + let config = NSURLSessionConfiguration.defaultSessionConfiguration() + let backingSession = NSURLSession(configuration: config, delegate: delegate, delegateQueue: nil) + let session = Session(cassetteName: "example", backingSession: backingSession) + session.recordingEnabled = false + + let task = session.dataTaskWithRequest(request) + task.resume() + + waitForExpectationsWithTimeout(1, handler: nil) + } } From 411583eae678ab41c3078724300cb40484f0182d Mon Sep 17 00:00:00 2001 From: Nate Armstrong Date: Sun, 3 Apr 2016 19:19:13 -0600 Subject: [PATCH 4/4] Fix task response when recording and using delegate --- DVR/SessionDataTask.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DVR/SessionDataTask.swift b/DVR/SessionDataTask.swift index 2bf1ca2..9e0c32c 100644 --- a/DVR/SessionDataTask.swift +++ b/DVR/SessionDataTask.swift @@ -81,8 +81,8 @@ class SessionDataTask: NSURLSessionDataTask { } // Create interaction - let interaction = Interaction(request: this.request, response: response, responseData: data) - this.session.finishTask(this, interaction: interaction, playback: false) + this.interaction = Interaction(request: this.request, response: response, responseData: data) + this.session.finishTask(this, interaction: this.interaction!, playback: false) } task.resume() }