[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [akonadi/dev/binary-protocol] autotests/server: Start porting testing infrastructure and tests
From:       Dan_Vrátil <dvratil () redhat ! com>
Date:       2015-06-03 20:10:30
Message-ID: E1Z0Eze-0008Pm-0Z () scm ! kde ! org
[Download RAW message or body]

Git commit 6e00dd768644fc263920b6dd8b487e7832484f76 by Dan Vrátil.
Committed on 03/06/2015 at 20:10.
Pushed by dvratil into branch 'dev/binary-protocol'.

Start porting testing infrastructure and tests

M  +222  -186  autotests/server/akappendhandlertest.cpp
M  +4    -4    autotests/server/dbinitializer.cpp
M  +10   -4    autotests/server/dbinitializer.h
M  +30   -38   autotests/server/fakeakonadiserver.cpp
M  +73   -9    autotests/server/fakeakonadiserver.h
M  +34   -29   autotests/server/fakeclient.cpp
M  +6    -2    autotests/server/fakeclient.h

http://commits.kde.org/akonadi/6e00dd768644fc263920b6dd8b487e7832484f76

diff --git a/autotests/server/akappendhandlertest.cpp b/autotests/server/akappendhandlertest.cpp
index 8b417cd..034b6ba 100644
--- a/autotests/server/akappendhandlertest.cpp
+++ b/autotests/server/akappendhandlertest.cpp
@@ -21,16 +21,15 @@
 #include <QSettings>
 
 #include <handler/akappend.h>
-#include <imapstreamparser.h>
-#include <response.h>
 #include <storage/selectquerybuilder.h>
 
 #include <private/notificationmessagev3_p.h>
 #include <private/notificationmessagev2_p.h>
-#include <private/imapparser_p.h>
+#include <private/scope_p.h>
 
 #include "fakeakonadiserver.h"
 #include "fakeentities.h"
+
 #include <shared/aktest.h>
 #include <shared/akstandarddirs.h>
 
@@ -158,23 +157,37 @@ public:
         }
     }
 
-    QByteArray createCommand(const PimItem &pimItem, const QDateTime &dt,
-                             qint64 overrideSize = -1)
+    Protocol::CreateItemCommand createCommand(const PimItem &pimItem,
+                                              const QDateTime &dt,
+                                              const QVector<Protocol::PartMetaData> &parts,
+                                              qint64 overrideSize = -1)
     {
         const qint64 size = overrideSize > -1 ? overrideSize : pimItem.size();
-        return "C: 2 X-AKAPPEND " + QByteArray::number(pimItem.collectionId()) + " "
-               + QByteArray::number(size) + " "
-               + "(\\RemoteId[" + pimItem.remoteId().toLatin1() + "] "
-               +  "\\MimeType[" + pimItem.mimeType().name().toLatin1() + "] "
-               +  "\\RemoteRevision[" + pimItem.remoteRevision().toLatin1() + "] "
-               +  "\\Gid[" + pimItem.gid().toLatin1() + "]) "
-               + "\"" + dt.toString(QLatin1String("dd-MMM-yyyy hh:mm:ss")).toLatin1() + " +0000\"";
+
+        Protocol::CreateItemCommand cmd;
+        cmd.setCollection(Scope(pimItem.collectionId()));
+        cmd.setItemSize(size);
+        cmd.setRemoteId(pimItem.remoteId());
+        cmd.setRemoteRevision(pimItem.remoteRevision());
+        cmd.setMimeType(pimItem.mimeType().name());
+        cmd.setGID(pimItem.gid());
+        cmd.setDateTime(dt);
+        cmd.setParts(parts);
+
+        return cmd;
+    }
+
+    TestScenario errorResponse(const QString &errorMsg)
+    {
+        Protocol::CreateItemResponse response;
+        response.setError(1, errorMsg);
+        return TestScenario::create(5, TestScenario::ServerCmd, response);
     }
 
 private Q_SLOTS:
     void testAkAppend_data()
     {
-        QTest::addColumn<QList<QByteArray> >("scenario");
+        QTest::addColumn<TestScenario::List>("scenarios");
         QTest::addColumn<NotificationMessageV3>("notification");
         QTest::addColumn<PimItem>("pimItem");
         QTest::addColumn<QVector<FakePart> >("parts");
@@ -184,7 +197,7 @@ private Q_SLOTS:
         QTest::addColumn<QDateTime>("datetime");
         QTest::addColumn<bool>("expectFail");
 
-        QList<QByteArray> scenario;
+        TestScenario::List scenarios;
         NotificationMessageV3 notification;
         qint64 uidnext = 0;
         QDateTime datetime(QDate(2014, 05, 12), QTime(14, 46, 00));
@@ -208,13 +221,12 @@ private Q_SLOTS:
         notification.addEntity(-1, QLatin1String("TEST-1"), QLatin1String("1"), \
                QLatin1String("application/octet-stream"));
         notification.setSessionId(FakeAkonadiServer::instanceName().toLatin1());
         uidnext = 13;
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << createCommand(pimItem, datetime) + " (PLD:DATA[0] {10}"
-                 << "S: + Ready for literal data (expecting 10 bytes)"
-                 << "C: 0123456789)"
-                 << "S: 2 [UIDNEXT 13 DATETIME \"12-May-2014 14:46:00 +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("single-part") << scenario << notification << pimItem << parts
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { \
Protocol::PartMetaData("PLD:DATA", 10, 0) })) +                  << TestScenario::create(5, \
TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", 10)) +                  << \
TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("0123456789")) +         \
<< TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); +        \
                QTest::newRow("single-part") << scenarios << notification << pimItem << parts
                                      << flags << tags << uidnext << datetime << false;
 
         updatePimItem(pimItem, QLatin1String("TEST-2"), 20);
@@ -222,32 +234,45 @@ private Q_SLOTS:
                              { QLatin1String("PLD:PLDTEST"), "Test Data", 9 } });
         updateNotifcationEntity(notification, pimItem);
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << createCommand(pimItem, datetime) + " (PLD:DATA[0] {11}"
-                 << "S: + Ready for literal data (expecting 11 bytes)"
-                 << "C: Random Data PLD:PLDTEST {9}"
-                 << "S: + Ready for literal data (expecting 9 bytes)"
-                 << "C: Test Data)"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("multi-part") << scenario << notification << pimItem << parts
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime,
+                                   { Protocol::PartMetaData("PLD:DATA", 11, 0),
+                                     Protocol::PartMetaData("PLD:PLDTEST", 9, 0)
+                                   }))
+                  << TestScenario::create(5, TestScenario::ServerCmd, \
Protocol::StreamPayloadCommand("PLD:DATA", 11)) +                  << TestScenario::create(5, \
TestScenario::ClientCmd, Protocol::StreamPayloadResponse("Random Data")) +                  << \
TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:PDTEST", 9)) +       \
<< TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("Test Data")) +       \
<< TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); +        \
                QTest::newRow("multi-part") << scenarios << notification << pimItem << parts
                                     << flags << tags << uidnext << datetime << false;
 
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << "C: 2 X-AKAPPEND 100 0 () ()"
-                 << "S: 2 NO Unknown collection for '100'.";
-        QTest::newRow("invalid collection") << scenario << NotificationMessageV3()
+        TestScenario scenario;
+        {
+            Protocol::CreateItemCommand cmd;
+            cmd.setCollection(Scope(100));
+            scenario = TestScenario::create(5, TestScenario::ClientCmd, cmd);
+        }
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << scenario
+                  << errorResponse(QLatin1String("Unknown collection for '100'."));
+        QTest::newRow("invalid collection") << scenarios << NotificationMessageV3()
                                             << PimItem() << QVector<FakePart>()
                                             << QVector<Flag>() << QVector<FakeTag>()
                                             << -1ll << QDateTime() << true;
 
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << "C: 2 X-AKAPPEND 6 0 () ()"
-                 << "S: 2 NO Cannot append item into virtual collection";
-        QTest::newRow("virtual collection") << scenario << NotificationMessageV3()
+        {
+            Protocol::CreateItemCommand cmd;
+            cmd.setCollection(Scope(6));
+            scenario = TestScenario::create(5, TestScenario::ClientCmd, cmd);
+        }
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << scenario
+                  << errorResponse(QLatin1String("Cannot append item into virtual collection"));
+        QTest::newRow("virtual collection") << scenarios << NotificationMessageV3()
                                             << PimItem() << QVector<FakePart>()
                                             << QVector<Flag>() << QVector<FakeTag>()
                                             << -1ll << QDateTime() << true;
