summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Christian <andrew.christian@nokia.com>2012-02-16 15:18:02 -0500
committerChris Craig <ext-chris.craig@nokia.com>2012-02-17 19:23:21 +0100
commit55db246f84514d42e211156c8e7fa28ff4d1b8d4 (patch)
tree2a3716276b992e3c21fc576c6855bc5cee741b53
parent7140c90c4c771f9e027b1922fea167ff102026a9 (diff)
Schema validation for remote socket protocol.
Change-Id: Ia4981187fb35edde82540042ff60688b8066f725 Reviewed-by: Chris Craig <ext-chris.craig@nokia.com>
-rw-r--r--schema/remote/inbound/set.json19
-rw-r--r--schema/remote/inbound/start.json9
-rw-r--r--schema/remote/inbound/stop.json9
-rw-r--r--schema/remote/inbound/write.json13
-rw-r--r--schema/remote/outbound/error.json10
-rw-r--r--schema/remote/outbound/finished.json10
-rw-r--r--schema/remote/outbound/output.json10
-rw-r--r--schema/remote/outbound/started.json9
-rw-r--r--schema/remote/outbound/statechanged.json9
-rw-r--r--src/core/socketlauncher.cpp9
-rw-r--r--src/core/socketlauncher.h2
-rw-r--r--tests/auto/processmanager/testSocketLauncher/main.cpp118
-rw-r--r--tests/auto/processmanager/tst_processmanager.cpp24
13 files changed, 248 insertions, 3 deletions
diff --git a/schema/remote/inbound/set.json b/schema/remote/inbound/set.json
new file mode 100644
index 0000000..da29b4e
--- /dev/null
+++ b/schema/remote/inbound/set.json
@@ -0,0 +1,19 @@
+{
+ "title": "Set schema",
+ "description": "The client would like to change a setting on an existing process",
+ "properties": {
+ "command": { "type": "string", "pattern": "set", "required": true },
+ "id": { "type": "integer", "required": true },
+
+ "key": {
+ "type": "string",
+ "enum": ["priority", "oomAdjustment"],
+ "required": true
+ },
+
+ "value": {
+ "type": "integer",
+ "required": true
+ }
+ }
+}
diff --git a/schema/remote/inbound/start.json b/schema/remote/inbound/start.json
new file mode 100644
index 0000000..378e171
--- /dev/null
+++ b/schema/remote/inbound/start.json
@@ -0,0 +1,9 @@
+{
+ "title": "Start schema",
+ "description": "The client request a new process to be started",
+ "properties": {
+ "command": { "type": "string", "pattern": "start", "required": true },
+ "id": { "type": "integer", "required": true },
+ "info": { "type": "object", "required": true }
+ }
+}
diff --git a/schema/remote/inbound/stop.json b/schema/remote/inbound/stop.json
new file mode 100644
index 0000000..7a9e6c3
--- /dev/null
+++ b/schema/remote/inbound/stop.json
@@ -0,0 +1,9 @@
+{
+ "title": "Stop schema",
+ "description": "The client request a process to be stopped",
+ "properties": {
+ "command": { "type": "string", "pattern": "stop", "required": true },
+ "id": { "type": "integer", "required": true },
+ "timeout": { "type": "integer", "required": true }
+ }
+}
diff --git a/schema/remote/inbound/write.json b/schema/remote/inbound/write.json
new file mode 100644
index 0000000..22e8595
--- /dev/null
+++ b/schema/remote/inbound/write.json
@@ -0,0 +1,13 @@
+{
+ "title": "Write schema",
+ "description": "The client is writing data to the stdin of an existing process",
+ "properties": {
+ "command": { "type": "string", "pattern": "write", "required": true },
+ "id": { "type": "integer", "required": true },
+
+ "data": {
+ "type": "string",
+ "required": true
+ }
+ }
+}
diff --git a/schema/remote/outbound/error.json b/schema/remote/outbound/error.json
new file mode 100644
index 0000000..1544070
--- /dev/null
+++ b/schema/remote/outbound/error.json
@@ -0,0 +1,10 @@
+{
+ "title": "Error schema",
+ "description": "Signal the client that a process has sent the error() signal",
+ "properties": {
+ "event": { "type": "string", "pattern": "error", "required": true },
+ "id": { "type": "integer", "required": true },
+ "error": { "type": "integer", "required": true },
+ "errorString": { "type": "string", "required": true }
+ }
+}
diff --git a/schema/remote/outbound/finished.json b/schema/remote/outbound/finished.json
new file mode 100644
index 0000000..4f53729
--- /dev/null
+++ b/schema/remote/outbound/finished.json
@@ -0,0 +1,10 @@
+{
+ "title": "Finished schema",
+ "description": "Signal the client that a process has sent the finished() signal",
+ "properties": {
+ "event": { "type": "string", "pattern": "finished", "required": true },
+ "id": { "type": "integer", "required": true },
+ "exitCode": { "type": "integer", "required": true },
+ "exitStatus": { "type": "integer", "required": true }
+ }
+}
diff --git a/schema/remote/outbound/output.json b/schema/remote/outbound/output.json
new file mode 100644
index 0000000..ee70cf2
--- /dev/null
+++ b/schema/remote/outbound/output.json
@@ -0,0 +1,10 @@
+{
+ "title": "Output schema",
+ "description": "Signal the client that a process has written data on stdout or stderr",
+ "properties": {
+ "event": { "type": "string", "pattern": "output", "required": true },
+ "id": { "type": "integer", "required": true },
+ "stdout": { "type": "string" },
+ "stderr": { "type": "string" }
+ }
+}
diff --git a/schema/remote/outbound/started.json b/schema/remote/outbound/started.json
new file mode 100644
index 0000000..cef861a
--- /dev/null
+++ b/schema/remote/outbound/started.json
@@ -0,0 +1,9 @@
+{
+ "title": "Started schema",
+ "description": "Signal the client that a process has sent the started() signal",
+ "properties": {
+ "event": { "type": "string", "pattern": "started", "required": true },
+ "id": { "type": "integer", "required": true },
+ "pid": { "type": "integer", "required": true }
+ }
+}
diff --git a/schema/remote/outbound/statechanged.json b/schema/remote/outbound/statechanged.json
new file mode 100644
index 0000000..acdddf8
--- /dev/null
+++ b/schema/remote/outbound/statechanged.json
@@ -0,0 +1,9 @@
+{
+ "title": "State Changed schema",
+ "description": "Signal the client that a process has sent the stateChanged() signal",
+ "properties": {
+ "event": { "type": "string", "pattern": "stateChanged", "required": true },
+ "id": { "type": "integer", "required": true },
+ "stateChanged": { "type": "integer", "required": true },
+ }
+}
diff --git a/src/core/socketlauncher.cpp b/src/core/socketlauncher.cpp
index bb6561f..909dc5f 100644
--- a/src/core/socketlauncher.cpp
+++ b/src/core/socketlauncher.cpp
@@ -92,6 +92,15 @@ bool SocketLauncher::listen(const QString& socketname, QtAddOn::JsonStream::Json
}
/*!
+ Return the internal JsonServer object.
+ */
+
+QtAddOn::JsonStream::JsonServer * SocketLauncher::server() const
+{
+ return m_server;
+}
+
+/*!
\internal
*/
void SocketLauncher::connectionAdded(const QString& identifier)
diff --git a/src/core/socketlauncher.h b/src/core/socketlauncher.h
index 0fb7ba1..7ee15b7 100644
--- a/src/core/socketlauncher.h
+++ b/src/core/socketlauncher.h
@@ -58,6 +58,8 @@ public:
Q_INVOKABLE bool listen(int port, QtAddOn::JsonStream::JsonAuthority *authority = 0);
Q_INVOKABLE bool listen(const QString& socketname, QtAddOn::JsonStream::JsonAuthority *authority=0);
+ QtAddOn::JsonStream::JsonServer * server() const;
+
private slots:
void connectionAdded(const QString& identifier);
void connectionRemoved(const QString& identifier);
diff --git a/tests/auto/processmanager/testSocketLauncher/main.cpp b/tests/auto/processmanager/testSocketLauncher/main.cpp
index 7d68db0..28bfe54 100644
--- a/tests/auto/processmanager/testSocketLauncher/main.cpp
+++ b/tests/auto/processmanager/testSocketLauncher/main.cpp
@@ -38,16 +38,132 @@
****************************************************************************/
#include <QCoreApplication>
+#include <QFileInfo>
+#include <QDir>
+#include <QDebug>
+
+#include <jsonserver.h>
+#include <schemavalidator.h>
+
#include "socketlauncher.h"
#include "standardprocessbackendfactory.h"
QT_USE_NAMESPACE_PROCESSMANAGER
+QString progname;
+
+static void usage()
+{
+ qWarning("Usage: %s [ARGS] <socketname>\n"
+ "\n"
+ "The socketname is the name of the Unix local socket to listen on\n"
+ "\n"
+ "Valid arguments:\n"
+ " -validate-inbound PATH Directory where inbound schema are stored\n"
+ " -validate-outbound PATH Directory where outbound schema are stored\n"
+ " -warn Warn on invalid messages\n"
+ " -drop Drop invalid messages\n"
+ , qPrintable(progname));
+ exit(1);
+}
+
+class ValidateMessage : public QObject {
+ Q_OBJECT
+public:
+ ValidateMessage(QObject *parent=0) : QObject(parent) {}
+public slots:
+ void failed(const QJsonObject& message) {
+ qDebug() << Q_FUNC_INFO << "Message failed to validate" << message;
+ }
+};
+
+static void loadSchemasFromDirectory(QtAddOn::JsonStream::SchemaValidator *validator, const QString& path)
+{
+ int count = 0;
+ QDir dir(path);
+ if (!dir.exists())
+ qFatal("Schema directory '%s' does not exist", qPrintable(path));
+
+ dir.setNameFilters( QStringList() << "*.json" );
+ foreach (QString filename, dir.entryList(QDir::Files | QDir::Readable)) {
+ if (!validator->loadFromFile(dir.filePath(filename))) {
+ QtAddOn::JsonStream::SchemaError err = validator->getLastError();
+ qFatal("Error loading schema file '%s', [%d] %s",
+ qPrintable(dir.filePath(filename)), err.errorCode(), qPrintable(err.errorString()));
+ }
+ count += 1;
+ }
+
+ if (count == 0)
+ qFatal("Unable to find any schema files in directory '%s'", qPrintable(path));
+ qDebug() << progname << ": loaded" << count << "schemas from" << path;
+}
+
int main(int argc, char **argv)
{
+ QtAddOn::JsonStream::JsonServer::ValidatorFlags flags(QtAddOn::JsonStream::JsonServer::NoValidation);
+ QString indir, outdir;
+
QCoreApplication app(argc, argv);
+ QStringList args = QCoreApplication::arguments();
+ progname = args.takeFirst();
+ while (args.size()) {
+ QString arg = args.at(0);
+ if (!arg.startsWith('-'))
+ break;
+ args.removeFirst();
+ if (arg == QLatin1String("-help"))
+ usage();
+ else if (arg == QLatin1String("-validate-inbound")) {
+ if (!args.size())
+ usage();
+ indir = args.takeFirst();
+ QFileInfo fi(indir);
+ if (!fi.exists() || !fi.isDir()) {
+ qWarning("Invalid inbound validation directory '%s'", qPrintable(indir));
+ exit(1);
+ }
+ }
+ else if (arg == QLatin1String("-validate-outbound")) {
+ if (!args.size())
+ usage();
+ outdir = args.takeFirst();
+ QFileInfo fi(outdir);
+ if (!fi.exists() || !fi.isDir()) {
+ qWarning("Invalid outbound validation directory '%s'", qPrintable(outdir));
+ exit(1);
+ }
+ }
+ else if (arg == QLatin1String("-warn"))
+ flags |= QtAddOn::JsonStream::JsonServer::WarnIfInvalid;
+ else if (arg == QLatin1String("-drop"))
+ flags |= QtAddOn::JsonStream::JsonServer::DropIfInvalid;
+ else {
+ qWarning("Unexpected argument '%s'", qPrintable(arg));
+ usage();
+ }
+ }
+
+ if (args.size() != 1)
+ usage();
+
SocketLauncher launcher;
launcher.addFactory(new StandardProcessBackendFactory);
- launcher.listen(argv[1]);
+ if (!indir.isEmpty())
+ loadSchemasFromDirectory(launcher.server()->inboundValidator(), indir);
+ if (!outdir.isEmpty())
+ loadSchemasFromDirectory(launcher.server()->outboundValidator(), outdir);
+ launcher.server()->setValidatorFlags(flags);
+
+ ValidateMessage *vtrap = new ValidateMessage;
+
+ QObject::connect(launcher.server(), SIGNAL(inboundMessageValidationFailed(const QJsonObject&)),
+ vtrap, SLOT(failed(const QJsonObject&)));
+ QObject::connect(launcher.server(), SIGNAL(outboundMessageValidationFailed(const QJsonObject&)),
+ vtrap, SLOT(failed(const QJsonObject&)));
+
+ launcher.listen(args[0]);
return app.exec();
}
+
+#include "main.moc"
diff --git a/tests/auto/processmanager/tst_processmanager.cpp b/tests/auto/processmanager/tst_processmanager.cpp
index c6863cf..f47d87c 100644
--- a/tests/auto/processmanager/tst_processmanager.cpp
+++ b/tests/auto/processmanager/tst_processmanager.cpp
@@ -676,12 +676,12 @@ static void pipeLauncherTest( clientFunc func )
}
-static void socketLauncherTest( clientFunc func )
+static void socketLauncherTest( clientFunc func, QStringList args=QStringList() )
{
QProcess *remote = new QProcess;
QString socketName = QLatin1String("/tmp/socketlauncher");
remote->setProcessChannelMode(QProcess::ForwardedChannels);
- remote->start("testSocketLauncher/testSocketLauncher", QStringList() << socketName);
+ remote->start("testSocketLauncher/testSocketLauncher", args << socketName);
QVERIFY(remote->waitForStarted());
waitForSocket(socketName);
@@ -699,6 +699,15 @@ static void socketLauncherTest( clientFunc func )
delete remote;
}
+static void socketSchemaTest( clientFunc func )
+{
+ QStringList args;
+ args << "-validate-inbound" << "../../../schema/remote/inbound"
+ << "-validate-outbound" << "../../../schema/remote/outbound"
+ << "-warn" << "-drop";
+ socketLauncherTest(func, args);
+}
+
/******************************************************************************/
@@ -765,6 +774,17 @@ private slots:
void socketLauncherOomChangeAfter() { socketLauncherTest(oomChangeAfterClient); }
#endif
+ void socketSchemaStartAndStop() { socketSchemaTest(startAndStopClient); }
+ void socketSchemaStartAndKill() { socketSchemaTest(startAndKillClient); }
+ void socketSchemaStartAndCrash() { socketSchemaTest(startAndCrashClient); }
+ void socketSchemaEcho() { socketSchemaTest(echoClient); }
+ void socketSchemaPriorityChangeBefore() { socketSchemaTest(priorityChangeBeforeClient); }
+ void socketSchemaPriorityChangeAfter() { socketSchemaTest(priorityChangeAfterClient); }
+#if defined(Q_OS_LINUX)
+ void socketSchemaOomChangeBefore() { socketSchemaTest(oomChangeBeforeClient); }
+ void socketSchemaOomChangeAfter() { socketSchemaTest(oomChangeAfterClient); }
+#endif
+
void prelaunchChildAbort();
void frontend();