File indexing completed on 2024-05-19 04:01:09
0001 /* 0002 SPDX-FileCopyrightText: 2016 Volker Krause <vkrause@kde.org> 0003 0004 SPDX-License-Identifier: MIT 0005 */ 0006 0007 #include "servercontroller.h" 0008 0009 #include <rest/restapi.h> 0010 #include <rest/restclient.h> 0011 0012 #include <provider/core/auditloguicontroller.h> 0013 #include <provider/core/provider.h> 0014 #include <provider/core/platforminfosource.h> 0015 #include <provider/core/screeninfosource.h> 0016 0017 #include <core/product.h> 0018 #include <core/schemaentryelement.h> 0019 #include <core/schemaentrytemplates.h> 0020 0021 #include <QAbstractItemModel> 0022 #include <QDebug> 0023 #include <QJsonArray> 0024 #include <QJsonDocument> 0025 #include <QJsonObject> 0026 #include <QtTest/qtest.h> 0027 #include <QNetworkReply> 0028 #include <QObject> 0029 #include <QSettings> 0030 #include <QSignalSpy> 0031 #include <QStandardPaths> 0032 0033 using namespace KUserFeedback; 0034 using namespace KUserFeedback::Console; 0035 0036 class SubmitTest : public QObject 0037 { 0038 Q_OBJECT 0039 private: 0040 ServerController m_server; 0041 0042 bool waitForFinished(QNetworkReply *reply) 0043 { 0044 Q_ASSERT(reply); 0045 QSignalSpy spy(reply, &QNetworkReply::finished); 0046 Q_ASSERT(spy.isValid()); 0047 return spy.wait(); 0048 } 0049 0050 private Q_SLOTS: 0051 void initTestCase() 0052 { 0053 Q_INIT_RESOURCE(schematemplates); 0054 QStandardPaths::setTestModeEnabled(true); 0055 QVERIFY(m_server.start()); 0056 } 0057 0058 void init() 0059 { 0060 // clear past audit logs 0061 AuditLogUiController alc; 0062 alc.clear(); 0063 QVERIFY(alc.logEntryModel()); 0064 QCOMPARE(alc.logEntryModel()->rowCount(), 0); 0065 } 0066 0067 void testProvider_data() 0068 { 0069 QTest::addColumn<QString>("path"); 0070 QTest::newRow("direct") << QString(); 0071 QTest::newRow("absolute redirect") << QStringLiteral("/absRedirect"); 0072 QTest::newRow("relative redirect") << QStringLiteral("/relRedirect"); 0073 } 0074 0075 void testProvider() 0076 { 0077 QFETCH(QString, path); 0078 ServerInfo serverInfo; 0079 auto serverUrl = m_server.url(); 0080 serverInfo.setUrl(serverUrl); 0081 serverUrl.setPath(path); 0082 0083 // delete previous leftovers 0084 RESTClient client; 0085 client.setServerInfo(serverInfo); 0086 client.setConnected(true); 0087 QVERIFY(client.isConnected()); 0088 Product p; 0089 p.setName(QStringLiteral("org.kde.UserFeedback.UnitTestProduct")); 0090 auto reply = RESTApi::deleteProduct(&client, p); 0091 waitForFinished(reply); 0092 0093 // create test product 0094 for (const auto &tpl : SchemaEntryTemplates::availableTemplates()) 0095 p.addTemplate(tpl); 0096 QVERIFY(p.isValid()); 0097 reply = RESTApi::createProduct(&client, p); 0098 QVERIFY(waitForFinished(reply)); 0099 QCOMPARE(reply->error(), QNetworkReply::NoError); 0100 0101 // submit data 0102 Provider provider; 0103 provider.setProductIdentifier(QStringLiteral("org.kde.UserFeedback.UnitTestProduct")); 0104 provider.setTelemetryMode(Provider::DetailedUsageStatistics); 0105 provider.setFeedbackServer(serverUrl); 0106 provider.addDataSource(new ScreenInfoSource); 0107 provider.addDataSource(new PlatformInfoSource); 0108 provider.submit(); 0109 QTest::qWait(100); // HACK submit is async 0110 0111 // retrieve data 0112 reply = RESTApi::listSamples(&client, p); 0113 QVERIFY(waitForFinished(reply)); 0114 QVERIFY(reply->header(QNetworkRequest::ContentTypeHeader).toString().startsWith(QLatin1String("text/json"))); 0115 auto doc = QJsonDocument::fromJson(reply->readAll()); 0116 QVERIFY(doc.isArray()); 0117 auto a = doc.array(); 0118 QCOMPARE(a.size(), 1); 0119 0120 auto obj = a.at(0).toObject(); 0121 QVERIFY(!obj.isEmpty()); 0122 QVERIFY(obj.contains(QLatin1String("id"))); 0123 QVERIFY(obj.contains(QLatin1String("timestamp"))); 0124 0125 QVERIFY(obj.contains(QLatin1String("platform"))); 0126 auto sub = obj.value(QLatin1String("platform")).toObject(); 0127 QVERIFY(sub.contains(QLatin1String("os"))); 0128 QVERIFY(sub.contains(QLatin1String("version"))); 0129 0130 QVERIFY(obj.contains(QLatin1String("screens"))); 0131 a = obj.value(QLatin1String("screens")).toArray(); 0132 QVERIFY(a.size() > 0); 0133 sub = a.at(0).toObject(); 0134 QVERIFY(sub.contains(QLatin1String("height"))); 0135 QVERIFY(sub.contains(QLatin1String("width"))); 0136 0137 // check we wrote an audit log 0138 AuditLogUiController alc; 0139 QVERIFY(alc.logEntryModel()); 0140 QCOMPARE(alc.logEntryModel()->rowCount(), 1); 0141 } 0142 0143 void testRedirectLoop() 0144 { 0145 auto serverUrl = m_server.url(); 0146 serverUrl.setPath(QLatin1String("/circleRedirect")); 0147 0148 // this must pass without ending in an infinite loop 0149 Provider provider; 0150 provider.setProductIdentifier(QStringLiteral("org.kde.UserFeedback.UnitTestProduct")); 0151 provider.setTelemetryMode(Provider::DetailedUsageStatistics); 0152 provider.setFeedbackServer(serverUrl); 0153 provider.addDataSource(new ScreenInfoSource); 0154 provider.addDataSource(new PlatformInfoSource); 0155 provider.submit(); 0156 QTest::qWait(500); // HACK submit is async, and we have no way of knowning the redirect loop ended... 0157 } 0158 0159 void testSurveyWithoutTelemetry() 0160 { 0161 ServerInfo serverInfo; 0162 auto serverUrl = m_server.url(); 0163 serverInfo.setUrl(serverUrl); 0164 0165 // delete previous leftovers 0166 RESTClient client; 0167 client.setServerInfo(serverInfo); 0168 client.setConnected(true); 0169 QVERIFY(client.isConnected()); 0170 Product p; 0171 p.setName(QStringLiteral("org.kde.UserFeedback.UnitTestProduct")); 0172 auto reply = RESTApi::deleteProduct(&client, p); 0173 waitForFinished(reply); 0174 0175 // create test product 0176 for (const auto &tpl : SchemaEntryTemplates::availableTemplates()) 0177 p.addTemplate(tpl); 0178 QVERIFY(p.isValid()); 0179 reply = RESTApi::createProduct(&client, p); 0180 QVERIFY(waitForFinished(reply)); 0181 QCOMPARE(reply->error(), QNetworkReply::NoError); 0182 0183 // submit data 0184 Provider provider; 0185 provider.setProductIdentifier(QStringLiteral("org.kde.UserFeedback.UnitTestProduct")); 0186 provider.setTelemetryMode(Provider::NoTelemetry); 0187 provider.setSubmissionInterval(7); 0188 provider.setSurveyInterval(30); 0189 provider.setFeedbackServer(serverUrl); 0190 provider.addDataSource(new ScreenInfoSource); 0191 provider.addDataSource(new PlatformInfoSource); 0192 provider.submit(); 0193 QTest::qWait(100); // HACK submit is async 0194 0195 // retrieve data 0196 reply = RESTApi::listSamples(&client, p); 0197 QVERIFY(waitForFinished(reply)); 0198 QVERIFY(reply->header(QNetworkRequest::ContentTypeHeader).toString().startsWith(QLatin1String("text/json"))); 0199 auto doc = QJsonDocument::fromJson(reply->readAll()); 0200 QVERIFY(doc.isArray()); 0201 auto a = doc.array(); 0202 QCOMPARE(a.size(), 0); 0203 0204 // check we wrote an audit log 0205 AuditLogUiController alc; 0206 QVERIFY(alc.logEntryModel()); 0207 QCOMPARE(alc.logEntryModel()->rowCount(), 1); 0208 } 0209 }; 0210 0211 QTEST_MAIN(SubmitTest) 0212 0213 #include "submittest.moc"