@@ -256,49 +281,47 @@ private Q_SLOTS:
         updateParts(parts, { { QLatin1String("PLD:DATA"), "12345", 5 } });
         updateNotifcationEntity(notification, pimItem);
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << createCommand(pimItem, datetime, 1) + " (PLD:DATA[0] {5}"
-                 << "S: + Ready for literal data (expecting 5 bytes)"
-                 << "C: 12345)"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("mismatch item sizes (smaller)") << scenario << notification << pimItem
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { \
Protocol::PartMetaData("PLD:DATA", 5, 0) }, 1)) +                  << TestScenario::create(5, \
TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", 5)) +                  << \
TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("12345")) +              \
<< TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); +        \
                QTest::newRow("mismatch item sizes (smaller)") << scenarios << notification << pimItem
                                                        << parts << flags << tags << uidnext
                                                        << datetime << false;
 
         updatePimItem(pimItem, QLatin1String("TEST-4"), 1000);
         updateNotifcationEntity(notification, pimItem);
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << createCommand(pimItem, datetime) + " (PLD:DATA[0] {5}"
-                 << "S: + Ready for literal data (expecting 5 bytes)"
-                 << "C: 12345)"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("mismatch item sizes (bigger)") << scenario << notification << pimItem
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { \
Protocol::PartMetaData("PLD:DATA", 5, 0) }, 10)) +                  << TestScenario::create(5, \
TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", 5)) +                  << \
TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("12345")) +              \
<< TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); +        \
                QTest::newRow("mismatch item sizes (bigger)") << scenarios << notification << pimItem
                                                       << parts << flags << tags << uidnext
                                                       << datetime << false;
 
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << createCommand(pimItem, datetime) + " (PLD:DATA[0] {4}"
-                 << "S: + Ready for literal data (expecting 4 bytes)"
-                 << "C: 123"
-                 << "S: 2 NO ImapParserException: Unable to read more data";
-        QTest::newRow("incomplete part data") << scenario << NotificationMessageV3()
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { \
Protocol::PartMetaData("PLD:DATA", 5, 0) })) +                  << TestScenario::create(5, \
TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", 5)) +                  << \
TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("123")) +                \
<< errorResponse(QLatin1String("Unable to read more data")); +        QTest::newRow("incomplete part \
                data") << scenarios << NotificationMessageV3()
                                               << PimItem() << QVector<FakePart>()
                                               << QVector<Flag>() << QVector<FakeTag>()
                                               << -1ll << QDateTime() << true;
 
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << createCommand(pimItem, datetime) + " (PLD:DATA[0] {4}"
-                 << "S: + Ready for literal data (expecting 4 bytes)"
-                 << "C: 12345678910"
-                 << "S: 2 NO PartTypeException: Invalid part type name.";
-        QTest::newRow("part data larger than advertised") << scenario << NotificationMessageV3()
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { \
Protocol::PartMetaData("PLD:DATA", 4, 0) })) +                  << TestScenario::create(5, \
TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", 4)) +                  << \
TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse("1234567890")) +         \
<< errorResponse(QLatin1String("PartTypeException: Invalid part type name.")); +        \
                QTest::newRow("part data larger than advertised") << scenarios << NotificationMessageV3()
                                                           << PimItem() << QVector<FakePart>()
                                                           << QVector<Flag>() << QVector<FakeTag>()
                                                           << -1ll << QDateTime() << true;
@@ -307,39 +330,26 @@ private Q_SLOTS:
         updateParts(parts, { { QLatin1String("PLD:DATA"), QByteArray(), 0 } });
         updateNotifcationEntity(notification, pimItem);
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << createCommand(pimItem, datetime) + " (PLD:DATA[0] NIL)"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("empty payload part") << scenario << notification << pimItem << parts
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { \
Protocol::PartMetaData("PLD:DATA", 0, 0) })) +                  << TestScenario::create(5, \
TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", 0)) +                  << \
TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse()) +                  << \
TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); +        \
                QTest::newRow("empty payload part") << scenarios << notification << pimItem << parts
                                             << flags << tags << uidnext << datetime << false;
 
-        updatePimItem(pimItem, QLatin1String("TEST-7"), 0);
-        updateNotifcationEntity(notification, pimItem);
-        ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << createCommand(pimItem, datetime) + " (PLD:DATA[0] {0}"
-                 << "S: + Ready for literal data (expecting 0 bytes)"
-                 << "C: )"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("empty part data") << scenario << notification << pimItem << parts
-                                         << flags << tags << uidnext << datetime << false;
-
         updatePimItem(pimItem, QLatin1String("TEST-8"), 1);
         updateParts(parts, { { QLatin1String("PLD:DATA"), QByteArray("\0", 1), 1 } });
         updateNotifcationEntity(notification, pimItem);
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << createCommand(pimItem,  datetime) + " (PLD:DATA[0] {1}"
-                 << "S: + Ready for literal data (expecting 1 bytes)"
-                 << "C: " + QByteArray("\0", 1) + ")"   // otherwise QByteArray trims the string \
                before"\0"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("part data will null character") << scenario << notification << pimItem
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem,  datetime, \
{ Protocol::PartMetaData("PLD:DATA", 1, 0) })) +                  << TestScenario::create(5, \
TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", 1)) +                  << \
TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponse(QByteArray("\0", 1))) +  \
<< TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse()); +        \
                QTest::newRow("part data will null character") << scenarios << notification << pimItem
                                                        << parts << flags << tags << uidnext
                                                        << datetime << false;
 
@@ -348,14 +358,13 @@ private Q_SLOTS:
         updateParts(parts, { { QLatin1String("PLD:DATA"), utf8String.toUtf8(), \
utf8String.toUtf8().size() } });  updateNotifcationEntity(notification, pimItem);
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << createCommand(pimItem, datetime) + " (PLD:DATA[0] {" + \
                QByteArray::number(parts.first().datasize()) + "}"
-                 << "S: + Ready for literal data (expecting " + \
                QByteArray::number(parts.first().datasize()) + " bytes)"
-                 << "C: " + utf8String.toUtf8() + ")"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("utf8 part data") << scenario << notification << pimItem << parts
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { \
Protocol::PartMetaData("PLD:DATA", parts.first().datasize()) })) +                  << \
TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", \
parts.first().datasize())) +                  << TestScenario::create(5, TestScenario::ClientCmd, \
Protocol::StreamPayloadResponse(utf8String.toUtf8())) +                  << TestScenario::create(5, \
TestScenario::ServerCmd, Protocol::CreateItemResponse()); +        QTest::newRow("utf8 part data") << \
                scenarios << notification << pimItem << parts
                                         << flags << tags << uidnext << datetime << false;
 
         const QByteArray hugeData = QByteArray("a").repeated(1 << 20);
