File indexing completed on 2024-11-10 04:40:21
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Daniel Vrátil <dvratil@redhat.com> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-or-later 0005 * 0006 */ 0007 0008 #include <QObject> 0009 0010 #include "aktest.h" 0011 #include "entities.h" 0012 #include "fakeakonadiserver.h" 0013 #include "fakeconnection.h" 0014 0015 #include "private/externalpartstorage_p.h" 0016 #include "private/standarddirs_p.h" 0017 0018 #include "storage/parthelper.h" 0019 #include "storage/partstreamer.h" 0020 0021 #include <QDir> 0022 #include <QSettings> 0023 #include <QTest> 0024 0025 #include "private/scope_p.h" 0026 0027 using namespace Akonadi; 0028 using namespace Akonadi::Server; 0029 0030 Q_DECLARE_METATYPE(Akonadi::Server::PimItem) 0031 Q_DECLARE_METATYPE(Akonadi::Server::Part::Storage) 0032 0033 class PartStreamerTest : public QObject 0034 { 0035 Q_OBJECT 0036 0037 FakeAkonadiServer mAkonadi; 0038 0039 public: 0040 PartStreamerTest() 0041 { 0042 // Set a very small threshold for easier testing 0043 const QString serverConfigFile = StandardDirs::serverConfigFile(StandardDirs::ReadWrite); 0044 QSettings settings(serverConfigFile, QSettings::IniFormat); 0045 settings.setValue(QStringLiteral("General/SizeThreshold"), 5); 0046 0047 mAkonadi.init(); 0048 } 0049 0050 Protocol::ModifyItemsCommandPtr createCommand(const PimItem &item) 0051 { 0052 auto cmd = Protocol::ModifyItemsCommandPtr::create(item.id()); 0053 cmd->setParts({"PLD:DATA"}); 0054 return cmd; 0055 } 0056 0057 private Q_SLOTS: 0058 void testStreamer_data() 0059 { 0060 QTest::addColumn<TestScenario::List>("scenarios"); 0061 QTest::addColumn<QByteArray>("expectedPartName"); 0062 QTest::addColumn<QByteArray>("expectedPartData"); 0063 QTest::addColumn<QByteArray>("expectedFileData"); 0064 QTest::addColumn<qint64>("expectedPartSize"); 0065 QTest::addColumn<bool>("expectedChanged"); 0066 QTest::addColumn<Part::Storage>("storage"); 0067 QTest::addColumn<PimItem>("pimItem"); 0068 0069 PimItem item; 0070 item.setCollectionId(Collection::retrieveByName(QStringLiteral("Col A")).id()); 0071 item.setMimeType(MimeType::retrieveByName(QStringLiteral("application/octet-stream"))); 0072 item.setSize(1); // this will not match reality during the test, but that does not matter, as 0073 // that's not the subject of this test 0074 QVERIFY(item.insert()); 0075 0076 qint64 partId = -1; 0077 Part::List parts = Part::retrieveAll(); 0078 if (parts.isEmpty()) { 0079 partId = 0; 0080 } else { 0081 partId = parts.last().id() + 1; 0082 } 0083 0084 // Order of these tests matters! 0085 { 0086 TestScenario::List scenarios; 0087 scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item)) 0088 << TestScenario::create(5, 0089 TestScenario::ServerCmd, 0090 Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0091 << TestScenario::create(5, 0092 TestScenario::ClientCmd, 0093 Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 3))) 0094 << TestScenario::create(5, 0095 TestScenario::ServerCmd, 0096 Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0097 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "123")) 0098 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create(item.id(), 1)) 0099 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create()); 0100 0101 QTest::newRow("item 1, internal") << scenarios << QByteArray("PLD:DATA") << QByteArray("123") << QByteArray() << 3ll << true << Part::Internal 0102 << item; 0103 } 0104 0105 { 0106 TestScenario::List scenarios; 0107 scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item)) 0108 << TestScenario::create(5, 0109 TestScenario::ServerCmd, 0110 Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0111 << TestScenario::create(5, 0112 TestScenario::ClientCmd, 0113 Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 9))) 0114 << TestScenario::create( 0115 5, 0116 TestScenario::ServerCmd, 0117 Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data, QStringLiteral("%1_r0").arg(partId))) 0118 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA")) 0119 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create(item.id(), 2)) 0120 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create()); 0121 0122 QTest::newRow("item 1, change to external") 0123 << scenarios << QByteArray("PLD:DATA") << QByteArray("15_r0") << QByteArray("123456789") << 9ll << true << Part::External << item; 0124 } 0125 0126 { 0127 TestScenario::List scenarios; 0128 scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item)) 0129 << TestScenario::create(5, 0130 TestScenario::ServerCmd, 0131 Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0132 << TestScenario::create(5, 0133 TestScenario::ClientCmd, 0134 Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 9))) 0135 << TestScenario::create( 0136 5, 0137 TestScenario::ServerCmd, 0138 Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data, QStringLiteral("%1_r1").arg(partId))) 0139 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA")) 0140 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create(item.id(), 3)) 0141 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create()); 0142 0143 QTest::newRow("item 1, update external") << scenarios << QByteArray("PLD:DATA") << QByteArray("15_r1") << QByteArray("987654321") << 9ll << true 0144 << Part::External << item; 0145 } 0146 0147 { 0148 TestScenario::List scenarios; 0149 scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item)) 0150 << TestScenario::create(5, 0151 TestScenario::ServerCmd, 0152 Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0153 << TestScenario::create(5, 0154 TestScenario::ClientCmd, 0155 Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 9))) 0156 << TestScenario::create( 0157 5, 0158 TestScenario::ServerCmd, 0159 Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data, QStringLiteral("%1_r2").arg(partId))) 0160 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA")) 0161 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create(item.id(), 4)) 0162 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create()); 0163 0164 QTest::newRow("item 1, external, no change") 0165 << scenarios << QByteArray("PLD:DATA") << QByteArray("15_r2") << QByteArray("987654321") << 9ll << false << Part::External << item; 0166 } 0167 0168 { 0169 TestScenario::List scenarios; 0170 scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item)) 0171 << TestScenario::create(5, 0172 TestScenario::ServerCmd, 0173 Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0174 << TestScenario::create(5, 0175 TestScenario::ClientCmd, 0176 Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 4))) 0177 << TestScenario::create(5, 0178 TestScenario::ServerCmd, 0179 Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0180 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "1234")) 0181 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create(item.id(), 5)) 0182 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create()); 0183 0184 QTest::newRow("item 1, change to internal") 0185 << scenarios << QByteArray("PLD:DATA") << QByteArray("1234") << QByteArray() << 4ll << true << Part::Internal << item; 0186 } 0187 0188 { 0189 TestScenario::List scenarios; 0190 scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item)) 0191 << TestScenario::create(5, 0192 TestScenario::ServerCmd, 0193 Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0194 << TestScenario::create(5, 0195 TestScenario::ClientCmd, 0196 Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 4))) 0197 << TestScenario::create(5, 0198 TestScenario::ServerCmd, 0199 Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0200 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", "1234")) 0201 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create(item.id(), 6)) 0202 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create()); 0203 0204 QTest::newRow("item 1, internal, no change") 0205 << scenarios << QByteArray("PLD:DATA") << QByteArray("1234") << QByteArray() << 4ll << false << Part::Internal << item; 0206 } 0207 0208 // Insert new item 0209 PimItem item2 = item; 0210 QVERIFY(item2.insert()); 0211 0212 const QString foreignPath = FakeAkonadiServer::basePath() + QStringLiteral("/tmp/foreignPayloadFile"); 0213 { 0214 TestScenario::List scenarios; 0215 scenarios << FakeAkonadiServer::loginScenario() << TestScenario::create(5, TestScenario::ClientCmd, createCommand(item2)) 0216 << TestScenario::create(5, 0217 TestScenario::ServerCmd, 0218 Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::MetaData)) 0219 << TestScenario::create( 0220 5, 0221 TestScenario::ClientCmd, 0222 Protocol::StreamPayloadResponsePtr::create("PLD:DATA", Protocol::PartMetaData("PLD:DATA", 3, 0, Protocol::PartMetaData::Foreign))) 0223 << TestScenario::create(5, 0224 TestScenario::ServerCmd, 0225 Protocol::StreamPayloadCommandPtr::create("PLD:DATA", Protocol::StreamPayloadCommand::Data)) 0226 << TestScenario::create(5, TestScenario::ClientCmd, Protocol::StreamPayloadResponsePtr::create("PLD:DATA", foreignPath.toUtf8())) 0227 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create(item2.id(), 1)) 0228 << TestScenario::create(5, TestScenario::ServerCmd, Protocol::ModifyItemsResponsePtr::create()); 0229 0230 QTest::newRow("item 2, new foreign part") << scenarios << QByteArray("PLD:DATA") << foreignPath.toUtf8() << QByteArray("123") << 3ll << false 0231 << Part::Foreign << item2; 0232 } 0233 } 0234 0235 void testStreamer() 0236 { 0237 QFETCH(TestScenario::List, scenarios); 0238 QFETCH(QByteArray, expectedPartName); 0239 QFETCH(QByteArray, expectedPartData); 0240 QFETCH(QByteArray, expectedFileData); 0241 QFETCH(qint64, expectedPartSize); 0242 QFETCH(Part::Storage, storage); 0243 QFETCH(PimItem, pimItem); 0244 0245 if (storage == Part::External) { 0246 // Create the payload file now, since don't have means to react 0247 // directly to the streaming command 0248 QFile file(ExternalPartStorage::resolveAbsolutePath(expectedPartData)); 0249 file.open(QIODevice::WriteOnly); 0250 file.write(expectedFileData); 0251 file.close(); 0252 } else if (storage == Part::Foreign) { 0253 // Create the foreign payload file 0254 QDir().mkpath(FakeAkonadiServer::basePath() + QStringLiteral("/tmp")); 0255 QFile file(QString::fromUtf8(expectedPartData)); 0256 file.open(QIODevice::WriteOnly); 0257 file.write(expectedFileData); 0258 file.close(); 0259 } 0260 0261 mAkonadi.setScenarios(scenarios); 0262 mAkonadi.runTest(); 0263 0264 PimItem item = PimItem::retrieveById(pimItem.id()); 0265 const QList<Part> parts = item.parts(); 0266 QVERIFY(parts.count() == 1); 0267 const Part part = parts[0]; 0268 QCOMPARE(part.datasize(), expectedPartSize); 0269 QCOMPARE(part.storage(), storage); 0270 const QByteArray data = part.data(); 0271 0272 if (storage == Part::External) { 0273 QCOMPARE(data, expectedPartData); 0274 QFile file(ExternalPartStorage::resolveAbsolutePath(data)); 0275 QVERIFY(file.exists()); 0276 QCOMPARE(file.size(), expectedPartSize); 0277 QVERIFY(file.open(QIODevice::ReadOnly)); 0278 0279 const QByteArray fileData = file.readAll(); 0280 QCOMPARE(fileData, expectedFileData); 0281 0282 // Make sure no previous versions are left behind in file_db_data 0283 const int revision = data.mid(data.indexOf("_r") + 2).toInt(); 0284 for (int i = 0; i < revision; ++i) { 0285 const QByteArray fileName = QByteArray::number(part.id()) + "_r" + QByteArray::number(i); 0286 const QString filePath = ExternalPartStorage::resolveAbsolutePath(fileName); 0287 // TRY because the deletion happens in another thread 0288 QTRY_VERIFY2(!QFile::exists(filePath), qPrintable(filePath)); 0289 } 0290 } else if (storage == Part::Foreign) { 0291 QCOMPARE(data, expectedPartData); 0292 QFile file(QString::fromUtf8(data)); 0293 QVERIFY(file.exists()); 0294 QCOMPARE(file.size(), expectedPartSize); 0295 QVERIFY(file.open(QIODevice::ReadOnly)); 0296 0297 const QByteArray fileData = file.readAll(); 0298 QCOMPARE(fileData, expectedFileData); 0299 } else { 0300 QCOMPARE(data, expectedPartData); 0301 0302 // Make sure nothing is left behind in file_db_data 0303 // TODO: we have no way of knowing what is the last revision 0304 for (int i = 0; i <= 100; ++i) { 0305 const QByteArray fileName = QByteArray::number(part.id()) + "_r" + QByteArray::number(i); 0306 const QString filePath = ExternalPartStorage::resolveAbsolutePath(fileName); 0307 QTRY_VERIFY2(!QFile::exists(filePath), qPrintable(filePath)); 0308 } 0309 } 0310 } 0311 }; 0312 0313 AKTEST_FAKESERVER_MAIN(PartStreamerTest) 0314 0315 #include "partstreamertest.moc"