为什么XMPPFramework会阻塞?

时间:2017-06-30 15:29:32

标签: swift unit-testing concurrency xctest xmppframework

我们正在尝试运行XMPPFramework的最小示例。

考虑这个简单的类:

import Foundation
import XMPPFramework

class Connection: NSObject, XMPPStreamDelegate {
    let stream: XMPPStream

    override init() {
        self.stream = XMPPStream()!
    }

    func connectToServer(timeout: TimeInterval) {
        stream.addDelegate(self, delegateQueue: DispatchQueue.main)
        stream.myJID = XMPPJID(string: "myuser")
        stream.hostName = "myserver.tld"
        stream.hostPort = 5222

        do {
            try stream.connect(withTimeout: timeout)
        }
        catch {
            print(error)
        }
    }

    func xmppStreamWillConnect(_ sender: XMPPStream!) {
        print("will connect")
    }

    func xmppStreamDidConnect(_ sender: XMPPStream!) {
        print("did connect")
        self.stream.disconnect()
    }
}

这个简单的测试类:

import Foundation
import XCTest
@testable import MyModule

class ConnectionTests: XCTestCase {
    func testConnect() {
        let connection = Connection()

        print("Try to connect")
        let expectation = self.expectation(description: "connect")
        connection.connectToServer(timeout: 3)
        self.waitForExpectations(timeout: 5)
    }
}

我期待这个输出:

Try to connect
will connect
did connect
<5s timeout since I don't fulfill>

如果不小心我的XMPP服务器没有对我的请求作出积极反应,我想看看:

Try to connect
will connect
<some error message>

如果XMPP服务器没有快速回复,我希望:

Try to connect
will connect
<3s timeout reached>

然而,我没有得到这些,而是​​:

Try to connect
will connect
<5s timeout since I don't fulfill>

发生了什么事?

这是我收集的内容。

  • XCTest等待DispatchQueue.main
  • 我们可以控制代表的运行位置;使用DispatchQueue.mainDispatchQueue(label: "test", qos: .userInitiated, attributes: .concurrent)似乎无关紧要。
  • 我可以跟踪dispatch_sync(xmppQueue, block);XMPPStream.connectWithTimeout的执行情况,其中xmppQueue是一个标签为xmpp的新队列;该块似乎也完全被执行。

所以我不明白是谁阻止了谁,以及如何防止它发生。

2 个答案:

答案 0 :(得分:0)

问题是三方面的:

  1. 期望超时,因为它永远不会实现。
  2. 我们从来没有看到“连接”,因为它从来没有那么远。
  3. 我们不了解XMPP(框架)以了解插件的位置。
  4. 我们实现了一些额外的委托方法:

    func xmppStream(_ sender: XMPPStream!, socketDidConnect socket: GCDAsyncSocket!) {
        print("socket did connect")
    }
    
    func xmppStreamDidStartNegotiation(_ sender: XMPPStream!) {
        print("negotiation started")
    }
    
    ...
    
    func xmppStream(_ sender: XMPPStream!, didReceiveError error: DDXMLElement!) {
        print("error: \(error)")
    }
    
    func xmppStreamDidDisconnect(_ sender: XMPPStream!, withError error: Error!) {
        print("disconnected")
        self.afterConnection()
    }
    

    此处,self.afterConnection是传递给connectToServer的函数作为附加参数。

    我们改变了测试:

    connection.connectToServer(timeout: 3, then: { expectation.fulfill() })
    

    现在测试以这种输出有序地终止:

    Try to connect
    will connect
    socket did connect
    negotiation started
    disconnected
    error: Optional(<stream:error xmlns:stream="http://etherx.jabber.org/streams"><host-unknown xmlns="urn:ietf:params:xml:ns:xmpp-streams"/></stream:error>)
    

    毕竟,这是服务器的问题。我们需要实施正确的代表来诊断问题;我们原本期望stream.connect在这种情况下抛出错误!

答案 1 :(得分:0)

使该类的单例如下:

 static let sharedInstance = Connection();

现在将其称为:

    func testConnect() {
            Connection.sharedInstance.connectToServer(timeout: 3);
}