@@ -363,14 +372,13 @@ private Q_SLOTS:
         updateParts(parts, { { QLatin1String("PLD:DATA"), hugeData, 1 << 20 } });
         updateNotifcationEntity(notification, pimItem);
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << createCommand(pimItem, datetime) + " (PLD:DATA[0] {" + \
                QByteArray::number(parts.first().datasize()) + "}"
-                 << "S: + Ready for literal data (expecting " + \
                QByteArray::number(parts.first().datasize()) + " bytes)"
-                 << "C: " + hugeData + ")"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("huge part data") << scenario << notification << pimItem << parts
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { \
Protocol::PartMetaData("PLD:DATA", parts.first().datasize()) })) +                  << \
TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", \
parts.first().datasize())) +                  << TestScenario::create(5, TestScenario::ClientCmd, \
Protocol::StreamPayloadResponse(hugeData)) +                  << TestScenario::create(5, \
TestScenario::ServerCmd, Protocol::CreateItemResponse()); +        QTest::newRow("huge part data") << \
                scenarios << notification << pimItem << parts
                                         << flags << tags << uidnext << datetime << false;
 
         const QByteArray dataWithNewLines = "Bernard, Bernard, Bernard, Bernard, look, look \
Bernard!\nWHAT!!!!!!!\nI'm a prostitute robot from the future!"; @@ -378,14 +386,13 @@ private Q_SLOTS:
         updateParts(parts, { { QLatin1String("PLD:DATA"), dataWithNewLines, dataWithNewLines.size() } \
});  updateNotifcationEntity(notification, pimItem);
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << createCommand(pimItem, datetime) + " (PLD:DATA[0] {" + \
                QByteArray::number(parts.first().datasize()) + "}"
-                 << "S: + Ready for literal data (expecting " + \
                QByteArray::number(parts.first().datasize()) + " bytes)"
-                 << "C: " + dataWithNewLines + ")"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("data with newlines") << scenario << notification << pimItem << parts
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { \
Protocol::PartMetaData("PLD:DATA", parts.first().datasize()) })) +                  << \
TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", \
parts.first().datasize())) +                  << TestScenario::create(5, TestScenario::ClientCmd, \
Protocol::StreamPayloadResponse(dataWithNewLines)) +                  << TestScenario::create(5, \
TestScenario::ServerCmd, Protocol::CreateItemResponse()); +        QTest::newRow("data with newlines") << \
                scenarios << notification << pimItem << parts
                                             << flags << tags << uidnext << datetime << false;
 
         const QByteArray lotsOfNewlines = QByteArray("\n").repeated(1 << 20);
@@ -393,14 +400,13 @@ private Q_SLOTS:
         updateParts(parts, { { QLatin1String("PLD:DATA"), lotsOfNewlines, lotsOfNewlines.size() } });
         updateNotifcationEntity(notification, pimItem);
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << createCommand(pimItem, datetime) + "(PLD:DATA[0] {" + \
                QByteArray::number(parts.first().datasize()) + "}"
