1ea6baaa364e773de48400115fd4ee364119c02c
[contrib/qtwebsockets.git] / tests / auto / qwebsocketserver / tst_qwebsocketserver.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Kurt Pattyn <pattyn.kurt@gmail.com>.
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <QString>
42 #include <QtTest>
43 #include <QNetworkProxy>
44 #include <QtWebSockets/QWebSocketServer>
45 #include <QtWebSockets/QWebSocket>
46 #include <QtWebSockets/QWebSocketCorsAuthenticator>
47 #include <QtWebSockets/qwebsocketprotocol.h>
48
49 QT_USE_NAMESPACE
50
51 Q_DECLARE_METATYPE(QWebSocketProtocol::Version)
52 Q_DECLARE_METATYPE(QWebSocketProtocol::CloseCode)
53 Q_DECLARE_METATYPE(QWebSocketServer::SslMode)
54 Q_DECLARE_METATYPE(QWebSocketCorsAuthenticator *)
55 Q_DECLARE_METATYPE(QSslError)
56
57 class tst_QWebSocketServer : public QObject
58 {
59     Q_OBJECT
60
61 public:
62     tst_QWebSocketServer();
63
64 private Q_SLOTS:
65     void init();
66     void initTestCase();
67     void cleanupTestCase();
68     void tst_initialisation();
69     void tst_settersAndGetters();
70     void tst_listening();
71     void tst_connectivity();
72     void tst_maxPendingConnections();
73 };
74
75 tst_QWebSocketServer::tst_QWebSocketServer()
76 {
77 }
78
79 void tst_QWebSocketServer::init()
80 {
81     qRegisterMetaType<QWebSocketProtocol::Version>("QWebSocketProtocol::Version");
82     qRegisterMetaType<QWebSocketProtocol::CloseCode>("QWebSocketProtocol::CloseCode");
83     qRegisterMetaType<QWebSocketServer::SslMode>("QWebSocketServer::SslMode");
84     qRegisterMetaType<QWebSocketCorsAuthenticator *>("QWebSocketCorsAuthenticator *");
85     qRegisterMetaType<QSslError>("QSslError");
86 }
87
88 void tst_QWebSocketServer::initTestCase()
89 {
90 }
91
92 void tst_QWebSocketServer::cleanupTestCase()
93 {
94 }
95
96 void tst_QWebSocketServer::tst_initialisation()
97 {
98     {
99         QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode);
100
101         QVERIFY(server.serverName().isEmpty());
102         QCOMPARE(server.secureMode(), QWebSocketServer::NonSecureMode);
103         QVERIFY(!server.isListening());
104         QCOMPARE(server.maxPendingConnections(), 30);
105         QCOMPARE(server.serverPort(), quint16(0));
106         QCOMPARE(server.serverAddress(), QHostAddress());
107         QCOMPARE(server.socketDescriptor(), -1);
108         QVERIFY(!server.hasPendingConnections());
109         QVERIFY(!server.nextPendingConnection());
110         QCOMPARE(server.error(), QWebSocketProtocol::CloseCodeNormal);
111         QVERIFY(server.errorString().isEmpty());
112     #ifndef QT_NO_NETWORKPROXY
113         QCOMPARE(server.proxy().type(), QNetworkProxy::DefaultProxy);
114     #endif
115     #ifndef QT_NO_SSL
116         QCOMPARE(server.sslConfiguration(), QSslConfiguration::defaultConfiguration());
117     #endif
118         QCOMPARE(server.supportedVersions().count(), 1);
119         QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::VersionLatest);
120         QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::Version13);
121
122         server.close();
123         //closing a server should not affect any of the parameters
124         //certainly if the server was not opened before
125
126         QVERIFY(server.serverName().isEmpty());
127         QCOMPARE(server.secureMode(), QWebSocketServer::NonSecureMode);
128         QVERIFY(!server.isListening());
129         QCOMPARE(server.maxPendingConnections(), 30);
130         QCOMPARE(server.serverPort(), quint16(0));
131         QCOMPARE(server.serverAddress(), QHostAddress());
132         QCOMPARE(server.socketDescriptor(), -1);
133         QVERIFY(!server.hasPendingConnections());
134         QVERIFY(!server.nextPendingConnection());
135         QCOMPARE(server.error(), QWebSocketProtocol::CloseCodeNormal);
136         QVERIFY(server.errorString().isEmpty());
137     #ifndef QT_NO_NETWORKPROXY
138         QCOMPARE(server.proxy().type(), QNetworkProxy::DefaultProxy);
139     #endif
140     #ifndef QT_NO_SSL
141         QCOMPARE(server.sslConfiguration(), QSslConfiguration::defaultConfiguration());
142     #endif
143         QCOMPARE(server.supportedVersions().count(), 1);
144         QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::VersionLatest);
145         QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::Version13);
146     }
147
148     {
149         QWebSocketServer sslServer(QString(), QWebSocketServer::SecureMode);
150 #ifndef QT_NO_SSL
151         QCOMPARE(sslServer.secureMode(), QWebSocketServer::SecureMode);
152 #else
153         QCOMPARE(sslServer.secureMode(), QWebSocketServer::NonSecureMode);
154 #endif
155     }
156 }
157
158 void tst_QWebSocketServer::tst_settersAndGetters()
159 {
160     QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode);
161
162     server.setMaxPendingConnections(23);
163     QCOMPARE(server.maxPendingConnections(), 23);
164     server.setMaxPendingConnections(INT_MIN);
165     QCOMPARE(server.maxPendingConnections(), INT_MIN);
166     server.setMaxPendingConnections(INT_MAX);
167     QCOMPARE(server.maxPendingConnections(), INT_MAX);
168
169     QVERIFY(!server.setSocketDescriptor(-2));
170     QCOMPARE(server.socketDescriptor(), -1);
171
172     server.setServerName(QStringLiteral("Qt WebSocketServer"));
173     QCOMPARE(server.serverName(), QStringLiteral("Qt WebSocketServer"));
174
175 #ifndef QT_NO_NETWORKPROXY
176     QNetworkProxy proxy(QNetworkProxy::Socks5Proxy);
177     server.setProxy(proxy);
178     QCOMPARE(server.proxy(), proxy);
179 #endif
180 #ifndef QT_NO_SSL
181     //cannot set an ssl configuration on a non secure server
182     QSslConfiguration sslConfiguration = QSslConfiguration::defaultConfiguration();
183     sslConfiguration.setPeerVerifyDepth(sslConfiguration.peerVerifyDepth() + 1);
184     server.setSslConfiguration(sslConfiguration);
185     QVERIFY(server.sslConfiguration() != sslConfiguration);
186     QCOMPARE(server.sslConfiguration(), QSslConfiguration::defaultConfiguration());
187
188     QWebSocketServer sslServer(QString(), QWebSocketServer::SecureMode);
189     sslServer.setSslConfiguration(sslConfiguration);
190     QCOMPARE(sslServer.sslConfiguration(), sslConfiguration);
191     QVERIFY(sslServer.sslConfiguration() != QSslConfiguration::defaultConfiguration());
192 #endif
193 }
194
195 void tst_QWebSocketServer::tst_listening()
196 {
197     //These listening tests are not too extensive, as the implementation of QWebSocketServer
198     //relies on QTcpServer
199
200     QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode);
201
202     QSignalSpy serverAcceptErrorSpy(&server, SIGNAL(acceptError(QAbstractSocket::SocketError)));
203     QSignalSpy serverConnectionSpy(&server, SIGNAL(newConnection()));
204     QSignalSpy serverErrorSpy(&server,
205                               SIGNAL(serverError(QWebSocketProtocol::CloseCode)));
206     QSignalSpy corsAuthenticationSpy(&server,
207                               SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*)));
208     QSignalSpy serverClosedSpy(&server, SIGNAL(closed()));
209 #ifndef QT_NO_SSL
210     QSignalSpy peerVerifyErrorSpy(&server, SIGNAL(peerVerifyError(QSslError)));
211     QSignalSpy sslErrorsSpy(&server, SIGNAL(sslErrors(QList<QSslError>)));
212 #endif
213
214     QVERIFY(server.listen());   //listen on all network interface, choose an appropriate port
215     QVERIFY(server.isListening());
216     QCOMPARE(serverClosedSpy.count(), 0);
217     server.close();
218     QVERIFY(serverClosedSpy.wait(1000));
219     QVERIFY(!server.isListening());
220     QCOMPARE(serverErrorSpy.count(), 0);
221
222     QVERIFY(!server.listen(QHostAddress(QStringLiteral("1.2.3.4")), 0));
223     QCOMPARE(server.error(), QWebSocketProtocol::CloseCodeAbnormalDisconnection);
224     QCOMPARE(server.errorString().toLatin1().constData(), "The address is not available");
225     QVERIFY(!server.isListening());
226
227     QCOMPARE(serverAcceptErrorSpy.count(), 0);
228     QCOMPARE(serverConnectionSpy.count(), 0);
229     QCOMPARE(corsAuthenticationSpy.count(), 0);
230 #ifndef QT_NO_SSL
231     QCOMPARE(peerVerifyErrorSpy.count(), 0);
232     QCOMPARE(sslErrorsSpy.count(), 0);
233 #endif
234     QCOMPARE(serverErrorSpy.count(), 1);
235     QCOMPARE(serverClosedSpy.count(), 1);
236 }
237
238 void tst_QWebSocketServer::tst_connectivity()
239 {
240     QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode);
241     QSignalSpy serverConnectionSpy(&server, SIGNAL(newConnection()));
242     QSignalSpy serverErrorSpy(&server,
243                               SIGNAL(serverError(QWebSocketProtocol::CloseCode)));
244     QSignalSpy corsAuthenticationSpy(&server,
245                               SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*)));
246     QSignalSpy serverClosedSpy(&server, SIGNAL(closed()));
247 #ifndef QT_NO_SSL
248     QSignalSpy peerVerifyErrorSpy(&server, SIGNAL(peerVerifyError(QSslError)));
249     QSignalSpy sslErrorsSpy(&server, SIGNAL(sslErrors(QList<QSslError>)));
250 #endif
251     QWebSocket socket;
252     QSignalSpy socketConnectedSpy(&socket, SIGNAL(connected()));
253
254     QVERIFY(server.listen());
255
256     socket.open(QStringLiteral("ws://") + QHostAddress(QHostAddress::LocalHost).toString() +
257                 QStringLiteral(":").append(QString::number(server.serverPort())));
258
259     if (socketConnectedSpy.count() == 0)
260         QVERIFY(socketConnectedSpy.wait());
261     QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
262     QCOMPARE(serverConnectionSpy.count(), 1);
263     QCOMPARE(corsAuthenticationSpy.count(), 1);
264
265     QCOMPARE(serverClosedSpy.count(), 0);
266
267     server.close();
268
269     QVERIFY(serverClosedSpy.wait());
270     QCOMPARE(serverClosedSpy.count(), 1);
271 #ifndef QT_NO_SSL
272     QCOMPARE(peerVerifyErrorSpy.count(), 0);
273     QCOMPARE(sslErrorsSpy.count(), 0);
274 #endif
275     QCOMPARE(serverErrorSpy.count(), 0);
276 }
277
278 void tst_QWebSocketServer::tst_maxPendingConnections()
279 {
280     //tests if maximum connections are respected
281     //also checks if there are no side-effects like signals that are unexpectedly thrown
282     QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode);
283     server.setMaxPendingConnections(2);
284     QSignalSpy serverConnectionSpy(&server, SIGNAL(newConnection()));
285     QSignalSpy serverErrorSpy(&server,
286                               SIGNAL(serverError(QWebSocketProtocol::CloseCode)));
287     QSignalSpy corsAuthenticationSpy(&server,
288                               SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*)));
289     QSignalSpy serverClosedSpy(&server, SIGNAL(closed()));
290 #ifndef QT_NO_SSL
291     QSignalSpy peerVerifyErrorSpy(&server, SIGNAL(peerVerifyError(QSslError)));
292     QSignalSpy sslErrorsSpy(&server, SIGNAL(sslErrors(QList<QSslError>)));
293 #endif
294     QSignalSpy serverAcceptErrorSpy(&server, SIGNAL(acceptError(QAbstractSocket::SocketError)));
295
296     QWebSocket socket1;
297     QWebSocket socket2;
298     QWebSocket socket3;
299
300     QSignalSpy socket1ConnectedSpy(&socket1, SIGNAL(connected()));
301     QSignalSpy socket2ConnectedSpy(&socket2, SIGNAL(connected()));
302     QSignalSpy socket3ConnectedSpy(&socket3, SIGNAL(connected()));
303
304     QVERIFY(server.listen());
305
306     socket1.open(QStringLiteral("ws://") + QHostAddress(QHostAddress::LocalHost).toString() +
307                  QStringLiteral(":").append(QString::number(server.serverPort())));
308
309     if (socket1ConnectedSpy.count() == 0)
310         QVERIFY(socket1ConnectedSpy.wait());
311     QCOMPARE(socket1.state(), QAbstractSocket::ConnectedState);
312     QCOMPARE(serverConnectionSpy.count(), 1);
313     QCOMPARE(corsAuthenticationSpy.count(), 1);
314     socket2.open(QStringLiteral("ws://") + QHostAddress(QHostAddress::LocalHost).toString() +
315                  QStringLiteral(":").append(QString::number(server.serverPort())));
316     if (socket2ConnectedSpy.count() == 0)
317         QVERIFY(socket2ConnectedSpy.wait());
318     QCOMPARE(socket2.state(), QAbstractSocket::ConnectedState);
319     QCOMPARE(serverConnectionSpy.count(), 2);
320     QCOMPARE(corsAuthenticationSpy.count(), 2);
321     socket3.open(QStringLiteral("ws://") + server.serverAddress().toString() +
322                  QStringLiteral(":").append(QString::number(server.serverPort())));
323     QVERIFY(!socket3ConnectedSpy.wait(250));
324     QCOMPARE(socket3.state(), QAbstractSocket::UnconnectedState);
325     QCOMPARE(serverConnectionSpy.count(), 2);
326     QCOMPARE(corsAuthenticationSpy.count(), 2);
327
328     QVERIFY(server.hasPendingConnections());
329     QWebSocket *pSocket = server.nextPendingConnection();
330     QVERIFY(pSocket);
331     delete pSocket;
332     QVERIFY(server.hasPendingConnections());
333     pSocket = server.nextPendingConnection();
334     QVERIFY(pSocket);
335     delete pSocket;
336     QVERIFY(!server.hasPendingConnections());
337     QVERIFY(!server.nextPendingConnection());
338
339     QCOMPARE(serverErrorSpy.count(), 1);
340     QCOMPARE(serverErrorSpy.at(0).at(0).value<QWebSocketProtocol::CloseCode>(),
341              QWebSocketProtocol::CloseCodeAbnormalDisconnection);
342
343     QCOMPARE(serverClosedSpy.count(), 0);
344
345     server.close();
346
347     QVERIFY(serverClosedSpy.wait());
348     QCOMPARE(serverClosedSpy.count(), 1);
349 #ifndef QT_NO_SSL
350     QCOMPARE(peerVerifyErrorSpy.count(), 0);
351     QCOMPARE(sslErrorsSpy.count(), 0);
352 #endif
353     QCOMPARE(serverAcceptErrorSpy.count(), 0);
354 }
355
356
357 QTEST_MAIN(tst_QWebSocketServer)
358
359 #include "tst_qwebsocketserver.moc"