File indexing completed on 2024-04-21 04:57:09

0001 /* This file is part of the KDE project
0002 
0003    Copyright (C) 2009 Dario Massarin <nekkar@libero.it>
0004    Copyright (C) 2010 Matthias Fuchs <mat69@gmx.net>
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 */
0011 
0012 #include "testtransfers.h"
0013 #include "core/kget.h"
0014 #include "core/transfergrouphandler.h"
0015 #include "core/transferhandler.h"
0016 
0017 #include "kget_debug.h"
0018 #include "kget_interface.h"
0019 #include "transfer_interface.h"
0020 #include "verifier_interface.h"
0021 
0022 #include <KDialogJobUiDelegate>
0023 #include <KIO/CommandLauncherJob>
0024 
0025 #include <QDBusConnection>
0026 #include <QDBusConnectionInterface>
0027 #include <QDBusPendingReply>
0028 #include <QList>
0029 
0030 #include <QTest>
0031 
0032 // FIXME not working fine if files or transfers are existing already
0033 QHash<QString, int> Commands::s_stringCommands;
0034 QHash<QString, int> Commands::s_transferChangeEvents;
0035 
0036 Commands::Commands(const QString &source, QObject *parent)
0037     : QObject(parent)
0038     , m_timerId(-1)
0039     , m_source(source)
0040     , m_transfer(nullptr)
0041     , m_verifier(nullptr)
0042 {
0043     static int instance = 0;
0044     if (!instance++) {
0045         s_stringCommands["start"] = Start;
0046         s_stringCommands["stop"] = Stop;
0047         s_stringCommands["addchecksum"] = AddChecksum;
0048         s_stringCommands["addpartialchecksums"] = AddPartialChecksums;
0049         s_stringCommands["isverifyable"] = IsVerifyable;
0050         s_stringCommands["verify"] = Verify;
0051         s_stringCommands["findbrokenpieces"] = FindBrokenPieces;
0052         s_stringCommands["repair"] = Repair;
0053         s_stringCommands["setdirectory"] = SetDirectory;
0054         s_stringCommands["wait"] = Wait;
0055         s_stringCommands["randomaction"] = RandomAction;
0056         s_stringCommands["verified"] = Verified;
0057         s_stringCommands["changedevent"] = ChangedEvent;
0058         s_stringCommands["brokenpieces"] = BrokenPieces;
0059 
0060         s_transferChangeEvents["tc_filename"] = Transfer::Tc_FileName;
0061         s_transferChangeEvents["tc_status"] = Transfer::Tc_Status;
0062         s_transferChangeEvents["tc_totalsize"] = Transfer::Tc_TotalSize;
0063         s_transferChangeEvents["tc_percent"] = Transfer::Tc_Percent;
0064         s_transferChangeEvents["tc_downloadspeed"] = Transfer::Tc_DownloadSpeed;
0065         s_transferChangeEvents["tc_remainingtime"] = Transfer::Tc_RemainingTime;
0066         s_transferChangeEvents["tc_uploadspeed"] = Transfer::Tc_UploadSpeed;
0067         s_transferChangeEvents["tc_uploadlimit"] = Transfer::Tc_UploadLimit;
0068         s_transferChangeEvents["tc_downloadlimit"] = Transfer::Tc_DownloadLimit;
0069         s_transferChangeEvents["tc_canresume"] = Transfer::Tc_CanResume;
0070         s_transferChangeEvents["tc_downloadedsize"] = Transfer::Tc_DownloadedSize;
0071         s_transferChangeEvents["tc_uploadedsize"] = Transfer::Tc_UploadedSize;
0072         s_transferChangeEvents["tc_log"] = Transfer::Tc_Log;
0073         s_transferChangeEvents["tc_group"] = Transfer::Tc_Group;
0074         s_transferChangeEvents["tc_selection"] = Transfer::Tc_Selection;
0075     }
0076 }
0077 
0078 QList<QPair<int, QVariant>> Commands::parseCommands(const QDomElement &e, TestTransfers *transfer)
0079 {
0080     QList<QPair<int, QVariant>> commands;
0081 
0082     for (QDomElement elem = e.firstChildElement("command"); !elem.isNull(); elem = elem.nextSiblingElement("command")) {
0083         const QString typeString = elem.attribute("type").toLower();
0084 
0085         if (!s_stringCommands.contains(typeString)) {
0086             qCDebug(KGET_DEBUG) << "Error while parsing, type" << typeString << "not supported.";
0087             QWARN("Problem while parsing.");
0088             return commands;
0089         }
0090         const int type = s_stringCommands[typeString];
0091 
0092         QVariant data;
0093         QStringList args;
0094         for (QDomElement arg = elem.firstChildElement("arg"); !arg.isNull(); arg = arg.nextSiblingElement("arg")) {
0095             args << arg.text();
0096         }
0097 
0098         switch (type) {
0099         case Verify:
0100         case FindBrokenPieces:
0101         case Start:
0102         case Stop:
0103             commands.append(QPair<int, QVariant>(type, data));
0104             break;
0105         case IsVerifyable:
0106         case Verified:
0107         case Repair:
0108             if (args.count() == 1) {
0109                 data = args.first();
0110                 if (data.canConvert(QVariant::Bool)) {
0111                     commands.append(QPair<int, QVariant>(type, data));
0112                     break;
0113                 }
0114             }
0115             qCDebug(KGET_DEBUG) << "Parsing IsVerifyable/Verified/Repair failed.";
0116             QWARN("Problem while parsing.");
0117             break;
0118         case AddChecksum:
0119             if (args.count() == 2) {
0120                 data = args;
0121                 commands.append(QPair<int, QVariant>(type, data));
0122             } else {
0123                 qCDebug(KGET_DEBUG) << "Parsing setHash failed.";
0124                 QWARN("Problem while parsing.");
0125             }
0126             break;
0127         case AddPartialChecksums: {
0128             if (args.count() >= 3) {
0129                 bool worked;
0130                 QList<QVariant> list;
0131                 list << args[0]; // Type
0132                 const qulonglong length = args[1].toULongLong(&worked);
0133                 if (worked) {
0134                     list << length;
0135                     for (int i = 2; i < args.count(); ++i) {
0136                         list << args[i];
0137                     }
0138                     data = list;
0139                     commands.append(QPair<int, QVariant>(type, data));
0140                     break;
0141                 }
0142             }
0143             qCDebug(KGET_DEBUG) << "Parsing AddPartialChecksums failed.";
0144             QWARN("Problem while parsing.");
0145             break;
0146         }
0147         case BrokenPieces: {
0148             QList<QVariant> list;
0149             bool worked = true;
0150             foreach (const QString &arg, args) {
0151                 const int value = arg.toInt(&worked);
0152                 if (!worked) {
0153                     break;
0154                 }
0155                 list << value;
0156             }
0157             if (worked) {
0158                 data = list;
0159                 commands.append(QPair<int, QVariant>(type, data));
0160                 break;
0161             }
0162             qCDebug(KGET_DEBUG) << "Parsing BrokenPieces failed.";
0163             QWARN("Problem while parsing.");
0164             break;
0165         }
0166         case RandomAction: {
0167             QList<QVariant> list;
0168             if (args.count() == 1) {
0169                 data = args.takeFirst();
0170                 if (data.canConvert(QVariant::Bool) && !data.toBool()) {
0171                     list << data.toBool();
0172                     data = list;
0173                     commands.append(QPair<int, QVariant>(type, data));
0174                     break;
0175                 }
0176             } else if (args.count() == 2) {
0177                 data = args.takeFirst();
0178                 if (data.canConvert(QVariant::Bool) && data.toBool()) {
0179                     list << data.toBool();
0180                     bool worked;
0181                     list << args.takeFirst().toInt(&worked);
0182                     if (worked) {
0183                         data = list;
0184                         commands.append(QPair<int, QVariant>(type, data));
0185                         break;
0186                     }
0187                 }
0188             }
0189             qCDebug(KGET_DEBUG) << "Parsing RandomAction failed.";
0190             QWARN("Problem while parsing.");
0191             break;
0192         }
0193         case SetDirectory:
0194             if (args.count() == 2) {
0195                 data = args.last();
0196                 QString newDirectory = args.first();
0197                 if (transfer) {
0198                     newDirectory.replace("${DIR}/", transfer->tempDir());
0199                 }
0200                 if (!newDirectory.isEmpty() && data.canConvert(QVariant::Bool)) {
0201                     const bool shouldWork = data.toBool();
0202                     QList<QVariant> list;
0203                     list << newDirectory << shouldWork;
0204                     data = list;
0205                     commands.append(QPair<int, QVariant>(type, data));
0206                     break;
0207                 }
0208             }
0209             qCDebug(KGET_DEBUG) << "Parsing SetDirectory failed.";
0210             QWARN("Problem while parsing.");
0211             break;
0212         case Wait:
0213             if (args.count() == 1) {
0214                 bool worked;
0215                 data = args.first().toInt(&worked);
0216                 if (worked) {
0217                     commands.append(QPair<int, QVariant>(type, data));
0218                     break;
0219                 }
0220             }
0221             qCDebug(KGET_DEBUG) << "Parsing Wait failed.";
0222             QWARN("Problem while parsing.");
0223             break;
0224         case ChangedEvent:
0225             if (!args.isEmpty() && (args.count() <= 2)) {
0226                 QList<QVariant> list;
0227                 const QString typeString = args.first().toLower();
0228                 if (s_transferChangeEvents.contains(typeString)) {
0229                     int value = s_transferChangeEvents[typeString];
0230                     list << value;
0231                     if (args.count() == 2) {
0232                         bool worked;
0233                         value = args.last().toInt(&worked);
0234                         if (worked) {
0235                             list << value;
0236                             data = list;
0237                             commands.append(QPair<int, QVariant>(type, data));
0238                             break;
0239                         }
0240                     } else {
0241                         data = list;
0242                         commands.append(QPair<int, QVariant>(type, data));
0243                         break;
0244                     }
0245                 }
0246             }
0247             qCDebug(KGET_DEBUG) << "Parsing ChangedEvent failed" << args;
0248             QWARN("Problem while parsing.");
0249             break;
0250         default:
0251             QWARN("Default should never happen.");
0252             break;
0253         }
0254     }
0255 
0256     return commands;
0257 }
0258 
0259 QString Commands::source() const
0260 {
0261     return m_source;
0262 }
0263 
0264 void Commands::associateTransfer(OrgKdeKgetTransferInterface *transfer)
0265 {
0266     if (m_transfer) {
0267         disconnect(m_transfer, nullptr, this, nullptr);
0268     }
0269     if (m_verifier) {
0270         disconnect(m_verifier, nullptr, this, nullptr);
0271         delete m_verifier;
0272     }
0273 
0274     m_transfer = transfer;
0275     qCDebug(KGET_DEBUG) << this << "associated with" << m_transfer << m_source;
0276 
0277     QDBusPendingReply<QString> reply = m_transfer->dest();
0278     const QString dest = reply.value();
0279 
0280     reply = m_transfer->verifier(dest);
0281     m_verifier = new OrgKdeKgetVerifierInterface("org.kde.kget", reply.value(), QDBusConnection::sessionBus(), this);
0282 
0283     connect(m_verifier, &OrgKdeKgetVerifierInterface::verified, this, &Commands::slotVerified);
0284     connect(m_verifier, SIGNAL(brokenPieces(QStringList, qulonglong)), this, SLOT(slotBrokenPieces(QStringList, qulonglong)));
0285     connect(m_transfer, &OrgKdeKgetTransferInterface::transferChangedEvent, this, &Commands::slotChangedEvent);
0286 }
0287 
0288 bool Commands::hasCommands() const
0289 {
0290     return !m_commands.isEmpty();
0291 }
0292 
0293 void Commands::setCommands(const QList<QPair<int, QVariant>> &commands)
0294 {
0295     m_commands = commands;
0296 }
0297 
0298 void Commands::timerEvent(QTimerEvent *event)
0299 {
0300     Q_UNUSED(event)
0301 
0302     const int value = QRandomGenerator::global()->bounded(10);
0303     // 70% of the cases start, in 30% stop
0304     if (value > 2) {
0305         qCDebug(KGET_DEBUG) << this << "is randomly started.";
0306         m_transfer->start();
0307     } else {
0308         qCDebug(KGET_DEBUG) << this << "is randomly stopped";
0309         m_transfer->stop();
0310     }
0311 }
0312 
0313 void Commands::slotWaitEvent()
0314 {
0315     // wait is over so continue with executing commands
0316     if (!m_commands.isEmpty()) {
0317         m_commands.takeFirst();
0318         executeCommands();
0319     }
0320 }
0321 
0322 void Commands::executeCommands()
0323 {
0324     if (!m_transfer) {
0325         QFAIL("Calling executeCommands when no transfer is set.");
0326     }
0327 
0328     // NOTE no checks are being done if the commands are correct, this is to ensure that KGet crashes
0329     // on faulty commands making sure that those are found
0330     while (!m_commands.isEmpty()) {
0331         const QPair<int, QVariant> operation = m_commands.first();
0332         const int type = operation.first;
0333 
0334         if (type >= CustomEvent) {
0335             return;
0336         }
0337         const QVariant command = operation.second;
0338 
0339         switch (type) {
0340         case Start:
0341             m_transfer->start();
0342             qCDebug(KGET_DEBUG) << this << "is started.";
0343             break;
0344         case Stop:
0345             m_transfer->stop();
0346             qCDebug(KGET_DEBUG) << this << "is stopped.";
0347             break;
0348         case AddChecksum: {
0349             QStringList hash = command.toStringList();
0350             qCDebug(KGET_DEBUG) << this << "adding hash" << hash;
0351             QDBusPendingReply<void> reply = m_verifier->addChecksum(hash.takeFirst(), hash.takeLast());
0352             break;
0353         }
0354         case AddPartialChecksums: {
0355             QList<QVariant> list = command.toList();
0356             qCDebug(KGET_DEBUG) << this << "adding partial hash" << list;
0357             const QString type = list.takeFirst().toString();
0358             const qulonglong length = list.takeFirst().toULongLong();
0359             QStringList checksums;
0360             foreach (const QVariant &value, list) {
0361                 checksums << value.toString();
0362             }
0363             m_verifier->addPartialChecksums(type, length, checksums);
0364             break;
0365         }
0366         case IsVerifyable: {
0367             const bool shouldWork = command.toBool();
0368             QDBusPendingReply<bool> reply = m_verifier->isVerifyable();
0369             qCDebug(KGET_DEBUG) << this << "isVerifyable" << reply.value();
0370             QVERIFY(reply.value() == shouldWork);
0371             break;
0372         }
0373         case Verify: {
0374             qCDebug(KGET_DEBUG) << this << "verification started.";
0375             m_verifier->verify();
0376             break;
0377         }
0378         case FindBrokenPieces:
0379             qCDebug(KGET_DEBUG) << this << "find broken pieces.";
0380             m_verifier->brokenPieces();
0381             break;
0382         case Repair: {
0383             const bool shouldWork = command.toBool();
0384             QDBusPendingReply<QString> dest = m_transfer->dest();
0385             QDBusPendingReply<bool> reply = m_transfer->repair(dest.value());
0386 
0387             const bool isRepairable = reply.value();
0388             qCDebug(KGET_DEBUG) << this << "repair started" << isRepairable;
0389             QVERIFY(isRepairable == shouldWork);
0390             break;
0391         }
0392         case SetDirectory: {
0393             QList<QVariant> commands = command.toList();
0394             const QString newDirectory = commands.takeFirst().toString();
0395             const bool shouldWork = commands.takeFirst().toBool();
0396             QDBusPendingReply<bool> reply = m_transfer->setDirectory(newDirectory);
0397 
0398             const bool moveStarted = reply.value();
0399             qCDebug(KGET_DEBUG) << this << "set changing directory started" << moveStarted;
0400             QVERIFY(moveStarted == shouldWork);
0401             break;
0402         }
0403         case Wait: {
0404             const int time = command.toInt();
0405             qCDebug(KGET_DEBUG) << this << "waiting for" << time << "msecs" << m_transfer;
0406             QTimer::singleShot(time, this, &Commands::slotWaitEvent);
0407             return;
0408             break;
0409         }
0410         case RandomAction: {
0411             QList<QVariant> commands = command.toList();
0412             const bool turnOn = commands.takeFirst().toBool();
0413             if (m_timerId == -1) {
0414                 if (turnOn) {
0415                     qCDebug(KGET_DEBUG) << this << "starting random timer.";
0416                     m_timerId = startTimer(commands.takeFirst().toInt());
0417                 }
0418             } else {
0419                 qCDebug(KGET_DEBUG) << this << "killing random timer.";
0420                 killTimer(m_timerId);
0421                 m_timerId = -1;
0422                 if (turnOn) {
0423                     qCDebug(KGET_DEBUG) << this << "starting random timer.";
0424                     m_timerId = startTimer(commands.takeFirst().toInt());
0425                 }
0426             }
0427             break;
0428         }
0429         }
0430 
0431         m_commands.takeFirst();
0432     }
0433 }
0434 void Commands::slotChangedEvent(int event)
0435 {
0436     if (!m_transfer || m_commands.isEmpty()) {
0437         return;
0438     }
0439 
0440     const QPair<int, QVariant> operation = m_commands.first();
0441     const int type = operation.first;
0442 
0443     if (type != ChangedEvent) {
0444         return;
0445     }
0446 
0447     const QList<QVariant> commands = operation.second.toList();
0448 
0449     // at least one and maximum two commands allowed;
0450     if (commands.isEmpty() || commands.count() > 2) {
0451         return;
0452     }
0453 
0454     bool worked;
0455     const int eventType = commands.first().toInt(&worked);
0456     if (!worked || !(eventType & event)) {
0457         return;
0458     }
0459 
0460     if (commands.count() == 2) {
0461         const int compareValue = commands.last().toInt(&worked);
0462         if (!worked) {
0463             return;
0464         }
0465 
0466         switch (eventType) {
0467         case Transfer::Tc_Status: {
0468             QDBusPendingReply<int> reply = m_transfer->status();
0469             if (reply.value() == compareValue) {
0470                 m_commands.takeFirst();
0471                 executeCommands();
0472             }
0473             break;
0474         }
0475         case Transfer::Tc_Percent: {
0476             QDBusPendingReply<int> reply = m_transfer->percent();
0477             if (reply.value() >= compareValue) {
0478                 qCDebug(KGET_DEBUG) << this << "ChangedEvent percent.";
0479                 m_commands.takeFirst();
0480                 executeCommands();
0481             }
0482             break;
0483         }
0484         default:
0485             break;
0486         }
0487     } else {
0488         m_commands.takeFirst();
0489         executeCommands();
0490     }
0491 }
0492 
0493 void Commands::slotVerified(bool verified)
0494 {
0495     if (!m_commands.isEmpty()) {
0496         const QPair<int, QVariant> operation = m_commands.first();
0497         const int type = operation.first;
0498 
0499         if (type == Verified) {
0500             const QVariant command = operation.second;
0501             m_commands.takeFirst();
0502             if (command.canConvert(QVariant::Bool)) {
0503                 const bool shouldWork = command.toBool();
0504                 qCDebug(KGET_DEBUG) << this << "is verified" << verified;
0505                 QVERIFY(verified == shouldWork);
0506             }
0507 
0508             executeCommands();
0509             return;
0510         }
0511     }
0512 
0513     qCDebug(KGET_DEBUG) << this << "is verified" << verified;
0514     QVERIFY(verified);
0515 }
0516 
0517 void Commands::slotBrokenPieces(const QStringList &offsets, qulonglong length)
0518 {
0519     if (m_commands.isEmpty()) {
0520         return;
0521     }
0522 
0523     const QPair<int, QVariant> operation = m_commands.first();
0524     const int type = operation.first;
0525     if (type != BrokenPieces) {
0526         return;
0527     }
0528 
0529     //     QList<QVariant> list = brokenPieces.variant().toList();//FIXME
0530     QList<QVariant> compareList = operation.second.toList();
0531     if (offsets.count() != compareList.count()) {
0532         QFAIL("Emitted brokenPieces list does not match.");
0533     }
0534     for (int i = 0; i < offsets.count(); ++i) {
0535         QVERIFY(static_cast<int>(offsets[i].toULongLong() / length) == compareList[i].toInt());
0536     }
0537 
0538     m_commands.takeFirst();
0539     executeCommands();
0540 }
0541 
0542 TestTransfers::TestTransfers()
0543 {
0544     if (!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget")) {
0545         const QString command = QStringLiteral("kget --showDropTarget --hideMainWindow");
0546         auto *job = new KIO::CommandLauncherJob(command);
0547         job->setDesktopName(QStringLiteral("org.kde.kget"));
0548         job->setUiDelegate(new KDialogJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, nullptr));
0549         job->start();
0550     }
0551 
0552     m_dir.reset(new QTemporaryDir());
0553     qCDebug(KGET_DEBUG) << "Using temp dir:" << tempDir();
0554 
0555     // TODO add a signal to check if the move worked!!
0556 
0557     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/kdeedu-4.3.1.tar.bz2"
0558     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/kdegames-4.3.1.tar.bz2"
0559     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/kdegraphics-4.3.1.tar.bz2"
0560     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/kdelibs-4.3.1.tar.bz2"
0561     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/kdelibs-experimental-4.3.1.tar.bz2"
0562     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/kdemultimedia-4.3.1.tar.bz2"
0563     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/kdenetwork-4.3.1.tar.bz2"
0564     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/kdepim-4.3.1.tar.bz2"
0565     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/kdepim-runtime-4.3.1.tar.bz2"
0566     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/kdepimlibs-4.3.1.tar.bz2"
0567     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/kdeplasma-addons-4.3.1.tar.bz2"
0568     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/kdesdk-4.3.1.tar.bz2"
0569     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/kdetoys-4.3.1.tar.bz2"
0570     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/kdewebdev-4.3.1.tar.bz2"
0571     //                << "http://mirrors.isc.org/pub/kde/stable/4.3.1/src/oxygen-icons-4.3.1.tar.bz2";
0572 
0573     //                << "6326cff7779dfadc1b18a3a6bbe7b0750fb7ceaf"
0574     //                << "576255ce66a0c089e0840bd90ea89d5705872bc8"
0575     //                << "d57d9007b95607c0ee925cc963d7e14798fc69f9"
0576     //                << "511532852caca9302c643fded4013ef1f57d5433"
0577     //                << "7d560817a186c4b7099d321ee4a58705962a59d3"
0578     //                << "ef50f869f1a6cdf91fe7808f095fccbd9463a7dd"
0579     //                << "57194b5f89b37329e562951c491fa18029c0b431"
0580     //                << "6fd0309dbd911e2667ec1c08d1f10f2626a54534"
0581     //                << "c39b0fc1d3721fb8c6074ba6a174ad8716c6c604"
0582     //                << "f4b04b21a6aa3accc530bc6c32cf0d820c611265"
0583     //                << "83421181dd3a80c4ac0ff5bab111b7f71f6a1192"
0584     //                << "ded236a12002b824f97856ce5dc882161ed437d2"
0585     //                << "31a60deafef34a02fb7de5339eed1c750a456d3b"
0586     //                << "28580c6f283fa7a6405f6a4415ebe9a4167f0992"
0587     //                << "75a82d2e80d946333f63e32db56767c3ed17ba33";
0588 }
0589 
0590 QString TestTransfers::tempDir() const
0591 {
0592     return m_dir->path();
0593 }
0594 
0595 void TestTransfers::parseFile()
0596 {
0597     const QString xmlFile = QFINDTESTDATA("kget-test.xml");
0598     QVERIFY(!xmlFile.isEmpty());
0599     QFile file(xmlFile);
0600     QVERIFY(file.open(QIODevice::ReadOnly));
0601 
0602     QDomDocument doc;
0603     if (!doc.setContent(&file)) {
0604         QFAIL("Not able to set content.");
0605     }
0606 
0607     for (QDomElement elem = doc.firstChildElement("tests").firstChildElement("transfer"); !elem.isNull(); elem = elem.nextSiblingElement("transfer")) {
0608         const QString source = elem.attribute("source");
0609         if (source.isEmpty()) {
0610             QFAIL("One transfer does not have an source attribute.");
0611             return;
0612         }
0613         auto *transfer = new Commands(source, this);
0614         transfer->setCommands(Commands::parseCommands(elem, this));
0615         m_commands.append(transfer);
0616     }
0617 }
0618 
0619 void TestTransfers::createTransfer()
0620 {
0621     if (m_commands.isEmpty()) {
0622         QFAIL("No commands set.");
0623     }
0624 
0625     if (!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget")) {
0626         qCDebug(KGET_DEBUG) << "Service not registered yet, retrying.";
0627         QTimer::singleShot(500, this, &TestTransfers::createTransfer);
0628         return;
0629     }
0630     QVERIFY(QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget"));
0631 
0632     OrgKdeKgetMainInterface kgetInterface("org.kde.kget", "/KGet", QDBusConnection::sessionBus());
0633 
0634     foreach (Commands *command, m_commands) {
0635         QDBusPendingReply<QStringList> reply =
0636             kgetInterface.addTransfer(command->source(), tempDir() + QUrl::fromLocalFile(command->source()).fileName(), false);
0637         reply.waitForFinished();
0638 
0639         if (reply.value().size()) {
0640             qCDebug(KGET_DEBUG) << "TestTransfers::createTransfer -> transfer = " << reply.value();
0641             auto *transfer = new OrgKdeKgetTransferInterface("org.kde.kget", reply.value().first(), QDBusConnection::sessionBus(), this);
0642 
0643             command->associateTransfer(transfer);
0644             command->executeCommands();
0645         } else {
0646             QFAIL("Reply NOT VALID!!!");
0647         }
0648     }
0649 }
0650 
0651 void TestTransfers::simpleTest()
0652 {
0653     parseFile();
0654     createTransfer();
0655 
0656     // execute as long as there are still commands left
0657     forever {
0658         bool abort = true;
0659         foreach (Commands *commands, m_commands) {
0660             if (commands->hasCommands()) {
0661                 abort = false;
0662                 break;
0663             }
0664         }
0665 
0666         if (abort) {
0667             break;
0668         }
0669         QTest::qWait(3000);
0670     }
0671 }
0672 
0673 QTEST_MAIN(TestTransfers)
0674 
0675 #include "moc_testtransfers.cpp"