-                 << "S: + Ready for literal data (expecting " + \
                QByteArray::number(parts.first().datasize()) + " bytes)"
-                 << "C: " + lotsOfNewlines + ")"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("data with lots of newlines") << scenario << notification << pimItem
+        scenarios.clear();
+          scenarios << FakeAkonadiServer::loginScenario()
+                  << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime, { \
Protocol::PartMetaData("PLD:DATA", parts.first().datasize()) })) +                  << \
TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:DATA", \
parts.first().datasize())) +                  << TestScenario::create(5, TestScenario::ClientCmd, \
Protocol::StreamPayloadResponse(lotsOfNewlines)) +                  << TestScenario::create(5, \
TestScenario::ServerCmd, Protocol::CreateItemResponse()); +        QTest::newRow("data with lots of \
                newlines") << scenarios << notification << pimItem
                                                     << parts << flags << tags << uidnext
                                                     << datetime << false;
 
@@ -409,16 +415,17 @@ private Q_SLOTS:
                              { QLatin1String("PLD:NEWPARTTYPE2"), "9876543210", 10 } });
         updateNotifcationEntity(notification, pimItem);
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << createCommand(pimItem, datetime) + "(PLD:NEWPARTTYPE1[0] {10}"
-                 << "S: + Ready for literal data (expecting 10 bytes)"
-                 << "C: 0123456789 PLD:NEWPARTTYPE2[0] {10}"
-                 << "S: + Ready for literal data (expecting 10 bytes)"
-                 << "C: 9876543210)"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("non-existent part types") << scenario << notification << pimItem
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << TestScenario::create(5, TestScenario::ClientCmd, createCommand(pimItem, datetime,
+                                   { Protocol::PartMetaData("PLD:NEWPARTTYPE1", 10, 0),
+                                     Protocol::PartMetaData("PLD:NEWPARTTYPE2", 10, 0) }))
+                  << TestScenario::create(5, TestScenario::ServerCmd, \
Protocol::StreamPayloadCommand("PLD:NEWPARTTYPE1", 10)) +                  << TestScenario::create(5, \
TestScenario::ClientCmd, Protocol::StreamPayloadResponse("0123456789")) +                  << \
TestScenario::create(5, TestScenario::ServerCmd, Protocol::StreamPayloadCommand("PLD:NEWPARTTYPE2", 10)) \
+                  << TestScenario::create(5, TestScenario::ClientCmd, \
Protocol::StreamPayloadResponse("9876543210")) +                  << TestScenario::create(5, \
TestScenario::ServerCmd, Protocol::CreateItemResponse()); +        QTest::newRow("non-existent part \
                types") << scenarios << notification << pimItem
                                                  << parts << flags << tags << uidnext
                                                  << datetime << false;
 
@@ -427,12 +434,16 @@ private Q_SLOTS:
         updateFlags(flags, QStringList() << QLatin1String("\\SEEN") << QLatin1String("\\RANDOM"));
         updateNotifcationEntity(notification, pimItem);
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << "C: 2 X-AKAPPEND 4 0 (\\RemoteId[TEST-14] \\MimeType[application/octet-stream] \
                \\RemoteRevision[1] \\Gid[TEST-14] \\SEEN \\RANDOM) \"12-May-2014 14:46:00 +0000\" ()"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("item with flags") << scenario << notification << pimItem << parts
+        {
+            auto cmd = createCommand(pimItem, datetime, {});
+            cmd.setFlags({ "\\SEEN", "\\RANDOM" });
+            scenario = TestScenario::create(5, TestScenario::ClientCmd, cmd);
+        }
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << scenario
+                  << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse());
+        QTest::newRow("item with flags") << scenarios << notification << pimItem << parts
                                          << flags << tags << uidnext << datetime << false;
 
         updatePimItem(pimItem, QLatin1String("TEST-15"), 0);
@@ -441,12 +452,16 @@ private Q_SLOTS:
                            { QLatin1String("PLAIN"), QLatin1String("TAG-2") } });
         updateNotifcationEntity(notification, pimItem);
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << "C: 2 X-AKAPPEND 4 0 (\\RemoteId[TEST-15] \\MimeType[application/octet-stream] \
                \\RemoteRevision[1] \\Gid[TEST-15] \\Tag[TAG-1] \\Tag[TAG-2]) \"12-May-2014 14:46:00 \
                +0000\" ()"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("item with non-existent tags (GID)") << scenario << notification << pimItem << \
parts +        {
+            auto cmd = createCommand(pimItem, datetime, {});
+            cmd.setTags(Scope(Scope::Rid, { QLatin1String("TAG-1"), QLatin1String("TAG-2") }));
+            scenario = TestScenario::create(5, TestScenario::ClientCmd, cmd);
+        }
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << scenario
+                  << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse());
+        QTest::newRow("item with non-existent tags (GID)") << scenarios << notification << pimItem << \
                parts
                                                            << flags << tags << uidnext << datetime << \
false;  
         updatePimItem(pimItem, QLatin1String("TEST-16"), 0);
@@ -454,13 +469,17 @@ private Q_SLOTS:
                            { QLatin1String("PLAIN"), QLatin1String("TAG-4") } });
         updateNotifcationEntity(notification, pimItem);
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << FakeAkonadiServer::selectResourceScenario(QLatin1String("akonadi_fake_resource_0"))
-                 << "C: 3 X-AKAPPEND 4 0 (\\RemoteId[TEST-16] \\MimeType[application/octet-stream] \
                \\RemoteRevision[1] \\Gid[TEST-16] \\RTag[TAG-3] \\RTag[TAG-4]) \"12-May-2014 14:46:00 \
                +0000\" ()"
