summaryrefslogtreecommitdiffstats
path: root/tests/auto/qlocalsocket
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /tests/auto/qlocalsocket
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'tests/auto/qlocalsocket')
-rw-r--r--tests/auto/qlocalsocket/.gitignore2
-rw-r--r--tests/auto/qlocalsocket/example/client/client.pro10
-rw-r--r--tests/auto/qlocalsocket/example/client/main.cpp84
-rw-r--r--tests/auto/qlocalsocket/example/example.pro3
-rw-r--r--tests/auto/qlocalsocket/example/server/main.cpp97
-rw-r--r--tests/auto/qlocalsocket/example/server/server.pro13
-rw-r--r--tests/auto/qlocalsocket/lackey/lackey.pro20
-rw-r--r--tests/auto/qlocalsocket/lackey/main.cpp296
-rwxr-xr-xtests/auto/qlocalsocket/lackey/scripts/client.js35
-rw-r--r--tests/auto/qlocalsocket/lackey/scripts/server.js19
-rw-r--r--tests/auto/qlocalsocket/qlocalsocket.pro4
-rw-r--r--tests/auto/qlocalsocket/test/test.pro50
-rw-r--r--tests/auto/qlocalsocket/tst_qlocalsocket.cpp1120
13 files changed, 1753 insertions, 0 deletions
diff --git a/tests/auto/qlocalsocket/.gitignore b/tests/auto/qlocalsocket/.gitignore
new file mode 100644
index 0000000000..b45c266ce3
--- /dev/null
+++ b/tests/auto/qlocalsocket/.gitignore
@@ -0,0 +1,2 @@
+tst_qlocalsocket
+lackey/lackey.exe
diff --git a/tests/auto/qlocalsocket/example/client/client.pro b/tests/auto/qlocalsocket/example/client/client.pro
new file mode 100644
index 0000000000..84f20d6ec0
--- /dev/null
+++ b/tests/auto/qlocalsocket/example/client/client.pro
@@ -0,0 +1,10 @@
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+CONFIG += console
+QT = core network
+
+SOURCES += main.cpp
+
+
diff --git a/tests/auto/qlocalsocket/example/client/main.cpp b/tests/auto/qlocalsocket/example/client/main.cpp
new file mode 100644
index 0000000000..1e331a994c
--- /dev/null
+++ b/tests/auto/qlocalsocket/example/client/main.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $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 <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <string.h>
+#include <qstring.h>
+#include <qdebug.h>
+
+#include "qlocalsocket.h"
+
+#define SOCK_PATH "echo_socket"
+
+int main(void)
+{
+ QLocalSocket socket;
+ socket.connectToServer(SOCK_PATH);
+ socket.open(QIODevice::ReadWrite);
+
+ printf("Connected.\n");
+ char str[100];
+ while(printf("> "), fgets(str, 100, stdin), !feof(stdin)) {
+ if (socket.write(str, strlen(str)) == -1) {
+ perror("send");
+ return EXIT_FAILURE;
+ }
+
+ int t;
+ if ((t = socket.read(str, 100)) > 0) {
+ str[t] = '\0';
+ printf("echo> %s", str);
+ } else {
+ if (t < 0)
+ perror("recv");
+ else
+ printf("Server closed connection.\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
diff --git a/tests/auto/qlocalsocket/example/example.pro b/tests/auto/qlocalsocket/example/example.pro
new file mode 100644
index 0000000000..8c678cd05a
--- /dev/null
+++ b/tests/auto/qlocalsocket/example/example.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = client server
+
diff --git a/tests/auto/qlocalsocket/example/server/main.cpp b/tests/auto/qlocalsocket/example/server/main.cpp
new file mode 100644
index 0000000000..03204709bc
--- /dev/null
+++ b/tests/auto/qlocalsocket/example/server/main.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $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 "qlocalserver.h"
+#include "qlocalsocket.h"
+
+#include <qcoreapplication.h>
+#include <qdebug.h>
+
+class EchoServer : public QLocalServer
+{
+public:
+ void incomingConnection(int socketDescriptor) {
+ QLocalServer::incomingConnection(socketDescriptor);
+ QLocalSocket *socket = nextPendingConnection();
+ socket->open(QIODevice::ReadWrite);
+
+ qDebug() << "server connection";
+
+ do {
+ const int Timeout = 5 * 1000;
+ while (!socket->canReadLine()) {
+ if (!socket->waitForReadyRead(Timeout)) {
+ return;
+ }
+ }
+ char str[100];
+ int n = socket->readLine(str, 100);
+ if (n < 0) {
+ perror("recv");
+ break;
+ }
+ if (n == 0)
+ break;
+ qDebug() << "Read" << str;
+ if ("exit" == str)
+ qApp->quit();
+
+ if (socket->write(str, 100) < 0) {
+ perror("send");
+ break;
+ }
+ } while (true);
+ }
+};
+
+#define SOCK_PATH "echo_socket"
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication application(argc, argv);
+
+ EchoServer echoServer;
+ echoServer.listen(SOCK_PATH);
+
+ return application.exec();
+}
+
diff --git a/tests/auto/qlocalsocket/example/server/server.pro b/tests/auto/qlocalsocket/example/server/server.pro
new file mode 100644
index 0000000000..bfd14d2bb7
--- /dev/null
+++ b/tests/auto/qlocalsocket/example/server/server.pro
@@ -0,0 +1,13 @@
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+
+CONFIG += console
+
+QT = core network
+
+# Input
+SOURCES += main.cpp
+
+
diff --git a/tests/auto/qlocalsocket/lackey/lackey.pro b/tests/auto/qlocalsocket/lackey/lackey.pro
new file mode 100644
index 0000000000..8182394dd3
--- /dev/null
+++ b/tests/auto/qlocalsocket/lackey/lackey.pro
@@ -0,0 +1,20 @@
+#include(../src/src.pri)
+
+QT = core script network
+
+requires(contains(QT_CONFIG,script))
+
+CONFIG += qtestlib
+
+DESTDIR = ./
+
+win32: CONFIG += console
+mac:CONFIG -= app_bundle
+
+DEFINES += QLOCALSERVER_DEBUG
+DEFINES += QLOCALSOCKET_DEBUG
+
+SOURCES += main.cpp
+TARGET = lackey
+
+symbian:TARGET.CAPABILITY = ALL -TCB \ No newline at end of file
diff --git a/tests/auto/qlocalsocket/lackey/main.cpp b/tests/auto/qlocalsocket/lackey/main.cpp
new file mode 100644
index 0000000000..08320c1075
--- /dev/null
+++ b/tests/auto/qlocalsocket/lackey/main.cpp
@@ -0,0 +1,296 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $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 <qscriptengine.h>
+ #include <QFile>
+#include <QTest>
+
+#include <qlocalsocket.h>
+#include <qlocalserver.h>
+
+class QScriptLocalSocket : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString serverName WRITE connectToServer READ serverName)
+
+public:
+ QScriptLocalSocket(QObject *parent = 0) : QObject(parent)
+ {
+ lc = new QLocalSocket(this);
+ }
+
+public slots:
+ QString serverName()
+ {
+ return lc->serverName();
+ }
+
+ void connectToServer(const QString &name) {
+ lc->connectToServer(name);
+ }
+
+ void sleep(int x) const
+ {
+ QTest::qSleep(x);
+ }
+
+ bool isConnected() {
+ return (lc->state() == QLocalSocket::ConnectedState);
+ }
+
+ void open() {
+ lc->open(QIODevice::ReadWrite);
+ }
+
+ bool waitForConnected() {
+ return lc->waitForConnected(100000);
+ }
+ void waitForReadyRead() {
+ lc->waitForReadyRead();
+ }
+
+ void write(const QString &string) {
+ QTextStream out(lc);
+ out << string << endl;
+ }
+
+ bool waitForBytesWritten(int t = 3000) {
+ return lc->waitForBytesWritten(t);
+ }
+
+ QString readLine() {
+ QTextStream in(lc);
+ return in.readLine();
+ }
+
+ QString errorString() {
+ return lc->errorString();
+ }
+
+ void close() {
+ lc->close();
+ }
+
+public:
+ QLocalSocket *lc;
+};
+
+class QScriptLocalServer : public QLocalServer
+{
+ Q_OBJECT
+ Q_PROPERTY(int maxPendingConnections WRITE setMaxPendingConnections READ maxPendingConnections)
+ Q_PROPERTY(QString name WRITE listen READ serverName)
+ Q_PROPERTY(bool listening READ isListening)
+
+public:
+ QScriptLocalServer(QObject *parent = 0) : QLocalServer(parent)
+ {
+ }
+
+public slots:
+ bool listen(const QString &name) {
+ if (!QLocalServer::listen(name)) {
+ if (serverError() == QAbstractSocket::AddressInUseError) {
+ QFile::remove(serverName());
+ return QLocalServer::listen(name);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ QScriptLocalSocket *nextConnection() {
+ QLocalSocket *other = nextPendingConnection();
+ QScriptLocalSocket *s = new QScriptLocalSocket(this);
+ delete s->lc;
+ s->lc = other;
+ return s;
+ }
+
+ bool waitForNewConnection() {
+ return QLocalServer::waitForNewConnection(30000);
+ }
+
+ QString errorString() {
+ return QLocalServer::errorString();
+ }
+
+
+};
+
+template <typename T>
+static QScriptValue _q_ScriptValueFromQObject(QScriptEngine *engine, T* const &in)
+{
+ return engine->newQObject(in);
+}
+template <typename T>
+static void _q_ScriptValueToQObject(const QScriptValue &v, T* &out)
+{ out = qobject_cast<T*>(v.toQObject());
+}
+template <typename T>
+static int _q_ScriptRegisterQObjectMetaType(QScriptEngine *engine, const QScriptValue &prototype)
+{
+ return qScriptRegisterMetaType<T*>(engine, _q_ScriptValueFromQObject<T>, _q_ScriptValueToQObject<T>, prototype);
+}
+
+QT_BEGIN_NAMESPACE
+Q_SCRIPT_DECLARE_QMETAOBJECT(QScriptLocalSocket, QObject*);
+Q_SCRIPT_DECLARE_QMETAOBJECT(QScriptLocalServer, QObject*);
+QT_END_NAMESPACE
+
+static void interactive(QScriptEngine &eng)
+{
+ QTextStream qin(stdin, QFile::ReadOnly);
+
+ const char *qscript_prompt = "qs> ";
+ const char *dot_prompt = ".... ";
+ const char *prompt = qscript_prompt;
+
+ QString code;
+
+ forever {
+ QString line;
+
+ printf("%s", prompt);
+ fflush(stdout);
+
+ line = qin.readLine();
+ if (line.isNull())
+ break;
+
+ code += line;
+ code += QLatin1Char('\n');
+
+ if (line.trimmed().isEmpty()) {
+ continue;
+
+ } else if (! eng.canEvaluate(code)) {
+ prompt = dot_prompt;
+
+ } else {
+ QScriptValue result = eng.evaluate(code);
+ code.clear();
+ prompt = qscript_prompt;
+ if (!result.isUndefined())
+ fprintf(stderr, "%s\n", qPrintable(result.toString()));
+ }
+ }
+}
+Q_DECLARE_METATYPE(QScriptLocalSocket*)
+Q_DECLARE_METATYPE(QScriptLocalServer*)
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+ QScriptEngine eng;
+ QScriptValue globalObject = eng.globalObject();
+
+ _q_ScriptRegisterQObjectMetaType<QScriptLocalServer>(&eng, QScriptValue());
+
+ QScriptValue lss = qScriptValueFromQMetaObject<QScriptLocalServer>(&eng);
+ eng.globalObject().setProperty("QScriptLocalServer", lss);
+
+ _q_ScriptRegisterQObjectMetaType<QScriptLocalSocket>(&eng, QScriptValue());
+
+ QScriptValue lsc = qScriptValueFromQMetaObject<QScriptLocalSocket>(&eng);
+ eng.globalObject().setProperty("QScriptLocalSocket", lsc);
+
+ if (! *++argv) {
+ interactive(eng);
+ return EXIT_SUCCESS;
+ }
+
+ QStringList arguments;
+ for (int i = 0; i < argc - 1; ++i)
+ arguments << QString::fromLocal8Bit(argv[i]);
+
+ while (!arguments.isEmpty()) {
+ QString fn = arguments.takeFirst();
+
+ if (fn == QLatin1String("-i")) {
+ interactive(eng);
+ break;
+ }
+
+ QString contents;
+
+ if (fn == QLatin1String("-")) {
+ QTextStream stream(stdin, QFile::ReadOnly);
+ contents = stream.readAll();
+ } else {
+ QFile file(fn);
+ if (!file.exists()) {
+ fprintf(stderr, "%s doesn't exists\n", qPrintable(fn));
+ return EXIT_FAILURE;
+ }
+ if (file.open(QFile::ReadOnly)) {
+ QTextStream stream(&file);
+ contents = stream.readAll();
+ file.close();
+ }
+ }
+
+ if (contents.isEmpty())
+ continue;
+
+ if (contents[0] == '#') {
+ contents.prepend("//");
+ QScriptValue args = eng.newArray();
+ args.setProperty("0", QScriptValue(&eng, fn));
+ int i = 1;
+ while (!arguments.isEmpty())
+ args.setProperty(i++, QScriptValue(&eng, arguments.takeFirst()));
+ eng.currentContext()->activationObject().setProperty("args", args);
+ }
+ QScriptValue r = eng.evaluate(contents);
+ if (eng.hasUncaughtException()) {
+ int line = eng.uncaughtExceptionLineNumber();
+ fprintf(stderr, "%d: %s\n\t%s\n\n", line, qPrintable(fn), qPrintable(r.toString()));
+ return EXIT_FAILURE;
+ }
+ if (r.isNumber())
+ return r.toInt32();
+ }
+
+ return EXIT_SUCCESS;
+}
+
+#include "main.moc"
diff --git a/tests/auto/qlocalsocket/lackey/scripts/client.js b/tests/auto/qlocalsocket/lackey/scripts/client.js
new file mode 100755
index 0000000000..76cc0b97ad
--- /dev/null
+++ b/tests/auto/qlocalsocket/lackey/scripts/client.js
@@ -0,0 +1,35 @@
+#/bin/qscript
+function QVERIFY(x, socket) {
+ if (!(x)) {
+ throw(socket.errorString());
+ }
+}
+
+var socket = new QScriptLocalSocket;
+var tries = 0;
+do {
+ socket.serverName = "qlocalsocket_autotest";
+ if ((socket.errorString() != "QLocalSocket::connectToServer: Invalid name")
+ && (socket.errorString() != "QLocalSocket::connectToServer: Connection refused"))
+ break;
+ socket.sleep(1);
+ ++tries;
+ print("isConnected:", socket.isConnected());
+} while ((socket.errorString() == "QLocalSocket::connectToServer: Invalid name"
+ || (socket.errorString() == "QlocalSocket::connectToServer: Connection refused"))
+ && tries < 5000);
+if (tries == 5000) {
+ print("too many tries, exiting");
+} else {
+socket.waitForConnected();
+//print("isConnected:", socket.isConnected());
+if (!socket.isConnected())
+ print("Not Connected:", socket.errorString());
+socket.waitForReadyRead();
+var text = socket.readLine();
+var testLine = "test";
+QVERIFY((text == testLine), socket);
+QVERIFY((socket.errorString() == "Unknown error"), socket);
+socket.close();
+//print("client: exiting", text);
+}
diff --git a/tests/auto/qlocalsocket/lackey/scripts/server.js b/tests/auto/qlocalsocket/lackey/scripts/server.js
new file mode 100644
index 0000000000..98a83bc9dd
--- /dev/null
+++ b/tests/auto/qlocalsocket/lackey/scripts/server.js
@@ -0,0 +1,19 @@
+#/bin/qscript
+function QVERIFY(x, server) {
+ if (!(x)) {
+ throw(server.errorString());
+ }
+}
+var server = new QScriptLocalServer;
+QVERIFY(server.listen("qlocalsocket_autotest"), server);
+var done = args[1];
+var testLine = "test";
+while (done > 0) {
+ QVERIFY(server.waitForNewConnection(), server);
+ var serverSocket = server.nextConnection();
+ serverSocket.write(testLine);
+ QVERIFY(serverSocket.waitForBytesWritten(), serverSocket);
+ QVERIFY(serverSocket.errorString() == ""
+ ||serverSocket.errorString() == "Unknown error", serverSocket);
+ --done;
+}
diff --git a/tests/auto/qlocalsocket/qlocalsocket.pro b/tests/auto/qlocalsocket/qlocalsocket.pro
new file mode 100644
index 0000000000..3911a64936
--- /dev/null
+++ b/tests/auto/qlocalsocket/qlocalsocket.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+SUBDIRS = lackey test
+!wince*:!symbian: SUBDIRS += example
+symbian: TARGET.CAPABILITY = NetworkServices
diff --git a/tests/auto/qlocalsocket/test/test.pro b/tests/auto/qlocalsocket/test/test.pro
new file mode 100644
index 0000000000..b2755b5411
--- /dev/null
+++ b/tests/auto/qlocalsocket/test/test.pro
@@ -0,0 +1,50 @@
+load(qttest_p4)
+
+DEFINES += QLOCALSERVER_DEBUG
+DEFINES += QLOCALSOCKET_DEBUG
+
+symbian {
+ # nothing
+} else:wince* {
+ DEFINES += QT_LOCALSOCKET_TCP
+ DEFINES += SRCDIR=\\\"../\\\"
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD/../\\\"
+}
+
+QT = core network
+
+SOURCES += ../tst_qlocalsocket.cpp
+
+TARGET = tst_qlocalsocket
+CONFIG(debug_and_release) {
+ CONFIG(debug, debug|release) {
+ DESTDIR = ../debug
+ } else {
+ DESTDIR = ../release
+ }
+} else {
+ DESTDIR = ..
+}
+
+wince* {
+ additionalFiles.files = ../lackey/lackey.exe
+ additionalFiles.path = lackey
+}
+
+symbian {
+ additionalFiles.files = lackey.exe
+ additionalFiles.path = \\sys\\bin
+ TARGET.UID3 = 0xE0340005
+ DEFINES += SYMBIAN_SRCDIR_UID=$$lower($$replace(TARGET.UID3,"0x",""))
+}
+
+wince*|symbian {
+ scriptFiles.files = ../lackey/scripts/*.js
+ scriptFiles.path = lackey/scripts
+ DEPLOYMENT += additionalFiles scriptFiles
+ QT += script # for easy deployment of QtScript
+
+ requires(contains(QT_CONFIG,script))
+}
+
diff --git a/tests/auto/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/qlocalsocket/tst_qlocalsocket.cpp
new file mode 100644
index 0000000000..77a5574b9c
--- /dev/null
+++ b/tests/auto/qlocalsocket/tst_qlocalsocket.cpp
@@ -0,0 +1,1120 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $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 <qtextstream.h>
+#include <QtNetwork/qlocalsocket.h>
+#include <QtNetwork/qlocalserver.h>
+#include "../../shared/util.h"
+
+#ifdef Q_OS_SYMBIAN
+ #include <unistd.h>
+#endif
+//TESTED_CLASS=QLocalServer, QLocalSocket
+//TESTED_FILES=network/socket/qlocalserver.cpp network/socket/qlocalsocket.cpp
+#ifdef Q_OS_SYMBIAN
+ #define STRINGIFY(x) #x
+ #define TOSTRING(x) STRINGIFY(x)
+ #define SRCDIR "C:/Private/" TOSTRING(SYMBIAN_SRCDIR_UID) "/"
+#endif
+Q_DECLARE_METATYPE(QLocalSocket::LocalSocketError)
+Q_DECLARE_METATYPE(QLocalSocket::LocalSocketState)
+
+class tst_QLocalSocket : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QLocalSocket();
+ virtual ~tst_QLocalSocket();
+
+public Q_SLOTS:
+ void init();
+ void cleanup();
+
+private slots:
+ // basics
+ void server_basic();
+ void server_connectionsCount();
+ void socket_basic();
+
+ void listen_data();
+ void listen();
+
+ void listenAndConnect_data();
+ void listenAndConnect();
+
+ void sendData_data();
+ void sendData();
+
+ void readBufferOverflow();
+
+ void fullPath();
+
+ void hitMaximumConnections_data();
+ void hitMaximumConnections();
+
+ void setSocketDescriptor();
+
+ void threadedConnection_data();
+ void threadedConnection();
+
+ void processConnection_data();
+ void processConnection();
+
+ void longPath();
+ void waitForDisconnect();
+ void waitForDisconnectByServer();
+
+ void removeServer();
+
+ void recycleServer();
+
+ void multiConnect();
+ void writeOnlySocket();
+ void writeToClientAndDisconnect();
+ void debug();
+ void bytesWrittenSignal();
+ void syncDisconnectNotify();
+ void asyncDisconnectNotify();
+
+#ifdef Q_OS_SYMBIAN
+private:
+ void unlink(QString serverName);
+#endif
+};
+
+tst_QLocalSocket::tst_QLocalSocket()
+{
+ if (!QFile::exists("lackey/lackey"
+#ifdef Q_OS_WIN
+ ".exe"
+#endif
+ ))
+ qWarning() << "lackey executable doesn't exists!";
+}
+
+tst_QLocalSocket::~tst_QLocalSocket()
+{
+}
+
+void tst_QLocalSocket::init()
+{
+ qRegisterMetaType<QLocalSocket::LocalSocketState>("QLocalSocket::LocalSocketState");
+ qRegisterMetaType<QLocalSocket::LocalSocketError>("QLocalSocket::LocalSocketError");
+}
+
+void tst_QLocalSocket::cleanup()
+{
+}
+
+class LocalServer : public QLocalServer
+{
+ Q_OBJECT
+
+public:
+ LocalServer() : QLocalServer()
+ {
+ connect(this, SIGNAL(newConnection()), this, SLOT(slotNewConnection()));
+ }
+
+ bool listen(const QString &name)
+ {
+ removeServer(name);
+ return QLocalServer::listen(name);
+ }
+
+ QList<int> hits;
+
+protected:
+ void incomingConnection(quintptr socketDescriptor)
+ {
+ hits.append(socketDescriptor);
+ QLocalServer::incomingConnection(socketDescriptor);
+ }
+
+private slots:
+ void slotNewConnection() {
+ QVERIFY(!hits.isEmpty());
+ QVERIFY(hasPendingConnections());
+ }
+};
+
+class LocalSocket : public QLocalSocket
+{
+ Q_OBJECT
+
+public:
+ LocalSocket(QObject *parent = 0) : QLocalSocket(parent)
+ {
+ connect(this, SIGNAL(connected()),
+ this, SLOT(slotConnected()));
+ connect(this, SIGNAL(disconnected()),
+ this, SLOT(slotDisconnected()));
+ connect(this, SIGNAL(error(QLocalSocket::LocalSocketError)),
+ this, SLOT(slotError(QLocalSocket::LocalSocketError)));
+ connect(this, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)),
+ this, SLOT(slotStateChanged(QLocalSocket::LocalSocketState)));
+ connect(this, SIGNAL(readyRead()),
+ this, SLOT(slotReadyRead()));
+ }
+
+private slots:
+ void slotConnected()
+ {
+ QCOMPARE(state(), QLocalSocket::ConnectedState);
+ }
+ void slotDisconnected()
+ {
+ QCOMPARE(state(), QLocalSocket::UnconnectedState);
+ }
+ void slotError(QLocalSocket::LocalSocketError newError)
+ {
+ QVERIFY(errorString() != "Unknown error");
+ QCOMPARE(error(), newError);
+ }
+ void slotStateChanged(QLocalSocket::LocalSocketState newState)
+ {
+ QCOMPARE(state(), newState);
+ }
+ void slotReadyRead()
+ {
+ QVERIFY(bytesAvailable() > 0);
+ }
+};
+
+// basic test make sure no segfaults and check default values
+void tst_QLocalSocket::server_basic()
+{
+ LocalServer server;
+ QSignalSpy spyNewConnection(&server, SIGNAL(newConnection()));
+ server.close();
+ QCOMPARE(server.errorString(), QString());
+ QCOMPARE(server.hasPendingConnections(), false);
+ QCOMPARE(server.isListening(), false);
+ QCOMPARE(server.maxPendingConnections(), 30);
+ QCOMPARE(server.nextPendingConnection(), (QLocalSocket*)0);
+ QCOMPARE(server.serverName(), QString());
+ QCOMPARE(server.fullServerName(), QString());
+ QCOMPARE(server.serverError(), QAbstractSocket::UnknownSocketError);
+ server.setMaxPendingConnections(20);
+ bool timedOut = true;
+ QCOMPARE(server.waitForNewConnection(3000, &timedOut), false);
+ QVERIFY(!timedOut);
+ QCOMPARE(server.listen(QString()), false);
+
+ QCOMPARE(server.hits.count(), 0);
+ QCOMPARE(spyNewConnection.count(), 0);
+}
+
+void tst_QLocalSocket::server_connectionsCount()
+{
+ LocalServer server;
+ server.setMaxPendingConnections(10);
+ QCOMPARE(server.maxPendingConnections(), 10);
+}
+
+// basic test make sure no segfaults and check default values
+void tst_QLocalSocket::socket_basic()
+{
+ LocalSocket socket;
+ QSignalSpy spyConnected(&socket, SIGNAL(connected()));
+ QSignalSpy spyDisconnected(&socket, SIGNAL(disconnected()));
+ QSignalSpy spyError(&socket, SIGNAL(error(QLocalSocket::LocalSocketError)));
+ QSignalSpy spyStateChanged(&socket, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)));
+ QSignalSpy spyReadyRead(&socket, SIGNAL(readyRead()));
+
+ QCOMPARE(socket.serverName(), QString());
+ QCOMPARE(socket.fullServerName(), QString());
+ socket.abort();
+ QVERIFY(socket.bytesAvailable() == 0);
+ QVERIFY(socket.bytesToWrite() == 0);
+ QCOMPARE(socket.canReadLine(), false);
+ socket.close();
+ socket.disconnectFromServer();
+ QCOMPARE(QLocalSocket::UnknownSocketError, socket.error());
+ QVERIFY(socket.errorString() != QString());
+ QCOMPARE(socket.flush(), false);
+ QCOMPARE(socket.isValid(), false);
+ QVERIFY(socket.readBufferSize() == 0);
+ socket.setReadBufferSize(0);
+ //QCOMPARE(socket.socketDescriptor(), -1);
+ QCOMPARE(socket.state(), QLocalSocket::UnconnectedState);
+ QCOMPARE(socket.waitForConnected(0), false);
+ QCOMPARE(socket.waitForDisconnected(0), false);
+ QCOMPARE(socket.waitForReadyRead(0), false);
+
+ QCOMPARE(spyConnected.count(), 0);
+ QCOMPARE(spyDisconnected.count(), 0);
+ QCOMPARE(spyError.count(), 0);
+ QCOMPARE(spyStateChanged.count(), 0);
+ QCOMPARE(spyReadyRead.count(), 0);
+}
+
+void tst_QLocalSocket::listen_data()
+{
+ QTest::addColumn<QString>("name");
+ QTest::addColumn<bool>("canListen");
+ QTest::addColumn<bool>("close");
+ QTest::newRow("null") << QString() << false << false;
+ QTest::newRow("tst_localsocket") << "tst_localsocket" << true << true;
+ QTest::newRow("tst_localsocket") << "tst_localsocket" << true << false;
+}
+
+// start a server that listens, but don't connect a socket, make sure everything is in order
+void tst_QLocalSocket::listen()
+{
+ LocalServer server;
+ QSignalSpy spyNewConnection(&server, SIGNAL(newConnection()));
+
+ QFETCH(QString, name);
+#ifdef Q_OS_SYMBIAN
+ unlink(name);
+#endif
+ QFETCH(bool, canListen);
+ QFETCH(bool, close);
+ QVERIFY2((server.listen(name) == canListen), server.errorString().toLatin1().constData());
+
+ // test listening
+ QCOMPARE(server.serverName(), name);
+ QVERIFY(server.fullServerName().contains(name));
+ QCOMPARE(server.isListening(), canListen);
+ QCOMPARE(server.hasPendingConnections(), false);
+ QCOMPARE(server.nextPendingConnection(), (QLocalSocket*)0);
+ QCOMPARE(server.hits.count(), 0);
+ QCOMPARE(spyNewConnection.count(), 0);
+ if (canListen) {
+ QVERIFY(server.errorString() == QString());
+ QCOMPARE(server.serverError(), QAbstractSocket::UnknownSocketError);
+ // already isListening
+ QVERIFY(!server.listen(name));
+ } else {
+ QVERIFY(server.errorString() != QString());
+ QCOMPARE(server.serverError(), QAbstractSocket::HostNotFoundError);
+ }
+ QCOMPARE(server.maxPendingConnections(), 30);
+ bool timedOut = false;
+ QCOMPARE(server.waitForNewConnection(3000, &timedOut), false);
+ QCOMPARE(timedOut, canListen);
+ if (close)
+ server.close();
+}
+
+void tst_QLocalSocket::listenAndConnect_data()
+{
+ QTest::addColumn<QString>("name");
+ QTest::addColumn<bool>("canListen");
+ QTest::addColumn<int>("connections");
+ for (int i = 0; i < 3; ++i) {
+ int connections = i;
+ if (i == 2)
+ connections = 5;
+ QTest::newRow(QString("null %1").arg(i).toLatin1()) << QString() << false << connections;
+ QTest::newRow(QString("tst_localsocket %1").arg(i).toLatin1()) << "tst_localsocket" << true << connections;
+ }
+}
+
+void tst_QLocalSocket::listenAndConnect()
+{
+ LocalServer server;
+ QSignalSpy spyNewConnection(&server, SIGNAL(newConnection()));
+
+ QFETCH(QString, name);
+ QFETCH(bool, canListen);
+#ifdef Q_OS_SYMBIAN
+ unlink(name);
+#endif
+ QCOMPARE(server.listen(name), canListen);
+ QTest::qWait(1000);
+ //QVERIFY(!server.errorString().isEmpty());
+ QCOMPARE(server.serverError(),
+ canListen ? QAbstractSocket::UnknownSocketError : QAbstractSocket::HostNotFoundError);
+
+ // test creating connection(s)
+ QFETCH(int, connections);
+ QList<QLocalSocket*> sockets;
+ for (int i = 0; i < connections; ++i) {
+ LocalSocket *socket = new LocalSocket;
+
+ QSignalSpy spyConnected(socket, SIGNAL(connected()));
+ QSignalSpy spyDisconnected(socket, SIGNAL(disconnected()));
+ QSignalSpy spyError(socket, SIGNAL(error(QLocalSocket::LocalSocketError)));
+ QSignalSpy spyStateChanged(socket, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)));
+ QSignalSpy spyReadyRead(socket, SIGNAL(readyRead()));
+
+ socket->connectToServer(name);
+#if defined(QT_LOCALSOCKET_TCP)
+ QTest::qWait(250);
+#endif
+
+ QCOMPARE(socket->serverName(), name);
+ QVERIFY(socket->fullServerName().contains(name));
+ sockets.append(socket);
+ if (canListen) {
+ QVERIFY(socket->waitForConnected());
+ QVERIFY(socket->isValid());
+ QCOMPARE(socket->errorString(), QString("Unknown error"));
+ QCOMPARE(socket->error(), QLocalSocket::UnknownSocketError);
+ QCOMPARE(socket->state(), QLocalSocket::ConnectedState);
+ //QVERIFY(socket->socketDescriptor() != -1);
+ QCOMPARE(spyError.count(), 0);
+ } else {
+ QVERIFY(socket->errorString() != QString());
+ QVERIFY(socket->error() != QLocalSocket::UnknownSocketError);
+ QCOMPARE(socket->state(), QLocalSocket::UnconnectedState);
+ //QVERIFY(socket->socketDescriptor() == -1);
+ QCOMPARE(qVariantValue<QLocalSocket::LocalSocketError>(spyError.first()[0]),
+ QLocalSocket::ServerNotFoundError);
+ }
+
+ QVERIFY(socket->bytesAvailable() == 0);
+ QVERIFY(socket->bytesToWrite() == 0);
+ QCOMPARE(socket->canReadLine(), false);
+ QCOMPARE(socket->flush(), false);
+ QCOMPARE(socket->isValid(), canListen);
+ QCOMPARE(socket->readBufferSize(), (qint64)0);
+ QCOMPARE(socket->waitForConnected(0), canListen);
+ QCOMPARE(socket->waitForReadyRead(0), false);
+
+ QTRY_COMPARE(spyConnected.count(), canListen ? 1 : 0);
+ QCOMPARE(spyDisconnected.count(), 0);
+
+ // error signals
+ QVERIFY(spyError.count() >= 0);
+ if (canListen) {
+ if (spyError.count() > 0)
+ QCOMPARE(qVariantValue<QLocalSocket::LocalSocketError>(spyError.first()[0]),
+ QLocalSocket::SocketTimeoutError);
+ } else {
+ QCOMPARE(qVariantValue<QLocalSocket::LocalSocketError>(spyError.first()[0]),
+ QLocalSocket::ServerNotFoundError);
+ }
+
+ // Check first and last state
+ QCOMPARE(qVariantValue<QLocalSocket::LocalSocketState>(spyStateChanged.first()[0]),
+ QLocalSocket::ConnectingState);
+#if 0
+ for (int j = 0; j < spyStateChanged.count(); ++j) {
+ QLocalSocket::LocalSocketState s;
+ s = qVariantValue<QLocalSocket::LocalSocketState>(spyStateChanged.at(j).at(0));
+ qDebug() << s;
+ }
+#endif
+ if (canListen)
+ QCOMPARE(qVariantValue<QLocalSocket::LocalSocketState>(spyStateChanged.last()[0]),
+ QLocalSocket::ConnectedState);
+ QCOMPARE(spyStateChanged.count(), 2);
+ QCOMPARE(spyReadyRead.count(), 0);
+
+ bool timedOut = true;
+ QCOMPARE(server.waitForNewConnection(3000, &timedOut), canListen);
+ QVERIFY(!timedOut);
+ QCOMPARE(server.hasPendingConnections(), canListen);
+ QCOMPARE(server.isListening(), canListen);
+ // NOTE: socket disconnecting is not tested here
+
+ // server checks post connection
+ if (canListen) {
+ QCOMPARE(server.serverName(), name);
+ QVERIFY(server.fullServerName().contains(name));
+ QVERIFY(server.nextPendingConnection() != (QLocalSocket*)0);
+ QTRY_COMPARE(server.hits.count(), i + 1);
+ QCOMPARE(spyNewConnection.count(), i + 1);
+ QVERIFY(server.errorString() == QString());
+ QCOMPARE(server.serverError(), QAbstractSocket::UnknownSocketError);
+ } else {
+ QVERIFY(server.serverName().isEmpty());
+ QVERIFY(server.fullServerName().isEmpty());
+ QVERIFY(server.nextPendingConnection() == (QLocalSocket*)0);
+ QCOMPARE(spyNewConnection.count(), 0);
+ QCOMPARE(server.hits.count(), 0);
+ QVERIFY(server.errorString() != QString());
+ QCOMPARE(server.serverError(), QAbstractSocket::HostNotFoundError);
+ }
+ }
+ qDeleteAll(sockets.begin(), sockets.end());
+
+ server.close();
+
+ QCOMPARE(server.hits.count(), (canListen ? connections : 0));
+ QCOMPARE(spyNewConnection.count(), (canListen ? connections : 0));
+}
+
+void tst_QLocalSocket::sendData_data()
+{
+ listenAndConnect_data();
+}
+
+void tst_QLocalSocket::sendData()
+{
+ QFETCH(QString, name);
+#ifdef Q_OS_SYMBIAN
+ unlink(name);
+#endif
+ QFETCH(bool, canListen);
+
+ LocalServer server;
+ QSignalSpy spy(&server, SIGNAL(newConnection()));
+
+ QCOMPARE(server.listen(name), canListen);
+
+ LocalSocket socket;
+ QSignalSpy spyConnected(&socket, SIGNAL(connected()));
+ QSignalSpy spyDisconnected(&socket, SIGNAL(disconnected()));
+ QSignalSpy spyError(&socket, SIGNAL(error(QLocalSocket::LocalSocketError)));
+ QSignalSpy spyStateChanged(&socket, SIGNAL(stateChanged(QLocalSocket::LocalSocketState)));
+ QSignalSpy spyReadyRead(&socket, SIGNAL(readyRead()));
+
+ // test creating a connection
+ socket.connectToServer(name);
+ bool timedOut = true;
+
+ QCOMPARE(server.waitForNewConnection(3000, &timedOut), canListen);
+
+#if defined(QT_LOCALSOCKET_TCP)
+ QTest::qWait(250);
+#endif
+ QVERIFY(!timedOut);
+ QCOMPARE(spyConnected.count(), canListen ? 1 : 0);
+ QCOMPARE(socket.state(), canListen ? QLocalSocket::ConnectedState : QLocalSocket::UnconnectedState);
+
+ // test sending/receiving data
+ if (server.hasPendingConnections()) {
+ QString testLine = "test";
+#ifdef Q_OS_SYMBIAN
+ for (int i = 0; i < 25 * 1024; ++i)
+#else
+ for (int i = 0; i < 50000; ++i)
+#endif
+ testLine += "a";
+ QLocalSocket *serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+ QCOMPARE(serverSocket->state(), QLocalSocket::ConnectedState);
+ QTextStream out(serverSocket);
+ QTextStream in(&socket);
+ out << testLine << endl;
+ bool wrote = serverSocket->waitForBytesWritten(3000);
+
+ if (!socket.canReadLine())
+ QVERIFY(socket.waitForReadyRead());
+
+ QVERIFY(socket.bytesAvailable() >= 0);
+ QCOMPARE(socket.bytesToWrite(), (qint64)0);
+ QCOMPARE(socket.flush(), false);
+ QCOMPARE(socket.isValid(), canListen);
+ QCOMPARE(socket.readBufferSize(), (qint64)0);
+ QCOMPARE(spyReadyRead.count(), 1);
+
+ QVERIFY(testLine.startsWith(in.readLine()));
+
+ QVERIFY(wrote || serverSocket->waitForBytesWritten(1000));
+
+ QCOMPARE(serverSocket->errorString(), QString("Unknown error"));
+ QCOMPARE(socket.errorString(), QString("Unknown error"));
+ }
+
+ socket.disconnectFromServer();
+ QCOMPARE(spyConnected.count(), canListen ? 1 : 0);
+ QCOMPARE(spyDisconnected.count(), canListen ? 1 : 0);
+ QCOMPARE(spyError.count(), canListen ? 0 : 1);
+ QCOMPARE(spyStateChanged.count(), canListen ? 4 : 2);
+ QCOMPARE(spyReadyRead.count(), canListen ? 1 : 0);
+
+ server.close();
+
+ QCOMPARE(server.hits.count(), (canListen ? 1 : 0));
+ QCOMPARE(spy.count(), (canListen ? 1 : 0));
+}
+
+void tst_QLocalSocket::readBufferOverflow()
+{
+ const int readBufferSize = 128;
+ const int dataBufferSize = readBufferSize * 2;
+ const QString serverName = QLatin1String("myPreciousTestServer");
+ LocalServer server;
+ server.listen(serverName);
+ QVERIFY(server.isListening());
+
+ LocalSocket client;
+ client.setReadBufferSize(readBufferSize);
+ client.connectToServer(serverName);
+
+ bool timedOut = true;
+ QVERIFY(server.waitForNewConnection(3000, &timedOut));
+ QVERIFY(!timedOut);
+
+ QCOMPARE(client.state(), QLocalSocket::ConnectedState);
+ QVERIFY(server.hasPendingConnections());
+
+ QLocalSocket* serverSocket = server.nextPendingConnection();
+ char buffer[dataBufferSize];
+ memset(buffer, 0, dataBufferSize);
+ serverSocket->write(buffer, dataBufferSize);
+ serverSocket->waitForBytesWritten();
+
+ // wait until the first 128 bytes are ready to read
+ QVERIFY(client.waitForReadyRead());
+ QCOMPARE(client.read(buffer, readBufferSize), qint64(readBufferSize));
+ // wait until the second 128 bytes are ready to read
+ QVERIFY(client.waitForReadyRead());
+ QCOMPARE(client.read(buffer, readBufferSize), qint64(readBufferSize));
+ // no more bytes available
+ QVERIFY(client.bytesAvailable() == 0);
+}
+
+// QLocalSocket/Server can take a name or path, check that it works as expected
+void tst_QLocalSocket::fullPath()
+{
+ QLocalServer server;
+ QString name = "qlocalsocket_pathtest";
+#if defined(Q_OS_SYMBIAN)
+ QString path = "";
+#elif defined(QT_LOCALSOCKET_TCP)
+ QString path = "QLocalServer";
+#elif defined(Q_OS_WIN)
+ QString path = "\\\\.\\pipe\\";
+#else
+ QString path = "/tmp";
+#endif
+ QString serverName = path + '/' + name;
+ QVERIFY2(server.listen(serverName), server.errorString().toLatin1().constData());
+ QCOMPARE(server.serverName(), serverName);
+ QCOMPARE(server.fullServerName(), serverName);
+
+ LocalSocket socket;
+ socket.connectToServer(serverName);
+
+ QCOMPARE(socket.serverName(), serverName);
+ QCOMPARE(socket.fullServerName(), serverName);
+ socket.disconnectFromServer();
+#ifdef QT_LOCALSOCKET_TCP
+ QTest::qWait(250);
+#endif
+ QCOMPARE(socket.serverName(), QString());
+ QCOMPARE(socket.fullServerName(), QString());
+}
+
+void tst_QLocalSocket::hitMaximumConnections_data()
+{
+ QTest::addColumn<int>("max");
+ QTest::newRow("none") << 0;
+ QTest::newRow("1") << 1;
+ QTest::newRow("3") << 3;
+}
+
+void tst_QLocalSocket::hitMaximumConnections()
+{
+ QFETCH(int, max);
+ LocalServer server;
+ QString name = "tst_localsocket";
+#ifdef Q_OS_SYMBIAN
+ unlink(name);
+#endif
+ server.setMaxPendingConnections(max);
+ QVERIFY2(server.listen(name), server.errorString().toLatin1().constData());
+ int connections = server.maxPendingConnections() + 1;
+ QList<QLocalSocket*> sockets;
+ for (int i = 0; i < connections; ++i) {
+ LocalSocket *socket = new LocalSocket;
+ sockets.append(socket);
+ socket->connectToServer(name);
+ }
+ bool timedOut = true;
+ QVERIFY(server.waitForNewConnection(3000, &timedOut));
+ QVERIFY(!timedOut);
+ QVERIFY(server.hits.count() > 0);
+ qDeleteAll(sockets.begin(), sockets.end());
+}
+
+// check that state and mode are kept
+void tst_QLocalSocket::setSocketDescriptor()
+{
+ LocalSocket socket;
+ quintptr minusOne = -1;
+ socket.setSocketDescriptor(minusOne, QLocalSocket::ConnectingState, QIODevice::Append);
+ QCOMPARE(socket.socketDescriptor(), minusOne);
+ QCOMPARE(socket.state(), QLocalSocket::ConnectingState);
+ QVERIFY((socket.openMode() & QIODevice::Append) != 0);
+}
+
+class Client : public QThread
+{
+
+public:
+ void run()
+ {
+ QString testLine = "test";
+ LocalSocket socket;
+ QSignalSpy spyReadyRead(&socket, SIGNAL(readyRead()));
+ socket.connectToServer("qlocalsocket_threadtest");
+ QVERIFY(socket.waitForConnected(1000));
+
+ // We should *not* have this signal yet!
+ QCOMPARE(spyReadyRead.count(), 0);
+ socket.waitForReadyRead();
+ QCOMPARE(spyReadyRead.count(), 1);
+ QTextStream in(&socket);
+ QCOMPARE(in.readLine(), testLine);
+ socket.close();
+ }
+};
+
+class Server : public QThread
+{
+
+public:
+ int clients;
+ QMutex mutex;
+ QWaitCondition wc;
+ void run()
+ {
+ QString testLine = "test";
+ LocalServer server;
+ server.setMaxPendingConnections(10);
+ QVERIFY2(server.listen("qlocalsocket_threadtest"),
+ server.errorString().toLatin1().constData());
+ mutex.lock();
+ wc.wakeAll();
+ mutex.unlock();
+ int done = clients;
+ while (done > 0) {
+ bool timedOut = true;
+ QVERIFY(server.waitForNewConnection(7000, &timedOut));
+ QVERIFY(!timedOut);
+ QLocalSocket *serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+ QTextStream out(serverSocket);
+ out << testLine << endl;
+ QCOMPARE(serverSocket->state(), QLocalSocket::ConnectedState);
+ QVERIFY2(serverSocket->waitForBytesWritten(), serverSocket->errorString().toLatin1().constData());
+ QCOMPARE(serverSocket->errorString(), QString("Unknown error"));
+ --done;
+ delete serverSocket;
+ }
+ QCOMPARE(server.hits.count(), clients);
+ }
+};
+
+void tst_QLocalSocket::threadedConnection_data()
+{
+ QTest::addColumn<int>("threads");
+ QTest::newRow("1 client") << 1;
+ QTest::newRow("2 clients") << 2;
+ QTest::newRow("5 clients") << 5;
+#ifndef Q_OS_WINCE
+ QTest::newRow("10 clients") << 10;
+ QTest::newRow("20 clients") << 20;
+#endif
+}
+
+void tst_QLocalSocket::threadedConnection()
+{
+#ifdef Q_OS_SYMBIAN
+ unlink("qlocalsocket_threadtest");
+#endif
+
+ QFETCH(int, threads);
+ Server server;
+#if defined(Q_OS_SYMBIAN)
+ server.setStackSize(0x14000);
+#endif
+ server.clients = threads;
+ server.mutex.lock();
+ server.start();
+ server.wc.wait(&server.mutex);
+
+ QList<Client*> clients;
+ for (int i = 0; i < threads; ++i) {
+ clients.append(new Client());
+#if defined(Q_OS_SYMBIAN)
+ clients.last()->setStackSize(0x14000);
+#endif
+ clients.last()->start();
+ }
+
+ server.wait();
+ while (!clients.isEmpty()) {
+ QVERIFY(clients.first()->wait(3000));
+ delete clients.takeFirst();
+ }
+}
+
+void tst_QLocalSocket::processConnection_data()
+{
+ QTest::addColumn<int>("processes");
+ QTest::newRow("1 client") << 1;
+#ifndef Q_OS_WIN
+ QTest::newRow("2 clients") << 2;
+ QTest::newRow("5 clients") << 5;
+#endif
+ QTest::newRow("30 clients") << 30;
+}
+
+/*!
+ Create external processes that produce and consume.
+ */
+void tst_QLocalSocket::processConnection()
+{
+#if defined(QT_NO_PROCESS) || defined(Q_CC_NOKIAX86)
+ QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
+#else
+ QFETCH(int, processes);
+ QStringList serverArguments = QStringList() << SRCDIR "lackey/scripts/server.js" << QString::number(processes);
+ QProcess producer;
+ producer.setProcessChannelMode(QProcess::ForwardedChannels);
+#ifdef Q_WS_QWS
+ serverArguments << "-qws";
+#endif
+ QList<QProcess*> consumers;
+ producer.start("lackey/lackey", serverArguments);
+ QVERIFY(producer.waitForStarted(-1));
+ QTest::qWait(2000);
+ for (int i = 0; i < processes; ++i) {
+ QStringList arguments = QStringList() << SRCDIR "lackey/scripts/client.js";
+#ifdef Q_WS_QWS
+ arguments << "-qws";
+#endif
+ QProcess *p = new QProcess;
+ p->setProcessChannelMode(QProcess::ForwardedChannels);
+ consumers.append(p);
+ p->start("lackey/lackey", arguments);
+ }
+
+ while (!consumers.isEmpty()) {
+ consumers.first()->waitForFinished(20000);
+ QCOMPARE(consumers.first()->exitStatus(), QProcess::NormalExit);
+ QCOMPARE(consumers.first()->exitCode(), 0);
+ QProcess *consumer = consumers.takeFirst();
+ consumer->terminate();
+ delete consumer;
+ }
+ producer.waitForFinished(15000);
+#endif
+}
+
+void tst_QLocalSocket::longPath()
+{
+#ifndef Q_OS_WIN
+ QString name;
+ for (int i = 0; i < 256; ++i)
+ name += 'a';
+ LocalServer server;
+ QVERIFY(!server.listen(name));
+
+ LocalSocket socket;
+ socket.connectToServer(name);
+ QCOMPARE(socket.state(), QLocalSocket::UnconnectedState);
+#endif
+}
+
+void tst_QLocalSocket::waitForDisconnect()
+{
+ QString name = "tst_localsocket";
+#ifdef Q_OS_SYMBIAN
+ unlink(name);
+#endif
+ LocalServer server;
+ QVERIFY(server.listen(name));
+ LocalSocket socket;
+ socket.connectToServer(name);
+ QVERIFY(socket.waitForConnected(3000));
+ QVERIFY(server.waitForNewConnection(3000));
+ QLocalSocket *serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+ socket.disconnectFromServer();
+ QTime timer;
+ timer.start();
+ QVERIFY(serverSocket->waitForDisconnected(3000));
+ QVERIFY(timer.elapsed() < 2000);
+}
+
+void tst_QLocalSocket::waitForDisconnectByServer()
+{
+ QString name = "tst_localsocket";
+ LocalServer server;
+ QVERIFY(server.listen(name));
+ LocalSocket socket;
+ QSignalSpy spy(&socket, SIGNAL(disconnected()));
+ QVERIFY(spy.isValid());
+ socket.connectToServer(name);
+ QVERIFY(socket.waitForConnected(3000));
+ QVERIFY(server.waitForNewConnection(3000));
+ QLocalSocket *serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+ serverSocket->close();
+ QVERIFY(serverSocket->state() == QLocalSocket::UnconnectedState);
+ QVERIFY(socket.waitForDisconnected(3000));
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_QLocalSocket::removeServer()
+{
+ // this is a hostile takeover, but recovering from a crash results in the same
+ QLocalServer server, server2;
+ QVERIFY(QLocalServer::removeServer("cleanuptest"));
+ QVERIFY(server.listen("cleanuptest"));
+#ifndef Q_OS_WIN
+ // on Windows, there can be several sockets listening on the same pipe
+ // on Unix, there can only be one socket instance
+ QVERIFY(! server2.listen("cleanuptest"));
+#endif
+ QVERIFY(QLocalServer::removeServer("cleanuptest"));
+ QVERIFY(server2.listen("cleanuptest"));
+}
+
+void tst_QLocalSocket::recycleServer()
+{
+#ifdef Q_OS_SYMBIAN
+ unlink("recycletest1");
+#endif
+
+ QLocalServer server;
+ QLocalSocket client;
+
+ QVERIFY(server.listen("recycletest1"));
+ client.connectToServer("recycletest1");
+ QVERIFY(client.waitForConnected(201));
+ QVERIFY(server.waitForNewConnection(201));
+ QVERIFY(server.nextPendingConnection() != 0);
+
+ server.close();
+ client.disconnectFromServer();
+ qApp->processEvents();
+
+ QVERIFY(server.listen("recycletest2"));
+ client.connectToServer("recycletest2");
+ QVERIFY(client.waitForConnected(202));
+ QVERIFY(server.waitForNewConnection(202));
+ QVERIFY(server.nextPendingConnection() != 0);
+}
+
+void tst_QLocalSocket::multiConnect()
+{
+ QLocalServer server;
+ QLocalSocket client1;
+ QLocalSocket client2;
+ QLocalSocket client3;
+
+ QVERIFY(server.listen("multiconnect"));
+
+ client1.connectToServer("multiconnect");
+ client2.connectToServer("multiconnect");
+ client3.connectToServer("multiconnect");
+
+ QVERIFY(client1.waitForConnected(201));
+ QVERIFY(client2.waitForConnected(202));
+ QVERIFY(client3.waitForConnected(203));
+
+ QVERIFY(server.waitForNewConnection(201));
+ QVERIFY(server.nextPendingConnection() != 0);
+ QVERIFY(server.waitForNewConnection(202));
+ QVERIFY(server.nextPendingConnection() != 0);
+ QVERIFY(server.waitForNewConnection(203));
+ QVERIFY(server.nextPendingConnection() != 0);
+}
+
+void tst_QLocalSocket::writeOnlySocket()
+{
+ QLocalServer server;
+#ifdef Q_OS_SYMBIAN
+ unlink("writeOnlySocket");
+#endif
+ QVERIFY(server.listen("writeOnlySocket"));
+
+ QLocalSocket client;
+ client.connectToServer("writeOnlySocket", QIODevice::WriteOnly);
+ QVERIFY(client.waitForConnected());
+#if defined(Q_OS_SYMBIAN)
+ QTest::qWait(250);
+#endif
+ QVERIFY(server.waitForNewConnection(200));
+ QLocalSocket* serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+
+ QCOMPARE(client.bytesAvailable(), qint64(0));
+ QCOMPARE(client.state(), QLocalSocket::ConnectedState);
+}
+
+void tst_QLocalSocket::writeToClientAndDisconnect()
+{
+#ifdef Q_OS_SYMBIAN
+ unlink("writeAndDisconnectServer");
+#endif
+
+ QLocalServer server;
+ QLocalSocket client;
+ QSignalSpy readChannelFinishedSpy(&client, SIGNAL(readChannelFinished()));
+
+ QVERIFY(server.listen("writeAndDisconnectServer"));
+ client.connectToServer("writeAndDisconnectServer");
+ QVERIFY(client.waitForConnected(200));
+ QVERIFY(server.waitForNewConnection(200));
+ QLocalSocket* clientSocket = server.nextPendingConnection();
+ QVERIFY(clientSocket);
+
+ char buffer[100];
+ memset(buffer, 0, sizeof(buffer));
+ QCOMPARE(clientSocket->write(buffer, sizeof(buffer)), (qint64)sizeof(buffer));
+ clientSocket->waitForBytesWritten();
+ clientSocket->close();
+ server.close();
+
+ QTRY_COMPARE(readChannelFinishedSpy.count(), 1);
+ QCOMPARE(client.read(buffer, sizeof(buffer)), (qint64)sizeof(buffer));
+ client.waitForDisconnected();
+ QCOMPARE(client.state(), QLocalSocket::UnconnectedState);
+}
+
+void tst_QLocalSocket::debug()
+{
+ // Make sure this compiles
+ qDebug() << QLocalSocket::ConnectionRefusedError << QLocalSocket::UnconnectedState;
+}
+
+class WriteThread : public QThread
+{
+Q_OBJECT
+public:
+ void run() {
+ QLocalSocket socket;
+ socket.connectToServer("qlocalsocket_readyread");
+
+ if (!socket.waitForConnected(3000))
+ exec();
+ connect(&socket, SIGNAL(bytesWritten(qint64)),
+ this, SLOT(bytesWritten(qint64)), Qt::QueuedConnection);
+ socket.write("testing\n");
+ exec();
+ }
+public slots:
+ void bytesWritten(qint64) {
+ exit();
+ }
+
+private:
+};
+
+/*
+ Tests the emission of the bytesWritten(qint64)
+ signal.
+
+ Create a thread that will write to a socket.
+ If the bytesWritten(qint64) signal is generated,
+ the slot connected to it will exit the thread,
+ indicating test success.
+
+*/
+void tst_QLocalSocket::bytesWrittenSignal()
+{
+ QLocalServer server;
+ QVERIFY(server.listen("qlocalsocket_readyread"));
+ WriteThread writeThread;
+ writeThread.start();
+ bool timedOut = false;
+ QVERIFY(server.waitForNewConnection(3000, &timedOut));
+ QVERIFY(!timedOut);
+ QTest::qWait(2000);
+ QVERIFY(writeThread.wait(2000));
+}
+
+void tst_QLocalSocket::syncDisconnectNotify()
+{
+#ifdef Q_OS_SYMBIAN
+ unlink("syncDisconnectNotify");
+#endif
+
+ QLocalServer server;
+ QVERIFY(server.listen("syncDisconnectNotify"));
+ QLocalSocket client;
+ client.connectToServer("syncDisconnectNotify");
+ QVERIFY(server.waitForNewConnection());
+ QLocalSocket* serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+ delete serverSocket;
+ QCOMPARE(client.waitForReadyRead(), false);
+}
+
+void tst_QLocalSocket::asyncDisconnectNotify()
+{
+#ifdef Q_OS_SYMBIAN
+ unlink("asyncDisconnectNotify");
+#endif
+
+ QLocalServer server;
+ QVERIFY(server.listen("asyncDisconnectNotify"));
+ QLocalSocket client;
+ QSignalSpy disconnectedSpy(&client, SIGNAL(disconnected()));
+ client.connectToServer("asyncDisconnectNotify");
+ QVERIFY(server.waitForNewConnection());
+ QLocalSocket* serverSocket = server.nextPendingConnection();
+ QVERIFY(serverSocket);
+ delete serverSocket;
+ QTRY_VERIFY(!disconnectedSpy.isEmpty());
+}
+
+#ifdef Q_OS_SYMBIAN
+void tst_QLocalSocket::unlink(QString name)
+{
+ if(name.length() == 0)
+ return;
+
+ QString fullName;
+ // determine the full server path
+ if (name.startsWith(QLatin1Char('/'))) {
+ fullName = name;
+ } else {
+ fullName = QDir::cleanPath(QDir::tempPath());
+ fullName += QLatin1Char('/') + name;
+ fullName = QDir::toNativeSeparators(fullName);
+ }
+
+ int result = ::unlink(fullName.toUtf8().data());
+
+ if(result != 0) {
+ qWarning() << "Unlinking " << fullName << " failed with " << strerror(errno);
+ }
+}
+#endif
+QTEST_MAIN(tst_QLocalSocket)
+#include "tst_qlocalsocket.moc"
+