78e70415b39db06973c14493b2f61f1143e4b33c
[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 #ifndef QT_NO_SSL
56 Q_DECLARE_METATYPE(QSslError)
57 #endif
58
59 class tst_QWebSocketServer : public QObject
60 {
61     Q_OBJECT
62
63 public:
64     tst_QWebSocketServer();
65
66 private Q_SLOTS:
67     void init();
68     void initTestCase();
69     void cleanupTestCase();
70     void tst_initialisation();
71     void tst_settersAndGetters();
72     void tst_listening();
73     void tst_connectivity();
74     void tst_maxPendingConnections();
75 };
76
77 tst_QWebSocketServer::tst_QWebSocketServer()
78 {
79 }
80
81 void tst_QWebSocketServer::init()
82 {
83     qRegisterMetaType<QWebSocketProtocol::Version>("QWebSocketProtocol::Version");
84     qRegisterMetaType<QWebSocketProtocol::CloseCode>("QWebSocketProtocol::CloseCode");
85     qRegisterMetaType<QWebSocketServer::SslMode>("QWebSocketServer::SslMode");
86     qRegisterMetaType<QWebSocketCorsAuthenticator *>("QWebSocketCorsAuthenticator *");
87 #ifndef QT_NO_SSL
88     qRegisterMetaType<QSslError>("QSslError");
89 #endif
90 }
91
92 void tst_QWebSocketServer::initTestCase()
93 {
94 }
95
96 void tst_QWebSocketServer::cleanupTestCase()
97 {
98 }
99
100 void tst_QWebSocketServer::tst_initialisation()
101 {
102     {
103         QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode);
104
105         QVERIFY(server.serverName().isEmpty());
106         QCOMPARE(server.secureMode(), QWebSocketServer::NonSecureMode);
107         QVERIFY(!server.isListening());
108         QCOMPARE(server.maxPendingConnections(), 30);
109         QCOMPARE(server.serverPort(), quint16(0));
110         QCOMPARE(server.serverAddress(), QHostAddress());
111         QCOMPARE(server.socketDescriptor(), -1);
112         QVERIFY(!server.hasPendingConnections());
113         QVERIFY(!server.nextPendingConnection());
114         QCOMPARE(server.error(), QWebSocketProtocol::CloseCodeNormal);
115         QVERIFY(server.errorString().isEmpty());
116     #ifndef QT_NO_NETWORKPROXY
117         QCOMPARE(server.proxy().type(), QNetworkProxy::DefaultProxy);
118     #endif
119     #ifndef QT_NO_SSL
120         QCOMPARE(server.sslConfiguration(), QSslConfiguration::defaultConfiguration());
121     #endif
122         QCOMPARE(server.supportedVersions().count(), 1);
123         QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::VersionLatest);
124         QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::Version13);
125
126         server.close();
127         //closing a server should not affect any of the parameters
128         //certainly if the server was not opened before
129
130         QVERIFY(server.serverName().isEmpty());
131         QCOMPARE(server.secureMode(), QWebSocketServer::NonSecureMode);
132         QVERIFY(!server.isListening());
133         QCOMPARE(server.maxPendingConnections(), 30);
134         QCOMPARE(server.serverPort(), quint16(0));
135         QCOMPARE(server.serverAddress(), QHostAddress());
136         QCOMPARE(server.socketDescriptor(), -1);
137         QVERIFY(!server.hasPendingConnections());
138         QVERIFY(!server.nextPendingConnection());
139         QCOMPARE(server.error(), QWebSocketProtocol::CloseCodeNormal);
140         QVERIFY(server.errorString().isEmpty());
141     #ifndef QT_NO_NETWORKPROXY
142         QCOMPARE(server.proxy().type(), QNetworkProxy::DefaultProxy);
143     #endif
144     #ifndef QT_NO_SSL
145         QCOMPARE(server.sslConfiguration(), QSslConfiguration::defaultConfiguration());
146     #endif
147         QCOMPARE(server.supportedVersions().count(), 1);
148         QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::VersionLatest);
149         QCOMPARE(server.supportedVersions().at(0), QWebSocketProtocol::Version13);
150         QCOMPARE(server.serverUrl(), QUrl());
151     }
152
153     {
154 #ifndef QT_NO_SSL
155         QWebSocketServer sslServer(QString(), QWebSocketServer::SecureMode);
156         QCOMPARE(sslServer.secureMode(), QWebSocketServer::SecureMode);
157 #endif
158     }
159 }
160
161 void tst_QWebSocketServer::tst_settersAndGetters()
162 {
163     QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode);
164
165     server.setMaxPendingConnections(23);
166     QCOMPARE(server.maxPendingConnections(), 23);
167     server.setMaxPendingConnections(INT_MIN);
168     QCOMPARE(server.maxPendingConnections(), INT_MIN);
169     server.setMaxPendingConnections(INT_MAX);
170     QCOMPARE(server.maxPendingConnections(), INT_MAX);
171
172     QVERIFY(!server.setSocketDescriptor(-2));
173     QCOMPARE(server.socketDescriptor(), -1);
174
175     server.setServerName(QStringLiteral("Qt WebSocketServer"));
176     QCOMPARE(server.serverName(), QStringLiteral("Qt WebSocketServer"));
177
178 #ifndef QT_NO_NETWORKPROXY
179     QNetworkProxy proxy(QNetworkProxy::Socks5Proxy);
180     server.setProxy(proxy);
181     QCOMPARE(server.proxy(), proxy);
182 #endif
183 #ifndef QT_NO_SSL
184     //cannot set an ssl configuration on a non secure server
185     QSslConfiguration sslConfiguration = QSslConfiguration::defaultConfiguration();
186     sslConfiguration.setPeerVerifyDepth(sslConfiguration.peerVerifyDepth() + 1);
187     server.setSslConfiguration(sslConfiguration);
188     QVERIFY(server.sslConfiguration() != sslConfiguration);
189     QCOMPARE(server.sslConfiguration(), QSslConfiguration::defaultConfiguration());
190
191     QWebSocketServer sslServer(QString(), QWebSocketServer::SecureMode);
192     sslServer.setSslConfiguration(sslConfiguration);
193     QCOMPARE(sslServer.sslConfiguration(), sslConfiguration);
194     QVERIFY(sslServer.sslConfiguration() != QSslConfiguration::defaultConfiguration());
195 #endif
196 }
197
198 void tst_QWebSocketServer::tst_listening()
199 {
200     //These listening tests are not too extensive, as the implementation of QWebSocketServer
201     //relies on QTcpServer
202
203     QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode);
204
205     QSignalSpy serverAcceptErrorSpy(&server, SIGNAL(acceptError(QAbstractSocket::SocketError)));
206     QSignalSpy serverConnectionSpy(&server, SIGNAL(newConnection()));
207     QSignalSpy serverErrorSpy(&server,
208                               SIGNAL(serverError(QWebSocketProtocol::CloseCode)));
209     QSignalSpy corsAuthenticationSpy(&server,
210                               SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*)));
211     QSignalSpy serverClosedSpy(&server, SIGNAL(closed()));
212 #ifndef QT_NO_SSL
213     QSignalSpy peerVerifyErrorSpy(&server, SIGNAL(peerVerifyError(QSslError)));
214     QSignalSpy sslErrorsSpy(&server, SIGNAL(sslErrors(QList<QSslError>)));
215 #endif
216
217     QVERIFY(server.listen());   //listen on all network interface, choose an appropriate port
218     QVERIFY(server.isListening());
219     QCOMPARE(serverClosedSpy.count(), 0);
220     server.close();
221     QVERIFY(serverClosedSpy.wait(1000));
222     QVERIFY(!server.isListening());
223     QCOMPARE(serverErrorSpy.count(), 0);
224
225     QVERIFY(!server.listen(QHostAddress(QStringLiteral("1.2.3.4")), 0));
226     QCOMPARE(server.error(), QWebSocketProtocol::CloseCodeAbnormalDisconnection);
227     QCOMPARE(server.errorString().toLatin1().constData(), "The address is not available");
228     QVERIFY(!server.isListening());
229
230     QCOMPARE(serverAcceptErrorSpy.count(), 0);
231     QCOMPARE(serverConnectionSpy.count(), 0);
232     QCOMPARE(corsAuthenticationSpy.count(), 0);
233 #ifndef QT_NO_SSL
234     QCOMPARE(peerVerifyErrorSpy.count(), 0);
235     QCOMPARE(sslErrorsSpy.count(), 0);
236 #endif
237     QCOMPARE(serverErrorSpy.count(), 1);
238     QCOMPARE(serverClosedSpy.count(), 1);
239 }
240
241 void tst_QWebSocketServer::tst_connectivity()
242 {
243     QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode);
244     QSignalSpy serverConnectionSpy(&server, SIGNAL(newConnection()));
245     QSignalSpy serverErrorSpy(&server,
246                               SIGNAL(serverError(QWebSocketProtocol::CloseCode)));
247     QSignalSpy corsAuthenticationSpy(&server,
248                               SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*)));
249     QSignalSpy serverClosedSpy(&server, SIGNAL(closed()));
250 #ifndef QT_NO_SSL
251     QSignalSpy peerVerifyErrorSpy(&server, SIGNAL(peerVerifyError(QSslError)));
252     QSignalSpy sslErrorsSpy(&server, SIGNAL(sslErrors(QList<QSslError>)));
253 #endif
254     QWebSocket socket;
255     QSignalSpy socketConnectedSpy(&socket, SIGNAL(connected()));
256
257     QVERIFY(server.listen());
258     QCOMPARE(server.serverAddress(), QHostAddress(QHostAddress::Any));
259     QCOMPARE(server.serverUrl(), QUrl(QStringLiteral("ws://") + QHostAddress(QHostAddress::LocalHost).toString() +
260                                  QStringLiteral(":").append(QString::number(server.serverPort()))));
261
262     socket.open(server.serverUrl().toString());
263
264     if (socketConnectedSpy.count() == 0)
265         QVERIFY(socketConnectedSpy.wait());
266     QCOMPARE(socket.state(), QAbstractSocket::ConnectedState);
267     QCOMPARE(serverConnectionSpy.count(), 1);
268     QCOMPARE(corsAuthenticationSpy.count(), 1);
269
270     QCOMPARE(serverClosedSpy.count(), 0);
271
272     server.close();
273
274     QVERIFY(serverClosedSpy.wait());
275     QCOMPARE(serverClosedSpy.count(), 1);
276 #ifndef QT_NO_SSL
277     QCOMPARE(peerVerifyErrorSpy.count(), 0);
278     QCOMPARE(sslErrorsSpy.count(), 0);
279 #endif
280     QCOMPARE(serverErrorSpy.count(), 0);
281 }
282
283 void tst_QWebSocketServer::tst_maxPendingConnections()
284 {
285     //tests if maximum connections are respected
286     //also checks if there are no side-effects like signals that are unexpectedly thrown
287     QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode);
288     server.setMaxPendingConnections(2);
289     QSignalSpy serverConnectionSpy(&server, SIGNAL(newConnection()));
290     QSignalSpy serverErrorSpy(&server,
291                               SIGNAL(serverError(QWebSocketProtocol::CloseCode)));
292     QSignalSpy corsAuthenticationSpy(&server,
293                               SIGNAL(originAuthenticationRequired(QWebSocketCorsAuthenticator*)));
294     QSignalSpy serverClosedSpy(&server, SIGNAL(closed()));
295 #ifndef QT_NO_SSL
296     QSignalSpy peerVerifyErrorSpy(&server, SIGNAL(peerVerifyError(QSslError)));
297     QSignalSpy sslErrorsSpy(&server, SIGNAL(sslErrors(QList<QSslError>)));
298 #endif
299     QSignalSpy serverAcceptErrorSpy(&server, SIGNAL(acceptError(QAbstractSocket::SocketError)));
300
301     QWebSocket socket1;
302     QWebSocket socket2;
303     QWebSocket socket3;
304
305     QSignalSpy socket1ConnectedSpy(&socket1, SIGNAL(connected()));
306     QSignalSpy socket2ConnectedSpy(&socket2, SIGNAL(connected()));
307     QSignalSpy socket3ConnectedSpy(&socket3, SIGNAL(connected()));
308
309     QVERIFY(server.listen());
310
311     socket1.open(server.serverUrl().toString());
312
313     if (socket1ConnectedSpy.count() == 0)
314         QVERIFY(socket1ConnectedSpy.wait());
315     QCOMPARE(socket1.state(), QAbstractSocket::ConnectedState);
316     QCOMPARE(serverConnectionSpy.count(), 1);
317     QCOMPARE(corsAuthenticationSpy.count(), 1);
318     socket2.open(server.serverUrl().toString());
319     if (socket2ConnectedSpy.count() == 0)
320         QVERIFY(socket2ConnectedSpy.wait());
321     QCOMPARE(socket2.state(), QAbstractSocket::ConnectedState);
322     QCOMPARE(serverConnectionSpy.count(), 2);
323     QCOMPARE(corsAuthenticationSpy.count(), 2);
324     socket3.open(server.serverUrl().toString());
325     if (socket3ConnectedSpy.count() == 0)
326         QVERIFY(!socket3ConnectedSpy.wait(250));
327     QCOMPARE(socket3.state(), QAbstractSocket::UnconnectedState);
328     QCOMPARE(serverConnectionSpy.count(), 2);
329     QCOMPARE(corsAuthenticationSpy.count(), 2);
330
331     QVERIFY(server.hasPendingConnections());
332     QWebSocket *pSocket = server.nextPendingConnection();
333     QVERIFY(pSocket);
334     delete pSocket;
335     QVERIFY(server.hasPendingConnections());
336     pSocket = server.nextPendingConnection();
337     QVERIFY(pSocket);
338     delete pSocket;
339     QVERIFY(!server.hasPendingConnections());
340     QVERIFY(!server.nextPendingConnection());
341
342 //will resolve in another commit
343 #ifndef Q_OS_WIN
344     QCOMPARE(serverErrorSpy.count(), 1);
345     QCOMPARE(serverErrorSpy.at(0).at(0).value<QWebSocketProtocol::CloseCode>(),
346              QWebSocketProtocol::CloseCodeAbnormalDisconnection);
347 #endif
348     QCOMPARE(serverClosedSpy.count(), 0);
349
350     server.close();
351
352     QVERIFY(serverClosedSpy.wait());
353     QCOMPARE(serverClosedSpy.count(), 1);
354 #ifndef QT_NO_SSL
355     QCOMPARE(peerVerifyErrorSpy.count(), 0);
356     QCOMPARE(sslErrorsSpy.count(), 0);
357 #endif
358     QCOMPARE(serverAcceptErrorSpy.count(), 0);
359 }
360
361
362 QTEST_MAIN(tst_QWebSocketServer)
363
364 #include "tst_qwebsocketserver.moc"