-                 << "S: 3 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 3 OK Append completed";
-        QTest::newRow("item with non-existent tags (RID)") << scenario << notification << pimItem << \
parts +        {
+            auto cmd = createCommand(pimItem, datetime, {});
+            cmd.setTags(Scope(Scope::Rid, { QLatin1String("TAG-3"), QLatin1String("TAG-4") }));
+            scenario = TestScenario::create(5, TestScenario::ClientCmd, cmd);
+        }
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << FakeAkonadiServer::selectResourceScenario(QLatin1String("akonadi_fake_resource_0"))
+                  << scenario
+                  << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse());
+        QTest::newRow("item with non-existent tags (RID)") << scenarios << notification << pimItem << \
                parts
                                                            << flags << tags << uidnext << datetime << \
false;  
         updatePimItem(pimItem, QLatin1String("TEST-17"), 0);
@@ -468,13 +487,17 @@ private Q_SLOTS:
         updateTags(tags, { { QLatin1String("PLAIN"), QLatin1String("TAG-1") },
                            { QLatin1String("PLAIN"), QLatin1String("TAG-2") } });
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << FakeAkonadiServer::selectResourceScenario(QLatin1String("akonadi_fake_resource_0"))
-                 << "C: 3 X-AKAPPEND 4 0 (\\RemoteId[TEST-17] \\MimeType[application/octet-stream] \
                \\RemoteRevision[1] \\Gid[TEST-17] \\RTag[TAG-1] \\RTag[TAG-2]) \"12-May-2014 14:46:00 \
                +0000\" ()"
-                 << "S: 3 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 3 OK Append completed";
-        QTest::newRow("item with existing tags (RID)") << scenario << notification << pimItem << parts
+        {
+            auto cmd = createCommand(pimItem, datetime, {});
+            cmd.setTags(Scope(Scope::Rid, { QLatin1String("TAG-1"), QLatin1String("TAG-2") }));
+            scenario = TestScenario::create(5, TestScenario::ClientCmd, cmd);
+        }
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << FakeAkonadiServer::selectResourceScenario(QLatin1String("akonadi_fake_resource_0"))
+                  << scenario
+                  << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse());
+        QTest::newRow("item with existing tags (RID)") << scenarios << notification << pimItem << parts
                                                        << flags << tags << uidnext << datetime << false;
 
         updatePimItem(pimItem, QLatin1String("TEST-18"), 0);
@@ -482,12 +505,16 @@ private Q_SLOTS:
         updateTags(tags, { { QLatin1String("PLAIN"), QLatin1String("TAG-3") },
                            { QLatin1String("PLAIN"), QLatin1String("TAG-4") } });
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << "C: 2 X-AKAPPEND 4 0 (\\RemoteId[TEST-18] \\MimeType[application/octet-stream] \
                \\RemoteRevision[1] \\Gid[TEST-18] \\Tag[TAG-3] \\Tag[TAG-4]) \"12-May-2014 14:46:00 \
                +0000\" ()"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("item with existing tags (GID)") << scenario << notification << pimItem << parts
+        {
+            auto cmd = createCommand(pimItem, datetime, {});
+            cmd.setTags(Scope(Scope::Rid, { QLatin1String("TAG-3"), QLatin1String("TAG-4") }));
+            scenario = TestScenario::create(5, TestScenario::ClientCmd, cmd);
+        }
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << scenario
+                  << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse());
+        QTest::newRow("item with existing tags (GID)") << scenarios << notification << pimItem << parts
                                                        << flags << tags << uidnext << datetime << false;
 
         updatePimItem(pimItem, QLatin1String("TEST-19"), 0);
@@ -496,12 +523,17 @@ private Q_SLOTS:
                            { QLatin1String("PLAIN"), QLatin1String("TAG-2") } });
         updateNotifcationEntity(notification, pimItem);
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << "C: 2 X-AKAPPEND 4 0 (\\RemoteId[TEST-19] \\MimeType[application/octet-stream] \
\\RemoteRevision[1] \\Gid[TEST-19] \\Tag[TAG-1] \\SEEN \\Tag[TAG-2] $FLAG) \"12-May-2014 14:46:00 +0000\" \
                ()"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("item with flags and tags") << scenario << notification << pimItem << parts
+        {
+            auto cmd = createCommand(pimItem, datetime, {});
+            cmd.setTags(Scope(Scope::Rid, { QLatin1String("TAG-1"), QLatin1String("TAG-2") }));
+            cmd.setFlags({ "\\SEEN", "$FLAG" });
+            scenario = TestScenario::create(5, TestScenario::ClientCmd, cmd);
+        }
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << scenario
+                  << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse());
+        QTest::newRow("item with flags and tags") << scenarios << notification << pimItem << parts
                                                   << flags << tags << uidnext << datetime << false;
 
         updatePimItem(pimItem, QLatin1String("TEST-20"), 0);
@@ -509,18 +541,22 @@ private Q_SLOTS:
         updateTags(tags, { { QLatin1String("PLAIN"), utf8String } });
         updateNotifcationEntity(notification, pimItem);;
         ++uidnext;
-        scenario.clear();
-        scenario << FakeAkonadiServer::defaultScenario()
-                 << "C: 2 X-AKAPPEND 4 0 (\\RemoteId[TEST-20] \\MimeType[application/octet-stream] \
                \\RemoteRevision[1] \\Gid[TEST-20] \\Tag[äöüß@€ µÃ¸Ä‘ ¢ © ®]) \"12-May-2014 \
                14:46:00 +0000\" ()"
-                 << "S: 2 [UIDNEXT " + QByteArray::number(uidnext) + " DATETIME \"12-May-2014 14:46:00 \
                +0000\"]"
