Skip to content

Commit 56d1967

Browse files
authored
Fixing a bug when stopping a disconnected connection (#283)
* fixing a bug when stopping a disconnected connection * add stop connection when disconnected unit test * check disconnected state refactoring
1 parent 0d9413f commit 56d1967

File tree

2 files changed

+47
-8
lines changed

2 files changed

+47
-8
lines changed

Sources/SignalRClient/ReconnectableConnection.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,11 @@ internal class ReconnectableConnection: Connection {
7171

7272
func stop(stopError: Error?) {
7373
logger.log(logLevel: .info, message: "Received connection stop request")
74-
_ = changeState(from: nil, to: .stopping)
75-
underlyingConnection.stop(stopError: stopError)
74+
if changeState(from: [.starting, .reconnecting, .running], to: .stopping) != nil {
75+
underlyingConnection.stop(stopError: stopError)
76+
} else {
77+
logger.log(logLevel: .warning, message: "Reconnectable connection is already in the disconnected state. Ignoring stop request")
78+
}
7679
}
7780

7881
private func startInternal() {

Tests/SignalRClientTests/ReconnectableConnectionTests.swift

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,29 +235,65 @@ class ReconnectableConnectionTests: XCTestCase {
235235

236236
waitForExpectations(timeout: 2 /*seconds*/)
237237
}
238-
239-
238+
239+
public func testReconnectableConnectionIgnoreStopRequestWhenDisconnected() {
240+
241+
var isConnectionOpen = false
242+
243+
let testConnection = TestConnection()
244+
let delegate = TestConnectionDelegate()
245+
let reconnectableConnection = ReconnectableConnection(connectionFactory: {return testConnection}, reconnectPolicy: NoReconnectPolicy(), callbackQueue: callbackQueue, logger: PrintLogger())
246+
reconnectableConnection.delegate = delegate
247+
248+
delegate.connectionDidOpenHandler = { connection in
249+
isConnectionOpen = true
250+
}
251+
252+
delegate.connectionDidCloseHandler = { connection in
253+
isConnectionOpen = false
254+
}
255+
256+
reconnectableConnection.start()
257+
XCTAssertTrue(isConnectionOpen)
258+
259+
reconnectableConnection.stop(stopError: nil)
260+
XCTAssertTrue(!isConnectionOpen)
261+
262+
// stop the connection while it is disconnected
263+
reconnectableConnection.stop(stopError: nil)
264+
XCTAssertTrue(!isConnectionOpen)
265+
266+
reconnectableConnection.start()
267+
XCTAssertTrue(isConnectionOpen)
268+
}
269+
240270
class TestConnection: Connection {
241271
var delegate: ConnectionDelegate?
242272
var openError: Error?
243-
273+
244274
var connectionId: String?
245275
var inherentKeepAlive = false
246-
276+
var isClosed: Bool = false
277+
247278
func start() {
248279
if let e = openError {
249280
delegate?.connectionDidFailToOpen(error: e)
250281
} else {
251282
delegate?.connectionDidOpen(connection: self)
283+
self.isClosed = false
252284
}
253285
}
254-
286+
255287
func send(data: Data, sendDidComplete: (Error?) -> Void) {
256288
sendDidComplete(nil)
257289
}
258-
290+
259291
func stop(stopError: Error?) {
292+
// Recreating the logic as in HTTPConnection. (the delegate method would only be called when the connection state changes to stopped. Therefore the state transition of ReconnectableConnection to disconnected will not be executed
293+
guard !self.isClosed else { return }
294+
self.isClosed = true
260295
delegate?.connectionDidClose(error: stopError)
261296
}
297+
262298
}
263299
}

0 commit comments

Comments
 (0)