Skip to content

Commit fe2c625

Browse files
authored
Fix invalidate url sessions (#446)
Close URLSession after completing a task to avoid memory leak
1 parent 9c135eb commit fe2c625

File tree

9 files changed

+21
-5
lines changed

9 files changed

+21
-5
lines changed

Sources/Customization/DefaultDatafileHandler.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ open class DefaultDatafileHandler: OPTDatafileHandler {
6969
}
7070

7171
let session = self.getSession(resourceTimeoutInterval: resourceTimeoutInterval)
72+
// without this the URLSession will leak, see docs on URLSession and https://stackoverflow.com/questions/67318867
73+
defer { session.finishTasksAndInvalidate() }
7274

7375
guard let request = self.getRequest(sdkKey: sdkKey) else { return }
7476

Sources/Customization/DefaultEventDispatcher.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ open class DefaultEventDispatcher: BackgroundingCallbacks, OPTEventDispatcher {
184184
}
185185

186186
let session = getSession()
187+
// without this the URLSession will leak, see docs on URLSession and https://stackoverflow.com/questions/67318867
188+
defer { session.finishTasksAndInvalidate() }
189+
187190
var request = URLRequest(url: event.url)
188191
request.httpMethod = "POST"
189192
request.httpBody = event.body

Tests/OptimizelyTests-APIs/OptimizelyClientTests_DatafileHandler.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class OptimizelyClientTests_DatafileHandler: XCTestCase {
2828
override func tearDown() {
2929
OTUtils.clearAllBinders()
3030
OTUtils.clearAllTestStorage(including: sdkKey)
31+
XCTAssertEqual(MockUrlSession.validSessions, 0, "all MockUrlSession must be invalidated")
3132
}
3233

3334
func testOptimizelyClientWithCachedDatafile() {

Tests/OptimizelyTests-Common/DatafileHandlerTests.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class DatafileHandlerTests: XCTestCase {
2828
override func tearDown() {
2929
OTUtils.clearAllBinders()
3030
OTUtils.clearAllTestStorage(including: sdkKey)
31+
XCTAssertEqual(MockUrlSession.validSessions, 0, "all MockUrlSession must be invalidated")
3132
}
3233

3334
func testDatafileHandler() {
@@ -331,13 +332,12 @@ class DatafileHandlerTests: XCTestCase {
331332
var localFileUrl:URL?
332333
// override getSession to return our own session.
333334
override func getSession(resourceTimeoutInterval: Double?) -> URLSession {
334-
var session = MockUrlSession(statusCode: 200)
335-
// will return 500
336335
if let _ = resourceTimeoutInterval {
337-
session = MockUrlSession(withError: true)
336+
// will return 500
337+
return MockUrlSession(withError: true)
338+
} else {
339+
return MockUrlSession(statusCode: 200)
338340
}
339-
340-
return session
341341
}
342342
}
343343

Tests/OptimizelyTests-Common/EventDispatcherTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class EventDispatcherTests: XCTestCase {
2626

2727
override func tearDown() {
2828
OTUtils.clearAllEventQueues()
29+
XCTAssertEqual(MockUrlSession.validSessions, 0, "all MockUrlSession must be invalidated")
2930
}
3031

3132
func testDefaultDispatcher() {

Tests/OptimizelyTests-Common/NetworkReachabilityTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class NetworkReachabilityTests: XCTestCase {
2626

2727
override func tearDown() {
2828
OTUtils.clearAllTestStorage(including: sdkKey)
29+
XCTAssertEqual(MockUrlSession.validSessions, 0, "all MockUrlSession must be invalidated")
2930
}
3031

3132
// Reachability (NWPathMonitor) can be tested with real devices only (no simulators), but framework logic testing is not supported on devices.

Tests/OptimizelyTests-MultiClients/DatafileHandlerTests_MultiClients.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class DatafileHandlerTests_MultiClients: XCTestCase {
3232
override func tearDown() {
3333
OTUtils.clearAllBinders()
3434
OTUtils.clearAllTestStorage()
35+
XCTAssertEqual(MockUrlSession.validSessions, 0, "all MockUrlSession must be invalidated")
3536
}
3637

3738
// MARK: - downloadDatafile

Tests/OptimizelyTests-MultiClients/MultiClientsTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class MultiClientsTests: XCTestCase {
2828

2929
override func tearDown() {
3030
OTUtils.clearAllTestStorage(including: testSdkKeyBasename)
31+
XCTAssertEqual(MockUrlSession.validSessions, 0, "all MockUrlSession must be invalidated")
3132
}
3233

3334
func testMultiClients() {

Tests/TestUtils/MockUrlSession.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import Foundation
2222
// the response also includes the url for the data download.
2323
// the cdn url is used to get the datafile if the datafile is not in cache
2424
class MockUrlSession: URLSession {
25+
static var validSessions = 0
2526
var statusCode: Int
2627
var withError: Bool
2728
var localResponseData: String?
@@ -53,13 +54,15 @@ class MockUrlSession: URLSession {
5354
}
5455

5556
init(handler: MockDatafileHandler? = nil, statusCode: Int = 0, withError: Bool = false, localResponseData: String? = nil) {
57+
Self.validSessions += 1
5658
self.handler = handler
5759
self.statusCode = statusCode
5860
self.withError = withError
5961
self.localResponseData = localResponseData
6062
}
6163

6264
init(handler: MockDatafileHandler? = nil, settingsMap: [String: (Int, Bool)]) {
65+
Self.validSessions += 1
6366
self.handler = handler
6467
self.statusCode = 0
6568
self.withError = false
@@ -109,4 +112,7 @@ class MockUrlSession: URLSession {
109112
}
110113
}
111114

115+
override func finishTasksAndInvalidate() {
116+
Self.validSessions -= 1
117+
}
112118
}

0 commit comments

Comments
 (0)