-                 << "S: 2 OK Append completed";
-        QTest::newRow("item with UTF-8 tag") << scenario << notification << pimItem << parts
+        {
+            auto cmd = createCommand(pimItem, datetime, {});
+            cmd.setTags(Scope(Scope::Rid, { utf8String }));
+            scenario = TestScenario::create(5, TestScenario::ClientCmd, cmd);
+        }
+        scenarios.clear();
+        scenarios << FakeAkonadiServer::loginScenario()
+                  << scenario
+                  << TestScenario::create(5, TestScenario::ServerCmd, Protocol::CreateItemResponse());
+        QTest::newRow("item with UTF-8 tag") << scenarios << notification << pimItem << parts
                                              << flags << tags << uidnext << datetime << false;
     }
 
     void testAkAppend()
     {
-        QFETCH(QList<QByteArray>, scenario);
+        QFETCH(TestScenario::List, scenarios);
         QFETCH(NotificationMessageV3, notification);
         QFETCH(PimItem, pimItem);
         QFETCH(QVector<FakePart>, parts);
@@ -529,7 +565,7 @@ private Q_SLOTS:
         QFETCH(qint64, uidnext);
         QFETCH(bool, expectFail);
 
-        FakeAkonadiServer::instance()->setScenario(scenario);
+        FakeAkonadiServer::instance()->setScenarios(scenarios);
         FakeAkonadiServer::instance()->runTest();
 
         QSignalSpy *notificationSpy = FakeAkonadiServer::instance()->notificationSpy();
diff --git a/autotests/server/dbinitializer.cpp b/autotests/server/dbinitializer.cpp
index c92350d..a173efe 100644
--- a/autotests/server/dbinitializer.cpp
+++ b/autotests/server/dbinitializer.cpp
@@ -84,15 +84,15 @@ QByteArray DbInitializer::toByteArray(bool enabled)
     return "FALSE";
 }
 
