1 /* 2 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 3 SPDX-FileCopyrightText: 2020 Harald Sitter <sitter@kde.org> 4 */ 5 6 #include <QTest> 7 8 #include <future> 9 #include <thread> 10 11 #include "transfer.h" 12 13 class TransferTest : public QObject 14 { 15 Q_OBJECT 16 private Q_SLOTS: testSegmentOnSmallFile()17 void testSegmentOnSmallFile() 18 { 19 // Files smaller than our minimal segment size ought to be transferred in one go 20 // otherwise we have a chance of degrading performance. 21 QCOMPARE(TransferSegment(1).buf.size(), 1); 22 } 23 testMaxSegment()24 void testMaxSegment() 25 { 26 // Large files may only use up to a given maximum. 27 QCOMPARE(TransferSegment(512 * 1024 * 1024).buf.size(), c_maxSegmentSize); 28 } 29 testIdealSegmentSize()30 void testIdealSegmentSize() 31 { 32 QCOMPARE(TransferSegment(64 * 1024 * 1024).buf.size(), 1342177); 33 } 34 testSegment()35 void testSegment() 36 { 37 TransferSegment s(8); 38 QCOMPARE(s.buf.size(), 8); 39 memset(s.buf.data(), 1, 8); 40 QCOMPARE(s.buf.data()[0], 1); 41 } 42 testRing()43 void testRing() 44 { 45 TransferRingBuffer ring(8); 46 for (auto i = 0; i <= 32; ++i) { 47 { 48 auto s = ring.nextFree(); 49 memset(s->buf.data(), i, 8); 50 ring.push(); 51 } 52 { 53 auto s = ring.pop(); 54 QCOMPARE(s->buf.data()[0], static_cast<char>(i)); 55 ring.unpop(); 56 } 57 } 58 } 59 testRingThreadedSlowPush()60 void testRingThreadedSlowPush() 61 { 62 const auto runs = 127; 63 const auto fileSize = 8; 64 TransferRingBuffer ring(fileSize); 65 66 std::atomic<bool> abort(false); 67 68 auto pullFuture = std::async(std::launch::async, [&ring, &abort]() -> bool { 69 for (auto i = 0; i <= runs && !abort; ++i) { 70 auto s = ring.pop(); 71 if (!QTest::qCompare(s->buf.data()[0], static_cast<char>(i), 72 qPrintable(QStringLiteral("On pull iteration %1").arg(i)), "", 73 __FILE__, __LINE__)) { 74 abort = true; 75 return false; 76 } 77 ring.unpop(); 78 } 79 return true; 80 }); 81 82 auto pushFuture = std::async(std::launch::async, [&ring, &abort]() -> bool { 83 for (auto i = 0; i <= runs && !abort; ++i) { 84 auto s = ring.nextFree(); 85 memset(s->buf.data(), i, fileSize); 86 ring.push(); 87 if (abort) { 88 ring.done(); 89 return false; 90 } 91 // Slow down this thread to simulate slow network reads. 92 std::this_thread::sleep_for(std::chrono::milliseconds(5)); 93 } 94 ring.done(); 95 return true; 96 }); 97 98 pushFuture.wait(); 99 pullFuture.wait(); 100 101 QVERIFY(pushFuture.get()); 102 QVERIFY(pullFuture.get()); 103 } 104 testRingThreadedSlowPull()105 void testRingThreadedSlowPull() 106 { 107 const auto runs = 127; 108 const auto fileSize = 8; 109 TransferRingBuffer ring(fileSize); 110 111 std::atomic<bool> abort(false); 112 113 auto pullFuture = std::async(std::launch::async, [&ring, &abort]() -> bool { 114 for (auto i = 0; i <= runs && !abort; ++i) { 115 auto s = ring.pop(); 116 if (!QTest::qCompare(s->buf.data()[0], static_cast<char>(i), 117 qPrintable(QStringLiteral("On pull iteration %1").arg(i)), "", 118 __FILE__, __LINE__)) { 119 abort = true; 120 } 121 // Slow down this thread to simulate slow local writes. 122 std::this_thread::sleep_for(std::chrono::milliseconds(5)); 123 ring.unpop(); 124 } 125 return true; 126 }); 127 128 auto pushFuture = std::async(std::launch::async, [&ring, &abort]() -> bool { 129 for (auto i = 0; i <= runs && !abort; ++i) { 130 auto s = ring.nextFree(); 131 memset(s->buf.data(), i, fileSize); 132 if (abort) { 133 ring.done(); 134 return false; 135 } 136 ring.push(); 137 } 138 ring.done(); 139 return true; 140 }); 141 142 pushFuture.wait(); 143 pullFuture.wait(); 144 145 QVERIFY(pushFuture.get()); 146 QVERIFY(pullFuture.get()); 147 } 148 }; 149 150 QTEST_GUILESS_MAIN(TransferTest) 151 152 #include "transfertest.moc" 153