tests/auto/qsocketnotifier/tst_qsocketnotifier.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    43 #include <QtTest/QtTest>
       
    44 
       
    45 #include <QtCore/QCoreApplication>
       
    46 #include <QtCore/QSocketNotifier>
       
    47 #include <QtNetwork/QTcpServer>
       
    48 #include <QtNetwork/QTcpSocket>
       
    49 #include <private/qnativesocketengine_p.h>
       
    50 
       
    51 class tst_QSocketNotifier : public QObject
       
    52 {
       
    53     Q_OBJECT
       
    54 public:
       
    55     tst_QSocketNotifier();
       
    56     ~tst_QSocketNotifier();
       
    57 
       
    58 private slots:
       
    59     void unexpectedDisconnection();
       
    60     void mixingWithTimers();
       
    61 };
       
    62 
       
    63 tst_QSocketNotifier::tst_QSocketNotifier()
       
    64 { }
       
    65 
       
    66 tst_QSocketNotifier::~tst_QSocketNotifier()
       
    67 {
       
    68 }
       
    69 
       
    70 class UnexpectedDisconnectTester : public QObject
       
    71 {
       
    72     Q_OBJECT
       
    73 public:
       
    74     QNativeSocketEngine *readEnd1, *readEnd2;
       
    75     int sequence;
       
    76 
       
    77     UnexpectedDisconnectTester(QNativeSocketEngine *s1, QNativeSocketEngine *s2)
       
    78         : readEnd1(s1), readEnd2(s2), sequence(0)
       
    79     {
       
    80         QSocketNotifier *notifier1 =
       
    81             new QSocketNotifier(readEnd1->socketDescriptor(), QSocketNotifier::Read, this);
       
    82         connect(notifier1, SIGNAL(activated(int)), SLOT(handleActivated()));
       
    83         QSocketNotifier *notifier2 =
       
    84             new QSocketNotifier(readEnd2->socketDescriptor(), QSocketNotifier::Read, this);
       
    85         connect(notifier2, SIGNAL(activated(int)), SLOT(handleActivated()));
       
    86     }
       
    87 
       
    88 public slots:
       
    89     void handleActivated()
       
    90     {
       
    91         char data1[1], data2[1];
       
    92         ++sequence;
       
    93         if (sequence == 1) {
       
    94             // read from both ends
       
    95             (void) readEnd1->read(data1, sizeof(data1));
       
    96             (void) readEnd2->read(data2, sizeof(data2));
       
    97             emit finished();
       
    98         } else if (sequence == 2) {
       
    99             // we should never get here
       
   100             QCOMPARE(readEnd2->read(data2, sizeof(data2)), qint64(-2));
       
   101             QVERIFY(readEnd2->isValid());
       
   102         }
       
   103     }
       
   104 
       
   105 signals:
       
   106     void finished();
       
   107 };
       
   108 
       
   109 void tst_QSocketNotifier::unexpectedDisconnection()
       
   110 {
       
   111     /*
       
   112       Given two sockets and two QSocketNotifiers registered on each
       
   113       their socket. If both sockets receive data, and the first slot
       
   114       invoked by one of the socket notifiers empties both sockets, the
       
   115       other notifier will also emit activated(). This results in
       
   116       unexpected disconnection in QAbstractSocket.
       
   117 
       
   118       The use case is that somebody calls one of the
       
   119       waitFor... functions in a QSocketNotifier activated slot, and
       
   120       the waitFor... functions do local selects that can empty both
       
   121       stdin and stderr while waiting for fex bytes to be written.
       
   122     */
       
   123 
       
   124     QTcpServer server;
       
   125     QVERIFY(server.listen(QHostAddress::LocalHost, 0));
       
   126 
       
   127     QNativeSocketEngine readEnd1;
       
   128     readEnd1.initialize(QAbstractSocket::TcpSocket);
       
   129     bool b = readEnd1.connectToHost(server.serverAddress(), server.serverPort());
       
   130     QVERIFY(readEnd1.waitForWrite());
       
   131 //    while (!b && readEnd1.state() != QAbstractSocket::ConnectedState)
       
   132 //        b = readEnd1.connectToHost(server.serverAddress(), server.serverPort());
       
   133     QVERIFY(readEnd1.state() == QAbstractSocket::ConnectedState);
       
   134     QVERIFY(server.waitForNewConnection());
       
   135     QTcpSocket *writeEnd1 = server.nextPendingConnection();
       
   136     QVERIFY(writeEnd1 != 0);
       
   137 
       
   138     QNativeSocketEngine readEnd2;
       
   139     readEnd2.initialize(QAbstractSocket::TcpSocket);
       
   140     b = readEnd2.connectToHost(server.serverAddress(), server.serverPort());
       
   141     QVERIFY(readEnd2.waitForWrite());
       
   142 //    while (!b)
       
   143 //        b = readEnd2.connectToHost(server.serverAddress(), server.serverPort());
       
   144     QVERIFY(readEnd2.state() == QAbstractSocket::ConnectedState);
       
   145     QVERIFY(server.waitForNewConnection());
       
   146     QTcpSocket *writeEnd2 = server.nextPendingConnection();
       
   147     QVERIFY(writeEnd2 != 0);
       
   148 
       
   149     writeEnd1->write("1", 1);
       
   150     writeEnd2->write("2", 1);
       
   151 
       
   152     writeEnd1->waitForBytesWritten();
       
   153     writeEnd2->waitForBytesWritten();
       
   154 
       
   155     writeEnd1->flush();
       
   156     writeEnd2->flush();
       
   157 
       
   158     UnexpectedDisconnectTester tester(&readEnd1, &readEnd2);
       
   159 
       
   160     do {
       
   161         // we have to wait until sequence value changes
       
   162         // as any event can make us jump out processing
       
   163         QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
       
   164     }  while(tester.sequence <= 0);
       
   165 
       
   166     QVERIFY(readEnd1.state() == QAbstractSocket::ConnectedState);
       
   167     QVERIFY(readEnd2.state() == QAbstractSocket::ConnectedState);
       
   168 
       
   169     QCOMPARE(tester.sequence, 2);
       
   170 
       
   171     readEnd1.close();
       
   172     readEnd2.close();
       
   173     writeEnd1->close();
       
   174     writeEnd2->close();
       
   175     server.close();
       
   176 }
       
   177 
       
   178 class MixingWithTimersHelper : public QObject
       
   179 {
       
   180     Q_OBJECT
       
   181 
       
   182 public:
       
   183     MixingWithTimersHelper(QTimer *timer, QTcpServer *server);
       
   184 
       
   185     bool timerActivated;
       
   186     bool socketActivated;
       
   187 
       
   188 private slots:
       
   189     void timerFired();
       
   190     void socketFired();
       
   191 };
       
   192 
       
   193 MixingWithTimersHelper::MixingWithTimersHelper(QTimer *timer, QTcpServer *server)
       
   194 {
       
   195     timerActivated = false;
       
   196     socketActivated = false;
       
   197 
       
   198     connect(timer, SIGNAL(timeout()), SLOT(timerFired()));
       
   199     connect(server, SIGNAL(newConnection()), SLOT(socketFired()));
       
   200 }
       
   201 
       
   202 void MixingWithTimersHelper::timerFired()
       
   203 {
       
   204     timerActivated = true;
       
   205 }
       
   206 
       
   207 void MixingWithTimersHelper::socketFired()
       
   208 {
       
   209     socketActivated = true;
       
   210 }
       
   211 
       
   212 void tst_QSocketNotifier::mixingWithTimers()
       
   213 {
       
   214     QTimer timer;
       
   215     timer.setInterval(0);
       
   216     timer.start();
       
   217 
       
   218     QTcpServer server;
       
   219     QVERIFY(server.listen(QHostAddress::LocalHost, 0));
       
   220 
       
   221     MixingWithTimersHelper helper(&timer, &server);
       
   222 
       
   223     QCoreApplication::processEvents();
       
   224 
       
   225     QCOMPARE(helper.timerActivated, true);
       
   226     QCOMPARE(helper.socketActivated, false);
       
   227 
       
   228     helper.timerActivated = false;
       
   229     helper.socketActivated = false;
       
   230 
       
   231     QTcpSocket socket;
       
   232     socket.connectToHost(server.serverAddress(), server.serverPort());
       
   233 
       
   234     QCoreApplication::processEvents();
       
   235 
       
   236     QCOMPARE(helper.timerActivated, true);
       
   237     QCOMPARE(helper.socketActivated, true);
       
   238 }
       
   239 
       
   240 QTEST_MAIN(tst_QSocketNotifier)
       
   241 #include <tst_qsocketnotifier.moc>