-QByteArray DbInitializer::toByteArray(Akonadi::Server::Tristate tristate)
+QByteArray DbInitializer::toByteArray(Akonadi::Tristate tristate)
 {
 
     switch (tristate) {
-    case Akonadi::Server::Tristate::True:
+    case Akonadi::Tristate::True:
         return "TRUE";
-    case Akonadi::Server::Tristate::False:
+    case Akonadi::Tristate::False:
         return "FALSE";
-    case Akonadi::Server::Tristate::Undefined:
+    case Akonadi::Tristate::Undefined:
     default:
         break;
     }
diff --git a/autotests/server/dbinitializer.h b/autotests/server/dbinitializer.h
index 46bf47f..a584ad4 100644
--- a/autotests/server/dbinitializer.h
+++ b/autotests/server/dbinitializer.h
@@ -21,15 +21,21 @@
 
 #include "entities.h"
 
-class DbInitializer {
+class DbInitializer
+{
 public:
     ~DbInitializer();
     Akonadi::Server::Resource createResource(const char *name);
-    Akonadi::Server::Collection createCollection(const char *name, const Akonadi::Server::Collection \
&parent = Akonadi::Server::Collection()); +    Akonadi::Server::Collection createCollection(const char \
*name, +                                                 const Akonadi::Server::Collection &parent = \
                Akonadi::Server::Collection());
     Akonadi::Server::PimItem createItem(const char *name, const Akonadi::Server::Collection &parent);
     QByteArray toByteArray(bool enabled);
-    QByteArray toByteArray(Akonadi::Server::Tristate tristate);
-    QByteArray listResponse(const Akonadi::Server::Collection &col, bool ancestors = false, bool \
mimetypes = true, const QStringList &ancestorFetchScope = QStringList()); +    QByteArray \
toByteArray(Akonadi::Tristate tristate); +    QByteArray listResponse(const Akonadi::Server::Collection \
&col, +                            bool ancestors = false,
+                            bool mimetypes = true,
+                            const QStringList &ancestorFetchScope = QStringList());
+
     Akonadi::Server::Collection collection(const char *name);
 
     void cleanup();
diff --git a/autotests/server/fakeakonadiserver.cpp b/autotests/server/fakeakonadiserver.cpp
index 9cfb535..812dc0b 100644
--- a/autotests/server/fakeakonadiserver.cpp
+++ b/autotests/server/fakeakonadiserver.cpp
@@ -32,7 +32,8 @@
 #include <QTest>
 
 #include <private/xdgbasedirs_p.h>
-#include <private/imapparser_p.h>
+#include <private/protocol_p.h>
+#include <private/scope_p.h>
 #include <shared/akstandarddirs.h>
 #include <shared/akapplication.h>
 
@@ -91,49 +92,40 @@ QString FakeAkonadiServer::instanceName()
     return QString::fromLatin1("akonadiserver-test-%1").arg(QCoreApplication::instance()->applicationPid());
  }
 
-QList<QByteArray> FakeAkonadiServer::loginScenario()
+TestScenario::List FakeAkonadiServer::loginScenario()
 {
-    QList<QByteArray> scenario;
-    // FIXME: Use real protocol version
-    scenario << "S: * OK Akonadi Almost IMAP Server [PROTOCOL " + \
                QByteArray::number(Connection::protocolVersion()) + "]";
-    scenario << "C: 0 LOGIN " + instanceName().toLatin1();
-    scenario << "S: 0 OK User logged in";
-    return scenario;
+    return {
+        TestScenario::create(0, TestScenario::ServerCmd,
+                             Protocol::HelloResponse(QStringLiteral("Akonadi"),
+                                                     QStringLiteral("Not Really IMAP server"),
+                                                     Connection::protocolVersion())),
+        TestScenario::create(1,TestScenario::ClientCmd,
+                             Protocol::LoginCommand(instanceName().toLatin1())),
+        TestScenario::create(1, TestScenario::ServerCmd,
+                             Protocol::LoginResponse())
+    };
 }
 
-QList<QByteArray> FakeAkonadiServer::defaultScenario()
+TestScenario::List FakeAkonadiServer::selectCollectionScenario(const QString &name)
 {
-    QList<QByteArray> caps;
-    caps << "NOTIFY 2";
-    caps << "NOPAYLOADPATH";
-    caps << "AKAPPENDSTREAMING";
-    return customCapabilitiesScenario(caps);
-}
-
-QList<QByteArray> FakeAkonadiServer::customCapabilitiesScenario(const QList<QByteArray> &capabilities)
-{
-    QList<QByteArray> scenario = loginScenario();
-    scenario << "C: 1 CAPABILITY (" + ImapParser::join(capabilities, " ") + ")";
-    scenario << "S: 1 OK CAPABILITY completed";
-    return scenario;
-}
-
-QList<QByteArray> FakeAkonadiServer::selectCollectionScenario(const QString &name)
-{
-    QList<QByteArray> scenario;
     const Collection collection = Collection::retrieveByName(name);
-    scenario << "C: 3 UID SELECT SILENT " + QByteArray::number(collection.id());
-    scenario << "S: 3 OK Completed";
-    return scenario;
+    return {
+        TestScenario::create(2, TestScenario::ClientCmd,
+                             Protocol::SelectCollectionCommand(collection.id())),
+        TestScenario::create(2, TestScenario::ServerCmd,
+                             Protocol::SelectCollectionResponse())
+    };
 }
 
-QList<QByteArray> FakeAkonadiServer::selectResourceScenario(const QString &name)
+TestScenario::List FakeAkonadiServer::selectResourceScenario(const QString &name)
 {
-    QList<QByteArray> scenario;
     const Resource resource = Resource::retrieveByName(name);
-    scenario << "C: 2 RESSELECT " + resource.name().toLatin1();
-    scenario << "S: 2 OK " + resource.name().toLatin1() + " selected";
-    return scenario;
+    return {
+        TestScenario::create(3, TestScenario::ClientCmd,
+                             Protocol::SelectResourceCommand(resource.name())),
+        TestScenario::create(3, TestScenario::ServerCmd,
+                             Protocol::SelectResourceResponse())
+    };
 }
 
 bool FakeAkonadiServer::init()
@@ -241,9 +233,9 @@ bool FakeAkonadiServer::quit()
     return true;
 }
 
-void FakeAkonadiServer::setScenario(const QList<QByteArray> &scenario)
+void FakeAkonadiServer::setScenarios(const TestScenario::List &scenarios)
 {
-    mClient->setScenario(scenario);
+    mClient->setScenarios(scenarios);
 }
 
 void FakeAkonadiServer::incomingConnection(quintptr socketDescriptor)
@@ -282,7 +274,7 @@ void FakeAkonadiServer::runTest()
 
 FakeDataStore *FakeAkonadiServer::dataStore() const
 {
-    Q_ASSERT_X(mDataStore, "FakeAkonadiServer::connection()",
+    Q_ASSERT_X(mDataStore, "FakeAkonadiServer::dataStore()",
                "You have to call FakeAkonadiServer::start() first");
     return mDataStore;
 }
diff --git a/autotests/server/fakeakonadiserver.h b/autotests/server/fakeakonadiserver.h
index 3fb48b2..1aa4aa7 100644
--- a/autotests/server/fakeakonadiserver.h
+++ b/autotests/server/fakeakonadiserver.h
@@ -24,19 +24,81 @@
 #include "exception.h"
 
 #include <QSignalSpy>
+#include <QBuffer>
+#include <QDataStream>
+
+#include <type_traits>
+
+#include <private/protocol_p.h>
 
 class QLocalServer;
 class QEventLoop;
 
-Q_DECLARE_METATYPE(QList<QByteArray>)
-
 namespace Akonadi {
 namespace Server {
 
-class FakeClient;
 class FakeSearchManager;
 class FakeDataStore;
 class FakeConnection;
+class FakeClient;
+
+class TestScenario {
+public:
+    typedef QList<TestScenario> List;
+
+    enum Action {
+        ServerCmd,
+        ClientCmd,
+        Wait,
+        Quit
+    };
+
+    Action action;
+    QByteArray data;
+
+    template<typename T>
+    static typename std::enable_if<std::is_base_of<Protocol::Response, T>::value, TestScenario>::type
+    create(qint64 tag, Action action, const T &response) {
+        TestScenario sc;
+        sc.action = action;
+        QDataStream stream(&sc.data, QIODevice::WriteOnly);
+        stream << tag
+               << response;
+
+        QDataStream os(sc.data);
+        qint64 vTag;
+        os >> vTag;
+        Protocol::Command cmd = Protocol::Factory::fromStream(os);
+
+        Q_ASSERT(vTag == tag);
+        Q_ASSERT(cmd.type() == response.type());
+        Q_ASSERT(cmd.isResponse() == response.isResponse());
+        Q_ASSERT(cmd == response);
+        return sc;
+    }
+
+    template<typename T>
+    static typename std::enable_if<std::is_base_of<Protocol::Response, T>::value == false, \
TestScenario>::type +    create(qint64 tag, Action action, const T &command, int */* dummy */ = 0)
+    {
+        TestScenario sc;
+        sc.action = action;
+        QDataStream stream(&sc.data, QIODevice::WriteOnly);
+        stream << tag
+               << command;
+        return sc;
+    }
+
+    static TestScenario wait(int timeout)
+    {
+        return TestScenario { Wait, QByteArray::number(timeout) };
+    }
+
+    static TestScenario quit()
+    {
+        return TestScenario { Quit, QByteArray() };
+    }
+};
 
 /**
  * A fake server used for testing. Losely based on KIMAP::FakeServer
@@ -61,13 +123,12 @@ public:
     static QString basePath();
     static QString socketFile();
     static QString instanceName();
-    static QList<QByteArray> loginScenario();
-    static QList<QByteArray> defaultScenario();
-    static QList<QByteArray> customCapabilitiesScenario(const QList<QByteArray> &capabilities);
-    static QList<QByteArray> selectCollectionScenario(const QString &name);
-    static QList<QByteArray> selectResourceScenario(const QString &name);
 
-    void setScenario(const QList<QByteArray> &scenario);
+    static TestScenario::List loginScenario();
+    static TestScenario::List selectCollectionScenario(const QString &name);
+    static TestScenario::List selectResourceScenario(const QString &name);
+
+    void setScenarios(const TestScenario::List &scenarios);
 
     void runTest();
 
@@ -103,4 +164,7 @@ AKONADI_EXCEPTION_MAKE_INSTANCE(FakeAkonadiServerException);
 }
 }
 
+Q_DECLARE_METATYPE(Akonadi::Server::TestScenario)
+Q_DECLARE_METATYPE(Akonadi::Server::TestScenario::List)
+
 #endif // FAKEAKONADISERVER_H
diff --git a/autotests/server/fakeclient.cpp b/autotests/server/fakeclient.cpp
index 3557951..2f3a5d5 100644
--- a/autotests/server/fakeclient.cpp
+++ b/autotests/server/fakeclient.cpp
@@ -21,6 +21,7 @@
 #include "fakeakonadiserver.h"
 
 #include <shared/akdebug.h>
+#include <private/protocol_p.h>
 
 #include <QTest>
 #include <QMutexLocker>
@@ -42,6 +43,7 @@ do {\
     }\
 } while (0)
 
+using namespace Akonadi;
 using namespace Akonadi::Server;
 
 FakeClient::FakeClient(QObject *parent)
@@ -54,47 +56,50 @@ FakeClient::~FakeClient()
 {
 }
 
-void FakeClient::setScenario(const QList<QByteArray> &scenario)
+void FakeClient::setScenarios(const TestScenario::List &scenarios)
 {
-    mScenario = scenario;
+    mScenarios = scenarios;
 }
 
 bool FakeClient::isScenarioDone() const
 {
     QMutexLocker locker(&mMutex);
-    return mScenario.isEmpty();
+    return mScenarios.isEmpty();
 }
 
 void FakeClient::dataAvailable()
 {
     QMutexLocker locker(&mMutex);
 
-    CLIENT_VERIFY(!mScenario.isEmpty());
+    CLIENT_VERIFY(!mScenarios.isEmpty());
 
+    qDebug() << mSocket->bytesAvailable();
     readServerPart();
     writeClientPart();
 }
 
 void FakeClient::readServerPart()
 {
-    while (!mScenario.isEmpty() && mScenario.first().startsWith("S: ")) {
-        if (mScenario.first().startsWith("S: IGNORE")) {
-            QByteArray command = mScenario.takeFirst();
-            command = command.mid(9).trimmed();
-            const int count = command.toInt();
-            for (int i = 0; i < count; i++) {
-                mStreamParser->readUntilCommandEnd();
-            }
-            continue;
-        }
-        const QByteArray received = "S: " + mStreamParser->readUntilCommandEnd();
-        const QByteArray expected = mScenario.takeFirst() + "\r\n";
-        CLIENT_COMPARE(QString::fromUtf8(received), QString::fromUtf8(expected));
-        CLIENT_COMPARE(received, expected);
+    while (!mScenarios.isEmpty() && mScenarios.at(0).action == TestScenario::ServerCmd) {
+        TestScenario scenario = mScenarios.takeFirst();
+        QDataStream expectedStream(scenario.data);
+        qint64 expectedTag, actualTag;
+        Protocol::Command expectedCommand, actualCommand;
+
+        expectedStream >> expectedTag;
+        mStream >> actualTag;
+        CLIENT_COMPARE(actualTag, expectedTag);
+
+        expectedCommand = Protocol::Factory::fromStream(expectedStream);
+        actualCommand = Protocol::Factory::fromStream(mStream);
+
+        CLIENT_COMPARE(actualCommand.type(), expectedCommand.type());
+        CLIENT_COMPARE(actualCommand.isResponse(), expectedCommand.isResponse());
+        CLIENT_COMPARE(actualCommand, expectedCommand);
     }
 
-    if (!mScenario.isEmpty()) {
-        CLIENT_VERIFY(mScenario.first().startsWith("C: "));
+    if (!mScenarios.isEmpty()) {
+        CLIENT_VERIFY(mScenarios.at(0).action == TestScenario::ClientCmd);
     } else {
         // Server replied and there's nothing else to send, then quit
         quit();
@@ -103,24 +108,24 @@ void FakeClient::readServerPart()
 
 void FakeClient::writeClientPart()
 {
-    while (!mScenario.isEmpty() && (mScenario.first().startsWith("C: ") || \
                mScenario.first().startsWith("W: "))) {
-        const QByteArray rule = mScenario.takeFirst();
+    while (!mScenarios.isEmpty() && (mScenarios.at(0).action == TestScenario::ClientCmd
+            || mScenarios.at(0).action == TestScenario::Wait)) {
+        const TestScenario rule = mScenarios.takeFirst();
 
-        if (rule.startsWith("C: ")) {
-            const QByteArray payload = rule.mid(3);
-            mSocket->write(payload + "\n");
+       if (rule.action == TestScenario::ClientCmd) {
+            mSocket->write(rule.data);
         } else {
-            const int timeout = rule.mid(3).toInt();
+            const int timeout = rule.data.toInt();
             QTest::qWait(timeout);
         }
     }
 
-    if (!mScenario.isEmpty() && mScenario.first().startsWith("X:")) {
+    if (!mScenarios.isEmpty() && mScenarios.at(0).action == TestScenario::Quit) {
         mSocket->close();
     }
 
-    if (!mScenario.isEmpty()) {
-        CLIENT_VERIFY(mScenario.first().startsWith("S: "));
+    if (!mScenarios.isEmpty()) {
+        CLIENT_VERIFY(mScenarios.at(0).action == TestScenario::ServerCmd);
     }
 }
 
diff --git a/autotests/server/fakeclient.h b/autotests/server/fakeclient.h
index 1fdcf07..7fcc6ff 100644
--- a/autotests/server/fakeclient.h
+++ b/autotests/server/fakeclient.h
@@ -24,6 +24,8 @@
 #include <QMutex>
 #include <QDataStream>
 
+#include "fakeakonadiserver.h"
+
 class QLocalSocket;
 
 namespace Akonadi {
@@ -34,10 +36,11 @@ class FakeClient : public QThread
     Q_OBJECT
 
 public:
+
     FakeClient(QObject *parent = 0);
     ~FakeClient();
 
-    void setScenario(const QList<QByteArray> &scenario);
+    void setScenarios(const TestScenario::List &scenarios);
 
     bool isScenarioDone() const;
 
@@ -53,11 +56,12 @@ private Q_SLOTS:
 private:
     mutable QMutex mMutex;
 
-    QList<QByteArray> mScenario;
+    TestScenario::List mScenarios;
     QLocalSocket *mSocket;
     QDataStream mStream;
 };
 }
 }
 
+
 #endif // AKONADI_SERVER_FAKECLIENT_H


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic