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"