File indexing completed on 2025-01-05 04:37:21

0001 /*
0002     SPDX-FileCopyrightText: 2010 Joris Guisson <joris.guisson@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include <QObject>
0008 #include <QtTest>
0009 #include <ctime>
0010 #include <interfaces/peerinterface.h>
0011 #include <peer/chunkcounter.h>
0012 #include <peer/superseeder.h>
0013 #include <util/log.h>
0014 
0015 using namespace bt;
0016 
0017 #define NUM_CHUNKS 10
0018 #define INVALID_CHUNK 0xFFFFFFFF
0019 
0020 static int peer_cnt = 0;
0021 
0022 class DummyPeer : public PeerInterface
0023 {
0024 public:
0025     DummyPeer()
0026         : PeerInterface(PeerID(), NUM_CHUNKS)
0027     {
0028         QString name = QStringLiteral("%1").arg(peer_cnt++);
0029         if (name.size() < 20)
0030             name = name.leftJustified(20, QLatin1Char(' '));
0031         peer_id = PeerID(name.toLatin1().constData());
0032         allowed_chunk = INVALID_CHUNK;
0033         allow_called = false;
0034     }
0035 
0036     ~DummyPeer() override
0037     {
0038     }
0039 
0040     void reset()
0041     {
0042         pieces.setAll(false);
0043         allowed_chunk = INVALID_CHUNK;
0044     }
0045 
0046     void have(Uint32 chunk)
0047     {
0048         pieces.set(chunk, true);
0049     }
0050 
0051     void haveAll()
0052     {
0053         pieces.setAll(true);
0054     }
0055 
0056     void kill() override
0057     {
0058         killed = true;
0059     }
0060 
0061     Uint32 averageDownloadSpeed() const override
0062     {
0063         return 0;
0064     }
0065 
0066     void chunkAllowed(Uint32 chunk) override
0067     {
0068         allowed_chunk = chunk;
0069         allow_called = true;
0070     }
0071 
0072     void handlePacket(const bt::Uint8 *packet, Uint32 size) override
0073     {
0074         Q_UNUSED(packet);
0075         Q_UNUSED(size);
0076     }
0077 
0078     Uint32 allowed_chunk;
0079     bool allow_called;
0080 };
0081 
0082 class SuperSeedTest : public QObject
0083 {
0084     Q_OBJECT
0085 public:
0086     SuperSeedTest(QObject *parent = nullptr)
0087         : QObject(parent)
0088     {
0089     }
0090 
0091     bool allowCalled(PeerInterface *peer)
0092     {
0093         return ((DummyPeer *)peer)->allow_called && ((DummyPeer *)peer)->allowed_chunk != INVALID_CHUNK;
0094     }
0095 
0096 private Q_SLOTS:
0097     void initTestCase()
0098     {
0099         bt::InitLog("superseedtest.log");
0100         allow_called = false;
0101     }
0102 
0103     void cleanupTestCase()
0104     {
0105     }
0106 
0107     void testSuperSeeding()
0108     {
0109         Out(SYS_GEN | LOG_DEBUG) << "testSuperSeeding" << endl;
0110         SuperSeeder ss(NUM_CHUNKS);
0111         // First test, all tree should get a chunk
0112         for (int i = 0; i < 3; i++) {
0113             DummyPeer *p = &peer[i];
0114             ss.peerAdded(p);
0115             QVERIFY(allowCalled(p));
0116             p->allow_called = false;
0117         }
0118 
0119         ss.dump();
0120 
0121         DummyPeer *uploader = &peer[0];
0122         DummyPeer *downloader = &peer[1];
0123         DummyPeer *next = &peer[2];
0124         // Simulate normal superseeding operation
0125         for (int i = 0; i < 4; i++) {
0126             Out(SYS_GEN | LOG_DEBUG) << "======================================" << endl;
0127             Uint32 prev_chunk = uploader->allowed_chunk;
0128             // Now simulate b downloaded the first chunk from a
0129             Uint32 chunk = prev_chunk;
0130 
0131             Out(SYS_GEN | LOG_DEBUG) << "uploader = " << uploader->getPeerID().toString() << endl;
0132             Out(SYS_GEN | LOG_DEBUG) << "downloader = " << downloader->getPeerID().toString() << endl;
0133             Out(SYS_GEN | LOG_DEBUG) << "chunk = " << chunk << endl;
0134 
0135             if (uploader->allowed_chunk == downloader->allowed_chunk) {
0136                 uploader->have(chunk);
0137                 downloader->have(chunk);
0138                 ss.have(downloader, chunk);
0139                 Out(SYS_GEN | LOG_DEBUG) << "prev_chunk = " << chunk << ", uploader->allowed_chunk = " << uploader->allowed_chunk << endl;
0140                 QVERIFY(uploader->allowed_chunk != prev_chunk && uploader->allowed_chunk != INVALID_CHUNK);
0141                 QVERIFY(allowCalled(uploader));
0142                 uploader->allow_called = false;
0143                 QVERIFY(!allowCalled(downloader));
0144             } else {
0145                 uploader->have(chunk);
0146                 downloader->have(chunk);
0147                 ss.have(downloader, chunk);
0148                 Out(SYS_GEN | LOG_DEBUG) << "prev_chunk = " << chunk << ", uploader->allowed_chunk = " << uploader->allowed_chunk << endl;
0149                 QVERIFY(uploader->allowed_chunk != prev_chunk && uploader->allowed_chunk != INVALID_CHUNK);
0150                 QVERIFY(allowCalled(uploader)); // allow should be called again on the uploader
0151                 uploader->allow_called = false;
0152             }
0153 
0154             // Cycle through peers
0155             DummyPeer *n = uploader;
0156             uploader = downloader;
0157             downloader = next;
0158             next = n;
0159 
0160             ss.dump();
0161         }
0162     }
0163 #if 0
0164     void testSeed()
0165     {
0166         Out(SYS_GEN | LOG_DEBUG) << "testSeed" << endl;
0167         SuperSeeder ss(NUM_CHUNKS, this);
0168 
0169         for (int i = 0; i < 4; i++)
0170             peer[i].reset();
0171 
0172         // First test, all tree should get a chunk
0173         for (int i = 0; i < 3; i++) {
0174             DummyPeer* p = &peer[i];
0175             ss.peerAdded(p);
0176             QVERIFY(allowCalled(p));
0177             QVERIFY(p->allowed_chunk != INVALID_CHUNK);
0178             target.clear();
0179         }
0180 
0181         ss.dump();
0182 
0183         // Now simulate a seed sending a have all message
0184         peer[3].haveAll();
0185         ss.haveAll(&peer[3]);
0186         QVERIFY(allow_called == false);
0187         target.clear();
0188 
0189         // Continue superseeding
0190         DummyPeer* uploader = &peer[0];
0191         DummyPeer* downloader = &peer[1];
0192         DummyPeer* next = &peer[2];
0193         for (int i = 0; i < 4; i++) {
0194             Out(SYS_GEN | LOG_DEBUG) << "======================================" << endl;
0195             Uint32 prev_chunk = uploader->allowed_chunk;
0196             // Now simulate b downloaded the first chunk from a
0197             Uint32 chunk = prev_chunk;
0198 
0199             Out(SYS_GEN | LOG_DEBUG) << "uploader = " << uploader->getPeerID().toString() << endl;
0200             Out(SYS_GEN | LOG_DEBUG) << "downloader = " << downloader->getPeerID().toString() << endl;
0201             Out(SYS_GEN | LOG_DEBUG) << "chunk = " << chunk << endl;
0202 
0203             uploader->have(chunk);
0204             downloader->have(chunk);
0205             ss.have(downloader, chunk);
0206             QVERIFY(allowCalled(uploader)); // allow should be called again on the uploader
0207 
0208             Out(SYS_GEN | LOG_DEBUG) << "prev_chunk = " << chunk << ", uploader->allowed_chunk = " << uploader->allowed_chunk << endl;
0209             QVERIFY(uploader->allowed_chunk != prev_chunk && uploader->allowed_chunk != INVALID_CHUNK);
0210             target.clear();
0211 
0212             // Cycle through peers
0213             DummyPeer* n = uploader;
0214             uploader = downloader;
0215             downloader = next;
0216             next = n;
0217 
0218             ss.dump();
0219         }
0220 
0221     }
0222 #endif
0223 private:
0224     DummyPeer peer[4];
0225     bool allow_called;
0226 };
0227 
0228 QTEST_MAIN(SuperSeedTest)
0229 
0230 #include "superseedtest.moc"