--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/auto/qsystemreadwritelock_oop/tst_qsystemreadwritelock_oop.cpp Wed Aug 25 15:49:42 2010 +0300
@@ -0,0 +1,491 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QDir>
+#include <QProcess>
+#include <QIODevice>
+#include <QLocalServer>
+#include <QLocalSocket>
+#include "qsystemreadwritelock_p.h"
+#include "common.h"
+
+QTM_USE_NAMESPACE
+class tst_QSystemReadWriteLock_oop : public QObject{
+ Q_OBJECT
+private slots:
+ void initTestCase();
+ void readLockBlockRelease();
+ void writeLockBlockRelease();
+ void multipleReadersBlockRelease();
+ void multipleReadersLoop();
+ void multipleWritersLoop();
+ void exclusiveWriteTest();
+ void writerPrecedence();
+
+private:
+ bool waitForLine(QIODevice *device, const QString &expectedLine,
+ bool print = false, int timeout=5000);
+
+};
+
+void tst_QSystemReadWriteLock_oop::initTestCase()
+{
+ // if an old writeLockExcl.tmp exists at the beginning of this test case, try to remove it,
+ // otherwise test functions may fail
+ QDir cwd;
+ if (cwd.exists("writeLockExcl.tmp")) {
+ QVERIFY(cwd.remove("writeLockExcl.tmp"));
+ }
+}
+
+/*
+ A writer aquires a write-lock, a reader tries to lock
+ the writer releases the lock, the reader gets the lock
+*/
+void tst_QSystemReadWriteLock_oop::readLockBlockRelease()
+{
+ bool print = false;
+ QSystemReadWriteLock testLock("Viper", QSystemReadWriteLock::Create);
+ if (print)
+ qDebug() << "Main process: About to lock for writing";
+ testLock.lockForWrite();
+ if (print)
+ qDebug() << "Main process: After lock for writing";
+
+ QLocalServer server;
+ QString connectionName = "readLockBlockRelease";
+ QVERIFY(QLocalServer::removeServer(connectionName));
+ QVERIFY(server.listen(connectionName));
+
+ QProcess reader;
+ reader.setReadChannel(QProcess::StandardError);
+ QStringList args;
+ args << connectionName;
+ args << "ReadLock";
+
+ reader.start("./lackey", args);
+ QVERIFY(reader.waitForStarted());
+
+ QVERIFY(server.waitForNewConnection(5000));
+ QLocalSocket *oopSocket = server.nextPendingConnection();
+
+ QVERIFY(waitForLine(oopSocket, Lackey::BeforeLockForRead,print));
+ QVERIFY(!waitForLine(oopSocket, Lackey::AfterLockForRead,false,1000));
+
+ testLock.unlock();
+ if (print)
+ qDebug() << "Main process: After unlock(write)";
+
+ QVERIFY(waitForLine(oopSocket, Lackey::AfterLockForRead, print));
+ QVERIFY(waitForLine(oopSocket, Lackey::AfterUnlockForRead, print));
+ QVERIFY(reader.waitForFinished());
+}
+
+/*
+ writer1(main process) aquires a write-lock, writer2(lackey) blocks,
+ writer1 releases the lock, writer2 gets the lock
+*/
+void tst_QSystemReadWriteLock_oop::writeLockBlockRelease()
+{
+ bool print = false;
+ QSystemReadWriteLock testLock("Viper", QSystemReadWriteLock::Create);
+ if (print)
+ qDebug() << "Main process: About to lock for writing";
+ testLock.lockForWrite();
+ if (print)
+ qDebug() << "Main process: After lock for writing";
+
+ QLocalServer server;
+ QString connectionName = "writeLockBlockRelease";
+ QVERIFY(QLocalServer::removeServer(connectionName));
+ QVERIFY(server.listen(connectionName));
+
+ QProcess writer;
+ writer.setReadChannel(QProcess::StandardError);
+ QStringList args;
+ args << connectionName;
+ args << "WriteLock";
+ writer.start("./lackey", args);
+ QVERIFY(writer.waitForStarted());
+
+ QVERIFY(server.waitForNewConnection(5000));
+ QLocalSocket *oopSocket = server.nextPendingConnection();
+
+ QVERIFY(waitForLine(oopSocket, Lackey::BeforeLockForWrite,print));
+ QVERIFY(!waitForLine(oopSocket, Lackey::AfterUnlockForWrite,false, 1000));
+
+ testLock.unlock();
+ if (print)
+ qDebug() << "Main process: After unlock(write)";
+
+ QVERIFY(waitForLine(oopSocket, Lackey::AfterLockForWrite, print));
+ QVERIFY(waitForLine(oopSocket, Lackey::AfterUnlockForWrite, print));
+ QVERIFY(writer.waitForFinished());
+}
+
+/*
+ Two readers aquire a read-lock, one writer attempts a write lock and blocks,
+ the readers release their locks, the writer gets the lock.
+*/
+void tst_QSystemReadWriteLock_oop::multipleReadersBlockRelease()
+{
+ bool print = false;
+ //Use the Create enum to ensure synchronization primitives are reset
+ //to a "clean" state
+ QSystemReadWriteLock rwlock("Viper", QSystemReadWriteLock::Create);
+
+ const int numReaders = 2;
+ QProcess readers[numReaders];
+ QLocalServer readerServers[numReaders];
+ QLocalSocket *readerSockets[numReaders];
+
+ QString connectionName = "multipleReadersBlockRelease";
+
+ QStringList args;
+ args << "ReadLockReleaseable";
+
+ for( int i=0; i < numReaders; ++i) {
+ QString readerConnectionName = connectionName.append("_reader_").append(QString::number(i));
+ QVERIFY(QLocalServer::removeServer(readerConnectionName));
+ QVERIFY(readerServers[i].listen(readerConnectionName));
+ args.push_front(readerConnectionName);
+
+ readers[i].setReadChannel(QProcess::StandardError);
+ readers[i].start("./lackey", args);
+ QVERIFY(readers[i].waitForStarted());
+
+ QVERIFY(readerServers[i].waitForNewConnection(5000));
+ readerSockets[i] = readerServers[i].nextPendingConnection();
+
+ QVERIFY(waitForLine(readerSockets[i], Lackey::BeforeLockForRead, print));
+ QVERIFY(waitForLine(readerSockets[i], Lackey::AfterLockForRead, print));
+
+ args.pop_front();
+ }
+
+ QLocalServer server;
+ QString writerConnectionName = connectionName.append("_writer");
+ QVERIFY(QLocalServer::removeServer(writerConnectionName));
+ QVERIFY(server.listen(writerConnectionName));
+
+ QProcess writer;
+ writer.setReadChannel(QProcess::StandardError);
+ args.clear();
+ args << writerConnectionName;
+ args << "WriteLock";
+ writer.start("./lackey", args);
+ QVERIFY(writer.waitForStarted());
+
+ QVERIFY(server.waitForNewConnection(5000));
+ QLocalSocket *writerSocket = server.nextPendingConnection();
+
+ QVERIFY(waitForLine(writerSocket, Lackey::BeforeLockForWrite, print));
+ QVERIFY(!waitForLine(writerSocket, Lackey::AfterLockForWrite, false, 1000));
+
+ for (int i = 0; i < numReaders; ++i) {
+ readerSockets[i]->write("release\n");
+ QVERIFY(waitForLine(readerSockets[i], Lackey::AfterUnlockForRead, print));
+ if ( i < (numReaders - 1))
+ QVERIFY(!waitForLine(writerSocket, Lackey::AfterLockForWrite, false, 1000));
+ }
+ QVERIFY(waitForLine(writerSocket, Lackey::AfterLockForWrite, print));
+ QVERIFY(waitForLine(writerSocket, Lackey::AfterUnlockForWrite, print));
+
+ for(int i = 0; i < numReaders; ++i) {
+ QVERIFY(readers[i].waitForFinished());
+ }
+ QVERIFY(writer.waitForFinished());
+}
+
+/*
+ Multiple readers locks and unlocks a lock.
+*/
+void tst_QSystemReadWriteLock_oop::multipleReadersLoop()
+{
+ //ensure synchronization primitives are reset to a "clean" state
+ QSystemReadWriteLock testLock("Viper", QSystemReadWriteLock::Create);
+
+ int runTime = 10;
+ int holdTime = 10;
+ int waitTime = 0;
+
+ const int numReaders = 10;
+ QProcess readers[numReaders];
+ QStringList args;
+ args << "NoComms" // no communications between test and lackey
+ << "ReadLockLoop"
+ << QString::number(runTime)
+ << QString::number(holdTime)
+ << QString::number(waitTime);
+
+ for (int i = 0; i < numReaders; ++i) {
+ readers[i].setProcessChannelMode(QProcess::ForwardedChannels);
+ readers[i].start("./lackey", args);
+ }
+
+ for (int i=0; i < numReaders; ++i) {
+ QVERIFY(readers[i].waitForFinished(5000));
+ QCOMPARE(readers[i].exitCode(), 0);
+ QCOMPARE(readers[i].exitStatus(), QProcess::NormalExit);
+ }
+}
+
+/*
+ Multiple writers lock and unlock a lock
+*/
+void tst_QSystemReadWriteLock_oop::multipleWritersLoop()
+{
+ //ensure synchronization primitives are reset to a "clean" state
+ QSystemReadWriteLock testLock("Viper", QSystemReadWriteLock::Create);
+
+ int runTime = 10;
+ int holdTime = 10;
+ int waitTime = 0;
+
+ const int numWriters = 10;
+ QProcess writers[numWriters];
+ QStringList args;
+ args << "NoComms" // no communications between test and lackey
+ << "WriteLockLoop"
+ << QString::number(runTime)
+ << QString::number(holdTime)
+ << QString::number(waitTime);
+
+ for (int i = 0; i < numWriters; ++i) {
+ writers[i].setProcessChannelMode(QProcess::ForwardedChannels);
+ writers[i].start("./lackey", args);
+ }
+
+ for (int i = 0; i < numWriters; ++i) {
+ QVERIFY(writers[i].waitForFinished(5000));
+ QCOMPARE(writers[i].exitCode(), 0);
+ QCOMPARE(writers[i].exitStatus(), QProcess::NormalExit);
+ }
+}
+
+/*
+ Writers create an exclusive file while they have a write lock
+ and remove it on unlock. Readers verify that that the file
+ does not exist and writers verify that the file does not
+ already exist when they obtain a lock.
+*/
+void tst_QSystemReadWriteLock_oop::exclusiveWriteTest()
+{
+ //ensure synchronization primitives are reset to a "clean" state
+ QSystemReadWriteLock testLock("Viper", QSystemReadWriteLock::Create);
+
+ int runTime=10000;
+#if !defined(Q_OS_WINCE)
+ const int numReaders = 20;
+#else
+ const int numReaders = 10;
+#endif
+
+ int readerHoldTime = 0;
+ int readerWaitTime = 1;
+
+ const int numWriters = 3;
+ int writerHoldTime = 20;
+ int writerWaitTime = 150;
+
+ QProcess readers[numReaders];
+ QProcess writers[numWriters];
+ QStringList args;
+ args << "NoComms" // no communications between test and lackey
+ << "ReadLockExcl"
+ << QString::number(runTime)
+ << QString::number(readerHoldTime)
+ << QString::number(readerWaitTime);
+
+ for (int i = 0; i < numReaders; ++i) {
+ readers[i].setProcessChannelMode(QProcess::ForwardedChannels);
+ readers[i].start("./lackey", args);
+ }
+
+ args.clear();
+ args << "NoComms" // no communications between test and lackey
+ << "WriteLockExcl"
+ << QString::number(runTime)
+ << QString::number(writerHoldTime)
+ << QString::number(writerWaitTime);
+ for (int i = 0; i < numWriters; ++i) {
+ writers[i].setProcessChannelMode(QProcess::ForwardedChannels);
+ writers[i].start("./lackey", args);
+ }
+
+ // Finding the existence of the exclusive file will
+ // result in a qFatal() in the lackey process
+ // The exit status checks below will fail if this
+ // is the case
+ for (int i = 0; i < numReaders; ++i) {
+ QVERIFY(readers[i].waitForFinished(2 * runTime));
+ QCOMPARE(readers[i].exitCode(), 0);
+ QCOMPARE(readers[i].exitStatus(), QProcess::NormalExit);
+ }
+
+ for (int i = 0; i < numWriters; ++i) {
+ QVERIFY(writers[i].waitForFinished(2 * runTime));
+ QCOMPARE(writers[i].exitCode(), 0);
+ QCOMPARE(writers[i].exitStatus(), QProcess::NormalExit);
+ }
+}
+
+/*
+ Writer1(main process) acquires a write-lock
+ Readers try to acquire read-locks but are blocked
+ Writer2(lackey) tries to acquire a write-lock, but is blocked
+ Writer1 releases the lock, writer2 gets the lock, readers still blocked
+ Writer2 releases the lock, readers are unblocked and get their read-locks
+*/
+void tst_QSystemReadWriteLock_oop::writerPrecedence()
+{
+ bool print = false;
+ QSystemReadWriteLock testRwLock("Viper", QSystemReadWriteLock::Create);
+ if (print)
+ qDebug() << "Main process: About to lock for writing";
+ testRwLock.lockForWrite();
+ if (print)
+ qDebug() << "Main process: After lock for writing";
+
+ const int numReaders = 5;
+ QProcess readers[numReaders];
+ QLocalServer readerServers[numReaders];
+ QLocalSocket *readerSockets[numReaders];
+
+ QString connectionName = "writePrecedence";
+
+ QStringList args;
+ args << "ReadLock";
+ for (int i = 0; i < numReaders; ++i) {
+ QString readerConnectionName = connectionName.append("_reader_").append(QString::number(i));
+ QVERIFY(QLocalServer::removeServer(readerConnectionName));
+ QVERIFY(readerServers[i].listen(readerConnectionName));
+ args.push_front(readerConnectionName);
+
+ readers[i].setReadChannel(QProcess::StandardError);
+ readers[i].start("./lackey", args);
+ QVERIFY(readers[i].waitForStarted());
+
+ QVERIFY(readerServers[i].waitForNewConnection(5000));
+ readerSockets[i] = readerServers[i].nextPendingConnection();
+
+ QVERIFY(waitForLine(readerSockets[i], Lackey::BeforeLockForRead, print));
+ QVERIFY(!waitForLine(readerSockets[i], Lackey::AfterLockForRead, false, 1000));
+
+ args.pop_front();
+ }
+
+ QLocalServer server;
+ QString writerConnectionName = connectionName.append("_writer");
+ QVERIFY(QLocalServer::removeServer(writerConnectionName));
+ QVERIFY(server.listen(writerConnectionName));
+
+ QProcess writer;
+ writer.setReadChannel(QProcess::StandardError);
+ args.clear();
+ args << writerConnectionName;
+ args << "WriteLockReleaseable";
+ writer.start("./lackey", args);
+
+ QVERIFY(server.waitForNewConnection(5000));
+ QLocalSocket *writerSocket = server.nextPendingConnection();
+
+ QVERIFY(waitForLine(writerSocket, Lackey::BeforeLockForWrite, print));
+ QVERIFY(!waitForLine(writerSocket, Lackey::AfterLockForWrite, false, 1000));
+
+ testRwLock.unlock();
+ QVERIFY(waitForLine(writerSocket, Lackey::AfterLockForWrite, print));
+ if (print)
+ qDebug() << "Main process: After unlock(write)";
+
+ //verify the reader processes are still blocked
+ QTest::qSleep(1000);
+ for (int i = 0; i < numReaders; ++i) {
+ QCOMPARE(readers[i].state(), QProcess::Running);
+ }
+
+ writerSocket->write("release\n");
+ QVERIFY(waitForLine(writerSocket, Lackey::AfterUnlockForWrite, print));
+
+ for (int i = 0; i < numReaders; ++i) {
+ QVERIFY(waitForLine(readerSockets[i], Lackey::AfterLockForRead, print));
+ }//Note: 2 loops (ie above and below) are used due to timing issues
+ for (int i = 0; i < numReaders; ++i) {
+ QVERIFY(waitForLine(readerSockets[i], Lackey::AfterUnlockForRead, print));
+ }
+
+ for (int i = 0; i < numReaders; ++i) {
+ QVERIFY(readers[i].waitForFinished(5000));
+ }
+ QVERIFY(writer.waitForFinished(5000));
+}
+
+
+/*
+ Waits for a given \a expectedLine to be written by \a process
+ for a given \a timeout(msecs). The line written by the process
+ is printed to console if \a print is true.
+*/
+bool tst_QSystemReadWriteLock_oop::waitForLine(QIODevice * device,const QString &expectedLine, bool print, int timeout)
+{
+ if (!device->waitForReadyRead(timeout))
+ {
+ if (print)
+ qWarning() << "Wait for ready read returned false";
+ return false;
+ }
+
+ QString line = device->readLine();
+ line = line.trimmed();
+ if (print)
+ qDebug() << qPrintable(line);
+ if (line.compare(expectedLine) !=0) {
+ qWarning() << "Expected Line: \t" << qPrintable(expectedLine);
+ qWarning() << "Actual Line: \t" << qPrintable(line);
+ return false;
+ }
+
+ return true;
+}
+
+QTEST_MAIN(tst_QSystemReadWriteLock_oop)
+#include "tst_qsystemreadwritelock_oop.moc"