File indexing completed on 2024-04-28 13:28:53
0001 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0002 // SPDX-FileCopyrightText: 2020-2021 Harald Sitter <sitter@kde.org> 0003 0004 #include <QDebug> 0005 #include <QDir> 0006 #include <QFile> 0007 #include <QJsonDocument> 0008 #include <QObject> 0009 #include <QSignalSpy> 0010 #include <QStandardPaths> 0011 #include <QTest> 0012 0013 #include <functional> 0014 0015 #include "devicenotifier.h" 0016 #include <device.h> 0017 #include <smartctl.h> 0018 #include <smartmonitor.h> 0019 0020 class SMARTMonitorTest : public QObject 0021 { 0022 Q_OBJECT 0023 0024 private Q_SLOTS: 0025 void testRun() 0026 { 0027 struct Ctl : public AbstractSMARTCtl { 0028 static QString readCLIData() 0029 { 0030 QFile file(QFINDTESTDATA("fixtures/cli.txt")); 0031 const bool open = file.open(QFile::ReadOnly); 0032 Q_ASSERT(open); 0033 return file.readAll(); 0034 } 0035 0036 void run(const QString &devicePath) override 0037 { 0038 static QMap<QString, QString> data{{"/dev/testfoobarpass", "fixtures/pass.json"}, 0039 {"/dev/invalid-vbox.json", "fixtures/invalid-vbox.json"}, 0040 {"/dev/testfoobarfail", "fixtures/fail.json"}, 0041 {"/dev/invalid-cmdline-bad-usb-bridge", "fixtures/invalid-cmdline-bad-usb-bridge.json"}}; 0042 0043 const QString fixture = data.value(devicePath); 0044 Q_ASSERT(!fixture.isEmpty()); 0045 QFile file(QFINDTESTDATA(fixture)); 0046 const bool open = file.open(QFile::ReadOnly); 0047 Q_ASSERT(open); 0048 QJsonParseError err{}; 0049 const auto document = QJsonDocument::fromJson(file.readAll(), &err); 0050 Q_ASSERT(err.error == QJsonParseError::NoError); 0051 0052 static QString cliData = readCLIData(); 0053 Q_EMIT finished(devicePath, document, cliData); 0054 } 0055 }; 0056 0057 struct Notifier : public DeviceNotifier { 0058 using DeviceNotifier::DeviceNotifier; 0059 void start() override 0060 { 0061 loadData(); 0062 } 0063 void loadData() override 0064 { 0065 Q_EMIT addDevice(new Device{"udi-pass", "product", "/dev/testfoobarpass"}); 0066 Q_EMIT addDevice(new Device{"udi-invalid", "product", "/dev/invalid-vbox.json"}); 0067 Q_EMIT addDevice(new Device{"udi-invalid-cmdline-bad-usb-bridge", "product", "/dev/invalid-cmdline-bad-usb-bridge"}); 0068 // discover this twice to ensure notifications aren't duplicated! 0069 Q_EMIT addDevice(new Device{"udi-fail", "product", "/dev/testfoobarfail"}); 0070 Q_EMIT addDevice(new Device{"udi-fail", "product", "/dev/testfoobarfail"}); 0071 } 0072 }; 0073 0074 SMARTMonitor monitor(std::make_unique<Ctl>(), std::make_unique<Notifier>()); 0075 QSignalSpy spy(&monitor, &SMARTMonitor::deviceAdded); 0076 QVERIFY(spy.isValid()); 0077 monitor.start(); 0078 // The signals are all emitted in one go and as such should arrive 0079 // within a single wait. 0080 QVERIFY(spy.wait()); 0081 QCOMPARE(spy.count(), 2); // There are 3 devices but one is a dupe. 0082 QCOMPARE(monitor.devices().count(), 2); // There are 3 devices but one is a dupe. 0083 0084 bool sawPass = false; 0085 bool sawInvalid = false; 0086 bool sawFail = false; 0087 bool sawInvalidCmdLine = false; 0088 for (const auto *device : monitor.devices()) { 0089 if (device->path() == "/dev/testfoobarpass") { 0090 QVERIFY(!device->failed()); 0091 sawPass = true; 0092 } 0093 if (device->path() == "/dev/invalid") { 0094 sawInvalid = true; 0095 } 0096 if (device->path() == "/dev/invalid-cmdline-bad-usb-bridge") { 0097 sawInvalidCmdLine = true; 0098 } 0099 if (device->path() == "/dev/testfoobarfail") { 0100 QVERIFY(device->failed()); 0101 sawFail = true; 0102 } 0103 } 0104 QVERIFY(sawPass); 0105 QVERIFY(!sawInvalid); // mustn't be seen, it's an invalid device ;) 0106 QVERIFY(!sawInvalidCmdLine); // ditto 0107 QVERIFY(sawFail); 0108 0109 // Ensure removing works as well. 0110 // https://bugs.kde.org/show_bug.cgi?id=428746 0111 0112 monitor.removeUDI("udi-pass"); 0113 QCOMPARE(monitor.devices().size(), 1); 0114 } 0115 }; 0116 0117 QTEST_MAIN(SMARTMonitorTest) 0118 0119 #include "smartmonitortest.moc"