testcfapishellextensionsipc.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * This software is in the public domain, furnished "as is", without technical
  3. * support, and with no warranty, express or implied, as to its usefulness for
  4. * any purpose.
  5. *
  6. */
  7. #include <QtTest>
  8. #include <QImage>
  9. #include <QPainter>
  10. #include "syncenginetestutils.h"
  11. #include "common/vfs.h"
  12. #include "common/shellextensionutils.h"
  13. #include "config.h"
  14. #include <syncengine.h>
  15. #include "folderman.h"
  16. #include "account.h"
  17. #include "accountstate.h"
  18. #include "accountmanager.h"
  19. #include "testhelper.h"
  20. #include "vfs/cfapi/shellext/thumbnailprovideripc.h"
  21. #include "shellextensionsserver.h"
  22. using namespace OCC;
  23. class TestCfApiShellExtensionsIPC : public QObject
  24. {
  25. Q_OBJECT
  26. FolderMan _fm;
  27. FakeFolder fakeFolder{FileInfo()};
  28. QScopedPointer<FakeQNAM> fakeQnam;
  29. OCC::AccountPtr account;
  30. OCC::AccountState* accountState;
  31. QScopedPointer<ShellExtensionsServer> _shellExtensionsServer;
  32. QStringList dummmyImageNames = {
  33. "A/photos/imageJpg.jpg",
  34. "A/photos/imagePng.png",
  35. "A/photos/imagePng.bmp",
  36. };
  37. QMap<QString, QByteArray> dummyImages;
  38. QString currentImage;
  39. private slots:
  40. void initTestCase()
  41. {
  42. VfsShellExtensions::ThumbnailProviderIpc::overrideServerName = VfsShellExtensions::serverNameForApplicationNameDefault();
  43. _shellExtensionsServer.reset(new ShellExtensionsServer);
  44. for (const auto &dummyImageName : dummmyImageNames) {
  45. const auto extension = dummyImageName.split(".").last();
  46. const auto format = dummyImageName.endsWith("PNG", Qt::CaseInsensitive) ? QImage::Format_ARGB32 : QImage::Format_RGB32;
  47. QImage image(QSize(640, 480), format);
  48. QPainter painter(&image);
  49. painter.setBrush(QBrush(Qt::red));
  50. painter.fillRect(QRectF(0, 0, 640, 480), Qt::red);
  51. QByteArray byteArray;
  52. QBuffer buffer(&byteArray);
  53. buffer.open(QIODevice::WriteOnly);
  54. image.save(&buffer, extension.toStdString().c_str());
  55. dummyImages.insert(dummyImageName, byteArray);
  56. }
  57. fakeQnam.reset(new FakeQNAM({}));
  58. account = OCC::Account::create();
  59. account->setCredentials(new FakeCredentials{fakeQnam.data()});
  60. account->setUrl(QUrl(("http://example.de")));
  61. accountState = new OCC::AccountState(account);
  62. OCC::AccountManager::instance()->addAccount(account);
  63. FolderMan *folderman = FolderMan::instance();
  64. QCOMPARE(folderman, &_fm);
  65. QVERIFY(folderman->addFolder(accountState, folderDefinition(fakeFolder.localPath())));
  66. fakeQnam->setOverride(
  67. [this](QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice *device) {
  68. Q_UNUSED(device);
  69. QNetworkReply *reply = nullptr;
  70. const auto urlQuery = QUrlQuery(req.url());
  71. const auto fileId = urlQuery.queryItemValue(QStringLiteral("fileId"));
  72. const auto x = urlQuery.queryItemValue(QStringLiteral("x")).toInt();
  73. const auto y = urlQuery.queryItemValue(QStringLiteral("y")).toInt();
  74. const auto path = req.url().path();
  75. if (fileId.isEmpty() || x <= 0 || y <= 0) {
  76. reply = new FakePayloadReply(op, req, {}, nullptr);
  77. } else {
  78. const auto foundImageIt = dummyImages.find(currentImage);
  79. QByteArray byteArray;
  80. if (foundImageIt != dummyImages.end()) {
  81. byteArray = foundImageIt.value();
  82. }
  83. currentImage.clear();
  84. auto fakePayloadReply = new FakePayloadReply(op, req, byteArray, nullptr);
  85. QMap<QNetworkRequest::KnownHeaders, QByteArray> additionalHeaders = {
  86. {QNetworkRequest::KnownHeaders::ContentTypeHeader, "image/jpeg"}};
  87. fakePayloadReply->_additionalHeaders = additionalHeaders;
  88. reply = fakePayloadReply;
  89. }
  90. return reply;
  91. });
  92. };
  93. void testRequestThumbnails()
  94. {
  95. FolderMan *folderman = FolderMan::instance();
  96. QVERIFY(folderman);
  97. auto folder = FolderMan::instance()->folderForPath(fakeFolder.localPath());
  98. QVERIFY(folder);
  99. folder->setVirtualFilesEnabled(true);
  100. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  101. ItemCompletedSpy completeSpy(fakeFolder);
  102. auto cleanup = [&]() {
  103. completeSpy.clear();
  104. };
  105. cleanup();
  106. // Create a virtual file for remote files
  107. fakeFolder.remoteModifier().mkdir("A");
  108. fakeFolder.remoteModifier().mkdir("A/photos");
  109. for (const auto &dummyImageName : dummmyImageNames) {
  110. fakeFolder.remoteModifier().insert(dummyImageName, 256);
  111. }
  112. QVERIFY(fakeFolder.syncOnce());
  113. QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
  114. cleanup();
  115. // just add records from fake folder's journal to real one's to make test work
  116. SyncJournalFileRecord record;
  117. auto realFolder = FolderMan::instance()->folderForPath(fakeFolder.localPath());
  118. QVERIFY(realFolder);
  119. for (const auto &dummyImageName : dummmyImageNames) {
  120. if (fakeFolder.syncJournal().getFileRecord(dummyImageName, &record)) {
  121. realFolder->journalDb()->setFileRecord(record);
  122. }
  123. }
  124. // #1 Test every fake image fetching. Everything must succeed.
  125. for (const auto &dummyImageName : dummmyImageNames) {
  126. QEventLoop loop;
  127. QByteArray thumbnailReplyData;
  128. currentImage = dummyImageName;
  129. // emulate thumbnail request from a separate thread (just like the real shell extension does)
  130. std::thread t([&] {
  131. VfsShellExtensions::ThumbnailProviderIpc thumbnailProviderIpc;
  132. thumbnailReplyData = thumbnailProviderIpc.fetchThumbnailForFile(
  133. fakeFolder.localPath() + dummyImageName, QSize(256, 256));
  134. QMetaObject::invokeMethod(&loop, &QEventLoop::quit, Qt::QueuedConnection);
  135. });
  136. loop.exec();
  137. t.detach();
  138. QVERIFY(!thumbnailReplyData.isEmpty());
  139. const auto imageFromData = QImage::fromData(thumbnailReplyData);
  140. QVERIFY(!imageFromData.isNull());
  141. }
  142. // #2 Test wrong image fetching. It must fail.
  143. QEventLoop loop;
  144. QByteArray thumbnailReplyData;
  145. std::thread t1([&] {
  146. VfsShellExtensions::ThumbnailProviderIpc thumbnailProviderIpc;
  147. thumbnailReplyData = thumbnailProviderIpc.fetchThumbnailForFile(
  148. fakeFolder.localPath() + QString("A/photos/wrong.jpg"), QSize(256, 256));
  149. QMetaObject::invokeMethod(&loop, &QEventLoop::quit, Qt::QueuedConnection);
  150. });
  151. loop.exec();
  152. t1.detach();
  153. QVERIFY(thumbnailReplyData.isEmpty());
  154. // #3 Test one image fetching, but set incorrect size. It must fail.
  155. currentImage = dummyImages.keys().first();
  156. std::thread t2([&] {
  157. VfsShellExtensions::ThumbnailProviderIpc thumbnailProviderIpc;
  158. thumbnailReplyData = thumbnailProviderIpc.fetchThumbnailForFile(fakeFolder.localPath() + currentImage, {});
  159. QMetaObject::invokeMethod(&loop, &QEventLoop::quit, Qt::QueuedConnection);
  160. });
  161. loop.exec();
  162. t2.detach();
  163. QVERIFY(thumbnailReplyData.isEmpty());
  164. }
  165. void cleanupTestCase()
  166. {
  167. VfsShellExtensions::ThumbnailProviderIpc::overrideServerName.clear();
  168. if (auto folder = FolderMan::instance()->folderForPath(fakeFolder.localPath())) {
  169. folder->setVirtualFilesEnabled(false);
  170. }
  171. FolderMan::instance()->unloadAndDeleteAllFolders();
  172. if (auto accountToDelete = OCC::AccountManager::instance()->accounts().first()) {
  173. OCC::AccountManager::instance()->deleteAccount(accountToDelete.data());
  174. }
  175. }
  176. };
  177. QTEST_GUILESS_MAIN(TestCfApiShellExtensionsIPC)
  178. #include "testcfapishellextensionsipc.moc"