File indexing completed on 2024-04-28 16:49:46

0001 #include "ksysguarddtest.h"
0002 #include "processcore/processcore_debug.h"
0003 
0004 KSGRD::SensorAgent *agent;
0005 
0006 Q_DECLARE_METATYPE(KSGRD::SensorAgent *)
0007 
0008 using namespace KSGRD;
0009 void TestKsysguardd::initTestCase()
0010 {
0011     qRegisterMetaType<KSGRD::SensorAgent *>();
0012     QCOMPARE(manager.count(), 0);
0013     hostConnectionLostSpy = new QSignalSpy(&manager, SIGNAL(hostConnectionLost(QString)));
0014     updateSpy = new QSignalSpy(&manager, SIGNAL(update()));
0015     hostAddedSpy = new QSignalSpy(&manager, SIGNAL(hostAdded(KSGRD::SensorAgent *, QString)));
0016     bool success = manager.engage("", "", "../../ksysguardd/ksysguardd", -1);
0017     QCOMPARE(hostAddedSpy->count(), 1);
0018     QVERIFY(success);
0019     QVERIFY(manager.isConnected(""));
0020     QCOMPARE(hostConnectionLostSpy->count(), 0);
0021     QCOMPARE(updateSpy->count(), 0);
0022     client = new SensorClientTest;
0023     nextId = 0;
0024 }
0025 void TestKsysguardd::init()
0026 {
0027 }
0028 void TestKsysguardd::cleanup()
0029 {
0030 }
0031 
0032 void TestKsysguardd::cleanupTestCase()
0033 {
0034     QCOMPARE(hostAddedSpy->count(), 1);
0035     QCOMPARE(manager.count(), 1);
0036     manager.disengage("");
0037     QCOMPARE(manager.count(), 0);
0038     delete updateSpy;
0039     delete hostConnectionLostSpy;
0040     delete client;
0041 }
0042 
0043 void TestKsysguardd::testSetup()
0044 {
0045     QCOMPARE(manager.count(), 1);
0046     QString shell;
0047     QString command;
0048     int port;
0049     bool success = manager.hostInfo("", shell, command, port);
0050     QCOMPARE(success, true);
0051     QCOMPARE(shell, QString(""));
0052     QCOMPARE(command, QString("../../ksysguardd/ksysguardd"));
0053     QCOMPARE(port, -1);
0054 
0055     success = manager.hostInfo("nonexistent host", shell, command, port);
0056     QCOMPARE(success, false);
0057 }
0058 
0059 /** Test the result from ksysguardd for each monitor info and monitor name follows the correct syntax */
0060 void TestKsysguardd::testFormatting_data()
0061 {
0062     QTest::addColumn<QByteArray>("monitorName");
0063     QTest::addColumn<QByteArray>("monitorType");
0064     QTest::addColumn<QByteArray>("monitorInfoName");
0065 
0066     int id = nextId++;
0067     bool success = manager.sendRequest("", "monitors", client, id);
0068     QVERIFY(success);
0069 
0070     QCOMPARE(hostConnectionLostSpy->count(), 0);
0071     QCOMPARE(updateSpy->count(), 0);
0072 
0073     int timeout = 300; // Wait up to 30 seconds
0074     while (!client->haveAnswer && !client->isSensorLost && timeout--)
0075         QTest::qWait(100);
0076     QVERIFY(client->haveAnswer);
0077     QVERIFY(!client->isSensorLost);
0078     QVERIFY(!client->answers[id].isSensorLost);
0079     QCOMPARE(client->answers[id].id, id);
0080 
0081     QList<QByteArray> monitors = client->answers[id].answer;
0082     QVERIFY(!monitors.isEmpty());
0083 
0084     // We now have a list of all the monitors
0085     foreach (const QByteArray &monitor, monitors) {
0086         QList<QByteArray> info = monitor.split('\t');
0087         QCOMPARE(info.count(), 2);
0088         QByteArray monitorName = info[0];
0089         QByteArray monitorType = info[1];
0090         QByteArray monitorInfoName = monitorName;
0091         monitorInfoName.append('?');
0092         client->haveAnswer = false;
0093         QTest::newRow(monitorName.constData()) << monitorName << monitorType << monitorInfoName;
0094     }
0095 }
0096 
0097 // Test each monitor for a correctly formatted info and correctly formatted data
0098 void TestKsysguardd::testFormatting()
0099 {
0100     QFETCH(QByteArray, monitorName);
0101     QFETCH(QByteArray, monitorType);
0102     QFETCH(QByteArray, monitorInfoName);
0103 
0104     // Query the monitor for its information
0105     if (client->haveAnswer || client->isSensorLost)
0106         return; // Skip rest of tests
0107     int id = nextId++;
0108     bool success = manager.sendRequest("", monitorInfoName, client, id);
0109     QVERIFY(success);
0110     int timeout = 50;
0111     while (!client->haveAnswer && !client->isSensorLost && timeout--)
0112         QTest::qWait(10);
0113     QVERIFY(client->haveAnswer);
0114     QVERIFY(!client->isSensorLost);
0115     QVERIFY(!client->answers[id].isSensorLost);
0116     QCOMPARE(client->answers[id].id, id);
0117 
0118     QCOMPARE(updateSpy->count(), 0);
0119     QCOMPARE(hostConnectionLostSpy->count(), 0);
0120 
0121     QList<QByteArray> columnHeadings;
0122     QList<QByteArray> columnTypes;
0123 
0124     // Now check the answer that we got for the monitor information
0125     if (monitorType == "integer") {
0126         QCOMPARE(client->answers[id].answer.count(), 1);
0127         QList<QByteArray> answer = client->answers[id].answer[0].split('\t');
0128         QCOMPARE(answer.count(), 4); // Name, minimum value, maximum value, unit
0129         QVERIFY(!answer[0].isEmpty()); // Name can't be empty
0130         QVERIFY(!answer[1].isEmpty()); // Minimum value cannot be empty
0131         QVERIFY(!answer[2].isEmpty()); // Maximum value cannot be empty.  unit can be
0132         // Make sure minimum and maximum values are numbers (doubles)
0133         bool isNumber;
0134         long min = answer[1].toLong(&isNumber); //(note that toLong is in C locale, which is what we want)
0135         QVERIFY(isNumber);
0136         long max = answer[2].toLong(&isNumber);
0137         QVERIFY(isNumber);
0138         QVERIFY(min <= max);
0139     } else if (monitorType == "float") {
0140         QCOMPARE(client->answers[id].answer.count(), 1);
0141         QList<QByteArray> answer = client->answers[id].answer[0].split('\t');
0142         QCOMPARE(answer.count(), 4); // Name, minimum value, maximum value, unit
0143         QVERIFY(!answer[0].isEmpty()); // Name can't be empty
0144         QVERIFY(!answer[1].isEmpty()); // Minimum value cannot be empty
0145         QVERIFY(!answer[2].isEmpty()); // Maximum value cannot be empty.  unit can be
0146         // Make sure minimum and maximum values are numbers (doubles)
0147         bool isNumber;
0148         double min = answer[1].toDouble(&isNumber); //(note that toDouble is in C locale, which is what we want)
0149         QVERIFY(isNumber);
0150         double max = answer[2].toDouble(&isNumber);
0151         QVERIFY(isNumber);
0152         QVERIFY(min <= max);
0153     } else if (monitorType == "logfile") {
0154         QCOMPARE(client->answers[id].answer.count(), 1);
0155         QList<QByteArray> answer = client->answers[id].answer[0].split('\t');
0156         QCOMPARE(answer.count(), 1);
0157         QCOMPARE(answer[0], QByteArray("LogFile"));
0158     } else if (monitorType == "listview" || monitorType == "table") {
0159         // listview is two lines.  The first line is the column headings, the second line is the type of each column
0160         QCOMPARE(client->answers[id].answer.count(), 2);
0161         columnHeadings = client->answers[id].answer[0].split('\t');
0162         columnTypes = client->answers[id].answer[1].split('\t');
0163         QCOMPARE(columnHeadings.count(), columnTypes.count());
0164         // column type is well defined
0165         foreach (const QByteArray &columnType, columnTypes) {
0166             switch (columnType[0]) {
0167             case 's': // string
0168             case 'S': // string to translate
0169             case 'd': // integer
0170             case 'D': // integer to display localized
0171             case 'f': // floating point number
0172             case 'M': // Disk stat - some special case
0173             case '%': // Disk stat - some special case
0174                 QCOMPARE(columnType.size(), 1);
0175                 break;
0176             case 'K': // Disk stat - some special case
0177                 QCOMPARE(columnType.size(), 2);
0178                 QCOMPARE(columnType, QByteArray("KB"));
0179                 break;
0180             default:
0181                 QVERIFY(false);
0182             }
0183         }
0184     } else if (monitorType == "string") {
0185         // TODO Check for something in the answer?
0186     } else {
0187         QVERIFY(false);
0188     }
0189 
0190     // Now read the actual data for the sensor, and check that it's valid
0191     client->haveAnswer = false;
0192     id = nextId++;
0193     success = manager.sendRequest("", monitorName, client, id);
0194     QVERIFY(success);
0195     QTime timer;
0196     timer.start();
0197     timeout = 300; // Wait up to 30 seconds
0198     while (!client->haveAnswer && !client->isSensorLost && timeout--)
0199         QTest::qWait(100);
0200     QVERIFY(client->haveAnswer);
0201     QVERIFY(!client->isSensorLost);
0202     QCOMPARE(client->answers[id].id, id);
0203     if (timer.elapsed() > 200)
0204         qCDebug(LIBKSYSGUARD) << monitorName << "took" << timer.elapsed() << "ms";
0205 
0206     if (monitorType == "integer") {
0207         QList<QByteArray> answer = client->answers[id].answer[0].split('\t');
0208         QCOMPARE(answer.count(), 1); // Just the number
0209         QVERIFY(!answer[0].isEmpty()); // Value cannot be empty
0210         // Make sure the value is valid
0211         bool isNumber;
0212         answer[0].toLong(&isNumber); //(note that toLong is in C locale, which is what we want)
0213         QVERIFY(isNumber);
0214     } else if (monitorType == "float") {
0215         QList<QByteArray> answer = client->answers[id].answer[0].split('\t');
0216         QCOMPARE(answer.count(), 1); // Just the number
0217         QVERIFY(!answer[0].isEmpty()); // Value cannot be empty
0218         // Make sure the value is valid
0219         bool isNumber;
0220         answer[0].toDouble(&isNumber); //(note that toDouble is in C locale, which is what we want)
0221         QVERIFY(isNumber);
0222     } else if (monitorType == "listview" || monitorType == "table") {
0223         foreach (const QByteArray &row, client->answers[id].answer) {
0224             QList<QByteArray> rowData = row.split('\t');
0225             QCOMPARE(rowData.count(), columnHeadings.count());
0226             for (int column = 0; column < columnHeadings.count(); column++) {
0227                 switch (columnTypes[column][0]) {
0228                 case 's': // string
0229                 case 'S': // string to translate
0230                     break;
0231                 case 'd': // integer
0232                 case 'D': { // integer to display localized
0233                     bool isNumber;
0234                     rowData[column].toLong(&isNumber);
0235                     QVERIFY2(isNumber, (QString("Row data was ") + row).toLatin1().constData());
0236                 }
0237                 case 'f': { // floating point number
0238                     bool isNumber;
0239                     rowData[column].toDouble(&isNumber);
0240                     QVERIFY(isNumber);
0241                 }
0242                 case 'M': // Disk stat - some special case
0243                     break;
0244                 }
0245             }
0246         }
0247     }
0248     client->haveAnswer = false;
0249 }
0250 
0251 void TestKsysguardd::testQueueing()
0252 {
0253     // Send lots of commands to ksysguardd, and check that they all return the right answer, in order
0254 
0255     delete client; // Start with a new client
0256     client = new SensorClientTest;
0257 
0258     const int N = 1000;
0259     for (int i = 0; i < N; i++) {
0260         bool success = manager.sendRequest("", "ps", client, i);
0261         QVERIFY(success);
0262     }
0263 
0264     int timeout = 300; // Wait up to 30 seconds for a single answer
0265     int lastCount = 0;
0266     while (client->answers.count() != N && !client->isSensorLost && timeout--) {
0267         if (client->answers.count() != lastCount) {
0268             lastCount = client->answers.count();
0269             timeout = 300; // reset timeout as we get new answers
0270         }
0271         QTest::qWait(100);
0272     }
0273     QCOMPARE(client->answers.count(), N);
0274 
0275     for (int i = 0; i < N; i++) {
0276         QCOMPARE(client->answers[i].id, i);
0277     }
0278 }
0279 QTEST_MAIN(TestKsysguardd)