Commit e396886f authored by Volker Krause's avatar Volker Krause
Browse files

Add unit test for survey API

parent 4c419ffc
......@@ -47,6 +47,19 @@ Survey::Survey(const Survey&) = default;
Survey::~Survey() = default;
Survey& Survey::operator=(const Survey&) = default;
bool Survey::operator==(const Survey& other) const
{
return d->name == other.d->name
&& d->url == other.d->url
&& d->id == other.d->id
&& d->active == other.d->active;
}
bool Survey::operator!=(const Survey& other) const
{
return !(*this == other);
}
int Survey::id() const
{
return d->id;
......
......@@ -39,6 +39,9 @@ public:
~Survey();
Survey& operator=(const Survey&);
bool operator==(const Survey &other) const;
bool operator!=(const Survey &other) const;
int id() const;
void setId(int id);
......
......@@ -260,7 +260,7 @@ void MainWindow::productSelected()
if (!product.isValid())
return;
m_dataModel->setProduct(product);
m_surveyModel->setProductId(product.name());
m_surveyModel->setProduct(product);
ui->schemaEdit->setProduct(product);
m_chart->setModel(nullptr);
......@@ -319,7 +319,7 @@ void MainWindow::createSurvey()
SurveyDialog dlg(this);
if (!dlg.exec())
return;
auto reply = m_restClient->post(QStringLiteral("surveys/") + product.name(), dlg.survey().toJson());
auto reply = RESTApi::createSurvey(m_restClient, product, dlg.survey());
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
if (reply->error() == QNetworkReply::NoError) {
logMessage(QString::fromUtf8(reply->readAll()));
......@@ -340,7 +340,7 @@ void MainWindow::deleteSurvey()
const auto survey = selection.first().data(SurveyModel::SurveyRole).value<Survey>();
if (survey.id() < 0)
return;
auto reply = m_restClient->deleteResource(QStringLiteral("surveys/") + QString::number(survey.id()));
auto reply = RESTApi::deleteSurvey(m_restClient, survey);
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
if (reply->error() != QNetworkReply::NoError)
return;
......
......@@ -17,6 +17,7 @@
#include "surveymodel.h"
#include <rest/restapi.h>
#include <rest/restclient.h>
#include <QDebug>
......@@ -39,18 +40,18 @@ void SurveyModel::setRESTClient(RESTClient* client)
reload();
}
void SurveyModel::setProductId(const QString& product)
void SurveyModel::setProduct(const Product& product)
{
m_productId = product;
m_product = product;
reload();
}
void SurveyModel::reload()
{
if (!m_restClient || !m_restClient->isConnected() || m_productId.isEmpty())
if (!m_restClient || !m_restClient->isConnected() || !m_product.isValid())
return;
auto reply = m_restClient->get(QStringLiteral("surveys/") + m_productId);
auto reply = RESTApi::listSurveys(m_restClient, m_product);
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
if (reply->error() == QNetworkReply::NoError) {
beginResetModel();
......@@ -99,7 +100,7 @@ bool SurveyModel::setData(const QModelIndex &index, const QVariant &value, int r
if (index.column() == 2 && role == Qt::CheckStateRole) {
auto &survey = m_surveys[index.row()];
survey.setActive(value.toInt() == Qt::Checked);
auto reply = m_restClient->put(QStringLiteral("surveys/") + QString::number(survey.id()), survey.toJson());
auto reply = RESTApi::updateSurvey(m_restClient, survey);
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
qDebug() << reply->readAll();
reload();
......
......@@ -18,6 +18,7 @@
#ifndef USERFEEDBACK_ANALYZER_SURVEYMODEL_H
#define USERFEEDBACK_ANALYZER_SURVEYMODEL_H
#include <core/product.h>
#include <core/survey.h>
#include <QAbstractTableModel>
......@@ -39,7 +40,7 @@ public:
~SurveyModel();
void setRESTClient(RESTClient *client);
void setProductId(const QString &product);
void setProduct(const Product &product);
void reload();
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
......@@ -51,7 +52,7 @@ public:
private:
RESTClient *m_restClient = nullptr;
QString m_productId;
Product m_product;
QVector<Survey> m_surveys;
};
......
......@@ -19,6 +19,7 @@
#include "restclient.h"
#include <core/product.h>
#include <core/survey.h>
using namespace UserFeedback::Analyzer;
......@@ -44,3 +45,25 @@ QNetworkReply* RESTApi::deleteProduct(RESTClient *client, const Product &p)
Q_ASSERT(p.isValid());
return client->deleteResource(QStringLiteral("products/") + p.name());
}
QNetworkReply* RESTApi::listSurveys(RESTClient *client, const Product &p)
{
Q_ASSERT(p.isValid());
return client->get(QStringLiteral("surveys/") + p.name());
}
QNetworkReply* RESTApi::createSurvey(RESTClient *client, const Product &p, const Survey &s)
{
Q_ASSERT(p.isValid());
return client->post(QStringLiteral("surveys/") + p.name(), s.toJson());
}
QNetworkReply* RESTApi::updateSurvey(RESTClient *client, const Survey &s)
{
return client->put(QStringLiteral("surveys/") + QString::number(s.id()), s.toJson());
}
QNetworkReply* RESTApi::deleteSurvey(RESTClient *client, const Survey &s)
{
return client->deleteResource(QStringLiteral("surveys/") + QString::number(s.id()));
}
......@@ -25,6 +25,7 @@ namespace Analyzer {
class Product;
class RESTClient;
class Survey;
/** C++ wrapper for the server-side API.
* Precondition for all methods is that client->isConnected() returns @c true.
......@@ -48,6 +49,18 @@ namespace RESTApi
* @param p The product to add. Must be valid.
*/
QNetworkReply* deleteProduct(RESTClient *client, const Product &p);
/** List all surveys for product @p p. */
QNetworkReply* listSurveys(RESTClient *client, const Product &p);
/** Create a new survey. */
QNetworkReply* createSurvey(RESTClient *client, const Product &p, const Survey &s);
/** Update an existing survey. */
QNetworkReply* updateSurvey(RESTClient *client, const Survey &s);
/** Delete a survey. */
QNetworkReply* deleteSurvey(RESTClient *client, const Survey &s);
}
}
......
......@@ -9,3 +9,7 @@ add_test(NAME productmodeltest COMMAND productmodeltest)
add_executable(schemamodeltest schemamodeltest.cpp ${CMAKE_SOURCE_DIR}/3rdparty/qt/modeltest.cpp)
target_link_libraries(schemamodeltest Qt5::Test UserFeedbackAnalyzer)
add_test(NAME schemamodeltest COMMAND schemamodeltest)
add_executable(surveyapitest surveyapitest.cpp ${CMAKE_SOURCE_DIR}/3rdparty/qt/modeltest.cpp)
target_link_libraries(surveyapitest Qt5::Test UserFeedbackAnalyzer)
add_test(NAME surveyapitest COMMAND surveyapitest)
/*
Copyright (C) 2016 Volker Krause <vkrause@kde.org>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <rest/restapi.h>
#include <rest/restclient.h>
#include <core/product.h>
#include <core/survey.h>
#include <QDebug>
#include <QtTest/qtest.h>
#include <QNetworkReply>
#include <QObject>
#include <QSignalSpy>
#include <QStandardPaths>
#include <limits>
using namespace UserFeedback::Analyzer;
class SurveyApiTest : public QObject
{
Q_OBJECT
private:
ServerInfo testServer() const
{
// TODO this needs to be read from an external file, and the test needs to be skipped if not available
ServerInfo s;
s.setUrl(QUrl(QStringLiteral("https://feedback.volkerkrause.eu/")));
s.setUserName(QStringLiteral("orwell"));
s.setPassword(QStringLiteral("1984"));
return s;
}
bool waitForFinished(QNetworkReply *reply)
{
Q_ASSERT(reply);
QSignalSpy spy(reply, &QNetworkReply::finished);
Q_ASSERT(spy.isValid());
return spy.wait();
}
private slots:
void initTestCase()
{
QStandardPaths::setTestModeEnabled(true);
}
void init()
{
RESTClient client;
client.connectToServer(testServer());
Product p;
p.setName(QStringLiteral("org.kde.UserFeedback.UnitTestProduct"));
auto reply = RESTApi::createProduct(&client, p);
waitForFinished(reply);
}
void cleanup()
{
RESTClient client;
client.connectToServer(testServer());
Product p;
p.setName(QStringLiteral("org.kde.UserFeedback.UnitTestProduct"));
auto reply = RESTApi::deleteProduct(&client, p);
waitForFinished(reply);
}
void testSurveyCRUD()
{
RESTClient client;
client.connectToServer(testServer());
QVERIFY(client.isConnected());
Product p;
p.setName(QStringLiteral("org.kde.UserFeedback.UnitTestProduct"));
// list surveys
auto reply = RESTApi::listSurveys(&client, p);
QVERIFY(waitForFinished(reply));
QCOMPARE(reply->error(), QNetworkReply::NoError);
auto surveys = Survey::fromJson(reply->readAll());
QVERIFY(surveys.isEmpty());
// add new survey
Survey s;
s.setName(QStringLiteral("unitTestSurvey"));
s.setUrl(QUrl(QStringLiteral("http://www.kde.org")));
s.setActive(false);
reply = RESTApi::createSurvey(&client, p, s);
QVERIFY(waitForFinished(reply));
QCOMPARE(reply->error(), QNetworkReply::NoError);
// verify the new product is there
reply = RESTApi::listSurveys(&client, p);
QVERIFY(waitForFinished(reply));
QCOMPARE(reply->error(), QNetworkReply::NoError);
surveys = Survey::fromJson(reply->readAll());
QCOMPARE(surveys.size(), 1);
QVERIFY(surveys.at(0) != s); // id is different
s.setId(surveys.at(0).id());
QCOMPARE(surveys.at(0), s);
// update a survey
s.setActive(true);
reply = RESTApi::updateSurvey(&client, s);
QVERIFY(waitForFinished(reply));
QCOMPARE(reply->error(), QNetworkReply::NoError);
// verify the update worked
reply = RESTApi::listSurveys(&client, p);
QVERIFY(waitForFinished(reply));
QCOMPARE(reply->error(), QNetworkReply::NoError);
surveys = Survey::fromJson(reply->readAll());
QCOMPARE(surveys.size(), 1);
QCOMPARE(s, surveys.at(0));
// delete a survey
reply = RESTApi::deleteSurvey(&client, s);
QVERIFY(waitForFinished(reply));
QCOMPARE(reply->error(), QNetworkReply::NoError);
// verify it's gone
reply = RESTApi::listSurveys(&client, p);
QVERIFY(waitForFinished(reply));
QCOMPARE(reply->error(), QNetworkReply::NoError);
surveys = Survey::fromJson(reply->readAll());
QVERIFY(surveys.isEmpty());
}
void testInvalidSurveyOperations()
{
RESTClient client;
client.connectToServer(testServer());
QVERIFY(client.isConnected());
Product invalidProduct;
invalidProduct.setName(QStringLiteral("org.kde.UserFeedback.Invalid"));
// create survey for non-existing product
Survey s;
s.setName(QStringLiteral("invalidTestSurvey"));
s.setUrl(QUrl(QStringLiteral("http://www.kde.org")));
auto reply = RESTApi::createSurvey(&client, invalidProduct, s);
QVERIFY(waitForFinished(reply));
QVERIFY(reply->error() != QNetworkReply::NoError);
// update a non-existing survey
s.setId(std::numeric_limits<int>::max());
reply = RESTApi::updateSurvey(&client, s);
QVERIFY(waitForFinished(reply));
qDebug() << reply->readAll();
QEXPECT_FAIL("", "check not implemented on the server", Continue);
QVERIFY(reply->error() != QNetworkReply::NoError);
// delete a non-existing survey
reply = RESTApi::deleteSurvey(&client, s);
QVERIFY(waitForFinished(reply));
QEXPECT_FAIL("", "check not implemented on the server", Continue);
QVERIFY(reply->error() != QNetworkReply::NoError);
}
};
QTEST_MAIN(SurveyApiTest)
#include "surveyapitest.moc"
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment