tests/auto/qsystemreadwritelock_oop/tst_qsystemreadwritelock_oop.cpp
changeset 0 876b1a06bc25
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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 Qt Mobility Components.
       
     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 #include <QtTest/QtTest>
       
    43 #include <QDir>
       
    44 #include <QProcess>
       
    45 #include <QIODevice>
       
    46 #include <QLocalServer>
       
    47 #include <QLocalSocket>
       
    48 #include "qsystemreadwritelock_p.h"
       
    49 #include "common.h"
       
    50 
       
    51 QTM_USE_NAMESPACE
       
    52 class tst_QSystemReadWriteLock_oop : public QObject{
       
    53     Q_OBJECT
       
    54 private slots:
       
    55     void initTestCase();
       
    56     void readLockBlockRelease();
       
    57     void writeLockBlockRelease();
       
    58     void multipleReadersBlockRelease();
       
    59     void multipleReadersLoop();
       
    60     void multipleWritersLoop();
       
    61     void exclusiveWriteTest();
       
    62     void writerPrecedence();
       
    63 
       
    64 private:
       
    65     bool waitForLine(QIODevice *device, const QString &expectedLine,
       
    66                     bool print = false, int timeout=5000);
       
    67 
       
    68 };
       
    69 
       
    70 void tst_QSystemReadWriteLock_oop::initTestCase()
       
    71 {
       
    72     // if an old writeLockExcl.tmp exists at the beginning of this test case, try to remove it,
       
    73     // otherwise test functions may fail
       
    74     QDir cwd;
       
    75     if (cwd.exists("writeLockExcl.tmp")) {
       
    76         QVERIFY(cwd.remove("writeLockExcl.tmp"));
       
    77     }
       
    78 }
       
    79 
       
    80 /*
       
    81     A writer aquires a write-lock, a reader tries to lock
       
    82     the writer releases the lock, the reader gets the lock
       
    83 */
       
    84 void tst_QSystemReadWriteLock_oop::readLockBlockRelease()
       
    85 {
       
    86     bool print = false;
       
    87     QSystemReadWriteLock testLock("Viper", QSystemReadWriteLock::Create);
       
    88     if (print)
       
    89         qDebug() << "Main process: About to lock for writing";
       
    90     testLock.lockForWrite();
       
    91     if (print)
       
    92         qDebug() << "Main process: After lock for writing";
       
    93 
       
    94     QLocalServer server;
       
    95     QString connectionName = "readLockBlockRelease";
       
    96     QVERIFY(QLocalServer::removeServer(connectionName));
       
    97     QVERIFY(server.listen(connectionName));
       
    98 
       
    99     QProcess reader;
       
   100     reader.setReadChannel(QProcess::StandardError);
       
   101     QStringList args;
       
   102     args << connectionName;
       
   103     args << "ReadLock";
       
   104 
       
   105     reader.start("./lackey", args);
       
   106     QVERIFY(reader.waitForStarted());
       
   107 
       
   108     QVERIFY(server.waitForNewConnection(5000));
       
   109     QLocalSocket *oopSocket = server.nextPendingConnection();
       
   110 
       
   111     QVERIFY(waitForLine(oopSocket, Lackey::BeforeLockForRead,print));
       
   112     QVERIFY(!waitForLine(oopSocket, Lackey::AfterLockForRead,false,1000));
       
   113 
       
   114     testLock.unlock();
       
   115     if (print)
       
   116         qDebug() << "Main process: After unlock(write)";
       
   117 
       
   118     QVERIFY(waitForLine(oopSocket, Lackey::AfterLockForRead, print));
       
   119     QVERIFY(waitForLine(oopSocket, Lackey::AfterUnlockForRead, print));
       
   120     QVERIFY(reader.waitForFinished());
       
   121 }
       
   122 
       
   123 /*
       
   124     writer1(main process) aquires a write-lock, writer2(lackey) blocks,
       
   125     writer1 releases the lock, writer2 gets the lock
       
   126 */
       
   127 void tst_QSystemReadWriteLock_oop::writeLockBlockRelease()
       
   128 {
       
   129     bool print = false;
       
   130     QSystemReadWriteLock testLock("Viper", QSystemReadWriteLock::Create);
       
   131     if (print)
       
   132         qDebug() << "Main process: About to lock for writing";
       
   133     testLock.lockForWrite();
       
   134     if (print)
       
   135         qDebug() << "Main process: After lock for writing";
       
   136 
       
   137     QLocalServer server;
       
   138     QString connectionName = "writeLockBlockRelease";
       
   139     QVERIFY(QLocalServer::removeServer(connectionName));
       
   140     QVERIFY(server.listen(connectionName));
       
   141 
       
   142     QProcess writer;
       
   143     writer.setReadChannel(QProcess::StandardError);
       
   144     QStringList args;
       
   145     args << connectionName;
       
   146     args << "WriteLock";
       
   147     writer.start("./lackey", args);
       
   148     QVERIFY(writer.waitForStarted());
       
   149 
       
   150     QVERIFY(server.waitForNewConnection(5000));
       
   151     QLocalSocket *oopSocket = server.nextPendingConnection();
       
   152 
       
   153     QVERIFY(waitForLine(oopSocket, Lackey::BeforeLockForWrite,print));
       
   154     QVERIFY(!waitForLine(oopSocket, Lackey::AfterUnlockForWrite,false, 1000));
       
   155 
       
   156     testLock.unlock();
       
   157     if (print)
       
   158         qDebug() << "Main process: After unlock(write)";
       
   159 
       
   160     QVERIFY(waitForLine(oopSocket, Lackey::AfterLockForWrite, print));
       
   161     QVERIFY(waitForLine(oopSocket, Lackey::AfterUnlockForWrite, print));
       
   162     QVERIFY(writer.waitForFinished());
       
   163 }
       
   164 
       
   165 /*
       
   166     Two readers aquire a read-lock, one writer attempts a write lock and blocks,
       
   167     the readers release their locks, the writer gets the lock.
       
   168 */
       
   169 void tst_QSystemReadWriteLock_oop::multipleReadersBlockRelease()
       
   170 {
       
   171     bool print = false;
       
   172     //Use the Create enum to ensure synchronization primitives are reset
       
   173     //to a "clean" state
       
   174     QSystemReadWriteLock rwlock("Viper", QSystemReadWriteLock::Create);
       
   175 
       
   176     const int numReaders = 2;
       
   177     QProcess readers[numReaders];
       
   178     QLocalServer readerServers[numReaders];
       
   179     QLocalSocket *readerSockets[numReaders];
       
   180 
       
   181     QString connectionName = "multipleReadersBlockRelease";
       
   182 
       
   183     QStringList args;
       
   184     args << "ReadLockReleaseable";
       
   185 
       
   186     for( int i=0; i < numReaders; ++i) {
       
   187         QString readerConnectionName = connectionName.append("_reader_").append(QString::number(i));
       
   188         QVERIFY(QLocalServer::removeServer(readerConnectionName));
       
   189         QVERIFY(readerServers[i].listen(readerConnectionName));
       
   190         args.push_front(readerConnectionName);
       
   191 
       
   192         readers[i].setReadChannel(QProcess::StandardError);
       
   193         readers[i].start("./lackey", args);
       
   194         QVERIFY(readers[i].waitForStarted());
       
   195 
       
   196         QVERIFY(readerServers[i].waitForNewConnection(5000));
       
   197         readerSockets[i] = readerServers[i].nextPendingConnection();
       
   198 
       
   199         QVERIFY(waitForLine(readerSockets[i], Lackey::BeforeLockForRead, print));
       
   200         QVERIFY(waitForLine(readerSockets[i], Lackey::AfterLockForRead, print));
       
   201 
       
   202         args.pop_front();
       
   203     }
       
   204 
       
   205     QLocalServer server;
       
   206     QString writerConnectionName = connectionName.append("_writer");
       
   207     QVERIFY(QLocalServer::removeServer(writerConnectionName));
       
   208     QVERIFY(server.listen(writerConnectionName));
       
   209 
       
   210     QProcess writer;
       
   211     writer.setReadChannel(QProcess::StandardError);
       
   212     args.clear();
       
   213     args << writerConnectionName;
       
   214     args << "WriteLock";
       
   215     writer.start("./lackey", args);
       
   216     QVERIFY(writer.waitForStarted());
       
   217 
       
   218     QVERIFY(server.waitForNewConnection(5000));
       
   219     QLocalSocket *writerSocket = server.nextPendingConnection();
       
   220 
       
   221     QVERIFY(waitForLine(writerSocket, Lackey::BeforeLockForWrite, print));
       
   222     QVERIFY(!waitForLine(writerSocket, Lackey::AfterLockForWrite, false, 1000));
       
   223 
       
   224     for (int i = 0; i < numReaders; ++i) {
       
   225         readerSockets[i]->write("release\n");
       
   226         QVERIFY(waitForLine(readerSockets[i], Lackey::AfterUnlockForRead, print));
       
   227         if ( i < (numReaders - 1))
       
   228             QVERIFY(!waitForLine(writerSocket, Lackey::AfterLockForWrite, false, 1000));
       
   229     }
       
   230     QVERIFY(waitForLine(writerSocket, Lackey::AfterLockForWrite, print));
       
   231     QVERIFY(waitForLine(writerSocket, Lackey::AfterUnlockForWrite, print));
       
   232 
       
   233     for(int i = 0; i < numReaders; ++i) {
       
   234         QVERIFY(readers[i].waitForFinished());
       
   235     }
       
   236     QVERIFY(writer.waitForFinished());
       
   237 }
       
   238 
       
   239 /*
       
   240     Multiple readers locks and unlocks a lock.
       
   241 */
       
   242 void tst_QSystemReadWriteLock_oop::multipleReadersLoop()
       
   243 {
       
   244     //ensure synchronization primitives are reset to a "clean" state
       
   245     QSystemReadWriteLock testLock("Viper", QSystemReadWriteLock::Create);
       
   246 
       
   247     int runTime = 10;
       
   248     int holdTime = 10;
       
   249     int waitTime = 0;
       
   250 
       
   251     const int numReaders = 10;
       
   252     QProcess readers[numReaders];
       
   253     QStringList args;
       
   254     args << "NoComms" // no communications between test and lackey
       
   255         << "ReadLockLoop"
       
   256         << QString::number(runTime)
       
   257         << QString::number(holdTime)
       
   258         << QString::number(waitTime);
       
   259 
       
   260     for (int i = 0; i < numReaders; ++i) {
       
   261         readers[i].setProcessChannelMode(QProcess::ForwardedChannels);
       
   262         readers[i].start("./lackey", args);
       
   263     }
       
   264 
       
   265     for (int i=0; i < numReaders; ++i) {
       
   266         QVERIFY(readers[i].waitForFinished(5000));
       
   267         QCOMPARE(readers[i].exitCode(), 0);
       
   268         QCOMPARE(readers[i].exitStatus(), QProcess::NormalExit);
       
   269     }
       
   270 }
       
   271 
       
   272 /*
       
   273     Multiple writers lock and unlock a lock
       
   274 */
       
   275 void tst_QSystemReadWriteLock_oop::multipleWritersLoop()
       
   276 {
       
   277     //ensure synchronization primitives are reset to a "clean" state
       
   278     QSystemReadWriteLock testLock("Viper", QSystemReadWriteLock::Create);
       
   279 
       
   280     int runTime = 10;
       
   281     int holdTime = 10;
       
   282     int waitTime = 0;
       
   283 
       
   284     const int numWriters = 10;
       
   285     QProcess writers[numWriters];
       
   286     QStringList args;
       
   287     args << "NoComms" // no communications between test and lackey
       
   288         << "WriteLockLoop"
       
   289         << QString::number(runTime)
       
   290         << QString::number(holdTime)
       
   291         << QString::number(waitTime);
       
   292 
       
   293     for (int i = 0; i < numWriters; ++i) {
       
   294         writers[i].setProcessChannelMode(QProcess::ForwardedChannels);
       
   295         writers[i].start("./lackey", args);
       
   296     }
       
   297 
       
   298     for (int i = 0; i < numWriters; ++i) {
       
   299         QVERIFY(writers[i].waitForFinished(5000));
       
   300         QCOMPARE(writers[i].exitCode(), 0);
       
   301         QCOMPARE(writers[i].exitStatus(), QProcess::NormalExit);
       
   302     }
       
   303 }
       
   304 
       
   305 /*
       
   306     Writers create an exclusive file while they have a write lock
       
   307     and remove it on unlock.  Readers verify that that the file
       
   308     does not exist and writers verify that the file does not
       
   309     already exist when they obtain a lock.
       
   310 */
       
   311 void tst_QSystemReadWriteLock_oop::exclusiveWriteTest()
       
   312 {
       
   313     //ensure synchronization primitives are reset to a "clean" state
       
   314     QSystemReadWriteLock testLock("Viper", QSystemReadWriteLock::Create);
       
   315 
       
   316     int runTime=10000;
       
   317 #if !defined(Q_OS_WINCE)
       
   318     const int numReaders = 20;
       
   319 #else
       
   320     const int numReaders = 10;
       
   321 #endif
       
   322 
       
   323     int readerHoldTime = 0;
       
   324     int readerWaitTime = 1;
       
   325 
       
   326     const int numWriters = 3;
       
   327     int writerHoldTime = 20;
       
   328     int writerWaitTime = 150;
       
   329 
       
   330     QProcess readers[numReaders];
       
   331     QProcess writers[numWriters];
       
   332     QStringList args;
       
   333     args << "NoComms" // no communications between test and lackey
       
   334         << "ReadLockExcl"
       
   335         << QString::number(runTime)
       
   336         << QString::number(readerHoldTime)
       
   337         << QString::number(readerWaitTime);
       
   338 
       
   339     for (int i = 0; i < numReaders; ++i) {
       
   340         readers[i].setProcessChannelMode(QProcess::ForwardedChannels);
       
   341         readers[i].start("./lackey", args);
       
   342     }
       
   343 
       
   344     args.clear();
       
   345     args << "NoComms" // no communications between test and lackey
       
   346         << "WriteLockExcl"
       
   347         << QString::number(runTime)
       
   348         << QString::number(writerHoldTime)
       
   349         << QString::number(writerWaitTime);
       
   350     for (int i = 0; i < numWriters; ++i) {
       
   351         writers[i].setProcessChannelMode(QProcess::ForwardedChannels);
       
   352         writers[i].start("./lackey", args);
       
   353     }
       
   354 
       
   355     // Finding the existence of the exclusive file will
       
   356     // result in a qFatal() in the lackey process
       
   357     // The exit status checks below will fail if this
       
   358     // is the case
       
   359     for (int i = 0; i < numReaders; ++i) {
       
   360         QVERIFY(readers[i].waitForFinished(2 * runTime));
       
   361         QCOMPARE(readers[i].exitCode(), 0);
       
   362         QCOMPARE(readers[i].exitStatus(), QProcess::NormalExit);
       
   363      }
       
   364 
       
   365     for (int i = 0; i < numWriters; ++i) {
       
   366         QVERIFY(writers[i].waitForFinished(2 * runTime));
       
   367         QCOMPARE(writers[i].exitCode(), 0);
       
   368         QCOMPARE(writers[i].exitStatus(), QProcess::NormalExit);
       
   369      }
       
   370 }
       
   371 
       
   372 /*
       
   373     Writer1(main process) acquires a write-lock
       
   374     Readers try to acquire read-locks but are blocked
       
   375     Writer2(lackey) tries to acquire a write-lock, but is blocked
       
   376     Writer1 releases the lock, writer2 gets the lock, readers still blocked
       
   377     Writer2 releases the lock, readers are unblocked and get their read-locks
       
   378 */
       
   379 void tst_QSystemReadWriteLock_oop::writerPrecedence()
       
   380 {
       
   381     bool print = false;
       
   382     QSystemReadWriteLock testRwLock("Viper", QSystemReadWriteLock::Create);
       
   383     if (print)
       
   384         qDebug() << "Main process: About to lock for writing";
       
   385     testRwLock.lockForWrite();
       
   386      if (print)
       
   387         qDebug() << "Main process: After lock for writing";
       
   388 
       
   389     const int numReaders = 5;
       
   390     QProcess readers[numReaders];
       
   391     QLocalServer readerServers[numReaders];
       
   392     QLocalSocket *readerSockets[numReaders];
       
   393 
       
   394     QString connectionName = "writePrecedence";
       
   395 
       
   396     QStringList args;
       
   397     args << "ReadLock";
       
   398     for (int i = 0; i < numReaders; ++i) {
       
   399         QString readerConnectionName = connectionName.append("_reader_").append(QString::number(i));
       
   400         QVERIFY(QLocalServer::removeServer(readerConnectionName));
       
   401         QVERIFY(readerServers[i].listen(readerConnectionName));
       
   402         args.push_front(readerConnectionName);
       
   403 
       
   404         readers[i].setReadChannel(QProcess::StandardError);
       
   405         readers[i].start("./lackey", args);
       
   406         QVERIFY(readers[i].waitForStarted());
       
   407 
       
   408         QVERIFY(readerServers[i].waitForNewConnection(5000));
       
   409         readerSockets[i] = readerServers[i].nextPendingConnection();
       
   410 
       
   411         QVERIFY(waitForLine(readerSockets[i], Lackey::BeforeLockForRead, print));
       
   412         QVERIFY(!waitForLine(readerSockets[i], Lackey::AfterLockForRead, false, 1000));
       
   413 
       
   414         args.pop_front();
       
   415     }
       
   416 
       
   417     QLocalServer server;
       
   418     QString writerConnectionName = connectionName.append("_writer");
       
   419     QVERIFY(QLocalServer::removeServer(writerConnectionName));
       
   420     QVERIFY(server.listen(writerConnectionName));
       
   421 
       
   422     QProcess writer;
       
   423     writer.setReadChannel(QProcess::StandardError);
       
   424     args.clear();
       
   425     args << writerConnectionName;
       
   426     args << "WriteLockReleaseable";
       
   427     writer.start("./lackey", args);
       
   428 
       
   429     QVERIFY(server.waitForNewConnection(5000));
       
   430     QLocalSocket *writerSocket = server.nextPendingConnection();
       
   431 
       
   432     QVERIFY(waitForLine(writerSocket, Lackey::BeforeLockForWrite, print));
       
   433     QVERIFY(!waitForLine(writerSocket, Lackey::AfterLockForWrite, false, 1000));
       
   434 
       
   435     testRwLock.unlock();
       
   436     QVERIFY(waitForLine(writerSocket, Lackey::AfterLockForWrite, print));
       
   437      if (print)
       
   438         qDebug() << "Main process: After unlock(write)";
       
   439 
       
   440    //verify the reader processes are still blocked
       
   441     QTest::qSleep(1000);
       
   442     for (int i = 0; i < numReaders; ++i) {
       
   443         QCOMPARE(readers[i].state(), QProcess::Running);
       
   444     }
       
   445 
       
   446     writerSocket->write("release\n");
       
   447     QVERIFY(waitForLine(writerSocket, Lackey::AfterUnlockForWrite, print));
       
   448 
       
   449     for (int i = 0; i < numReaders; ++i) {
       
   450         QVERIFY(waitForLine(readerSockets[i], Lackey::AfterLockForRead, print));
       
   451     }//Note: 2 loops (ie above and below) are used due to timing issues
       
   452     for (int i = 0; i < numReaders; ++i) {
       
   453         QVERIFY(waitForLine(readerSockets[i], Lackey::AfterUnlockForRead, print));
       
   454     }
       
   455 
       
   456     for (int i = 0; i < numReaders; ++i) {
       
   457         QVERIFY(readers[i].waitForFinished(5000));
       
   458     }
       
   459     QVERIFY(writer.waitForFinished(5000));
       
   460 }
       
   461 
       
   462 
       
   463 /*
       
   464    Waits for a given \a expectedLine to be written by \a process
       
   465    for a given \a timeout(msecs).  The line written by the process
       
   466    is printed to console if \a print is true.
       
   467 */
       
   468 bool tst_QSystemReadWriteLock_oop::waitForLine(QIODevice * device,const QString &expectedLine, bool print, int timeout)
       
   469 {
       
   470     if (!device->waitForReadyRead(timeout))
       
   471     {
       
   472         if (print)
       
   473             qWarning() << "Wait for ready read returned false";
       
   474         return false;
       
   475     }
       
   476 
       
   477     QString line = device->readLine();
       
   478     line = line.trimmed();
       
   479     if (print)
       
   480         qDebug() << qPrintable(line);
       
   481     if (line.compare(expectedLine) !=0) {
       
   482         qWarning() << "Expected Line: \t" << qPrintable(expectedLine);
       
   483         qWarning() << "Actual Line: \t" << qPrintable(line);
       
   484         return false;
       
   485     }
       
   486 
       
   487     return true;
       
   488 }
       
   489 
       
   490 QTEST_MAIN(tst_QSystemReadWriteLock_oop)
       
   491 #include "tst_qsystemreadwritelock_oop.moc"