File indexing completed on 2024-05-12 04:59:53

0001 /*
0002     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0003     SPDX-FileCopyrightText: 2020 Harald Sitter <sitter@kde.org>
0004 */
0005 
0006 #include <QTest>
0007 
0008 #include <future>
0009 #include <thread>
0010 
0011 #include "transfer.h"
0012 
0013 class TransferTest : public QObject
0014 {
0015     Q_OBJECT
0016 private Q_SLOTS:
0017     void testSegmentOnSmallFile()
0018     {
0019         // Files smaller than our minimal segment size ought to be transferred in one go
0020         // otherwise we have a chance of degrading performance.
0021         QCOMPARE(TransferSegment(1).buf.size(), 1);
0022     }
0023 
0024     void testMaxSegment()
0025     {
0026         // Large files may only use up to a given maximum.
0027         QCOMPARE(TransferSegment(512 * 1024 * 1024).buf.size(), c_maxSegmentSize);
0028     }
0029 
0030     void testIdealSegmentSize()
0031     {
0032         QCOMPARE(TransferSegment(64 * 1024 * 1024).buf.size(), 1342177);
0033     }
0034 
0035     void testSegment()
0036     {
0037         TransferSegment s(8);
0038         QCOMPARE(s.buf.size(), 8);
0039         memset(s.buf.data(), 1, 8);
0040         QCOMPARE(s.buf.data()[0], 1);
0041     }
0042 
0043     void testRing()
0044     {
0045         TransferRingBuffer ring(8);
0046         for (auto i = 0; i <= 32; ++i) {
0047             {
0048                 auto s = ring.nextFree();
0049                 memset(s->buf.data(), i, 8);
0050                 ring.push();
0051             }
0052             {
0053                 auto s = ring.pop();
0054                 QCOMPARE(s->buf.data()[0], static_cast<char>(i));
0055                 ring.unpop();
0056             }
0057         }
0058     }
0059 
0060     void testRingThreadedSlowPush()
0061     {
0062         const auto runs = 127;
0063         const auto fileSize = 8;
0064         TransferRingBuffer ring(fileSize);
0065 
0066         std::atomic<bool> abort(false);
0067 
0068         auto pullFuture = std::async(std::launch::async, [&ring, &abort]() -> bool {
0069             for (auto i = 0; i <= runs && !abort; ++i) {
0070                 auto s = ring.pop();
0071                 if (!QTest::qCompare(s->buf.data()[0],
0072                                      static_cast<char>(i),
0073                                      qPrintable(QStringLiteral("On pull iteration %1").arg(i)),
0074                                      "",
0075                                      __FILE__,
0076                                      __LINE__)) {
0077                     abort = true;
0078                     return false;
0079                 }
0080                 ring.unpop();
0081             }
0082             return true;
0083         });
0084 
0085         auto pushFuture = std::async(std::launch::async, [&ring, &abort]() -> bool {
0086             for (auto i = 0; i <= runs && !abort; ++i) {
0087                 auto s = ring.nextFree();
0088                 memset(s->buf.data(), i, fileSize);
0089                 ring.push();
0090                 if (abort) {
0091                     ring.done();
0092                     return false;
0093                 }
0094                 // Slow down this thread to simulate slow network reads.
0095                 std::this_thread::sleep_for(std::chrono::milliseconds(5));
0096             }
0097             ring.done();
0098             return true;
0099         });
0100 
0101         pushFuture.wait();
0102         pullFuture.wait();
0103 
0104         QVERIFY(pushFuture.get());
0105         QVERIFY(pullFuture.get());
0106     }
0107 
0108     void testRingThreadedSlowPull()
0109     {
0110         const auto runs = 127;
0111         const auto fileSize = 8;
0112         TransferRingBuffer ring(fileSize);
0113 
0114         std::atomic<bool> abort(false);
0115 
0116         auto pullFuture = std::async(std::launch::async, [&ring, &abort]() -> bool {
0117             for (auto i = 0; i <= runs && !abort; ++i) {
0118                 auto s = ring.pop();
0119                 if (!QTest::qCompare(s->buf.data()[0],
0120                                      static_cast<char>(i),
0121                                      qPrintable(QStringLiteral("On pull iteration %1").arg(i)),
0122                                      "",
0123                                      __FILE__,
0124                                      __LINE__)) {
0125                     abort = true;
0126                 }
0127                 // Slow down this thread to simulate slow local writes.
0128                 std::this_thread::sleep_for(std::chrono::milliseconds(5));
0129                 ring.unpop();
0130             }
0131             return true;
0132         });
0133 
0134         auto pushFuture = std::async(std::launch::async, [&ring, &abort]() -> bool {
0135             for (auto i = 0; i <= runs && !abort; ++i) {
0136                 auto s = ring.nextFree();
0137                 memset(s->buf.data(), i, fileSize);
0138                 if (abort) {
0139                     ring.done();
0140                     return false;
0141                 }
0142                 ring.push();
0143             }
0144             ring.done();
0145             return true;
0146         });
0147 
0148         pushFuture.wait();
0149         pullFuture.wait();
0150 
0151         QVERIFY(pushFuture.get());
0152         QVERIFY(pullFuture.get());
0153     }
0154 };
0155 
0156 QTEST_GUILESS_MAIN(TransferTest)
0157 
0158 #include "transfertest.moc"